240 lines
8.7 KiB
C
240 lines
8.7 KiB
C
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
#include <X11/Xlib.h>
|
|
#include <wayland-server-core.h>
|
|
#include <wlr/types/wlr_output.h>
|
|
#include "../../screen.h"
|
|
#include "../../shutdown.h"
|
|
#include "../../dialog.h"
|
|
#include <WINGs/WINGsP.h>
|
|
#include "wl_types.h"
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* Screen open/close */
|
|
|
|
void
|
|
wl_screen_open(WScreen *scr)
|
|
{
|
|
/* Set geometry from the headless output created in display_open(). */
|
|
scr->scr_width = wl_state.output ?
|
|
(int)wl_state.output->width : 1920;
|
|
scr->scr_height = wl_state.output ?
|
|
(int)wl_state.output->height : 1080;
|
|
scr->depth = 24;
|
|
scr->root_win = (WNativeWindow)0x0FFFFFFF; /* synthetic root window ID */
|
|
scr->colormap = 0;
|
|
|
|
/* Wayland has no X11-style window border; the frame_buf renders the
|
|
* full decoration. Set border width to 0 so policy code does not
|
|
* offset the client position by a non-existent border. */
|
|
scr->frame_border_width = 0;
|
|
|
|
/* XWayland bridge: fill in real X11 screen values so RCreateContext
|
|
* and WINGs can use the display connection for drawing and fonts. */
|
|
if (wl_state.x_display) {
|
|
int snum = DefaultScreen(wl_state.x_display);
|
|
scr->root_win = DefaultRootWindow(wl_state.x_display);
|
|
scr->depth = DefaultDepth(wl_state.x_display, snum);
|
|
scr->colormap = DefaultColormap(wl_state.x_display, snum);
|
|
}
|
|
}
|
|
|
|
void wl_screen_close(WScreen *scr) { (void)scr; }
|
|
|
|
int
|
|
wl_screen_init_display(WScreen *scr, int screen_number)
|
|
{
|
|
(void)screen_number;
|
|
scr->w_depth = 32;
|
|
scr->rcontext = RCreateContextWayland(scr->scr_width, scr->scr_height, NULL);
|
|
|
|
/* WINGs widget backends are selected via W_SetNextScreenKind — the
|
|
* compositor uses the Wayland-mode set even though wmaker itself is
|
|
* the compositor (rendering goes through pixman → wlroots scenes). */
|
|
W_SetNextScreenKind(WM_SCREEN_KIND_WAYLAND);
|
|
scr->wmscreen = WMCreateScreenWithRContext(NULL, 0, scr->rcontext);
|
|
if (!scr->wmscreen) {
|
|
wfatal(_("could not initialize WINGs widget set"));
|
|
return 0;
|
|
}
|
|
|
|
scr->black = WMBlackColor(scr->wmscreen);
|
|
scr->white = WMWhiteColor(scr->wmscreen);
|
|
scr->gray = WMGrayColor(scr->wmscreen);
|
|
scr->darkGray = WMDarkGrayColor(scr->wmscreen);
|
|
|
|
scr->black_pixel = scr->black ? WMColorPixel(scr->black) : 0xFF000000;
|
|
scr->white_pixel = scr->white ? WMColorPixel(scr->white) : 0xFFFFFFFF;
|
|
scr->light_pixel = scr->gray ? WMColorPixel(scr->gray) : 0xFFAAAAAA;
|
|
scr->dark_pixel = scr->darkGray ? WMColorPixel(scr->darkGray) : 0xFF555555;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
wl_show_crash_dialog(int sig)
|
|
{
|
|
/* Wayland: showing a UI from a crashed compositor's child process is
|
|
* not possible (the child would need to connect to the dead parent
|
|
* for its compositor). Default to auto-restart, which is the most
|
|
* useful behavior for a daily-driver compositor — the user's session
|
|
* recovers on its own. The crash signal is logged separately by
|
|
* the monitor parent. */
|
|
(void)sig;
|
|
return WMRestart;
|
|
}
|
|
int wl_get_color_for_colormap(unsigned long colormap,
|
|
const char *color_name, WMColorRGB *color)
|
|
{
|
|
unsigned int r, g, b;
|
|
(void)colormap;
|
|
|
|
if (!color_name || !color)
|
|
return 0;
|
|
|
|
/* Parse #RGB, #RRGGBB, #RRRRGGGGBBBB */
|
|
if (color_name[0] == '#') {
|
|
int len = strlen(color_name + 1);
|
|
if (len == 6) {
|
|
if (sscanf(color_name, "#%2x%2x%2x", &r, &g, &b) == 3) {
|
|
color->red = r << 8 | r;
|
|
color->green = g << 8 | g;
|
|
color->blue = b << 8 | b;
|
|
color->pixel = (0xFF << 24) | (r << 16) | (g << 8) | b;
|
|
return 1;
|
|
}
|
|
} else if (len == 12) {
|
|
if (sscanf(color_name, "#%4hx%4hx%4hx",
|
|
&color->red, &color->green, &color->blue) == 3) {
|
|
color->pixel = (0xFF << 24) |
|
|
((color->red >> 8) << 16) |
|
|
((color->green >> 8) << 8) |
|
|
(color->blue >> 8);
|
|
return 1;
|
|
}
|
|
} else if (len == 3) {
|
|
if (sscanf(color_name, "#%1x%1x%1x", &r, &g, &b) == 3) {
|
|
color->red = r << 12 | r << 8 | r << 4 | r;
|
|
color->green = g << 12 | g << 8 | g << 4 | g;
|
|
color->blue = b << 12 | b << 8 | b << 4 | b;
|
|
color->pixel = (0xFF << 24) | (r*17 << 16) | (g*17 << 8) | b*17;
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* X11 rgb:RR/GG/BB or rgb:RRRR/GGGG/BBBB format */
|
|
if (strncasecmp(color_name, "rgb:", 4) == 0) {
|
|
unsigned int rv, gv, bv;
|
|
const char *p = color_name + 4;
|
|
int n = sscanf(p, "%x/%x/%x", &rv, &gv, &bv);
|
|
if (n == 3) {
|
|
/* Determine component width from first component */
|
|
const char *slash = strchr(p, '/');
|
|
int width = slash ? (int)(slash - p) : 2;
|
|
if (width == 1) {
|
|
color->red = rv << 12 | rv << 8 | rv << 4 | rv;
|
|
color->green = gv << 12 | gv << 8 | gv << 4 | gv;
|
|
color->blue = bv << 12 | bv << 8 | bv << 4 | bv;
|
|
} else if (width == 2) {
|
|
color->red = rv << 8 | rv;
|
|
color->green = gv << 8 | gv;
|
|
color->blue = bv << 8 | bv;
|
|
} else {
|
|
color->red = rv;
|
|
color->green = gv;
|
|
color->blue = bv;
|
|
}
|
|
color->pixel = (0xFF << 24) |
|
|
((color->red >> 8) << 16) |
|
|
((color->green >> 8) << 8) |
|
|
(color->blue >> 8);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/* Named colors — common ones */
|
|
struct { const char *name; unsigned short r, g, b; } named[] = {
|
|
{"black", 0x0000, 0x0000, 0x0000},
|
|
{"white", 0xFFFF, 0xFFFF, 0xFFFF},
|
|
{"red", 0xFFFF, 0x0000, 0x0000},
|
|
{"green", 0x0000, 0xFFFF, 0x0000},
|
|
{"blue", 0x0000, 0x0000, 0xFFFF},
|
|
{"gray", 0xBEBE, 0xBEBE, 0xBEBE},
|
|
{"grey", 0xBEBE, 0xBEBE, 0xBEBE},
|
|
{"darkgray",0xA9A9, 0xA9A9, 0xA9A9},
|
|
{"darkgrey",0xA9A9, 0xA9A9, 0xA9A9},
|
|
{"lightgray",0xD3D3, 0xD3D3, 0xD3D3},
|
|
{"lightgrey",0xD3D3, 0xD3D3, 0xD3D3},
|
|
{NULL, 0, 0, 0}
|
|
};
|
|
for (int i = 0; named[i].name; i++) {
|
|
if (strcasecmp(color_name, named[i].name) == 0) {
|
|
color->red = named[i].r;
|
|
color->green = named[i].g;
|
|
color->blue = named[i].b;
|
|
color->pixel = (0xFF << 24) |
|
|
((color->red >> 8) << 16) |
|
|
((color->green >> 8) << 8) |
|
|
(color->blue >> 8);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/* grayNN / greyNN (0-100) */
|
|
if ((strncasecmp(color_name, "gray", 4) == 0 || strncasecmp(color_name, "grey", 4) == 0)
|
|
&& color_name[4] >= '0' && color_name[4] <= '9') {
|
|
int pct = atoi(color_name + 4);
|
|
if (pct >= 0 && pct <= 100) {
|
|
unsigned int v = (pct * 255 + 50) / 100;
|
|
color->red = color->green = color->blue = v << 8 | v;
|
|
color->pixel = (0xFF << 24) | (v << 16) | (v << 8) | v;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/* Look up in X11 rgb.txt database */
|
|
{
|
|
const char *rgb_paths[] = {
|
|
"/usr/share/X11/rgb.txt",
|
|
"/usr/lib/X11/rgb.txt",
|
|
"/etc/X11/rgb.txt",
|
|
NULL
|
|
};
|
|
FILE *f = NULL;
|
|
for (int i = 0; rgb_paths[i] && !f; i++)
|
|
f = fopen(rgb_paths[i], "r");
|
|
if (f) {
|
|
char line[256];
|
|
while (fgets(line, sizeof(line), f)) {
|
|
unsigned int rv, gv, bv;
|
|
char name[128];
|
|
if (line[0] == '!' || line[0] == '#')
|
|
continue;
|
|
if (sscanf(line, "%u %u %u %127[^\n]", &rv, &gv, &bv, name) == 4) {
|
|
/* Trim leading whitespace/tabs from name */
|
|
char *n = name;
|
|
while (*n == ' ' || *n == '\t') n++;
|
|
if (strcasecmp(n, color_name) == 0) {
|
|
color->red = rv << 8 | rv;
|
|
color->green = gv << 8 | gv;
|
|
color->blue = bv << 8 | bv;
|
|
color->pixel = (0xFF << 24) | (rv << 16) | (gv << 8) | bv;
|
|
fclose(f);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
fclose(f);
|
|
}
|
|
}
|
|
|
|
wwarning(_("could not parse color \"%s\" (Wayland)"), color_name);
|
|
return 0;
|
|
}
|
|
|
|
int wl_parse_color(WScreen *scr, const char *name, WMColorRGB *color_out)
|
|
{ (void)scr; return wl_get_color_for_colormap(0, name, color_out); }
|
|
|