#include <float.h>
#include <sys/time.h>
#include <xcb/randr.h>
-#include <X11/XKBlib.h>
#define SN_API_NOT_YET_FROZEN 1
#include <libsn/sn-monitor.h>
ungrab_all_keys(conn);
translate_keysyms();
- grab_all_keys(conn, false);
+ grab_all_keys(conn);
return;
}
return;
}
- /* Dock windows can be reconfigured in their height */
+ /* Dock windows can be reconfigured in their height and moved to another output. */
if (con->parent && con->parent->type == CT_DOCKAREA) {
- DLOG("Dock window, only height reconfiguration allowed\n");
+ DLOG("Reconfiguring dock window (con = %p).\n", con);
if (event->value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
- DLOG("Height given, changing\n");
+ DLOG("Dock client wants to change height to %d, we can do that.\n", event->height);
con->geometry.height = event->height;
tree_render();
}
+
+ if (event->value_mask & XCB_CONFIG_WINDOW_X || event->value_mask & XCB_CONFIG_WINDOW_Y) {
+ int16_t x = event->value_mask & XCB_CONFIG_WINDOW_X ? event->x : (int16_t)con->geometry.x;
+ int16_t y = event->value_mask & XCB_CONFIG_WINDOW_Y ? event->y : (int16_t)con->geometry.y;
+
+ Con *current_output = con_get_output(con);
+ Output *target = get_output_containing(x, y);
+ if (target != NULL && current_output != target->con) {
+ DLOG("Dock client is requested to be moved to output %s, moving it there.\n", target->name);
+ Match *match;
+ Con *nc = con_for_window(target->con, con->window, &match);
+ DLOG("Dock client will be moved to container %p.\n", nc);
+ con_detach(con);
+ con_attach(con, nc, false);
+
+ tree_render();
+ } else {
+ DLOG("Dock client will not be moved, we only support moving it to another output.\n");
+ }
+ }
}
fake_absolute_configure_notify(con);
goto ignore_end;
}
- tree_close(con, DONT_KILL_WINDOW, false, false);
+ /* Since we close the container, we need to unset _NET_WM_DESKTOP and
+ * _NET_WM_STATE according to the spec. */
+ xcb_delete_property(conn, event->window, A__NET_WM_DESKTOP);
+ xcb_delete_property(conn, event->window, A__NET_WM_STATE);
+
+ tree_close_internal(con, DONT_KILL_WINDOW, false, false);
tree_render();
ignore_end:
return;
}
- /* Since we render to our pixmap on every change anyways, expose events
+ /* Since we render to our surface on every change anyways, expose events
* only tell us that the X server lost (parts of) the window contents. We
- * can handle that by copying the appropriate part from our pixmap to the
+ * can handle that by copying the appropriate part from our surface to the
* window. */
- xcb_copy_area(conn, parent->pixmap, parent->frame, parent->pm_gc,
- event->x, event->y, event->x, event->y,
- event->width, event->height);
+ draw_util_copy_surface(conn, &(parent->frame_buffer), &(parent->frame),
+ event->x, event->y, event->x, event->y,
+ event->width, event->height);
xcb_flush(conn);
-
return;
}
if (event->type == A__NET_WM_STATE) {
if (event->format != 32 ||
(event->data.data32[1] != A__NET_WM_STATE_FULLSCREEN &&
- event->data.data32[1] != A__NET_WM_STATE_DEMANDS_ATTENTION)) {
+ event->data.data32[1] != A__NET_WM_STATE_DEMANDS_ATTENTION &&
+ event->data.data32[1] != A__NET_WM_STATE_STICKY)) {
DLOG("Unknown atom in clientmessage of type %d\n", event->data.data32[1]);
return;
}
con_set_urgency(con, false);
else if (event->data.data32[0] == _NET_WM_STATE_TOGGLE)
con_set_urgency(con, !con->urgent);
+ } else if (event->data.data32[1] == A__NET_WM_STATE_STICKY) {
+ DLOG("Received a client message to modify _NET_WM_STATE_STICKY.\n");
+ if (event->data.data32[0] == _NET_WM_STATE_ADD)
+ con->sticky = true;
+ else if (event->data.data32[0] == _NET_WM_STATE_REMOVE)
+ con->sticky = false;
+ else if (event->data.data32[0] == _NET_WM_STATE_TOGGLE)
+ con->sticky = !con->sticky;
+
+ DLOG("New sticky status for con = %p is %i.\n", con, con->sticky);
+ ewmh_update_sticky(con->window->id, con->sticky);
+ output_push_sticky_windows(focused);
+ ewmh_update_wm_desktop();
}
tree_render();
uint32_t rnd = event->data.data32[1];
DLOG("[i3 sync protocol] Sending random value %d back to X11 window 0x%08x\n", rnd, window);
- void *reply = scalloc(32);
+ void *reply = scalloc(32, 1);
xcb_client_message_event_t *ev = reply;
ev->response_type = XCB_CLIENT_MESSAGE;
* a request to focus the given workspace. See
* http://standards.freedesktop.org/wm-spec/latest/ar01s03.html#idm140251368135008
* */
- Con *output;
- uint32_t idx = 0;
DLOG("Request to change current desktop to index %d\n", event->data.data32[0]);
+ Con *ws = ewmh_get_workspace_by_index(event->data.data32[0]);
+ if (ws == NULL) {
+ ELOG("Could not determine workspace for this index, ignoring request.\n");
+ return;
+ }
- TAILQ_FOREACH(output, &(croot->nodes_head), nodes) {
- Con *ws;
- TAILQ_FOREACH(ws, &(output_get_content(output)->nodes_head), nodes) {
- if (STARTS_WITH(ws->name, "__"))
- continue;
-
- if (idx == event->data.data32[0]) {
- /* data32[1] is a timestamp used to prevent focus race conditions */
- if (event->data.data32[1])
- last_timestamp = event->data.data32[1];
+ DLOG("Handling request to focus workspace %s\n", ws->name);
+ workspace_show(ws);
+ tree_render();
+ } else if (event->type == A__NET_WM_DESKTOP) {
+ uint32_t index = event->data.data32[0];
+ DLOG("Request to move window %d to EWMH desktop index %d\n", event->window, index);
- DLOG("Handling request to focus workspace %s\n", ws->name);
+ Con *con = con_by_window_id(event->window);
+ if (con == NULL) {
+ DLOG("Couldn't find con for window %d, ignoring the request.\n", event->window);
+ return;
+ }
- workspace_show(ws);
- tree_render();
+ if (index == NET_WM_DESKTOP_ALL) {
+ /* The window is requesting to be visible on all workspaces, so
+ * let's float it and make it sticky. */
+ DLOG("The window was requested to be visible on all workspaces, making it sticky and floating.\n");
- return;
- }
+ floating_enable(con, false);
- ++idx;
+ con->sticky = true;
+ ewmh_update_sticky(con->window->id, true);
+ output_push_sticky_windows(focused);
+ } else {
+ Con *ws = ewmh_get_workspace_by_index(index);
+ if (ws == NULL) {
+ ELOG("Could not determine workspace for this index, ignoring request.\n");
+ return;
}
+
+ con_move_to_workspace(con, ws, true, false, false);
}
+
+ tree_render();
+ ewmh_update_wm_desktop();
} else if (event->type == A__NET_CLOSE_WINDOW) {
/*
* Pagers wanting to close a window MUST send a _NET_CLOSE_WINDOW
if (event->data.data32[0])
last_timestamp = event->data.data32[0];
- tree_close(con, KILL_WINDOW, false, false);
+ tree_close_internal(con, KILL_WINDOW, false, false);
tree_render();
} else {
DLOG("Couldn't find con for _NET_CLOSE_WINDOW request. (window = %d)\n", event->window);
break;
}
} else {
- DLOG("unhandled clientmessage\n");
- return;
+ DLOG("Skipping client message for unhandled type %d\n", event->type);
}
}
bool changed = false;
if ((size_hints.flags & XCB_ICCCM_SIZE_HINT_P_RESIZE_INC)) {
if (size_hints.width_inc > 0 && size_hints.width_inc < 0xFFFF)
- if (con->width_increment != size_hints.width_inc) {
- con->width_increment = size_hints.width_inc;
+ if (con->window->width_increment != size_hints.width_inc) {
+ con->window->width_increment = size_hints.width_inc;
changed = true;
}
if (size_hints.height_inc > 0 && size_hints.height_inc < 0xFFFF)
- if (con->height_increment != size_hints.height_inc) {
- con->height_increment = size_hints.height_inc;
+ if (con->window->height_increment != size_hints.height_inc) {
+ con->window->height_increment = size_hints.height_inc;
changed = true;
}
base_height = size_hints.min_height;
}
- if (base_width != con->base_width ||
- base_height != con->base_height) {
- con->base_width = base_width;
- con->base_height = base_height;
+ if (base_width != con->window->base_width ||
+ base_height != con->window->base_height) {
+ con->window->base_width = base_width;
+ con->window->base_height = base_height;
DLOG("client's base_height changed to %d\n", base_height);
DLOG("client's base_width changed to %d\n", base_width);
changed = true;
} else
goto render_and_return;
- if (fabs(con->aspect_ratio - aspect_ratio) > DBL_EPSILON) {
- con->aspect_ratio = aspect_ratio;
+ if (fabs(con->window->aspect_ratio - aspect_ratio) > DBL_EPSILON) {
+ con->window->aspect_ratio = aspect_ratio;
changed = true;
}
*
*/
void handle_event(int type, xcb_generic_event_t *event) {
- DLOG("event type %d, xkb_base %d\n", type, xkb_base);
+ if (type != XCB_MOTION_NOTIFY)
+ DLOG("event type %d, xkb_base %d\n", type, xkb_base);
+
if (randr_base > -1 &&
type == randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY) {
handle_screen_change(event);
DLOG("xkb new keyboard notify, sequence %d, time %d\n", state->sequence, state->time);
xcb_key_symbols_free(keysyms);
keysyms = xcb_key_symbols_alloc(conn);
+ if (((xcb_xkb_new_keyboard_notify_event_t *)event)->changed & XCB_XKB_NKN_DETAIL_KEYCODES)
+ (void)load_keymap();
ungrab_all_keys(conn);
translate_keysyms();
- grab_all_keys(conn, false);
+ grab_all_keys(conn);
} else if (state->xkbType == XCB_XKB_MAP_NOTIFY) {
if (event_is_ignored(event->sequence, type)) {
DLOG("Ignoring map notify event for sequence %d.\n", state->sequence);
keysyms = xcb_key_symbols_alloc(conn);
ungrab_all_keys(conn);
translate_keysyms();
- grab_all_keys(conn, false);
+ grab_all_keys(conn);
+ (void)load_keymap();
}
} else if (state->xkbType == XCB_XKB_STATE_NOTIFY) {
DLOG("xkb state group = %d\n", state->group);
-
- /* See The XKB Extension: Library Specification, section 14.1 */
- /* We check if the current group (each group contains
- * two levels) has been changed. Mode_switch activates
- * group XCB_XKB_GROUP_2 */
if (xkb_current_group == state->group)
return;
xkb_current_group = state->group;
- if (state->group == XCB_XKB_GROUP_1) {
- DLOG("Mode_switch disabled\n");
- ungrab_all_keys(conn);
- grab_all_keys(conn, false);
- } else {
- DLOG("Mode_switch enabled\n");
- grab_all_keys(conn, true);
- }
+ ungrab_all_keys(conn);
+ grab_all_keys(conn);
}
return;