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/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 \
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
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