#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"
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);
static void client_get_shaped(ObClient *self);
-static void client_get_mwm_hints(ObClient *self);
static void client_get_colormap(ObClient *self);
static void client_set_desktop_recursive(ObClient *self,
guint target,
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)
{
(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;
}
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 {
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)
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)) {
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)
/* 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)
}
}
-static void client_get_mwm_hints(ObClient *self)
+void client_get_mwm_hints(ObClient *self)
{
guint num;
guint32 *hints;
/* 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))
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
}
}
+/*! 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];
for (it = self->parents; it; it = g_slist_next(it)) {
ObClient *c = it->data;
- if ((c = client_search_focus_tree_full(it->data))) return c;
+ if ((c = client_search_focus_tree_full(c))) return c;
}
return NULL;
desktop!
*/
client_change_wm_state(self);
-
- hooks_queue(OB_HOOK_WIN_VISIBLE, self);
}
return show;
}
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
desktop!
*/
client_change_wm_state(self);
-
- hooks_queue(OB_HOOK_WIN_INVISIBLE, self);
}
return hide;
}
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
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)
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)
/* 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);
/* 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 */
value = self->demands_attention;
else if (state == OBT_PROP_ATOM(OB_WM_STATE_UNDECORATED))
value = undecorated;
+ else
+ g_assert_not_reached();
action = value ? OBT_PROP_ATOM(NET_WM_STATE_REMOVE) :
OBT_PROP_ATOM(NET_WM_STATE_ADD);
}
go moving on us */
event_halt_focus_delay();
- event_cancel_all_key_grabs();
-
obt_display_ignore_errors(TRUE);
if (self->can_focus) {
}
/* 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);
}
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);
}
}
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();
*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;
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,