windowmaker-wl/src/backend/wayland/wl_screen.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); }