X-Git-Url: https://git.brokenzipper.com/gitweb?a=blobdiff_plain;f=openbox%2Fclient.c;h=8592aa93506a023bce7a2a0070aaa3842b15e587;hb=cc2ad0a823a918e826c7cf77f0b61e63c21910c3;hp=52dfaaa3aa1434d15c07e9eacb5bfefdc9b92a89;hpb=f506cbceae9e3d41f1e6e09d7c5e83ab3935adf9;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index 52dfaaa3..8592aa93 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -57,13 +57,14 @@ typedef struct { - ObClientDestructor func; + ObClientCallback func; gpointer data; -} Destructor; +} ClientCallback; -GList *client_list = NULL; +GList *client_list = NULL; -static GSList *client_destructors = NULL; +static GSList *client_destructors = NULL; +static GSList *client_desktop_notifies = NULL; static void client_get_all(ObClient *self); static void client_toggle_border(ObClient *self, gboolean show); @@ -105,20 +106,20 @@ void client_shutdown(gboolean reconfig) { } -void client_add_destructor(ObClientDestructor func, gpointer data) +void client_add_destructor(ObClientCallback func, gpointer data) { - Destructor *d = g_new(Destructor, 1); + ClientCallback *d = g_new(ClientCallback, 1); d->func = func; d->data = data; client_destructors = g_slist_prepend(client_destructors, d); } -void client_remove_destructor(ObClientDestructor func) +void client_remove_destructor(ObClientCallback func) { GSList *it; for (it = client_destructors; it; it = g_slist_next(it)) { - Destructor *d = it->data; + ClientCallback *d = it->data; if (d->func == func) { g_free(d); client_destructors = g_slist_delete_link(client_destructors, it); @@ -127,6 +128,29 @@ void client_remove_destructor(ObClientDestructor func) } } +void client_add_desktop_notify(ObClientCallback func, gpointer data) +{ + ClientCallback *d = g_new(ClientCallback, 1); + d->func = func; + d->data = data; + client_desktop_notifies = g_slist_prepend(client_desktop_notifies, d); +} + +void client_remove_desktop_notify(ObClientCallback func) +{ + GSList *it; + + for (it = client_desktop_notifies; it; it = g_slist_next(it)) { + ClientCallback *d = it->data; + if (d->func == func) { + g_free(d); + client_desktop_notifies = + g_slist_delete_link(client_desktop_notifies, it); + break; + } + } +} + void client_set_list() { Window *windows, *win_it; @@ -533,7 +557,7 @@ void client_unmanage(ObClient *self) screen_update_areas(); for (it = client_destructors; it; it = g_slist_next(it)) { - Destructor *d = it->data; + ClientCallback *d = it->data; d->func(self, d->data); } @@ -1254,11 +1278,13 @@ static void client_update_transient_tree(ObClient *self, } - /* If the group changed then we need to remove any old group transient - windows from our children. But if we're transient for the group, then + /* If the group changed, or if we are just becoming transient for the + group, then we need to remove any old group transient windows + from our children. But if we were already transient for the group, then other group transients are not our children. */ - if (oldgroup != newgroup && oldgroup != NULL && - oldparent != OB_TRAN_GROUP) + if ((oldgroup != newgroup || + (newparent == OB_TRAN_GROUP && oldparent != newparent)) && + oldgroup != NULL && oldparent != OB_TRAN_GROUP) { for (it = self->transients; it; it = next) { next = g_slist_next(it); @@ -2143,9 +2169,11 @@ static void client_change_wm_state(ObClient *self) old = self->wmstate; - if (self->shaded || !self->frame->visible) + if (self->shaded || self->iconic || + (self->desktop != DESKTOP_ALL && self->desktop != screen_desktop)) + { self->wmstate = IconicState; - else + } else self->wmstate = NormalState; if (old != self->wmstate) { @@ -2303,23 +2331,6 @@ gboolean client_should_show(ObClient *self) return FALSE; if (client_normal(self) && screen_showing_desktop) return FALSE; - /* - if (self->transient_for) { - if (self->transient_for != OB_TRAN_GROUP) - return client_should_show(self->transient_for); - else { - GSList *it; - - for (it = self->group->members; it; it = g_slist_next(it)) { - ObClient *c = it->data; - if (c != self && !c->transient_for) { - if (client_should_show(c)) - return TRUE; - } - } - } - } - */ if (self->desktop == screen_desktop || self->desktop == DESKTOP_ALL) return TRUE; @@ -2376,10 +2387,11 @@ gboolean client_normal(ObClient *self) { self->type == OB_CLIENT_TYPE_SPLASH); } -gboolean client_application(ObClient *self) +gboolean client_helper(ObClient *self) { - return (self->type == OB_CLIENT_TYPE_NORMAL || - self->type == OB_CLIENT_TYPE_DIALOG); + return (self->type == OB_CLIENT_TYPE_UTILITY || + self->type == OB_CLIENT_TYPE_MENU || + self->type == OB_CLIENT_TYPE_TOOLBAR); } static void client_apply_startup_state(ObClient *self, gint x, gint y) @@ -2801,7 +2813,7 @@ static void client_iconify_recursive(ObClient *self, if (curdesk && self->desktop != screen_desktop && self->desktop != DESKTOP_ALL) - client_set_desktop(self, screen_desktop, FALSE); + client_set_desktop(self, screen_desktop, FALSE, FALSE); /* this puts it after the current focused window */ focus_order_remove(self); @@ -2981,7 +2993,9 @@ void client_hilite(ObClient *self, gboolean hilite) } void client_set_desktop_recursive(ObClient *self, - guint target, gboolean donthide) + guint target, + gboolean donthide, + gboolean focus_nonintrusive) { guint old; GSList *it; @@ -2993,7 +3007,8 @@ void client_set_desktop_recursive(ObClient *self, g_assert(target < screen_num_desktops || target == DESKTOP_ALL); /* remove from the old desktop(s) */ - focus_order_remove(self); + if (!focus_nonintrusive) + focus_order_remove(self); old = self->desktop; self->desktop = target; @@ -3010,23 +3025,34 @@ void client_set_desktop_recursive(ObClient *self, screen_update_areas(); /* add to the new desktop(s) */ - if (config_focus_new) - focus_order_to_top(self); - else - focus_order_to_bottom(self); + if (!focus_nonintrusive) { + if (config_focus_new) + focus_order_to_top(self); + else + focus_order_to_bottom(self); + } + + /* call the notifies */ + GSList *it; + for (it = client_desktop_notifies; it; it = g_slist_next(it)) { + ClientCallback *d = it->data; + d->func(self, d->data); + } } /* move all transients */ for (it = self->transients; it; it = g_slist_next(it)) if (it->data != self) if (client_is_direct_child(self, it->data)) - client_set_desktop_recursive(it->data, target, donthide); + client_set_desktop_recursive(it->data, target, + donthide, focus_nonintrusive); } -void client_set_desktop(ObClient *self, guint target, gboolean donthide) +void client_set_desktop(ObClient *self, guint target, + gboolean donthide, gboolean focus_nonintrusive) { self = client_search_top_normal_parent(self); - client_set_desktop_recursive(self, target, donthide); + client_set_desktop_recursive(self, target, donthide, focus_nonintrusive); } gboolean client_is_direct_child(ObClient *parent, ObClient *child) @@ -3360,7 +3386,7 @@ static void client_present(ObClient *self, gboolean here, gboolean raise) self->desktop != screen_desktop) { if (here) - client_set_desktop(self, screen_desktop, FALSE); + client_set_desktop(self, screen_desktop, FALSE, FALSE); else screen_set_desktop(self->desktop, FALSE); } else if (!self->frame->visible) @@ -3385,29 +3411,75 @@ static void client_present(ObClient *self, gboolean here, gboolean raise) void client_activate(ObClient *self, gboolean here, gboolean user) { guint32 last_time = focus_client ? focus_client->user_time : CurrentTime; + gboolean allow = FALSE; + gboolean relative = FALSE; + + if (user || !focus_client) + allow = TRUE; + /* if the request came from an application and something already has focus + then do some checks; */ + else { + GSList *it; + + /* search if someone related to us by transience already has focus */ + for (it = client_search_all_top_parents(self); it && !relative; + it = g_slist_next(it)) + { + if (client_search_transient(it->data, focus_client)) + relative = TRUE; + } + + /* search if someone in the group already has focus */ + for (it = client_search_all_top_parents(self); it && !relative; + it = g_slist_next(it)) + { + if (client_search_transient(it->data, focus_client)) + relative = TRUE; + } + + /* if a relative has focus, then if the time is newer (or we can't + check the time - very lenient), allow focus to move */ + allow = relative && (!event_curtime || !last_time || + event_time_after(event_curtime, last_time)); + } + - /* XXX do some stuff here if user is false to determine if we really want - to activate it or not (a parent or group member is currently - active)? - */ ob_debug_type(OB_DEBUG_FOCUS, "Want to activate window 0x%x with time %u (last time %u), " - "source=%s\n", + "source=%s allowing? %d\n", self->window, event_curtime, last_time, - (user ? "user" : "application")); + (user ? "user" : "application"), allow); - if (!user && event_curtime && last_time && - !event_time_after(event_curtime, last_time)) - { - client_hilite(self, TRUE); - } else { + if (allow) { if (event_curtime != CurrentTime) self->user_time = event_curtime; client_present(self, here, TRUE); + } else + /* don't focus it but tell the user it wants attention */ + client_hilite(self, TRUE); +} + +static void client_bring_helper_windows_recursive(ObClient *self, + guint desktop) +{ + GSList *it; + + for (it = self->transients; it; it = g_slist_next(it)) + client_bring_helper_windows_recursive(it->data, desktop); + + if (client_helper(self) && + self->desktop != desktop && self->desktop != DESKTOP_ALL) + { + client_set_desktop(self, desktop, FALSE, TRUE); } } +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); @@ -3842,7 +3914,7 @@ gboolean client_has_group_siblings(ObClient *self) return self->group && self->group->members->next; } -gboolean client_has_application_group_siblings(ObClient *self) +gboolean client_has_non_helper_group_siblings(ObClient *self) { GSList *it; @@ -3850,7 +3922,7 @@ gboolean client_has_application_group_siblings(ObClient *self) for (it = self->group->members; it; it = g_slist_next(it)) { ObClient *c = it->data; - if (c != self && client_application(c)) + if (c != self && client_normal(c) && !client_helper(c)) return TRUE; } return FALSE;