#include "mouse.h"
#include "render/render.h"
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
#include <glib.h>
#include <X11/Xutil.h>
/*! The event mask to grab on client windows */
-#define CLIENT_EVENTMASK (PropertyChangeMask | StructureNotifyMask)
+#define CLIENT_EVENTMASK (PropertyChangeMask | StructureNotifyMask | \
+ ColormapChangeMask)
#define CLIENT_NOPROPAGATEMASK (ButtonPressMask | ButtonReleaseMask | \
ButtonMotionMask)
gpointer data;
} Destructor;
-GList *client_list = NULL;
+GList *client_list = NULL;
static GSList *client_destructors = NULL;
-static Time client_last_user_time = CurrentTime;
static void client_get_all(ObClient *self);
static void client_toggle_border(ObClient *self, gboolean show);
static void client_get_shaped(ObClient *self);
static void client_get_mwm_hints(ObClient *self);
static void client_get_gravity(ObClient *self);
+static void client_get_client_machine(ObClient *self);
+static void client_get_colormap(ObClient *self);
static void client_change_allowed_actions(ObClient *self);
static void client_change_state(ObClient *self);
static void client_change_wm_state(ObClient *self);
static void client_restore_session_state(ObClient *self);
static void client_restore_session_stacking(ObClient *self);
static ObAppSettings *client_get_settings_state(ObClient *self);
-static void client_unfocus(ObClient *self);
void client_startup(gboolean reconfig)
{
self->wmstate = WithdrawnState; /* make sure it gets updated first time */
self->layer = -1;
self->desktop = screen_num_desktops; /* always an invalid value */
- self->user_time = ~0; /* maximum value, always newer than the real time */
+ self->user_time = CurrentTime;
client_get_all(self);
- client_restore_session_state(self);
/* per-app settings override stuff, and return the settings for other
uses too */
settings = client_get_settings_state(self);
+ /* the session should get the last say */
+ client_restore_session_state(self);
client_calc_layer(self);
/* focus the new window? */
if (ob_state() != OB_STATE_STARTING &&
+ !self->iconic &&
/* this means focus=true for window is same as config_focus_new=true */
((config_focus_new || (settings && settings->focus == 1)) ||
client_search_focus_parent(self)) &&
self->type == OB_CLIENT_TYPE_DIALOG))
{
activate = TRUE;
-#if 0
- if (self->desktop != screen_desktop) {
- /* activate the window */
- activate = TRUE;
- } else {
- gboolean group_foc = FALSE;
-
- if (self->group) {
- GSList *it;
-
- for (it = self->group->members; it; it = g_slist_next(it))
- {
- if (client_focused(it->data))
- {
- group_foc = TRUE;
- break;
- }
- }
- }
- if ((group_foc ||
- (!self->transient_for && (!self->group ||
- !self->group->members->next))) ||
- client_search_focus_tree_full(self) ||
- !focus_client ||
- !client_normal(focus_client))
- {
- /* activate the window */
- activate = TRUE;
- }
- }
-#endif
}
/* get the current position */
self->window, newx, newy, self->area.width, self->area.height);
client_apply_startup_state(self, newx, newy);
- keyboard_grab_for_client(self, TRUE);
mouse_grab_for_client(self, TRUE);
if (activate) {
+ guint32 last_time = focus_client ?
+ focus_client->user_time : CurrentTime;
+
/* This is focus stealing prevention */
ob_debug("Want to focus new window 0x%x with time %u (last time %u)\n",
- self->window, self->user_time, client_last_user_time);
+ self->window, self->user_time, last_time);
- /* If a nothing at all, or a parent was focused, then focus this
+ /* if it's on another desktop */
+ if (!(self->desktop == screen_desktop || self->desktop == DESKTOP_ALL)
+ && /* the timestamp is from before you changed desktops */
+ self->user_time && screen_desktop_user_time &&
+ !event_time_after(self->user_time, screen_desktop_user_time))
+ {
+ activate = FALSE;
+ }
+ /* If nothing is focused, or a parent was focused, then focus this
always
*/
- if (!focus_client || client_search_focus_parent(self) != NULL)
+ else if (!focus_client || client_search_focus_parent(self) != NULL)
activate = TRUE;
else
{
/* If time stamp is old, don't steal focus */
- if (self->user_time && self->user_time < client_last_user_time)
+ if (self->user_time && last_time &&
+ !event_time_after(self->user_time, last_time))
+ {
activate = FALSE;
+ }
/* Don't steal focus from globally active clients.
I stole this idea from KWin. It seems nice.
*/
activate = FALSE;
}
- if (activate)
- {
- /* since focus can change the stacking orders, if we focus the
- window then the standard raise it gets is not enough, we need
- to queue one for after the focus change takes place */
- client_raise(self);
- } else {
+ if (!activate) {
ob_debug("Focus stealing prevention activated for %s with time %u "
"(last time %u)\n",
- self->title, self->user_time, client_last_user_time);
+ self->title, self->user_time, last_time);
/* if the client isn't focused, then hilite it so the user
knows it is there */
client_hilite(self, TRUE);
/* this has to happen before we try focus the window, but we want it to
happen after the client's stacking has been determined or it looks bad
*/
- client_showhide(self);
+ client_show(self);
/* use client_focus instead of client_activate cuz client_activate does
stuff like switch desktops etc and I'm not interested in all that when
a window maps since its not based on an action from the user like
clicking a window to activate it. so keep the new window out of the way
but do focus it. */
- if (activate) {
- /* if using focus_delay, stop the timer now so that focus doesn't
- go moving on us */
- event_halt_focus_delay();
- client_focus(self);
- }
-
- /* client_activate does this but we aret using it so we have to do it
- here as well */
- if (screen_showing_desktop)
- screen_show_desktop(FALSE);
+ if (activate)
+ client_activate(self, FALSE, TRUE);
/* add to client list/map */
client_list = g_list_append(client_list, self);
g_assert(self != NULL);
- /* update the focus lists */
- focus_order_remove(self);
-
- if (focus_client == self) {
- XEvent e;
-
- /* focus the last focused window on the desktop, and ignore enter
- events from the unmap so it doesnt mess with the focus */
- while (XCheckTypedEvent(ob_display, EnterNotify, &e));
- /* remove these flags so we don't end up getting focused in the
- fallback! */
- self->can_focus = FALSE;
- self->focus_notify = FALSE;
- self->modal = FALSE;
- client_unfocus(self);
- }
-
- /* potentially fix focusLast */
- if (config_focus_last)
- grab_pointer(TRUE, OB_CURSOR_NONE);
+ /* we dont want events no more. do this before hiding the frame so we
+ don't generate more events */
+ XSelectInput(ob_display, self->window, NoEventMask);
frame_hide(self->frame);
+ /* flush to send the hide to the server quickly */
XFlush(ob_display);
- keyboard_grab_for_client(self, FALSE);
+ if (focus_client == self) {
+ /* ignore enter events from the unmap so it doesnt mess with the focus
+ */
+ event_ignore_queued_enters();
+ }
+
mouse_grab_for_client(self, FALSE);
/* remove the window from our save set */
XChangeSaveSet(ob_display, self->window, SetModeDelete);
- /* we dont want events no more */
- XSelectInput(ob_display, self->window, NoEventMask);
+ /* update the focus lists */
+ focus_order_remove(self);
+ /* don't leave an invalid focus_client */
+ if (self == focus_client)
+ focus_client = NULL;
client_list = g_list_remove(client_list, self);
stacking_remove(self);
self->group = NULL;
}
- /* give the client its border back */
- client_toggle_border(self, TRUE);
+ /* restore the window's original geometry so it is not lost */
+ {
+ Rect a = self->area;
+
+ if (self->fullscreen)
+ a = self->pre_fullscreen_area;
+ else if (self->max_horz || self->max_vert) {
+ if (self->max_horz) {
+ a.x = self->pre_max_area.x;
+ a.width = self->pre_max_area.width;
+ }
+ if (self->max_vert) {
+ a.y = self->pre_max_area.y;
+ a.height = self->pre_max_area.height;
+ }
+ }
+
+ /* give the client its border back */
+ client_toggle_border(self, TRUE);
+
+ self->fullscreen = self->max_horz = self->max_vert = FALSE;
+ self->decorations = 0; /* unmanaged windows have no decor */
+
+ client_move_resize(self, a.x, a.y, a.width, a.height);
+ }
/* reparent the window out of the frame, and free the frame */
frame_release_client(self->frame, self);
self->frame = NULL;
- /* restore the window's original geometry so it is not lost */
- if (self->fullscreen)
- XMoveResizeWindow(ob_display, self->window,
- self->pre_fullscreen_area.x,
- self->pre_fullscreen_area.y,
- self->pre_fullscreen_area.width,
- self->pre_fullscreen_area.height);
- else if (self->max_horz || self->max_vert) {
- Rect a = self->area;
- if (self->max_horz) {
- a.x = self->pre_max_area.x;
- a.width = self->pre_max_area.width;
- }
- if (self->max_vert) {
- a.y = self->pre_max_area.y;
- a.height = self->pre_max_area.height;
- }
- XMoveResizeWindow(ob_display, self->window,
- a.x, a.y, a.width, a.height);
- }
-
if (ob_state() != OB_STATE_EXITING) {
/* these values should not be persisted across a window
unmapping/mapping */
XMapWindow(ob_display, self->window);
}
-
ob_debug("Unmanaged window 0x%lx\n", self->window);
/* free all data allocated in the client struct */
g_free(self->name);
g_free(self->class);
g_free(self->role);
+ g_free(self->client_machine);
g_free(self->sm_client_id);
g_free(self);
/* update the list hints */
client_set_list();
-
- if (config_focus_last)
- grab_pointer(FALSE, OB_CURSOR_NONE);
}
static ObAppSettings *client_get_settings_state(ObClient *self)
if (settings->max_vert != -1)
self->max_vert = !!settings->max_vert;
if (settings->max_horz != -1)
- self->max_vert = !!settings->max_horz;
+ self->max_horz = !!settings->max_horz;
if (settings->fullscreen != -1)
self->fullscreen = !!settings->fullscreen;
if (settings->desktop < screen_num_desktops
|| settings->desktop == DESKTOP_ALL)
- client_set_desktop(self, settings->desktop, TRUE);
+ self->desktop = settings->desktop;
if (settings->layer == -1) {
self->below = TRUE;
if (show) {
XSetWindowBorderWidth(ob_display, self->window, self->border_width);
- /* move the client so it is back it the right spot _with_ its
- border! */
- if (x != oldx || y != oldy)
- XMoveWindow(ob_display, self->window, x, y);
+ /* set border_width to 0 because there is no border to add into
+ calculations anymore */
+ self->border_width = 0;
} else
XSetWindowBorderWidth(ob_display, self->window, 0);
}
(min/max sizes), so we're ready to set up the decorations/functions */
client_setup_decor_and_functions(self);
+#ifdef SYNC
+ client_update_sync_request_counter(self);
+#endif
+ client_get_client_machine(self);
+ client_get_colormap(self);
client_update_title(self);
client_update_class(self);
client_update_sm_client_id(self);
client_update_strut(self);
client_update_icons(self);
- client_update_user_time(self, FALSE);
+ client_update_user_time(self);
}
static void client_get_startup_id(ObClient *self)
g_assert(ret != BadWindow);
RECT_SET(self->area, wattrib.x, wattrib.y, wattrib.width, wattrib.height);
+ POINT_SET(self->root_pos, wattrib.x, wattrib.y);
self->border_width = wattrib.border_width;
ob_debug("client area: %d %d %d %d\n", wattrib.x, wattrib.y,
self->desktop = screen_desktop;
}
}
- if (self->desktop != d) {
- /* set the desktop hint, to make sure that it always exists */
- PROP_SET32(self->window, net_wm_desktop, cardinal, self->desktop);
- }
}
static void client_get_layer(ObClient *self)
if (PROP_GETA32(self->window, wm_protocols, atom, &proto, &num_return)) {
for (i = 0; i < num_return; ++i) {
- if (proto[i] == prop_atoms.wm_delete_window) {
+ if (proto[i] == prop_atoms.wm_delete_window)
/* this means we can request the window to close */
self->delete_window = TRUE;
- } else if (proto[i] == prop_atoms.wm_take_focus)
+ else if (proto[i] == prop_atoms.wm_take_focus)
/* if this protocol is requested, then the window will be
notified whenever we want it to receive focus */
self->focus_notify = TRUE;
+#ifdef SYNC
+ else if (proto[i] == prop_atoms.net_wm_sync_request)
+ /* if this protocol is requested, then resizing the
+ window will be synchronized between the frame and the
+ client */
+ self->sync_request = TRUE;
+#endif
}
g_free(proto);
}
}
+#ifdef SYNC
+void client_update_sync_request_counter(ObClient *self)
+{
+ guint32 i;
+
+ if (PROP_GET32(self->window, net_wm_sync_request_counter, cardinal, &i)) {
+ self->sync_counter = i;
+ } else
+ self->sync_counter = None;
+}
+#endif
+
static void client_get_gravity(ObClient *self)
{
XWindowAttributes wattrib;
self->gravity = wattrib.win_gravity;
}
+void client_get_colormap(ObClient *self)
+{
+ XWindowAttributes wa;
+
+ if (XGetWindowAttributes(ob_display, self->window, &wa))
+ client_update_colormap(self, wa.colormap);
+}
+
+void client_update_colormap(ObClient *self, Colormap colormap)
+{
+ self->colormap = colormap;
+}
+
void client_update_normal_hints(ObClient *self)
{
XSizeHints size;
void client_update_title(ObClient *self)
{
gchar *data = NULL;
+ gchar *visible = NULL;
g_free(self->title);
}
}
- PROP_SETS(self->window, net_wm_visible_name, data);
- self->title = data;
+ if (self->client_machine) {
+ visible = g_strdup_printf("%s (%s)", data, self->client_machine);
+ g_free(data);
+ } else
+ visible = data;
+
+ PROP_SETS(self->window, net_wm_visible_name, visible);
+ self->title = visible;
if (self->frame)
frame_adjust_title(self->frame);
}
}
- if (self->frame)
+ /* set the default icon onto the window
+ in theory, this could be a race, but if a window doesn't set an icon
+ or removes it entirely, it's not very likely it is going to set one
+ right away afterwards */
+ if (self->nicons == 0) {
+ RrPixel32 *icon = ob_rr_theme->def_win_icon;
+ gulong *data;
+
+ data = g_new(guint32, 48*48+2);
+ data[0] = data[1] = 48;
+ for (i = 0; i < 48*48; ++i)
+ data[i+2] = (((icon[i] >> RrDefaultAlphaOffset) & 0xff) << 24) +
+ (((icon[i] >> RrDefaultRedOffset) & 0xff) << 16) +
+ (((icon[i] >> RrDefaultGreenOffset) & 0xff) << 8) +
+ (((icon[i] >> RrDefaultBlueOffset) & 0xff) << 0);
+ PROP_SETA32(self->window, net_wm_icon, cardinal, data, 48*48+2);
+ g_free(data);
+ } else if (self->frame)
+ /* don't draw the icon empty if we're just setting one now anyways,
+ we'll get the property change any second */
frame_adjust_icon(self->frame);
}
-void client_update_user_time(ObClient *self, gboolean new_event)
+void client_update_user_time(ObClient *self)
{
guint32 time;
if (PROP_GET32(self->window, net_wm_user_time, cardinal, &time)) {
- self->user_time = time;
/* we set this every time, not just when it grows, because in practice
sometimes time goes backwards! (ntpdate.. yay....) so.. if it goes
backward we don't want all windows to stop focusing. we'll just
assume noone is setting times older than the last one, cuz that
would be pretty stupid anyways
- However! This is called when a window is mapped to get its user time
- but it's an old number, it's not changing it from new user
- interaction, so in that case, don't change the last user time.
*/
- if (new_event)
- client_last_user_time = time;
+ self->user_time = time;
/*
ob_debug("window %s user time %u\n", self->title, time);
- ob_debug("last user time %u\n", client_last_user_time);
*/
}
}
+static void client_get_client_machine(ObClient *self)
+{
+ gchar *data = NULL;
+ gchar localhost[128];
+
+ g_free(self->client_machine);
+
+ if (PROP_GETS(self->window, wm_client_machine, locale, &data)) {
+ gethostname(localhost, 127);
+ localhost[127] = '\0';
+ if (strcmp(localhost, data))
+ self->client_machine = data;
+ }
+}
+
static void client_change_wm_state(ObClient *self)
{
gulong state[2];
return FALSE;
}
+void client_show(ObClient *self)
+{
+
+ if (client_should_show(self)) {
+ frame_show(self->frame);
+ }
+
+ /* According to the ICCCM (sec 4.1.3.1) when a window is not visible, it
+ needs to be in IconicState. This includes when it is on another
+ desktop!
+ */
+ client_change_wm_state(self);
+}
+
+void client_hide(ObClient *self)
+{
+ if (!client_should_show(self)) {
+ frame_hide(self->frame);
+ }
+
+ /* According to the ICCCM (sec 4.1.3.1) when a window is not visible, it
+ needs to be in IconicState. This includes when it is on another
+ desktop!
+ */
+ client_change_wm_state(self);
+}
+
void client_showhide(ObClient *self)
{
}
else {
frame_hide(self->frame);
-
- /* Fall back focus since we're disappearing */
- if (focus_client == self)
- client_unfocus(self);
}
/* According to the ICCCM (sec 4.1.3.1) when a window is not visible, it
self->area.x = x;
self->area.y = y;
+ /* set the desktop hint, to make sure that it always exists */
+ PROP_SET32(self->window, net_wm_desktop, cardinal, self->desktop);
+
/* these are in a carefully crafted order.. */
if (self->iconic) {
pos = TRUE;
}
- /* if the client didn't get positioned yet, then do so now */
- if (!pos && (ox != x || oy != y)) {
+ /* if the client didn't get positioned yet, then do so now
+ call client_move even if the window is not being moved anywhere, because
+ when we reparent it and decorate it, it is getting moved and we need to
+ be telling it so with a ConfigureNotify event.
+ */
+ if (!pos) {
/* use the saved position */
self->area.x = ox;
self->area.y = oy;
the updated frame dimensions. */
frame_adjust_area(self->frame, TRUE, TRUE, TRUE);
- /* gets the frame's position */
- frame_client_gravity(self->frame, x, y);
-
- /* these positions are frame positions, not client positions */
-
- /* set the size and position if fullscreen */
- if (self->fullscreen) {
- Rect *a;
- guint i;
-
- i = screen_find_monitor(&desired_area);
- a = screen_physical_area_monitor(i);
-
- *x = a->x;
- *y = a->y;
- *w = a->width;
- *h = a->height;
-
- user = FALSE; /* ignore that increment etc shit when in fullscreen */
- } else {
- Rect *a;
- guint i;
-
- i = screen_find_monitor(&desired_area);
- a = screen_area_monitor(self->desktop, i);
-
- /* set the size and position if maximized */
- if (self->max_horz) {
- *x = a->x;
- *w = a->width - self->frame->size.left - self->frame->size.right;
- }
- if (self->max_vert) {
- *y = a->y;
- *h = a->height - self->frame->size.top - self->frame->size.bottom;
- }
- }
-
- /* gets the client's position */
- frame_frame_gravity(self->frame, x, y);
-
- /* these override the above states! if you cant move you can't move! */
- if (user) {
- if (!(self->functions & OB_CLIENT_FUNC_MOVE)) {
- *x = self->area.x;
- *y = self->area.y;
- }
- if (!(self->functions & OB_CLIENT_FUNC_RESIZE)) {
- *w = self->area.width;
- *h = self->area.height;
- }
- }
-
+ /* work within the prefered sizes given by the window */
if (!(*w == self->area.width && *h == self->area.height)) {
gint basew, baseh, minw, minh;
*h += self->base_size.height;
}
+ /* gets the frame's position */
+ frame_client_gravity(self->frame, x, y);
+
+ /* these positions are frame positions, not client positions */
+
+ /* set the size and position if fullscreen */
+ if (self->fullscreen) {
+ Rect *a;
+ guint i;
+
+ i = screen_find_monitor(&desired_area);
+ a = screen_physical_area_monitor(i);
+
+ *x = a->x;
+ *y = a->y;
+ *w = a->width;
+ *h = a->height;
+
+ user = FALSE; /* ignore if the client can't be moved/resized when it
+ is entering fullscreen */
+ } else if (self->max_horz || self->max_vert) {
+ Rect *a;
+ guint i;
+
+ i = screen_find_monitor(&desired_area);
+ a = screen_area_monitor(self->desktop, i);
+
+ /* set the size and position if maximized */
+ if (self->max_horz) {
+ *x = a->x;
+ *w = a->width - self->frame->size.left - self->frame->size.right;
+ }
+ if (self->max_vert) {
+ *y = a->y;
+ *h = a->height - self->frame->size.top - self->frame->size.bottom;
+ }
+
+ /* maximizing is not allowed if the user can't move+resize the window
+ */
+ }
+
+ /* gets the client's position */
+ frame_frame_gravity(self->frame, x, y);
+
+ /* these override the above states! if you cant move you can't move! */
+ if (user) {
+ if (!(self->functions & OB_CLIENT_FUNC_MOVE)) {
+ *x = self->area.x;
+ *y = self->area.y;
+ }
+ if (!(self->functions & OB_CLIENT_FUNC_RESIZE)) {
+ *w = self->area.width;
+ *h = self->area.height;
+ }
+ }
+
g_assert(*w > 0);
g_assert(*h > 0);
gboolean user, gboolean final,
gboolean force_reply)
{
- gint oldw, oldh;
+ gint oldw, oldh, oldrx, oldry;
gboolean send_resize_client;
- gboolean moved = FALSE, resized = FALSE;
+ gboolean moved = FALSE, resized = FALSE, rootmoved = FALSE;
guint fdecor = self->frame->decorations;
gboolean fhorz = self->frame->max_horz;
gint logicalw, logicalh;
(resized && config_resize_redraw))));
/* if the client is enlarging, then resize the client before the frame */
- if (send_resize_client && user && (w > oldw || h > oldh))
+ if (send_resize_client && user && (w > oldw || h > oldh)) {
XResizeWindow(ob_display, self->window, MAX(w, oldw), MAX(h, oldh));
-
- /* move/resize the frame to match the request */
- if (self->frame) {
- if (self->decorations != fdecor || self->max_horz != fhorz)
- moved = resized = TRUE;
-
- if (moved || resized)
- frame_adjust_area(self->frame, moved, resized, FALSE);
-
- if (!resized && (force_reply || ((!user && moved) || (user && final))))
- {
- XEvent event;
- event.type = ConfigureNotify;
- event.xconfigure.display = ob_display;
- event.xconfigure.event = self->window;
- event.xconfigure.window = self->window;
-
- /* root window real coords */
- event.xconfigure.x = self->frame->area.x + self->frame->size.left -
- self->border_width;
- event.xconfigure.y = self->frame->area.y + self->frame->size.top -
- self->border_width;
- event.xconfigure.width = w;
- event.xconfigure.height = h;
- event.xconfigure.border_width = 0;
- event.xconfigure.above = self->frame->plate;
- event.xconfigure.override_redirect = FALSE;
- XSendEvent(event.xconfigure.display, event.xconfigure.window,
- FALSE, StructureNotifyMask, &event);
- }
+ frame_adjust_client_area(self->frame);
+ }
+
+ /* find the frame's dimensions and move/resize it */
+ if (self->decorations != fdecor || self->max_horz != fhorz)
+ moved = resized = TRUE;
+ if (moved || resized)
+ frame_adjust_area(self->frame, moved, resized, FALSE);
+
+ /* find the client's position relative to the root window */
+ oldrx = self->root_pos.x;
+ oldry = self->root_pos.y;
+ rootmoved = (oldrx != (signed)(self->frame->area.x +
+ self->frame->size.left -
+ self->border_width) ||
+ oldry != (signed)(self->frame->area.y +
+ self->frame->size.top -
+ self->border_width));
+
+ if (force_reply || ((!user || (user && final)) && rootmoved))
+ {
+ XEvent event;
+
+ POINT_SET(self->root_pos,
+ self->frame->area.x + self->frame->size.left -
+ self->border_width,
+ self->frame->area.y + self->frame->size.top -
+ self->border_width);
+
+ event.type = ConfigureNotify;
+ event.xconfigure.display = ob_display;
+ event.xconfigure.event = self->window;
+ event.xconfigure.window = self->window;
+
+ /* root window real coords */
+ event.xconfigure.x = self->root_pos.x;
+ event.xconfigure.y = self->root_pos.y;
+ event.xconfigure.width = w;
+ event.xconfigure.height = h;
+ event.xconfigure.border_width = 0;
+ event.xconfigure.above = self->frame->plate;
+ event.xconfigure.override_redirect = FALSE;
+ XSendEvent(event.xconfigure.display, event.xconfigure.window,
+ FALSE, StructureNotifyMask, &event);
}
/* if the client is shrinking, then resize the frame before the client */
- if (send_resize_client && (!user || (w <= oldw || h <= oldh)))
+ if (send_resize_client && (!user || (w <= oldw || h <= oldh))) {
+ frame_adjust_client_area(self->frame);
XResizeWindow(ob_display, self->window, w, h);
+ }
XFlush(ob_display);
}
/* choose the correct target */
self = client_focus_target(self);
-#if 0
- if (!client_validate(self))
- return FALSE;
-#endif
-
if (!client_can_focus(self)) {
if (!self->frame->visible) {
/* update the focus lists */
return FALSE;
}
- ob_debug("Focusing client \"%s\" at time %u\n", self->title, event_curtime);
+ ob_debug_type(OB_DEBUG_FOCUS,
+ "Focusing client \"%s\" at time %u\n",
+ self->title, event_curtime);
if (self->can_focus) {
+ /* This can cause a BadMatch error with CurrentTime, or if an app
+ passed in a bad time for _NET_WM_ACTIVE_WINDOW. */
+ xerror_set_ignore(TRUE);
XSetInputFocus(ob_display, self->window, RevertToPointerRoot,
event_curtime);
+ xerror_set_ignore(FALSE);
}
if (self->focus_notify) {
return TRUE;
}
-/* Used when the current client is closed or otherwise hidden, focus_last will
- then prevent focus from going to the mouse pointer
-*/
-static void client_unfocus(ObClient *self)
-{
- if (focus_client == self) {
-#ifdef DEBUG_FOCUS
- ob_debug("client_unfocus for %lx\n", self->window);
-#endif
- focus_fallback(FALSE);
- }
-}
-
void client_activate(ObClient *self, gboolean here, gboolean user)
{
+ guint32 last_time = focus_client ? focus_client->user_time : CurrentTime;
+
/* 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)?
*/
- ob_debug("Want to activate window 0x%x with time %u (last time %u), "
- "source=%s\n",
- self->window, event_curtime, client_last_user_time,
- (user ? "user" : "application"));
- if (!user && event_curtime &&
- !event_time_after(event_curtime, client_last_user_time))
+ ob_debug_type(OB_DEBUG_FOCUS,
+ "Want to activate window 0x%x with time %u (last time %u), "
+ "source=%s\n",
+ self->window, event_curtime, last_time,
+ (user ? "user" : "application"));
+
+ if (!user && event_curtime && last_time &&
+ !event_time_after(event_curtime, last_time))
{
client_hilite(self, TRUE);
} else {
+ if (event_curtime != CurrentTime)
+ self->user_time = event_curtime;
+
+ /* if using focus_delay, stop the timer now so that focus doesn't
+ go moving on us */
+ event_halt_focus_delay();
+
if (client_normal(self) && screen_showing_desktop)
screen_show_desktop(FALSE);
if (self->iconic)
client_focus(self);
- /* we do this an action here. this is rather important. this is because
- we want the results from the focus change to take place BEFORE we go
- about raising the window. when a fullscreen window loses focus, we
- need this or else the raise wont be able to raise above the
- to-lose-focus fullscreen window. */
+ /* we do this as an action here. this is rather important. this is
+ because we want the results from the focus change to take place
+ BEFORE we go about raising the window. when a fullscreen window
+ loses focus, we need this or else the raise wont be able to raise
+ above the to-lose-focus fullscreen window. */
client_raise(self);
}
}
return ret;
}
-/* this be mostly ripped from fvwm */
-ObClient *client_find_directional(ObClient *c, ObDirection dir)
-{
- gint my_cx, my_cy, his_cx, his_cy;
- gint offset = 0;
- gint distance = 0;
- gint score, best_score;
- ObClient *best_client, *cur;
- GList *it;
-
- if(!client_list)
- return NULL;
-
- /* first, find the centre coords of the currently focused window */
- my_cx = c->frame->area.x + c->frame->area.width / 2;
- my_cy = c->frame->area.y + c->frame->area.height / 2;
-
- best_score = -1;
- best_client = NULL;
-
- for(it = g_list_first(client_list); it; it = g_list_next(it)) {
- cur = it->data;
-
- /* the currently selected window isn't interesting */
- if(cur == c)
- continue;
- if (!client_normal(cur))
- continue;
- /* using c->desktop instead of screen_desktop doesn't work if the
- * current window was omnipresent, hope this doesn't have any other
- * side effects */
- if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL)
- continue;
- if(cur->iconic)
- continue;
- if(!(client_focus_target(cur) == cur &&
- client_can_focus(cur)))
- continue;
-
- /* find the centre coords of this window, from the
- * currently focused window's point of view */
- his_cx = (cur->frame->area.x - my_cx)
- + cur->frame->area.width / 2;
- his_cy = (cur->frame->area.y - my_cy)
- + cur->frame->area.height / 2;
-
- if(dir == OB_DIRECTION_NORTHEAST || dir == OB_DIRECTION_SOUTHEAST ||
- dir == OB_DIRECTION_SOUTHWEST || dir == OB_DIRECTION_NORTHWEST) {
- gint tx;
- /* Rotate the diagonals 45 degrees counterclockwise.
- * To do this, multiply the matrix /+h +h\ with the
- * vector (x y). \-h +h/
- * h = sqrt(0.5). We can set h := 1 since absolute
- * distance doesn't matter here. */
- tx = his_cx + his_cy;
- his_cy = -his_cx + his_cy;
- his_cx = tx;
- }
-
- switch(dir) {
- case OB_DIRECTION_NORTH:
- case OB_DIRECTION_SOUTH:
- case OB_DIRECTION_NORTHEAST:
- case OB_DIRECTION_SOUTHWEST:
- offset = (his_cx < 0) ? -his_cx : his_cx;
- distance = ((dir == OB_DIRECTION_NORTH ||
- dir == OB_DIRECTION_NORTHEAST) ?
- -his_cy : his_cy);
- break;
- case OB_DIRECTION_EAST:
- case OB_DIRECTION_WEST:
- case OB_DIRECTION_SOUTHEAST:
- case OB_DIRECTION_NORTHWEST:
- offset = (his_cy < 0) ? -his_cy : his_cy;
- distance = ((dir == OB_DIRECTION_WEST ||
- dir == OB_DIRECTION_NORTHWEST) ?
- -his_cx : his_cx);
- break;
- }
-
- /* the target must be in the requested direction */
- if(distance <= 0)
- continue;
-
- /* Calculate score for this window. The smaller the better. */
- score = distance + offset;
-
- /* windows more than 45 degrees off the direction are
- * heavily penalized and will only be chosen if nothing
- * else within a million pixels */
- if(offset > distance)
- score += 1000000;
-
- if(best_score == -1 || score < best_score)
- best_client = cur,
- best_score = score;
- }
-
- return best_client;
-}
-
void client_set_layer(ObClient *self, gint layer)
{
if (layer < 0) {
ObClient *client_search_top_parent(ObClient *self)
{
- while (self->transient_for && self->transient_for != OB_TRAN_GROUP)
+ while (self->transient_for && self->transient_for != OB_TRAN_GROUP &&
+ client_normal(self))
self = self->transient_for;
return self;
}
for (it = self->group->members; it; it = g_slist_next(it)) {
ObClient *c = it->data;
- if (!c->transient_for)
+ if (!c->transient_for && client_normal(c))
ret = g_slist_prepend(ret, c);
}