/* Do plausibility checks: This event may be useless for us if it occurs on a window
which is in a stacked container but not the focused one */
- if (client->container->mode == MODE_STACK && client->container->currently_focused != client) {
+ if (client->container != NULL &&
+ client->container->mode == MODE_STACK &&
+ client->container->currently_focused != client) {
LOG("Plausibility check says: no\n");
return 1;
}
wa.u.override_redirect = reply->override_redirect;
LOG("window = 0x%08x, serial is %d.\n", event->window, event->sequence);
add_ignore_event(event->sequence);
+
manage_window(prophs, conn, event->window, wa);
return 1;
}
}
}
+ if (client->dock) {
+ LOG("Removing from dock clients\n");
+ SLIST_REMOVE(&(client->workspace->dock_clients), client, Client, dock_clients);
+ }
+
LOG("child of 0x%08x.\n", client->frame);
xcb_reparent_window(conn, client->child, root, 0, 0);
xcb_destroy_window(conn, client->frame);
xcb_flush(conn);
table_remove(byParent, client->frame);
- cleanup_table(conn, client->container->workspace);
+ if (client->container != NULL)
+ cleanup_table(conn, client->container->workspace);
free(client);
return 1;
}
-/*
- * This handler makes sure that windows are closed correctly as we drop the first unmap event we
- * get because they are sometimes generated by remapping.
- *
- * FIXME: Rather than providing this event, I’d rather know why some applications need to have
- * unmap events ignored (like VLC’s open dialog, just open it two times) while others don’t (GIMP).
- * For now, just make it work.
- *
- */
-int handle_destroy_notify_event(void *data, xcb_connection_t *conn, xcb_destroy_notify_event_t *event) {
- LOG("Destroynotify, faking unmapnotify\n");
- return handle_unmap_notify_event(data, conn, (xcb_unmap_notify_event_t*)event);
-}
-
/*
* Called when a window changes its title
*
if (old_name != NULL)
free(old_name);
+ /* If the client is a dock window, we don’t need to render anything */
+ if (client->dock)
+ return 1;
+
if (client->container->mode == MODE_STACK)
render_container(conn, client->container);
else decorate_window(conn, client, client->frame, client->titlegc, 0);
}
LOG("got client %s\n", client->name);
+ if (client->dock) {
+ LOG("this is a dock\n");
+ return 1;
+ }
+
if (client->container->mode != MODE_STACK)
decorate_window(conn, client, client->frame, client->titlegc, 0);
else {
*
*/
static void reposition_client(xcb_connection_t *conn, Client *client) {
- LOG("frame needs to be pushed to %dx%d\n", client->rect.x, client->rect.y);
+ LOG("frame 0x%08x needs to be pushed to %dx%d\n", client->frame, client->rect.x, client->rect.y);
/* Note: We can use a pointer to client->x like an array of uint32_ts
because it is followed by client->y by definition */
xcb_configure_window(conn, client->frame, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, &(client->rect.x));
static void resize_client(xcb_connection_t *conn, Client *client) {
i3Font *font = load_font(conn, config.font);
- LOG("resizing client to %d x %d\n", client->rect.width, client->rect.height);
+ LOG("resizing client 0x%08x to %d x %d\n", client->frame, client->rect.width, client->rect.height);
xcb_configure_window(conn, client->frame,
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
&(client->rect.width));
XCB_CONFIG_WINDOW_WIDTH |
XCB_CONFIG_WINDOW_HEIGHT;
Rect *rect = &(client->child_rect);
- switch (client->container->mode) {
+ switch ((client->container != NULL ? client->container->mode : MODE_DEFAULT)) {
case MODE_STACK:
rect->x = 2;
rect->y = 0;
static void render_bars(xcb_connection_t *conn, Workspace *r_ws, int width, int *height) {
Client *client;
SLIST_FOREACH(client, &(r_ws->dock_clients), dock_clients) {
+ LOG("client is at %d, should be at %d\n", client->rect.y, *height);
if (client->force_reconfigure |
update_if_necessary(&(client->rect.x), 0) |
update_if_necessary(&(client->rect.y), *height))
int16_t x, int16_t y, uint16_t width, uint16_t height) {
xcb_get_property_cookie_t wm_type_cookie, strut_cookie;
+ uint32_t mask = 0;
+ uint32_t values[3];
- /* Place requests for properties ASAP */
- wm_type_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_WINDOW_TYPE], UINT32_MAX);
- strut_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STRUT_PARTIAL], UINT32_MAX);
+ /* We are interested in property changes */
+ mask = XCB_CW_EVENT_MASK;
+ values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE |
+ XCB_EVENT_MASK_STRUCTURE_NOTIFY |
+ XCB_EVENT_MASK_ENTER_WINDOW;
+ xcb_change_window_attributes(conn, child, mask, values);
/* Map the window first to avoid flickering */
xcb_map_window(conn, child);
+ /* Place requests for properties ASAP */
+ wm_type_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_WINDOW_TYPE], UINT32_MAX);
+ strut_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STRUT_PARTIAL], UINT32_MAX);
+
Client *new = table_get(byChild, child);
/* Events for already managed windows should already be filtered in manage_window() */
LOG("reparenting new client\n");
new = calloc(sizeof(Client), 1);
new->force_reconfigure = true;
- uint32_t mask = 0;
- uint32_t values[3];
/* Update the data structures */
Client *old_focused = CUR_CELL->currently_focused;
new->container = CUR_CELL;
+ new->workspace = new->container->workspace;
new->frame = xcb_generate_id(conn);
new->child = child;
new->rect.width = width;
new->rect.height = height;
+ mask = 0;
+
/* Don’t generate events for our new window, it should *not* be managed */
mask |= XCB_CW_OVERRIDE_REDIRECT;
values[0] = 1;
return;
}
- /* We are interested in property changes */
- mask = XCB_CW_EVENT_MASK;
- values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE |
- XCB_EVENT_MASK_STRUCTURE_NOTIFY |
- XCB_EVENT_MASK_ENTER_WINDOW;
- cookie = xcb_change_window_attributes_checked(conn, child, mask, values);
- if (xcb_request_check(conn, cookie) != NULL) {
- LOG("Could not change window attributes, aborting\n");
- xcb_destroy_window(conn, new->frame);
- free(new);
- return;
- }
-
/* Put our data structure (Client) into the table */
table_put(byParent, new->frame, new);
table_put(byChild, child, new);
1 /* left mouse button */,
XCB_BUTTON_MASK_ANY /* don’t filter for any modifiers */);
- /* Focus the new window if we’re not in fullscreen mode */
- if (CUR_CELL->workspace->fullscreen_client == NULL) {
- CUR_CELL->currently_focused = new;
- xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, new->child, XCB_CURRENT_TIME);
- } else {
- /* If we are in fullscreen, we should lower the window to not be annoying */
- uint32_t values[] = { XCB_STACK_MODE_BELOW };
- xcb_configure_window(conn, new->frame, XCB_CONFIG_WINDOW_STACK_MODE, values);
- }
-
/* Get _NET_WM_WINDOW_TYPE (to see if it’s a dock) */
xcb_atom_t *atom;
xcb_get_property_reply_t *preply = xcb_get_property_reply(conn, wm_type_cookie, NULL);
}
}
- /* Get _NET_WM_STRUT_PARTIAL to determine the client’s requested height */
- uint32_t *strut;
- preply = xcb_get_property_reply(conn, strut_cookie, NULL);
- if (preply != NULL && preply->value_len > 0 && (strut = xcb_get_property_value(preply))) {
- /* We only use a subset of the provided values, namely the reserved space at the top/bottom
- of the screen. This is because the only possibility for bars is at to be at the top/bottom
- with maximum horizontal size.
- TODO: bars at the top */
- new->desired_height = strut[3];
- LOG("the client wants to be %d pixels height\n", new->desired_height);
+ if (new->dock) {
+ /* Get _NET_WM_STRUT_PARTIAL to determine the client’s requested height */
+ uint32_t *strut;
+ preply = xcb_get_property_reply(conn, strut_cookie, NULL);
+ if (preply != NULL && preply->value_len > 0 && (strut = xcb_get_property_value(preply))) {
+ /* We only use a subset of the provided values, namely the reserved space at the top/bottom
+ of the screen. This is because the only possibility for bars is at to be at the top/bottom
+ with maximum horizontal size.
+ TODO: bars at the top */
+ new->desired_height = strut[3];
+ if (new->desired_height == 0) {
+ LOG("Client wanted to be 0 pixels high, using the window's height (%d)\n", height);
+ new->desired_height = height;
+ }
+ LOG("the client wants to be %d pixels high\n", new->desired_height);
+ } else {
+ LOG("The client didn't specify space to reserve at the screen edge, using its height (%d)\n", height);
+ new->desired_height = height;
+ }
+ }
+
+ /* Focus the new window if we’re not in fullscreen mode and if it is not a dock window */
+ if (CUR_CELL->workspace->fullscreen_client == NULL) {
+ if (!new->dock) {
+ CUR_CELL->currently_focused = new;
+ xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, new->child, XCB_CURRENT_TIME);
+ }
+ } else {
+ /* If we are in fullscreen, we should lower the window to not be annoying */
+ uint32_t values[] = { XCB_STACK_MODE_BELOW };
+ xcb_configure_window(conn, new->frame, XCB_CONFIG_WINDOW_STACK_MODE, values);
}
/* Insert into the currently active container, if it’s not a dock window */
if (!new->dock) {
/* Insert after the old active client, if existing. If it does not exist, the
container is empty and it does not matter, where we insert it */
- if (old_focused != NULL)
+ if (old_focused != NULL && !old_focused->dock)
CIRCLEQ_INSERT_AFTER(&(CUR_CELL->clients), old_focused, new, clients);
else CIRCLEQ_INSERT_TAIL(&(CUR_CELL->clients), new, clients);
it any longer. Usually, the client destroys the window shortly afterwards. */
xcb_event_set_unmap_notify_handler(&evenths, handle_unmap_notify_event, NULL);
- /* Destroy notify is a step further than unmap notify. We handle it to make sure
- that windows whose unmap notify was falsely ignored will get deleted properly */
- xcb_event_set_destroy_notify_handler(&evenths, handle_destroy_notify_event, NULL);
-
/* Configure notify = window’s configuration (geometry, stacking, …). We only need
it to set up ignore the following enter_notify events */
xcb_event_set_configure_notify_handler(&evenths, handle_configure_event, NULL);