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);
{
}
-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);
}
}
+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;
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);
}
}
- /* 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);
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);
}
+gboolean client_mouse_focusable(ObClient *self)
+{
+ return !(self->type == OB_CLIENT_TYPE_MENU ||
+ self->type == OB_CLIENT_TYPE_TOOLBAR ||
+ self->type == OB_CLIENT_TYPE_SPLASH ||
+ self->type == OB_CLIENT_TYPE_DOCK);
+}
+
+gboolean client_enter_focusable(ObClient *self)
+{
+ /* you can focus desktops but it shouldn't on enter */
+ return (client_mouse_focusable(self) &&
+ self->type != OB_CLIENT_TYPE_DESKTOP);
+}
+
+
static void client_apply_startup_state(ObClient *self, gint x, gint y)
{
gboolean pos = FALSE; /* has the window's position been configured? */
}
void client_set_desktop_recursive(ObClient *self,
- guint target, gboolean donthide)
+ guint target,
+ gboolean donthide)
{
guint old;
GSList *it;
g_assert(target < screen_num_desktops || target == DESKTOP_ALL);
- /* remove from the old desktop(s) */
- focus_order_remove(self);
-
old = self->desktop;
self->desktop = target;
PROP_SET32(self->window, net_wm_desktop, cardinal, target);
if (STRUT_EXISTS(self->strut))
screen_update_areas();
- /* add to the new desktop(s) */
- 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 */
client_set_desktop_recursive(it->data, target, donthide);
}
-void client_set_desktop(ObClient *self, guint target, gboolean donthide)
+void client_set_desktop(ObClient *self, guint target,
+ gboolean donthide)
{
self = client_search_top_normal_parent(self);
client_set_desktop_recursive(self, target, donthide);
gboolean modal = self->modal;
gboolean iconic = self->iconic;
gboolean demands_attention = self->demands_attention;
+ gboolean above = self->above;
+ gboolean below = self->below;
gint i;
if (!(action == prop_atoms.net_wm_state_add ||
} else if (state == prop_atoms.net_wm_state_fullscreen) {
fullscreen = TRUE;
} else if (state == prop_atoms.net_wm_state_above) {
- self->above = TRUE;
- self->below = FALSE;
+ above = TRUE;
+ below = FALSE;
} else if (state == prop_atoms.net_wm_state_below) {
- self->above = FALSE;
- self->below = TRUE;
+ above = FALSE;
+ below = TRUE;
} else if (state == prop_atoms.net_wm_state_demands_attention) {
demands_attention = TRUE;
} else if (state == prop_atoms.openbox_wm_state_undecorated) {
} else if (state == prop_atoms.net_wm_state_fullscreen) {
fullscreen = FALSE;
} else if (state == prop_atoms.net_wm_state_above) {
- self->above = FALSE;
+ above = FALSE;
} else if (state == prop_atoms.net_wm_state_below) {
- self->below = FALSE;
+ below = FALSE;
} else if (state == prop_atoms.net_wm_state_demands_attention) {
demands_attention = FALSE;
} else if (state == prop_atoms.openbox_wm_state_undecorated) {
if (demands_attention != self->demands_attention)
client_hilite(self, demands_attention);
+ if (above != self->above || below != self->below) {
+ self->above = above;
+ self->below = below;
+ client_calc_layer(self);
+ }
+
client_change_state(self); /* change the hint to reflect these changes */
}
void client_activate(ObClient *self, gboolean here, gboolean user)
{
guint32 last_time = focus_client ? focus_client->user_time : CurrentTime;
+ gboolean allow = FALSE;
- /* 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)?
+ /* if the request came from the user, or if nothing is focused, then grant
+ the request.
+ if the currently focused app doesn't set a user_time, then it can't
+ benefit from any focus stealing prevention.
*/
+ if (user || !focus_client || !last_time)
+ allow = TRUE;
+ /* otherwise, if they didn't give a time stamp or if it is too old, they
+ don't get focus */
+ else
+ allow = event_curtime && event_time_after(event_curtime, last_time);
+
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);
}
}
+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);
{
return self->group && self->group->members->next;
}
-
-gboolean client_has_application_group_siblings(ObClient *self)
-{
- GSList *it;
-
- if (!self->group) return FALSE;
-
- for (it = self->group->members; it; it = g_slist_next(it)) {
- ObClient *c = it->data;
- if (c != self && client_application(c))
- return TRUE;
- }
- return FALSE;
-}