X-Git-Url: https://git.brokenzipper.com/gitweb?a=blobdiff_plain;f=openbox%2Fclient.c;h=b6ca93a32d69e376d27ccadbd75d1759f58af6b4;hb=661a53cb6843d02f3373feab91052c47397bb6ed;hp=66006a48917571f8758fa9cab3fa2c36ccda9a75;hpb=26cc41f6c6187dabd5c7ee4365c8fa44751009e5;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index 66006a48..b6ca93a3 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -33,6 +33,7 @@ #include "focus.h" #include "stacking.h" #include "openbox.h" +#include "hooks.h" #include "group.h" #include "config.h" #include "menuframe.h" @@ -107,7 +108,6 @@ 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); - void client_startup(gboolean reconfig) { if ((client_default_icon = RrImageCacheFind(ob_rr_icons, @@ -413,6 +413,14 @@ void client_manage(Window window, ObPrompt *prompt) 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, @@ -420,6 +428,12 @@ void client_manage(Window window, ObPrompt *prompt) "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 focuesed: %d relative focused: %d", + parent_focused, relative_focused); if (menu_frame_visible || moveresize_in_progress) { activate = FALSE; @@ -443,13 +457,12 @@ void client_manage(Window window, ObPrompt *prompt) "Not focusing the window because its on another " "desktop"); } - /* If something is focused, and it's not our relative... */ - else if (focus_client && client_search_focus_tree_full(self) == NULL && - client_search_focus_group_full(self) == NULL) - { + /* If something is focused... */ + else if (focus_client) { /* If the user is working in another window right now, then don't steal focus */ - if (event_last_user_time && launch_time && + 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, @@ -458,10 +471,12 @@ void client_manage(Window window, ObPrompt *prompt) activate = FALSE; ob_debug_type(OB_DEBUG_FOCUS, "Not focusing the window because the user is " - "working in another window"); + "working in another window that is not " + "its parent"); } - /* If it's a transient (and its parents aren't focused) */ - else if (client_has_parent(self)) { + /* 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 " @@ -487,8 +502,11 @@ void client_manage(Window window, ObPrompt *prompt) "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)) + self->desktop == DESKTOP_ALL) && + !relative_focused) { activate = FALSE; raise = TRUE; @@ -560,8 +578,9 @@ 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) { @@ -635,6 +654,9 @@ 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)) { @@ -911,6 +933,19 @@ static gboolean client_restore_session_stacking(ObClient *self) return FALSE; } +void client_reconfigure(ObClient *self, gboolean force) +{ + int x, y, w, h, lw, lh; + + x = self->area.x; + y = self->area.y; + w = self->area.width; + h = self->area.height; + client_try_configure(self, &x, &y, &w, &h, &lw, &lh, FALSE); + client_find_onscreen(self, &x, &y, w, h, FALSE); + client_configure(self, x, y, w, h, FALSE, TRUE, force); +} + void client_move_onscreen(ObClient *self, gboolean rude) { gint x = self->area.x; @@ -1286,7 +1321,6 @@ static void client_update_transient_tree(ObClient *self, transient windows as their children. * * */ - /* No change has occured */ if (oldgroup == newgroup && oldgtran == newgtran && @@ -2102,7 +2136,6 @@ void client_update_icons(ObClient *self) (gint*)&w, (gint*)&h, &data); obt_display_ignore_errors(FALSE); - if (xicon) { if (w > 0 && h > 0) { /* is this icon in the cache yet? */ @@ -2519,6 +2552,8 @@ gboolean client_show(ObClient *self) desktop! */ client_change_wm_state(self); + + hooks_queue(OB_HOOK_WIN_VISIBLE, self); } return show; } @@ -2557,6 +2592,8 @@ gboolean client_hide(ObClient *self) desktop! */ client_change_wm_state(self); + + hooks_queue(OB_HOOK_WIN_INVISIBLE, self); } return hide; } @@ -2595,7 +2632,6 @@ gboolean client_enter_focusable(ObClient *self) self->type != OB_CLIENT_TYPE_DESKTOP); } - static void client_apply_startup_state(ObClient *self, gint x, gint y, gint w, gint h) { @@ -2796,8 +2832,10 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h, /* gets the client's position */ frame_frame_gravity(self->frame, x, y); - /* work within the preferred sizes given by the window */ - if (!(*w == self->area.width && *h == self->area.height)) { + /* work within the preferred sizes given by the window, these may have + changed rather than it's requested width and height, so always run + through this code */ + { gint basew, baseh, minw, minh; gint incw, inch; gfloat minratio, maxratio; @@ -2903,7 +2941,6 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h, g_assert(*h > 0); } - void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gboolean user, gboolean final, gboolean force_reply) { @@ -3150,6 +3187,9 @@ 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 @@ -3176,7 +3216,7 @@ void client_maximize(ObClient *self, gboolean max, gint dir) gint x, y, w, h; g_assert(dir == 0 || dir == 1 || dir == 2); - if (!(self->functions & OB_CLIENT_FUNC_MAXIMIZE)) return; /* can't */ + if (!(self->functions & OB_CLIENT_FUNC_MAXIMIZE) && max) return;/* can't */ /* check if already done */ if (max) { @@ -3237,6 +3277,8 @@ 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) @@ -3250,6 +3292,8 @@ 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) @@ -3312,12 +3356,20 @@ void client_close(ObClient *self) #define OB_KILL_RESULT_NO 0 #define OB_KILL_RESULT_YES 1 -static void client_kill_requested(ObPrompt *p, gint result, gpointer data) +static gboolean client_kill_requested(ObPrompt *p, gint result, gpointer data) { ObClient *self = data; if (result == OB_KILL_RESULT_YES) client_kill(self); + return TRUE; /* call the cleanup func */ +} + +static void client_kill_cleanup(ObPrompt *p, gpointer data) +{ + ObClient *self = data; + + g_assert(p == self->kill_prompt); prompt_unref(self->kill_prompt); self->kill_prompt = NULL; @@ -3332,7 +3384,14 @@ static void client_prompt_kill(ObClient *self) { 0, OB_KILL_RESULT_YES } }; gchar *m; - const gchar *y; + const gchar *y, *title; + + title = self->original_title; + if (title[0] == '\0') { + /* empty string, so use its parent */ + ObClient *p = client_search_top_direct_parent(self); + if (p) title = p->original_title; + } if (client_on_localhost(self)) { const gchar *sig; @@ -3344,24 +3403,26 @@ static void client_prompt_kill(ObClient *self) m = g_strdup_printf (_("The window \"%s\" does not seem to be responding. Do you want to force it to exit by sending the %s signal?"), - self->original_title, sig); + title, sig); y = _("End Process"); } else { m = g_strdup_printf (_("The window \"%s\" does not seem to be responding. Do you want to disconnect it from the X server?"), - self->original_title); + title); y = _("Disconnect"); } /* set the dialog buttons' text */ answers[0].text = _("Cancel"); /* "no" */ answers[1].text = y; /* "yes" */ - self->kill_prompt = prompt_new(m, answers, + self->kill_prompt = prompt_new(m, NULL, answers, sizeof(answers)/sizeof(answers[0]), OB_KILL_RESULT_NO, /* default = no */ OB_KILL_RESULT_NO, /* cancel = no */ - client_kill_requested, self); + client_kill_requested, + client_kill_cleanup, + self); g_free(m); } @@ -3444,6 +3505,9 @@ 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 */ @@ -3523,6 +3587,7 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2) gboolean above = self->above; gboolean below = self->below; gint i; + gboolean value; if (!(action == OBT_PROP_ATOM(NET_WM_STATE_ADD) || action == OBT_PROP_ATOM(NET_WM_STATE_REMOVE) || @@ -3538,103 +3603,65 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2) /* if toggling, then pick whether we're adding or removing */ if (action == OBT_PROP_ATOM(NET_WM_STATE_TOGGLE)) { if (state == OBT_PROP_ATOM(NET_WM_STATE_MODAL)) - action = modal ? OBT_PROP_ATOM(NET_WM_STATE_REMOVE) : - OBT_PROP_ATOM(NET_WM_STATE_ADD); + value = modal; else if (state == OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_VERT)) - action = self->max_vert ? OBT_PROP_ATOM(NET_WM_STATE_REMOVE) : - OBT_PROP_ATOM(NET_WM_STATE_ADD); + value = self->max_vert; else if (state == OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_HORZ)) - action = self->max_horz ? OBT_PROP_ATOM(NET_WM_STATE_REMOVE) : - OBT_PROP_ATOM(NET_WM_STATE_ADD); + value = self->max_horz; else if (state == OBT_PROP_ATOM(NET_WM_STATE_SHADED)) - action = shaded ? OBT_PROP_ATOM(NET_WM_STATE_REMOVE) : - OBT_PROP_ATOM(NET_WM_STATE_ADD); + value = shaded; else if (state == OBT_PROP_ATOM(NET_WM_STATE_SKIP_TASKBAR)) - action = self->skip_taskbar ? - OBT_PROP_ATOM(NET_WM_STATE_REMOVE) : - OBT_PROP_ATOM(NET_WM_STATE_ADD); + value = self->skip_taskbar; else if (state == OBT_PROP_ATOM(NET_WM_STATE_SKIP_PAGER)) - action = self->skip_pager ? - OBT_PROP_ATOM(NET_WM_STATE_REMOVE) : - OBT_PROP_ATOM(NET_WM_STATE_ADD); + value = self->skip_pager; else if (state == OBT_PROP_ATOM(NET_WM_STATE_HIDDEN)) - action = self->iconic ? - OBT_PROP_ATOM(NET_WM_STATE_REMOVE) : - OBT_PROP_ATOM(NET_WM_STATE_ADD); + value = self->iconic; else if (state == OBT_PROP_ATOM(NET_WM_STATE_FULLSCREEN)) - action = fullscreen ? - OBT_PROP_ATOM(NET_WM_STATE_REMOVE) : - OBT_PROP_ATOM(NET_WM_STATE_ADD); + value = fullscreen; else if (state == OBT_PROP_ATOM(NET_WM_STATE_ABOVE)) - action = self->above ? OBT_PROP_ATOM(NET_WM_STATE_REMOVE) : - OBT_PROP_ATOM(NET_WM_STATE_ADD); + value = self->above; else if (state == OBT_PROP_ATOM(NET_WM_STATE_BELOW)) - action = self->below ? OBT_PROP_ATOM(NET_WM_STATE_REMOVE) : - OBT_PROP_ATOM(NET_WM_STATE_ADD); + value = self->below; else if (state == OBT_PROP_ATOM(NET_WM_STATE_DEMANDS_ATTENTION)) - action = self->demands_attention ? - OBT_PROP_ATOM(NET_WM_STATE_REMOVE) : - OBT_PROP_ATOM(NET_WM_STATE_ADD); + value = self->demands_attention; else if (state == OBT_PROP_ATOM(OB_WM_STATE_UNDECORATED)) - action = undecorated ? OBT_PROP_ATOM(NET_WM_STATE_REMOVE) : - OBT_PROP_ATOM(NET_WM_STATE_ADD); + value = undecorated; + action = value ? OBT_PROP_ATOM(NET_WM_STATE_REMOVE) : + OBT_PROP_ATOM(NET_WM_STATE_ADD); } - if (action == OBT_PROP_ATOM(NET_WM_STATE_ADD)) { - if (state == OBT_PROP_ATOM(NET_WM_STATE_MODAL)) { - modal = TRUE; - } else if (state == OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_VERT)) { - max_vert = TRUE; - } else if (state == OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_HORZ)) { - max_horz = TRUE; - } else if (state == OBT_PROP_ATOM(NET_WM_STATE_SHADED)) { - shaded = TRUE; - } else if (state == OBT_PROP_ATOM(NET_WM_STATE_SKIP_TASKBAR)) { - self->skip_taskbar = TRUE; - } else if (state == OBT_PROP_ATOM(NET_WM_STATE_SKIP_PAGER)) { - self->skip_pager = TRUE; - } else if (state == OBT_PROP_ATOM(NET_WM_STATE_HIDDEN)) { - iconic = TRUE; - } else if (state == OBT_PROP_ATOM(NET_WM_STATE_FULLSCREEN)) { - fullscreen = TRUE; - } else if (state == OBT_PROP_ATOM(NET_WM_STATE_ABOVE)) { - above = TRUE; + value = action == OBT_PROP_ATOM(NET_WM_STATE_ADD); + if (state == OBT_PROP_ATOM(NET_WM_STATE_MODAL)) { + modal = value; + } else if (state == OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_VERT)) { + max_vert = value; + } else if (state == OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_HORZ)) { + max_horz = value; + } else if (state == OBT_PROP_ATOM(NET_WM_STATE_SHADED)) { + shaded = value; + } else if (state == OBT_PROP_ATOM(NET_WM_STATE_SKIP_TASKBAR)) { + self->skip_taskbar = value; + } else if (state == OBT_PROP_ATOM(NET_WM_STATE_SKIP_PAGER)) { + self->skip_pager = value; + } else if (state == OBT_PROP_ATOM(NET_WM_STATE_HIDDEN)) { + iconic = value; + } else if (state == OBT_PROP_ATOM(NET_WM_STATE_FULLSCREEN)) { + fullscreen = value; + } else if (state == OBT_PROP_ATOM(NET_WM_STATE_ABOVE)) { + above = value; + /* only unset below when setting above, otherwise you can't get to + the normal layer */ + if (value) below = FALSE; - } else if (state == OBT_PROP_ATOM(NET_WM_STATE_BELOW)) { - above = FALSE; - below = TRUE; - } else if (state == OBT_PROP_ATOM(NET_WM_STATE_DEMANDS_ATTENTION)){ - demands_attention = TRUE; - } else if (state == OBT_PROP_ATOM(OB_WM_STATE_UNDECORATED)) { - undecorated = TRUE; - } - - } else { /* action == OBT_PROP_ATOM(NET_WM_STATE_REMOVE) */ - if (state == OBT_PROP_ATOM(NET_WM_STATE_MODAL)) { - modal = FALSE; - } else if (state == OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_VERT)) { - max_vert = FALSE; - } else if (state == OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_HORZ)) { - max_horz = FALSE; - } else if (state == OBT_PROP_ATOM(NET_WM_STATE_SHADED)) { - shaded = FALSE; - } else if (state == OBT_PROP_ATOM(NET_WM_STATE_SKIP_TASKBAR)) { - self->skip_taskbar = FALSE; - } else if (state == OBT_PROP_ATOM(NET_WM_STATE_SKIP_PAGER)) { - self->skip_pager = FALSE; - } else if (state == OBT_PROP_ATOM(NET_WM_STATE_HIDDEN)) { - iconic = FALSE; - } else if (state == OBT_PROP_ATOM(NET_WM_STATE_FULLSCREEN)) { - fullscreen = FALSE; - } else if (state == OBT_PROP_ATOM(NET_WM_STATE_ABOVE)) { + } else if (state == OBT_PROP_ATOM(NET_WM_STATE_BELOW)) { + /* and vice versa */ + if (value) above = FALSE; - } else if (state == OBT_PROP_ATOM(NET_WM_STATE_BELOW)) { - below = FALSE; - } else if (state == OBT_PROP_ATOM(NET_WM_STATE_DEMANDS_ATTENTION)){ - demands_attention = FALSE; - } else if (state == OBT_PROP_ATOM(OB_WM_STATE_UNDECORATED)) { - undecorated = FALSE; - } + below = value; + } else if (state == OBT_PROP_ATOM(NET_WM_STATE_DEMANDS_ATTENTION)){ + demands_attention = value; + } else if (state == OBT_PROP_ATOM(OB_WM_STATE_UNDECORATED)) { + undecorated = value; } } @@ -3883,6 +3910,9 @@ 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); } } @@ -3945,6 +3975,21 @@ ObClient *client_search_focus_parent(ObClient *self) return NULL; } +ObClient *client_search_focus_parent_full(ObClient *self) +{ + GSList *it; + ObClient *ret = NULL; + + for (it = self->parents; it; it = g_slist_next(it)) { + if (client_focused(it->data)) + ret = it->data; + else + ret = client_search_focus_parent_full(it->data); + if (ret) break; + } + return ret; +} + ObClient *client_search_parent(ObClient *self, ObClient *search) { GSList *it; @@ -4028,12 +4073,12 @@ static void detect_edge(Rect area, ObDirection dir, /* check if the head of this window is closer than the previously chosen edge (take into account that the previously chosen edge might have been a tail, not a head) */ - if (head + (*near_edge ? 0 : my_size) < *dest) + if (head + (*near_edge ? 0 : my_size) <= *dest) skip_head = TRUE; /* check if the tail of this window is closer than the previously chosen edge (take into account that the previously chosen edge might have been a head, not a tail) */ - if (tail - (!*near_edge ? 0 : my_size) < *dest) + if (tail - (!*near_edge ? 0 : my_size) <= *dest) skip_tail = TRUE; break; case OB_DIRECTION_SOUTH: @@ -4047,12 +4092,12 @@ static void detect_edge(Rect area, ObDirection dir, /* check if the head of this window is closer than the previously chosen edge (take into account that the previously chosen edge might have been a tail, not a head) */ - if (head - (*near_edge ? 0 : my_size) > *dest) + if (head - (*near_edge ? 0 : my_size) >= *dest) skip_head = TRUE; /* check if the tail of this window is closer than the previously chosen edge (take into account that the previously chosen edge might have been a head, not a tail) */ - if (tail + (!*near_edge ? 0 : my_size) > *dest) + if (tail + (!*near_edge ? 0 : my_size) >= *dest) skip_tail = TRUE; break; default: @@ -4060,7 +4105,7 @@ static void detect_edge(Rect area, ObDirection dir, } ob_debug("my head %d size %d", my_head, my_size); - ob_debug("head %d tail %d deest %d", head, tail, *dest); + ob_debug("head %d tail %d dest %d", head, tail, *dest); if (!skip_head) { ob_debug("using near edge %d", head); *dest = head; @@ -4223,28 +4268,28 @@ void client_find_resize_directional(ObClient *self, ObDirection side, switch (side) { case OB_DIRECTION_EAST: head = RECT_RIGHT(self->frame->area) + - (self->size_inc.width - 1) * (grow ? 1 : -1); + (self->size_inc.width - 1) * (grow ? 1 : 0); e_start = RECT_TOP(self->frame->area); e_size = self->frame->area.height; dir = grow ? OB_DIRECTION_EAST : OB_DIRECTION_WEST; break; case OB_DIRECTION_WEST: head = RECT_LEFT(self->frame->area) - - (self->size_inc.width - 1) * (grow ? 1 : -1); + (self->size_inc.width - 1) * (grow ? 1 : 0); e_start = RECT_TOP(self->frame->area); e_size = self->frame->area.height; dir = grow ? OB_DIRECTION_WEST : OB_DIRECTION_EAST; break; case OB_DIRECTION_NORTH: head = RECT_TOP(self->frame->area) - - (self->size_inc.height - 1) * (grow ? 1 : -1); + (self->size_inc.height - 1) * (grow ? 1 : 0); e_start = RECT_LEFT(self->frame->area); e_size = self->frame->area.width; dir = grow ? OB_DIRECTION_NORTH : OB_DIRECTION_SOUTH; break; case OB_DIRECTION_SOUTH: head = RECT_BOTTOM(self->frame->area) + - (self->size_inc.height - 1) * (grow ? 1 : -1); + (self->size_inc.height - 1) * (grow ? 1 : 0); e_start = RECT_LEFT(self->frame->area); e_size = self->frame->area.width; dir = grow ? OB_DIRECTION_SOUTH : OB_DIRECTION_NORTH;