X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fclient.c;h=4d8f4e77ae014e374fc53c31ce3dadcb3bd55b46;hb=7aae8cc5262c1b36e3196845d62489b76af9063f;hp=5bf22fb7fa546d0f23ff63d0787af3c906c16dde;hpb=fa0ae17adbc8f73b707c33836d37841e81b9303a;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index 5bf22fb7..4d8f4e77 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -33,13 +33,12 @@ #include "focus.h" #include "stacking.h" #include "openbox.h" -#include "hooks.h" #include "group.h" #include "config.h" #include "menuframe.h" #include "keyboard.h" #include "mouse.h" -#include "render/render.h" +#include "obrender/render.h" #include "gettext.h" #include "obt/display.h" #include "obt/prop.h" @@ -76,6 +75,7 @@ static RrImage *client_default_icon = NULL; static void client_get_all(ObClient *self, gboolean real); static void client_get_startup_id(ObClient *self); static void client_get_session_ids(ObClient *self); +static void client_save_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); @@ -106,6 +106,8 @@ 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); void client_startup(gboolean reconfig) { @@ -288,7 +290,8 @@ void client_manage(Window window, ObPrompt *prompt) (user_time != 0) && /* this checks for focus=false for the window */ (!settings || settings->focus != 0) && - focus_valid_target(self, FALSE, FALSE, TRUE, FALSE, FALSE)) + focus_valid_target(self, FALSE, FALSE, TRUE, FALSE, FALSE, + settings->focus == 1)) { activate = TRUE; } @@ -419,121 +422,14 @@ 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) { - gboolean raise = FALSE; - gboolean relative_focused; - gboolean parent_focused; - - parent_focused = (focus_client != NULL && - client_search_focus_parent(self)); - relative_focused = (focus_client != NULL && - (client_search_focus_tree_full(self) != NULL || - client_search_focus_group_full(self) != NULL)); - - /* This is focus stealing prevention */ - ob_debug_type(OB_DEBUG_FOCUS, - "Want to focus new window 0x%x at time %u " - "launched at %u (last user interaction time %u)", - self->window, map_time, launch_time, - event_last_user_time); - ob_debug_type(OB_DEBUG_FOCUS, - "Current focus_client: %s", - (focus_client ? focus_client->title : "(none)")); - ob_debug_type(OB_DEBUG_FOCUS, - "parent focused: %d relative focused: %d", - parent_focused, relative_focused); - - if (menu_frame_visible || moveresize_in_progress) { - activate = FALSE; - raise = TRUE; - ob_debug_type(OB_DEBUG_FOCUS, - "Not focusing the window because the user is inside " - "an Openbox menu or is move/resizing a window and " - "we don't want to interrupt them"); - } - - /* if it's on another desktop */ - else if (!(self->desktop == screen_desktop || - self->desktop == DESKTOP_ALL) && - /* the timestamp is from before you changed desktops */ - launch_time && screen_desktop_user_time && - !event_time_after(launch_time, screen_desktop_user_time)) - { - activate = FALSE; - raise = TRUE; - ob_debug_type(OB_DEBUG_FOCUS, - "Not focusing the window because its on another " - "desktop"); - } - /* If something is focused... */ - else if (focus_client) { - /* If the user is working in another window right now, then don't - steal focus */ - if (!parent_focused && - event_last_user_time && launch_time && - event_time_after(event_last_user_time, launch_time) && - event_last_user_time != launch_time && - event_time_after(event_last_user_time, - map_time - OB_EVENT_USER_TIME_DELAY)) - { - activate = FALSE; - ob_debug_type(OB_DEBUG_FOCUS, - "Not focusing the window because the user is " - "working in another window that is not " - "its parent"); - } - /* If the new window is a transient (and its relatives aren't - focused) */ - else if (client_has_parent(self) && !relative_focused) { - activate = FALSE; - ob_debug_type(OB_DEBUG_FOCUS, - "Not focusing the window because it is a " - "transient, and its relatives aren't focused"); - } - /* Don't steal focus from globally active clients. - I stole this idea from KWin. It seems nice. - */ - else if (!(focus_client->can_focus || - focus_client->focus_notify)) - { - activate = FALSE; - ob_debug_type(OB_DEBUG_FOCUS, - "Not focusing the window because a globally " - "active client has focus"); - } - /* Don't move focus if it's not going to go to this window - anyway */ - else if (client_focus_target(self) != self) { - activate = FALSE; - raise = TRUE; - ob_debug_type(OB_DEBUG_FOCUS, - "Not focusing the window because another window " - "would get the focus anyway"); - } - /* Don't move focus if the window is not visible on the current - desktop and none of its relatives are focused */ - else if (!(self->desktop == screen_desktop || - self->desktop == DESKTOP_ALL) && - !relative_focused) - { - activate = FALSE; - raise = TRUE; - ob_debug_type(OB_DEBUG_FOCUS, - "Not focusing the window because it is on " - "another desktop and no relatives are focused "); - } - } + activate = client_can_steal_focus(self, map_time, launch_time); if (!activate) { - ob_debug_type(OB_DEBUG_FOCUS, - "Focus stealing prevention activated for %s at " - "time %u (last user interaction time %u)", - self->title, map_time, event_last_user_time); - /* if the client isn't focused, then hilite it so the user - knows it is there */ - client_hilite(self, TRUE); - /* we may want to raise it even tho we're not activating it */ - if (raise && !client_restore_session_stacking(self)) - stacking_raise(CLIENT_AS_WINDOW(self)); + /* if the client isn't stealing focus, then hilite it so the user + knows it is there, but don't do this if we're restoring from a + session */ + if (!client_restore_session_stacking(self)) + client_hilite(self, TRUE); } } else { @@ -585,8 +481,6 @@ void client_manage(Window window, ObPrompt *prompt) ob_debug("Managed window 0x%lx plate 0x%x (%s)", window, self->frame->window, self->class); - - hooks_queue(OB_HOOK_WIN_NEW, self); } ObClient *client_fake_manage(Window window) @@ -661,9 +555,6 @@ void client_unmanage(ObClient *self) if (!self->prompt) XChangeSaveSet(obt_display, self->window, SetModeDelete); - /* this can't be queued to run later */ - hooks_run(OB_HOOK_WIN_CLOSE, self); - /* update the focus lists */ focus_order_remove(self); if (client_focused(self)) { @@ -787,6 +678,105 @@ void client_fake_unmanage(ObClient *self) g_free(self); } +static gboolean client_can_steal_focus(ObClient *self, Time steal_time, + Time launch_time) +{ + gboolean steal; + gboolean relative_focused; + gboolean parent_focused; + + steal = TRUE; + + parent_focused = (focus_client != NULL && + client_search_focus_parent(self)); + relative_focused = (focus_client != NULL && + (client_search_focus_tree_full(self) != NULL || + client_search_focus_group_full(self) != NULL)); + + /* This is focus stealing prevention */ + ob_debug_type(OB_DEBUG_FOCUS, + "Want to focus new window 0x%x at time %u " + "launched at %u (last user interaction time %u)", + self->window, steal_time, launch_time, + event_last_user_time); + + /* 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 && screen_desktop_user_time && + !event_time_after(launch_time, screen_desktop_user_time)) + { + steal = FALSE; + ob_debug_type(OB_DEBUG_FOCUS, + "Not focusing the window because its on another " + "desktop\n"); + } + /* If something is focused... */ + else if (focus_client) { + /* If the user is working in another window right now, then don't + steal focus */ + if (!parent_focused && + event_last_user_time && launch_time && + event_time_after(event_last_user_time, launch_time) && + event_last_user_time != launch_time && + event_time_after(event_last_user_time, + steal_time - OB_EVENT_USER_TIME_DELAY)) + { + steal = FALSE; + ob_debug_type(OB_DEBUG_FOCUS, + "Not focusing the window because the user is " + "working in another window that is not " + "its parent"); + } + /* If the new window is a transient (and its relatives aren't + focused) */ + else if (client_has_parent(self) && !relative_focused) { + steal = FALSE; + ob_debug_type(OB_DEBUG_FOCUS, + "Not focusing the window because it is a " + "transient, and its relatives aren't focused"); + } + /* Don't steal focus from globally active clients. + I stole this idea from KWin. It seems nice. + */ + else if (!(focus_client->can_focus || + focus_client->focus_notify)) + { + steal = FALSE; + ob_debug_type(OB_DEBUG_FOCUS, + "Not focusing the window because a globally " + "active client has focus"); + } + /* Don't move focus if it's not going to go to this window + anyway */ + else if (client_focus_target(self) != self) { + steal = FALSE; + ob_debug_type(OB_DEBUG_FOCUS, + "Not focusing the window because another window " + "would get the focus anyway"); + } + /* Don't move focus if the window is not visible on the current + desktop and none of its relatives are focused */ + else if (!(self->desktop == screen_desktop || + self->desktop == DESKTOP_ALL) && + !relative_focused) + { + steal = FALSE; + ob_debug_type(OB_DEBUG_FOCUS, + "Not focusing the window because it is on " + "another desktop and no relatives are focused "); + } + } + + if (!steal) + ob_debug_type(OB_DEBUG_FOCUS, + "Focus stealing prevention activated for %s at " + "time %u (last user interaction time %u)", + self->title, steal_time, event_last_user_time); + return steal; +} + /*! Returns a new structure containing the per-app settings for this client. The returned structure needs to be freed with g_free. */ static ObAppSettings *client_get_settings_state(ObClient *self) @@ -1087,6 +1077,7 @@ static void client_get_all(ObClient *self, gboolean real) /* get the session related properties, these can change decorations from per-app settings */ client_get_session_ids(self); + client_save_session_ids(self); /* now we got everything that can affect the decorations */ if (!real) @@ -1758,7 +1749,8 @@ void client_setup_decor_and_functions(ObClient *self, gboolean reconfig) /* 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) - self->decorations = 0; + self->decorations &= (config_theme_keepborder ? + OB_FRAME_DECOR_BORDER : 0); /* if we don't have a titlebar, then we cannot shade! */ if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR)) @@ -2042,7 +2034,7 @@ void client_update_strut(ObClient *self) STRUT_PARTIAL_SET(strut, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - if (!STRUT_EQUAL(strut, self->strut)) { + if (!PARTIAL_STRUT_EQUAL(strut, self->strut)) { self->strut = strut; /* updating here is pointless while we're being mapped cuz we're not in @@ -2299,6 +2291,15 @@ static void client_get_session_ids(ObClient *self) } } +/*! Save the session IDs as seen by Openbox when the window mapped, so that + users can still access them later if the app changes them */ +static void client_save_session_ids(ObClient *self) +{ + OBT_PROP_SETS(self->window, OB_ROLE, utf8, self->role); + OBT_PROP_SETS(self->window, OB_NAME, utf8, self->name); + OBT_PROP_SETS(self->window, OB_CLASS, utf8, self->class); +} + static void client_change_wm_state(ObClient *self) { gulong state[2]; @@ -2546,8 +2547,6 @@ gboolean client_show(ObClient *self) desktop! */ client_change_wm_state(self); - - hooks_queue(OB_HOOK_WIN_VISIBLE, self); } return show; } @@ -2557,10 +2556,6 @@ gboolean client_hide(ObClient *self) gboolean hide = FALSE; if (!client_should_show(self)) { - if (self == focus_client) { - event_cancel_all_key_grabs(); - } - /* We don't need to ignore enter events here. The window can hide/iconify in 3 different ways: 1 - through an x message. in this case we ignore all enter events @@ -2586,8 +2581,6 @@ gboolean client_hide(ObClient *self) desktop! */ client_change_wm_state(self); - - hooks_queue(OB_HOOK_WIN_INVISIBLE, self); } return hide; } @@ -3181,9 +3174,6 @@ static void client_iconify_recursive(ObClient *self, frame_begin_iconify_animation(self->frame, iconic); /* do this after starting the animation so it doesn't flash */ client_showhide(self); - - hooks_queue((iconic ? OB_HOOK_WIN_ICONIC : OB_HOOK_WIN_UNICONIC), - self); } /* iconify all direct transients, and deiconify all transients @@ -3271,8 +3261,6 @@ void client_maximize(ObClient *self, gboolean max, gint dir) client_setup_decor_and_functions(self, FALSE); client_move_resize(self, x, y, w, h); - - hooks_queue((max ? OB_HOOK_WIN_MAX : OB_HOOK_WIN_UNMAX), self); } void client_shade(ObClient *self, gboolean shade) @@ -3286,8 +3274,6 @@ void client_shade(ObClient *self, gboolean shade) client_change_wm_state(self); /* the window is being hidden/shown */ /* resize the frame to just the titlebar */ frame_adjust_area(self->frame, FALSE, TRUE, FALSE); - - hooks_queue((shade ? OB_HOOK_WIN_SHADE : OB_HOOK_WIN_UNSHADE), self); } static void client_ping_event(ObClient *self, gboolean dead) @@ -3459,8 +3445,18 @@ void client_hilite(ObClient *self, gboolean hilite) /* don't allow focused windows to hilite */ self->demands_attention = hilite && !client_focused(self); if (self->frame != NULL) { /* if we're mapping, just set the state */ - if (self->demands_attention) + if (self->demands_attention) { frame_flash_start(self->frame); + + /* if the window is on another desktop then raise it and make it + the most recently used window */ + if (self->desktop != screen_desktop && + self->desktop != DESKTOP_ALL) + { + stacking_raise(CLIENT_AS_WINDOW(self)); + focus_order_to_top(self); + } + } else frame_flash_stop(self->frame); client_change_state(self); @@ -3499,9 +3495,6 @@ static void client_set_desktop_recursive(ObClient *self, /* the new desktop's geometry may be different, so we may need to resize, for example if we are maximized */ client_reconfigure(self, FALSE); - - if (old != self->desktop) - hooks_queue(OB_HOOK_WIN_DESK_CHANGE, self); } /* move all transients */ @@ -3778,8 +3771,6 @@ gboolean client_focus(ObClient *self) go moving on us */ event_halt_focus_delay(); - event_cancel_all_key_grabs(); - obt_display_ignore_errors(TRUE); if (self->can_focus) { @@ -3838,12 +3829,17 @@ static void client_present(ObClient *self, gboolean here, gboolean raise, } /* this function exists to map to the net_active_window message in the ewmh */ -void client_activate(ObClient *self, gboolean here, gboolean raise, +void client_activate(ObClient *self, gboolean desktop, + gboolean here, gboolean raise, gboolean unshade, gboolean user) { - if (user || (self->desktop == DESKTOP_ALL || - self->desktop == screen_desktop)) + if ((user && (desktop || + self->desktop == DESKTOP_ALL || + self->desktop == screen_desktop)) || + client_can_steal_focus(self, event_curtime, CurrentTime)) + { client_present(self, here, raise, unshade); + } else client_hilite(self, TRUE); } @@ -3928,9 +3924,6 @@ void client_set_undecorated(ObClient *self, gboolean undecorated) self->undecorated = undecorated; client_setup_decor_and_functions(self, TRUE); client_change_state(self); /* reflect this in the state hints */ - - hooks_queue((undecorated ? - OB_HOOK_WIN_UNDECORATED : OB_HOOK_WIN_DECORATED), self); } } @@ -4142,39 +4135,26 @@ void client_find_edge_directional(ObClient *self, ObDirection dir, gint *dest, gboolean *near_edge) { GList *it; - Rect *a, *mon; + Rect *a; Rect dock_area; gint edge; + guint i; a = screen_area(self->desktop, SCREEN_AREA_ALL_MONITORS, &self->frame->area); - mon = screen_area(self->desktop, SCREEN_AREA_ONE_MONITOR, - &self->frame->area); switch (dir) { case OB_DIRECTION_NORTH: - if (my_head >= RECT_TOP(*mon) + 1) - edge = RECT_TOP(*mon) - 1; - else - edge = RECT_TOP(*a) - 1; + edge = RECT_TOP(*a) - 1; break; case OB_DIRECTION_SOUTH: - if (my_head <= RECT_BOTTOM(*mon) - 1) - edge = RECT_BOTTOM(*mon) + 1; - else - edge = RECT_BOTTOM(*a) + 1; + edge = RECT_BOTTOM(*a) + 1; break; case OB_DIRECTION_EAST: - if (my_head <= RECT_RIGHT(*mon) - 1) - edge = RECT_RIGHT(*mon) + 1; - else - edge = RECT_RIGHT(*a) + 1; + edge = RECT_RIGHT(*a) + 1; break; case OB_DIRECTION_WEST: - if (my_head >= RECT_LEFT(*mon) + 1) - edge = RECT_LEFT(*mon) - 1; - else - edge = RECT_LEFT(*a) - 1; + edge = RECT_LEFT(*a) - 1; break; default: g_assert_not_reached(); @@ -4183,6 +4163,15 @@ void client_find_edge_directional(ObClient *self, ObDirection dir, *dest = edge; *near_edge = TRUE; + /* search for edges of monitors */ + for (i = 0; i < screen_num_monitors; ++i) { + Rect *area = screen_area(self->desktop, i, NULL); + detect_edge(*area, dir, my_head, my_size, my_edge_start, + my_edge_size, dest, near_edge); + g_free(area); + } + + /* search for edges of clients */ for (it = client_list; it; it = g_list_next(it)) { ObClient *cur = it->data; @@ -4204,7 +4193,6 @@ void client_find_edge_directional(ObClient *self, ObDirection dir, detect_edge(dock_area, dir, my_head, my_size, my_edge_start, my_edge_size, dest, near_edge); g_free(a); - g_free(mon); } void client_find_move_directional(ObClient *self, ObDirection dir,