From 0cb5d7448d1db3db79f4cf374b0968dd7b5ecf06 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 31 May 2009 00:31:18 +0200 Subject: [PATCH] Implement clients going automatically into floating --- include/data.h | 11 +++++++++-- include/floating.h | 5 ++++- src/client.c | 2 +- src/commands.c | 10 +++++----- src/floating.c | 13 +++++++++---- src/handlers.c | 19 +++++++++++++++---- src/layout.c | 4 ++-- src/manage.c | 4 +++- src/util.c | 2 +- 9 files changed, 49 insertions(+), 21 deletions(-) diff --git a/include/data.h b/include/data.h index 7308f5c1..5354217b 100644 --- a/include/data.h +++ b/include/data.h @@ -242,6 +242,10 @@ struct Font { * */ struct Client { + /* initialized will be set to true if the client was fully initialized by + * manage_window() and all functions can be used normally */ + bool initialized; + /* if you set a client to floating and set it back to managed, it does remember its old position and *tries* to get back there */ Cell old_position; @@ -284,8 +288,11 @@ struct Client { /* fullscreen is pretty obvious */ bool fullscreen; - /* floating? (= not in tiling layout) */ - bool floating; + /* floating? (= not in tiling layout) This cannot be simply a bool because we want to keep track + * of whether the status was set by the application (by setting WM_CLASS to tools for example) or + * by the user. The user’s choice overwrites automatic mode, of course. The order of the values + * is important because we check with >= FLOATING_AUTO_ON if a client is floating. */ + enum { FLOATING_AUTO_OFF = 0, FLOATING_USER_OFF = 1, FLOATING_AUTO_ON = 2, FLOATING_USER_ON = 3 } floating; /* Ensure TITLEBAR_TOP maps to 0 because we use calloc for initialization later */ enum { TITLEBAR_TOP = 0, TITLEBAR_LEFT, TITLEBAR_RIGHT, TITLEBAR_BOTTOM, TITLEBAR_OFF } titlebar_position; diff --git a/include/floating.h b/include/floating.h index aa3c55b7..232e118e 100644 --- a/include/floating.h +++ b/include/floating.h @@ -16,8 +16,11 @@ * Correctly takes care of the position/size (separately stored for tiling/floating mode) * and repositions/resizes/redecorates the client. * + * If the automatic flag is set to true, this was an automatic update by a change of the + * window class from the application which can be overwritten by the user. + * */ -void toggle_floating_mode(xcb_connection_t *conn, Client *client); +void toggle_floating_mode(xcb_connection_t *conn, Client *client, bool automatic); /** * Called whenever the user clicks on a border (not the titlebar!) of a floating window. diff --git a/src/client.c b/src/client.c index 9eb34565..53cacbf4 100644 --- a/src/client.c +++ b/src/client.c @@ -186,7 +186,7 @@ void client_toggle_fullscreen(xcb_connection_t *conn, Client *client) { LOG("leaving fullscreen mode\n"); client->fullscreen = false; workspace->fullscreen_client = NULL; - if (client->floating) { + if (client->floating >= FLOATING_AUTO_ON) { /* For floating clients it’s enough if we just reconfigure that window (in fact, * re-rendering the layout will not update the client.) */ reposition_client(conn, client); diff --git a/src/commands.c b/src/commands.c index 8a66f480..d84adf45 100644 --- a/src/commands.c +++ b/src/commands.c @@ -617,7 +617,7 @@ void show_workspace(xcb_connection_t *conn, int workspace) { /* Map all floating clients */ SLIST_FOREACH(client, &(c_ws->focus_stack), focus_clients) { - if (!client->floating) + if (client->floating <= FLOATING_USER_OFF) continue; xcb_map_window(conn, client->frame); @@ -836,7 +836,7 @@ void parse_command(xcb_connection_t *conn, const char *command) { /* Is it just 's' for stacking or 'd' for default? */ if ((command[0] == 's' || command[0] == 'd') && (command[1] == '\0')) { - if (last_focused == NULL || last_focused->floating) { + if (last_focused == NULL || last_focused->floating >= FLOATING_AUTO_ON) { LOG("not switching, this is a floating client\n"); return; } @@ -852,7 +852,7 @@ void parse_command(xcb_connection_t *conn, const char *command) { return; } - toggle_floating_mode(conn, last_focused); + toggle_floating_mode(conn, last_focused, false); /* delete all empty columns/rows */ cleanup_table(conn, last_focused->workspace); @@ -908,13 +908,13 @@ void parse_command(xcb_connection_t *conn, const char *command) { } if (*rest == '\0') { - if (last_focused != NULL && last_focused->floating) + if (last_focused != NULL && last_focused->floating >= FLOATING_AUTO_ON) move_floating_window_to_workspace(conn, last_focused, workspace); else move_current_window_to_workspace(conn, workspace); return; } - if (last_focused == NULL || last_focused->floating) { + if (last_focused == NULL || last_focused->floating >= FLOATING_AUTO_ON) { LOG("Not performing (null or floating) \n"); return; } diff --git a/src/floating.c b/src/floating.c index 90064c29..9c71cf36 100644 --- a/src/floating.c +++ b/src/floating.c @@ -39,15 +39,18 @@ static void drag_pointer(xcb_connection_t *conn, Client *client, xcb_button_pres * Correctly takes care of the position/size (separately stored for tiling/floating mode) * and repositions/resizes/redecorates the client. * + * If the automatic flag is set to true, this was an automatic update by a change of the + * window class from the application which can be overwritten by the user. + * */ -void toggle_floating_mode(xcb_connection_t *conn, Client *client) { +void toggle_floating_mode(xcb_connection_t *conn, Client *client, bool automatic) { Container *con = client->container; if (con == NULL) { LOG("This client is already in floating (container == NULL), re-inserting\n"); Client *next_tiling; SLIST_FOREACH(next_tiling, &(client->workspace->focus_stack), focus_clients) - if (!next_tiling->floating) + if (next_tiling->floating <= FLOATING_USER_OFF) break; /* If there are no tiling clients on this workspace, there can only be one * container: the first one */ @@ -60,7 +63,7 @@ void toggle_floating_mode(xcb_connection_t *conn, Client *client) { /* Preserve position/size */ memcpy(&(client->floating_rect), &(client->rect), sizeof(Rect)); - client->floating = false; + client->floating = FLOATING_USER_OFF; client->container = con; if (old_focused != NULL && !old_focused->dock) @@ -88,7 +91,9 @@ void toggle_floating_mode(xcb_connection_t *conn, Client *client) { con->currently_focused = get_last_focused_client(conn, con, NULL); } - client->floating = true; + if (automatic) + client->floating = FLOATING_AUTO_ON; + else client->floating = FLOATING_USER_ON; /* Initialize the floating position from the position in tiling mode, if this * client never was floating (width == 0) */ diff --git a/src/handlers.c b/src/handlers.c index 7682aaf0..0d828d20 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -336,7 +336,7 @@ int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_ LOG("client. done.\n"); xcb_allow_events(conn, XCB_ALLOW_REPLAY_POINTER, event->time); /* Floating clients should be raised on click */ - if (client->floating) + if (client->floating >= FLOATING_AUTO_ON) xcb_raise_window(conn, client->frame); xcb_flush(conn); return 1; @@ -348,7 +348,7 @@ int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_ LOG("click on titlebar\n"); /* Floating clients can be dragged by grabbing their titlebar */ - if (client->floating) { + if (client->floating >= FLOATING_AUTO_ON) { /* Firstly, we raise it. Maybe the user just wanted to raise it without grabbing */ uint32_t values[] = { XCB_STACK_MODE_ABOVE }; xcb_configure_window(conn, client->frame, XCB_CONFIG_WINDOW_STACK_MODE, values); @@ -359,7 +359,7 @@ int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_ return 1; } - if (client->floating) + if (client->floating >= FLOATING_AUTO_ON) return floating_border_click(conn, client, event); if (event->event_y < 2) { @@ -542,7 +542,7 @@ int handle_unmap_notify_event(void *data, xcb_connection_t *conn, xcb_unmap_noti /* Only if this is the active container, we need to really change focus */ if ((con->currently_focused != NULL) && ((con == CUR_CELL) || client->fullscreen)) set_focus(conn, con->currently_focused, true); - } else if (client->floating) { + } else if (client->floating >= FLOATING_AUTO_ON) { SLIST_REMOVE(&(client->workspace->focus_stack), client, Client, focus_clients); } @@ -737,6 +737,17 @@ int handle_windowclass_change(void *data, xcb_connection_t *conn, uint8_t state, client->window_class = new_class; FREE(old_class); + if (!client->initialized) { + LOG("Client is not yet initialized, not putting it to floating\n"); + return 1; + } + + if (strcmp(new_class, "tools") == 0) { + LOG("tool window, should we put it floating?\n"); + if (client->floating == FLOATING_AUTO_OFF) + toggle_floating_mode(conn, client, true); + } + return 1; } diff --git a/src/layout.c b/src/layout.c index 060625d9..0085cdc4 100644 --- a/src/layout.c +++ b/src/layout.c @@ -109,9 +109,9 @@ void decorate_window(xcb_connection_t *conn, Client *client, xcb_drawable_t draw return; LOG("redecorating child %08x\n", client->child); - if (client->floating || client->container->currently_focused == client) { + if (client->floating >= FLOATING_AUTO_ON || client->container->currently_focused == client) { /* Distinguish if the window is currently focused… */ - if (client->floating || CUR_CELL->currently_focused == client) + if (client->floating >= FLOATING_AUTO_ON || CUR_CELL->currently_focused == client) background_color = get_colorpixel(conn, config.client.focused.background); /* …or if it is the focused window in a not focused container */ else background_color = get_colorpixel(conn, config.client.focused_inactive.background); diff --git a/src/manage.c b/src/manage.c index 5e6e6eed..c87de575 100644 --- a/src/manage.c +++ b/src/manage.c @@ -339,7 +339,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child, /* Ensure that it is below all floating clients */ Client *first_floating; SLIST_FOREACH(first_floating, &(new->container->workspace->focus_stack), focus_clients) - if (first_floating->floating) + if (first_floating->floating >= FLOATING_AUTO_ON) break; if (first_floating != SLIST_END(&(new->container->workspace->focus_stack))) { @@ -349,6 +349,8 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child, } } + new->initialized = true; + /* Check if the window already got the fullscreen hint set */ xcb_atom_t *state; if ((preply = xcb_get_property_reply(conn, state_cookie, NULL)) != NULL && diff --git a/src/util.c b/src/util.c index 3cbb93d9..40e39e84 100644 --- a/src/util.c +++ b/src/util.c @@ -264,7 +264,7 @@ void unmap_workspace(xcb_connection_t *conn, Workspace *u_ws) { /* To find floating clients, we traverse the focus stack */ SLIST_FOREACH(client, &(u_ws->focus_stack), focus_clients) { - if (!client->floating) + if (client->floating <= FLOATING_USER_OFF) continue; xcb_unmap_window(conn, client->frame);