X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;ds=sidebyside;f=openbox%2Fclient.c;h=8fb481600da65c09f6067e272365593ac4541743;hb=4a34c7ddb250130e59d664862363f88eb875c01c;hp=3f3f161de016c79126136d3eb84491f4d8a09a5a;hpb=851555348ec39a01a0e150d2e12b71212b8d338b;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index 3f3f161d..8fb48160 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -66,19 +66,16 @@ 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); static void client_get_area(ObClient *self); static void client_get_desktop(ObClient *self); 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 +233,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 +274,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,13 +286,15 @@ 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); /* the session should get the last say */ client_restore_session_state(self); + client_setup_decor_and_functions(self); + client_calc_layer(self); { @@ -311,14 +309,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. */ @@ -454,7 +452,7 @@ void client_manage(Window window) raised to the top. Legacy begets legacy I guess? */ if (!client_restore_session_stacking(self)) - client_raise(self); + stacking_raise(CLIENT_AS_WINDOW(self)); } /* this has to happen before we try focus the window, but we want it to @@ -484,6 +482,34 @@ 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); + + client_setup_decor_and_functions(self); + + /* create the decoration frame for the client window and adjust its size */ + self->frame = frame_new(self); + frame_adjust_area(self->frame, FALSE, TRUE, TRUE); + return self; } void client_unmanage_all() @@ -497,8 +523,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 +536,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 +574,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 +621,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 +632,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 +658,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,35 +986,39 @@ 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); + + /* these things can change the decor and functions of the window */ + 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_normal_hints(self); - /* The transient-ness of a window is used to pick a type, but the type can - also affect transiency. + /* get the session related properties, these can change decorations + from per-app settings */ + client_get_session_ids(self); - Dialogs are always made transients for their group if they have one. + /* now we got everything that can affect the decorations */ + if (!real) + return; - 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_state(self); + client_update_protocols(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); - client_get_layer(self); /* if layer hasn't been specified, get it from - other sources if possible */ - { /* a couple type-based defaults for new windows */ @@ -985,24 +1026,11 @@ static void client_get_all(ObClient *self) if (self->type == OB_CLIENT_TYPE_DESKTOP) self->desktop = DESKTOP_ALL; } - - client_update_protocols(self); - - client_get_gravity(self); /* get the attribute gravity */ - client_update_normal_hints(self); /* this may override the attribute - gravity */ - - /* 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); #ifdef SYNC client_update_sync_request_counter(self); #endif - /* get the session related properties */ - client_get_session_ids(self); - client_get_colormap(self); client_update_title(self); client_update_strut(self); @@ -1078,41 +1106,6 @@ static void client_get_desktop(ObClient *self) } } -static void client_get_layer(ObClient *self) -{ - if (!(self->above || self->below)) { - if (self->group) { - /* apply stuff from the group */ - GSList *it; - gint layer = -2; - - for (it = self->group->members; it; it = g_slist_next(it)) { - ObClient *c = it->data; - if (c != self && !client_search_transient(self, c) && - client_normal(self) && client_normal(c)) - { - layer = MAX(layer, - (c->above ? 1 : (c->below ? -1 : 0))); - } - } - switch (layer) { - case -1: - self->below = TRUE; - break; - case -2: - case 0: - break; - case 1: - self->above = TRUE; - break; - default: - g_assert_not_reached(); - break; - } - } - } -} - static void client_get_state(ObClient *self) { guint32 *state; @@ -1170,20 +1163,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 +1205,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 +1341,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 +1382,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 +1395,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 +1447,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; @@ -1649,7 +1630,7 @@ void client_setup_decor_and_functions(ObClient *self) /* kill the handle on fully maxed windows */ if (self->max_vert && self->max_horz) - self->decorations &= ~OB_FRAME_DECOR_HANDLE; + self->decorations &= ~(OB_FRAME_DECOR_HANDLE | OB_FRAME_DECOR_GRIPS); /* finally, the user can have requested no decorations, which overrides everything (but doesnt give it a border if it doesnt have one) */ @@ -2184,6 +2165,8 @@ static void client_get_session_ids(ObClient *self) localhost[127] = '\0'; if (strcmp(localhost, s) != 0) self->client_machine = s; + else + g_free(s); } } @@ -2327,13 +2310,25 @@ static void client_calc_layer_recursive(ObClient *self, ObClient *orig, for (it = self->transients; it; it = g_slist_next(it)) client_calc_layer_recursive(it->data, orig, self->layer, - raised ? raised : self->layer != old); + raised ? raised : self->layer > old); + + /* restack. but only if the original window is managed. - if (!raised && self->layer != old) - if (orig->frame) { /* only restack if the original window is managed */ + raised is used so that only the bottom-most window in the stacking + order is raised, the others will automatically come with it. + + also only the highest windows in the stacking order (no transients) + are lowered, cuz the rest come for free + */ + if (!raised && orig->frame) { + if (self->layer > old) { stacking_remove(CLIENT_AS_WINDOW(self)); - stacking_add(CLIENT_AS_WINDOW(self)); + stacking_add_nonintrusive(CLIENT_AS_WINDOW(self)); + } else if (self->layer < old && self->transients == NULL) { + stacking_remove(CLIENT_AS_WINDOW(self)); + stacking_add_nonintrusive(CLIENT_AS_WINDOW(self)); } + } } void client_calc_layer(ObClient *self) @@ -3060,7 +3055,7 @@ void client_set_desktop_recursive(ObClient *self, client_showhide(self); /* raise if it was not already on the desktop */ if (old != DESKTOP_ALL) - client_raise(self); + stacking_raise(CLIENT_AS_WINDOW(self)); if (STRUT_EXISTS(self->strut)) screen_update_areas(); } @@ -3285,7 +3280,7 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2) self->modal = modal; /* when a window changes modality, then its stacking order with its transients needs to change */ - client_raise(self); + stacking_raise(CLIENT_AS_WINDOW(self)); } if (iconic != self->iconic) client_iconify(self, iconic, FALSE); @@ -3427,17 +3422,10 @@ static void client_present(ObClient *self, gboolean here, gboolean raise) return; if (self->shaded) client_shade(self, FALSE); + if (raise) + stacking_raise(CLIENT_AS_WINDOW(self)); client_focus(self); - - if (raise) { - /* we do this as an action here. this is rather important. this is - because we want the results from the focus change to take place - BEFORE we go about raising the window. when a fullscreen window - loses focus, we need this or else the raise wont be able to raise - above the to-lose-focus fullscreen window. */ - client_raise(self); - } } void client_activate(ObClient *self, gboolean here, gboolean user) @@ -3493,16 +3481,6 @@ void client_bring_helper_windows(ObClient *self) client_bring_helper_windows_recursive(self, self->desktop); } -void client_raise(ObClient *self) -{ - action_run_string("Raise", self, CurrentTime); -} - -void client_lower(ObClient *self) -{ - action_run_string("Lower", self, CurrentTime); -} - gboolean client_focused(ObClient *self) { return self == focus_client;