#include "internal.h" #include "x11.h" #include "xkb_unicode.h" #include #include #include static void render(struct bm_menu *menu) { struct x11 *x11 = menu->renderer->internal; bm_x11_window_render(&x11->window, menu); XFlush(x11->display); XEvent ev; if (XNextEvent(x11->display, &ev) || XFilterEvent(&ev, x11->window.drawable)) return; switch (ev.type) { case KeyPress: bm_x11_window_key_press(&x11->window, &ev.xkey); break; case SelectionNotify: // paste here break; case VisibilityNotify: if (ev.xvisibility.state != VisibilityUnobscured) { XRaiseWindow(x11->display, x11->window.drawable); XFlush(x11->display); } break; } } static enum bm_key poll_key(const struct bm_menu *menu, unsigned int *unicode) { struct x11 *x11 = menu->renderer->internal; assert(x11 && unicode); if (x11->window.keysym == NoSymbol) return BM_KEY_UNICODE; KeySym sym = x11->window.keysym; uint32_t mods = x11->window.mods; *unicode = bm_x11_key_sym2unicode(sym); x11->window.keysym = NoSymbol; switch (sym) { case XK_Up: return BM_KEY_UP; case XK_Down: return BM_KEY_DOWN; case XK_Left: return (mods & MOD_SHIFT ? BM_KEY_UP : BM_KEY_LEFT); case XK_Right: return (mods & MOD_SHIFT ? BM_KEY_DOWN : BM_KEY_RIGHT); case XK_Home: return BM_KEY_HOME; case XK_End: return BM_KEY_END; case XK_Page_Up: return (mods & MOD_SHIFT ? BM_KEY_SHIFT_PAGE_UP : BM_KEY_PAGE_UP); case XK_less: return (mods & MOD_ALT ? BM_KEY_SHIFT_PAGE_UP : BM_KEY_UNICODE); case XK_Page_Down: return (mods & MOD_SHIFT ? BM_KEY_SHIFT_PAGE_DOWN : BM_KEY_PAGE_DOWN); case XK_greater: return (mods & MOD_ALT ? BM_KEY_SHIFT_PAGE_DOWN : BM_KEY_UNICODE); case XK_v: return (mods & MOD_CTRL ? BM_KEY_PAGE_DOWN : (mods & MOD_ALT ? BM_KEY_PAGE_UP : BM_KEY_UNICODE)); case XK_BackSpace: return BM_KEY_BACKSPACE; case XK_Delete: return (mods & MOD_SHIFT ? BM_KEY_LINE_DELETE_LEFT : BM_KEY_DELETE); case XK_Tab: return (mods & MOD_SHIFT ? BM_KEY_SHIFT_TAB : BM_KEY_TAB); case XK_ISO_Left_Tab: return BM_KEY_SHIFT_TAB; case XK_Insert: return BM_KEY_SHIFT_RETURN; case XK_KP_Enter: case XK_Return: return (mods & MOD_CTRL ? BM_KEY_CONTROL_RETURN : (mods & MOD_SHIFT ? BM_KEY_SHIFT_RETURN : BM_KEY_RETURN)); case XK_g: if (!(mods & MOD_CTRL)) return BM_KEY_UNICODE; // fall through case XK_c: if (!(mods & MOD_CTRL)) return BM_KEY_UNICODE; // fall through case XK_bracketleft: if (!(mods & MOD_CTRL)) return BM_KEY_UNICODE; // fall through case XK_Escape: return BM_KEY_ESCAPE; case XK_p: return (mods & MOD_CTRL ? BM_KEY_UP : BM_KEY_UNICODE); case XK_n: return (mods & MOD_CTRL ? BM_KEY_DOWN : BM_KEY_UNICODE); case XK_l: return (mods & MOD_CTRL ? BM_KEY_LEFT : (mods & MOD_ALT ? BM_KEY_DOWN : BM_KEY_UNICODE)); case XK_f: return (mods & MOD_CTRL ? BM_KEY_RIGHT : BM_KEY_UNICODE); case XK_a: return (mods & MOD_CTRL ? BM_KEY_HOME : BM_KEY_UNICODE); case XK_e: return (mods & MOD_CTRL ? BM_KEY_END : BM_KEY_UNICODE); case XK_h: return (mods & MOD_CTRL ? BM_KEY_BACKSPACE : (mods & MOD_ALT ? BM_KEY_UP : BM_KEY_UNICODE)); case XK_u: return (mods & MOD_CTRL ? BM_KEY_LINE_DELETE_LEFT : (mods & MOD_ALT ? BM_KEY_PAGE_UP : BM_KEY_UNICODE)); case XK_k: return (mods & MOD_CTRL ? BM_KEY_LINE_DELETE_RIGHT : (mods & MOD_ALT ? BM_KEY_UP : BM_KEY_UNICODE)); case XK_w: return (mods & MOD_CTRL ? BM_KEY_WORD_DELETE : BM_KEY_UNICODE); case XK_y: return (mods & MOD_CTRL ? BM_KEY_PASTE : BM_KEY_UNICODE); case XK_j: return (mods & MOD_ALT ? BM_KEY_DOWN : BM_KEY_UNICODE); case XK_d: return (mods & MOD_ALT ? BM_KEY_PAGE_DOWN : BM_KEY_UNICODE); case XK_m: return (mods & MOD_CTRL ? BM_KEY_RETURN : BM_KEY_UNICODE); case XK_1: if ((mods & MOD_ALT)) return BM_KEY_CUSTOM_1; break; case XK_2: if ((mods & MOD_ALT)) return BM_KEY_CUSTOM_2; break; case XK_3: if ((mods & MOD_ALT)) return BM_KEY_CUSTOM_3; break; case XK_4: if ((mods & MOD_ALT)) return BM_KEY_CUSTOM_4; break; case XK_5: if ((mods & MOD_ALT)) return BM_KEY_CUSTOM_5; break; case XK_6: if ((mods & MOD_ALT)) return BM_KEY_CUSTOM_6; break; case XK_7: if ((mods & MOD_ALT)) return BM_KEY_CUSTOM_7; break; case XK_8: if ((mods & MOD_ALT)) return BM_KEY_CUSTOM_8; break; case XK_9: if ((mods & MOD_ALT)) return BM_KEY_CUSTOM_9; break; case XK_0: if ((mods & MOD_ALT)) return BM_KEY_CUSTOM_10; break; default: break; } return BM_KEY_UNICODE; } static uint32_t get_displayed_count(const struct bm_menu *menu) { struct x11 *x11 = menu->renderer->internal; assert(x11); return x11->window.displayed; } static void set_align(const struct bm_menu *menu, enum bm_align align) { struct x11 *x11 = menu->renderer->internal; assert(x11); bm_x11_window_set_align(&x11->window, align); } static void set_width(const struct bm_menu *menu, uint32_t margin, float factor) { struct x11 *x11 = menu->renderer->internal; assert(x11); bm_x11_window_set_width(&x11->window, margin, factor); } static void set_monitor(const struct bm_menu *menu, int32_t monitor) { struct x11 *x11 = menu->renderer->internal; assert(x11); bm_x11_window_set_monitor(&x11->window, monitor); } static void grab_keyboard(const struct bm_menu *menu, bool grab) { struct x11 *x11 = menu->renderer->internal; assert(x11); if (grab) { for (uint32_t i = 0; i < 1000; ++i) { if (XGrabKeyboard(x11->display, DefaultRootWindow(x11->display), True, GrabModeAsync, GrabModeAsync, CurrentTime) == GrabSuccess) return; usleep(1000); } fprintf(stderr, "x11: cannot grab keyboard\n"); } else { XUngrabKeyboard(x11->display, CurrentTime); } } static void destructor(struct bm_menu *menu) { struct x11 *x11 = menu->renderer->internal; if (!x11) return; bm_x11_window_destroy(&x11->window); if (x11->display) XCloseDisplay(x11->display); free(x11); menu->renderer->internal = NULL; } static bool constructor(struct bm_menu *menu) { if (getenv("WAYLAND_DISPLAY") || getenv("WAYLAND_SOCKET")) return false; struct x11 *x11; if (!(menu->renderer->internal = x11 = calloc(1, sizeof(struct x11)))) goto fail; if (!(x11->display = XOpenDisplay(NULL))) goto fail; if (!bm_x11_window_create(&x11->window, x11->display)) goto fail; XSetClassHint(x11->window.display, x11->window.drawable, (XClassHint[]){{.res_name = (menu->title ? menu->title : "bemenu"), .res_class = "bemenu"}}); x11->window.align = menu->align; bm_x11_window_set_monitor(&x11->window, menu->monitor); x11->window.notify.render = bm_cairo_paint; return true; fail: destructor(menu); return false; } BM_PUBLIC extern const char* register_renderer(struct render_api *api) { api->constructor = constructor; api->destructor = destructor; api->get_displayed_count = get_displayed_count; api->poll_key = poll_key; api->render = render; api->set_align = set_align; api->set_width = set_width; api->set_monitor = set_monitor; api->grab_keyboard = grab_keyboard; api->priorty = BM_PRIO_GUI; api->version = BM_PLUGIN_VERSION; return "x11"; } /* vim: set ts=8 sw=4 tw=0 :*/