From: Dana Jansens Date: Wed, 9 May 2007 20:13:20 +0000 (+0000) Subject: add support for _NET_REQUEST_FRAME_EXTENTS X-Git-Url: https://git.brokenzipper.com/gitweb?a=commitdiff_plain;h=7f262bc2a0733a77ae5a30752aecdcf4ba35f223;p=chaz%2Fopenbox add support for _NET_REQUEST_FRAME_EXTENTS --- diff --git a/openbox/client.c b/openbox/client.c index 3f3f161d..83c59030 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -66,7 +66,7 @@ GList *client_list = NULL; static GSList *client_destructors = NULL; -static void client_get_all(ObClient *self); +static void client_get_all(ObClient *self, gboolean real); static void client_toggle_border(ObClient *self, gboolean show); static void client_get_startup_id(ObClient *self); static void client_get_session_ids(ObClient *self); @@ -76,9 +76,7 @@ static void client_get_state(ObClient *self); static void client_get_layer(ObClient *self); static void client_get_shaped(ObClient *self); static void client_get_mwm_hints(ObClient *self); -static void client_get_gravity(ObClient *self); static void client_get_colormap(ObClient *self); -static void client_get_transientness(ObClient *self); static void client_change_allowed_actions(ObClient *self); static void client_change_state(ObClient *self); static void client_change_wm_state(ObClient *self); @@ -236,8 +234,8 @@ void client_manage(Window window) grab_server(TRUE); - /* check if it has already been unmapped by the time we started mapping. - the grab does a sync so we don't have to here */ + /* check if it has already been unmapped by the time we started + mapping. the grab does a sync so we don't have to here */ if (XCheckTypedWindowEvent(ob_display, window, DestroyNotify, &e) || XCheckTypedWindowEvent(ob_display, window, UnmapNotify, &e)) { @@ -277,7 +275,6 @@ void client_manage(Window window) XChangeWindowAttributes(ob_display, window, CWEventMask|CWDontPropagate, &attrib_set); - /* create the ObClient struct, and populate it from the hints on the window */ self = g_new0(ObClient, 1); @@ -290,7 +287,7 @@ void client_manage(Window window) self->desktop = screen_num_desktops; /* always an invalid value */ self->user_time = focus_client ? focus_client->user_time : CurrentTime; - client_get_all(self); + client_get_all(self, TRUE); /* per-app settings override stuff, and return the settings for other uses too */ settings = client_get_settings_state(self); @@ -311,14 +308,14 @@ void client_manage(Window window) /* remove the client's border (and adjust re gravity) */ client_toggle_border(self, FALSE); - /* specify that if we exit, the window should not be destroyed and should - be reparented back to root automatically */ + /* specify that if we exit, the window should not be destroyed and + should be reparented back to root automatically */ XChangeSaveSet(ob_display, window, SetModeInsert); /* create the decoration frame for the client window */ self->frame = frame_new(self); - frame_grab_client(self->frame, self); + frame_grab_client(self->frame); /* do this after we have a frame.. it uses the frame to help determine the WM_STATE to apply. */ @@ -484,6 +481,31 @@ void client_manage(Window window) client_set_list(); ob_debug("Managed window 0x%lx (%s)\n", window, self->class); + + return; +} + + +ObClient *client_fake_manage(Window window) +{ + ObClient *self; + ObAppSettings *settings; + + ob_debug("Pretend-managing window: %lx\n", window); + + /* do this minimal stuff to figure out the client's decorations */ + + self = g_new0(ObClient, 1); + self->window = window; + + client_get_all(self, FALSE); + /* per-app settings override stuff, and return the settings for other + uses too */ + settings = client_get_settings_state(self); + + /* create the decoration frame for the client window */ + self->frame = frame_new(self); + return self; } void client_unmanage_all() @@ -497,8 +519,8 @@ void client_unmanage(ObClient *self) guint j; GSList *it; - ob_debug("Unmanaging window: %lx (%s) (%s)\n", self->window, self->class, - self->title ? self->title : ""); + ob_debug("Unmanaging window: %lx (%s) (%s)\n", self->window, + self->class, self->title ? self->title : ""); g_assert(self != NULL); @@ -510,7 +532,8 @@ void client_unmanage(ObClient *self) /* flush to send the hide to the server quickly */ XFlush(ob_display); - /* ignore enter events from the unmap so it doesnt mess with the focus */ + /* ignore enter events from the unmap so it doesnt mess with the + focus */ event_ignore_queued_enters(); mouse_grab_for_client(self, FALSE); @@ -547,7 +570,7 @@ void client_unmanage(ObClient *self) for (it = self->group->members; it; it = g_slist_next(it)) if (it->data != self) ((ObClient*)it->data)->transients = - g_slist_remove(((ObClient*)it->data)->transients, self); + g_slist_remove(((ObClient*)it->data)->transients,self); } else if (self->transient_for) { /* transient of window */ self->transient_for->transients = g_slist_remove(self->transient_for->transients, self); @@ -594,7 +617,8 @@ void client_unmanage(ObClient *self) } /* reparent the window out of the frame, and free the frame */ - frame_release_client(self->frame, self); + frame_release_client(self->frame); + frame_free(self->frame); self->frame = NULL; if (ob_state() != OB_STATE_EXITING) { @@ -604,11 +628,15 @@ void client_unmanage(ObClient *self) PROP_ERASE(self->window, net_wm_state); PROP_ERASE(self->window, wm_state); } else { - /* if we're left in an unmapped state, the client wont be mapped. this - is bad, since we will no longer be managing the window on restart */ + /* if we're left in an unmapped state, the client wont be mapped. + this is bad, since we will no longer be managing the window on + restart */ XMapWindow(ob_display, self->window); } + /* update the list hints */ + client_set_list(); + ob_debug("Unmanaged window 0x%lx\n", self->window); /* free all data allocated in the client struct */ @@ -626,9 +654,14 @@ void client_unmanage(ObClient *self) g_free(self->client_machine); g_free(self->sm_client_id); g_free(self); - - /* update the list hints */ - client_set_list(); +} + +void client_fake_unmanage(ObClient *self) +{ + /* this is all that got allocated to get the decorations */ + + frame_free(self->frame); + g_free(self); } static ObAppSettings *client_get_settings_state(ObClient *self) @@ -949,68 +982,62 @@ static void client_toggle_border(ObClient *self, gboolean show) } -static void client_get_all(ObClient *self) +static void client_get_all(ObClient *self, gboolean real) { + /* this is needed for the frame to set itself up */ client_get_area(self); - client_get_mwm_hints(self); - - /* The transient-ness of a window is used to pick a type, but the type can - also affect transiency. - Dialogs are always made transients for their group if they have one. + /* these things can change the decor and functions of the window */ - I also have made non-application type windows be transients for their - group (eg utility windows). - */ - client_get_transientness(self); - client_get_type(self);/* this can change the mwmhints for special cases */ + client_get_mwm_hints(self); + /* this can change the mwmhints for special cases */ + client_get_type_and_transientness(self); client_get_state(self); + client_update_protocols(self); + client_update_normal_hints(self); - client_update_wmhints(self); - /* this may have already been called from client_update_wmhints */ - if (self->transient_for == NULL) - client_update_transient_for(self); - client_get_startup_id(self); - client_get_desktop(self);/* uses transient data/group/startup id if a - desktop is not specified */ - client_get_shaped(self); + /* got the type, the mwmhints, the protocols, and the normal hints + (min/max sizes), so we're ready to set up the decorations/functions */ + client_setup_decor_and_functions(self); - client_get_layer(self); /* if layer hasn't been specified, get it from - other sources if possible */ + if (real) { + client_update_wmhints(self); + /* this may have already been called from client_update_wmhints */ + if (self->transient_for == NULL) + client_update_transient_for(self); - { - /* a couple type-based defaults for new windows */ + client_get_startup_id(self); + client_get_desktop(self);/* uses transient data/group/startup id if a + desktop is not specified */ + client_get_shaped(self); - /* this makes sure that these windows appear on all desktops */ - if (self->type == OB_CLIENT_TYPE_DESKTOP) - self->desktop = DESKTOP_ALL; - } - - client_update_protocols(self); + client_get_layer(self); /* if layer hasn't been specified, get it from + other sources if possible */ - client_get_gravity(self); /* get the attribute gravity */ - client_update_normal_hints(self); /* this may override the attribute - gravity */ + { + /* a couple type-based defaults for new windows */ - /* got the type, the mwmhints, the protocols, and the normal hints - (min/max sizes), so we're ready to set up the decorations/functions */ - client_setup_decor_and_functions(self); + /* this makes sure that these windows appear on all desktops */ + if (self->type == OB_CLIENT_TYPE_DESKTOP) + self->desktop = DESKTOP_ALL; + } #ifdef SYNC - client_update_sync_request_counter(self); + client_update_sync_request_counter(self); #endif - /* get the session related properties */ - client_get_session_ids(self); + /* get the session related properties */ + client_get_session_ids(self); - client_get_colormap(self); - client_update_title(self); - client_update_strut(self); - client_update_icons(self); - client_update_user_time_window(self); - if (!self->user_time_window) /* check if this would have been called */ - client_update_user_time(self); - client_update_icon_geometry(self); + client_get_colormap(self); + client_update_title(self); + client_update_strut(self); + client_update_icons(self); + client_update_user_time_window(self); + if (!self->user_time_window) /* check if this would have been called */ + client_update_user_time(self); + client_update_icon_geometry(self); + } } static void client_get_startup_id(ObClient *self) @@ -1170,20 +1197,12 @@ static void client_get_shaped(ObClient *self) #endif } -void client_get_transientness(ObClient *self) -{ - Window t; - if (XGetTransientForHint(ob_display, self->window, &t)) - self->transient = TRUE; -} - void client_update_transient_for(ObClient *self) { Window t = None; ObClient *target = NULL; if (XGetTransientForHint(ob_display, self->window, &t)) { - self->transient = TRUE; if (t != self->window) { /* cant be transient to itself! */ target = g_hash_table_lookup(window_map, &t); /* if this happens then we need to check for it*/ @@ -1220,16 +1239,8 @@ void client_update_transient_for(ObClient *self) } } } - } else if (self->type == OB_CLIENT_TYPE_DIALOG || - self->type == OB_CLIENT_TYPE_TOOLBAR || - self->type == OB_CLIENT_TYPE_MENU || - self->type == OB_CLIENT_TYPE_UTILITY) - { - self->transient = TRUE; - if (self->group) - target = OB_TRAN_GROUP; - } else - self->transient = FALSE; + } else if (self->transient && self->group) + target = OB_TRAN_GROUP; client_update_transient_tree(self, self->group, self->group, self->transient_for, target); @@ -1364,12 +1375,14 @@ static void client_get_mwm_hints(ObClient *self) } } -void client_get_type(ObClient *self) +void client_get_type_and_transientness(ObClient *self) { guint num, i; guint32 *val; + Window t; self->type = -1; + self->transient = FALSE; if (PROP_GETA32(self->window, net_wm_window_type, atom, &val, &num)) { /* use the first value that we know about in the array */ @@ -1403,7 +1416,10 @@ void client_get_type(ObClient *self) } g_free(val); } - + + if (XGetTransientForHint(ob_display, self->window, &t)) + self->transient = TRUE; + if (self->type == (ObClientType) -1) { /*the window type hint was not set, which means we either classify ourself as a normal window or a dialog, depending on if we are a @@ -1413,6 +1429,15 @@ void client_get_type(ObClient *self) else self->type = OB_CLIENT_TYPE_NORMAL; } + + /* then, based on our type, we can update our transientness.. */ + if (self->type == OB_CLIENT_TYPE_DIALOG || + self->type == OB_CLIENT_TYPE_TOOLBAR || + self->type == OB_CLIENT_TYPE_MENU || + self->type == OB_CLIENT_TYPE_UTILITY) + { + self->transient = TRUE; + } } void client_update_protocols(ObClient *self) @@ -1456,16 +1481,6 @@ void client_update_sync_request_counter(ObClient *self) } #endif -static void client_get_gravity(ObClient *self) -{ - XWindowAttributes wattrib; - Status ret; - - ret = XGetWindowAttributes(ob_display, self->window, &wattrib); - g_assert(ret != BadWindow); - self->gravity = wattrib.win_gravity; -} - void client_get_colormap(ObClient *self) { XWindowAttributes wa; diff --git a/openbox/client.h b/openbox/client.h index f9a19483..30d40510 100644 --- a/openbox/client.h +++ b/openbox/client.h @@ -314,13 +314,22 @@ void client_remove_destructor(ObClientCallback func); /*! Manages all existing windows */ void client_manage_all(); -/*! Manages a given window */ +/*! Manages a given window +*/ void client_manage(Window win); /*! Unmanages all managed windows */ void client_unmanage_all(); /*! Unmanages a given client */ void client_unmanage(ObClient *client); +/*! This manages a window only so far as is needed to get it's decorations. + This is used when you want to determine a window's decorations before it + is mapped. Call client_fake_unmanage() with the returned client when you + are done with it. */ +ObClient *client_fake_manage(Window win); +/*! Free the stuff created by client_fake_manage() */ +void client_fake_unmanage(ObClient *self); + /*! Sets the client list on the root window from the client_list */ void client_set_list(); @@ -354,7 +363,7 @@ gboolean client_focused(ObClient *self); /*! Convery a position/size from a given gravity to the client's true gravity */ -void client_convert_gravity(ObClient *client, gint gravity, gint *x, gint *y, +void client_convert_gravity(ObClient *self, gint gravity, gint *x, gint *y, gint w, gint h); #define client_move(self, x, y) \ @@ -536,7 +545,7 @@ void client_activate(ObClient *self, gboolean here, gboolean user); /*! Bring all of its helper windows to its desktop. These are the utility and stuff windows. */ -void client_bring_helper_windows(ObClient *client); +void client_bring_helper_windows(ObClient *self); /*! Calculates the stacking layer for the client window */ void client_calc_layer(ObClient *self); @@ -600,8 +609,8 @@ void client_update_icon_geometry(ObClient *self); */ void client_setup_decor_and_functions(ObClient *self); -/*! Retrieves the window's type and sets ObClient->type */ -void client_get_type(ObClient *self); +/*! Sets the window's type and transient flag */ +void client_get_type_and_transientness(ObClient *self); const ObClientIcon *client_icon(ObClient *self, gint w, gint h); diff --git a/openbox/event.c b/openbox/event.c index babb5197..fe06935d 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -568,8 +568,32 @@ static void event_process(const XEvent *ec, gpointer data) event_handle_root(e); else if (e->type == MapRequest) client_manage(window); + else if (e->type == ClientMessage) { + /* This is for _NET_WM_REQUEST_FRAME_EXTENTS messages. They come for + windows that are not managed yet. */ + if (e->xclient.message_type == prop_atoms.net_request_frame_extents) { + /* Pretend to manage the client, getting information used to + determine its decorations */ + ObClient *c = client_fake_manage(e->xclient.window); + gulong vals[4]; + + /* adjust the decorations so we know the sizes */ + frame_adjust_area(c->frame, FALSE, TRUE, TRUE); + + /* set the frame extents on the window */ + vals[0] = c->frame->size.left; + vals[1] = c->frame->size.right; + vals[2] = c->frame->size.top; + vals[3] = c->frame->size.bottom; + PROP_SETA32(e->xclient.window, net_frame_extents, + cardinal, vals, 4); + + /* Free the pretend client */ + client_fake_unmanage(c); + } + } else if (e->type == ConfigureRequest) { - /* unhandled configure requests must be used to configure the + /* unhandled config5Aure requests must be used to configure the window directly */ XWindowChanges xwc; @@ -1167,7 +1191,7 @@ static void event_handle_client(ObClient *client, XEvent *e) client_update_wmhints(client); } else if (msgtype == XA_WM_TRANSIENT_FOR) { client_update_transient_for(client); - client_get_type(client); + client_get_type_and_transientness(client); /* type may have changed, so update the layer */ client_calc_layer(client); client_setup_decor_and_functions(client); diff --git a/openbox/frame.c b/openbox/frame.c index 2c3fb58f..dd24f5ca 100644 --- a/openbox/frame.c +++ b/openbox/frame.c @@ -99,6 +99,7 @@ ObFrame *frame_new(ObClient *client) Visual *visual; self = g_new0(ObFrame, 1); + self->client = client; visual = check_32bit_client(client); @@ -245,7 +246,7 @@ static void free_theme_statics(ObFrame *self) RrAppearanceFree(self->a_icon); } -static void frame_free(ObFrame *self) +void frame_free(ObFrame *self) { free_theme_statics(self); @@ -553,12 +554,10 @@ void frame_adjust_icon(ObFrame *self) framerender_frame(self); } -void frame_grab_client(ObFrame *self, ObClient *client) +void frame_grab_client(ObFrame *self) { - self->client = client; - /* reparent the client to the frame */ - XReparentWindow(ob_display, client->window, self->plate, 0, 0); + XReparentWindow(ob_display, self->client->window, self->plate, 0, 0); /* When reparenting the client window, it is usually not mapped yet, since this occurs from a MapRequest. However, in the case where Openbox is @@ -568,52 +567,50 @@ void frame_grab_client(ObFrame *self, ObClient *client) handled and need to be ignored. */ if (ob_state() == OB_STATE_STARTING) - client->ignore_unmaps += 2; + self->client->ignore_unmaps += 2; /* select the event mask on the client's parent (to receive config/map req's) the ButtonPress is to catch clicks on the client border */ XSelectInput(ob_display, self->plate, PLATE_EVENTMASK); /* map the client so it maps when the frame does */ - XMapWindow(ob_display, client->window); + XMapWindow(ob_display, self->client->window); /* adjust the frame to the client's size */ frame_adjust_area(self, FALSE, TRUE, FALSE); /* set all the windows for the frame in the window_map */ - g_hash_table_insert(window_map, &self->window, client); - g_hash_table_insert(window_map, &self->plate, client); - g_hash_table_insert(window_map, &self->inner, client); - g_hash_table_insert(window_map, &self->title, client); - g_hash_table_insert(window_map, &self->label, client); - g_hash_table_insert(window_map, &self->max, client); - g_hash_table_insert(window_map, &self->close, client); - g_hash_table_insert(window_map, &self->desk, client); - g_hash_table_insert(window_map, &self->shade, client); - g_hash_table_insert(window_map, &self->icon, client); - g_hash_table_insert(window_map, &self->iconify, client); - g_hash_table_insert(window_map, &self->handle, client); - g_hash_table_insert(window_map, &self->lgrip, client); - g_hash_table_insert(window_map, &self->rgrip, client); - g_hash_table_insert(window_map, &self->tltresize, client); - g_hash_table_insert(window_map, &self->tllresize, client); - g_hash_table_insert(window_map, &self->trtresize, client); - g_hash_table_insert(window_map, &self->trrresize, client); + g_hash_table_insert(window_map, &self->window, self->client); + g_hash_table_insert(window_map, &self->plate, self->client); + g_hash_table_insert(window_map, &self->inner, self->client); + g_hash_table_insert(window_map, &self->title, self->client); + g_hash_table_insert(window_map, &self->label, self->client); + g_hash_table_insert(window_map, &self->max, self->client); + g_hash_table_insert(window_map, &self->close, self->client); + g_hash_table_insert(window_map, &self->desk, self->client); + g_hash_table_insert(window_map, &self->shade, self->client); + g_hash_table_insert(window_map, &self->icon, self->client); + g_hash_table_insert(window_map, &self->iconify, self->client); + g_hash_table_insert(window_map, &self->handle, self->client); + g_hash_table_insert(window_map, &self->lgrip, self->client); + g_hash_table_insert(window_map, &self->rgrip, self->client); + g_hash_table_insert(window_map, &self->tltresize, self->client); + g_hash_table_insert(window_map, &self->tllresize, self->client); + g_hash_table_insert(window_map, &self->trtresize, self->client); + g_hash_table_insert(window_map, &self->trrresize, self->client); } -void frame_release_client(ObFrame *self, ObClient *client) +void frame_release_client(ObFrame *self) { XEvent ev; gboolean reparent = TRUE; - g_assert(self->client == client); - /* if there was any animation going on, kill it */ ob_main_loop_timeout_remove_data(ob_main_loop, frame_animate_iconify, self, FALSE); /* check if the app has already reparented its window away */ - while (XCheckTypedWindowEvent(ob_display, client->window, + while (XCheckTypedWindowEvent(ob_display, self->client->window, ReparentNotify, &ev)) { /* This check makes sure we don't catch our own reparent action to @@ -633,10 +630,10 @@ void frame_release_client(ObFrame *self, ObClient *client) if (reparent) { /* according to the ICCCM - if the client doesn't reparent itself, then we will reparent the window to root for them */ - XReparentWindow(ob_display, client->window, + XReparentWindow(ob_display, self->client->window, RootWindow(ob_display, ob_screen), - client->area.x, - client->area.y); + self->client->area.x, + self->client->area.y); } /* remove all the windows for the frame from the window_map */ @@ -660,8 +657,6 @@ void frame_release_client(ObFrame *self, ObClient *client) g_hash_table_remove(window_map, &self->trrresize); ob_main_loop_timeout_remove_data(ob_main_loop, flash_timeout, self, TRUE); - - frame_free(self); } /* is there anything present between us and the label? */ diff --git a/openbox/frame.h b/openbox/frame.h index 3a5dfdb2..147f59de 100644 --- a/openbox/frame.h +++ b/openbox/frame.h @@ -162,6 +162,8 @@ struct _ObFrame }; ObFrame *frame_new(struct _ObClient *c); +void frame_free(ObFrame *self); + void frame_show(ObFrame *self); void frame_hide(ObFrame *self); void frame_adjust_theme(ObFrame *self); @@ -173,8 +175,8 @@ void frame_adjust_state(ObFrame *self); void frame_adjust_focus(ObFrame *self, gboolean hilite); void frame_adjust_title(ObFrame *self); void frame_adjust_icon(ObFrame *self); -void frame_grab_client(ObFrame *self, struct _ObClient *client); -void frame_release_client(ObFrame *self, struct _ObClient *client); +void frame_grab_client(ObFrame *self); +void frame_release_client(ObFrame *self); ObFrameContext frame_context_from_string(const gchar *name); diff --git a/openbox/prop.h b/openbox/prop.h index f8b44a73..4f45b6d4 100644 --- a/openbox/prop.h +++ b/openbox/prop.h @@ -132,6 +132,7 @@ typedef struct Atoms { Atom net_wm_user_time; Atom net_wm_user_time_window; Atom net_frame_extents; + Atom net_request_frame_extents; /* application protocols */ /* Atom net_wm_ping; */ diff --git a/openbox/screen.c b/openbox/screen.c index 9265c73b..190468aa 100644 --- a/openbox/screen.c +++ b/openbox/screen.c @@ -275,6 +275,7 @@ gboolean screen_annex(const gchar *program_name) supported[i++] = prop_atoms.net_wm_user_time; supported[i++] = prop_atoms.net_wm_user_time_window; supported[i++] = prop_atoms.net_frame_extents; + supported[i++] = prop_atoms.net_request_frame_extents; supported[i++] = prop_atoms.net_startup_id; #ifdef SYNC supported[i++] = prop_atoms.net_wm_sync_request;