* vim:ts=4:sw=4:expandtab
*
* i3 - an improved dynamic tiling window manager
- * © 2009-2013 Michael Stapelberg and contributors (see also: LICENSE)
+ * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
*
* manage.c: Initially managing new windows (or existing ones on restart).
*
utf8_title_cookie, title_cookie,
class_cookie, leader_cookie, transient_cookie,
role_cookie, startup_id_cookie, wm_hints_cookie,
- wm_normal_hints_cookie, motif_wm_hints_cookie;
+ wm_normal_hints_cookie, motif_wm_hints_cookie, wm_user_time_cookie;
geomc = xcb_get_geometry(conn, d);
wm_hints_cookie = xcb_icccm_get_wm_hints(conn, window);
wm_normal_hints_cookie = xcb_icccm_get_wm_normal_hints(conn, window);
motif_wm_hints_cookie = GET_PROPERTY(A__MOTIF_WM_HINTS, 5 * sizeof(uint64_t));
+ wm_user_time_cookie = GET_PROPERTY(A__NET_WM_USER_TIME, UINT32_MAX);
DLOG("Managing window 0x%08x\n", window);
- i3Window *cwindow = scalloc(sizeof(i3Window));
+ i3Window *cwindow = scalloc(1, sizeof(i3Window));
cwindow->id = window;
cwindow->depth = get_visual_depth(attr->visual);
- /* We need to grab the mouse buttons for click to focus */
- xcb_grab_button(conn, false, window, XCB_EVENT_MASK_BUTTON_PRESS,
- XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE,
- 1 /* left mouse button */,
- XCB_BUTTON_MASK_ANY /* don’t filter for any modifiers */);
-
- xcb_grab_button(conn, false, window, XCB_EVENT_MASK_BUTTON_PRESS,
- XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE,
- 2 /* middle mouse button */,
- XCB_BUTTON_MASK_ANY /* don’t filter for any modifiers */);
-
- xcb_grab_button(conn, false, window, XCB_EVENT_MASK_BUTTON_PRESS,
- XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE,
- 3 /* right mouse button */,
- XCB_BUTTON_MASK_ANY /* don’t filter for any modifiers */);
+ xcb_grab_buttons(conn, window, bindings_should_grab_scrollwheel_buttons());
/* update as much information as possible so far (some replies may be NULL) */
window_update_class(cwindow, xcb_get_property_reply(conn, class_cookie, NULL), true);
if (match != NULL && match->insert_where != M_BELOW) {
DLOG("Removing match %p from container %p\n", match, nc);
TAILQ_REMOVE(&(nc->swallow_head), match, matches);
+ match_free(match);
}
}
if (nc->window != NULL && nc->window != cwindow) {
if (!restore_kill_placeholder(nc->window->id)) {
DLOG("Uh?! Container without a placeholder, but with a window, has swallowed this to-be-managed window?!\n");
+ } else {
+ /* Remove remaining criteria, the first swallowed window wins. */
+ while (!TAILQ_EMPTY(&(nc->swallow_head))) {
+ Match *first = TAILQ_FIRST(&(nc->swallow_head));
+ TAILQ_REMOVE(&(nc->swallow_head), first, matches);
+ match_free(first);
+ }
}
}
nc->window = cwindow;
want_floating = true;
}
+ if (xcb_reply_contains_atom(state_reply, A__NET_WM_STATE_STICKY))
+ nc->sticky = true;
+
FREE(state_reply);
FREE(type_reply);
if (cwindow->dock)
want_floating = false;
+ /* Plasma windows set their geometry in WM_SIZE_HINTS. */
+ if ((wm_size_hints.flags & XCB_ICCCM_SIZE_HINT_US_POSITION || wm_size_hints.flags & XCB_ICCCM_SIZE_HINT_P_POSITION) &&
+ (wm_size_hints.flags & XCB_ICCCM_SIZE_HINT_US_SIZE || wm_size_hints.flags & XCB_ICCCM_SIZE_HINT_P_SIZE)) {
+ DLOG("We are setting geometry according to wm_size_hints x=%d y=%d w=%d h=%d\n",
+ wm_size_hints.x, wm_size_hints.y, wm_size_hints.width, wm_size_hints.height);
+ geom->x = wm_size_hints.x;
+ geom->y = wm_size_hints.y;
+ geom->width = wm_size_hints.width;
+ geom->height = wm_size_hints.height;
+ }
+
/* Store the requested geometry. The width/height gets raised to at least
* 75x50 when entering floating mode, which is the minimum size for a
* window to be useful (smaller windows are usually overlays/toolbars/…
values[0] = XCB_NONE;
xcb_change_window_attributes(conn, window, XCB_CW_EVENT_MASK, values);
- xcb_void_cookie_t rcookie = xcb_reparent_window_checked(conn, window, nc->frame, 0, 0);
+ xcb_void_cookie_t rcookie = xcb_reparent_window_checked(conn, window, nc->frame.id, 0, 0);
if (xcb_request_check(conn, rcookie) != NULL) {
LOG("Could not reparent the window, aborting\n");
goto geom_out;
/* Send an event about window creation */
ipc_send_window_event("new", nc);
+ if (set_focus && assignment_for(cwindow, A_NO_FOCUS) != NULL) {
+ /* The first window on a workspace should always be focused. We have to
+ * compare with == 1 because the container has already been inserted at
+ * this point. */
+ if (con_num_children(ws) == 1) {
+ DLOG("This is the first window on this workspace, ignoring no_focus.\n");
+ } else {
+ DLOG("no_focus was set for con = %p, not setting focus.\n", nc);
+ set_focus = false;
+ }
+ }
+
+ if (set_focus) {
+ DLOG("Checking con = %p for _NET_WM_USER_TIME.\n", nc);
+
+ uint32_t *wm_user_time;
+ xcb_get_property_reply_t *wm_user_time_reply = xcb_get_property_reply(conn, wm_user_time_cookie, NULL);
+ if (wm_user_time_reply != NULL && xcb_get_property_value_length(wm_user_time_reply) != 0 &&
+ (wm_user_time = xcb_get_property_value(wm_user_time_reply)) &&
+ wm_user_time[0] == 0) {
+ DLOG("_NET_WM_USER_TIME set to 0, not focusing con = %p.\n", nc);
+ set_focus = false;
+ }
+
+ FREE(wm_user_time_reply);
+ } else {
+ xcb_discard_reply(conn, wm_user_time_cookie.sequence);
+ }
+
/* Defer setting focus after the 'new' event has been sent to ensure the
* proper window event sequence. */
if (set_focus && !nc->window->doesnt_accept_focus && nc->mapped) {
- if (assignment_for(cwindow, A_NO_FOCUS) == NULL) {
- DLOG("Now setting focus.\n");
- con_focus(nc);
- }
+ DLOG("Now setting focus.\n");
+ con_focus(nc);
}
tree_render();