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:
Dana Jansens 2007-04-18 19:22:59 +00:00
parent f18d9a9539
commit 90cd9c6219
5 changed files with 256 additions and 21 deletions

View file

@ -137,6 +137,8 @@ openbox_openbox_SOURCES = \
openbox/action.h \ openbox/action.h \
openbox/client.c \ openbox/client.c \
openbox/client.h \ openbox/client.h \
openbox/client_time_heap.c \
openbox/client_time_heap.h \
openbox/client_list_menu.c \ openbox/client_list_menu.c \
openbox/client_list_menu.h \ openbox/client_list_menu.h \
openbox/client_list_combined_menu.c \ openbox/client_list_combined_menu.c \

View file

@ -18,6 +18,7 @@
*/ */
#include "client.h" #include "client.h"
#include "client_time_heap.h"
#include "debug.h" #include "debug.h"
#include "startupnotify.h" #include "startupnotify.h"
#include "dock.h" #include "dock.h"
@ -56,10 +57,10 @@ typedef struct
gpointer data; gpointer data;
} Destructor; } Destructor;
GList *client_list = NULL; GList *client_list = NULL;
ObClientTimeHeap *client_user_times = NULL;
static GSList *client_destructors = NULL; static GSList *client_destructors = NULL;
static Time client_last_user_time = CurrentTime;
static void client_get_all(ObClient *self); static void client_get_all(ObClient *self);
static void client_toggle_border(ObClient *self, gboolean show); static void client_toggle_border(ObClient *self, gboolean show);
@ -84,11 +85,13 @@ void client_startup(gboolean reconfig)
{ {
if (reconfig) return; if (reconfig) return;
client_user_times = client_time_heap_new();
client_set_list(); client_set_list();
} }
void client_shutdown(gboolean reconfig) void client_shutdown(gboolean reconfig)
{ {
client_time_heap_free(client_user_times);
} }
void client_add_destructor(ObClientDestructor func, gpointer data) 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->wmstate = WithdrawnState; /* make sure it gets updated first time */
self->layer = -1; self->layer = -1;
self->desktop = screen_num_desktops; /* always an invalid value */ self->desktop = screen_num_desktops; /* always an invalid value */
self->user_time = client_last_user_time; self->user_time = CurrentTime;
client_get_all(self); client_get_all(self);
/* per-app settings override stuff, and return the settings for other /* per-app settings override stuff, and return the settings for other
@ -405,7 +408,8 @@ void client_manage(Window window)
if (activate) { if (activate) {
/* This is focus stealing prevention */ /* This is focus stealing prevention */
ob_debug("Want to focus new window 0x%x with time %u (last time %u)\n", 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 /* If a nothing at all, or a parent was focused, then focus this
always always
@ -414,9 +418,10 @@ void client_manage(Window window)
activate = TRUE; activate = TRUE;
else else
{ {
guint32 last_time = client_time_heap_maximum(client_user_times);
/* If time stamp is old, don't steal focus */ /* If time stamp is old, don't steal focus */
if (self->user_time && if (self->user_time && last_time &&
!event_time_after(self->user_time, client_last_user_time)) !event_time_after(self->user_time, last_time))
{ {
activate = FALSE; activate = FALSE;
} }
@ -436,7 +441,8 @@ void client_manage(Window window)
} else { } else {
ob_debug("Focus stealing prevention activated for %s with time %u " ob_debug("Focus stealing prevention activated for %s with time %u "
"(last time %u)\n", "(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 /* if the client isn't focused, then hilite it so the user
knows it is there */ knows it is there */
client_hilite(self, TRUE); client_hilite(self, TRUE);
@ -538,6 +544,9 @@ void client_unmanage(ObClient *self)
/* we dont want events no more */ /* we dont want events no more */
XSelectInput(ob_display, self->window, NoEventMask); 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); client_list = g_list_remove(client_list, self);
stacking_remove(self); stacking_remove(self);
g_hash_table_remove(window_map, &self->window); 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_sm_client_id(self);
client_update_strut(self); client_update_strut(self);
client_update_icons(self); client_update_icons(self);
client_update_user_time(self, FALSE); client_update_user_time(self);
} }
static void client_get_startup_id(ObClient *self) static void client_get_startup_id(ObClient *self)
@ -1852,27 +1861,35 @@ void client_update_icons(ObClient *self)
frame_adjust_icon(self->frame); frame_adjust_icon(self->frame);
} }
void client_update_user_time(ObClient *self, gboolean new_event) void client_update_user_time(ObClient *self)
{ {
guint32 time; guint32 time;
if (PROP_GET32(self->window, net_wm_user_time, cardinal, &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 /* we set this every time, not just when it grows, because in practice
sometimes time goes backwards! (ntpdate.. yay....) so.. if it goes sometimes time goes backwards! (ntpdate.. yay....) so.. if it goes
backward we don't want all windows to stop focusing. we'll just 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 assume noone is setting times older than the last one, cuz that
would be pretty stupid anyways 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) self->user_time = time;
client_last_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("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) 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 /* 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 to activate it or not (a parent or group member is currently
active)? active)?
*/ */
ob_debug("Want to activate window 0x%x with time %u (last time %u), " ob_debug("Want to activate window 0x%x with time %u (last time %u), "
"source=%s\n", "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")); (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); client_hilite(self, TRUE);
} else { } else {

View file

@ -2,7 +2,7 @@
client.h for the Openbox window manager client.h for the Openbox window manager
Copyright (c) 2006 Mikael Magnusson 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 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 it under the terms of the GNU General Public License as published by
@ -32,6 +32,7 @@
struct _ObFrame; struct _ObFrame;
struct _ObGroup; struct _ObGroup;
struct _ObSessionState; struct _ObSessionState;
struct _ObClientTimeHeap;
typedef struct _ObClient ObClient; typedef struct _ObClient ObClient;
typedef struct _ObClientIcon ObClientIcon; typedef struct _ObClientIcon ObClientIcon;
@ -300,6 +301,7 @@ struct _ObAppSettings
}; };
extern GList *client_list; extern GList *client_list;
extern struct _ObClientTimeHeap *client_user_times;
void client_startup(gboolean reconfig); void client_startup(gboolean reconfig);
void client_shutdown(gboolean reconfig); void client_shutdown(gboolean reconfig);
@ -559,7 +561,7 @@ void client_update_strut(ObClient *self);
/*! Updates the window's icons */ /*! Updates the window's icons */
void client_update_icons(ObClient *self); void client_update_icons(ObClient *self);
/*! Updates the window's user time */ /*! 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 /*! Set up what decor should be shown on the window and what functions should
be allowed (ObClient::decorations and ObClient::functions). be allowed (ObClient::decorations and ObClient::functions).

158
openbox/client_time_heap.c Normal file
View 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);
}
}
}

View 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