From ae8cc4119f42c6859cb088b6aa45abd9cea677bd Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Tue, 8 May 2007 12:23:17 +0000 Subject: [PATCH] merge r6168-6175 from trunk --- openbox/action.c | 6 +-- openbox/client.c | 107 +++++++++++++++++++++++++++++++------------- openbox/client.h | 24 +++++++--- openbox/event.c | 21 ++++++--- openbox/focus.c | 7 ++- openbox/menuframe.c | 6 +-- openbox/screen.c | 34 +++++++++----- 7 files changed, 139 insertions(+), 66 deletions(-) diff --git a/openbox/action.c b/openbox/action.c index f8b2b7b3..f8e66439 100644 --- a/openbox/action.c +++ b/openbox/action.c @@ -1351,7 +1351,7 @@ void action_toggle_omnipresent(union ActionData *data) { client_set_desktop(data->client.any.c, data->client.any.c->desktop == DESKTOP_ALL ? - screen_desktop : DESKTOP_ALL, FALSE); + screen_desktop : DESKTOP_ALL, FALSE, FALSE); } void action_move_relative_horz(union ActionData *data) @@ -1515,7 +1515,7 @@ void action_send_to_desktop(union ActionData *data) if (data->sendto.desk < screen_num_desktops || data->sendto.desk == DESKTOP_ALL) { - client_set_desktop(c, data->sendto.desk, data->sendto.follow); + client_set_desktop(c, data->sendto.desk, data->sendto.follow, FALSE); if (data->sendto.follow) screen_set_desktop(data->sendto.desk, TRUE); } @@ -1582,7 +1582,7 @@ void action_send_to_desktop_dir(union ActionData *data) !data->sendtodir.inter.final || data->sendtodir.inter.cancel) { - client_set_desktop(c, d, data->sendtodir.follow); + client_set_desktop(c, d, data->sendtodir.follow, FALSE); if (data->sendtodir.follow) screen_set_desktop(d, TRUE); } diff --git a/openbox/client.c b/openbox/client.c index 54ae99fc..c872bbc9 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -2387,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) @@ -2812,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); @@ -2992,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; @@ -3004,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; @@ -3021,10 +3025,12 @@ 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; @@ -3038,13 +3044,15 @@ void client_set_desktop_recursive(ObClient *self, 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) @@ -3107,6 +3115,8 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2) 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 || @@ -3183,11 +3193,11 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2) } 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) { @@ -3212,9 +3222,9 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2) } 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) { @@ -3259,6 +3269,12 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2) 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 */ } @@ -3378,7 +3394,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) @@ -3403,29 +3419,56 @@ 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; - /* 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, 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); @@ -3860,7 +3903,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; @@ -3868,7 +3911,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; diff --git a/openbox/client.h b/openbox/client.h index d902f72a..ae60181c 100644 --- a/openbox/client.h +++ b/openbox/client.h @@ -334,10 +334,9 @@ gboolean client_should_show(ObClient *self); to them in a number of places regarding focus or user interaction. */ gboolean client_normal(ObClient *self); -/*! Returns if the window is one of an application's main windows (normal or - dialog type) rather than an accessory window (utilty, menu, etc) or a - non-normal window */ -gboolean client_application(ObClient *self); +/*! Returns if the window is one of an application's helper windows + (utilty, menu, etc) */ +gboolean client_helper(ObClient *self); /* Returns if the window is focused */ gboolean client_focused(ObClient *self); @@ -465,8 +464,13 @@ void client_kill(ObClient *self); /*! Sends the window to the specified desktop @param donthide If TRUE, the window will not be shown/hidden after its - desktop has been changed. Generally this should be FALSE. */ -void client_set_desktop(ObClient *self, guint target, gboolean donthide); + desktop has been changed. Generally this should be FALSE. + @param focus_nonintrusive If TRUE, the window will not be moved in the + focus order at all. Do this when moving windows to a desktop in + the "background" or something. It can be used to make a window share + multiple desktops. Generally this should be FALSE. */ +void client_set_desktop(ObClient *self, guint target, + gboolean donthide, gboolean focus_nonintrusive); /*! Show the client if it should be shown. */ void client_show(ObClient *self); @@ -520,6 +524,10 @@ gboolean client_focus(ObClient *self); */ 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); + /*! Calculates the stacking layer for the client window */ void client_calc_layer(ObClient *self); @@ -657,6 +665,8 @@ ObClient* client_under_pointer(); gboolean client_has_group_siblings(ObClient *self); -gboolean client_has_application_group_siblings(ObClient *self); +/*! Returns if a client has an group siblings which are main application + windows (not helper or non-normal windows) */ +gboolean client_has_non_helper_group_siblings(ObClient *self); #endif diff --git a/openbox/event.c b/openbox/event.c index bb6a42f9..ace3e861 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -504,6 +504,7 @@ static void event_process(const XEvent *ec, gpointer data) frame_adjust_focus(client->frame, TRUE); focus_set_client(client); client_calc_layer(client); + client_bring_helper_windows(client); } } else if (e->type == FocusOut) { gboolean nomove = FALSE; @@ -709,8 +710,15 @@ static void event_handle_client(ObClient *client, XEvent *e) case ButtonPress: case ButtonRelease: /* Wheel buttons don't draw because they are an instant click, so it - is a waste of resources to go drawing it. */ - if (!(e->xbutton.button == 4 || e->xbutton.button == 5)) { + is a waste of resources to go drawing it. + if the user is doing an intereactive thing, or has a menu open then + the mouse is grabbed (possibly) and if we get these events we don't + want to deal with them + */ + if (!(e->xbutton.button == 4 || e->xbutton.button == 5) && + !keyboard_interactively_grabbed() && + !menu_frame_visible) + { con = frame_context(client, e->xbutton.window); con = mouse_button_frame_context(con, e->xbutton.button); switch (con) { @@ -1017,7 +1025,7 @@ static void event_handle_client(ObClient *client, XEvent *e) if ((unsigned)e->xclient.data.l[0] < screen_num_desktops || (unsigned)e->xclient.data.l[0] == DESKTOP_ALL) client_set_desktop(client, (unsigned)e->xclient.data.l[0], - FALSE); + FALSE, FALSE); } else if (msgtype == prop_atoms.net_wm_state) { /* can't compress these */ ob_debug("net_wm_state %s %ld %ld for 0x%lx\n", @@ -1039,9 +1047,10 @@ static void event_handle_client(ObClient *client, XEvent *e) (e->xclient.data.l[0] == 2 ? "user" : "INVALID")))); /* XXX make use of data.l[2] !? */ event_curtime = e->xclient.data.l[1]; - ob_debug_type(OB_DEBUG_APP_BUGS, - "_NET_ACTIVE_WINDOW message for window %s is " - "missing a timestamp\n", client->title); + if (event_curtime == 0) + ob_debug_type(OB_DEBUG_APP_BUGS, + "_NET_ACTIVE_WINDOW message for window %s is " + "missing a timestamp\n", client->title); client_activate(client, FALSE, (e->xclient.data.l[0] == 0 || e->xclient.data.l[0] == 2)); diff --git a/openbox/focus.c b/openbox/focus.c index 15c036dc..b473686a 100644 --- a/openbox/focus.c +++ b/openbox/focus.c @@ -224,7 +224,7 @@ ObClient* focus_fallback_target(gboolean allow_refocus, ObClient *old) } - ob_debug_type(OB_DEBUG_FOCUS, "trying the focus order\n"); + ob_debug_type(OB_DEBUG_FOCUS, "trying the focus order\n"); for (it = focus_order; it; it = g_list_next(it)) if (allow_refocus || it->data != old) { ObClient *c = it->data; @@ -556,9 +556,8 @@ static gboolean valid_focus_target(ObClient *ft, /* let alt-tab go to these windows when a window in its group already has focus ... */ ((focus_client && ft->group == focus_client->group) || - /* ... or if there are no application windows in its - group */ - !client_has_application_group_siblings(ft)))); + /* ... or if there are no main windows in its group */ + !client_has_non_helper_group_siblings(ft)))); /* it's not set to skip the taskbar (unless it is a type that would be expected to set this hint */ diff --git a/openbox/menuframe.c b/openbox/menuframe.c index 65571761..01d3ae1f 100644 --- a/openbox/menuframe.c +++ b/openbox/menuframe.c @@ -972,10 +972,10 @@ static gboolean menu_frame_show(ObMenuFrame *self) if (menu_frame_visible == NULL) { /* no menus shown yet */ - if (!grab_pointer(TRUE, FALSE, OB_CURSOR_POINTER)) + if (!grab_pointer(TRUE, TRUE, OB_CURSOR_POINTER)) return FALSE; if (!grab_keyboard(TRUE)) { - grab_pointer(FALSE, FALSE, OB_CURSOR_POINTER); + grab_pointer(FALSE, TRUE, OB_CURSOR_POINTER); return FALSE; } } @@ -1084,7 +1084,7 @@ void menu_frame_hide(ObMenuFrame *self) if (menu_frame_visible == NULL) { /* last menu shown */ - grab_pointer(FALSE, FALSE, OB_CURSOR_NONE); + grab_pointer(FALSE, TRUE, OB_CURSOR_NONE); grab_keyboard(FALSE); } diff --git a/openbox/screen.c b/openbox/screen.c index 5fc2bb92..19e18a21 100644 --- a/openbox/screen.c +++ b/openbox/screen.c @@ -438,7 +438,7 @@ void screen_set_num_desktops(guint num) for (it = client_list; it; it = g_list_next(it)) { ObClient *c = it->data; if (c->desktop >= num && c->desktop != DESKTOP_ALL) - client_set_desktop(c, num - 1, FALSE); + client_set_desktop(c, num - 1, FALSE, FALSE); } /* change our struts/area to match (after moving windows) */ @@ -473,7 +473,7 @@ void screen_set_desktop(guint num, gboolean dofocus) ob_debug("Moving to desktop %d\n", num+1); if (moveresize_client) - client_set_desktop(moveresize_client, num, TRUE); + client_set_desktop(moveresize_client, num, TRUE, FALSE); /* show windows before hiding the rest to lessen the enter/leave events */ @@ -485,6 +485,27 @@ void screen_set_desktop(guint num, gboolean dofocus) } } + /* have to try focus here because when you leave an empty desktop + there is no focus out to watch for + + do this before hiding the windows so if helper windows are coming + with us, they don't get hidden + */ + if (dofocus && (c = focus_fallback_target(TRUE, focus_client))) { + /* only do the flicker reducing stuff ahead of time if we are going + to call xsetinputfocus on the window ourselves. otherwise there is + no guarantee the window will actually take focus.. */ + if (c->can_focus) { + /* do this here so that if you switch desktops to a window with + helper windows then the helper windows won't flash */ + client_bring_helper_windows(c); + /* reduce flicker by hiliting now rather than waiting for the + server FocusIn event */ + frame_adjust_focus(c->frame, TRUE); + } + client_focus(c); + } + /* hide windows from bottom to top */ for (it = g_list_last(stacking_list); it; it = g_list_previous(it)) { if (WINDOW_IS_CLIENT(it->data)) { @@ -493,15 +514,6 @@ void screen_set_desktop(guint num, gboolean dofocus) } } - /* have to try focus here because when you leave an empty desktop - there is no focus out to watch for */ - if (dofocus && (c = focus_fallback_target(TRUE, focus_client))) { - /* reduce flicker by hiliting now rather than waiting for the server - FocusIn event */ - frame_adjust_focus(c->frame, TRUE); - client_focus(c); - } - event_ignore_queued_enters(); if (event_curtime != CurrentTime) -- 2.34.1