From 4204b8e2b00b86916aca4718753d5f684eddfafa Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 10 Oct 2011 12:48:43 +0100 Subject: [PATCH] Get the _NET_STARTUP_ID in manage_window, get the corresponding workspace --- include/atoms.xmacro | 1 + include/startup.h | 11 ++++++++++ src/manage.c | 17 +++++++++++++++- src/startup.c | 48 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+), 1 deletion(-) diff --git a/include/atoms.xmacro b/include/atoms.xmacro index 309a3325..f08a90d5 100644 --- a/include/atoms.xmacro +++ b/include/atoms.xmacro @@ -15,6 +15,7 @@ xmacro(_NET_CLIENT_LIST_STACKING) xmacro(_NET_CURRENT_DESKTOP) xmacro(_NET_ACTIVE_WINDOW) xmacro(_NET_WORKAREA) +xmacro(_NET_STARTUP_ID) xmacro(WM_PROTOCOLS) xmacro(WM_DELETE_WINDOW) xmacro(UTF8_STRING) diff --git a/include/startup.h b/include/startup.h index 9e131019..555a1191 100644 --- a/include/startup.h +++ b/include/startup.h @@ -32,4 +32,15 @@ void start_application(const char *command); */ void startup_monitor_event(SnMonitorEvent *event, void *userdata); +/** + * Checks if the given window belongs to a startup notification by checking if + * the _NET_STARTUP_ID property is set on the window (or on its leader, if it’s + * unset). + * + * If so, returns the workspace on which the startup was initiated. + * Returns NULL otherwise. + * + */ +char *startup_workspace_for_window(i3Window *cwindow, xcb_get_property_reply_t *startup_id_reply); + #endif diff --git a/src/manage.c b/src/manage.c index 35055d17..22c2814f 100644 --- a/src/manage.c +++ b/src/manage.c @@ -84,7 +84,7 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki 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; + role_cookie, startup_id_cookie; geomc = xcb_get_geometry(conn, d); @@ -147,6 +147,7 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki title_cookie = GET_PROPERTY(XCB_ATOM_WM_NAME, 128); 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); /* TODO: also get wm_normal_hints here. implement after we got rid of xcb-event */ DLOG("reparenting!\n"); @@ -175,6 +176,11 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki 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); + xcb_get_property_reply_t *startup_id_reply; + startup_id_reply = xcb_get_property_reply(conn, startup_id_cookie, NULL); + char *startup_ws = startup_workspace_for_window(cwindow, startup_id_reply); + DLOG("startup workspace = %s\n", startup_ws); + /* check if the window needs WM_TAKE_FOCUS */ cwindow->needs_take_focus = window_supports_protocol(cwindow->id, A_WM_TAKE_FOCUS); @@ -233,6 +239,15 @@ void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cooki else nc = tree_open_con(nc->parent, cwindow); } /* TODO: handle assignments with type == A_TO_OUTPUT */ + } else if (startup_ws) { + /* If it’s not assigned, but was started on a specific workspace, + * we want to open it there */ + DLOG("Using workspace on which this application was started (%s)\n", startup_ws); + nc = con_descend_tiling_focused(workspace_get(startup_ws, NULL)); + DLOG("focused on ws %s: %p / %s\n", startup_ws, nc, nc->name); + if (nc->type == CT_WORKSPACE) + nc = tree_open_con(nc, cwindow); + else nc = tree_open_con(nc->parent, cwindow); } else { /* If not, insert it at the currently focused position */ if (focused->type == CT_CON && con_accepts_window(focused)) { diff --git a/src/startup.c b/src/startup.c index 5fc875a3..30932e33 100644 --- a/src/startup.c +++ b/src/startup.c @@ -115,3 +115,51 @@ void startup_monitor_event(SnMonitorEvent *event, void *userdata) { break; } } + +/* + * Checks if the given window belongs to a startup notification by checking if + * the _NET_STARTUP_ID property is set on the window (or on its leader, if it’s + * unset). + * + * If so, returns the workspace on which the startup was initiated. + * Returns NULL otherwise. + * + */ +char *startup_workspace_for_window(i3Window *cwindow, xcb_get_property_reply_t *startup_id_reply) { + /* The _NET_STARTUP_ID is only needed during this function, so we get it + * here and don’t save it in the 'cwindow'. */ + if (startup_id_reply == NULL || xcb_get_property_value_length(startup_id_reply) == 0) { + DLOG("No _NET_STARTUP_ID set on this window\n"); + /* TODO: check the leader, if any */ + FREE(startup_id_reply); + return NULL; + } + + char *startup_id; + if (asprintf(&startup_id, "%.*s", xcb_get_property_value_length(startup_id_reply), + (char*)xcb_get_property_value(startup_id_reply)) == -1) { + perror("asprintf()"); + DLOG("Could not get _NET_STARTUP_ID\n"); + free(startup_id_reply); + return NULL; + } + + struct Startup_Sequence *current, *sequence = NULL; + TAILQ_FOREACH(current, &startup_sequences, sequences) { + if (strcmp(current->id, startup_id) != 0) + continue; + + sequence = current; + break; + } + + free(startup_id); + free(startup_id_reply); + + if (!sequence) { + DLOG("WARNING: This sequence (ID %s) was not found\n", startup_id); + return NULL; + } + + return sequence->workspace; +}