1
0
Fork 0
mirror of https://github.com/Cloudef/bemenu synced 2024-05-23 07:56:10 +02:00
bemenu/lib/renderers/x11/x11.c
2020-08-28 21:01:22 +09:00

296 lines
7.8 KiB
C

#include "internal.h"
#include "x11.h"
#include "xkb_unicode.h"
#include <stdlib.h>
#include <unistd.h>
#include <X11/Xutil.h>
static void
render(const 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_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_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_bottom(const struct bm_menu *menu, bool bottom)
{
struct x11 *x11 = menu->renderer->internal;
assert(x11);
bm_x11_window_set_bottom(&x11->window, bottom);
}
static void
set_monitor(const struct bm_menu *menu, uint32_t monitor)
{
struct x11 *x11 = menu->renderer->internal;
assert(x11);
bm_x11_window_set_monitor(&x11->window, (monitor != (uint32_t)-1 ? monitor : 0));
}
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.bottom = menu->bottom;
bm_x11_window_set_monitor(&x11->window, menu->monitor);
x11->window.notify.render = bm_cairo_paint;
return true;
fail:
destructor(menu);
return false;
}
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_bottom = set_bottom;
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 :*/