This function never returns CurrentTime, which is nice, cuz using CurrentTime for XSetFocus always sucks.
If the current XEvent did not have a timestamp, then event_time() will find one. It finds the first timestamp available in the X event queue, meaning the earliest timestamp >= the current (nontimestamped) event. All future events should have a timestamp >= event_time(), so using this in XSetFocus() should not mess up any future calls we make to it.
This change seems to work well, as it appears to fix bug #3648.
ob_debug("Managing window: 0x%lx", window);
- /* we want to always have a valid time when the window is mapping */
- g_assert(event_curtime != CurrentTime);
-
/* choose the events we want to receive on the CLIENT window
(ObPrompt windows can request events too) */
attrib_set.event_mask = CLIENT_EVENTMASK |
launch_time = sn_app_started(self->startup_id, self->class, self->name);
if (!OBT_PROP_GET32(self->window, NET_WM_USER_TIME, CARDINAL, &user_time))
- user_time = event_curtime;
+ user_time = event_time();
/* do this after we have a frame.. it uses the frame to help determine the
WM_STATE to apply. */
ob_debug_type(OB_DEBUG_FOCUS, "Going to try activate new window? %s",
activate ? "yes" : "no");
if (activate) {
- activate = client_can_steal_focus(self, event_curtime, launch_time);
+ activate = client_can_steal_focus(self, event_time(), launch_time);
if (!activate) {
/* if the client isn't stealing focus, then hilite it so the user
else {
/* request the client to close with WM_DELETE_WINDOW */
OBT_PROP_MSG_TO(self->window, self->window, WM_PROTOCOLS,
- OBT_PROP_ATOM(WM_DELETE_WINDOW), event_curtime,
+ OBT_PROP_ATOM(WM_DELETE_WINDOW), event_time(),
0, 0, 0, NoEventMask);
/* we're trying to close the window, so see if it is responding. if it
ob_debug_type(OB_DEBUG_FOCUS,
"Focusing client \"%s\" (0x%x) at time %u",
- self->title, self->window, event_curtime);
+ self->title, self->window, event_time());
/* if using focus_delay, stop the timer now so that focus doesn't
go moving on us */
/* This can cause a BadMatch error with CurrentTime, or if an app
passed in a bad time for _NET_WM_ACTIVE_WINDOW. */
XSetInputFocus(obt_display, self->window, RevertToPointerRoot,
- event_curtime);
+ event_time());
}
if (self->focus_notify) {
ce.xclient.window = self->window;
ce.xclient.format = 32;
ce.xclient.data.l[0] = OBT_PROP_ATOM(WM_TAKE_FOCUS);
- ce.xclient.data.l[1] = event_curtime;
+ ce.xclient.data.l[1] = event_time();
ce.xclient.data.l[2] = 0l;
ce.xclient.data.l[3] = 0l;
ce.xclient.data.l[4] = 0l;
if ((user && (desktop ||
self->desktop == DESKTOP_ALL ||
self->desktop == screen_desktop)) ||
- client_can_steal_focus(self, event_curtime, CurrentTime))
+ client_can_steal_focus(self, event_time(), CurrentTime))
{
client_present(self, here, raise, unshade);
}
static gboolean unfocus_delay_func(gpointer data);
static void focus_delay_client_dest(ObClient *client, gpointer data);
-Time event_curtime = CurrentTime;
-Time event_last_user_time = CurrentTime;
-/*! The serial of the current X event */
+Time event_last_user_time;
+
+/*! The time of the current X event (if it had a timestamp) */
+static Time event_curtime;
+/*! The source time that started the current X event (user-provided, so not
+ to be trusted) */
+static Time event_sourcetime;
+/*! The serial of the current X event */
static gulong event_curserial;
static gboolean focus_left_screen = FALSE;
/*! A list of ObSerialRanges which are to be ignored for mouse enter events */
client_add_destroy_notify(focus_delay_client_dest, NULL);
- /* get an initial time for event_curtime (mapping the initial windows needs
- a timestamp) */
- event_curtime = event_get_server_time();
+ event_curtime = CurrentTime;
+ event_sourcetime = CurrentTime;
+ event_last_user_time = CurrentTime;
}
void event_shutdown(gboolean reconfig)
return window;
}
-static inline Time event_time(const XEvent *e)
+static inline Time event_get_timestamp(const XEvent *e)
{
Time t = CurrentTime;
static void event_set_curtime(XEvent *e)
{
- Time t = event_time(e);
-
- if (t == CurrentTime) {
- /* Some events don't come with timestamps :(
- ...but we want the time anyways. */
- if (e->type == MapRequest)
- t = event_get_server_time();
- }
+ Time t = event_get_timestamp(e);
/* watch that if we get an event earlier than the last specified user_time,
which can happen if the clock goes backwards, we erase the last
if (t && event_last_user_time && event_time_after(event_last_user_time, t))
event_last_user_time = CurrentTime;
+ event_sourcetime = CurrentTime;
event_curtime = t;
}
/* if something happens and it's not from an XEvent, then we don't know
the time */
- event_curtime = CurrentTime;
+ event_curtime = event_sourcetime = CurrentTime;
event_curserial = 0;
}
if (msgtype == OBT_PROP_ATOM(NET_CURRENT_DESKTOP)) {
guint d = e->xclient.data.l[0];
if (d < screen_num_desktops) {
- event_curtime = e->xclient.data.l[1];
- if (event_curtime == 0)
+ if (e->xclient.data.l[1] == 0)
ob_debug_type(OB_DEBUG_APP_BUGS,
"_NET_CURRENT_DESKTOP message is missing "
"a timestamp");
+ else
+ event_sourcetime = e->xclient.data.l[1];
screen_set_desktop(d, TRUE);
}
} else if (msgtype == OBT_PROP_ATOM(NET_NUMBER_OF_DESKTOPS)) {
data = g_slice_new(ObFocusDelayData);
data->client = client;
- data->time = event_curtime;
+ data->time = event_time();
data->serial = event_curserial;
obt_main_loop_timeout_add(ob_main_loop,
} else {
ObFocusDelayData data;
data.client = client;
- data.time = event_curtime;
+ data.time = event_time();
data.serial = event_curserial;
focus_delay_func(&data);
}
data = g_slice_new(ObFocusDelayData);
data->client = client;
- data->time = event_curtime;
+ data->time = event_time();
data->serial = event_curserial;
obt_main_loop_timeout_add(ob_main_loop,
} else {
ObFocusDelayData data;
data.client = client;
- data.time = event_curtime;
+ data.time = event_time();
data.serial = event_curserial;
unfocus_delay_func(&data);
}
so do not use this timestamp in event_curtime, as this would
be used in XSetInputFocus.
*/
- /*event_curtime = e->xclient.data.l[1];*/
+ event_sourcetime = e->xclient.data.l[1];
if (e->xclient.data.l[1] == 0)
ob_debug_type(OB_DEBUG_APP_BUGS,
"_NET_ACTIVE_WINDOW message for window %s is"
" missing a timestamp", client->title);
-
- event_curtime = event_get_server_time();
} else
ob_debug_type(OB_DEBUG_APP_BUGS,
"_NET_ACTIVE_WINDOW message for window %s is "
static gboolean focus_delay_func(gpointer data)
{
ObFocusDelayData *d = data;
- Time old = event_curtime;
+ Time old = event_curtime; /* save the curtime */
event_curtime = d->time;
event_curserial = d->serial;
static gboolean unfocus_delay_func(gpointer data)
{
ObFocusDelayData *d = data;
- Time old = event_curtime;
+ Time old = event_curtime; /* save the curtime */
event_curtime = d->time;
event_curserial = d->serial;
Bool find_timestamp(Display *d, XEvent *e, XPointer a)
{
- const Time t = event_time(e);
+ const Time t = event_get_timestamp(e);
return t != CurrentTime;
}
-Time event_get_server_time(void)
+Time event_time(void)
{
XEvent event;
+ if (event_curtime) return event_curtime;
+
+ /* Some events don't come with timestamps :(
+ ...but we can get one anyways >:) */
+
/* Generate a timestamp so there is guaranteed at least one in the queue
eventually */
XChangeProperty(obt_display, screen_support_win,
/* Grab the first timestamp available */
XPeekIfEvent(obt_display, &event, find_timestamp, NULL);
- return event.xproperty.time;
+ /* Save the time so we don't have to do this again for this event */
+ return event_curtime = event.xproperty.time;
+}
+
+Time event_source_time(void)
+{
+ return event_sourcetime;
}
to determine if the user is working in another window */
#define OB_EVENT_USER_TIME_DELAY (500) /* 0.5 seconds */
-/*! Time at which the last event with a timestamp occured. */
-extern Time event_curtime;
/*! The last user-interaction time, as given by the clients */
extern Time event_last_user_time;
comes at the same time or later than t2. */
gboolean event_time_after(guint32 t1, guint32 t2);
-Time event_get_server_time(void);
+/*! Time at which the current event occured. If this is not known, this
+ is a time at or after it, but at or before any other events we will process
+*/
+Time event_time(void);
+/*! A time at which an event happened that caused this current event to be
+ generated. This is a user-provided time and not to be trusted.
+ Returns CurrentTime if there was no source time provided.
+ */
+Time event_source_time(void);
#endif
/* when nothing will be focused, send focus to the backup target */
XSetInputFocus(obt_display, screen_support_win, RevertToPointerRoot,
- event_curtime);
+ event_time());
}
void focus_order_add_new(ObClient *c)
static Time ungrab_time(void)
{
- Time t = event_curtime;
+ Time t = event_time();
if (grab_time == CurrentTime ||
!(t == CurrentTime || event_time_after(t, grab_time)))
/* When the time moves backward on the server, then we can't use
if (kgrabs++ == 0) {
ret = XGrabKeyboard(obt_display, grab_window(),
False, GrabModeAsync, GrabModeAsync,
- event_curtime) == Success;
+ event_time()) == Success;
if (!ret)
--kgrabs;
else {
passive_count = 0;
- grab_time = event_curtime;
+ grab_time = event_time();
}
} else
ret = TRUE;
GRAB_PTR_MASK,
GrabModeAsync, GrabModeAsync,
(confine ? obt_root(ob_screen) : None),
- ob_cursor(cur), event_curtime) == Success;
+ ob_cursor(cur), event_time()) == Success;
if (!ret)
--pgrabs;
else
- grab_time = event_curtime;
+ grab_time = event_time();
} else
ret = TRUE;
} else if (pgrabs > 0) {
/*ob_debug("ungrabbing %d passive grabs\n", passive_count);*/
if (passive_count) {
/* kill our passive grab */
- XUngrabKeyboard(obt_display, event_curtime);
+ XUngrabKeyboard(obt_display, event_time());
passive_count = 0;
}
}
{
if (replay_pointer_needed) {
/* replay the pointer event before any windows move */
- XAllowEvents(obt_display, ReplayPointer, event_curtime);
+ XAllowEvents(obt_display, ReplayPointer, event_time());
replay_pointer_needed = FALSE;
}
}
ce.xclient.window = moveresize_client->window;
ce.xclient.format = 32;
ce.xclient.data.l[0] = OBT_PROP_ATOM(NET_WM_SYNC_REQUEST);
- ce.xclient.data.l[1] = event_curtime;
+ ce.xclient.data.l[1] = event_time();
ce.xclient.data.l[2] = XSyncValueLow32(val);
ce.xclient.data.l[3] = XSyncValueHigh32(val);
ce.xclient.data.l[4] = 0l;
/* activate the prompt */
OBT_PROP_MSG(ob_screen, self->super.window, NET_ACTIVE_WINDOW,
1, /* from an application.. */
- event_curtime,
+ event_time(),
0,
0, 0);
return;
current_wm_sn_owner = None;
}
- timestamp = event_get_server_time();
+ timestamp = event_time();
XSetSelectionOwner(obt_display, wm_sn_atom, screen_support_win,
timestamp);
event_end_ignore_all_enters(ignore_start);
- if (event_curtime != CurrentTime)
- screen_desktop_user_time = event_curtime;
+ if (event_source_time() != CurrentTime)
+ screen_desktop_user_time = event_source_time();
}
void screen_add_desktop(gboolean current)
if (desktop >= 0 && (unsigned) desktop < screen_num_desktops)
sn_launcher_context_set_workspace(sn_launcher, (signed) desktop);
sn_launcher_context_initiate(sn_launcher, "openbox", program,
- event_curtime);
+ event_time());
id = sn_launcher_context_get_startup_id(sn_launcher);
/* 20 second timeout for apps to start */