X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fclient.c;h=e666d589eda3bfd512d7a5dacaf129035eb75cd8;hb=9fcf466aebe8e8312472191a309263df56cdedb8;hp=3399b509d48667a239fa16ca736d44614e449f86;hpb=171e476ba3faaa3dbd95e9e95f4121fae2db6564;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index 3399b509..e666d589 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -42,6 +42,7 @@ #include "obrender/render.h" #include "gettext.h" #include "obt/display.h" +#include "obt/xqueue.h" #include "obt/prop.h" #ifdef HAVE_UNISTD_H @@ -107,8 +108,9 @@ static GSList *client_search_all_top_parents_internal(ObClient *self, static void client_call_notifies(ObClient *self, GSList *list); static void client_ping_event(ObClient *self, gboolean dead); static void client_prompt_kill(ObClient *self); -static gboolean client_can_steal_focus(ObClient *self, Time steal_time, - Time launch_time); +static gboolean client_can_steal_focus(ObClient *self, + gboolean allow_other_desktop, + Time steal_time, Time launch_time); void client_startup(gboolean reconfig) { @@ -209,9 +211,6 @@ void client_manage(Window window, ObPrompt *prompt) ob_debug("Managing window: 0x%lx", window); - /* we want to always have a valid time when the window is mapping */ - g_assert(event_curtime != CurrentTime); - /* choose the events we want to receive on the CLIENT window (ObPrompt windows can request events too) */ attrib_set.event_mask = CLIENT_EVENTMASK | @@ -246,11 +245,6 @@ void client_manage(Window window, ObPrompt *prompt) that needs to be freed with g_free(). */ settings = client_get_settings_state(self); - /* now we have all of the window's information so we can set this up. - do this before creating the frame, so it can tell that we are still - mapping and doesn't go applying things right away */ - client_setup_decor_and_functions(self, FALSE); - /* specify that if we exit, the window should not be destroyed and should be reparented back to root automatically, unless we are managing an internal ObPrompt window */ @@ -273,7 +267,7 @@ void client_manage(Window window, ObPrompt *prompt) launch_time = sn_app_started(self->startup_id, self->class, self->name); if (!OBT_PROP_GET32(self->window, NET_WM_USER_TIME, CARDINAL, &user_time)) - user_time = event_curtime; + user_time = event_time(); /* do this after we have a frame.. it uses the frame to help determine the WM_STATE to apply. */ @@ -289,12 +283,12 @@ void client_manage(Window window, ObPrompt *prompt) if (ob_state() != OB_STATE_STARTING && (!self->session || self->session->focused) && /* this means focus=true for window is same as config_focus_new=true */ - ((config_focus_new || (settings && settings->focus == 1)) || + ((config_focus_new || settings->focus == 1) || client_search_focus_tree_full(self)) && /* NET_WM_USER_TIME 0 when mapping means don't focus */ (user_time != 0) && /* this checks for focus=false for the window */ - (!settings || settings->focus != 0) && + settings->focus != 0 && focus_valid_target(self, self->desktop, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, settings->focus == 1)) @@ -374,7 +368,7 @@ void client_manage(Window window, ObPrompt *prompt) (self->type == OB_CLIENT_TYPE_DIALOG || self->type == OB_CLIENT_TYPE_SPLASH || (!((self->positioned & USPosition) || - (settings && settings->pos_given)) && + settings->pos_given) && client_normal(self) && !self->session && /* don't move oldschool fullscreen windows to @@ -442,7 +436,8 @@ void client_manage(Window window, ObPrompt *prompt) ob_debug_type(OB_DEBUG_FOCUS, "Going to try activate new window? %s", activate ? "yes" : "no"); if (activate) { - activate = client_can_steal_focus(self, event_curtime, launch_time); + activate = client_can_steal_focus(self, settings->focus, + event_time(), launch_time); if (!activate) { /* if the client isn't stealing focus, then hilite it so the user @@ -520,11 +515,11 @@ ObClient *client_fake_manage(Window window) uses too. this returns a shallow copy that needs to be freed */ settings = client_get_settings_state(self); - client_setup_decor_and_functions(self, FALSE); - /* 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); + + client_apply_startup_state(self, self->area.x, self->area.y, + self->area.width, self->area.height); ob_debug("gave extents left %d right %d top %d bottom %d", self->frame->size.left, self->frame->size.right, @@ -700,7 +695,9 @@ void client_fake_unmanage(ObClient *self) g_slice_free(ObClient, self); } -static gboolean client_can_steal_focus(ObClient *self, Time steal_time, +static gboolean client_can_steal_focus(ObClient *self, + gboolean allow_other_desktop, + Time steal_time, Time launch_time) { gboolean steal; @@ -722,11 +719,13 @@ static gboolean client_can_steal_focus(ObClient *self, Time steal_time, self->window, steal_time, launch_time, event_last_user_time); - /* if it's on another desktop */ + /* if it's on another desktop... */ if (!(self->desktop == screen_desktop || self->desktop == DESKTOP_ALL) && - /* the timestamp is from before you changed desktops */ - (!launch_time || + /* and (we dont know when it launched, and we don't want to allow + focus stealing from other desktops */ + ((!launch_time && !allow_other_desktop) || + /* or the timestamp is from before you changed desktops) */ (screen_desktop_user_time && !event_time_after(launch_time, screen_desktop_user_time)))) { @@ -1099,9 +1098,16 @@ static void client_get_all(ObClient *self, gboolean real) 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); + /* set up the decor/functions before getting the state. the states may + affect which functions are available, but we want to know the maximum + decor/functions are available to this window, so we can then apply them + in client_apply_startup_state() */ + client_setup_decor_and_functions(self, FALSE); + + client_get_state(self); + /* get the session related properties, these can change decorations from per-app settings */ client_get_session_ids(self); @@ -1553,7 +1559,13 @@ void client_update_sync_request_counter(ObClient *self) if (OBT_PROP_GET32(self->window, NET_WM_SYNC_REQUEST_COUNTER, CARDINAL,&i)) { + XSyncValue val; + self->sync_counter = i; + + /* this must be set when managing a new window according to EWMH */ + XSyncIntToValue(&val, 0); + XSyncSetCounter(obt_display, self->sync_counter, val); } else self->sync_counter = None; } @@ -1713,6 +1725,13 @@ void client_setup_decor_and_functions(ObClient *self, gboolean reconfig) break; } + /* If the client has no decor from its type (which never changes) then + don't allow the user to "undecorate" the window. Otherwise, allow them + to, even if there are motif hints removing the decor, because those + may change these days (e.g. chromium) */ + if (self->decorations == 0) + self->functions &= ~OB_CLIENT_FUNC_UNDECORATE; + /* Mwm Hints are applied subtractively to what has already been chosen for decor and functionality */ if (self->mwmhints.flags & OB_MWM_FLAG_DECORATIONS) { @@ -1765,17 +1784,13 @@ void client_setup_decor_and_functions(ObClient *self, gboolean reconfig) } if (self->max_horz && self->max_vert) { - /* you can't resize fully maximized windows */ - self->functions &= ~OB_CLIENT_FUNC_RESIZE; - /* kill the handle on fully maxed windows */ + /* once upon a time you couldn't resize maximized windows, that is not + the case any more though ! + + but do kill the handle on fully maxed windows */ self->decorations &= ~(OB_FRAME_DECOR_HANDLE | OB_FRAME_DECOR_GRIPS); } - /* If there are no decorations to remove, don't allow the user to try - toggle the state */ - if (self->decorations == 0) - self->functions &= ~OB_CLIENT_FUNC_UNDECORATE; - /* finally, the user can have requested no decorations, which overrides everything (but doesnt give it a border if it doesnt have one) */ if (self->undecorated) @@ -1797,8 +1812,8 @@ void client_setup_decor_and_functions(ObClient *self, gboolean reconfig) client_change_allowed_actions(self); if (reconfig) - /* force reconfigure to make sure decorations are updated */ - client_reconfigure(self, TRUE); + /* reconfigure to make sure decorations are updated */ + client_reconfigure(self, FALSE); } static void client_change_allowed_actions(ObClient *self) @@ -2490,10 +2505,6 @@ gboolean client_is_oldfullscreen(const ObClient *self, static ObStackingLayer calc_layer(ObClient *self) { ObStackingLayer l; - const Rect *monitor, *allmonitors; - - monitor = screen_physical_area_monitor(client_monitor(self)); - allmonitors = screen_physical_area_all_monitors(); if (self->type == OB_CLIENT_TYPE_DESKTOP) l = OB_STACKING_LAYER_DESKTOP; @@ -2725,8 +2736,6 @@ static void client_apply_startup_state(ObClient *self, if (iconic) client_iconify(self, TRUE, FALSE, TRUE); - if (fullscreen) - client_fullscreen(self, TRUE); if (undecorated) client_set_undecorated(self, TRUE); if (shaded) @@ -2741,6 +2750,10 @@ static void client_apply_startup_state(ObClient *self, else if (max_horz) client_maximize(self, TRUE, 1); + /* fullscreen removes the ability to apply other states */ + if (fullscreen) + client_fullscreen(self, TRUE); + /* if the window hasn't been configured yet, then do so now, in fact the x,y,w,h may _not_ be the same as the area rect, which can end up meaning that the client isn't properly moved/resized by the fullscreen @@ -2889,11 +2902,11 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h, through this code */ { gint basew, baseh, minw, minh; - gint incw, inch; + gint incw, inch, maxw, maxh; gfloat minratio, maxratio; - incw = self->fullscreen || self->max_horz ? 1 : self->size_inc.width; - inch = self->fullscreen || self->max_vert ? 1 : self->size_inc.height; + incw = self->size_inc.width; + inch = self->size_inc.height; minratio = self->fullscreen || (self->max_horz && self->max_vert) ? 0 : self->min_ratio; maxratio = self->fullscreen || (self->max_horz && self->max_vert) ? @@ -2929,6 +2942,10 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h, *w -= basew; *h -= baseh; + /* the sizes to used for maximized */ + maxw = *w; + maxh = *h; + /* keep to the increments */ *w /= incw; *h /= inch; @@ -2944,6 +2961,10 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h, *w *= incw; *h *= inch; + /* if maximized/fs then don't use the size increments */ + if (self->fullscreen || self->max_horz) *w = maxw; + if (self->fullscreen || self->max_vert) *h = maxh; + *w += basew; *h += baseh; @@ -3081,16 +3102,18 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h, When user = FALSE, then the request is coming from the application itself, and we are more strict about when to send a synthetic ConfigureNotify. We strictly follow the rules of the ICCCM sec 4.1.5 - in this case (if force_reply is true) + in this case (or send one if force_reply is true) When user = TRUE, then the request is coming from "us", like when we maximize a window or something. In this case we are more lenient. We used to follow the same rules as above, but _Java_ Swing can't handle this. So just to appease Swing, when user = TRUE, we always send a synthetic ConfigureNotify to give the window its root coordinates. + Lastly, if force_reply is TRUE, we always send a + ConfigureNotify, which is needed during a resize with XSYNCronization. */ if ((!user && !resized && (rootmoved || force_reply)) || - (user && final && rootmoved)) + (user && ((!resized && force_reply) || (final && rootmoved)))) { XEvent event; @@ -3131,11 +3154,16 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h, /* if it moved between monitors, then this can affect the stacking layer of this window or others - for fullscreen windows. also if it changed to/from oldschool fullscreen then its layer may - change */ - if (screen_find_monitor(&self->frame->area) != - screen_find_monitor(&oldframe) || - (final && (client_is_oldfullscreen(self, &oldclient) != - client_is_oldfullscreen(self, &self->area)))) + change + + watch out tho, don't try change stacking stuff if the window is no + longer being managed ! + */ + if (self->managed && + (screen_find_monitor(&self->frame->area) != + screen_find_monitor(&oldframe) || + (final && (client_is_oldfullscreen(self, &oldclient) != + client_is_oldfullscreen(self, &self->area))))) { client_calc_layer(self); } @@ -3198,6 +3226,11 @@ void client_fullscreen(ObClient *self, gboolean fs) ob_debug("Window %s going fullscreen (%d)", self->title, self->fullscreen); + if (fs) { + /* make sure the window is on some monitor */ + client_find_onscreen(self, &x, &y, w, h, FALSE); + } + client_setup_decor_and_functions(self, FALSE); client_move_resize(self, x, y, w, h); @@ -3340,6 +3373,11 @@ void client_maximize(ObClient *self, gboolean max, gint dir) if (dir == 0 || dir == 2) /* vert */ self->max_vert = max; + if (max) { + /* make sure the window is on some monitor */ + client_find_onscreen(self, &x, &y, w, h, FALSE); + } + client_change_state(self); /* change the state hints on the client */ client_setup_decor_and_functions(self, FALSE); @@ -3400,7 +3438,7 @@ void client_close(ObClient *self) else { /* request the client to close with WM_DELETE_WINDOW */ OBT_PROP_MSG_TO(self->window, self->window, WM_PROTOCOLS, - OBT_PROP_ATOM(WM_DELETE_WINDOW), event_curtime, + OBT_PROP_ATOM(WM_DELETE_WINDOW), event_time(), 0, 0, 0, NoEventMask); /* we're trying to close the window, so see if it is responding. if it @@ -3618,36 +3656,31 @@ ObClient *client_search_modal_child(ObClient *self) return NULL; } -static gboolean client_validate_unmap(ObClient *self, int n) -{ - XEvent e; - gboolean ret = TRUE; - - if (XCheckTypedWindowEvent(obt_display, self->window, UnmapNotify, &e)) { - if (n < self->ignore_unmaps) // ignore this one, but look for more - ret = client_validate_unmap(self, n+1); - else - ret = FALSE; // the window is going to become unmanaged +struct ObClientFindDestroyUnmap { + Window window; + gint ignore_unmaps; +}; - /* put them back on the event stack so they end up in the same order */ - XPutBackEvent(obt_display, &e); - } - - return ret; +static gboolean find_destroy_unmap(XEvent *e, gpointer data) +{ + struct ObClientFindDestroyUnmap *find = data; + if (e->type == DestroyNotify) + return e->xdestroywindow.window == find->window; + if (e->type == UnmapNotify && e->xunmap.window == find->window) + /* ignore the first $find->ignore_unmaps$ many unmap events */ + return --find->ignore_unmaps < 0; + return FALSE; } gboolean client_validate(ObClient *self) { - XEvent e; + struct ObClientFindDestroyUnmap find; XSync(obt_display, FALSE); /* get all events on the server */ - if (XCheckTypedWindowEvent(obt_display, self->window, DestroyNotify, &e)) { - XPutBackEvent(obt_display, &e); - return FALSE; - } - - if (!client_validate_unmap(self, 0)) + find.window = self->window; + find.ignore_unmaps = self->ignore_unmaps; + if (xqueue_exists_local(find_destroy_unmap, &find)) return FALSE; return TRUE; @@ -3839,6 +3872,8 @@ gboolean client_can_focus(ObClient *self) gboolean client_focus(ObClient *self) { + if (!client_validate(self)) return FALSE; + /* we might not focus this window, so if we have modal children which would be focused instead, bring them to this desktop */ client_bring_modal_windows(self); @@ -3854,7 +3889,7 @@ gboolean client_focus(ObClient *self) ob_debug_type(OB_DEBUG_FOCUS, "Focusing client \"%s\" (0x%x) at time %u", - self->title, self->window, event_curtime); + self->title, self->window, event_time()); /* if using focus_delay, stop the timer now so that focus doesn't go moving on us */ @@ -3866,7 +3901,7 @@ gboolean client_focus(ObClient *self) /* This can cause a BadMatch error with CurrentTime, or if an app passed in a bad time for _NET_WM_ACTIVE_WINDOW. */ XSetInputFocus(obt_display, self->window, RevertToPointerRoot, - event_curtime); + event_time()); } if (self->focus_notify) { @@ -3877,7 +3912,7 @@ gboolean client_focus(ObClient *self) ce.xclient.window = self->window; ce.xclient.format = 32; ce.xclient.data.l[0] = OBT_PROP_ATOM(WM_TAKE_FOCUS); - ce.xclient.data.l[1] = event_curtime; + ce.xclient.data.l[1] = event_time(); ce.xclient.data.l[2] = 0l; ce.xclient.data.l[3] = 0l; ce.xclient.data.l[4] = 0l; @@ -3925,7 +3960,7 @@ void client_activate(ObClient *self, gboolean desktop, if ((user && (desktop || self->desktop == DESKTOP_ALL || self->desktop == screen_desktop)) || - client_can_steal_focus(self, event_curtime, CurrentTime)) + client_can_steal_focus(self, desktop, event_time(), CurrentTime)) { client_present(self, here, raise, unshade); }