get rid of global client_last_user_time variable.
add ObClientTimeHeap. This is a max-heap of the clients based on their user times. this only includes the clients whose user time is not CurrentTime. the maximum from this heap replaces the client_last_user_time variable, so that you always have the latest time, not the last time that was changed. hoefully it works, so far it seems to.
This commit is contained in:
parent
f18d9a9539
commit
90cd9c6219
5 changed files with 256 additions and 21 deletions
|
@ -137,6 +137,8 @@ openbox_openbox_SOURCES = \
|
|||
openbox/action.h \
|
||||
openbox/client.c \
|
||||
openbox/client.h \
|
||||
openbox/client_time_heap.c \
|
||||
openbox/client_time_heap.h \
|
||||
openbox/client_list_menu.c \
|
||||
openbox/client_list_menu.h \
|
||||
openbox/client_list_combined_menu.c \
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include "client.h"
|
||||
#include "client_time_heap.h"
|
||||
#include "debug.h"
|
||||
#include "startupnotify.h"
|
||||
#include "dock.h"
|
||||
|
@ -57,9 +58,9 @@ typedef struct
|
|||
} Destructor;
|
||||
|
||||
GList *client_list = NULL;
|
||||
ObClientTimeHeap *client_user_times = 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);
|
||||
|
@ -84,11 +85,13 @@ 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)
|
||||
|
@ -272,7 +275,7 @@ void client_manage(Window window)
|
|||
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 = client_last_user_time;
|
||||
self->user_time = CurrentTime;
|
||||
|
||||
client_get_all(self);
|
||||
/* per-app settings override stuff, and return the settings for other
|
||||
|
@ -405,7 +408,8 @@ void client_manage(Window window)
|
|||
if (activate) {
|
||||
/* 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,
|
||||
client_time_heap_maximum(client_user_times));
|
||||
|
||||
/* If a nothing at all, or a parent was focused, then focus this
|
||||
always
|
||||
|
@ -414,9 +418,10 @@ void client_manage(Window window)
|
|||
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 &&
|
||||
!event_time_after(self->user_time, client_last_user_time))
|
||||
if (self->user_time && last_time &&
|
||||
!event_time_after(self->user_time, last_time))
|
||||
{
|
||||
activate = FALSE;
|
||||
}
|
||||
|
@ -436,7 +441,8 @@ void client_manage(Window window)
|
|||
} else {
|
||||
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,
|
||||
client_time_heap_maximum(client_user_times));
|
||||
/* if the client isn't focused, then hilite it so the user
|
||||
knows it is there */
|
||||
client_hilite(self, TRUE);
|
||||
|
@ -538,6 +544,9 @@ void client_unmanage(ObClient *self)
|
|||
/* 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);
|
||||
|
||||
client_list = g_list_remove(client_list, self);
|
||||
stacking_remove(self);
|
||||
g_hash_table_remove(window_map, &self->window);
|
||||
|
@ -949,7 +958,7 @@ static void client_get_all(ObClient *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)
|
||||
|
@ -1852,27 +1861,35 @@ void client_update_icons(ObClient *self)
|
|||
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;
|
||||
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
|
||||
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;
|
||||
/* 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_last_user_time);
|
||||
ob_debug("last user time %u\n", client_time_heap_maximum(client_user_times));
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
@ -3067,16 +3084,21 @@ static void client_unfocus(ObClient *self)
|
|||
|
||||
void client_activate(ObClient *self, gboolean here, gboolean user)
|
||||
{
|
||||
guint32 last_time;
|
||||
|
||||
/* 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,
|
||||
self->window, event_curtime,
|
||||
client_time_heap_maximum(client_user_times),
|
||||
(user ? "user" : "application"));
|
||||
if (!user && event_curtime &&
|
||||
!event_time_after(event_curtime, client_last_user_time))
|
||||
|
||||
last_time = client_time_heap_maximum(client_user_times);
|
||||
if (!user && event_curtime && last_time &&
|
||||
!event_time_after(event_curtime, last_time))
|
||||
{
|
||||
client_hilite(self, TRUE);
|
||||
} else {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
client.h for the Openbox window manager
|
||||
Copyright (c) 2006 Mikael Magnusson
|
||||
Copyright (c) 2003 Ben Jansens
|
||||
Copyright (c) 2003-2007 Dana Jansens
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -32,6 +32,7 @@
|
|||
struct _ObFrame;
|
||||
struct _ObGroup;
|
||||
struct _ObSessionState;
|
||||
struct _ObClientTimeHeap;
|
||||
|
||||
typedef struct _ObClient ObClient;
|
||||
typedef struct _ObClientIcon ObClientIcon;
|
||||
|
@ -300,6 +301,7 @@ struct _ObAppSettings
|
|||
};
|
||||
|
||||
extern GList *client_list;
|
||||
extern struct _ObClientTimeHeap *client_user_times;
|
||||
|
||||
void client_startup(gboolean reconfig);
|
||||
void client_shutdown(gboolean reconfig);
|
||||
|
@ -559,7 +561,7 @@ void client_update_strut(ObClient *self);
|
|||
/*! Updates the window's icons */
|
||||
void client_update_icons(ObClient *self);
|
||||
/*! Updates the window's user time */
|
||||
void client_update_user_time(ObClient *self, gboolean new_event);
|
||||
void client_update_user_time(ObClient *self);
|
||||
|
||||
/*! Set up what decor should be shown on the window and what functions should
|
||||
be allowed (ObClient::decorations and ObClient::functions).
|
||||
|
|
158
openbox/client_time_heap.c
Normal file
158
openbox/client_time_heap.c
Normal file
|
@ -0,0 +1,158 @@
|
|||
/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
|
||||
|
||||
client_time_heap.c for the Openbox window manager
|
||||
Copyright (c) 2006 Mikael Magnusson
|
||||
Copyright (c) 2003-2007 Dana Jansens
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
See the COPYING file for a copy of the GNU General Public License.
|
||||
*/
|
||||
|
||||
#include "client_time_heap.h"
|
||||
#include "client.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
/* Helper functions for the heap */
|
||||
|
||||
#define isroot(n) (n == 0)
|
||||
#define parent(n) ((n-1)/2)
|
||||
#define right(n) ((n+1)*2)
|
||||
#define left(n) (right(n)-1)
|
||||
#define exists(n) (n < h->nodes->len)
|
||||
#define key(n) (((ObClient*)h->nodes->pdata[n])->user_time)
|
||||
|
||||
static inline void swap(ObClientTimeHeap *h, guint a, guint b)
|
||||
{
|
||||
gpointer c;
|
||||
|
||||
g_assert(a < h->nodes->len);
|
||||
g_assert(b < h->nodes->len);
|
||||
|
||||
c = h->nodes->pdata[a];
|
||||
h->nodes->pdata[a] = h->nodes->pdata[b];
|
||||
h->nodes->pdata[b] = c;
|
||||
}
|
||||
|
||||
static inline void heapify(ObClientTimeHeap *h, guint n)
|
||||
{
|
||||
g_assert(exists(n));
|
||||
|
||||
/* fix up the heap, move it down below keys it's smaller than */
|
||||
while ((exists(left(n)) && key(n) < key(left(n))) ||
|
||||
(exists(right(n)) && key(n) < key(right(n))))
|
||||
{
|
||||
if (exists(left(n)) && exists(right(n)))
|
||||
if (key(left(n)) > key(right(n))) {
|
||||
swap(h, n, left(n));
|
||||
n = left(n);
|
||||
} else {
|
||||
swap(h, n, right(n));
|
||||
n = right(n);
|
||||
}
|
||||
else {
|
||||
/* its impossible in this structure to have a right child but no
|
||||
left child */
|
||||
swap(h, n, left(n));
|
||||
n = left(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ObClientTimeHeap* client_time_heap_new()
|
||||
{
|
||||
ObClientTimeHeap *h = g_new0(ObClientTimeHeap, 1);
|
||||
h->nodes = g_ptr_array_new();
|
||||
return h;
|
||||
}
|
||||
|
||||
void client_time_heap_free(ObClientTimeHeap *h)
|
||||
{
|
||||
if (h != NULL) {
|
||||
/* all the clients should be removed before the heap is destroyed. */
|
||||
g_assert(h->nodes->len == 0);
|
||||
g_ptr_array_free(h->nodes, TRUE);
|
||||
g_free(h);
|
||||
}
|
||||
}
|
||||
|
||||
guint32 client_time_heap_maximum(ObClientTimeHeap *h)
|
||||
{
|
||||
if (h->nodes->len == 0)
|
||||
return CurrentTime;
|
||||
else
|
||||
return key(0);
|
||||
}
|
||||
|
||||
|
||||
void client_time_heap_add(ObClientTimeHeap *h, ObClient *c)
|
||||
{
|
||||
guint n;
|
||||
|
||||
/* insert it as the last leaf */
|
||||
g_ptr_array_add(h->nodes, c);
|
||||
n = h->nodes->len - 1;
|
||||
|
||||
/* move it up to its proper place */
|
||||
while (!isroot(n) && key(n) > key(parent(n))) {
|
||||
swap(h, n, parent(n));
|
||||
n = parent(n);
|
||||
}
|
||||
}
|
||||
|
||||
void client_time_heap_remove(ObClientTimeHeap *h, ObClient *c)
|
||||
{
|
||||
/* find the client */
|
||||
guint n;
|
||||
for (n = 0; h->nodes->pdata[n] != c && n < h->nodes->len; ++n);
|
||||
|
||||
/* if the client is in the heap */
|
||||
if (n < h->nodes->len) {
|
||||
/* move it to a leaf and delete it from the heap */
|
||||
swap(h, n, h->nodes->len-1);
|
||||
g_ptr_array_remove_index(h->nodes, h->nodes->len-1);
|
||||
|
||||
/* move the swapped leaf down to its proper place if it wasn't just
|
||||
deleted */
|
||||
if (exists(n))
|
||||
heapify(h, n);
|
||||
}
|
||||
}
|
||||
|
||||
void client_time_heap_decrease_key(ObClientTimeHeap *h, ObClient *c)
|
||||
{
|
||||
/* find the client */
|
||||
guint n;
|
||||
for (n = 0; h->nodes->pdata[n] != c && n < h->nodes->len; ++n);
|
||||
|
||||
/* if the client is in the heap */
|
||||
if (n < h->nodes->len) {
|
||||
/* move it down to its proper place */
|
||||
heapify(h, n);
|
||||
}
|
||||
}
|
||||
|
||||
void client_time_heap_increase_key(ObClientTimeHeap *h, ObClient *c)
|
||||
{
|
||||
/* find the client */
|
||||
guint n;
|
||||
for (n = 0; h->nodes->pdata[n] != c && n < h->nodes->len; ++n);
|
||||
|
||||
/* if the client is in the heap */
|
||||
if (n < h->nodes->len) {
|
||||
/* move it up to its proper place */
|
||||
while (!isroot(n) && key(n) > key(parent(n))) {
|
||||
swap(h, n, parent(n));
|
||||
n = parent(n);
|
||||
}
|
||||
}
|
||||
}
|
51
openbox/client_time_heap.h
Normal file
51
openbox/client_time_heap.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
|
||||
|
||||
client_time_heap.h for the Openbox window manager
|
||||
Copyright (c) 2006 Mikael Magnusson
|
||||
Copyright (c) 2003-2007 Dana Jansens
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
See the COPYING file for a copy of the GNU General Public License.
|
||||
*/
|
||||
|
||||
#ifndef __client_time_heap_h
|
||||
#define __client_time_heap_h
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
struct _ObClient *client;
|
||||
|
||||
typedef struct _ObClientTimeHeap ObClientTimeHeap;
|
||||
typedef struct _ObClientTimeHeapNode ObClientTimeHeapNode;
|
||||
|
||||
/*! A min-heap of the clients based on their user_time as the key */
|
||||
struct _ObClientTimeHeap
|
||||
{
|
||||
/* The nodes in the heap */
|
||||
GPtrArray *nodes;
|
||||
};
|
||||
|
||||
ObClientTimeHeap* client_time_heap_new ();
|
||||
void client_time_heap_free (ObClientTimeHeap *h);
|
||||
|
||||
guint32 client_time_heap_maximum (ObClientTimeHeap *h);
|
||||
|
||||
void client_time_heap_add (ObClientTimeHeap *h,
|
||||
struct _ObClient *c);
|
||||
void client_time_heap_remove (ObClientTimeHeap *h,
|
||||
struct _ObClient *c);
|
||||
void client_time_heap_decrease_key (ObClientTimeHeap *h,
|
||||
struct _ObClient *c);
|
||||
void client_time_heap_increase_key (ObClientTimeHeap *h,
|
||||
struct _ObClient *c);
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue