15 #include <xcb/randr.h>
16 #include <X11/XKBlib.h>
17 #define SN_API_NOT_YET_FROZEN 1
18 #include <libsn/sn-monitor.h>
40 event->added = time(NULL);
51 time_t now = time(NULL);
53 if ((now - event->
added) > 5) {
58 }
else event =
SLIST_NEXT(event, ignore_events);
90 DLOG(
"Keypress %d, state raw = %d\n", event->detail, event->state);
93 uint16_t state_filtered =
event->state & ~(
xcb_numlock_mask | XCB_MOD_MASK_LOCK);
94 DLOG(
"(removed numlock, state = %d)\n", state_filtered);
97 state_filtered &= 0xFF;
98 DLOG(
"(removed upper 8 bits, state = %d)\n", state_filtered);
103 DLOG(
"(checked mode_switch, state %d)\n", state_filtered);
114 DLOG(
"no match, new state_filtered = %d\n", state_filtered);
115 if ((bind =
get_binding(state_filtered, event->detail)) == NULL) {
116 ELOG(
"Could not lookup key binding (modifiers %d, keycode %d)\n",
117 state_filtered, event->detail);
144 ELOG(
"ERROR: No such screen\n");
148 if (output->
con == NULL) {
149 ELOG(
"ERROR: The screen is not recognized by i3 (no container associated)\n");
175 DLOG(
"enter_notify for %08x, mode = %d, detail %d, serial %d\n",
176 event->event, event->mode, event->detail, event->sequence);
177 DLOG(
"coordinates %d, %d\n", event->event_x, event->event_y);
178 if (event->mode != XCB_NOTIFY_MODE_NORMAL) {
179 DLOG(
"This was not a normal notify, ignoring\n");
185 DLOG(
"Event ignored\n");
189 bool enter_child =
false;
198 DLOG(
"Getting screen at %d x %d\n", event->root_x, event->root_y);
204 DLOG(
"Ignoring, this is a dock client\n");
210 if (layout == L_DEFAULT) {
214 LOG(
"using child %p / %s instead!\n", child, child->
name);
221 if (client->workspace != c_ws && client->workspace->output == c_ws->output) {
225 DLOG(
"enter_notify for a client on a different workspace but the same screen, ignoring\n");
259 if (event->child != 0)
271 if (con->
layout != L_DEFAULT)
298 if (event->request != XCB_MAPPING_KEYBOARD &&
299 event->request != XCB_MAPPING_MODIFIER)
302 DLOG(
"Received mapping_notify for keyboard or modifier mapping, re-grabbing keys\n");
303 xcb_refresh_keyboard_mapping(
keysyms, event);
319 xcb_get_window_attributes_cookie_t cookie;
321 cookie = xcb_get_window_attributes_unchecked(
conn, event->window);
323 DLOG(
"window = 0x%08x, serial is %d.\n", event->window, event->sequence);
342 DLOG(
"window 0x%08x wants to be at %dx%d with %dx%d\n",
343 event->window, event->x, event->y, event->width, event->height);
348 DLOG(
"Configure request for unmanaged window, can do that.\n");
353 #define COPY_MASK_MEMBER(mask_member, event_member) do { \
354 if (event->value_mask & mask_member) { \
355 mask |= mask_member; \
356 values[c++] = event->event_member; \
368 xcb_configure_window(
conn, event->window, mask, values);
374 DLOG(
"Configure request!\n");
382 bsr.
y += deco_height;
383 bsr.
height -= deco_height;
389 if (event->value_mask & XCB_CONFIG_WINDOW_X) {
390 newrect.
x =
event->x + (-1) * bsr.
x;
391 DLOG(
"proposed x = %d, new x is %d\n", event->x, newrect.
x);
393 if (event->value_mask & XCB_CONFIG_WINDOW_Y) {
394 newrect.
y =
event->y + (-1) * bsr.
y;
395 DLOG(
"proposed y = %d, new y is %d\n", event->y, newrect.
y);
397 if (event->value_mask & XCB_CONFIG_WINDOW_WIDTH) {
398 newrect.
width =
event->width + (-1) * bsr.
width;
400 DLOG(
"proposed width = %d, new width is %d (x11 border %d)\n",
403 if (event->value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
406 DLOG(
"proposed height = %d, new height is %d (x11 border %d)\n",
410 DLOG(
"Container is a floating leaf node, will do that.\n");
417 DLOG(
"Dock window, only height reconfiguration allowed\n");
418 if (event->value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
419 DLOG(
"Height given, changing\n");
437 int handle_configure_event(
void *prophs, xcb_connection_t *
conn, xcb_configure_notify_event_t *event) {
438 DLOG(
"configure_event, sequence %d\n", event->sequence);
453 DLOG(
"RandR screen change\n");
457 ipc_send_event(
"output", I3_IPC_EVENT_OUTPUT,
"{\"change\":\"unspecified\"}");
468 DLOG(
"UnmapNotify for 0x%08x (received from 0x%08x), serial %d\n", event->window, event->event, event->sequence);
469 xcb_get_input_focus_cookie_t cookie;
476 LOG(
"Not a managed window, ignoring UnmapNotify event\n");
483 cookie = xcb_get_input_focus(
conn);
484 DLOG(
"ignore_unmap = %d for frame of container %p\n", con->
ignore_unmap, con);
489 cookie = xcb_get_input_focus(
conn);
522 free(xcb_get_input_focus_reply(
conn, cookie, NULL));
535 DLOG(
"destroy notify for 0x%08x, 0x%08x\n", event->event, event->window);
537 xcb_unmap_notify_event_t unmap;
538 unmap.sequence =
event->sequence;
539 unmap.event =
event->event;
540 unmap.window =
event->window;
550 xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *prop) {
568 xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *prop) {
585 xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *prop) {
600 static int handle_windowclass_change(
void *data, xcb_connection_t *
conn, uint8_t
state,
601 xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *prop) {
619 DLOG(
"window = %08x\n", event->window);
622 LOG(
"expose event for unknown window, ignoring\n");
631 event->x, event->y, event->x, event->y,
632 event->width, event->height);
645 if (sn_xcb_display_process_event(
sndisplay, (xcb_generic_event_t*)event))
648 LOG(
"ClientMessage for window 0x%08x\n", event->window);
649 if (event->type == A__NET_WM_STATE) {
650 if (event->format != 32 || event->data.data32[1] != A__NET_WM_STATE_FULLSCREEN) {
651 DLOG(
"atom in clientmessage is %d, fullscreen is %d\n",
652 event->data.data32[1], A__NET_WM_STATE_FULLSCREEN);
653 DLOG(
"not about fullscreen atom\n");
659 DLOG(
"Could not get window for client message\n");
670 DLOG(
"toggling fullscreen\n");
676 }
else if (event->type == A_I3_SYNC) {
677 DLOG(
"i3 sync, yay\n");
678 xcb_window_t window =
event->data.data32[0];
679 uint32_t rnd =
event->data.data32[1];
680 DLOG(
"Sending random value %d back to X11 window 0x%08x\n", rnd, window);
683 xcb_client_message_event_t *ev = reply;
685 ev->response_type = XCB_CLIENT_MESSAGE;
687 ev->type = A_I3_SYNC;
689 ev->data.data32[0] = window;
690 ev->data.data32[1] = rnd;
692 xcb_send_event(conn,
false, window, XCB_EVENT_MASK_NO_EVENT, (
char*)ev);
696 DLOG(
"unhandled clientmessage\n");
702 int handle_window_type(
void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
703 xcb_atom_t atom, xcb_get_property_reply_t *property) {
706 ELOG(
"_NET_WM_WINDOW_TYPE changed, this is not yet implemented.\n");
719 xcb_atom_t name, xcb_get_property_reply_t *reply) {
722 DLOG(
"Received WM_NORMAL_HINTS for unknown client\n");
726 xcb_size_hints_t size_hints;
738 DLOG(
"Minimum size: %d (width) x %d (height)\n", size_hints.min_width, size_hints.min_height);
741 bool changed =
false;
743 if (size_hints.width_inc > 0 && size_hints.width_inc < 0xFFFF)
748 if (size_hints.height_inc > 0 && size_hints.height_inc < 0xFFFF)
755 DLOG(
"resize increments changed\n");
758 int base_width = 0, base_height = 0;
764 base_width = size_hints.base_width;
765 base_height = size_hints.base_height;
768 base_width = size_hints.min_width;
769 base_height = size_hints.min_height;
776 DLOG(
"client's base_height changed to %d\n", base_height);
777 DLOG(
"client's base_width changed to %d\n", base_width);
783 (size_hints.min_aspect_num <= 0) ||
784 (size_hints.min_aspect_den <= 0)) {
785 goto render_and_return;
792 double min_aspect = (double)size_hints.min_aspect_num / size_hints.min_aspect_den;
793 double max_aspect = (
double)size_hints.max_aspect_num / size_hints.min_aspect_den;
795 DLOG(
"Aspect ratio set: minimum %f, maximum %f\n", min_aspect, max_aspect);
796 DLOG(
"width = %f, height = %f\n", width, height);
799 if (max_aspect <= 0 || min_aspect <= 0 || height == 0 || (width / height) <= 0)
800 goto render_and_return;
803 if ((width / height) < min_aspect) {
810 }
else if ((width / height) > max_aspect) {
817 }
else goto render_and_return;
830 static bool handle_hints(
void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t window,
831 xcb_atom_t name, xcb_get_property_reply_t *reply) {
834 DLOG(
"Received WM_HINTS for unknown client\n");
848 DLOG(
"Ignoring urgency flag for current client\n");
865 LOG(
"Urgency flag changed to %d\n", con->
urgent);
890 xcb_atom_t name, xcb_get_property_reply_t *prop) {
894 DLOG(
"No such window\n");
899 prop = xcb_get_property_reply(conn, xcb_get_property_unchecked(conn,
916 xcb_atom_t name, xcb_get_property_reply_t *prop) {
922 prop = xcb_get_property_reply(conn, xcb_get_property_unchecked(conn,
940 DLOG(
"focus change in, for window 0x%08x\n", event->event);
944 DLOG(
"That is con %p / %s\n", con, con->
name);
946 if (event->mode == XCB_NOTIFY_MODE_GRAB ||
947 event->mode == XCB_NOTIFY_MODE_UNGRAB) {
948 DLOG(
"FocusIn event for grab/ungrab, ignoring\n");
952 if (event->detail == XCB_NOTIFY_DETAIL_POINTER) {
953 DLOG(
"notify detail is pointer, ignoring this event\n");
958 DLOG(
"focus matches the currently focused window, not doing anything\n");
964 DLOG(
"This is a dock client, not focusing.\n");
968 DLOG(
"focus is different, updating decorations\n");
986 typedef bool (*
cb_property_handler_t)(
void *data, xcb_connection_t *c, uint8_t
state, xcb_window_t window, xcb_atom_t atom, xcb_get_property_reply_t *property);
1003 #define NUM_HANDLERS (sizeof(property_handlers) / sizeof(struct property_handler_t))
1014 property_handlers[0].
atom = A__NET_WM_NAME;
1018 property_handlers[4].
atom = A_WM_CLIENT_LEADER;
1020 property_handlers[6].
atom = A_WM_WINDOW_ROLE;
1025 xcb_get_property_reply_t *propr = NULL;
1028 if (property_handlers[c].atom != atom)
1031 handler = &property_handlers[c];
1035 if (handler == NULL) {
1040 if (state != XCB_PROPERTY_DELETE) {
1041 xcb_get_property_cookie_t cookie = xcb_get_property(conn, 0, window, atom, XCB_GET_PROPERTY_TYPE_ANY, 0, handler->
long_len);
1042 propr = xcb_get_property_reply(conn, cookie, 0);
1046 if (!handler->
cb(NULL, conn, state, window, atom, propr))
1057 type ==
randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY) {
1067 case XCB_BUTTON_PRESS:
1071 case XCB_MAP_REQUEST:
1075 case XCB_UNMAP_NOTIFY:
1079 case XCB_DESTROY_NOTIFY:
1087 case XCB_MOTION_NOTIFY:
1092 case XCB_ENTER_NOTIFY:
1099 case XCB_CLIENT_MESSAGE:
1104 case XCB_CONFIGURE_REQUEST:
1109 case XCB_MAPPING_NOTIFY:
1117 case XCB_PROPERTY_NOTIFY: {
1118 xcb_property_notify_event_t *e = (xcb_property_notify_event_t*)event;