#include "manage.h"
#include "floating.h"
#include "client.h"
+#include "workspace.h"
/*
* Go through all existing windows (if the window manager is restarted) and manage them
void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *conn,
xcb_window_t window, xcb_get_window_attributes_cookie_t cookie,
bool needs_to_be_mapped) {
- LOG("managing window.\n");
xcb_drawable_t d = { window };
xcb_get_geometry_cookie_t geomc;
xcb_get_geometry_reply_t *geom;
return;
}
- if (needs_to_be_mapped && attr->map_state != XCB_MAP_STATE_VIEWABLE) {
- LOG("Window not mapped, not managing\n");
+ if (needs_to_be_mapped && attr->map_state != XCB_MAP_STATE_VIEWABLE)
goto out;
- }
/* Don’t manage clients with the override_redirect flag */
- if (attr->override_redirect) {
- LOG("override_redirect set, not managing\n");
+ if (attr->override_redirect)
goto out;
- }
/* Check if the window is already managed */
if (table_get(&by_child, window))
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_NAME);
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_NORMAL_HINTS);
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_TRANSIENT_FOR);
+ xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, atoms[WM_CLIENT_LEADER]);
xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, atoms[_NET_WM_NAME]);
free(geom);
int16_t x, int16_t y, uint16_t width, uint16_t height) {
xcb_get_property_cookie_t wm_type_cookie, strut_cookie, state_cookie,
- utf8_title_cookie, title_cookie, class_cookie;
+ utf8_title_cookie, title_cookie,
+ class_cookie, leader_cookie;
uint32_t mask = 0;
uint32_t values[3];
uint16_t original_height = height;
+ bool map_frame = true;
/* We are interested in property changes */
mask = XCB_CW_EVENT_MASK;
strut_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STRUT_PARTIAL], UINT32_MAX);
state_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STATE], UINT32_MAX);
utf8_title_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_NAME], 128);
+ leader_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[WM_CLIENT_LEADER], UINT32_MAX);
title_cookie = xcb_get_any_property_unchecked(conn, false, child, WM_NAME, 128);
- class_cookie = xcb_get_any_property_unchecked(conn, false, child, WM_CLASS, 128);
+ class_cookie = xcb_get_any_property_unchecked(conn, false, child, WM_CLASS, 128);
Client *new = table_get(&by_child, child);
/* Events for already managed windows should already be filtered in manage_window() */
assert(new == NULL);
- LOG("reparenting new client\n");
+ LOG("Reparenting window 0x%08x\n", child);
LOG("x = %d, y = %d, width = %d, height = %d\n", x, y, width, height);
new = calloc(sizeof(Client), 1);
new->force_reconfigure = true;
new->child = child;
new->rect.width = width;
new->rect.height = height;
+ new->width_increment = 1;
+ new->height_increment = 1;
/* Pre-initialize the values for floating */
new->floating_rect.x = -1;
new->floating_rect.width = width;
mask |= XCB_CW_EVENT_MASK;
values[1] = FRAME_EVENT_MASK;
- LOG("Reparenting 0x%08x under 0x%08x.\n", child, new->frame);
-
i3Font *font = load_font(conn, config.font);
width = min(width, c_ws->rect.x + c_ws->rect.width);
height = min(height, c_ws->rect.y + c_ws->rect.height);
/* Yo dawg, I heard you like windows, so I create a window around your window… */
new->frame = create_window(conn, framerect, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_CURSOR_LEFT_PTR, false, mask, values);
- /* Set WM_STATE_NORMAL because GTK applications don’t want to drag & drop if we don’t.
- * Also, xprop(1) needs that to work. */
- long data[] = { XCB_WM_STATE_NORMAL, XCB_NONE };
- xcb_change_property(conn, XCB_PROP_MODE_REPLACE, new->child, atoms[WM_STATE], atoms[WM_STATE], 32, 2, data);
-
/* Put the client inside the save set. Upon termination (whether killed or normal exit
does not matter) of the window manager, these clients will be correctly reparented
to their most closest living ancestor (= cleanup) */
if (atom[i] == atoms[_NET_WM_WINDOW_TYPE_DOCK]) {
LOG("Window is a dock.\n");
new->dock = true;
+ new->borderless = true;
new->titlebar_position = TITLEBAR_OFF;
new->force_reconfigure = true;
new->container = NULL;
SLIST_INSERT_HEAD(&(c_ws->screen->dock_clients), new, dock_clients);
/* If it’s a dock we can’t make it float, so we break */
+ new->floating = FLOATING_AUTO_OFF;
break;
} else if (atom[i] == atoms[_NET_WM_WINDOW_TYPE_DIALOG] ||
atom[i] == atoms[_NET_WM_WINDOW_TYPE_UTILITY] ||
}
}
+ /* All clients which have a leader should be floating */
+ if (!new->dock && !client_is_floating(new) && new->leader != 0) {
+ LOG("Client has WM_CLIENT_LEADER hint set, setting floating\n");
+ new->floating = FLOATING_AUTO_ON;
+ }
+
if (new->workspace->auto_float) {
new->floating = FLOATING_AUTO_ON;
LOG("workspace is in autofloat mode, setting floating\n");
preply = xcb_get_property_reply(conn, class_cookie, NULL);
handle_windowclass_change(NULL, conn, 0, new->child, WM_CLASS, preply);
- LOG("DEBUG: should have all infos now\n");
+ preply = xcb_get_property_reply(conn, leader_cookie, NULL);
+ handle_clientleader_change(NULL, conn, 0, new->child, atoms[WM_CLIENT_LEADER], preply);
+
struct Assignment *assign;
TAILQ_FOREACH(assign, &assignments, assignments) {
if (get_matching_client(conn, assign->windowclass_title, new) == NULL)
break;
}
- LOG("Changin container/workspace and unmapping the client\n");
+ LOG("Changing container/workspace and unmapping the client\n");
Workspace *t_ws = &(workspaces[assign->workspace-1]);
- if (t_ws->screen == NULL) {
- LOG("initializing new workspace, setting num to %d\n", assign->workspace);
- t_ws->screen = c_ws->screen;
- /* Copy the dimensions from the virtual screen */
- memcpy(&(t_ws->rect), &(t_ws->screen->rect), sizeof(Rect));
- }
+ workspace_initialize(t_ws, c_ws->screen);
new->container = t_ws->table[t_ws->current_col][t_ws->current_row];
new->workspace = t_ws;
old_focused = new->container->currently_focused;
- xcb_unmap_window(conn, new->frame);
+ map_frame = workspace_is_visible(t_ws);
break;
}
}
new->container = NULL;
- new->floating_rect.x = new->rect.x = x;
- new->floating_rect.y = new->rect.y = y;
new->rect.width = new->floating_rect.width + 2 + 2;
new->rect.height = new->floating_rect.height + (font->height + 2 + 2) + 2;
+
+ /* Some clients (like GIMP’s color picker window) get mapped
+ * to (0, 0), so we push them to a reasonable position
+ * (centered over their leader) */
+ if (new->leader != 0 && x == 0 && y == 0) {
+ LOG("Floating client wants to (0x0), moving it over its leader instead\n");
+ Client *leader = table_get(&by_child, new->leader);
+ if (leader == NULL) {
+ LOG("leader is NULL, centering it over current workspace\n");
+
+ x = c_ws->rect.x + (c_ws->rect.width / 2) - (new->rect.width / 2);
+ y = c_ws->rect.y + (c_ws->rect.height / 2) - (new->rect.height / 2);
+ } else {
+ x = leader->rect.x + (leader->rect.width / 2) - (new->rect.width / 2);
+ y = leader->rect.y + (leader->rect.height / 2) - (new->rect.height / 2);
+ }
+ }
+ new->floating_rect.x = new->rect.x = x;
+ new->floating_rect.y = new->rect.y = y;
LOG("copying floating_rect from tiling (%d, %d) size (%d, %d)\n",
new->floating_rect.x, new->floating_rect.y,
new->floating_rect.width, new->floating_rect.height);
and don’t event bother to redraw the layout – that would not change
anything anyways */
client_toggle_fullscreen(conn, new);
- return;
+ goto map;
}
render_layout(conn);
+map:
/* Map the window first to avoid flickering */
- xcb_map_window(conn, new->frame);
xcb_map_window(conn, child);
- if (CUR_CELL->workspace->fullscreen_client == NULL && !new->dock) {
+ if (map_frame)
+ client_map(conn, new);
+
+ if ((CUR_CELL->workspace->fullscreen_client == NULL || new->fullscreen) && !new->dock) {
/* Focus the new window if we’re not in fullscreen mode and if it is not a dock window */
- if (new->container->workspace->fullscreen_client == NULL) {
+ if ((new->workspace->fullscreen_client == NULL) || new->fullscreen) {
if (!client_is_floating(new))
new->container->currently_focused = new;
- if (new->container == CUR_CELL)
+ if (new->container == CUR_CELL || client_is_floating(new))
xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, new->child, XCB_CURRENT_TIME);
}
}