+#undef I3__FILE__
+#define I3__FILE__ "manage.c"
/*
* vim:ts=4:sw=4:expandtab
*
* i3 - an improved dynamic tiling window manager
- * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE)
+ * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
*
- * manage.c: Contains all functions for initially managing new windows
- * (or existing ones on restart).
+ * manage.c: Initially managing new windows (or existing ones on restart).
*
*/
-
#include "all.h"
/*
* side-effects which are to be expected when continuing to run i3.
*
*/
-void restore_geometry() {
+void restore_geometry(void) {
DLOG("Restoring geometry\n");
Con *con;
xcb_get_geometry_reply_t *geom;
xcb_get_window_attributes_reply_t *attr = NULL;
- DLOG("---> looking at window 0x%08x\n", window);
-
xcb_get_property_cookie_t wm_type_cookie, strut_cookie, state_cookie,
utf8_title_cookie, title_cookie,
class_cookie, leader_cookie, transient_cookie,
- role_cookie, startup_id_cookie;
+ role_cookie, startup_id_cookie, wm_hints_cookie;
geomc = xcb_get_geometry(conn, d);
}
if (needs_to_be_mapped && attr->map_state != XCB_MAP_STATE_VIEWABLE) {
- DLOG("map_state unviewable\n");
FREE_GEOMETRY();
goto out;
}
/* Don’t manage clients with the override_redirect flag */
- DLOG("override_redirect is %d\n", attr->override_redirect);
if (attr->override_redirect) {
FREE_GEOMETRY();
goto out;
uint32_t values[1];
/* Set a temporary event mask for the new window, consisting only of
- * PropertyChange. We need to be notified of PropertyChanges because the
- * client can change its properties *after* we requested them but *before*
- * we actually reparented it and have set our final event mask. */
- values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE;
- xcb_change_window_attributes(conn, window, XCB_CW_EVENT_MASK, values);
+ * PropertyChange and StructureNotify. We need to be notified of
+ * PropertyChanges because the client can change its properties *after* we
+ * requested them but *before* we actually reparented it and have set our
+ * final event mask.
+ * We need StructureNotify because the client may unmap the window before
+ * we get to re-parent it.
+ * If this request fails, we assume the client has already unmapped the
+ * window between the MapRequest and our event mask change. */
+ values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE |
+ XCB_EVENT_MASK_STRUCTURE_NOTIFY;
+ xcb_void_cookie_t event_mask_cookie =
+ xcb_change_window_attributes_checked(conn, window, XCB_CW_EVENT_MASK, values);
+ if (xcb_request_check(conn, event_mask_cookie) != NULL) {
+ LOG("Could not change event mask, the window probably already disappeared.\n");
+ goto out;
+ }
#define GET_PROPERTY(atom, len) xcb_get_property(conn, false, window, atom, XCB_GET_PROPERTY_TYPE_ANY, 0, len)
class_cookie = GET_PROPERTY(XCB_ATOM_WM_CLASS, 128);
role_cookie = GET_PROPERTY(A_WM_WINDOW_ROLE, 128);
startup_id_cookie = GET_PROPERTY(A__NET_STARTUP_ID, 512);
+ wm_hints_cookie = xcb_icccm_get_wm_hints(conn, window);
/* TODO: also get wm_normal_hints here. implement after we got rid of xcb-event */
- DLOG("reparenting!\n");
+ DLOG("Managing window 0x%08x\n", window);
i3Window *cwindow = scalloc(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,
window_update_transient_for(cwindow, xcb_get_property_reply(conn, transient_cookie, NULL));
window_update_strut_partial(cwindow, xcb_get_property_reply(conn, strut_cookie, NULL));
window_update_role(cwindow, xcb_get_property_reply(conn, role_cookie, NULL), true);
+ window_update_hints(cwindow, xcb_get_property_reply(conn, wm_hints_cookie, NULL));
xcb_get_property_reply_t *startup_id_reply;
startup_id_reply = xcb_get_property_reply(conn, startup_id_cookie, NULL);
DLOG("Initial geometry: (%d, %d, %d, %d)\n", geom->x, geom->y, geom->width, geom->height);
Con *nc = NULL;
- Match *match;
+ Match *match = NULL;
Assignment *assignment;
/* TODO: two matches for one container */
nc->border_width = geom->border_width;
char *name;
- asprintf(&name, "[i3 con] container around %p", cwindow);
+ sasprintf(&name, "[i3 con] container around %p", cwindow);
x_set_name(nc, name);
free(name);
if (fs == NULL) {
DLOG("Not in fullscreen mode, focusing\n");
if (!cwindow->dock) {
- /* Check that the workspace is visible. If the window was assigned
- * to an invisible workspace, we should not steal focus. */
- if (workspace_is_visible(ws)) {
- con_focus(nc);
+ /* Check that the workspace is visible and on the same output as
+ * the current focused container. If the window was assigned to an
+ * invisible workspace, we should not steal focus. */
+ Con *current_output = con_get_output(focused);
+ Con *target_output = con_get_output(ws);
+
+ if (workspace_is_visible(ws) && current_output == target_output) {
+ if (!match || !match->restart_mode) {
+ con_focus(nc);
+ } else DLOG("not focusing, matched with restart_mode == true\n");
} else DLOG("workspace not visible, not focusing\n");
} else DLOG("dock, not focusing\n");
} else {
(cwindow->leader != XCB_NONE &&
cwindow->leader != cwindow->id &&
con_by_window_id(cwindow->leader) != NULL)) {
- LOG("This window is transiert for another window, setting floating\n");
+ LOG("This window is transient for another window, setting floating\n");
want_floating = true;
if (config.popup_during_fullscreen == PDF_LEAVE_FULLSCREEN &&
/* Check if any assignments match */
run_assignments(cwindow);
+ /* If this window was put onto an invisible workspace (via assignments), we
+ * render this workspace. It wouldn’t be rendered in our normal code path
+ * because only the visible workspaces get rendered.
+ *
+ * By rendering the workspace, we assign proper coordinates (read: not
+ * width=0, height=0) to the window, which is important for windows who
+ * actually use them to position their GUI elements, e.g. rhythmbox. */
+ if (ws && !workspace_is_visible(ws)) {
+ /* This is a bit hackish: we need to copy the content container’s rect
+ * to the workspace, because calling render_con() on the content
+ * container would also take the shortcut and not render the invisible
+ * workspace at all. However, just calling render_con() on the
+ * workspace isn’t enough either — it needs the rect. */
+ ws->rect = ws->parent->rect;
+ render_con(ws, true);
+ }
tree_render();
geom_out: