decompose wl_stubs.c: move remaining real implementations to module files
This commit is contained in:
parent
859af074ad
commit
29aeffd6ac
|
|
@ -11,6 +11,7 @@
|
|||
#include <wlr/interfaces/wlr_buffer.h>
|
||||
#include "../../screen.h"
|
||||
#include "wl_types.h"
|
||||
#include "../../window.h"
|
||||
#include <WINGs/WINGsP.h>
|
||||
|
||||
/* Forward declarations from sibling modules. */
|
||||
|
|
@ -485,3 +486,93 @@ wl_client_snapshot(WScreen *scr, WNativeWindow client_win, WNativeWindow frame_w
|
|||
wlr_buffer_end_data_ptr_access(buf);
|
||||
return res;
|
||||
}
|
||||
void wl_client_set_state(WWindow *wwin, int state, WNativeWindow icon_win)
|
||||
{
|
||||
(void)icon_win;
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(wwin->client_win);
|
||||
if (!v)
|
||||
return;
|
||||
switch (state) {
|
||||
case 3: /* WM_STATE_ICONIC */
|
||||
if (v->scene_node)
|
||||
wlr_scene_node_set_enabled(&v->scene_node->node, false);
|
||||
break;
|
||||
case 1: /* WM_STATE_NORMAL */
|
||||
if (v->scene_node)
|
||||
wlr_scene_node_set_enabled(&v->scene_node->node, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void wl_client_set_maximized(WNativeWindow win, int maximized)
|
||||
{
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(win);
|
||||
if (!v) return;
|
||||
if (v->xdg_surface && v->xdg_surface->toplevel)
|
||||
wlr_xdg_toplevel_set_maximized(v->xdg_surface->toplevel, maximized);
|
||||
}
|
||||
|
||||
void wl_client_send_protocol(WWindow *wwin, unsigned long protocol,
|
||||
unsigned long timestamp)
|
||||
{
|
||||
(void)protocol; (void)timestamp;
|
||||
wm_backend->client_close(wwin->client_win);
|
||||
}
|
||||
|
||||
void wl_client_kill_impl(WWindow *wwin)
|
||||
{
|
||||
wm_backend->client_close(wwin->client_win);
|
||||
}
|
||||
|
||||
void wl_client_message_forward(WMEvent *event, WNativeWindow target_win)
|
||||
{
|
||||
/* Forward OffiX DND ClientMessage to the real client_win for
|
||||
* XWayland clients. Native Wayland clients have no analog. */
|
||||
if (!wl_state.x_display || !event) return;
|
||||
XEvent *xev = (XEvent *)event->_x11_raw;
|
||||
if (!xev) return;
|
||||
xev->xclient.window = (WNativeWindow)target_win;
|
||||
XSendEvent(wl_state.x_display, (WNativeWindow)target_win, False, 0L, xev);
|
||||
}
|
||||
|
||||
void wl_client_send_key(WNativeWindow win, unsigned int keycode,
|
||||
unsigned int modifier_mask, int press)
|
||||
{
|
||||
/* For XWayland clients, deliver via the X server (wl_state.x_display)
|
||||
* the same way the X11 backend does. Native Wayland clients are not
|
||||
* yet supported (would require zwp_virtual_keyboard_v1). */
|
||||
if (!wl_state.x_display) return;
|
||||
XEvent ev;
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.xkey.type = press ? KeyPress : KeyRelease;
|
||||
ev.xkey.display = wl_state.x_display;
|
||||
ev.xkey.window = (WNativeWindow)win;
|
||||
ev.xkey.root = DefaultRootWindow(wl_state.x_display);
|
||||
ev.xkey.subwindow = WM_NATIVE_NONE;
|
||||
ev.xkey.same_screen = True;
|
||||
ev.xkey.time = WM_CURRENT_TIME;
|
||||
ev.xkey.keycode = keycode;
|
||||
ev.xkey.state = modifier_mask;
|
||||
XSendEvent(wl_state.x_display, (WNativeWindow)win, press ? False : True,
|
||||
press ? WM_EVMASK_KEY_PRESS : WM_EVMASK_KEY_RELEASE, &ev);
|
||||
}
|
||||
|
||||
char *wl_get_command_for_window(WNativeWindow win, int elements)
|
||||
{
|
||||
char **argv, *command = NULL;
|
||||
int argc;
|
||||
if (!wm_backend->icccm_get_command(win, &argv, &argc))
|
||||
return NULL;
|
||||
if (argc > 0 && argv != NULL) {
|
||||
if (elements == 0)
|
||||
elements = argc;
|
||||
command = wtokenjoin(argv, WMIN(argc, elements));
|
||||
if (command[0] == 0) {
|
||||
wfree(command);
|
||||
command = NULL;
|
||||
}
|
||||
}
|
||||
wm_backend->icccm_free_command(argv);
|
||||
return command;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,3 +23,8 @@ void wl_event_drain_motion(void) {}
|
|||
void wl_event_discard_enter_leave_until(unsigned long timestamp) { (void)timestamp; }
|
||||
void wl_event_handle_extensions(WMEvent *event) { (void)event; }
|
||||
void wl_event_randr_update(WMEvent *event) { (void)event; }
|
||||
void wl_event_handle_signal_exit(void)
|
||||
{
|
||||
wm_backend->event_loop_terminate();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -869,3 +869,59 @@ wl_netwm_update_opacity(WWindow *wwin)
|
|||
}
|
||||
}
|
||||
}
|
||||
void wl_frame_paint_resizebar(WFrameWindow *fwin)
|
||||
{
|
||||
/* Resizebar is rendered into the parent frame buffer by wl_frame_paint.
|
||||
* Don't commit a separate buffer here — it would overlay the texture. */
|
||||
(void)fwin;
|
||||
}
|
||||
|
||||
void wl_frame_paint_titlebar(WFrameWindow *fwin, int state)
|
||||
{
|
||||
if (!fwin->titlebar || !fwin->titlebar->window)
|
||||
return;
|
||||
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)fwin->titlebar->window);
|
||||
if (!fb || !fb->image)
|
||||
return;
|
||||
|
||||
WScreen *scr = fwin->screen_ptr;
|
||||
uint32_t *dst = (uint32_t *)pixman_image_get_data(fb->image);
|
||||
int stride = pixman_image_get_stride(fb->image) / 4;
|
||||
|
||||
/* Background: use texture color or default */
|
||||
uint32_t bg;
|
||||
if (fwin->title_texture[state] &&
|
||||
fwin->title_texture[state]->any.type == WTEX_SOLID) {
|
||||
unsigned long px = fwin->title_texture[state]->solid.normal.pixel;
|
||||
bg = 0xFF000000 | (px & 0xFFFFFF);
|
||||
} else {
|
||||
bg = (state == 0) ? 0xFF4A6984 : 0xFF808080; /* focused blue / unfocused grey */
|
||||
}
|
||||
|
||||
for (int row = 0; row < fb->height; row++)
|
||||
for (int col = 0; col < fb->width; col++)
|
||||
dst[row * stride + col] = bg;
|
||||
|
||||
/* Draw title text */
|
||||
if (fwin->title && fwin->font && fwin->title_color[state]) {
|
||||
char *title = ShrinkString(*fwin->font, fwin->title, fb->width - 12);
|
||||
int titlelen = strlen(title);
|
||||
int tw = WMWidthOfString(*fwin->font, title, titlelen);
|
||||
int x;
|
||||
switch (fwin->flags.justification) {
|
||||
case WTJ_LEFT: x = 6; break;
|
||||
case WTJ_RIGHT: x = fb->width - tw - 6; break;
|
||||
default: x = (fb->width - tw) / 2; break;
|
||||
}
|
||||
int fh = WMFontHeight(*fwin->font);
|
||||
int y = (fb->height - fh) / 2;
|
||||
|
||||
WMDrawable d = (WMDrawable)(uintptr_t)fb->image;
|
||||
WMDrawString(scr->wmscreen, d, fwin->title_color[state],
|
||||
*fwin->font, x, y, title, titlelen);
|
||||
wfree(title);
|
||||
}
|
||||
|
||||
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
#include "../../defaults.h"
|
||||
#include "../../def_pixmaps.h"
|
||||
#include "wl_types.h"
|
||||
#include "../../workspace.h"
|
||||
#include "../../dock.h"
|
||||
#include <WINGs/WINGsP.h>
|
||||
|
||||
/* Forward declarations */
|
||||
|
|
@ -167,3 +169,114 @@ wl_appicon_paint(WAppIcon *aicon)
|
|||
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
|
||||
wlr_scene_node_set_enabled(&fb->scene_buf->node, true);
|
||||
}
|
||||
void wl_clip_icon_paint(WAppIcon *aicon)
|
||||
{
|
||||
if (!aicon || !aicon->icon || !aicon->icon->core)
|
||||
return;
|
||||
|
||||
WScreen *scr = aicon->icon->core->screen_ptr;
|
||||
if (!scr->workspaces || !scr->workspaces[scr->current_workspace])
|
||||
return;
|
||||
|
||||
/* Paint base tile + icon image */
|
||||
wl_appicon_paint(aicon);
|
||||
|
||||
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)aicon->icon->core->window);
|
||||
if (!fb || !fb->image)
|
||||
return;
|
||||
|
||||
WWorkspace *workspace = scr->workspaces[scr->current_workspace];
|
||||
/* Use aicon->dock to read collapsed state — workspace->clip may be a
|
||||
* stale freed pointer during wWorkspaceRestoreState (the old clip is
|
||||
* destroyed before scr->workspaces[i]->clip is reassigned, and we
|
||||
* are called from wDockCreate inside that gap). */
|
||||
int collapsed = aicon->dock ? aicon->dock->collapsed : 0;
|
||||
WMColor *color;
|
||||
if (wPreferences.flags.noclip || !collapsed)
|
||||
color = scr->clip_title_color[CLIP_NORMAL];
|
||||
else
|
||||
color = scr->clip_title_color[CLIP_COLLAPSED];
|
||||
if (!color || !scr->clip_title_font)
|
||||
return;
|
||||
|
||||
int size = wPreferences.icon_size;
|
||||
WMDrawable d = (WMDrawable)(uintptr_t)fb->image;
|
||||
|
||||
/* Draw workspace number at top center */
|
||||
char ws_number[20];
|
||||
snprintf(ws_number, sizeof ws_number, "%u", scr->current_workspace + 1);
|
||||
int nlength = strlen(ws_number);
|
||||
int tx = (size / 2 - WMWidthOfString(scr->clip_title_font, ws_number, nlength)) / 2;
|
||||
WMDrawString(scr->wmscreen, d, color, scr->clip_title_font, tx, 2, ws_number, nlength);
|
||||
|
||||
/* Draw workspace name at bottom */
|
||||
if (wPreferences.show_clip_title) {
|
||||
int length = strlen(workspace->name);
|
||||
int ty = size - WMFontHeight(scr->clip_title_font) - 3;
|
||||
tx = CLIP_BUTTON_SIZE * size / 64;
|
||||
WMDrawString(scr->wmscreen, d, color, scr->clip_title_font, tx, ty, workspace->name, length);
|
||||
}
|
||||
|
||||
/* Commit updated buffer */
|
||||
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
|
||||
}
|
||||
|
||||
void wl_drawer_icon_paint(WAppIcon *aicon)
|
||||
{
|
||||
if (!aicon || !aicon->icon || !aicon->icon->core)
|
||||
return;
|
||||
|
||||
wl_appicon_paint(aicon);
|
||||
|
||||
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)aicon->icon->core->window);
|
||||
if (!fb || !fb->image)
|
||||
return;
|
||||
|
||||
WScreen *scr = aicon->icon->core->screen_ptr;
|
||||
WMColor *color;
|
||||
if (!aicon->dock->collapsed)
|
||||
color = scr->clip_title_color[CLIP_NORMAL];
|
||||
else
|
||||
color = scr->clip_title_color[CLIP_COLLAPSED];
|
||||
if (!color)
|
||||
return;
|
||||
|
||||
int size = wPreferences.icon_size;
|
||||
uint32_t pixel = ((uint32_t)0xFF << 24) |
|
||||
((uint32_t)WMRedComponentOfColor(color) >> 8 << 16) |
|
||||
((uint32_t)WMGreenComponentOfColor(color) >> 8 << 8) |
|
||||
((uint32_t)WMBlueComponentOfColor(color) >> 8);
|
||||
uint32_t *data = (uint32_t *)pixman_image_get_data(fb->image);
|
||||
int stride = pixman_image_get_stride(fb->image) / 4;
|
||||
|
||||
/* Draw directional arrow (triangle) */
|
||||
int cx, cy = size / 2;
|
||||
if (aicon->dock->on_right_side) {
|
||||
/* Arrow pointing left: tip at x=5, base at x=10 */
|
||||
for (int dy = -5; dy <= 5; dy++) {
|
||||
int row = cy + dy;
|
||||
if (row < 0 || row >= size) continue;
|
||||
int width = 5 - abs(dy);
|
||||
for (int dx = 0; dx <= width; dx++) {
|
||||
cx = 10 - dx;
|
||||
if (cx >= 0 && cx < size)
|
||||
data[row * stride + cx] = pixel;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Arrow pointing right: tip at x=size-6, base at x=size-11 */
|
||||
for (int dy = -5; dy <= 5; dy++) {
|
||||
int row = cy + dy;
|
||||
if (row < 0 || row >= size) continue;
|
||||
int width = 5 - abs(dy);
|
||||
for (int dx = 0; dx <= width; dx++) {
|
||||
cx = size - 11 + dx;
|
||||
if (cx >= 0 && cx < size)
|
||||
data[row * stride + cx] = pixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -252,3 +252,23 @@ wl_pointer_change_grab(unsigned int event_mask, int cursor_id,
|
|||
}
|
||||
wl_set_cursor_image(name);
|
||||
}
|
||||
void wl_pointer_change_cursor(int cursor_id)
|
||||
{
|
||||
const char *name;
|
||||
switch (cursor_id) {
|
||||
case 1: /* WCUR_MOVE */ name = "fleur"; break;
|
||||
case 2: /* WCUR_RESIZE */ name = "bottom_right_corner"; break;
|
||||
case 7: /* WCUR_WAIT */ name = "watch"; break;
|
||||
case 8: /* WCUR_ARROW */ name = "left_ptr"; break;
|
||||
case 9: /* WCUR_QUESTION */name = "question_arrow"; break;
|
||||
case 10:/* WCUR_TEXT */ name = "xterm"; break;
|
||||
default: name = "left_ptr"; break;
|
||||
}
|
||||
wl_set_cursor_image(name);
|
||||
}
|
||||
|
||||
void wl_pointer_get_position(int *x, int *y) {
|
||||
*x = (int)wl_state.pointer_x;
|
||||
*y = (int)wl_state.pointer_y;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -84,3 +84,156 @@ wl_show_crash_dialog(int sig)
|
|||
(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); }
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,30 @@ void wl_netwm_update_opacity(WWindow *wwin);
|
|||
void wl_icon_paint(WIcon *icon);
|
||||
void wl_appicon_show(WApplication *wapp);
|
||||
void wl_appicon_paint(WAppIcon *aicon);
|
||||
void wl_client_set_state(WWindow *wwin, int state, WNativeWindow icon_win);
|
||||
void wl_client_set_maximized(WNativeWindow win, int maximized);
|
||||
void wl_client_send_protocol(WWindow *wwin, unsigned long protocol, unsigned long timestamp);
|
||||
void wl_client_kill_impl(WWindow *wwin);
|
||||
char *wl_get_command_for_window(WNativeWindow win, int elements);
|
||||
void wl_client_message_forward(WMEvent *event, WNativeWindow target_win);
|
||||
void wl_client_send_key(WNativeWindow win, unsigned int keycode, unsigned int modifiers, int grabbed);
|
||||
int wl_get_color_for_colormap(unsigned long colormap, const char *color_name, WMColorRGB *color);
|
||||
void wl_frame_paint_resizebar(WFrameWindow *fwin);
|
||||
void wl_frame_paint_titlebar(WFrameWindow *fwin, int state);
|
||||
void wl_menu_paint_entry(WMenu *menu, int index, int selected);
|
||||
void wl_menu_draw_frame(WScreen *scr, WNativeWindow win, int y, int w, int h, int type);
|
||||
void wl_balloon_init(WScreen *scr);
|
||||
void wl_balloon_show(WScreen *scr, void *bal_ptr);
|
||||
void wl_context_init(void);
|
||||
int wl_window_get_command(WNativeWindow win, char ***argv_out, int *argc_out);
|
||||
void wl_clip_icon_paint(WAppIcon *aicon);
|
||||
void wl_drawer_icon_paint(WAppIcon *aicon);
|
||||
void wl_pointer_change_cursor(int cursor_id);
|
||||
void wl_pointer_get_position(int *x, int *y);
|
||||
void wl_event_handle_signal_exit(void);
|
||||
unsigned long wl_keysym_from_name(const char *name);
|
||||
RContext *wl_create_rcontext(int screen_number, RContextAttributes *attribs);
|
||||
int wl_parse_color(WScreen *scr, const char *name, WMColorRGB *color_out);
|
||||
extern void *W_RegisterBacking(unsigned long id, void *img);
|
||||
extern void W_UnregisterBacking(unsigned long id);
|
||||
|
||||
|
|
@ -82,46 +106,7 @@ void wl_noop_prop_set_wmaker_protocols(WNativeWindow root) { (void)root; }
|
|||
void wl_noop_prop_set_icon_tile(WScreen *scr, RImage *image) { (void)scr; (void)image; }
|
||||
void wl_noop_prop_cleanup(WNativeWindow root) { (void)root; }
|
||||
|
||||
void wl_noop_client_restore(WWindow *wwin) { (void)wwin; }
|
||||
void wl_client_set_state(WWindow *wwin, int state, WNativeWindow icon_win)
|
||||
{
|
||||
(void)icon_win;
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(wwin->client_win);
|
||||
if (!v)
|
||||
return;
|
||||
switch (state) {
|
||||
case 3: /* WM_STATE_ICONIC */
|
||||
if (v->scene_node)
|
||||
wlr_scene_node_set_enabled(&v->scene_node->node, false);
|
||||
break;
|
||||
case 1: /* WM_STATE_NORMAL */
|
||||
if (v->scene_node)
|
||||
wlr_scene_node_set_enabled(&v->scene_node->node, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void wl_client_set_maximized(WNativeWindow win, int maximized)
|
||||
{
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(win);
|
||||
if (!v) return;
|
||||
if (v->xdg_surface && v->xdg_surface->toplevel)
|
||||
wlr_xdg_toplevel_set_maximized(v->xdg_surface->toplevel, maximized);
|
||||
}
|
||||
|
||||
void wl_client_send_protocol(WWindow *wwin, unsigned long protocol,
|
||||
unsigned long timestamp)
|
||||
{
|
||||
(void)protocol; (void)timestamp;
|
||||
wm_backend->client_close(wwin->client_win);
|
||||
}
|
||||
|
||||
void wl_client_kill_impl(WWindow *wwin)
|
||||
{
|
||||
wm_backend->client_close(wwin->client_win);
|
||||
}
|
||||
|
||||
void wl_noop_client_get_colormap_windows(WWindow *wwin) { (void)wwin; }
|
||||
void wl_noop_client_restore(WWindow *wwin) { (void)wwin; }void wl_noop_client_get_colormap_windows(WWindow *wwin) { (void)wwin; }
|
||||
|
||||
void wl_noop_eat_expose(void) { }
|
||||
|
||||
|
|
@ -139,25 +124,6 @@ char *wl_noop_get_text_selection(WScreen *scr, unsigned long selection)
|
|||
char *wl_noop_get_shortcut_string(WShortKey key)
|
||||
{ (void)key; return NULL; }
|
||||
|
||||
char *wl_get_command_for_window(WNativeWindow win, int elements)
|
||||
{
|
||||
char **argv, *command = NULL;
|
||||
int argc;
|
||||
if (!wm_backend->icccm_get_command(win, &argv, &argc))
|
||||
return NULL;
|
||||
if (argc > 0 && argv != NULL) {
|
||||
if (elements == 0)
|
||||
elements = argc;
|
||||
command = wtokenjoin(argv, WMIN(argc, elements));
|
||||
if (command[0] == 0) {
|
||||
wfree(command);
|
||||
command = NULL;
|
||||
}
|
||||
}
|
||||
wm_backend->icccm_free_command(argv);
|
||||
return command;
|
||||
}
|
||||
|
||||
void wl_noop_icon_update_pixmap(WIcon *icon) { (void)icon; }
|
||||
|
||||
/*
|
||||
|
|
@ -172,159 +138,7 @@ void wl_noop_icon_update_pixmap(WIcon *icon) { (void)icon; }
|
|||
|
||||
|
||||
void wl_noop_restore_desktop(WScreen *scr) { (void)scr; }
|
||||
void wl_noop_wipe_desktop(WScreen *scr) { (void)scr; }
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void wl_noop_free_color(WScreen *scr, unsigned long pixel)
|
||||
void wl_noop_wipe_desktop(WScreen *scr) { (void)scr; }void wl_noop_free_color(WScreen *scr, unsigned long pixel)
|
||||
{ (void)scr; (void)pixel; }
|
||||
|
||||
void wl_noop_colormap_install(WScreen *scr, WWindow *wwin)
|
||||
|
|
@ -339,323 +153,9 @@ void wl_noop_appicon_bounce(WAppIcon *aicon, void *data)
|
|||
{ (void)aicon; (void)data; }
|
||||
|
||||
void wl_noop_manage_all_windows(WScreen *scr, int crash_recovery)
|
||||
{ (void)scr; (void)crash_recovery; }
|
||||
|
||||
void wl_event_handle_signal_exit(void)
|
||||
{
|
||||
wm_backend->event_loop_terminate();
|
||||
}
|
||||
|
||||
void wl_noop_icon_select(WIcon *icon) { (void)icon; }
|
||||
void wl_noop_icon_change_title(WIcon *icon, WWindow *wwin) { (void)icon; (void)wwin; }
|
||||
void wl_clip_icon_paint(WAppIcon *aicon)
|
||||
{
|
||||
if (!aicon || !aicon->icon || !aicon->icon->core)
|
||||
return;
|
||||
|
||||
WScreen *scr = aicon->icon->core->screen_ptr;
|
||||
if (!scr->workspaces || !scr->workspaces[scr->current_workspace])
|
||||
return;
|
||||
|
||||
/* Paint base tile + icon image */
|
||||
wl_appicon_paint(aicon);
|
||||
|
||||
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)aicon->icon->core->window);
|
||||
if (!fb || !fb->image)
|
||||
return;
|
||||
|
||||
WWorkspace *workspace = scr->workspaces[scr->current_workspace];
|
||||
/* Use aicon->dock to read collapsed state — workspace->clip may be a
|
||||
* stale freed pointer during wWorkspaceRestoreState (the old clip is
|
||||
* destroyed before scr->workspaces[i]->clip is reassigned, and we
|
||||
* are called from wDockCreate inside that gap). */
|
||||
int collapsed = aicon->dock ? aicon->dock->collapsed : 0;
|
||||
WMColor *color;
|
||||
if (wPreferences.flags.noclip || !collapsed)
|
||||
color = scr->clip_title_color[CLIP_NORMAL];
|
||||
else
|
||||
color = scr->clip_title_color[CLIP_COLLAPSED];
|
||||
if (!color || !scr->clip_title_font)
|
||||
return;
|
||||
|
||||
int size = wPreferences.icon_size;
|
||||
WMDrawable d = (WMDrawable)(uintptr_t)fb->image;
|
||||
|
||||
/* Draw workspace number at top center */
|
||||
char ws_number[20];
|
||||
snprintf(ws_number, sizeof ws_number, "%u", scr->current_workspace + 1);
|
||||
int nlength = strlen(ws_number);
|
||||
int tx = (size / 2 - WMWidthOfString(scr->clip_title_font, ws_number, nlength)) / 2;
|
||||
WMDrawString(scr->wmscreen, d, color, scr->clip_title_font, tx, 2, ws_number, nlength);
|
||||
|
||||
/* Draw workspace name at bottom */
|
||||
if (wPreferences.show_clip_title) {
|
||||
int length = strlen(workspace->name);
|
||||
int ty = size - WMFontHeight(scr->clip_title_font) - 3;
|
||||
tx = CLIP_BUTTON_SIZE * size / 64;
|
||||
WMDrawString(scr->wmscreen, d, color, scr->clip_title_font, tx, ty, workspace->name, length);
|
||||
}
|
||||
|
||||
/* Commit updated buffer */
|
||||
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
|
||||
}
|
||||
void wl_drawer_icon_paint(WAppIcon *aicon)
|
||||
{
|
||||
if (!aicon || !aicon->icon || !aicon->icon->core)
|
||||
return;
|
||||
|
||||
wl_appicon_paint(aicon);
|
||||
|
||||
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)aicon->icon->core->window);
|
||||
if (!fb || !fb->image)
|
||||
return;
|
||||
|
||||
WScreen *scr = aicon->icon->core->screen_ptr;
|
||||
WMColor *color;
|
||||
if (!aicon->dock->collapsed)
|
||||
color = scr->clip_title_color[CLIP_NORMAL];
|
||||
else
|
||||
color = scr->clip_title_color[CLIP_COLLAPSED];
|
||||
if (!color)
|
||||
return;
|
||||
|
||||
int size = wPreferences.icon_size;
|
||||
uint32_t pixel = ((uint32_t)0xFF << 24) |
|
||||
((uint32_t)WMRedComponentOfColor(color) >> 8 << 16) |
|
||||
((uint32_t)WMGreenComponentOfColor(color) >> 8 << 8) |
|
||||
((uint32_t)WMBlueComponentOfColor(color) >> 8);
|
||||
uint32_t *data = (uint32_t *)pixman_image_get_data(fb->image);
|
||||
int stride = pixman_image_get_stride(fb->image) / 4;
|
||||
|
||||
/* Draw directional arrow (triangle) */
|
||||
int cx, cy = size / 2;
|
||||
if (aicon->dock->on_right_side) {
|
||||
/* Arrow pointing left: tip at x=5, base at x=10 */
|
||||
for (int dy = -5; dy <= 5; dy++) {
|
||||
int row = cy + dy;
|
||||
if (row < 0 || row >= size) continue;
|
||||
int width = 5 - abs(dy);
|
||||
for (int dx = 0; dx <= width; dx++) {
|
||||
cx = 10 - dx;
|
||||
if (cx >= 0 && cx < size)
|
||||
data[row * stride + cx] = pixel;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Arrow pointing right: tip at x=size-6, base at x=size-11 */
|
||||
for (int dy = -5; dy <= 5; dy++) {
|
||||
int row = cy + dy;
|
||||
if (row < 0 || row >= size) continue;
|
||||
int width = 5 - abs(dy);
|
||||
for (int dx = 0; dx <= width; dx++) {
|
||||
cx = size - 11 + dx;
|
||||
if (cx >= 0 && cx < size)
|
||||
data[row * stride + cx] = pixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
|
||||
}
|
||||
void wl_balloon_init(WScreen *scr)
|
||||
{
|
||||
scr->balloon = wmalloc(sizeof(WBalloon));
|
||||
memset(scr->balloon, 0, sizeof(WBalloon));
|
||||
|
||||
/* Create a frame_buf in the overlay layer for balloon tooltips */
|
||||
if (wl_state.scene) {
|
||||
struct wl_frame_buf *fb = wmalloc(sizeof(*fb));
|
||||
memset(fb, 0, sizeof(*fb));
|
||||
|
||||
int w = 1, h = 1;
|
||||
fb->image = pixman_image_create_bits(PIXMAN_a8r8g8b8, w, h, NULL, 0);
|
||||
wlr_buffer_init(&fb->base, &frame_buf_impl, w, h);
|
||||
fb->id = wl_state.next_synthetic_id++;
|
||||
fb->width = w;
|
||||
fb->height = h;
|
||||
|
||||
struct wlr_scene_tree *parent = wl_state.level_trees[WL_LAYER_OVERLAY]
|
||||
? wl_state.level_trees[WL_LAYER_OVERLAY] : &wl_state.scene->tree;
|
||||
fb->tree = wlr_scene_tree_create(parent);
|
||||
if (fb->tree) {
|
||||
fb_attach_tree_listener(fb);
|
||||
wlr_scene_node_set_position(&fb->tree->node, 0, 0);
|
||||
fb->scene_buf = wlr_scene_buffer_create(fb->tree, &fb->base);
|
||||
if (fb->scene_buf) {
|
||||
fb_attach_scene_buf_listener(fb);
|
||||
wlr_scene_node_set_position(&fb->scene_buf->node, 0, 0);
|
||||
}
|
||||
wlr_scene_node_set_enabled(&fb->tree->node, false);
|
||||
}
|
||||
|
||||
wl_list_insert(&wl_state.frame_list, &fb->link);
|
||||
W_RegisterBacking(fb->id, fb->image);
|
||||
scr->balloon->window = (WNativeWindow)fb->id;
|
||||
}
|
||||
}
|
||||
void wl_noop_do_kaboom(WScreen *scr, WNativeWindow win, int x, int y)
|
||||
{ (void)scr; (void)win; (void)x; (void)y; }
|
||||
void wl_menu_paint_entry(WMenu *menu, int index, int selected)
|
||||
{
|
||||
if (!menu || !menu->menu || !menu->menu->window)
|
||||
return;
|
||||
|
||||
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)menu->menu->window);
|
||||
if (!fb || !fb->image)
|
||||
return;
|
||||
|
||||
/* Guard against painting before wMenuRealize: entry_height is 0,
|
||||
* fb->image is the initial 1x10 placeholder, and the bevel-line
|
||||
* computations below would write outside the pixman buffer.
|
||||
* wMenuSetEnabled() in particular triggers paints on the brother
|
||||
* during updateOptionsMenu before the menu is realized. */
|
||||
if (menu->entry_height <= 0 || fb->width <= 1 || fb->height <= 10)
|
||||
return;
|
||||
|
||||
WScreen *scr = menu->frame->screen_ptr;
|
||||
WMenuEntry *entry = menu->entries[index];
|
||||
int y = menu->entry_height * index;
|
||||
int h = menu->entry_height;
|
||||
int w = fb->width;
|
||||
uint32_t *dst = (uint32_t *)pixman_image_get_data(fb->image);
|
||||
int stride = pixman_image_get_stride(fb->image) / 4;
|
||||
|
||||
/* Background color from appearance preferences */
|
||||
uint32_t bg;
|
||||
if (selected) {
|
||||
WMColor *sc = scr->select_color;
|
||||
bg = 0xFF000000 | ((uint32_t)WMRedComponentOfColor(sc) >> 8 << 16)
|
||||
| ((uint32_t)WMGreenComponentOfColor(sc) >> 8 << 8)
|
||||
| ((uint32_t)WMBlueComponentOfColor(sc) >> 8);
|
||||
} else {
|
||||
WTexSolid *ts = (WTexSolid *)scr->menu_item_texture;
|
||||
if (ts)
|
||||
bg = 0xFF000000 | ((uint32_t)ts->normal.red >> 8 << 16)
|
||||
| ((uint32_t)ts->normal.green >> 8 << 8)
|
||||
| ((uint32_t)ts->normal.blue >> 8);
|
||||
else
|
||||
bg = 0xFFAEAAAE;
|
||||
}
|
||||
|
||||
for (int row = y; row < y + h && row < fb->height; row++)
|
||||
for (int col = 0; col < w; col++)
|
||||
dst[row * stride + col] = bg;
|
||||
|
||||
/* Draw text using WINGs font backend (renders via PangoFT2 → pixman) */
|
||||
WMColor *color = selected ? scr->select_text_color :
|
||||
(entry->flags.enabled ? scr->mtext_color : scr->dtext_color);
|
||||
WMFont *font = scr->menu_entry_font;
|
||||
WMDrawable d = (WMDrawable)(uintptr_t)fb->image;
|
||||
|
||||
if (entry->text && font && color) {
|
||||
int text_y = y + 3;
|
||||
WMDrawString(scr->wmscreen, d, color, font,
|
||||
8, text_y, entry->text, strlen(entry->text));
|
||||
}
|
||||
|
||||
if (entry->rtext && entry->cascade < 0 && font && color) {
|
||||
int tw = WMWidthOfString(font, entry->rtext, strlen(entry->rtext));
|
||||
int text_y = y + 3;
|
||||
WMDrawString(scr->wmscreen, d, color, font,
|
||||
w - 8 - tw, text_y, entry->rtext, strlen(entry->rtext));
|
||||
}
|
||||
|
||||
/* Draw cascade arrow for submenus (3D right-pointing triangle matching X11) */
|
||||
if (entry->cascade >= 0) {
|
||||
WTexSolid *aux = (WTexSolid *)scr->menu_item_texture;
|
||||
uint32_t dim_c = 0xFF606060;
|
||||
uint32_t light_c = 0xFFE0E0E0;
|
||||
uint32_t dark_c = 0xFF303030;
|
||||
if (aux) {
|
||||
dim_c = 0xFF000000 | ((uint32_t)aux->dim.red >> 8 << 16)
|
||||
| ((uint32_t)aux->dim.green >> 8 << 8)
|
||||
| ((uint32_t)aux->dim.blue >> 8);
|
||||
light_c = 0xFF000000 | ((uint32_t)aux->light.red >> 8 << 16)
|
||||
| ((uint32_t)aux->light.green >> 8 << 8)
|
||||
| ((uint32_t)aux->light.blue >> 8);
|
||||
dark_c = 0xFF000000 | ((uint32_t)aux->dark.red >> 8 << 16)
|
||||
| ((uint32_t)aux->dark.green >> 8 << 8)
|
||||
| ((uint32_t)aux->dark.blue >> 8);
|
||||
}
|
||||
/* Top edge: dim line from (w-11, y+6) to (w-6, y+h/2-1) */
|
||||
int x0 = w - 11, y0 = y + 6, x1 = w - 6, y1 = y + h / 2 - 1;
|
||||
for (int i = 0; i <= 5; i++) {
|
||||
int lx = x0 + i * (x1 - x0) / 5;
|
||||
int ly = y0 + i * (y1 - y0) / 5;
|
||||
if (lx >= 0 && lx < (int)fb->width && ly >= 0 && ly < fb->height)
|
||||
dst[ly * stride + lx] = dim_c;
|
||||
}
|
||||
/* Bottom edge: light line from (w-11, y+h-8) to (w-6, y+h/2-1) */
|
||||
y0 = y + h - 8;
|
||||
for (int i = 0; i <= 5; i++) {
|
||||
int lx = x0 + i * (x1 - x0) / 5;
|
||||
int ly = y0 + i * (y1 - y0) / 5;
|
||||
if (lx >= 0 && lx < (int)fb->width && ly >= 0 && ly < fb->height)
|
||||
dst[ly * stride + lx] = light_c;
|
||||
}
|
||||
/* Left edge: dark vertical line at w-12 from y+6 to y+h-8 */
|
||||
int lx = w - 12;
|
||||
if (lx >= 0 && lx < (int)fb->width)
|
||||
for (int ly = y + 6; ly <= y + h - 8 && ly < fb->height; ly++)
|
||||
if (ly >= 0)
|
||||
dst[ly * stride + lx] = dark_c;
|
||||
}
|
||||
|
||||
/* Bevel lines (separators between entries) */
|
||||
uint32_t light = 0xFFDDDDDD;
|
||||
uint32_t dark = 0xFF555555;
|
||||
|
||||
/* Left edge - light */
|
||||
for (int row = y; row < y + h && row < fb->height; row++)
|
||||
dst[row * stride] = light;
|
||||
/* Right edge - dark */
|
||||
for (int row = y; row < y + h && row < fb->height; row++)
|
||||
if (w - 1 < fb->width)
|
||||
dst[row * stride + (w - 1)] = dark;
|
||||
/* Top line - light (skip first entry) */
|
||||
if (index > 0 && y < fb->height)
|
||||
for (int col = 0; col < w && col < fb->width; col++)
|
||||
dst[y * stride + col] = light;
|
||||
/* Bottom line - dark (skip last entry) */
|
||||
if (index < menu->entry_no - 1 && y + h - 1 < fb->height)
|
||||
for (int col = 0; col < w && col < fb->width; col++)
|
||||
dst[(y + h - 1) * stride + col] = dark;
|
||||
|
||||
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
|
||||
}
|
||||
|
||||
void wl_menu_draw_frame(WScreen *scr, WNativeWindow win, int y, int w, int h, int type)
|
||||
{
|
||||
struct wl_frame_buf *fb = frame_buf_find(win);
|
||||
if (!fb || !fb->image)
|
||||
return;
|
||||
|
||||
uint32_t *dst = (uint32_t *)pixman_image_get_data(fb->image);
|
||||
int stride = pixman_image_get_stride(fb->image) / 4;
|
||||
uint32_t dark = 0xFF555555;
|
||||
uint32_t light = 0xFFDDDDDD;
|
||||
|
||||
/* Right edge */
|
||||
for (int row = y; row < y + h && row < fb->height; row++)
|
||||
if (w - 1 < fb->width)
|
||||
dst[row * stride + (w - 1)] = dark;
|
||||
/* Bottom edge */
|
||||
if (y + h - 1 < fb->height)
|
||||
for (int col = 0; col < w && col < fb->width; col++)
|
||||
dst[(y + h - 1) * stride + col] = dark;
|
||||
/* Left edge */
|
||||
for (int row = y; row < y + h && row < fb->height; row++)
|
||||
dst[row * stride] = light;
|
||||
/* Top edge */
|
||||
if (y < fb->height)
|
||||
for (int col = 0; col < w && col < fb->width; col++)
|
||||
dst[y * stride + col] = light;
|
||||
|
||||
(void)scr; (void)type;
|
||||
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
|
||||
}
|
||||
|
||||
void wl_noop_draw_bevel(WNativeWindow d, unsigned int width, unsigned int height,
|
||||
{ (void)scr; (void)crash_recovery; }void wl_noop_icon_select(WIcon *icon) { (void)icon; }
|
||||
void wl_noop_icon_change_title(WIcon *icon, WWindow *wwin) { (void)icon; (void)wwin; }void wl_noop_do_kaboom(WScreen *scr, WNativeWindow win, int x, int y)
|
||||
{ (void)scr; (void)win; (void)x; (void)y; }void wl_noop_draw_bevel(WNativeWindow d, unsigned int width, unsigned int height,
|
||||
WTexSolid *texture, int relief)
|
||||
{ (void)d; (void)width; (void)height; (void)texture; (void)relief; }
|
||||
|
||||
|
|
@ -684,70 +184,7 @@ WPixmap *wl_noop_pixmap_create_from_xbm(WScreen *scr, char *data, char *mask,
|
|||
{ (void)scr; (void)data; (void)mask; (void)width; (void)height; (void)fg; (void)bg; return NULL; }
|
||||
|
||||
WPixmap *wl_noop_pixmap_create(unsigned long image, unsigned long mask)
|
||||
{ (void)image; (void)mask; return NULL; }
|
||||
|
||||
unsigned long wl_keysym_from_name(const char *name)
|
||||
{
|
||||
return (unsigned long)xkb_keysym_from_name(name, XKB_KEYSYM_NO_FLAGS);
|
||||
}
|
||||
|
||||
void wl_frame_paint_resizebar(WFrameWindow *fwin)
|
||||
{
|
||||
/* Resizebar is rendered into the parent frame buffer by wl_frame_paint.
|
||||
* Don't commit a separate buffer here — it would overlay the texture. */
|
||||
(void)fwin;
|
||||
}
|
||||
|
||||
void wl_frame_paint_titlebar(WFrameWindow *fwin, int state)
|
||||
{
|
||||
if (!fwin->titlebar || !fwin->titlebar->window)
|
||||
return;
|
||||
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)fwin->titlebar->window);
|
||||
if (!fb || !fb->image)
|
||||
return;
|
||||
|
||||
WScreen *scr = fwin->screen_ptr;
|
||||
uint32_t *dst = (uint32_t *)pixman_image_get_data(fb->image);
|
||||
int stride = pixman_image_get_stride(fb->image) / 4;
|
||||
|
||||
/* Background: use texture color or default */
|
||||
uint32_t bg;
|
||||
if (fwin->title_texture[state] &&
|
||||
fwin->title_texture[state]->any.type == WTEX_SOLID) {
|
||||
unsigned long px = fwin->title_texture[state]->solid.normal.pixel;
|
||||
bg = 0xFF000000 | (px & 0xFFFFFF);
|
||||
} else {
|
||||
bg = (state == 0) ? 0xFF4A6984 : 0xFF808080; /* focused blue / unfocused grey */
|
||||
}
|
||||
|
||||
for (int row = 0; row < fb->height; row++)
|
||||
for (int col = 0; col < fb->width; col++)
|
||||
dst[row * stride + col] = bg;
|
||||
|
||||
/* Draw title text */
|
||||
if (fwin->title && fwin->font && fwin->title_color[state]) {
|
||||
char *title = ShrinkString(*fwin->font, fwin->title, fb->width - 12);
|
||||
int titlelen = strlen(title);
|
||||
int tw = WMWidthOfString(*fwin->font, title, titlelen);
|
||||
int x;
|
||||
switch (fwin->flags.justification) {
|
||||
case WTJ_LEFT: x = 6; break;
|
||||
case WTJ_RIGHT: x = fb->width - tw - 6; break;
|
||||
default: x = (fb->width - tw) / 2; break;
|
||||
}
|
||||
int fh = WMFontHeight(*fwin->font);
|
||||
int y = (fb->height - fh) / 2;
|
||||
|
||||
WMDrawable d = (WMDrawable)(uintptr_t)fb->image;
|
||||
WMDrawString(scr->wmscreen, d, fwin->title_color[state],
|
||||
*fwin->font, x, y, title, titlelen);
|
||||
wfree(title);
|
||||
}
|
||||
|
||||
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
|
||||
}
|
||||
|
||||
WNativeWindow wl_noop_prop_get_client_leader(WNativeWindow window) { (void)window; return WNATIVE_NONE; }
|
||||
{ (void)image; (void)mask; return NULL; }WNativeWindow wl_noop_prop_get_client_leader(WNativeWindow window) { (void)window; return WNATIVE_NONE; }
|
||||
int wl_noop_prop_get_window_state(WNativeWindow window) { (void)window; return -1; }
|
||||
|
||||
void wl_noop_setup_modifier_lock_masks(void) { }
|
||||
|
|
@ -755,43 +192,16 @@ void wl_noop_key_grab_hacked(WNativeWindow window, int keycode, unsigned int mod
|
|||
{ (void)window; (void)keycode; (void)modifiers; }
|
||||
void wl_noop_button_grab_hacked(unsigned int button, unsigned int modifiers,
|
||||
WNativeWindow window, int owner_events, unsigned int event_mask)
|
||||
{ (void)button; (void)modifiers; (void)window; (void)owner_events; (void)event_mask; }
|
||||
void wl_context_init(void)
|
||||
{
|
||||
/* Wayland uses a hash table instead of X11 contexts */
|
||||
w_global.context.client_win = 1;
|
||||
w_global.context.app_win = 2;
|
||||
w_global.context.stack = 3;
|
||||
}
|
||||
void wl_noop_query_tree(WNativeWindow root, WNativeWindow **children_out,
|
||||
{ (void)button; (void)modifiers; (void)window; (void)owner_events; (void)event_mask; }void wl_noop_query_tree(WNativeWindow root, WNativeWindow **children_out,
|
||||
unsigned int *nchildren_out)
|
||||
{ (void)root; *children_out = NULL; *nchildren_out = 0; }
|
||||
|
||||
WScreen *wl_noop_screen_for_window(WNativeWindow window)
|
||||
{ (void)window; return wScreenWithNumber(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); }
|
||||
int wl_noop_cursor_create_from_files(WScreen *scr, const char *bitmap_path,
|
||||
{ (void)window; return wScreenWithNumber(0); }int wl_noop_cursor_create_from_files(WScreen *scr, const char *bitmap_path,
|
||||
const char *mask_path, WMNativeCursor *cursor_out)
|
||||
{ (void)scr; (void)bitmap_path; (void)mask_path; (void)cursor_out; return 0; }
|
||||
void wl_noop_cursor_free(WMNativeCursor cursor) { (void)cursor; }
|
||||
void wl_noop_cursor_set(WNativeWindow window, WMNativeCursor cursor) { (void)window; (void)cursor; }
|
||||
void wl_pointer_change_cursor(int cursor_id)
|
||||
{
|
||||
const char *name;
|
||||
switch (cursor_id) {
|
||||
case 1: /* WCUR_MOVE */ name = "fleur"; break;
|
||||
case 2: /* WCUR_RESIZE */ name = "bottom_right_corner"; break;
|
||||
case 7: /* WCUR_WAIT */ name = "watch"; break;
|
||||
case 8: /* WCUR_ARROW */ name = "left_ptr"; break;
|
||||
case 9: /* WCUR_QUESTION */name = "question_arrow"; break;
|
||||
case 10:/* WCUR_TEXT */ name = "xterm"; break;
|
||||
default: name = "left_ptr"; break;
|
||||
}
|
||||
wl_set_cursor_image(name);
|
||||
}
|
||||
void wl_noop_appicon_paint_dock_dots(WAppIcon *aicon, void *wapp)
|
||||
void wl_noop_cursor_set(WNativeWindow window, WMNativeCursor cursor) { (void)window; (void)cursor; }void wl_noop_appicon_paint_dock_dots(WAppIcon *aicon, void *wapp)
|
||||
{ (void)aicon; (void)wapp; }
|
||||
|
||||
int wl_noop_pixmap_get_size(unsigned long drawable, unsigned int *w, unsigned int *h, unsigned int *depth)
|
||||
|
|
@ -801,79 +211,7 @@ void wl_noop_icon_paint_title_bg(WScreen *scr, unsigned long pixmap, int height)
|
|||
void wl_noop_icon_select_paint(WIcon *icon, int step)
|
||||
{ (void)icon; (void)step; }
|
||||
unsigned long wl_noop_window_get_event_mask(WNativeWindow window)
|
||||
{ (void)window; return 0; }
|
||||
void wl_balloon_show(WScreen *scr, void *bal_ptr)
|
||||
{
|
||||
WBalloon *bal = (WBalloon *)bal_ptr;
|
||||
if (!bal->text || !bal->text[0])
|
||||
return;
|
||||
|
||||
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)bal->window);
|
||||
if (!fb)
|
||||
return;
|
||||
|
||||
WMFont *font = scr->info_text_font;
|
||||
int textlen = strlen(bal->text);
|
||||
int tw = WMWidthOfString(font, bal->text, textlen);
|
||||
int th = WMFontHeight(font);
|
||||
int pad = 4;
|
||||
int bw = tw + pad * 2;
|
||||
int bh = th + pad * 2;
|
||||
|
||||
/* Resize pixman buffer if needed */
|
||||
if (bw != fb->width || bh != fb->height) {
|
||||
W_UnregisterBacking(fb->id);
|
||||
pixman_image_unref(fb->image);
|
||||
fb->image = pixman_image_create_bits(PIXMAN_a8r8g8b8, bw, bh, NULL, 0);
|
||||
fb->width = bw;
|
||||
fb->height = bh;
|
||||
fb->base.width = bw;
|
||||
fb->base.height = bh;
|
||||
W_RegisterBacking(fb->id, fb->image);
|
||||
}
|
||||
|
||||
/* Fill pale yellow background */
|
||||
uint32_t *data = pixman_image_get_data(fb->image);
|
||||
for (int i = 0; i < bw * bh; i++)
|
||||
data[i] = 0xFFFFFFE0;
|
||||
|
||||
/* 1px black border */
|
||||
for (int x = 0; x < bw; x++) {
|
||||
data[x] = 0xFF000000;
|
||||
data[(bh - 1) * bw + x] = 0xFF000000;
|
||||
}
|
||||
for (int y = 0; y < bh; y++) {
|
||||
data[y * bw] = 0xFF000000;
|
||||
data[y * bw + bw - 1] = 0xFF000000;
|
||||
}
|
||||
|
||||
/* Draw text */
|
||||
WMDrawString(scr->wmscreen, (WMDrawable)fb->id, scr->black, font,
|
||||
pad, pad, bal->text, textlen);
|
||||
|
||||
/* Position near objectWindow */
|
||||
int bx = 0, by = 0;
|
||||
struct wl_frame_buf *obj = frame_buf_find((WNativeWindow)bal->objectWindow);
|
||||
if (obj) {
|
||||
bx = obj->x;
|
||||
by = obj->y + bal->h + 2;
|
||||
}
|
||||
|
||||
/* Clamp to screen */
|
||||
if (bx + bw > scr->scr_width)
|
||||
bx = scr->scr_width - bw;
|
||||
if (by + bh > scr->scr_height)
|
||||
by = by - bal->h - bh - 2;
|
||||
|
||||
if (fb->scene_buf) {
|
||||
wlr_scene_node_set_position(&fb->scene_buf->node, bx, by);
|
||||
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
|
||||
wlr_scene_node_set_enabled(&fb->tree->node, true);
|
||||
}
|
||||
|
||||
bal->mapped = 1;
|
||||
}
|
||||
void wl_noop_window_fill_stipple(WNativeWindow win, int x, int y, int w, int h)
|
||||
{ (void)window; return 0; }void wl_noop_window_fill_stipple(WNativeWindow win, int x, int y, int w, int h)
|
||||
{ (void)win; (void)x; (void)y; (void)w; (void)h; }
|
||||
int wl_noop_event_check_enter_leave(void *dock) { (void)dock; return 1; }
|
||||
|
||||
|
|
@ -884,95 +222,11 @@ void wl_noop_event_flush_window(WNativeWindow win, int t) { (void)win; (void)t;
|
|||
void wl_noop_event_flush_type(int t) { (void)t; }
|
||||
int wl_noop_event_check_window(WNativeWindow win, int t) { (void)win; (void)t; return 0; }
|
||||
int wl_noop_event_check_type(int t, WMEvent *e) { (void)t; (void)e; return 0; }
|
||||
void wl_noop_client_send_event(WNativeWindow win, void *d) { (void)win; (void)d; }
|
||||
void wl_client_message_forward(WMEvent *event, WNativeWindow target_win)
|
||||
{
|
||||
/* Forward OffiX DND ClientMessage to the real client_win for
|
||||
* XWayland clients. Native Wayland clients have no analog. */
|
||||
if (!wl_state.x_display || !event) return;
|
||||
XEvent *xev = (XEvent *)event->_x11_raw;
|
||||
if (!xev) return;
|
||||
xev->xclient.window = (WNativeWindow)target_win;
|
||||
XSendEvent(wl_state.x_display, (WNativeWindow)target_win, False, 0L, xev);
|
||||
}
|
||||
void wl_client_send_key(WNativeWindow win, unsigned int keycode,
|
||||
unsigned int modifier_mask, int press)
|
||||
{
|
||||
/* For XWayland clients, deliver via the X server (wl_state.x_display)
|
||||
* the same way the X11 backend does. Native Wayland clients are not
|
||||
* yet supported (would require zwp_virtual_keyboard_v1). */
|
||||
if (!wl_state.x_display) return;
|
||||
XEvent ev;
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.xkey.type = press ? KeyPress : KeyRelease;
|
||||
ev.xkey.display = wl_state.x_display;
|
||||
ev.xkey.window = (WNativeWindow)win;
|
||||
ev.xkey.root = DefaultRootWindow(wl_state.x_display);
|
||||
ev.xkey.subwindow = WM_NATIVE_NONE;
|
||||
ev.xkey.same_screen = True;
|
||||
ev.xkey.time = WM_CURRENT_TIME;
|
||||
ev.xkey.keycode = keycode;
|
||||
ev.xkey.state = modifier_mask;
|
||||
XSendEvent(wl_state.x_display, (WNativeWindow)win, press ? False : True,
|
||||
press ? WM_EVMASK_KEY_PRESS : WM_EVMASK_KEY_RELEASE, &ev);
|
||||
}
|
||||
int wl_noop_window_exists(WNativeWindow win) { (void)win; return 1; }
|
||||
void wl_noop_client_send_event(WNativeWindow win, void *d) { (void)win; (void)d; }int wl_noop_window_exists(WNativeWindow win) { (void)win; return 1; }
|
||||
void wl_noop_window_get_colormap(WNativeWindow win, unsigned long *c) { (void)win; (void)c; }
|
||||
WNativeWindow wl_noop_pointer_query_window(WNativeWindow root) { (void)root; return WNATIVE_NONE; }
|
||||
void wl_noop_dialog_paint_icon(unsigned long d, void *b, void *p, WScreen *s,
|
||||
int x, int y, int w, int h) { (void)d;(void)b;(void)p;(void)s;(void)x;(void)y;(void)w;(void)h; }
|
||||
void wl_pointer_get_position(int *x, int *y) {
|
||||
*x = (int)wl_state.pointer_x;
|
||||
*y = (int)wl_state.pointer_y;
|
||||
}
|
||||
const char *wl_noop_keysym_to_string(unsigned long ks) { (void)ks; return ""; }
|
||||
int wl_window_get_command(WNativeWindow win, char ***argv_out, int *argc_out)
|
||||
{
|
||||
/* Wayland native clients: return [app_id] as a single-arg command.
|
||||
* Most app_ids match the binary name (e.g. "foot", "firefox") so this
|
||||
* is sufficient for session restore via PATH lookup or a desktop-file
|
||||
* Exec= line.
|
||||
*
|
||||
* XWayland clients: prefer WM_COMMAND (read from wl_state.x_display)
|
||||
* and fall back to xw_surface->instance / class. */
|
||||
*argv_out = NULL;
|
||||
*argc_out = 0;
|
||||
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(win);
|
||||
if (!v) return 0;
|
||||
|
||||
const char *cmd = NULL;
|
||||
if (v->xw_surface) {
|
||||
/* XWayland: try WM_COMMAND first via the X server. */
|
||||
if (wl_state.x_display && v->xw_surface->window_id) {
|
||||
char **cmd_argv = NULL;
|
||||
int cmd_argc = 0;
|
||||
if (XGetCommand(wl_state.x_display, v->xw_surface->window_id,
|
||||
&cmd_argv, &cmd_argc) && cmd_argc > 0 && cmd_argv) {
|
||||
/* Copy to wmaker's allocator */
|
||||
*argv_out = wmalloc(sizeof(char *) * cmd_argc);
|
||||
for (int i = 0; i < cmd_argc; i++)
|
||||
(*argv_out)[i] = wstrdup(cmd_argv[i]);
|
||||
*argc_out = cmd_argc;
|
||||
XFreeStringList(cmd_argv);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
cmd = v->xw_surface->instance ? v->xw_surface->instance :
|
||||
v->xw_surface->class;
|
||||
} else if (v->xdg_surface && v->xdg_surface->toplevel) {
|
||||
cmd = v->xdg_surface->toplevel->app_id;
|
||||
}
|
||||
|
||||
if (!cmd || !*cmd) return 0;
|
||||
|
||||
*argv_out = wmalloc(sizeof(char *));
|
||||
(*argv_out)[0] = wstrdup(cmd);
|
||||
*argc_out = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int wl_noop_window_get_command(WNativeWindow win, char ***a, int *c) { (void)win; (void)a; *c=0; return 0; }
|
||||
int x, int y, int w, int h) { (void)d;(void)b;(void)p;(void)s;(void)x;(void)y;(void)w;(void)h; }const char *wl_noop_keysym_to_string(unsigned long ks) { (void)ks; return ""; }int wl_noop_window_get_command(WNativeWindow win, char ***a, int *c) { (void)win; (void)a; *c=0; return 0; }
|
||||
int wl_noop_netwm_process_client_message(WMEvent *e) { (void)e; return 0; }
|
||||
int wl_noop_xdnd_process_client_message(WMEvent *e) { (void)e; return 0; }
|
||||
void wl_noop_xdnd_process_selection(WMEvent *e) { (void)e; }
|
||||
|
|
@ -983,12 +237,6 @@ void wl_noop_netwm_check_client_hint_change(WWindow *w, void *e) { (void)w; (voi
|
|||
void wl_noop_netwm_position_splash(WWindow *w, int *x, int *y, int ww, int h) { (void)w;(void)x;(void)y;(void)ww;(void)h; }
|
||||
void wl_noop_netwm_check_initial_frame_state(WWindow *w) { (void)w; }
|
||||
|
||||
RContext *wl_create_rcontext(int screen_number, RContextAttributes *attribs)
|
||||
{
|
||||
(void)screen_number;
|
||||
return RCreateContextWayland(1920, 1080, attribs);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* vtable */
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,13 @@
|
|||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
#include <wlr/xwayland.h>
|
||||
#include "../../menu.h"
|
||||
#include "../../balloon.h"
|
||||
#include "../../framewin.h"
|
||||
#include "../../texture.h"
|
||||
#include "../../def_pixmaps.h"
|
||||
#include <wlr/interfaces/wlr_buffer.h>
|
||||
|
||||
#include "../../screen.h"
|
||||
#include "wl_types.h"
|
||||
|
||||
|
|
@ -16,6 +23,8 @@ struct wl_toplevel_view *wl_find_view_by_xdg_surface(struct wlr_xdg_surface *sur
|
|||
void wmaker_popup_apply(struct wl_toplevel_view *view);
|
||||
void frame_buf_update_children_abs(WNativeWindow parent_id);
|
||||
struct wl_frame_buf *frame_buf_find(WNativeWindow id);
|
||||
extern void *W_RegisterBacking(unsigned long id, void *img);
|
||||
extern void W_UnregisterBacking(unsigned long id);
|
||||
struct wl_toplevel_view *wl_find_view_by_id(WNativeWindow id);
|
||||
pixman_image_t *get_window_image_from_x11(Display *x_display, WNativeWindow win);
|
||||
|
||||
|
|
@ -385,3 +394,326 @@ void wl_window_add_events(WNativeWindow win, unsigned long extra_mask) { (void)w
|
|||
void wl_window_select_events(WNativeWindow win, unsigned long mask) { (void)win; (void)mask; }
|
||||
void wl_window_shape_clear(WWindow *wwin) { (void)wwin; }
|
||||
void wl_window_shape_set(WWindow *wwin) { (void)wwin; }
|
||||
void wl_menu_paint_entry(WMenu *menu, int index, int selected)
|
||||
{
|
||||
if (!menu || !menu->menu || !menu->menu->window)
|
||||
return;
|
||||
|
||||
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)menu->menu->window);
|
||||
if (!fb || !fb->image)
|
||||
return;
|
||||
|
||||
/* Guard against painting before wMenuRealize: entry_height is 0,
|
||||
* fb->image is the initial 1x10 placeholder, and the bevel-line
|
||||
* computations below would write outside the pixman buffer.
|
||||
* wMenuSetEnabled() in particular triggers paints on the brother
|
||||
* during updateOptionsMenu before the menu is realized. */
|
||||
if (menu->entry_height <= 0 || fb->width <= 1 || fb->height <= 10)
|
||||
return;
|
||||
|
||||
WScreen *scr = menu->frame->screen_ptr;
|
||||
WMenuEntry *entry = menu->entries[index];
|
||||
int y = menu->entry_height * index;
|
||||
int h = menu->entry_height;
|
||||
int w = fb->width;
|
||||
uint32_t *dst = (uint32_t *)pixman_image_get_data(fb->image);
|
||||
int stride = pixman_image_get_stride(fb->image) / 4;
|
||||
|
||||
/* Background color from appearance preferences */
|
||||
uint32_t bg;
|
||||
if (selected) {
|
||||
WMColor *sc = scr->select_color;
|
||||
bg = 0xFF000000 | ((uint32_t)WMRedComponentOfColor(sc) >> 8 << 16)
|
||||
| ((uint32_t)WMGreenComponentOfColor(sc) >> 8 << 8)
|
||||
| ((uint32_t)WMBlueComponentOfColor(sc) >> 8);
|
||||
} else {
|
||||
WTexSolid *ts = (WTexSolid *)scr->menu_item_texture;
|
||||
if (ts)
|
||||
bg = 0xFF000000 | ((uint32_t)ts->normal.red >> 8 << 16)
|
||||
| ((uint32_t)ts->normal.green >> 8 << 8)
|
||||
| ((uint32_t)ts->normal.blue >> 8);
|
||||
else
|
||||
bg = 0xFFAEAAAE;
|
||||
}
|
||||
|
||||
for (int row = y; row < y + h && row < fb->height; row++)
|
||||
for (int col = 0; col < w; col++)
|
||||
dst[row * stride + col] = bg;
|
||||
|
||||
/* Draw text using WINGs font backend (renders via PangoFT2 → pixman) */
|
||||
WMColor *color = selected ? scr->select_text_color :
|
||||
(entry->flags.enabled ? scr->mtext_color : scr->dtext_color);
|
||||
WMFont *font = scr->menu_entry_font;
|
||||
WMDrawable d = (WMDrawable)(uintptr_t)fb->image;
|
||||
|
||||
if (entry->text && font && color) {
|
||||
int text_y = y + 3;
|
||||
WMDrawString(scr->wmscreen, d, color, font,
|
||||
8, text_y, entry->text, strlen(entry->text));
|
||||
}
|
||||
|
||||
if (entry->rtext && entry->cascade < 0 && font && color) {
|
||||
int tw = WMWidthOfString(font, entry->rtext, strlen(entry->rtext));
|
||||
int text_y = y + 3;
|
||||
WMDrawString(scr->wmscreen, d, color, font,
|
||||
w - 8 - tw, text_y, entry->rtext, strlen(entry->rtext));
|
||||
}
|
||||
|
||||
/* Draw cascade arrow for submenus (3D right-pointing triangle matching X11) */
|
||||
if (entry->cascade >= 0) {
|
||||
WTexSolid *aux = (WTexSolid *)scr->menu_item_texture;
|
||||
uint32_t dim_c = 0xFF606060;
|
||||
uint32_t light_c = 0xFFE0E0E0;
|
||||
uint32_t dark_c = 0xFF303030;
|
||||
if (aux) {
|
||||
dim_c = 0xFF000000 | ((uint32_t)aux->dim.red >> 8 << 16)
|
||||
| ((uint32_t)aux->dim.green >> 8 << 8)
|
||||
| ((uint32_t)aux->dim.blue >> 8);
|
||||
light_c = 0xFF000000 | ((uint32_t)aux->light.red >> 8 << 16)
|
||||
| ((uint32_t)aux->light.green >> 8 << 8)
|
||||
| ((uint32_t)aux->light.blue >> 8);
|
||||
dark_c = 0xFF000000 | ((uint32_t)aux->dark.red >> 8 << 16)
|
||||
| ((uint32_t)aux->dark.green >> 8 << 8)
|
||||
| ((uint32_t)aux->dark.blue >> 8);
|
||||
}
|
||||
/* Top edge: dim line from (w-11, y+6) to (w-6, y+h/2-1) */
|
||||
int x0 = w - 11, y0 = y + 6, x1 = w - 6, y1 = y + h / 2 - 1;
|
||||
for (int i = 0; i <= 5; i++) {
|
||||
int lx = x0 + i * (x1 - x0) / 5;
|
||||
int ly = y0 + i * (y1 - y0) / 5;
|
||||
if (lx >= 0 && lx < (int)fb->width && ly >= 0 && ly < fb->height)
|
||||
dst[ly * stride + lx] = dim_c;
|
||||
}
|
||||
/* Bottom edge: light line from (w-11, y+h-8) to (w-6, y+h/2-1) */
|
||||
y0 = y + h - 8;
|
||||
for (int i = 0; i <= 5; i++) {
|
||||
int lx = x0 + i * (x1 - x0) / 5;
|
||||
int ly = y0 + i * (y1 - y0) / 5;
|
||||
if (lx >= 0 && lx < (int)fb->width && ly >= 0 && ly < fb->height)
|
||||
dst[ly * stride + lx] = light_c;
|
||||
}
|
||||
/* Left edge: dark vertical line at w-12 from y+6 to y+h-8 */
|
||||
int lx = w - 12;
|
||||
if (lx >= 0 && lx < (int)fb->width)
|
||||
for (int ly = y + 6; ly <= y + h - 8 && ly < fb->height; ly++)
|
||||
if (ly >= 0)
|
||||
dst[ly * stride + lx] = dark_c;
|
||||
}
|
||||
|
||||
/* Bevel lines (separators between entries) */
|
||||
uint32_t light = 0xFFDDDDDD;
|
||||
uint32_t dark = 0xFF555555;
|
||||
|
||||
/* Left edge - light */
|
||||
for (int row = y; row < y + h && row < fb->height; row++)
|
||||
dst[row * stride] = light;
|
||||
/* Right edge - dark */
|
||||
for (int row = y; row < y + h && row < fb->height; row++)
|
||||
if (w - 1 < fb->width)
|
||||
dst[row * stride + (w - 1)] = dark;
|
||||
/* Top line - light (skip first entry) */
|
||||
if (index > 0 && y < fb->height)
|
||||
for (int col = 0; col < w && col < fb->width; col++)
|
||||
dst[y * stride + col] = light;
|
||||
/* Bottom line - dark (skip last entry) */
|
||||
if (index < menu->entry_no - 1 && y + h - 1 < fb->height)
|
||||
for (int col = 0; col < w && col < fb->width; col++)
|
||||
dst[(y + h - 1) * stride + col] = dark;
|
||||
|
||||
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
|
||||
}
|
||||
|
||||
void wl_menu_draw_frame(WScreen *scr, WNativeWindow win, int y, int w, int h, int type)
|
||||
{
|
||||
struct wl_frame_buf *fb = frame_buf_find(win);
|
||||
if (!fb || !fb->image)
|
||||
return;
|
||||
|
||||
uint32_t *dst = (uint32_t *)pixman_image_get_data(fb->image);
|
||||
int stride = pixman_image_get_stride(fb->image) / 4;
|
||||
uint32_t dark = 0xFF555555;
|
||||
uint32_t light = 0xFFDDDDDD;
|
||||
|
||||
/* Right edge */
|
||||
for (int row = y; row < y + h && row < fb->height; row++)
|
||||
if (w - 1 < fb->width)
|
||||
dst[row * stride + (w - 1)] = dark;
|
||||
/* Bottom edge */
|
||||
if (y + h - 1 < fb->height)
|
||||
for (int col = 0; col < w && col < fb->width; col++)
|
||||
dst[(y + h - 1) * stride + col] = dark;
|
||||
/* Left edge */
|
||||
for (int row = y; row < y + h && row < fb->height; row++)
|
||||
dst[row * stride] = light;
|
||||
/* Top edge */
|
||||
if (y < fb->height)
|
||||
for (int col = 0; col < w && col < fb->width; col++)
|
||||
dst[y * stride + col] = light;
|
||||
|
||||
(void)scr; (void)type;
|
||||
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
|
||||
}
|
||||
|
||||
void wl_balloon_init(WScreen *scr)
|
||||
{
|
||||
scr->balloon = wmalloc(sizeof(WBalloon));
|
||||
memset(scr->balloon, 0, sizeof(WBalloon));
|
||||
|
||||
/* Create a frame_buf in the overlay layer for balloon tooltips */
|
||||
if (wl_state.scene) {
|
||||
struct wl_frame_buf *fb = wmalloc(sizeof(*fb));
|
||||
memset(fb, 0, sizeof(*fb));
|
||||
|
||||
int w = 1, h = 1;
|
||||
fb->image = pixman_image_create_bits(PIXMAN_a8r8g8b8, w, h, NULL, 0);
|
||||
wlr_buffer_init(&fb->base, &frame_buf_impl, w, h);
|
||||
fb->id = wl_state.next_synthetic_id++;
|
||||
fb->width = w;
|
||||
fb->height = h;
|
||||
|
||||
struct wlr_scene_tree *parent = wl_state.level_trees[WL_LAYER_OVERLAY]
|
||||
? wl_state.level_trees[WL_LAYER_OVERLAY] : &wl_state.scene->tree;
|
||||
fb->tree = wlr_scene_tree_create(parent);
|
||||
if (fb->tree) {
|
||||
fb_attach_tree_listener(fb);
|
||||
wlr_scene_node_set_position(&fb->tree->node, 0, 0);
|
||||
fb->scene_buf = wlr_scene_buffer_create(fb->tree, &fb->base);
|
||||
if (fb->scene_buf) {
|
||||
fb_attach_scene_buf_listener(fb);
|
||||
wlr_scene_node_set_position(&fb->scene_buf->node, 0, 0);
|
||||
}
|
||||
wlr_scene_node_set_enabled(&fb->tree->node, false);
|
||||
}
|
||||
|
||||
wl_list_insert(&wl_state.frame_list, &fb->link);
|
||||
W_RegisterBacking(fb->id, fb->image);
|
||||
scr->balloon->window = (WNativeWindow)fb->id;
|
||||
}
|
||||
}
|
||||
|
||||
void wl_balloon_show(WScreen *scr, void *bal_ptr)
|
||||
{
|
||||
WBalloon *bal = (WBalloon *)bal_ptr;
|
||||
if (!bal->text || !bal->text[0])
|
||||
return;
|
||||
|
||||
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)bal->window);
|
||||
if (!fb)
|
||||
return;
|
||||
|
||||
WMFont *font = scr->info_text_font;
|
||||
int textlen = strlen(bal->text);
|
||||
int tw = WMWidthOfString(font, bal->text, textlen);
|
||||
int th = WMFontHeight(font);
|
||||
int pad = 4;
|
||||
int bw = tw + pad * 2;
|
||||
int bh = th + pad * 2;
|
||||
|
||||
/* Resize pixman buffer if needed */
|
||||
if (bw != fb->width || bh != fb->height) {
|
||||
W_UnregisterBacking(fb->id);
|
||||
pixman_image_unref(fb->image);
|
||||
fb->image = pixman_image_create_bits(PIXMAN_a8r8g8b8, bw, bh, NULL, 0);
|
||||
fb->width = bw;
|
||||
fb->height = bh;
|
||||
fb->base.width = bw;
|
||||
fb->base.height = bh;
|
||||
W_RegisterBacking(fb->id, fb->image);
|
||||
}
|
||||
|
||||
/* Fill pale yellow background */
|
||||
uint32_t *data = pixman_image_get_data(fb->image);
|
||||
for (int i = 0; i < bw * bh; i++)
|
||||
data[i] = 0xFFFFFFE0;
|
||||
|
||||
/* 1px black border */
|
||||
for (int x = 0; x < bw; x++) {
|
||||
data[x] = 0xFF000000;
|
||||
data[(bh - 1) * bw + x] = 0xFF000000;
|
||||
}
|
||||
for (int y = 0; y < bh; y++) {
|
||||
data[y * bw] = 0xFF000000;
|
||||
data[y * bw + bw - 1] = 0xFF000000;
|
||||
}
|
||||
|
||||
/* Draw text */
|
||||
WMDrawString(scr->wmscreen, (WMDrawable)fb->id, scr->black, font,
|
||||
pad, pad, bal->text, textlen);
|
||||
|
||||
/* Position near objectWindow */
|
||||
int bx = 0, by = 0;
|
||||
struct wl_frame_buf *obj = frame_buf_find((WNativeWindow)bal->objectWindow);
|
||||
if (obj) {
|
||||
bx = obj->x;
|
||||
by = obj->y + bal->h + 2;
|
||||
}
|
||||
|
||||
/* Clamp to screen */
|
||||
if (bx + bw > scr->scr_width)
|
||||
bx = scr->scr_width - bw;
|
||||
if (by + bh > scr->scr_height)
|
||||
by = by - bal->h - bh - 2;
|
||||
|
||||
if (fb->scene_buf) {
|
||||
wlr_scene_node_set_position(&fb->scene_buf->node, bx, by);
|
||||
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
|
||||
wlr_scene_node_set_enabled(&fb->tree->node, true);
|
||||
}
|
||||
|
||||
bal->mapped = 1;
|
||||
}
|
||||
|
||||
void wl_context_init(void)
|
||||
{
|
||||
/* Wayland uses a hash table instead of X11 contexts */
|
||||
w_global.context.client_win = 1;
|
||||
w_global.context.app_win = 2;
|
||||
w_global.context.stack = 3;
|
||||
}
|
||||
|
||||
int wl_window_get_command(WNativeWindow win, char ***argv_out, int *argc_out)
|
||||
{
|
||||
/* Wayland native clients: return [app_id] as a single-arg command.
|
||||
* Most app_ids match the binary name (e.g. "foot", "firefox") so this
|
||||
* is sufficient for session restore via PATH lookup or a desktop-file
|
||||
* Exec= line.
|
||||
*
|
||||
* XWayland clients: prefer WM_COMMAND (read from wl_state.x_display)
|
||||
* and fall back to xw_surface->instance / class. */
|
||||
*argv_out = NULL;
|
||||
*argc_out = 0;
|
||||
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(win);
|
||||
if (!v) return 0;
|
||||
|
||||
const char *cmd = NULL;
|
||||
if (v->xw_surface) {
|
||||
/* XWayland: try WM_COMMAND first via the X server. */
|
||||
if (wl_state.x_display && v->xw_surface->window_id) {
|
||||
char **cmd_argv = NULL;
|
||||
int cmd_argc = 0;
|
||||
if (XGetCommand(wl_state.x_display, v->xw_surface->window_id,
|
||||
&cmd_argv, &cmd_argc) && cmd_argc > 0 && cmd_argv) {
|
||||
/* Copy to wmaker's allocator */
|
||||
*argv_out = wmalloc(sizeof(char *) * cmd_argc);
|
||||
for (int i = 0; i < cmd_argc; i++)
|
||||
(*argv_out)[i] = wstrdup(cmd_argv[i]);
|
||||
*argc_out = cmd_argc;
|
||||
XFreeStringList(cmd_argv);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
cmd = v->xw_surface->instance ? v->xw_surface->instance :
|
||||
v->xw_surface->class;
|
||||
} else if (v->xdg_surface && v->xdg_surface->toplevel) {
|
||||
cmd = v->xdg_surface->toplevel->app_id;
|
||||
}
|
||||
|
||||
if (!cmd || !*cmd) return 0;
|
||||
|
||||
*argv_out = wmalloc(sizeof(char *));
|
||||
(*argv_out)[0] = wstrdup(cmd);
|
||||
*argc_out = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,3 +12,9 @@ Display *wl_get_x_display(void)
|
|||
return wl_state.x_display;
|
||||
}
|
||||
|
||||
RContext *wl_create_rcontext(int screen_number, RContextAttributes *attribs)
|
||||
{
|
||||
(void)screen_number;
|
||||
return RCreateContextWayland(1920, 1080, attribs);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,3 +68,8 @@ wl_keysym_from_keycode(unsigned int keycode, unsigned int index)
|
|||
|
||||
void wl_xkb_lock_group(int group) { (void)group; }
|
||||
int wl_xkb_get_group(void) { return 0; }
|
||||
unsigned long wl_keysym_from_name(const char *name)
|
||||
{
|
||||
return (unsigned long)xkb_keysym_from_name(name, XKB_KEYSYM_NO_FLAGS);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue