30#define G_LOG_DOMAIN "X11Helper"
44#include <xcb/xcb_aux.h>
45#include <xcb/xcb_cursor.h>
46#include <xcb/xcb_ewmh.h>
47#include <xcb/xinerama.h>
49#include <xcb/xproto.h>
50#include <xkbcommon/xkbcommon-x11.h>
51#include <xkbcommon/xkbcommon.h>
53#define SN_API_NOT_YET_FROZEN
56#define sn_launcher_context_set_application_id sn_launcher_set_application_id
72#define RANDR_PREF_MAJOR_VERSION 1
74#define RANDR_PREF_MINOR_VERSION 5
77#define INTERSECT(x, y, x1, y1, w1, h1) \
78 ((((x) >= (x1)) && ((x) < (x1 + w1))) && (((y) >= (y1)) && ((y) < (y1 + h1))))
98xcb_colormap_t
map = XCB_COLORMAP_NONE;
119 {
"default",
"left_ptr"}, {
"pointer",
"hand"}, {
"text",
"xterm"}};
122 xcb_depth_iterator_t d;
123 d = xcb_screen_allowed_depths_iterator(s);
124 for (; d.rem; xcb_depth_next(&d)) {
125 xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator(d.data);
126 for (; v.rem; xcb_visualtype_next(&v)) {
127 if (v.data->visual_id ==
visual) {
141 int size = 2 * (int)(radius) + 1;
142 uint32_t *kernel = (uint32_t *)(g_malloc(
sizeof(uint32_t) * (size + 1)));
143 double radiusf = fabs(radius) + 1.0;
144 double value = -radius;
148 if (deviation == 0.0) {
149 deviation = sqrt(-(radiusf * radiusf) / (2.0 * log(1.0 / 255.0)));
154 for (i = 0; i < size; i++) {
155 kernel[1 + i] = INT16_MAX / (2.506628275 * deviation) *
156 exp(-((value * value) / (2.0 * (deviation * deviation))));
158 sum += kernel[1 + i];
170 uint32_t *kernel = 0;
171 cairo_format_t format;
172 unsigned int channels;
174 if (cairo_surface_status(surface)) {
178 uint8_t *data = cairo_image_surface_get_data(surface);
179 format = cairo_image_surface_get_format(surface);
180 const int width = cairo_image_surface_get_width(surface);
181 const int height = cairo_image_surface_get_height(surface);
182 const int stride = cairo_image_surface_get_stride(surface);
184 if (format == CAIRO_FORMAT_ARGB32) {
190 horzBlur = (uint32_t *)(g_malloc(
sizeof(uint32_t) * height * stride));
197 uint32_t *horzBlur_ptr = horzBlur;
198 for (
int iY = 0; iY < height; iY++) {
199 const int iYs = iY * stride;
200 for (
int iX = 0; iX < width; iX++) {
205 int offset = (int)(kernel[0]) / -2;
207 for (
int i = 0; i < (int)(kernel[0]); i++) {
210 if (x < 0 || x >= width) {
215 uint8_t *dataPtr = &data[iYs + x * channels];
216 const uint32_t kernip1 = kernel[i + 1];
218 blue += kernip1 * dataPtr[0];
219 green += kernip1 * dataPtr[1];
220 red += kernip1 * dataPtr[2];
221 alpha += kernip1 * dataPtr[3];
225 *horzBlur_ptr++ = blue / sum;
226 *horzBlur_ptr++ = green / sum;
227 *horzBlur_ptr++ = red / sum;
228 *horzBlur_ptr++ = alpha / sum;
234 for (
int iY = 0; iY < height; iY++) {
235 for (
int iX = 0; iX < width; iX++) {
240 int offset = (int)(kernel[0]) / -2;
242 const int iXs = iX * channels;
243 for (
int i = 0; i < (int)(kernel[0]); i++) {
246 if (y < 0 || y >= height) {
251 uint32_t *dataPtr = &horzBlur[y * stride + iXs];
252 const uint32_t kernip1 = kernel[i + 1];
254 blue += kernip1 * dataPtr[0];
255 green += kernip1 * dataPtr[1];
256 red += kernip1 * dataPtr[2];
257 alpha += kernip1 * dataPtr[3];
262 *data++ = blue / sum;
263 *data++ = green / sum;
265 *data++ = alpha / sum;
278 xcb_get_geometry_cookie_t cookie;
279 xcb_get_geometry_reply_t *reply;
282 reply = xcb_get_geometry_reply(
xcb->
connection, cookie, NULL);
287 xcb_get_window_attributes_cookie_t attributesCookie =
289 xcb_get_window_attributes_reply_t *attributes =
290 xcb_get_window_attributes_reply(
xcb->
connection, attributesCookie, NULL);
291 if (attributes == NULL || (attributes->map_state != XCB_MAP_STATE_VIEWABLE)) {
302 cairo_surface_t *t = cairo_xcb_surface_create(
xcb->
connection, window, vt,
303 reply->width, reply->height);
305 if (cairo_surface_status(t) != CAIRO_STATUS_SUCCESS) {
306 cairo_surface_destroy(t);
312 int max = MAX(reply->width, reply->height);
313 double scale = (double)size / max;
315 cairo_surface_t *s2 = cairo_surface_create_similar_image(
316 t, CAIRO_FORMAT_ARGB32, reply->width * scale, reply->height * scale);
319 if (cairo_surface_status(s2) != CAIRO_STATUS_SUCCESS) {
320 cairo_surface_destroy(t);
324 cairo_t *d = cairo_create(s2);
325 cairo_scale(d, scale, scale);
326 cairo_set_source_surface(d, t, 0, 0);
330 cairo_surface_destroy(t);
345 xcb_get_property_cookie_t cookie;
346 xcb_get_property_reply_t *reply;
347 xcb_pixmap_t rootpixmap = XCB_NONE;
349 cookie = xcb_get_property(c, 0, screen->root, atom, XCB_ATOM_PIXMAP, 0, 1);
351 reply = xcb_get_property_reply(c, cookie, NULL);
354 if (xcb_get_property_value_length(reply) ==
sizeof(xcb_pixmap_t)) {
355 memcpy(&rootpixmap, xcb_get_property_value(reply),
sizeof(xcb_pixmap_t));
366 if (pm == XCB_NONE) {
378 xcb_get_property_cookie_t c = xcb_get_property(
379 xcb->
connection, 0, w, atom, XCB_GET_PROPERTY_TYPE_ANY, 0, UINT_MAX);
380 xcb_get_property_reply_t *r =
383 if (xcb_get_property_value_length(r) > 0) {
385 if (r->type ==
netatoms[UTF8_STRING]) {
386 str = g_strndup(xcb_get_property_value(r),
387 xcb_get_property_value_length(r));
388 }
else if (r->type ==
netatoms[STRING]) {
390 xcb_get_property_value_length(r));
392 str = g_strdup(
"Invalid encoding.");
405 xcb_change_property(
xcb->
connection, XCB_PROP_MODE_REPLACE, w, prop,
406 XCB_ATOM_ATOM, 32,
count, atoms);
435 double ratio_res = w->
w / (double)w->
h;
436 double ratio_size = w->
mw / (double)w->
mh;
438 if ((ratio_res < 1.0 && ratio_size > 1.0) ||
439 (ratio_res > 1.0 && ratio_size < 1.0)) {
450 xcb_randr_get_output_info_reply_t *op_reply;
451 xcb_randr_get_crtc_info_reply_t *crtc_reply;
452 xcb_randr_get_output_info_cookie_t it =
453 xcb_randr_get_output_info(
xcb->
connection, out, XCB_CURRENT_TIME);
454 op_reply = xcb_randr_get_output_info_reply(
xcb->
connection, it, NULL);
455 if (op_reply->crtc == XCB_NONE) {
459 xcb_randr_get_crtc_info_cookie_t ct = xcb_randr_get_crtc_info(
461 crtc_reply = xcb_randr_get_crtc_info_reply(
xcb->
connection, ct, NULL);
467 retv->
x = crtc_reply->x;
468 retv->
y = crtc_reply->y;
469 retv->
w = crtc_reply->width;
470 retv->
h = crtc_reply->height;
472 retv->
mw = op_reply->mm_width;
473 retv->
mh = op_reply->mm_height;
476 char *tname = (
char *)xcb_randr_get_output_info_name(op_reply);
477 int tname_len = xcb_randr_get_output_info_name_length(op_reply);
479 retv->
name = g_malloc0((tname_len + 1) *
sizeof(
char));
480 memcpy(retv->
name, tname, tname_len);
487#if (((XCB_RANDR_MAJOR_VERSION >= RANDR_PREF_MAJOR_VERSION) && \
488 (XCB_RANDR_MINOR_VERSION >= RANDR_PREF_MINOR_VERSION)) || \
489 XCB_RANDR_MAJOR_VERSION > RANDR_PREF_MAJOR_VERSION)
498x11_get_monitor_from_randr_monitor(xcb_randr_monitor_info_t *
mon) {
500 xcb_generic_error_t *err;
501 xcb_get_atom_name_cookie_t anc =
503 xcb_get_atom_name_reply_t *atom_reply =
506 g_warning(
"Could not get RandR monitor name: X11 error code %d\n",
519 retv->
w =
mon->width;
520 retv->
h =
mon->height;
523 retv->
mw =
mon->width_in_millimeters;
524 retv->
mh =
mon->height_in_millimeters;
529 g_strdup_printf(
"%.*s", xcb_get_atom_name_name_length(atom_reply),
530 xcb_get_atom_name_name(atom_reply));
540 xcb_query_extension_cookie_t randr_cookie =
541 xcb_query_extension(
xcb->
connection, strlen(extension), extension);
543 xcb_query_extension_reply_t *randr_reply =
544 xcb_query_extension_reply(
xcb->
connection, randr_cookie, NULL);
546 int present = randr_reply->present;
554 xcb_xinerama_query_screens_cookie_t screens_cookie =
557 xcb_xinerama_query_screens_reply_t *screens_reply =
558 xcb_xinerama_query_screens_reply(
xcb->
connection, screens_cookie, NULL);
560 xcb_xinerama_screen_info_iterator_t screens_iterator =
561 xcb_xinerama_query_screens_screen_info_iterator(screens_reply);
563 for (; screens_iterator.rem > 0;
564 xcb_xinerama_screen_info_next(&screens_iterator)) {
567 w->
x = screens_iterator.data->x_org;
568 w->
y = screens_iterator.data->y_org;
569 w->
w = screens_iterator.data->width;
570 w->
h = screens_iterator.data->height;
592 g_debug(
"Query XINERAMA for monitor layout.");
596 g_debug(
"No RANDR or Xinerama available for getting monitor layout.");
599 g_debug(
"Query RANDR for monitor layout.");
601 g_debug(
"Randr XCB api version: %d.%d.", XCB_RANDR_MAJOR_VERSION,
602 XCB_RANDR_MINOR_VERSION);
603#if (((XCB_RANDR_MAJOR_VERSION == RANDR_PREF_MAJOR_VERSION) && \
604 (XCB_RANDR_MINOR_VERSION >= RANDR_PREF_MINOR_VERSION)) || \
605 XCB_RANDR_MAJOR_VERSION > RANDR_PREF_MAJOR_VERSION)
606 xcb_randr_query_version_cookie_t cversion = xcb_randr_query_version(
608 xcb_randr_query_version_reply_t *rversion =
609 xcb_randr_query_version_reply(
xcb->
connection, cversion, NULL);
611 g_debug(
"Found randr version: %d.%d", rversion->major_version,
612 rversion->minor_version);
617 xcb_randr_get_monitors_cookie_t t =
619 xcb_randr_get_monitors_reply_t *mreply =
622 xcb_randr_monitor_info_iterator_t iter =
623 xcb_randr_get_monitors_monitors_iterator(mreply);
624 while (iter.rem > 0) {
625 workarea *w = x11_get_monitor_from_randr_monitor(iter.data);
630 xcb_randr_monitor_info_next(&iter);
641 xcb_randr_get_screen_resources_current_reply_t *res_reply;
642 xcb_randr_get_screen_resources_current_cookie_t src;
643 src = xcb_randr_get_screen_resources_current(
xcb->
connection,
645 res_reply = xcb_randr_get_screen_resources_current_reply(
xcb->
connection,
651 xcb_randr_get_screen_resources_current_outputs_length(res_reply);
652 xcb_randr_output_t *ops =
653 xcb_randr_get_screen_resources_current_outputs(res_reply);
656 xcb_randr_get_output_primary_cookie_t pc =
658 xcb_randr_get_output_primary_reply_t *pc_rep =
659 xcb_randr_get_output_primary_reply(
xcb->
connection, pc, NULL);
661 for (
int i = mon_num - 1; i >= 0; i--) {
666 if (pc_rep && pc_rep->output == ops[i]) {
681 iter->monitor_id = index++;
686 int is_term = isatty(fileno(stdout));
687 printf(
"Monitor layout:\n");
689 printf(
"%s ID%s: %d", (is_term) ?
color_bold :
"",
692 printf(
" (primary)");
695 printf(
"%s name%s: %s\n", (is_term) ?
color_bold :
"",
697 printf(
"%s position%s: %d,%d\n", (is_term) ?
color_bold :
"",
699 printf(
"%s size%s: %d,%d\n", (is_term) ?
color_bold :
"",
701 if (iter->mw > 0 && iter->mh > 0) {
702 printf(
"%s size%s: %dmm,%dmm dpi: %.0f,%.0f\n",
704 iter->mh, iter->w * 25.4 / (double)iter->mw,
705 iter->h * 25.4 / (
double)iter->mh);
712 GSpawnChildSetupFunc *child_setup,
713 gpointer *user_data) {
714 if (context == NULL) {
718 SnLauncherContext *sncontext;
722 sn_launcher_context_set_name(sncontext, context->
name);
723 sn_launcher_context_set_description(sncontext, context->
description);
724 if (context->
binary != NULL) {
725 sn_launcher_context_set_binary_name(sncontext, context->
binary);
727 if (context->
icon != NULL) {
728 sn_launcher_context_set_icon_name(sncontext, context->
icon);
730 if (context->
app_id != NULL) {
733 if (context->
wmclass != NULL) {
734 sn_launcher_context_set_wmclass(sncontext, context->
wmclass);
737 xcb_get_property_cookie_t c;
738 unsigned int current_desktop = 0;
741 if (xcb_ewmh_get_current_desktop_reply(&
xcb->
ewmh, c, ¤t_desktop,
743 sn_launcher_context_set_workspace(sncontext, current_desktop);
746 sn_launcher_context_initiate(sncontext,
"rofi", context->
command,
749 *child_setup = (GSpawnChildSetupFunc)sn_launcher_context_setup_child_process;
750 *user_data = sncontext;
770 g_error(
"%s: mon == NULL", __FUNCTION__);
778 if (
INTERSECT(x, y, iter->x, iter->y, iter->w, iter->h)) {
798 xcb_query_pointer_cookie_t c = xcb_query_pointer(
xcb->
connection, root);
799 xcb_query_pointer_reply_t *r =
813 g_error(
"%s: mon == NULL", __FUNCTION__);
817 xcb_get_geometry_cookie_t c = xcb_get_geometry(
xcb->
connection,
id);
818 xcb_get_geometry_reply_t *r =
821 xcb_translate_coordinates_cookie_t ct =
822 xcb_translate_coordinates(
xcb->
connection,
id, root, r->x, r->y);
823 xcb_translate_coordinates_reply_t *t =
829 mon->
x = t->dst_x - r->x;
830 mon->
y = t->dst_y - r->y;
843 xcb_window_t active_window;
844 xcb_get_property_cookie_t awc;
846 g_error(
"%s: mon == NULL", __FUNCTION__);
850 if (!xcb_ewmh_get_active_window_reply(&
xcb->
ewmh, awc, &active_window,
853 "Failed to get active window, falling back to mouse location (-5).");
856 xcb_query_tree_cookie_t tree_cookie =
858 xcb_query_tree_reply_t *tree_reply =
862 "Failed to get parent window, falling back to mouse location (-5).");
866 xcb_get_geometry_cookie_t c =
868 xcb_get_geometry_reply_t *r =
871 g_debug(
"Failed to get geometry of active window, falling back to mouse "
876 xcb_translate_coordinates_cookie_t ct = xcb_translate_coordinates(
878 xcb_translate_coordinates_reply_t *t =
885 mon->
x = t->dst_x - r->x;
886 mon->
y = t->dst_y - r->y;
896 }
else if (mon_id == -4) {
897 g_debug(
"Find monitor at location: %d %d", t->dst_x, t->dst_y);
904 g_debug(
"Failed to get translate position of active window, falling back "
905 "to mouse location (-5).");
915 g_error(
"%s: mon == NULL", __FUNCTION__);
918 g_debug(
"Monitor id: %d", mon_id);
929 else if (mon_id == -1) {
930 g_debug(
"rofi on current monitor");
932 unsigned int current_desktop = 0;
933 xcb_get_property_cookie_t gcdc;
935 if (xcb_ewmh_get_current_desktop_reply(&
xcb->
ewmh, gcdc, ¤t_desktop,
937 g_debug(
"Found current desktop: %u", current_desktop);
938 xcb_get_property_cookie_t c =
940 xcb_ewmh_get_desktop_viewport_reply_t vp;
941 if (xcb_ewmh_get_desktop_viewport_reply(&
xcb->
ewmh, c, &vp, NULL)) {
942 g_debug(
"Found %d number of desktops", vp.desktop_viewport_len);
943 if (current_desktop < vp.desktop_viewport_len) {
944 g_debug(
"Found viewport for desktop: %d %d",
945 vp.desktop_viewport[current_desktop].x,
946 vp.desktop_viewport[current_desktop].y);
948 vp.desktop_viewport[current_desktop].y,
mon);
949 g_debug(
"Found monitor @: %d %d %dx%d",
mon->
x,
mon->
y,
mon->
w,
951 xcb_ewmh_get_desktop_viewport_reply_wipe(&vp);
954 g_debug(
"Viewport does not exist for current desktop: %d, falling "
955 "back to mouse location (-5)",
957 xcb_ewmh_get_desktop_viewport_reply_wipe(&vp);
959 g_debug(
"Failed to get viewport for current desktop: %d, falling back "
960 "to mouse location (-5).",
964 g_debug(
"Failed to get current desktop, falling back to mouse location "
967 }
else if (mon_id == -2 || mon_id == -4) {
973 else if (mon_id == -5) {
981 g_debug(
"Failed to find monitor, fall back to monitor showing mouse.");
994 g_error(
"%s: mon == NULL", __FUNCTION__);
997 g_debug(
"Monitor active");
1013 g_debug(
"Monitor lookup by name failed: %s",
config.
monitor);
1017 if (iter->primary) {
1027 xcb_drawable_t win = g_ascii_strtoll(
config.
monitor + 4, &end, 0);
1047 g_warning(
"Failed to find selected monitor.");
1070 xcb_selection_notify_event_t *xse) {
1071 if (xse->property == XCB_ATOM_NONE) {
1072 g_warning(
"Failed to convert selection");
1073 }
else if (xse->property ==
xcb->
ewmh.UTF8_STRING) {
1075 if (text != NULL && text[0] !=
'\0') {
1076 unsigned int dl = strlen(text);
1078 for (
unsigned int i = 0; i < dl; i++) {
1079 if (text[i] ==
'\n') {
1087 g_warning(
"Failed");
1093 NkBindingsMouseButton *button) {
1094 switch (x11_button) {
1096 *button = NK_BINDINGS_MOUSE_BUTTON_PRIMARY;
1099 *button = NK_BINDINGS_MOUSE_BUTTON_SECONDARY;
1102 *button = NK_BINDINGS_MOUSE_BUTTON_MIDDLE;
1105 *button = NK_BINDINGS_MOUSE_BUTTON_BACK;
1108 *button = NK_BINDINGS_MOUSE_BUTTON_FORWARD;
1116 *button = NK_BINDINGS_MOUSE_BUTTON_EXTRA + x11_button;
1122 NkBindingsScrollAxis *axis,
1125 switch (x11_button) {
1130 *axis = NK_BINDINGS_SCROLL_AXIS_VERTICAL;
1136 *axis = NK_BINDINGS_SCROLL_AXIS_HORIZONTAL;
1149 if (state == NULL) {
1153 switch (event->response_type & ~0x80) {
1154 case XCB_CLIENT_MESSAGE: {
1155 xcb_client_message_event_t *cme = (xcb_client_message_event_t *)event;
1156 xcb_atom_t atom = cme->data.data32[0];
1157 xcb_timestamp_t
time = cme->data.data32[1];
1158 if (atom ==
netatoms[WM_TAKE_FOCUS]) {
1159 xcb_set_input_focus(
xcb->
connection, XCB_INPUT_FOCUS_NONE, cme->window,
1165 case XCB_DESTROY_NOTIFY: {
1166 xcb_window_t win = ((xcb_destroy_notify_event_t *)event)->window;
1169 window_client_handle_signal(win, FALSE);
1176 case XCB_CREATE_NOTIFY: {
1177 xcb_window_t win = ((xcb_create_notify_event_t *)event)->window;
1180 window_client_handle_signal(win, TRUE);
1188 case XCB_CONFIGURE_NOTIFY: {
1189 xcb_configure_notify_event_t *xce = (xcb_configure_notify_event_t *)event;
1193 case XCB_MOTION_NOTIFY: {
1194 xcb_motion_notify_event_t *xme = (xcb_motion_notify_event_t *)event;
1195 gboolean button_mask = xme->state & XCB_EVENT_MASK_BUTTON_1_MOTION;
1203 case XCB_BUTTON_PRESS: {
1204 xcb_button_press_event_t *bpe = (xcb_button_press_event_t *)event;
1205 NkBindingsMouseButton button;
1206 NkBindingsScrollAxis axis;
1213 NK_BINDINGS_BUTTON_STATE_PRESS, bpe->time);
1219 case XCB_BUTTON_RELEASE: {
1220 xcb_button_release_event_t *bre = (xcb_button_release_event_t *)event;
1221 NkBindingsMouseButton button;
1226 NK_BINDINGS_BUTTON_STATE_RELEASE,
1238 case XCB_SELECTION_NOTIFY:
1241 case XCB_KEYMAP_NOTIFY: {
1242 xcb_keymap_notify_event_t *kne = (xcb_keymap_notify_event_t *)event;
1243 for (gint32 by = 0; by < 31; ++by) {
1244 for (gint8 bi = 0; bi < 7; ++bi) {
1245 if (kne->keys[by] & (1 << bi)) {
1249 NK_BINDINGS_KEY_STATE_PRESSED);
1255 case XCB_KEY_PRESS: {
1256 xcb_key_press_event_t *xkpe = (xcb_key_press_event_t *)event;
1261 text = nk_bindings_seat_handle_key_with_modmask(
1263 NK_BINDINGS_KEY_STATE_PRESS);
1265 text = nk_bindings_seat_handle_key(
1267 NK_BINDINGS_KEY_STATE_PRESS);
1275 case XCB_KEY_RELEASE: {
1276 xcb_key_release_event_t *xkre = (xcb_key_release_event_t *)event;
1279 NK_BINDINGS_KEY_STATE_RELEASE);
1289 G_GNUC_UNUSED gpointer user_data) {
1293 g_warning(
"The XCB connection to X server had a fatal error: %d", status);
1295 return G_SOURCE_REMOVE;
1300 return G_SOURCE_CONTINUE;
1302 uint8_t type = ev->response_type & ~0x80;
1305 case XCB_XKB_MAP_NOTIFY: {
1306 struct xkb_keymap *keymap = xkb_x11_keymap_new_from_device(
1309 struct xkb_state *state = xkb_x11_state_new_from_device(
1312 xkb_keymap_unref(keymap);
1313 xkb_state_unref(state);
1316 case XCB_XKB_STATE_NOTIFY: {
1317 xcb_xkb_state_notify_event_t *ksne = (xcb_xkb_state_notify_event_t *)ev;
1319 ksne->latchedMods, ksne->lockedMods,
1320 ksne->baseGroup, ksne->latchedGroup,
1326 return G_SOURCE_CONTINUE;
1332 return G_SOURCE_CONTINUE;
1340 xcb_generic_error_t *error;
1341 xcb_get_input_focus_reply_t *freply;
1342 xcb_get_input_focus_cookie_t fcookie = xcb_get_input_focus(
xcb->
connection);
1343 freply = xcb_get_input_focus_reply(
xcb->
connection, fcookie, &error);
1344 if (error != NULL) {
1345 g_warning(
"Could not get input focus (error %d), will revert focus to best "
1353 xcb_set_input_focus(
xcb->
connection, XCB_INPUT_FOCUS_POINTER_ROOT, w,
1363 xcb_set_input_focus(
xcb->
connection, XCB_INPUT_FOCUS_POINTER_ROOT,
1372 g_warning(
"Connection has error");
1375 xcb_grab_pointer_cookie_t cc =
1376 xcb_grab_pointer(
xcb->
connection, 1, w, XCB_EVENT_MASK_BUTTON_RELEASE,
1377 XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, w, XCB_NONE,
1379 xcb_grab_pointer_reply_t *r =
1382 if (r->status == XCB_GRAB_STATUS_SUCCESS) {
1388 if ((++i) > iters) {
1391 struct timespec del = {.tv_sec = 0, .tv_nsec = 1000000};
1392 nanosleep(&del, NULL);
1401 g_warning(
"Connection has error");
1404 xcb_grab_keyboard_cookie_t cc =
1406 XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
1407 xcb_grab_keyboard_reply_t *r =
1410 if (r->status == XCB_GRAB_STATUS_SUCCESS) {
1416 if ((++i) > iters) {
1419 struct timespec del = {.tv_sec = 0, .tv_nsec = 1000000};
1420 nanosleep(&del, NULL);
1435 G_GNUC_UNUSED xcb_connection_t *xdisplay) {
1440 xcb_connection_t *xdisplay) {
1442 g_warning(
"Error trap underflow!");
1446 xcb_flush(xdisplay);
1456 xcb_intern_atom_cookie_t cc = xcb_intern_atom(
1458 xcb_intern_atom_reply_t *r =
1468 xcb_window_t wm_win = 0;
1469 xcb_get_property_cookie_t cc = xcb_ewmh_get_supporting_wm_check_unchecked(
1472 if (xcb_ewmh_get_supporting_wm_check_reply(&
xcb->
ewmh, cc, &wm_win, NULL)) {
1473 xcb_ewmh_get_utf8_strings_reply_t wtitle;
1474 xcb_get_property_cookie_t cookie =
1475 xcb_ewmh_get_wm_name_unchecked(&(
xcb->
ewmh), wm_win);
1476 if (xcb_ewmh_get_wm_name_reply(&(
xcb->
ewmh), cookie, &wtitle, (
void *)0)) {
1477 if (wtitle.strings_len > 0) {
1478 g_debug(
"Found window manager: |%s|", wtitle.strings);
1479 if (g_strcmp0(wtitle.strings,
"i3") == 0) {
1482 }
else if (g_strcmp0(wtitle.strings,
"bspwm") == 0) {
1486 xcb_ewmh_get_utf8_strings_reply_wipe(&wtitle);
1494 char *display_str = (
char *)g_getenv(
"DISPLAY");
1502 g_warning(
"Failed to open display: %s", display_str);
1513 xcb_intern_atom_cookie_t *ac =
1515 xcb_generic_error_t *errors = NULL;
1516 xcb_ewmh_init_atoms_replies(&
xcb->
ewmh, ac, &errors);
1518 g_warning(
"Failed to create EWMH atoms");
1525 if (xkb_x11_setup_xkb_extension(
1527 XKB_X11_MIN_MINOR_XKB_VERSION, XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS,
1529 g_warning(
"cannot setup XKB extension!");
1537 (XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY |
1538 XCB_XKB_EVENT_TYPE_MAP_NOTIFY | XCB_XKB_EVENT_TYPE_STATE_NOTIFY),
1540 required_nkn_details = (XCB_XKB_NKN_DETAIL_KEYCODES),
1542 required_map_parts =
1543 (XCB_XKB_MAP_PART_KEY_TYPES | XCB_XKB_MAP_PART_KEY_SYMS |
1544 XCB_XKB_MAP_PART_MODIFIER_MAP | XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS |
1545 XCB_XKB_MAP_PART_KEY_ACTIONS | XCB_XKB_MAP_PART_VIRTUAL_MODS |
1546 XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP),
1548 required_state_details =
1549 (XCB_XKB_STATE_PART_MODIFIER_BASE | XCB_XKB_STATE_PART_MODIFIER_LATCH |
1550 XCB_XKB_STATE_PART_MODIFIER_LOCK | XCB_XKB_STATE_PART_GROUP_BASE |
1551 XCB_XKB_STATE_PART_GROUP_LATCH | XCB_XKB_STATE_PART_GROUP_LOCK),
1554 static const xcb_xkb_select_events_details_t details = {
1555 .affectNewKeyboard = required_nkn_details,
1556 .newKeyboardDetails = required_nkn_details,
1557 .affectState = required_state_details,
1558 .stateDetails = required_state_details,
1569 struct xkb_keymap *keymap = xkb_x11_keymap_new_from_device(
1572 if (keymap == NULL) {
1573 g_warning(
"Failed to get Keymap for current keyboard device.");
1576 struct xkb_state *state = xkb_x11_state_new_from_device(
1578 if (state == NULL) {
1579 g_warning(
"Failed to get state object for current keyboard device.");
1584 xkb_state_unref(state);
1585 xkb_keymap_unref(keymap);
1591 g_warning(
"Connection has error");
1595 uint32_t val[] = {XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY};
1598 XCB_CW_EVENT_MASK, val);
1604 g_warning(
"Connection has error");
1613 g_warning(
"Connection has error");
1621 xcb_depth_t *root_depth = NULL;
1622 xcb_depth_iterator_t depth_iter;
1623 for (depth_iter = xcb_screen_allowed_depths_iterator(
xcb->
screen);
1624 depth_iter.rem; xcb_depth_next(&depth_iter)) {
1625 xcb_depth_t *d = depth_iter.data;
1627 xcb_visualtype_iterator_t visual_iter;
1628 for (visual_iter = xcb_depth_visuals_iterator(d); visual_iter.rem;
1629 xcb_visualtype_next(&visual_iter)) {
1630 xcb_visualtype_t *v = visual_iter.data;
1631 if ((v->bits_per_rgb_value == 8) && (d->depth == 32) &&
1632 (v->_class == XCB_VISUAL_CLASS_TRUE_COLOR)) {
1636 if (
xcb->
screen->root_visual == v->visual_id) {
1643 xcb_void_cookie_t c;
1644 xcb_generic_error_t *e;
1646 c = xcb_create_colormap_checked(
xcb->
connection, XCB_COLORMAP_ALLOC_NONE,
1664 xcb_cursor_context_t *ctx;
1673 if (
cursors[i] == XCB_CURSOR_NONE) {
1679 xcb_cursor_context_free(ctx);
1689 g_warning(
"Failed to grab pointer after %u times. Giving up.",
1691 return G_SOURCE_REMOVE;
1694 return G_SOURCE_REMOVE;
1697 return G_SOURCE_CONTINUE;
1702 g_warning(
"Failed to grab keyboard after %u times. Giving up.",
1705 return G_SOURCE_REMOVE;
1708 return G_SOURCE_REMOVE;
1711 return G_SOURCE_CONTINUE;
1725 if (
find_arg(
"-normal-window") >= 0) {
1728 if (
find_arg(
"-no-lazy-grab") >= 0) {
1730 g_warning(
"Failed to grab keyboard, even after %d uS.", 500 * 1000);
1734 g_warning(
"Failed to grab mouse pointer, even after %d uS.", 100 * 1000);
1760 g_debug(
"Cleaning up XCB and XKB");
1772 xcb_ewmh_connection_wipe(&(
xcb->
ewmh));
1784 const uint32_t MWM_HINTS_DECORATIONS = (1 << 1);
1786 struct MotifWMHints {
1789 uint32_t decorations;
1794 struct MotifWMHints hints;
1795 hints.flags = MWM_HINTS_DECORATIONS;
1796 hints.decorations = 0;
1797 hints.functions = 0;
1798 hints.inputMode = 0;
1801 xcb_atom_t ha =
netatoms[_MOTIF_WM_HINTS];
1802 xcb_change_property(
xcb->
connection, XCB_PROP_MODE_REPLACE, window, ha, ha,
1811 if (
cursors[type] == XCB_CURSOR_NONE) {
1815 xcb_change_window_attributes(
xcb->
connection, window, XCB_CW_CURSOR,
char * rofi_latin_to_utf8_strdup(const char *input, gssize length)
int find_arg_str(const char *const key, char **val)
int find_arg(const char *const key)
xcb_window_t rofi_view_get_window(void)
RofiViewState * rofi_view_get_active(void)
void rofi_view_handle_text(RofiViewState *state, char *text)
void rofi_view_handle_mouse_motion(RofiViewState *state, gint x, gint y, gboolean find_mouse_target)
void rofi_view_temp_click_to_exit(RofiViewState *state, xcb_window_t target)
void rofi_view_temp_configure_notify(RofiViewState *state, xcb_configure_notify_event_t *xce)
void rofi_view_frame_callback(void)
void rofi_view_maybe_update(RofiViewState *state)
const gchar * description
gboolean xserver_i300_workaround
xcb_connection_t * connection
SnLauncheeContext * sncontext
struct _workarea * monitors
xcb_timestamp_t last_timestamp
xcb_ewmh_connection_t ewmh
struct _xcb_stuff::@8 xkb
NkBindingsSeat * bindings_seat
xcb_window_t focus_revert
gboolean display_late_setup(void)
static int take_pointer(xcb_window_t w, int iters)
int monitor_active(workarea *mon)
const struct @4 cursor_names[]
static void x11_build_monitor_layout_xinerama()
#define RANDR_PREF_MAJOR_VERSION
const char * traditional_name
void display_early_cleanup(void)
static int x11_is_extension_present(const char *extension)
static gboolean lazy_grab_pointer(G_GNUC_UNUSED gpointer data)
static void x11_workarea_fix_rotation(workarea *w)
void display_startup_notification(RofiHelperExecuteContext *context, GSpawnChildSetupFunc *child_setup, gpointer *user_data)
cairo_surface_t * x11_helper_get_screenshot_surface(void)
static xcb_visualtype_t * lookup_visual(xcb_screen_t *s, xcb_visualid_t visual)
static void x11_build_monitor_layout()
char * window_get_text_prop(xcb_window_t w, xcb_atom_t atom)
void display_cleanup(void)
static xcb_pixmap_t get_root_pixmap(xcb_connection_t *c, xcb_screen_t *screen, xcb_atom_t atom)
static void release_pointer(void)
struct _xcb_stuff xcb_int
static uint32_t * create_kernel(double radius, double deviation, uint32_t *sum2)
static int monitor_active_from_winid(xcb_drawable_t id, workarea *mon)
static void x11_create_visual_and_colormap(void)
static gboolean x11_button_to_nk_bindings_scroll(guint32 x11_button, NkBindingsScrollAxis *axis, gint32 *steps)
static void monitor_dimensions(int x, int y, workarea *mon)
void rofi_xcb_revert_input_focus(void)
cairo_surface_t * x11_helper_get_bg_surface(void)
static void x11_lookup_cursors(void)
void rofi_xcb_set_input_focus(xcb_window_t w)
static gboolean lazy_grab_keyboard(G_GNUC_UNUSED gpointer data)
#define INTERSECT(x, y, x1, y1, w1, h1)
static workarea * x11_get_monitor_from_output(xcb_randr_output_t out)
static void error_trap_pop(G_GNUC_UNUSED SnDisplay *display, xcb_connection_t *xdisplay)
void x11_set_cursor(xcb_window_t window, X11CursorType type)
unsigned int lazy_grab_retry_count_pt
static xcb_visualtype_t * root_visual
static void x11_create_frequently_used_atoms(void)
static int monitor_active_from_id_focused(int mon_id, workarea *mon)
static gboolean x11_button_to_nk_bindings_button(guint32 x11_button, NkBindingsMouseButton *button)
xcb_cursor_t cursors[NUM_CURSORS]
static void x11_monitor_free(workarea *m)
static void x11_helper_discover_window_manager(void)
static int monitor_get_dimension(int monitor_id, workarea *mon)
static int take_keyboard(xcb_window_t w, int iters)
xcb_window_t xcb_stuff_get_root_window(void)
unsigned int lazy_grab_retry_count_kb
static void rofi_view_paste(RofiViewState *state, xcb_selection_notify_event_t *xse)
void window_set_atom_prop(xcb_window_t w, xcb_atom_t prop, xcb_atom_t *atoms, int count)
const char * netatom_names[]
void cairo_image_surface_blur(cairo_surface_t *surface, double radius, double deviation)
static int monitor_active_from_id(int mon_id, workarea *mon)
static void x11_monitors_free(void)
gboolean display_setup(GMainLoop *main_loop, NkBindings *bindings)
void display_dump_monitor_layout(void)
static void error_trap_push(G_GNUC_UNUSED SnDisplay *display, G_GNUC_UNUSED xcb_connection_t *xdisplay)
WindowManagerQuirk current_window_manager
static int pointer_get(xcb_window_t root, int *x, int *y)
#define RANDR_PREF_MINOR_VERSION
#define sn_launcher_context_set_application_id
static int error_trap_depth
static void release_keyboard(void)
static gboolean main_loop_x11_event_handler(xcb_generic_event_t *ev, G_GNUC_UNUSED gpointer user_data)
void x11_disable_decoration(xcb_window_t window)
static void main_loop_x11_event_handler_view(xcb_generic_event_t *event)
xcb_atom_t netatoms[NUM_NETATOMS]
xcb_visualtype_t * visual
cairo_surface_t * x11_helper_get_screenshot_surface_window(xcb_window_t window, int size)
@ WM_PANGO_WORKSPACE_NAMES
@ WM_DO_NOT_CHANGE_CURRENT_DESKTOP