#include "focus.h"
#include "stacking.h"
#include "openbox.h"
+#include "hooks.h"
#include "group.h"
#include "config.h"
#include "menuframe.h"
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,
gboolean transient = FALSE;
Rect place, *monitor;
Time launch_time, map_time;
+ guint32 user_time;
ob_debug("Managing window: 0x%lx", window);
ob_debug("Window type: %d", self->type);
ob_debug("Window group: 0x%x", self->group?self->group->leader:0);
+ ob_debug("Window name: %s class: %s", self->name, self->class);
/* now we have all of the window's information so we can set this up.
do this before creating the frame, so it can tell that we are still
/* tell startup notification that this app started */
launch_time = sn_app_started(self->startup_id, self->class, self->name);
+ if (!OBT_PROP_GET32(self->window, NET_WM_USER_TIME, CARDINAL, &user_time))
+ user_time = map_time;
+
/* do this after we have a frame.. it uses the frame to help determine the
WM_STATE to apply. */
client_change_state(self);
/* this means focus=true for window is same as config_focus_new=true */
((config_focus_new || (settings && settings->focus == 1)) ||
client_search_focus_tree_full(self)) &&
+ /* NET_WM_USER_TIME 0 when mapping means don't focus */
+ (user_time != 0) &&
/* this checks for focus=false for the window */
(!settings || settings->focus != 0) &&
focus_valid_target(self, FALSE, FALSE, TRUE, FALSE, FALSE))
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,
"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;
"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,
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 "
"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;
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)) {
transient windows as their children.
* * */
-
/* No change has occured */
if (oldgroup == newgroup &&
oldgtran == newgtran &&
(gint*)&w, (gint*)&h, &data);
obt_display_ignore_errors(FALSE);
-
if (xicon) {
if (w > 0 && h > 0) {
/* is this icon in the cache yet? */
desktop!
*/
client_change_wm_state(self);
+
+ hooks_queue(OB_HOOK_WIN_VISIBLE, self);
}
return show;
}
desktop!
*/
client_change_wm_state(self);
+
+ hooks_queue(OB_HOOK_WIN_INVISIBLE, self);
}
return hide;
}
self->type != OB_CLIENT_TYPE_DESKTOP);
}
-
static void client_apply_startup_state(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;
g_assert(*h > 0);
}
-
void client_configure(ObClient *self, gint x, gint y, gint w, gint h,
gboolean user, gboolean final, gboolean force_reply)
{
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
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) {
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)
#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;
{ 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;
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);
}
/* 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 */
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) ||
/* 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)) {
+ } else if (state == OBT_PROP_ATOM(NET_WM_STATE_BELOW)) {
+ /* and vice versa */
+ if (value)
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)) {
- 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;
}
}
client_focus(self);
}
-/* this function exists to map to the client_activate message in the ewmh,
- the user arg is unused because nobody uses it correctly anyway. */
+/* this function exists to map to the net_active_window message in the ewmh */
void client_activate(ObClient *self, gboolean here, gboolean raise,
gboolean unshade, gboolean user)
{
- client_present(self, here, raise, unshade);
+ if (user || (self->desktop == DESKTOP_ALL ||
+ self->desktop == screen_desktop))
+ client_present(self, here, raise, unshade);
+ else
+ client_hilite(self, TRUE);
}
static void client_bring_windows_recursive(ObClient *self,
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);
}
}
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;
/* 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:
/* 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:
}
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;
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;