*/
#include "client.h"
-#include "client_time_heap.h"
#include "debug.h"
#include "startupnotify.h"
#include "dock.h"
#include "mouse.h"
#include "render/render.h"
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
#include <glib.h>
#include <X11/Xutil.h>
} Destructor;
GList *client_list = NULL;
-ObClientTimeHeap *client_user_times = NULL;
static GSList *client_destructors = NULL;
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_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)
{
if (reconfig) return;
- client_user_times = client_time_heap_new();
client_set_list();
}
void client_shutdown(gboolean reconfig)
{
- client_time_heap_free(client_user_times);
}
void client_add_destructor(ObClientDestructor func, gpointer data)
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_time_heap_maximum(client_user_times));
+ self->window, self->user_time, last_time);
/* If a nothing at all, or a parent was focused, then focus this
always
activate = TRUE;
else
{
- guint32 last_time = client_time_heap_maximum(client_user_times);
/* If time stamp is old, don't steal focus */
if (self->user_time && last_time &&
!event_time_after(self->user_time, last_time))
} else {
ob_debug("Focus stealing prevention activated for %s with time %u "
"(last time %u)\n",
- self->title, self->user_time,
- client_time_heap_maximum(client_user_times));
+ 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);
client_focus(self);
}
- /* client_activate does this but we aret using it so we have to do it
+ /* client_activate does this but we aren't using it so we have to do it
here as well */
if (screen_showing_desktop)
screen_show_desktop(FALSE);
g_assert(self != NULL);
- /* update the focus lists */
- focus_order_remove(self);
+ /* 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);
- if (focus_client == self) {
- XEvent e;
+ frame_hide(self->frame);
+ /* flush to send the hide to the server quickly */
+ XFlush(ob_display);
- /* 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);
+ if (focus_client == self) {
+ /* ignore enter events from the unmap so it doesnt mess with the focus
+ */
+ event_ignore_queued_enters();
}
- /* potentially fix focusLast */
- if (config_focus_last)
- grab_pointer(TRUE, OB_CURSOR_NONE);
-
- frame_hide(self->frame);
- XFlush(ob_display);
keyboard_grab_for_client(self, FALSE);
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);
-
- /* remove from the time heap */
- client_time_heap_remove(client_user_times, self);
+ /* update the focus lists */
+ focus_order_remove(self);
client_list = g_list_remove(client_list, self);
stacking_remove(self);
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)
(min/max sizes), so we're ready to set up the decorations/functions */
client_setup_decor_and_functions(self);
+ client_get_client_machine(self);
client_update_title(self);
client_update_class(self);
client_update_sm_client_id(self);
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);
guint32 time;
if (PROP_GET32(self->window, net_wm_user_time, cardinal, &time)) {
- guint32 otime = self->user_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
would be pretty stupid anyways
*/
self->user_time = time;
- /* adjust the time heap - windows with CurrentTime for their user_time
- are not in the heap */
- if (time == CurrentTime && otime != CurrentTime)
- client_time_heap_remove(client_user_times, self);
- else if (time != CurrentTime && otime == CurrentTime)
- client_time_heap_add(client_user_times, self);
- else if (time != CurrentTime && otime != CurrentTime) {
- if (event_time_after(time, otime))
- client_time_heap_increase_key(client_user_times, self);
- else
- client_time_heap_decrease_key(client_user_times, self);
- }
/*
ob_debug("window %s user time %u\n", self->title, time);
- ob_debug("last user time %u\n", client_time_heap_maximum(client_user_times));
*/
}
}
+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;
}
- 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;
+ 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
*/
ob_debug("Want to activate window 0x%x with time %u (last time %u), "
"source=%s\n",
- self->window, event_curtime,
- client_time_heap_maximum(client_user_times),
+ self->window, event_curtime, last_time,
(user ? "user" : "application"));
- last_time = client_time_heap_maximum(client_user_times);
if (!user && event_curtime && last_time &&
!event_time_after(event_curtime, last_time))
{
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) {
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);
}