diff --git a/src/backend/wayland/wl_client.c b/src/backend/wayland/wl_client.c index 2e60303..8400a98 100644 --- a/src/backend/wayland/wl_client.c +++ b/src/backend/wayland/wl_client.c @@ -11,6 +11,7 @@ #include #include "../../screen.h" #include "wl_types.h" +#include "../../window.h" #include /* 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; +} + diff --git a/src/backend/wayland/wl_event.c b/src/backend/wayland/wl_event.c index 318faab..cf44914 100644 --- a/src/backend/wayland/wl_event.c +++ b/src/backend/wayland/wl_event.c @@ -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(); +} + diff --git a/src/backend/wayland/wl_framebuf.c b/src/backend/wayland/wl_framebuf.c index 9a94557..8334add 100644 --- a/src/backend/wayland/wl_framebuf.c +++ b/src/backend/wayland/wl_framebuf.c @@ -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); +} + diff --git a/src/backend/wayland/wl_icon.c b/src/backend/wayland/wl_icon.c index f36e714..8ec7e3e 100644 --- a/src/backend/wayland/wl_icon.c +++ b/src/backend/wayland/wl_icon.c @@ -16,6 +16,8 @@ #include "../../defaults.h" #include "../../def_pixmaps.h" #include "wl_types.h" +#include "../../workspace.h" +#include "../../dock.h" #include /* 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); +} + diff --git a/src/backend/wayland/wl_pointer_focus.c b/src/backend/wayland/wl_pointer_focus.c index f327d95..b53b09e 100644 --- a/src/backend/wayland/wl_pointer_focus.c +++ b/src/backend/wayland/wl_pointer_focus.c @@ -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; +} + diff --git a/src/backend/wayland/wl_screen.c b/src/backend/wayland/wl_screen.c index b1cdede..40f081b 100644 --- a/src/backend/wayland/wl_screen.c +++ b/src/backend/wayland/wl_screen.c @@ -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); } + diff --git a/src/backend/wayland/wl_stubs.c b/src/backend/wayland/wl_stubs.c index 8d536a1..873aa86 100644 --- a/src/backend/wayland/wl_stubs.c +++ b/src/backend/wayland/wl_stubs.c @@ -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 */ diff --git a/src/backend/wayland/wl_window.c b/src/backend/wayland/wl_window.c index f3a60da..bf1eea6 100644 --- a/src/backend/wayland/wl_window.c +++ b/src/backend/wayland/wl_window.c @@ -8,6 +8,13 @@ #include #include #include +#include "../../menu.h" +#include "../../balloon.h" +#include "../../framewin.h" +#include "../../texture.h" +#include "../../def_pixmaps.h" +#include + #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; +} + diff --git a/src/backend/wayland/wl_xdisplay.c b/src/backend/wayland/wl_xdisplay.c index 487a550..dd0e111 100644 --- a/src/backend/wayland/wl_xdisplay.c +++ b/src/backend/wayland/wl_xdisplay.c @@ -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); +} + diff --git a/src/backend/wayland/wl_xkb.c b/src/backend/wayland/wl_xkb.c index 5fbb1fd..5ea8add 100644 --- a/src/backend/wayland/wl_xkb.c +++ b/src/backend/wayland/wl_xkb.c @@ -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); +} +