2003-09-17 07:44:49 +00:00
|
|
|
/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
|
2003-09-17 07:32:52 +00:00
|
|
|
|
2004-03-21 11:57:31 +00:00
|
|
|
event.c for the Openbox window manager
|
2006-08-22 16:37:35 +00:00
|
|
|
Copyright (c) 2006 Mikael Magnusson
|
2004-03-21 11:57:31 +00:00
|
|
|
Copyright (c) 2003 Ben Jansens
|
2003-09-17 07:32:52 +00:00
|
|
|
|
2004-03-21 11:57:31 +00:00
|
|
|
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.
|
2003-09-17 07:32:52 +00:00
|
|
|
|
2004-03-21 11:57:31 +00:00
|
|
|
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.
|
2003-09-17 07:32:52 +00:00
|
|
|
|
2004-03-21 11:57:31 +00:00
|
|
|
See the COPYING file for a copy of the GNU General Public License.
|
2003-09-17 07:32:52 +00:00
|
|
|
*/
|
|
|
|
|
2003-09-21 20:17:23 +00:00
|
|
|
#include "event.h"
|
2003-07-24 06:02:38 +00:00
|
|
|
#include "debug.h"
|
2003-09-21 20:17:23 +00:00
|
|
|
#include "window.h"
|
2003-03-16 21:11:39 +00:00
|
|
|
#include "openbox.h"
|
2003-05-16 18:10:10 +00:00
|
|
|
#include "dock.h"
|
2003-03-16 21:11:39 +00:00
|
|
|
#include "client.h"
|
|
|
|
#include "xerror.h"
|
|
|
|
#include "prop.h"
|
2003-04-08 07:31:26 +00:00
|
|
|
#include "config.h"
|
2003-03-16 21:11:39 +00:00
|
|
|
#include "screen.h"
|
|
|
|
#include "frame.h"
|
2003-04-16 05:36:51 +00:00
|
|
|
#include "menu.h"
|
2003-08-28 02:10:23 +00:00
|
|
|
#include "menuframe.h"
|
2003-08-12 07:26:16 +00:00
|
|
|
#include "keyboard.h"
|
|
|
|
#include "mouse.h"
|
2003-08-30 07:20:16 +00:00
|
|
|
#include "mainloop.h"
|
2003-04-13 07:18:28 +00:00
|
|
|
#include "framerender.h"
|
2003-03-16 21:11:39 +00:00
|
|
|
#include "focus.h"
|
2003-04-17 05:28:35 +00:00
|
|
|
#include "moveresize.h"
|
2003-09-15 06:50:13 +00:00
|
|
|
#include "group.h"
|
2003-03-16 21:11:39 +00:00
|
|
|
#include "stacking.h"
|
|
|
|
#include "extensions.h"
|
|
|
|
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include <X11/keysym.h>
|
|
|
|
#include <X11/Xatom.h>
|
2003-05-14 03:34:29 +00:00
|
|
|
#include <glib.h>
|
|
|
|
|
2003-03-21 20:25:34 +00:00
|
|
|
#ifdef HAVE_SYS_SELECT_H
|
|
|
|
# include <sys/select.h>
|
|
|
|
#endif
|
2003-06-21 05:31:54 +00:00
|
|
|
#ifdef HAVE_SIGNAL_H
|
|
|
|
# include <signal.h>
|
|
|
|
#endif
|
2005-01-06 18:50:01 +00:00
|
|
|
#ifdef XKB
|
|
|
|
# include <X11/XKBlib.h>
|
|
|
|
#endif
|
2003-06-21 05:31:54 +00:00
|
|
|
|
2003-06-21 08:45:25 +00:00
|
|
|
#ifdef USE_SM
|
2003-06-21 05:31:54 +00:00
|
|
|
#include <X11/ICE/ICElib.h>
|
2003-06-21 08:45:25 +00:00
|
|
|
#endif
|
2003-03-16 21:11:39 +00:00
|
|
|
|
2004-03-18 11:54:15 +00:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
gboolean ignored;
|
|
|
|
} ObEventData;
|
|
|
|
|
2007-04-22 02:34:05 +00:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
ObClient *client;
|
|
|
|
Time time;
|
|
|
|
} ObFocusDelayData;
|
|
|
|
|
2003-08-30 07:20:16 +00:00
|
|
|
static void event_process(const XEvent *e, gpointer data);
|
2003-03-16 21:11:39 +00:00
|
|
|
static void event_handle_root(XEvent *e);
|
2003-08-28 02:10:23 +00:00
|
|
|
static void event_handle_menu(XEvent *e);
|
2003-07-10 16:29:40 +00:00
|
|
|
static void event_handle_dock(ObDock *s, XEvent *e);
|
|
|
|
static void event_handle_dockapp(ObDockApp *app, XEvent *e);
|
2003-07-10 06:38:42 +00:00
|
|
|
static void event_handle_client(ObClient *c, XEvent *e);
|
2003-09-15 06:50:13 +00:00
|
|
|
static void event_handle_group(ObGroup *g, XEvent *e);
|
2003-03-16 21:11:39 +00:00
|
|
|
|
2007-04-22 04:16:00 +00:00
|
|
|
static void focus_delay_dest(gpointer data);
|
|
|
|
static gboolean focus_delay_cmp(gconstpointer d1, gconstpointer d2);
|
2003-09-03 08:12:07 +00:00
|
|
|
static gboolean focus_delay_func(gpointer data);
|
2003-09-28 06:31:00 +00:00
|
|
|
static void focus_delay_client_dest(ObClient *client, gpointer data);
|
2003-09-03 08:12:07 +00:00
|
|
|
|
2003-09-10 19:37:52 +00:00
|
|
|
static gboolean menu_hide_delay_func(gpointer data);
|
|
|
|
|
2007-03-12 23:23:39 +00:00
|
|
|
/* The time for the current event being processed */
|
2007-03-02 02:23:00 +00:00
|
|
|
Time event_curtime = CurrentTime;
|
2003-03-16 21:11:39 +00:00
|
|
|
|
|
|
|
/*! The value of the mask for the NumLock modifier */
|
2003-10-15 03:59:35 +00:00
|
|
|
guint NumLockMask;
|
2003-03-16 21:11:39 +00:00
|
|
|
/*! The value of the mask for the ScrollLock modifier */
|
2003-10-15 03:59:35 +00:00
|
|
|
guint ScrollLockMask;
|
2003-03-16 21:11:39 +00:00
|
|
|
/*! The key codes for the modifier keys */
|
|
|
|
static XModifierKeymap *modmap;
|
|
|
|
/*! Table of the constant modifier masks */
|
2003-10-15 03:59:35 +00:00
|
|
|
static const gint mask_table[] = {
|
2003-03-16 21:11:39 +00:00
|
|
|
ShiftMask, LockMask, ControlMask, Mod1Mask,
|
|
|
|
Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
|
|
|
|
};
|
2003-10-15 03:59:35 +00:00
|
|
|
static gint mask_table_size;
|
2003-03-16 21:11:39 +00:00
|
|
|
|
2003-09-21 18:10:39 +00:00
|
|
|
static guint ignore_enter_focus = 0;
|
2003-09-03 15:39:27 +00:00
|
|
|
|
2003-09-10 19:37:52 +00:00
|
|
|
static gboolean menu_can_hide;
|
|
|
|
|
2003-06-21 08:45:25 +00:00
|
|
|
#ifdef USE_SM
|
2003-10-15 03:59:35 +00:00
|
|
|
static void ice_handler(gint fd, gpointer conn)
|
2003-08-30 07:20:16 +00:00
|
|
|
{
|
|
|
|
Bool b;
|
|
|
|
IceProcessMessages(conn, NULL, &b);
|
|
|
|
}
|
2003-06-21 05:31:54 +00:00
|
|
|
|
|
|
|
static void ice_watch(IceConn conn, IcePointer data, Bool opening,
|
|
|
|
IcePointer *watch_data)
|
|
|
|
{
|
2003-08-30 07:20:16 +00:00
|
|
|
static gint fd = -1;
|
|
|
|
|
2003-06-21 05:31:54 +00:00
|
|
|
if (opening) {
|
2003-08-30 07:20:16 +00:00
|
|
|
fd = IceConnectionNumber(conn);
|
|
|
|
ob_main_loop_fd_add(ob_main_loop, fd, ice_handler, conn, NULL);
|
2003-06-21 05:31:54 +00:00
|
|
|
} else {
|
2003-08-30 07:20:16 +00:00
|
|
|
ob_main_loop_fd_remove(ob_main_loop, fd);
|
|
|
|
fd = -1;
|
2003-06-21 05:31:54 +00:00
|
|
|
}
|
|
|
|
}
|
2003-06-21 08:45:25 +00:00
|
|
|
#endif
|
2003-05-14 03:34:29 +00:00
|
|
|
|
2003-09-03 18:11:39 +00:00
|
|
|
void event_startup(gboolean reconfig)
|
2003-03-16 21:11:39 +00:00
|
|
|
{
|
2003-09-03 18:11:39 +00:00
|
|
|
if (reconfig) return;
|
|
|
|
|
2003-03-16 21:11:39 +00:00
|
|
|
mask_table_size = sizeof(mask_table) / sizeof(mask_table[0]);
|
|
|
|
|
|
|
|
/* get lock masks that are defined by the display (not constant) */
|
|
|
|
modmap = XGetModifierMapping(ob_display);
|
|
|
|
g_assert(modmap);
|
|
|
|
if (modmap && modmap->max_keypermod > 0) {
|
2003-10-03 07:07:57 +00:00
|
|
|
size_t cnt;
|
|
|
|
const size_t size = mask_table_size * modmap->max_keypermod;
|
|
|
|
/* get the values of the keyboard lock modifiers
|
|
|
|
Note: Caps lock is not retrieved the same way as Scroll and Num
|
|
|
|
lock since it doesn't need to be. */
|
|
|
|
const KeyCode num_lock = XKeysymToKeycode(ob_display, XK_Num_Lock);
|
|
|
|
const KeyCode scroll_lock = XKeysymToKeycode(ob_display,
|
|
|
|
XK_Scroll_Lock);
|
2004-03-20 15:48:38 +00:00
|
|
|
|
2003-10-03 07:07:57 +00:00
|
|
|
for (cnt = 0; cnt < size; ++cnt) {
|
|
|
|
if (! modmap->modifiermap[cnt]) continue;
|
2004-03-20 15:48:38 +00:00
|
|
|
|
2003-10-03 07:07:57 +00:00
|
|
|
if (num_lock == modmap->modifiermap[cnt])
|
|
|
|
NumLockMask = mask_table[cnt / modmap->max_keypermod];
|
|
|
|
if (scroll_lock == modmap->modifiermap[cnt])
|
|
|
|
ScrollLockMask = mask_table[cnt / modmap->max_keypermod];
|
|
|
|
}
|
2003-03-16 21:11:39 +00:00
|
|
|
}
|
2003-05-14 03:34:29 +00:00
|
|
|
|
2004-03-18 11:54:15 +00:00
|
|
|
ob_main_loop_x_add(ob_main_loop, event_process, NULL, NULL);
|
2003-06-21 05:31:54 +00:00
|
|
|
|
2003-06-21 08:45:25 +00:00
|
|
|
#ifdef USE_SM
|
2003-06-21 05:31:54 +00:00
|
|
|
IceAddConnectionWatch(ice_watch, NULL);
|
2003-06-21 08:45:25 +00:00
|
|
|
#endif
|
2003-06-21 05:31:54 +00:00
|
|
|
|
2003-09-28 06:31:00 +00:00
|
|
|
client_add_destructor(focus_delay_client_dest, NULL);
|
2003-03-16 21:11:39 +00:00
|
|
|
}
|
|
|
|
|
2003-09-03 18:11:39 +00:00
|
|
|
void event_shutdown(gboolean reconfig)
|
2003-03-16 21:11:39 +00:00
|
|
|
{
|
2003-09-03 18:11:39 +00:00
|
|
|
if (reconfig) return;
|
|
|
|
|
2003-09-14 20:57:14 +00:00
|
|
|
#ifdef USE_SM
|
|
|
|
IceRemoveConnectionWatch(ice_watch, NULL);
|
|
|
|
#endif
|
|
|
|
|
2003-09-03 08:12:07 +00:00
|
|
|
client_remove_destructor(focus_delay_client_dest);
|
2003-03-16 21:11:39 +00:00
|
|
|
XFreeModifiermap(modmap);
|
|
|
|
}
|
|
|
|
|
2003-04-14 17:07:04 +00:00
|
|
|
static Window event_get_window(XEvent *e)
|
2003-03-16 21:11:39 +00:00
|
|
|
{
|
|
|
|
Window window;
|
|
|
|
|
|
|
|
/* pick a window */
|
|
|
|
switch (e->type) {
|
2003-07-22 18:09:41 +00:00
|
|
|
case SelectionClear:
|
|
|
|
window = RootWindow(ob_display, ob_screen);
|
|
|
|
break;
|
2003-03-23 19:39:20 +00:00
|
|
|
case MapRequest:
|
2003-10-03 07:07:57 +00:00
|
|
|
window = e->xmap.window;
|
|
|
|
break;
|
2003-03-16 21:11:39 +00:00
|
|
|
case UnmapNotify:
|
2003-10-03 07:07:57 +00:00
|
|
|
window = e->xunmap.window;
|
|
|
|
break;
|
2003-03-16 21:11:39 +00:00
|
|
|
case DestroyNotify:
|
2003-10-03 07:07:57 +00:00
|
|
|
window = e->xdestroywindow.window;
|
|
|
|
break;
|
2003-03-16 21:11:39 +00:00
|
|
|
case ConfigureRequest:
|
2003-10-03 07:07:57 +00:00
|
|
|
window = e->xconfigurerequest.window;
|
|
|
|
break;
|
2003-05-09 16:57:17 +00:00
|
|
|
case ConfigureNotify:
|
|
|
|
window = e->xconfigure.window;
|
|
|
|
break;
|
2003-03-16 21:11:39 +00:00
|
|
|
default:
|
2003-03-24 19:07:28 +00:00
|
|
|
#ifdef XKB
|
2003-10-03 07:07:57 +00:00
|
|
|
if (extensions_xkb && e->type == extensions_xkb_event_basep) {
|
|
|
|
switch (((XkbAnyEvent*)e)->xkb_type) {
|
|
|
|
case XkbBellNotify:
|
|
|
|
window = ((XkbBellNotifyEvent*)e)->window;
|
|
|
|
default:
|
|
|
|
window = None;
|
|
|
|
}
|
2003-03-24 19:07:28 +00:00
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
window = e->xany.window;
|
2003-03-16 21:11:39 +00:00
|
|
|
}
|
2003-04-14 17:07:04 +00:00
|
|
|
return window;
|
|
|
|
}
|
2003-03-28 11:05:38 +00:00
|
|
|
|
2007-03-12 23:23:39 +00:00
|
|
|
static void event_set_curtime(XEvent *e)
|
2003-04-14 17:07:04 +00:00
|
|
|
{
|
2007-03-12 23:23:39 +00:00
|
|
|
Time t = CurrentTime;
|
2003-08-12 04:06:30 +00:00
|
|
|
|
2003-03-16 21:11:39 +00:00
|
|
|
/* grab the lasttime and hack up the state */
|
|
|
|
switch (e->type) {
|
|
|
|
case ButtonPress:
|
|
|
|
case ButtonRelease:
|
2003-10-03 07:07:57 +00:00
|
|
|
t = e->xbutton.time;
|
|
|
|
break;
|
2003-03-16 21:11:39 +00:00
|
|
|
case KeyPress:
|
2003-10-03 07:07:57 +00:00
|
|
|
t = e->xkey.time;
|
|
|
|
break;
|
2003-03-16 21:11:39 +00:00
|
|
|
case KeyRelease:
|
2003-10-03 07:07:57 +00:00
|
|
|
t = e->xkey.time;
|
|
|
|
break;
|
2003-04-14 17:07:04 +00:00
|
|
|
case MotionNotify:
|
2003-10-03 07:07:57 +00:00
|
|
|
t = e->xmotion.time;
|
|
|
|
break;
|
2003-04-14 17:07:04 +00:00
|
|
|
case PropertyNotify:
|
2003-10-03 07:07:57 +00:00
|
|
|
t = e->xproperty.time;
|
|
|
|
break;
|
2003-04-14 17:07:04 +00:00
|
|
|
case EnterNotify:
|
|
|
|
case LeaveNotify:
|
2003-10-03 07:07:57 +00:00
|
|
|
t = e->xcrossing.time;
|
|
|
|
break;
|
2003-04-14 17:07:04 +00:00
|
|
|
default:
|
2003-08-12 04:06:30 +00:00
|
|
|
/* if more event types are anticipated, get their timestamp
|
|
|
|
explicitly */
|
2003-04-14 17:07:04 +00:00
|
|
|
break;
|
|
|
|
}
|
2003-08-12 04:06:30 +00:00
|
|
|
|
2007-03-12 23:23:39 +00:00
|
|
|
event_curtime = t;
|
2003-04-14 17:07:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define STRIP_MODS(s) \
|
2004-03-21 01:03:00 +00:00
|
|
|
s &= ~(LockMask | NumLockMask | ScrollLockMask), \
|
|
|
|
/* kill off the Button1Mask etc, only want the modifiers */ \
|
|
|
|
s &= (ControlMask | ShiftMask | Mod1Mask | \
|
2003-04-14 17:07:04 +00:00
|
|
|
Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \
|
|
|
|
|
|
|
|
static void event_hack_mods(XEvent *e)
|
|
|
|
{
|
2005-01-06 18:50:01 +00:00
|
|
|
#ifdef XKB
|
|
|
|
XkbStateRec xkb_state;
|
|
|
|
#endif
|
2003-04-14 17:07:04 +00:00
|
|
|
KeyCode *kp;
|
2003-10-15 03:59:35 +00:00
|
|
|
gint i, k;
|
2003-04-14 17:07:04 +00:00
|
|
|
|
|
|
|
switch (e->type) {
|
|
|
|
case ButtonPress:
|
|
|
|
case ButtonRelease:
|
|
|
|
STRIP_MODS(e->xbutton.state);
|
2003-10-03 07:07:57 +00:00
|
|
|
break;
|
2003-04-14 17:07:04 +00:00
|
|
|
case KeyPress:
|
|
|
|
STRIP_MODS(e->xkey.state);
|
2003-10-03 07:07:57 +00:00
|
|
|
break;
|
2003-04-14 17:07:04 +00:00
|
|
|
case KeyRelease:
|
|
|
|
STRIP_MODS(e->xkey.state);
|
2003-10-03 07:07:57 +00:00
|
|
|
/* remove from the state the mask of the modifier being released, if
|
|
|
|
it is a modifier key being released (this is a little ugly..) */
|
2005-01-06 18:50:01 +00:00
|
|
|
#ifdef XKB
|
|
|
|
if (XkbGetState(ob_display, XkbUseCoreKbd, &xkb_state) == Success) {
|
|
|
|
e->xkey.state = xkb_state.compat_state;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
2003-10-03 07:07:57 +00:00
|
|
|
kp = modmap->modifiermap;
|
|
|
|
for (i = 0; i < mask_table_size; ++i) {
|
|
|
|
for (k = 0; k < modmap->max_keypermod; ++k) {
|
|
|
|
if (*kp == e->xkey.keycode) { /* found the keycode */
|
|
|
|
/* remove the mask for it */
|
|
|
|
e->xkey.state &= ~mask_table[i];
|
|
|
|
/* cause the first loop to break; */
|
|
|
|
i = mask_table_size;
|
|
|
|
break; /* get outta here! */
|
|
|
|
}
|
|
|
|
++kp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2003-03-16 21:11:39 +00:00
|
|
|
case MotionNotify:
|
2003-04-14 17:07:04 +00:00
|
|
|
STRIP_MODS(e->xmotion.state);
|
2003-10-03 07:07:57 +00:00
|
|
|
/* compress events */
|
2003-04-14 17:07:04 +00:00
|
|
|
{
|
|
|
|
XEvent ce;
|
|
|
|
while (XCheckTypedWindowEvent(ob_display, e->xmotion.window,
|
|
|
|
e->type, &ce)) {
|
|
|
|
e->xmotion.x_root = ce.xmotion.x_root;
|
|
|
|
e->xmotion.y_root = ce.xmotion.y_root;
|
|
|
|
}
|
2003-10-03 07:07:57 +00:00
|
|
|
}
|
|
|
|
break;
|
2003-04-14 17:07:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-12 05:25:34 +00:00
|
|
|
static gboolean wanted_focusevent(XEvent *e)
|
|
|
|
{
|
|
|
|
gint mode = e->xfocus.mode;
|
|
|
|
gint detail = e->xfocus.detail;
|
2007-03-21 16:12:21 +00:00
|
|
|
Window win = e->xany.window;
|
2007-03-12 05:25:34 +00:00
|
|
|
|
|
|
|
if (e->type == FocusIn) {
|
|
|
|
|
|
|
|
/* These are ones we never want.. */
|
|
|
|
|
|
|
|
/* This means focus was given by a keyboard/mouse grab. */
|
|
|
|
if (mode == NotifyGrab)
|
|
|
|
return FALSE;
|
|
|
|
/* This means focus was given back from a keyboard/mouse grab. */
|
|
|
|
if (mode == NotifyUngrab)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* These are the ones we want.. */
|
|
|
|
|
2007-03-21 16:12:21 +00:00
|
|
|
if (win == RootWindow(ob_display, ob_screen)) {
|
|
|
|
/* This means focus reverted off of a client */
|
2007-03-24 23:19:45 +00:00
|
|
|
if (detail == NotifyPointerRoot || detail == NotifyDetailNone ||
|
|
|
|
detail == NotifyInferior)
|
2007-03-21 16:12:21 +00:00
|
|
|
return TRUE;
|
|
|
|
else
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2007-03-12 05:25:34 +00:00
|
|
|
/* This means focus moved from the root window to a client */
|
|
|
|
if (detail == NotifyVirtual)
|
|
|
|
return TRUE;
|
|
|
|
/* This means focus moved from one client to another */
|
|
|
|
if (detail == NotifyNonlinearVirtual)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
/* Otherwise.. */
|
|
|
|
return FALSE;
|
|
|
|
} else {
|
|
|
|
g_assert(e->type == FocusOut);
|
|
|
|
|
|
|
|
|
|
|
|
/* These are ones we never want.. */
|
|
|
|
|
|
|
|
/* This means focus was taken by a keyboard/mouse grab. */
|
|
|
|
if (mode == NotifyGrab)
|
|
|
|
return FALSE;
|
|
|
|
|
2007-03-21 16:12:21 +00:00
|
|
|
/* Focus left the root window revertedto state */
|
|
|
|
if (win == RootWindow(ob_display, ob_screen))
|
|
|
|
return FALSE;
|
|
|
|
|
2007-03-12 05:25:34 +00:00
|
|
|
/* These are the ones we want.. */
|
|
|
|
|
|
|
|
/* This means focus moved from a client to the root window */
|
|
|
|
if (detail == NotifyVirtual)
|
|
|
|
return TRUE;
|
|
|
|
/* This means focus moved from one client to another */
|
|
|
|
if (detail == NotifyNonlinearVirtual)
|
|
|
|
return TRUE;
|
2007-04-22 21:29:02 +00:00
|
|
|
/* This means focus had moved to our frame window and now moved off */
|
|
|
|
if (detail == NotifyNonlinear)
|
|
|
|
return TRUE;
|
2007-03-12 05:25:34 +00:00
|
|
|
|
|
|
|
/* Otherwise.. */
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static Bool look_for_focusin(Display *d, XEvent *e, XPointer arg)
|
|
|
|
{
|
|
|
|
return e->type == FocusIn && wanted_focusevent(e);
|
|
|
|
}
|
|
|
|
|
2003-07-10 06:38:42 +00:00
|
|
|
static gboolean event_ignore(XEvent *e, ObClient *client)
|
2003-04-14 17:07:04 +00:00
|
|
|
{
|
|
|
|
switch(e->type) {
|
2003-03-16 21:11:39 +00:00
|
|
|
case FocusIn:
|
2007-04-22 20:10:17 +00:00
|
|
|
if (!wanted_focusevent(e))
|
|
|
|
return TRUE;
|
|
|
|
break;
|
2003-03-16 21:11:39 +00:00
|
|
|
case FocusOut:
|
2007-04-22 19:13:38 +00:00
|
|
|
if (!wanted_focusevent(e))
|
2003-09-29 10:06:19 +00:00
|
|
|
return TRUE;
|
2004-03-18 11:54:15 +00:00
|
|
|
break;
|
2003-09-29 10:06:19 +00:00
|
|
|
}
|
2004-03-18 11:54:15 +00:00
|
|
|
return FALSE;
|
2003-04-14 17:07:04 +00:00
|
|
|
}
|
|
|
|
|
2003-08-30 07:20:16 +00:00
|
|
|
static void event_process(const XEvent *ec, gpointer data)
|
2003-04-14 17:07:04 +00:00
|
|
|
{
|
|
|
|
Window window;
|
2003-09-15 06:50:13 +00:00
|
|
|
ObGroup *group = NULL;
|
2003-07-10 06:38:42 +00:00
|
|
|
ObClient *client = NULL;
|
2003-07-10 16:29:40 +00:00
|
|
|
ObDock *dock = NULL;
|
|
|
|
ObDockApp *dockapp = NULL;
|
2003-05-16 18:10:10 +00:00
|
|
|
ObWindow *obwin = NULL;
|
2003-08-30 07:20:16 +00:00
|
|
|
XEvent ee, *e;
|
2004-03-18 11:54:15 +00:00
|
|
|
ObEventData *ed = data;
|
2003-08-30 07:20:16 +00:00
|
|
|
|
|
|
|
/* make a copy we can mangle */
|
|
|
|
ee = *ec;
|
|
|
|
e = ⅇ
|
2003-04-14 17:07:04 +00:00
|
|
|
|
|
|
|
window = event_get_window(e);
|
2003-09-15 06:50:13 +00:00
|
|
|
if (!(e->type == PropertyNotify &&
|
|
|
|
(group = g_hash_table_lookup(group_map, &window))))
|
|
|
|
if ((obwin = g_hash_table_lookup(window_map, &window))) {
|
|
|
|
switch (obwin->type) {
|
|
|
|
case Window_Dock:
|
|
|
|
dock = WINDOW_AS_DOCK(obwin);
|
|
|
|
break;
|
|
|
|
case Window_DockApp:
|
|
|
|
dockapp = WINDOW_AS_DOCKAPP(obwin);
|
|
|
|
break;
|
|
|
|
case Window_Client:
|
|
|
|
client = WINDOW_AS_CLIENT(obwin);
|
|
|
|
break;
|
|
|
|
case Window_Menu:
|
|
|
|
case Window_Internal:
|
|
|
|
/* not to be used for events */
|
|
|
|
g_assert_not_reached();
|
|
|
|
break;
|
|
|
|
}
|
2003-05-16 18:10:10 +00:00
|
|
|
}
|
2003-05-09 23:15:28 +00:00
|
|
|
|
2007-03-12 23:23:39 +00:00
|
|
|
event_set_curtime(e);
|
2003-04-14 17:07:04 +00:00
|
|
|
event_hack_mods(e);
|
2004-03-18 11:54:15 +00:00
|
|
|
if (event_ignore(e, client)) {
|
|
|
|
if (ed)
|
|
|
|
ed->ignored = TRUE;
|
2003-04-14 17:07:04 +00:00
|
|
|
return;
|
2004-03-18 11:54:15 +00:00
|
|
|
} else if (ed)
|
|
|
|
ed->ignored = FALSE;
|
2003-03-16 21:11:39 +00:00
|
|
|
|
2003-03-17 20:16:32 +00:00
|
|
|
/* deal with it in the kernel */
|
2007-04-22 02:12:32 +00:00
|
|
|
|
|
|
|
if (menu_frame_visible &&
|
|
|
|
(e->type == EnterNotify || e->type == LeaveNotify))
|
|
|
|
{
|
|
|
|
/* crossing events for menu */
|
|
|
|
event_handle_menu(e);
|
2007-04-22 13:53:28 +00:00
|
|
|
} else if (e->type == FocusIn) {
|
2007-04-22 20:27:13 +00:00
|
|
|
if (client && client != focus_client) {
|
2007-04-22 13:53:28 +00:00
|
|
|
frame_adjust_focus(client->frame, TRUE);
|
2007-04-22 19:13:38 +00:00
|
|
|
focus_set_client(client);
|
2007-04-22 19:35:50 +00:00
|
|
|
client_calc_layer(client);
|
2007-04-22 13:53:28 +00:00
|
|
|
}
|
|
|
|
} else if (e->type == FocusOut) {
|
|
|
|
gboolean nomove = FALSE;
|
|
|
|
XEvent ce;
|
|
|
|
|
|
|
|
ob_debug_type(OB_DEBUG_FOCUS, "FocusOut Event\n");
|
|
|
|
|
|
|
|
/* Look for the followup FocusIn */
|
|
|
|
if (!XCheckIfEvent(ob_display, &ce, look_for_focusin, NULL)) {
|
|
|
|
/* There is no FocusIn, this means focus went to a window that
|
|
|
|
is not being managed, or a window on another screen. */
|
|
|
|
ob_debug_type(OB_DEBUG_FOCUS, "Focus went to a black hole !\n");
|
2007-04-22 19:13:38 +00:00
|
|
|
/* nothing is focused */
|
|
|
|
focus_set_client(NULL);
|
2007-04-22 13:53:28 +00:00
|
|
|
} else if (ce.xany.window == e->xany.window) {
|
2007-04-22 20:41:26 +00:00
|
|
|
ob_debug_type(OB_DEBUG_FOCUS, "Focus didn't go anywhere\n");
|
2007-04-22 13:53:28 +00:00
|
|
|
/* If focus didn't actually move anywhere, there is nothing to do*/
|
|
|
|
nomove = TRUE;
|
2007-04-22 20:27:13 +00:00
|
|
|
} else if (ce.xfocus.detail == NotifyPointerRoot ||
|
|
|
|
ce.xfocus.detail == NotifyDetailNone ||
|
|
|
|
ce.xfocus.detail == NotifyInferior) {
|
|
|
|
ob_debug_type(OB_DEBUG_FOCUS, "Focus went to root\n");
|
|
|
|
/* Focus has been reverted to the root window or nothing
|
|
|
|
FocusOut events come after UnmapNotify, so we don't need to
|
|
|
|
worry about focusing an invalid window
|
|
|
|
*/
|
|
|
|
focus_fallback(TRUE);
|
2007-04-22 13:53:28 +00:00
|
|
|
} else {
|
|
|
|
/* Focus did move, so process the FocusIn event */
|
|
|
|
ObEventData ed = { .ignored = FALSE };
|
|
|
|
event_process(&ce, &ed);
|
|
|
|
if (ed.ignored) {
|
|
|
|
/* The FocusIn was ignored, this means it was on a window
|
|
|
|
that isn't a client. */
|
|
|
|
ob_debug_type(OB_DEBUG_FOCUS,
|
|
|
|
"Focus went to an unmanaged window 0x%x !\n",
|
|
|
|
ce.xfocus.window);
|
|
|
|
focus_fallback(TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (client && !nomove) {
|
|
|
|
frame_adjust_focus(client->frame, FALSE);
|
2007-04-22 19:52:37 +00:00
|
|
|
/* focus_set_client has already been called for sure */
|
2007-04-22 13:53:28 +00:00
|
|
|
client_calc_layer(client);
|
|
|
|
}
|
2007-04-22 02:12:32 +00:00
|
|
|
} else if (group)
|
2003-10-02 04:06:40 +00:00
|
|
|
event_handle_group(group, e);
|
2003-09-15 06:50:13 +00:00
|
|
|
else if (client)
|
2003-10-02 04:06:40 +00:00
|
|
|
event_handle_client(client, e);
|
2003-05-16 18:10:10 +00:00
|
|
|
else if (dockapp)
|
2003-10-02 04:06:40 +00:00
|
|
|
event_handle_dockapp(dockapp, e);
|
2003-05-16 18:10:10 +00:00
|
|
|
else if (dock)
|
2003-10-02 04:06:40 +00:00
|
|
|
event_handle_dock(dock, e);
|
2003-07-10 19:01:41 +00:00
|
|
|
else if (window == RootWindow(ob_display, ob_screen))
|
2003-10-02 04:06:40 +00:00
|
|
|
event_handle_root(e);
|
2003-03-23 19:39:20 +00:00
|
|
|
else if (e->type == MapRequest)
|
2003-10-02 04:06:40 +00:00
|
|
|
client_manage(window);
|
2003-03-16 21:11:39 +00:00
|
|
|
else if (e->type == ConfigureRequest) {
|
2003-10-02 04:06:40 +00:00
|
|
|
/* unhandled configure requests must be used to configure the
|
|
|
|
window directly */
|
|
|
|
XWindowChanges xwc;
|
2004-03-20 15:48:38 +00:00
|
|
|
|
2003-10-03 07:07:57 +00:00
|
|
|
xwc.x = e->xconfigurerequest.x;
|
|
|
|
xwc.y = e->xconfigurerequest.y;
|
|
|
|
xwc.width = e->xconfigurerequest.width;
|
|
|
|
xwc.height = e->xconfigurerequest.height;
|
|
|
|
xwc.border_width = e->xconfigurerequest.border_width;
|
|
|
|
xwc.sibling = e->xconfigurerequest.above;
|
|
|
|
xwc.stack_mode = e->xconfigurerequest.detail;
|
2003-03-16 21:11:39 +00:00
|
|
|
|
2003-10-03 07:07:57 +00:00
|
|
|
/* we are not to be held responsible if someone sends us an
|
|
|
|
invalid request! */
|
|
|
|
xerror_set_ignore(TRUE);
|
|
|
|
XConfigureWindow(ob_display, window,
|
|
|
|
e->xconfigurerequest.value_mask, &xwc);
|
|
|
|
xerror_set_ignore(FALSE);
|
2003-03-16 21:11:39 +00:00
|
|
|
}
|
|
|
|
|
2003-04-14 17:07:04 +00:00
|
|
|
/* user input (action-bound) events */
|
|
|
|
if (e->type == ButtonPress || e->type == ButtonRelease ||
|
2003-08-12 07:26:16 +00:00
|
|
|
e->type == MotionNotify || e->type == KeyPress ||
|
|
|
|
e->type == KeyRelease)
|
|
|
|
{
|
2003-08-29 06:52:55 +00:00
|
|
|
if (menu_frame_visible)
|
|
|
|
event_handle_menu(e);
|
|
|
|
else {
|
2003-09-09 08:05:06 +00:00
|
|
|
if (!keyboard_process_interactive_grab(e, &client)) {
|
2003-09-18 06:09:44 +00:00
|
|
|
if (moveresize_in_progress) {
|
2003-09-09 07:16:38 +00:00
|
|
|
moveresize_event(e);
|
2003-08-12 07:26:16 +00:00
|
|
|
|
2003-09-18 06:09:44 +00:00
|
|
|
/* make further actions work on the client being
|
|
|
|
moved/resized */
|
|
|
|
client = moveresize_client;
|
|
|
|
}
|
|
|
|
|
2003-09-10 19:37:52 +00:00
|
|
|
menu_can_hide = FALSE;
|
|
|
|
ob_main_loop_timeout_add(ob_main_loop,
|
2004-03-20 22:53:16 +00:00
|
|
|
config_menu_hide_delay * 1000,
|
2003-09-10 19:37:52 +00:00
|
|
|
menu_hide_delay_func,
|
2007-04-22 04:16:00 +00:00
|
|
|
NULL, g_direct_equal, NULL);
|
2003-09-10 19:37:52 +00:00
|
|
|
|
2003-08-29 06:52:55 +00:00
|
|
|
if (e->type == ButtonPress || e->type == ButtonRelease ||
|
2007-04-22 15:22:25 +00:00
|
|
|
e->type == MotionNotify) {
|
2007-04-22 15:58:09 +00:00
|
|
|
mouse_event(client, e);
|
2007-04-22 15:22:25 +00:00
|
|
|
} else if (e->type == KeyPress) {
|
2003-10-09 19:08:07 +00:00
|
|
|
keyboard_event((focus_cycle_target ? focus_cycle_target :
|
2007-04-22 19:13:38 +00:00
|
|
|
client), e);
|
2007-03-12 05:44:16 +00:00
|
|
|
}
|
2003-08-29 06:52:55 +00:00
|
|
|
}
|
2003-08-12 07:26:16 +00:00
|
|
|
}
|
|
|
|
}
|
2007-03-12 23:23:39 +00:00
|
|
|
/* if something happens and it's not from an XEvent, then we don't know
|
|
|
|
the time */
|
|
|
|
event_curtime = CurrentTime;
|
2003-03-16 21:11:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void event_handle_root(XEvent *e)
|
|
|
|
{
|
|
|
|
Atom msgtype;
|
|
|
|
|
|
|
|
switch(e->type) {
|
2003-07-22 18:09:41 +00:00
|
|
|
case SelectionClear:
|
2003-07-24 06:02:38 +00:00
|
|
|
ob_debug("Another WM has requested to replace us. Exiting.\n");
|
2007-03-04 09:01:52 +00:00
|
|
|
ob_exit_replace();
|
2003-07-22 18:09:41 +00:00
|
|
|
break;
|
|
|
|
|
2003-03-16 21:11:39 +00:00
|
|
|
case ClientMessage:
|
2003-10-03 07:07:57 +00:00
|
|
|
if (e->xclient.format != 32) break;
|
|
|
|
|
|
|
|
msgtype = e->xclient.message_type;
|
|
|
|
if (msgtype == prop_atoms.net_current_desktop) {
|
2003-10-15 03:59:35 +00:00
|
|
|
guint d = e->xclient.data.l[0];
|
2007-04-12 02:26:58 +00:00
|
|
|
if (d < screen_num_desktops) {
|
|
|
|
event_curtime = e->xclient.data.l[1];
|
|
|
|
ob_debug("SWITCH DESKTOP TIME: %d\n", event_curtime);
|
2003-10-03 07:07:57 +00:00
|
|
|
screen_set_desktop(d);
|
2007-04-12 02:26:58 +00:00
|
|
|
}
|
2003-10-03 07:07:57 +00:00
|
|
|
} else if (msgtype == prop_atoms.net_number_of_desktops) {
|
2003-10-15 03:59:35 +00:00
|
|
|
guint d = e->xclient.data.l[0];
|
2003-10-03 07:07:57 +00:00
|
|
|
if (d > 0)
|
|
|
|
screen_set_num_desktops(d);
|
|
|
|
} else if (msgtype == prop_atoms.net_showing_desktop) {
|
|
|
|
screen_show_desktop(e->xclient.data.l[0] != 0);
|
2007-03-04 20:05:00 +00:00
|
|
|
} else if (msgtype == prop_atoms.ob_control) {
|
scary commit..but here goes.
YOUR THEMES ARE NOW OFFICIALLY BROKEN.
Openbox has just moved it's theme format to an XML based one. The details of
this format can be found in data/themerc.xsd (and http://openbox.org/themerc.xsd
ALSO! This is very good and important and stuff! In the tools directory you
will find THEMETOXML ! This tool takes a themerc on stdin, and spits out
the same theme in theme.xml format. So this is all you need to do to update
your themes.
PLEASE NOTE: This themetoxml does _not_ install itself anywhere. It simply
builds and then lives out in its tools/themetoxml directory, and that's it. So
if you want to use it, that is where to find it.
In moving to the new XML format, a number of additions/changes to the theme
engine have been made. Themetoxml takes these into account and will set all
the new things appropriately to make your theme look the same as it always has.
New additions include..
* padding now has an horizontal and vertical component, instead of being one number
* menus can have different borders than windows (color and size)
* menu offset can now be negative. it's a little weird, but someone will want it no doubt
* fonts are no longer controled by the theme at all, however font shadowing is, and on that note..
* font shadows are now any color you want, not just black and white
* you can now set the shadow anywhere you can set the text's color, so you have more control, i.e. you can set shadow on active menu items but not inactive, or disabled, etc.
* every color now has an alpha channel. at the moment they don't do anything, besides the font shadow one, but it leaves room for future explorations. it is REALLY HIGHLY RECOMMENDED that you set the alpha to 255 all the time, until such time as it could be useful. otherwise one day your theme may turn awful for people.
* font colors are in the range 0-255, in case you were wondering, and they have to be specified in decimal
* if you'd like to change you font's you can do so in your configuration file. this is how it is going to stay. changing the font in the theme assumes too much about peoples eye sight and locality and stuff. it doesn't belong there, sorry. the system-wide default rc.xml includes the new font settings for your viewing pleasure, and ill drop an example of it below.
* shadows can now be positioned in any direction, they have both an x and a y offset which can be negative and positive. and offset of 0,0 will disable the shadow
This isn't a release or anything. If someone had some good ideas about the xml theme format, I'd like to hear them. But I don't think it will be changing much right now beyond where it is. I don't even know how the new functionality will play out for themers, so we'll see.
Whew.. I guess that's it. I'm not sure if I mentioned every little change or not, but oh well. Mileage may vary.. Please send any feedback.
Here's the font configuration example. Hopefully ObConf will let you set this real soon.
<theme>
...
<font place="ActiveWindow">
<name>arial,sans</name>
<size>7</size>
<weight>bold</weight>
<slant>normal</slant>
</font>
<font place="InactiveWindow">
<name>arial,sans</name>
<size>7</size>
<weight>bold</weight>
<slant>normal</slant>
</font>
<font place="MenuTitle">
<name>arial,sans</name>
<size>8</size>
<weight>bold</weight>
<slant>normal</slant>
</font>
<font place="MenuItem">
<name>arial,sans</name>
<size>8</size>
<weight>bold</weight>
<slant>normal</slant>
</font>
</theme>
2007-03-05 15:44:17 +00:00
|
|
|
if (e->xclient.data.l[0] == 1)
|
2007-03-04 20:32:47 +00:00
|
|
|
ob_reconfigure();
|
scary commit..but here goes.
YOUR THEMES ARE NOW OFFICIALLY BROKEN.
Openbox has just moved it's theme format to an XML based one. The details of
this format can be found in data/themerc.xsd (and http://openbox.org/themerc.xsd
ALSO! This is very good and important and stuff! In the tools directory you
will find THEMETOXML ! This tool takes a themerc on stdin, and spits out
the same theme in theme.xml format. So this is all you need to do to update
your themes.
PLEASE NOTE: This themetoxml does _not_ install itself anywhere. It simply
builds and then lives out in its tools/themetoxml directory, and that's it. So
if you want to use it, that is where to find it.
In moving to the new XML format, a number of additions/changes to the theme
engine have been made. Themetoxml takes these into account and will set all
the new things appropriately to make your theme look the same as it always has.
New additions include..
* padding now has an horizontal and vertical component, instead of being one number
* menus can have different borders than windows (color and size)
* menu offset can now be negative. it's a little weird, but someone will want it no doubt
* fonts are no longer controled by the theme at all, however font shadowing is, and on that note..
* font shadows are now any color you want, not just black and white
* you can now set the shadow anywhere you can set the text's color, so you have more control, i.e. you can set shadow on active menu items but not inactive, or disabled, etc.
* every color now has an alpha channel. at the moment they don't do anything, besides the font shadow one, but it leaves room for future explorations. it is REALLY HIGHLY RECOMMENDED that you set the alpha to 255 all the time, until such time as it could be useful. otherwise one day your theme may turn awful for people.
* font colors are in the range 0-255, in case you were wondering, and they have to be specified in decimal
* if you'd like to change you font's you can do so in your configuration file. this is how it is going to stay. changing the font in the theme assumes too much about peoples eye sight and locality and stuff. it doesn't belong there, sorry. the system-wide default rc.xml includes the new font settings for your viewing pleasure, and ill drop an example of it below.
* shadows can now be positioned in any direction, they have both an x and a y offset which can be negative and positive. and offset of 0,0 will disable the shadow
This isn't a release or anything. If someone had some good ideas about the xml theme format, I'd like to hear them. But I don't think it will be changing much right now beyond where it is. I don't even know how the new functionality will play out for themers, so we'll see.
Whew.. I guess that's it. I'm not sure if I mentioned every little change or not, but oh well. Mileage may vary.. Please send any feedback.
Here's the font configuration example. Hopefully ObConf will let you set this real soon.
<theme>
...
<font place="ActiveWindow">
<name>arial,sans</name>
<size>7</size>
<weight>bold</weight>
<slant>normal</slant>
</font>
<font place="InactiveWindow">
<name>arial,sans</name>
<size>7</size>
<weight>bold</weight>
<slant>normal</slant>
</font>
<font place="MenuTitle">
<name>arial,sans</name>
<size>8</size>
<weight>bold</weight>
<slant>normal</slant>
</font>
<font place="MenuItem">
<name>arial,sans</name>
<size>8</size>
<weight>bold</weight>
<slant>normal</slant>
</font>
</theme>
2007-03-05 15:44:17 +00:00
|
|
|
else if (e->xclient.data.l[0] == 2)
|
2007-03-04 20:32:47 +00:00
|
|
|
ob_restart();
|
2003-10-03 07:07:57 +00:00
|
|
|
}
|
|
|
|
break;
|
2003-03-16 21:11:39 +00:00
|
|
|
case PropertyNotify:
|
2003-10-03 07:07:57 +00:00
|
|
|
if (e->xproperty.atom == prop_atoms.net_desktop_names)
|
|
|
|
screen_update_desktop_names();
|
|
|
|
else if (e->xproperty.atom == prop_atoms.net_desktop_layout)
|
|
|
|
screen_update_layout();
|
|
|
|
break;
|
2003-05-09 16:57:17 +00:00
|
|
|
case ConfigureNotify:
|
|
|
|
#ifdef XRANDR
|
|
|
|
XRRUpdateConfiguration(e);
|
|
|
|
#endif
|
2003-07-10 05:44:23 +00:00
|
|
|
screen_resize();
|
2003-05-09 16:57:17 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
;
|
2003-03-16 21:11:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-09-15 06:50:13 +00:00
|
|
|
static void event_handle_group(ObGroup *group, XEvent *e)
|
|
|
|
{
|
|
|
|
GSList *it;
|
|
|
|
|
|
|
|
g_assert(e->type == PropertyNotify);
|
|
|
|
|
|
|
|
for (it = group->members; it; it = g_slist_next(it))
|
|
|
|
event_handle_client(it->data, e);
|
|
|
|
}
|
|
|
|
|
2003-09-21 21:26:07 +00:00
|
|
|
void event_enter_client(ObClient *client)
|
|
|
|
{
|
|
|
|
g_assert(config_focus_follow);
|
|
|
|
|
|
|
|
if (client_normal(client) && client_can_focus(client)) {
|
|
|
|
if (config_focus_delay) {
|
2007-04-22 04:16:00 +00:00
|
|
|
ObFocusDelayData *data;
|
|
|
|
|
2003-09-21 21:26:07 +00:00
|
|
|
ob_main_loop_timeout_remove(ob_main_loop, focus_delay_func);
|
2007-04-22 02:34:05 +00:00
|
|
|
|
2007-04-22 04:16:00 +00:00
|
|
|
data = g_new(ObFocusDelayData, 1);
|
|
|
|
data->client = client;
|
|
|
|
data->time = event_curtime;
|
2007-04-22 02:34:05 +00:00
|
|
|
|
2003-09-21 21:26:07 +00:00
|
|
|
ob_main_loop_timeout_add(ob_main_loop,
|
|
|
|
config_focus_delay,
|
|
|
|
focus_delay_func,
|
2007-04-22 04:16:00 +00:00
|
|
|
data, focus_delay_cmp, focus_delay_dest);
|
2007-04-22 02:49:52 +00:00
|
|
|
} else {
|
2007-04-22 04:16:00 +00:00
|
|
|
ObFocusDelayData data;
|
|
|
|
data.client = client;
|
|
|
|
data.time = event_curtime;
|
|
|
|
focus_delay_func(&data);
|
2007-04-22 02:49:52 +00:00
|
|
|
}
|
2003-09-21 21:26:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-07-10 06:38:42 +00:00
|
|
|
static void event_handle_client(ObClient *client, XEvent *e)
|
2003-03-16 21:11:39 +00:00
|
|
|
{
|
|
|
|
XEvent ce;
|
|
|
|
Atom msgtype;
|
2003-10-15 03:59:35 +00:00
|
|
|
gint i=0;
|
2003-07-28 16:24:20 +00:00
|
|
|
ObFrameContext con;
|
2003-03-16 21:11:39 +00:00
|
|
|
|
|
|
|
switch (e->type) {
|
2003-08-20 23:01:56 +00:00
|
|
|
case VisibilityNotify:
|
|
|
|
client->frame->obscured = e->xvisibility.state != VisibilityUnobscured;
|
|
|
|
break;
|
2003-04-13 07:18:28 +00:00
|
|
|
case ButtonPress:
|
|
|
|
case ButtonRelease:
|
2003-05-17 15:16:45 +00:00
|
|
|
/* Wheel buttons don't draw because they are an instant click, so it
|
|
|
|
is a waste of resources to go drawing it. */
|
|
|
|
if (!(e->xbutton.button == 4 || e->xbutton.button == 5)) {
|
2003-09-10 20:05:06 +00:00
|
|
|
con = frame_context(client, e->xbutton.window);
|
|
|
|
con = mouse_button_frame_context(con, e->xbutton.button);
|
|
|
|
switch (con) {
|
2003-07-10 07:16:19 +00:00
|
|
|
case OB_FRAME_CONTEXT_MAXIMIZE:
|
2003-05-17 15:16:45 +00:00
|
|
|
client->frame->max_press = (e->type == ButtonPress);
|
|
|
|
framerender_frame(client->frame);
|
|
|
|
break;
|
2003-07-10 07:16:19 +00:00
|
|
|
case OB_FRAME_CONTEXT_CLOSE:
|
2003-05-17 15:16:45 +00:00
|
|
|
client->frame->close_press = (e->type == ButtonPress);
|
|
|
|
framerender_frame(client->frame);
|
|
|
|
break;
|
2003-07-10 07:16:19 +00:00
|
|
|
case OB_FRAME_CONTEXT_ICONIFY:
|
2003-05-17 15:16:45 +00:00
|
|
|
client->frame->iconify_press = (e->type == ButtonPress);
|
|
|
|
framerender_frame(client->frame);
|
|
|
|
break;
|
2003-07-10 07:16:19 +00:00
|
|
|
case OB_FRAME_CONTEXT_ALLDESKTOPS:
|
2003-05-17 15:16:45 +00:00
|
|
|
client->frame->desk_press = (e->type == ButtonPress);
|
|
|
|
framerender_frame(client->frame);
|
|
|
|
break;
|
2003-07-10 07:16:19 +00:00
|
|
|
case OB_FRAME_CONTEXT_SHADE:
|
2003-05-17 15:16:45 +00:00
|
|
|
client->frame->shade_press = (e->type == ButtonPress);
|
|
|
|
framerender_frame(client->frame);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* nothing changes with clicks for any other contexts */
|
|
|
|
break;
|
|
|
|
}
|
2003-04-13 07:18:28 +00:00
|
|
|
}
|
|
|
|
break;
|
2003-07-28 19:21:45 +00:00
|
|
|
case LeaveNotify:
|
|
|
|
con = frame_context(client, e->xcrossing.window);
|
2003-07-28 16:24:20 +00:00
|
|
|
switch (con) {
|
|
|
|
case OB_FRAME_CONTEXT_MAXIMIZE:
|
2003-07-28 19:21:45 +00:00
|
|
|
client->frame->max_hover = FALSE;
|
|
|
|
frame_adjust_state(client->frame);
|
|
|
|
break;
|
2003-07-28 16:24:20 +00:00
|
|
|
case OB_FRAME_CONTEXT_ALLDESKTOPS:
|
2003-07-28 19:21:45 +00:00
|
|
|
client->frame->desk_hover = FALSE;
|
|
|
|
frame_adjust_state(client->frame);
|
|
|
|
break;
|
2003-07-28 16:24:20 +00:00
|
|
|
case OB_FRAME_CONTEXT_SHADE:
|
2003-07-28 19:21:45 +00:00
|
|
|
client->frame->shade_hover = FALSE;
|
|
|
|
frame_adjust_state(client->frame);
|
|
|
|
break;
|
2003-07-28 16:24:20 +00:00
|
|
|
case OB_FRAME_CONTEXT_ICONIFY:
|
2003-07-28 19:21:45 +00:00
|
|
|
client->frame->iconify_hover = FALSE;
|
|
|
|
frame_adjust_state(client->frame);
|
|
|
|
break;
|
2003-07-28 16:24:20 +00:00
|
|
|
case OB_FRAME_CONTEXT_CLOSE:
|
2003-07-28 19:21:45 +00:00
|
|
|
client->frame->close_hover = FALSE;
|
2003-07-28 16:24:20 +00:00
|
|
|
frame_adjust_state(client->frame);
|
|
|
|
break;
|
2003-09-03 08:12:07 +00:00
|
|
|
case OB_FRAME_CONTEXT_FRAME:
|
2007-04-22 15:22:25 +00:00
|
|
|
if (keyboard_interactively_grabbed())
|
|
|
|
break;
|
2007-04-22 04:16:00 +00:00
|
|
|
if (config_focus_follow && config_focus_delay)
|
|
|
|
ob_main_loop_timeout_remove_data(ob_main_loop,
|
|
|
|
focus_delay_func,
|
|
|
|
client, FALSE);
|
2003-09-21 21:26:07 +00:00
|
|
|
break;
|
2003-07-28 16:24:20 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2003-07-28 19:21:45 +00:00
|
|
|
break;
|
|
|
|
case EnterNotify:
|
2003-09-21 18:10:39 +00:00
|
|
|
{
|
|
|
|
gboolean nofocus = FALSE;
|
|
|
|
|
|
|
|
if (ignore_enter_focus) {
|
|
|
|
ignore_enter_focus--;
|
|
|
|
nofocus = TRUE;
|
|
|
|
}
|
|
|
|
|
2003-07-28 19:21:45 +00:00
|
|
|
con = frame_context(client, e->xcrossing.window);
|
|
|
|
switch (con) {
|
|
|
|
case OB_FRAME_CONTEXT_MAXIMIZE:
|
|
|
|
client->frame->max_hover = TRUE;
|
|
|
|
frame_adjust_state(client->frame);
|
|
|
|
break;
|
|
|
|
case OB_FRAME_CONTEXT_ALLDESKTOPS:
|
|
|
|
client->frame->desk_hover = TRUE;
|
|
|
|
frame_adjust_state(client->frame);
|
|
|
|
break;
|
|
|
|
case OB_FRAME_CONTEXT_SHADE:
|
|
|
|
client->frame->shade_hover = TRUE;
|
|
|
|
frame_adjust_state(client->frame);
|
|
|
|
break;
|
|
|
|
case OB_FRAME_CONTEXT_ICONIFY:
|
|
|
|
client->frame->iconify_hover = TRUE;
|
|
|
|
frame_adjust_state(client->frame);
|
|
|
|
break;
|
|
|
|
case OB_FRAME_CONTEXT_CLOSE:
|
|
|
|
client->frame->close_hover = TRUE;
|
|
|
|
frame_adjust_state(client->frame);
|
|
|
|
break;
|
|
|
|
case OB_FRAME_CONTEXT_FRAME:
|
2007-04-22 15:22:25 +00:00
|
|
|
if (keyboard_interactively_grabbed())
|
|
|
|
break;
|
2003-09-21 21:26:07 +00:00
|
|
|
if (e->xcrossing.mode == NotifyGrab ||
|
|
|
|
e->xcrossing.mode == NotifyUngrab)
|
|
|
|
{
|
2007-04-21 21:04:35 +00:00
|
|
|
ob_debug_type(OB_DEBUG_FOCUS,
|
|
|
|
"%sNotify mode %d detail %d on %lx IGNORED\n",
|
|
|
|
(e->type == EnterNotify ? "Enter" : "Leave"),
|
|
|
|
e->xcrossing.mode,
|
|
|
|
e->xcrossing.detail, client?client->window:0);
|
2003-09-21 21:26:07 +00:00
|
|
|
} else {
|
2007-04-21 21:04:35 +00:00
|
|
|
ob_debug_type(OB_DEBUG_FOCUS,
|
|
|
|
"%sNotify mode %d detail %d on %lx, "
|
|
|
|
"focusing window: %d\n",
|
|
|
|
(e->type == EnterNotify ? "Enter" : "Leave"),
|
|
|
|
e->xcrossing.mode,
|
|
|
|
e->xcrossing.detail, (client?client->window:0),
|
|
|
|
!nofocus);
|
2003-09-21 21:26:07 +00:00
|
|
|
if (!nofocus && config_focus_follow)
|
|
|
|
event_enter_client(client);
|
2003-04-07 22:27:02 +00:00
|
|
|
}
|
2003-07-28 19:21:45 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2003-03-27 23:10:22 +00:00
|
|
|
}
|
|
|
|
break;
|
2003-09-21 18:10:39 +00:00
|
|
|
}
|
2003-03-16 21:11:39 +00:00
|
|
|
case ConfigureRequest:
|
2003-10-03 07:07:57 +00:00
|
|
|
/* compress these */
|
|
|
|
while (XCheckTypedWindowEvent(ob_display, client->window,
|
|
|
|
ConfigureRequest, &ce)) {
|
2003-03-24 19:52:09 +00:00
|
|
|
++i;
|
2003-10-03 07:07:57 +00:00
|
|
|
/* XXX if this causes bad things.. we can compress config req's
|
|
|
|
with the same mask. */
|
|
|
|
e->xconfigurerequest.value_mask |=
|
|
|
|
ce.xconfigurerequest.value_mask;
|
|
|
|
if (ce.xconfigurerequest.value_mask & CWX)
|
|
|
|
e->xconfigurerequest.x = ce.xconfigurerequest.x;
|
|
|
|
if (ce.xconfigurerequest.value_mask & CWY)
|
|
|
|
e->xconfigurerequest.y = ce.xconfigurerequest.y;
|
|
|
|
if (ce.xconfigurerequest.value_mask & CWWidth)
|
|
|
|
e->xconfigurerequest.width = ce.xconfigurerequest.width;
|
|
|
|
if (ce.xconfigurerequest.value_mask & CWHeight)
|
|
|
|
e->xconfigurerequest.height = ce.xconfigurerequest.height;
|
|
|
|
if (ce.xconfigurerequest.value_mask & CWBorderWidth)
|
|
|
|
e->xconfigurerequest.border_width =
|
|
|
|
ce.xconfigurerequest.border_width;
|
|
|
|
if (ce.xconfigurerequest.value_mask & CWStackMode)
|
|
|
|
e->xconfigurerequest.detail = ce.xconfigurerequest.detail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if we are iconic (or shaded (fvwm does this)) ignore the event */
|
|
|
|
if (client->iconic || client->shaded) return;
|
|
|
|
|
|
|
|
/* resize, then move, as specified in the EWMH section 7.7 */
|
|
|
|
if (e->xconfigurerequest.value_mask & (CWWidth | CWHeight |
|
|
|
|
CWX | CWY |
|
2003-07-30 06:19:15 +00:00
|
|
|
CWBorderWidth)) {
|
2003-10-15 03:59:35 +00:00
|
|
|
gint x, y, w, h;
|
2003-10-03 07:07:57 +00:00
|
|
|
ObCorner corner;
|
2003-07-28 07:19:47 +00:00
|
|
|
|
2003-07-30 06:19:15 +00:00
|
|
|
if (e->xconfigurerequest.value_mask & CWBorderWidth)
|
|
|
|
client->border_width = e->xconfigurerequest.border_width;
|
|
|
|
|
2003-10-03 07:07:57 +00:00
|
|
|
x = (e->xconfigurerequest.value_mask & CWX) ?
|
|
|
|
e->xconfigurerequest.x : client->area.x;
|
|
|
|
y = (e->xconfigurerequest.value_mask & CWY) ?
|
|
|
|
e->xconfigurerequest.y : client->area.y;
|
|
|
|
w = (e->xconfigurerequest.value_mask & CWWidth) ?
|
|
|
|
e->xconfigurerequest.width : client->area.width;
|
|
|
|
h = (e->xconfigurerequest.value_mask & CWHeight) ?
|
|
|
|
e->xconfigurerequest.height : client->area.height;
|
2003-07-28 07:19:47 +00:00
|
|
|
|
2003-07-28 19:59:37 +00:00
|
|
|
{
|
2003-10-15 03:59:35 +00:00
|
|
|
gint newx = x;
|
|
|
|
gint newy = y;
|
|
|
|
gint fw = w +
|
|
|
|
client->frame->size.left + client->frame->size.right;
|
|
|
|
gint fh = h +
|
|
|
|
client->frame->size.top + client->frame->size.bottom;
|
2007-03-10 22:24:47 +00:00
|
|
|
/* make this rude for size-only changes but not for position
|
|
|
|
changes.. */
|
|
|
|
gboolean moving = ((e->xconfigurerequest.value_mask & CWX) ||
|
|
|
|
(e->xconfigurerequest.value_mask & CWY));
|
|
|
|
|
2003-08-27 18:50:12 +00:00
|
|
|
client_find_onscreen(client, &newx, &newy, fw, fh,
|
2007-03-10 22:24:47 +00:00
|
|
|
!moving);
|
2003-07-28 18:06:55 +00:00
|
|
|
if (e->xconfigurerequest.value_mask & CWX)
|
|
|
|
x = newx;
|
|
|
|
if (e->xconfigurerequest.value_mask & CWY)
|
|
|
|
y = newy;
|
|
|
|
}
|
2004-03-21 01:03:00 +00:00
|
|
|
|
2003-10-03 07:07:57 +00:00
|
|
|
switch (client->gravity) {
|
|
|
|
case NorthEastGravity:
|
|
|
|
case EastGravity:
|
|
|
|
corner = OB_CORNER_TOPRIGHT;
|
|
|
|
break;
|
|
|
|
case SouthWestGravity:
|
|
|
|
case SouthGravity:
|
|
|
|
corner = OB_CORNER_BOTTOMLEFT;
|
|
|
|
break;
|
|
|
|
case SouthEastGravity:
|
|
|
|
corner = OB_CORNER_BOTTOMRIGHT;
|
|
|
|
break;
|
|
|
|
default: /* NorthWest, Static, etc */
|
|
|
|
corner = OB_CORNER_TOPLEFT;
|
|
|
|
}
|
|
|
|
|
|
|
|
client_configure_full(client, corner, x, y, w, h, FALSE, TRUE,
|
2003-07-30 06:19:15 +00:00
|
|
|
TRUE);
|
2003-10-03 07:07:57 +00:00
|
|
|
}
|
2003-03-16 21:11:39 +00:00
|
|
|
|
2003-10-03 07:07:57 +00:00
|
|
|
if (e->xconfigurerequest.value_mask & CWStackMode) {
|
|
|
|
switch (e->xconfigurerequest.detail) {
|
|
|
|
case Below:
|
|
|
|
case BottomIf:
|
2007-03-11 04:44:15 +00:00
|
|
|
/* Apps are so rude. And this is totally disconnected from
|
|
|
|
activation/focus. Bleh. */
|
|
|
|
/*client_lower(client);*/
|
2003-10-03 07:07:57 +00:00
|
|
|
break;
|
2003-03-16 21:11:39 +00:00
|
|
|
|
2003-10-03 07:07:57 +00:00
|
|
|
case Above:
|
|
|
|
case TopIf:
|
|
|
|
default:
|
2007-03-11 04:44:15 +00:00
|
|
|
/* Apps are so rude. And this is totally disconnected from
|
|
|
|
activation/focus. Bleh. */
|
|
|
|
/*client_raise(client);*/
|
2003-10-03 07:07:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2003-03-16 21:11:39 +00:00
|
|
|
case UnmapNotify:
|
2003-10-03 07:07:57 +00:00
|
|
|
if (client->ignore_unmaps) {
|
|
|
|
client->ignore_unmaps--;
|
|
|
|
break;
|
|
|
|
}
|
2007-04-21 21:04:35 +00:00
|
|
|
ob_debug("UnmapNotify for window 0x%x eventwin 0x%x sendevent %d "
|
|
|
|
"ignores left %d\n",
|
|
|
|
client->window, e->xunmap.event, e->xunmap.from_configure,
|
|
|
|
client->ignore_unmaps);
|
2003-10-03 07:07:57 +00:00
|
|
|
client_unmanage(client);
|
|
|
|
break;
|
2003-03-16 21:11:39 +00:00
|
|
|
case DestroyNotify:
|
2007-03-19 17:59:16 +00:00
|
|
|
ob_debug("DestroyNotify for window 0x%x\n", client->window);
|
2003-10-03 07:07:57 +00:00
|
|
|
client_unmanage(client);
|
|
|
|
break;
|
2003-03-16 21:11:39 +00:00
|
|
|
case ReparentNotify:
|
2003-10-03 07:07:57 +00:00
|
|
|
/* this is when the client is first taken captive in the frame */
|
|
|
|
if (e->xreparent.parent == client->frame->plate) break;
|
|
|
|
|
|
|
|
/*
|
|
|
|
This event is quite rare and is usually handled in unmapHandler.
|
|
|
|
However, if the window is unmapped when the reparent event occurs,
|
|
|
|
the window manager never sees it because an unmap event is not sent
|
|
|
|
to an already unmapped window.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* we don't want the reparent event, put it back on the stack for the
|
|
|
|
X server to deal with after we unmanage the window */
|
|
|
|
XPutBackEvent(ob_display, e);
|
2003-03-16 21:11:39 +00:00
|
|
|
|
2007-03-24 23:19:45 +00:00
|
|
|
ob_debug("ReparentNotify for window 0x%x\n", client->window);
|
2003-10-03 07:07:57 +00:00
|
|
|
client_unmanage(client);
|
|
|
|
break;
|
2003-03-16 21:11:39 +00:00
|
|
|
case MapRequest:
|
2003-07-24 06:02:38 +00:00
|
|
|
ob_debug("MapRequest for 0x%lx\n", client->window);
|
2003-03-25 02:20:16 +00:00
|
|
|
if (!client->iconic) break; /* this normally doesn't happen, but if it
|
2003-10-15 17:04:27 +00:00
|
|
|
does, we don't want it!
|
|
|
|
it can happen now when the window is on
|
|
|
|
another desktop, but we still don't
|
|
|
|
want it! */
|
2007-03-19 17:59:16 +00:00
|
|
|
client_activate(client, FALSE, TRUE);
|
2003-09-26 18:18:15 +00:00
|
|
|
break;
|
2003-03-16 21:11:39 +00:00
|
|
|
case ClientMessage:
|
2003-09-26 18:18:15 +00:00
|
|
|
/* validate cuz we query stuff off the client here */
|
|
|
|
if (!client_validate(client)) break;
|
2003-03-16 21:11:39 +00:00
|
|
|
|
2003-09-26 18:18:15 +00:00
|
|
|
if (e->xclient.format != 32) return;
|
|
|
|
|
|
|
|
msgtype = e->xclient.message_type;
|
|
|
|
if (msgtype == prop_atoms.wm_change_state) {
|
|
|
|
/* compress changes into a single change */
|
|
|
|
while (XCheckTypedWindowEvent(ob_display, client->window,
|
|
|
|
e->type, &ce)) {
|
|
|
|
/* XXX: it would be nice to compress ALL messages of a
|
|
|
|
type, not just messages in a row without other
|
|
|
|
message types between. */
|
|
|
|
if (ce.xclient.message_type != msgtype) {
|
|
|
|
XPutBackEvent(ob_display, &ce);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
e->xclient = ce.xclient;
|
|
|
|
}
|
|
|
|
client_set_wm_state(client, e->xclient.data.l[0]);
|
|
|
|
} else if (msgtype == prop_atoms.net_wm_desktop) {
|
|
|
|
/* compress changes into a single change */
|
|
|
|
while (XCheckTypedWindowEvent(ob_display, client->window,
|
|
|
|
e->type, &ce)) {
|
|
|
|
/* XXX: it would be nice to compress ALL messages of a
|
|
|
|
type, not just messages in a row without other
|
|
|
|
message types between. */
|
|
|
|
if (ce.xclient.message_type != msgtype) {
|
|
|
|
XPutBackEvent(ob_display, &ce);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
e->xclient = ce.xclient;
|
|
|
|
}
|
2003-03-26 08:29:34 +00:00
|
|
|
if ((unsigned)e->xclient.data.l[0] < screen_num_desktops ||
|
|
|
|
(unsigned)e->xclient.data.l[0] == DESKTOP_ALL)
|
2003-03-28 08:11:02 +00:00
|
|
|
client_set_desktop(client, (unsigned)e->xclient.data.l[0],
|
|
|
|
FALSE);
|
2003-09-26 18:18:15 +00:00
|
|
|
} else if (msgtype == prop_atoms.net_wm_state) {
|
|
|
|
/* can't compress these */
|
|
|
|
ob_debug("net_wm_state %s %ld %ld for 0x%lx\n",
|
2003-07-24 06:02:38 +00:00
|
|
|
(e->xclient.data.l[0] == 0 ? "Remove" :
|
|
|
|
e->xclient.data.l[0] == 1 ? "Add" :
|
|
|
|
e->xclient.data.l[0] == 2 ? "Toggle" : "INVALID"),
|
|
|
|
e->xclient.data.l[1], e->xclient.data.l[2],
|
|
|
|
client->window);
|
2003-09-26 18:18:15 +00:00
|
|
|
client_set_state(client, e->xclient.data.l[0],
|
|
|
|
e->xclient.data.l[1], e->xclient.data.l[2]);
|
|
|
|
} else if (msgtype == prop_atoms.net_close_window) {
|
|
|
|
ob_debug("net_close_window for 0x%lx\n", client->window);
|
|
|
|
client_close(client);
|
|
|
|
} else if (msgtype == prop_atoms.net_active_window) {
|
2007-03-02 02:23:00 +00:00
|
|
|
ob_debug("net_active_window for 0x%lx source=%s\n",
|
|
|
|
client->window,
|
|
|
|
(e->xclient.data.l[0] == 0 ? "unknown" :
|
|
|
|
(e->xclient.data.l[0] == 1 ? "application" :
|
|
|
|
(e->xclient.data.l[0] == 2 ? "user" : "INVALID"))));
|
2007-03-19 17:59:16 +00:00
|
|
|
/* XXX make use of data.l[2] ! */
|
|
|
|
event_curtime = e->xclient.data.l[1];
|
2007-03-02 02:23:00 +00:00
|
|
|
client_activate(client, FALSE,
|
|
|
|
(e->xclient.data.l[0] == 0 ||
|
2007-03-19 17:59:16 +00:00
|
|
|
e->xclient.data.l[0] == 2));
|
2003-09-26 18:18:15 +00:00
|
|
|
} else if (msgtype == prop_atoms.net_wm_moveresize) {
|
2007-03-11 05:00:56 +00:00
|
|
|
ob_debug("net_wm_moveresize for 0x%lx direction %d\n",
|
|
|
|
client->window, e->xclient.data.l[2]);
|
2003-04-17 05:43:41 +00:00
|
|
|
if ((Atom)e->xclient.data.l[2] ==
|
|
|
|
prop_atoms.net_wm_moveresize_size_topleft ||
|
|
|
|
(Atom)e->xclient.data.l[2] ==
|
|
|
|
prop_atoms.net_wm_moveresize_size_top ||
|
|
|
|
(Atom)e->xclient.data.l[2] ==
|
|
|
|
prop_atoms.net_wm_moveresize_size_topright ||
|
|
|
|
(Atom)e->xclient.data.l[2] ==
|
|
|
|
prop_atoms.net_wm_moveresize_size_right ||
|
|
|
|
(Atom)e->xclient.data.l[2] ==
|
|
|
|
prop_atoms.net_wm_moveresize_size_right ||
|
|
|
|
(Atom)e->xclient.data.l[2] ==
|
|
|
|
prop_atoms.net_wm_moveresize_size_bottomright ||
|
|
|
|
(Atom)e->xclient.data.l[2] ==
|
|
|
|
prop_atoms.net_wm_moveresize_size_bottom ||
|
|
|
|
(Atom)e->xclient.data.l[2] ==
|
|
|
|
prop_atoms.net_wm_moveresize_size_bottomleft ||
|
|
|
|
(Atom)e->xclient.data.l[2] ==
|
|
|
|
prop_atoms.net_wm_moveresize_size_left ||
|
|
|
|
(Atom)e->xclient.data.l[2] ==
|
|
|
|
prop_atoms.net_wm_moveresize_move ||
|
|
|
|
(Atom)e->xclient.data.l[2] ==
|
|
|
|
prop_atoms.net_wm_moveresize_size_keyboard ||
|
|
|
|
(Atom)e->xclient.data.l[2] ==
|
|
|
|
prop_atoms.net_wm_moveresize_move_keyboard) {
|
|
|
|
|
|
|
|
moveresize_start(client, e->xclient.data.l[0],
|
2003-04-17 07:00:13 +00:00
|
|
|
e->xclient.data.l[1], e->xclient.data.l[3],
|
|
|
|
e->xclient.data.l[2]);
|
2003-04-17 05:43:41 +00:00
|
|
|
}
|
2007-03-11 05:00:56 +00:00
|
|
|
else if ((Atom)e->xclient.data.l[2] ==
|
|
|
|
prop_atoms.net_wm_moveresize_cancel)
|
|
|
|
moveresize_end(TRUE);
|
2003-04-17 05:43:41 +00:00
|
|
|
} else if (msgtype == prop_atoms.net_moveresize_window) {
|
2003-10-15 03:59:35 +00:00
|
|
|
gint oldg = client->gravity;
|
|
|
|
gint tmpg, x, y, w, h;
|
2003-04-17 05:43:41 +00:00
|
|
|
|
|
|
|
if (e->xclient.data.l[0] & 0xff)
|
|
|
|
tmpg = e->xclient.data.l[0] & 0xff;
|
|
|
|
else
|
|
|
|
tmpg = oldg;
|
|
|
|
|
|
|
|
if (e->xclient.data.l[0] & 1 << 8)
|
|
|
|
x = e->xclient.data.l[1];
|
|
|
|
else
|
|
|
|
x = client->area.x;
|
|
|
|
if (e->xclient.data.l[0] & 1 << 9)
|
|
|
|
y = e->xclient.data.l[2];
|
|
|
|
else
|
|
|
|
y = client->area.y;
|
|
|
|
if (e->xclient.data.l[0] & 1 << 10)
|
|
|
|
w = e->xclient.data.l[3];
|
|
|
|
else
|
2003-07-29 11:19:57 +00:00
|
|
|
w = client->area.width;
|
2003-04-17 05:43:41 +00:00
|
|
|
if (e->xclient.data.l[0] & 1 << 11)
|
|
|
|
h = e->xclient.data.l[4];
|
|
|
|
else
|
2003-07-29 11:19:57 +00:00
|
|
|
h = client->area.height;
|
2003-04-17 05:43:41 +00:00
|
|
|
client->gravity = tmpg;
|
2003-07-28 07:19:47 +00:00
|
|
|
|
2003-07-28 19:59:37 +00:00
|
|
|
{
|
2003-10-15 03:59:35 +00:00
|
|
|
gint newx = x;
|
|
|
|
gint newy = y;
|
|
|
|
gint fw = w +
|
|
|
|
client->frame->size.left + client->frame->size.right;
|
|
|
|
gint fh = h +
|
|
|
|
client->frame->size.top + client->frame->size.bottom;
|
2003-08-27 18:50:12 +00:00
|
|
|
client_find_onscreen(client, &newx, &newy, fw, fh,
|
2003-08-27 18:53:25 +00:00
|
|
|
client_normal(client));
|
2003-07-28 18:06:55 +00:00
|
|
|
if (e->xclient.data.l[0] & 1 << 8)
|
|
|
|
x = newx;
|
|
|
|
if (e->xclient.data.l[0] & 1 << 9)
|
|
|
|
y = newy;
|
|
|
|
}
|
2004-03-21 01:03:00 +00:00
|
|
|
|
2003-07-10 06:18:47 +00:00
|
|
|
client_configure(client, OB_CORNER_TOPLEFT,
|
|
|
|
x, y, w, h, FALSE, TRUE);
|
2003-07-28 07:19:47 +00:00
|
|
|
|
2003-04-17 05:43:41 +00:00
|
|
|
client->gravity = oldg;
|
|
|
|
}
|
2003-09-26 18:18:15 +00:00
|
|
|
break;
|
2003-03-16 21:11:39 +00:00
|
|
|
case PropertyNotify:
|
2003-09-26 18:18:15 +00:00
|
|
|
/* validate cuz we query stuff off the client here */
|
|
|
|
if (!client_validate(client)) break;
|
2003-03-16 21:11:39 +00:00
|
|
|
|
2003-09-26 18:18:15 +00:00
|
|
|
/* compress changes to a single property into a single change */
|
|
|
|
while (XCheckTypedWindowEvent(ob_display, client->window,
|
|
|
|
e->type, &ce)) {
|
2003-08-31 19:50:17 +00:00
|
|
|
Atom a, b;
|
|
|
|
|
|
|
|
/* XXX: it would be nice to compress ALL changes to a property,
|
2003-09-26 18:18:15 +00:00
|
|
|
not just changes in a row without other props between. */
|
2003-08-31 19:50:17 +00:00
|
|
|
|
|
|
|
a = ce.xproperty.atom;
|
|
|
|
b = e->xproperty.atom;
|
|
|
|
|
|
|
|
if (a == b)
|
|
|
|
continue;
|
|
|
|
if ((a == prop_atoms.net_wm_name ||
|
|
|
|
a == prop_atoms.wm_name ||
|
|
|
|
a == prop_atoms.net_wm_icon_name ||
|
|
|
|
a == prop_atoms.wm_icon_name)
|
|
|
|
&&
|
|
|
|
(b == prop_atoms.net_wm_name ||
|
|
|
|
b == prop_atoms.wm_name ||
|
|
|
|
b == prop_atoms.net_wm_icon_name ||
|
|
|
|
b == prop_atoms.wm_icon_name)) {
|
|
|
|
continue;
|
|
|
|
}
|
2007-03-11 00:59:13 +00:00
|
|
|
if (a == prop_atoms.net_wm_icon &&
|
|
|
|
b == prop_atoms.net_wm_icon)
|
2003-08-31 19:50:17 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
XPutBackEvent(ob_display, &ce);
|
|
|
|
break;
|
2003-09-26 18:18:15 +00:00
|
|
|
}
|
2003-03-16 21:11:39 +00:00
|
|
|
|
2003-09-26 18:18:15 +00:00
|
|
|
msgtype = e->xproperty.atom;
|
|
|
|
if (msgtype == XA_WM_NORMAL_HINTS) {
|
|
|
|
client_update_normal_hints(client);
|
|
|
|
/* normal hints can make a window non-resizable */
|
|
|
|
client_setup_decor_and_functions(client);
|
|
|
|
} else if (msgtype == XA_WM_HINTS) {
|
|
|
|
client_update_wmhints(client);
|
|
|
|
} else if (msgtype == XA_WM_TRANSIENT_FOR) {
|
|
|
|
client_update_transient_for(client);
|
|
|
|
client_get_type(client);
|
|
|
|
/* type may have changed, so update the layer */
|
|
|
|
client_calc_layer(client);
|
|
|
|
client_setup_decor_and_functions(client);
|
|
|
|
} else if (msgtype == prop_atoms.net_wm_name ||
|
2003-08-31 19:50:17 +00:00
|
|
|
msgtype == prop_atoms.wm_name ||
|
|
|
|
msgtype == prop_atoms.net_wm_icon_name ||
|
|
|
|
msgtype == prop_atoms.wm_icon_name) {
|
2003-09-26 18:18:15 +00:00
|
|
|
client_update_title(client);
|
|
|
|
} else if (msgtype == prop_atoms.wm_class) {
|
|
|
|
client_update_class(client);
|
2003-08-31 19:50:17 +00:00
|
|
|
} else if (msgtype == prop_atoms.wm_protocols) {
|
2003-09-26 18:18:15 +00:00
|
|
|
client_update_protocols(client);
|
|
|
|
client_setup_decor_and_functions(client);
|
|
|
|
}
|
|
|
|
else if (msgtype == prop_atoms.net_wm_strut) {
|
|
|
|
client_update_strut(client);
|
2003-07-28 19:53:54 +00:00
|
|
|
}
|
2007-03-11 00:59:13 +00:00
|
|
|
else if (msgtype == prop_atoms.net_wm_icon) {
|
2003-09-26 18:18:15 +00:00
|
|
|
client_update_icons(client);
|
2003-08-31 19:50:17 +00:00
|
|
|
}
|
2007-03-11 02:06:34 +00:00
|
|
|
else if (msgtype == prop_atoms.net_wm_user_time) {
|
2007-04-18 19:21:14 +00:00
|
|
|
client_update_user_time(client);
|
2007-03-11 02:06:34 +00:00
|
|
|
}
|
2003-09-15 06:50:13 +00:00
|
|
|
else if (msgtype == prop_atoms.sm_client_id) {
|
|
|
|
client_update_sm_client_id(client);
|
|
|
|
}
|
2003-03-24 19:07:28 +00:00
|
|
|
default:
|
|
|
|
;
|
|
|
|
#ifdef SHAPE
|
|
|
|
if (extensions_shape && e->type == extensions_shape_event_basep) {
|
2003-03-24 19:10:33 +00:00
|
|
|
client->shaped = ((XShapeEvent*)e)->shaped;
|
2003-04-13 07:18:28 +00:00
|
|
|
frame_adjust_shape(client->frame);
|
2003-03-24 19:07:28 +00:00
|
|
|
}
|
|
|
|
#endif
|
2003-03-16 21:11:39 +00:00
|
|
|
}
|
|
|
|
}
|
2003-04-16 05:36:51 +00:00
|
|
|
|
2003-07-10 16:29:40 +00:00
|
|
|
static void event_handle_dock(ObDock *s, XEvent *e)
|
2003-05-16 15:15:30 +00:00
|
|
|
{
|
|
|
|
switch (e->type) {
|
|
|
|
case ButtonPress:
|
2004-07-22 22:50:48 +00:00
|
|
|
if (e->xbutton.button == 1)
|
2007-03-12 02:27:58 +00:00
|
|
|
stacking_raise(DOCK_AS_WINDOW(s));
|
2004-07-22 22:50:48 +00:00
|
|
|
else if (e->xbutton.button == 2)
|
2007-03-12 02:27:58 +00:00
|
|
|
stacking_lower(DOCK_AS_WINDOW(s));
|
2003-05-22 05:23:41 +00:00
|
|
|
break;
|
2003-05-16 15:15:30 +00:00
|
|
|
case EnterNotify:
|
2003-05-16 18:10:10 +00:00
|
|
|
dock_hide(FALSE);
|
2003-05-16 15:15:30 +00:00
|
|
|
break;
|
|
|
|
case LeaveNotify:
|
2003-05-16 18:10:10 +00:00
|
|
|
dock_hide(TRUE);
|
2003-05-16 15:15:30 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-07-10 16:29:40 +00:00
|
|
|
static void event_handle_dockapp(ObDockApp *app, XEvent *e)
|
2003-05-10 20:52:32 +00:00
|
|
|
{
|
|
|
|
switch (e->type) {
|
2003-05-11 05:15:43 +00:00
|
|
|
case MotionNotify:
|
2003-05-16 18:10:10 +00:00
|
|
|
dock_app_drag(app, &e->xmotion);
|
2003-05-11 05:15:43 +00:00
|
|
|
break;
|
2003-05-10 20:52:32 +00:00
|
|
|
case UnmapNotify:
|
2003-09-26 18:18:15 +00:00
|
|
|
if (app->ignore_unmaps) {
|
|
|
|
app->ignore_unmaps--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
dock_remove(app, TRUE);
|
|
|
|
break;
|
2003-05-10 20:52:32 +00:00
|
|
|
case DestroyNotify:
|
2003-09-26 18:18:15 +00:00
|
|
|
dock_remove(app, FALSE);
|
|
|
|
break;
|
2003-05-10 20:52:32 +00:00
|
|
|
case ReparentNotify:
|
2003-09-26 18:18:15 +00:00
|
|
|
dock_remove(app, FALSE);
|
|
|
|
break;
|
2003-05-10 22:20:08 +00:00
|
|
|
case ConfigureNotify:
|
2003-05-16 18:10:10 +00:00
|
|
|
dock_app_configure(app, e->xconfigure.width, e->xconfigure.height);
|
2003-05-10 22:20:08 +00:00
|
|
|
break;
|
2003-05-10 20:52:32 +00:00
|
|
|
}
|
|
|
|
}
|
2003-08-28 02:10:23 +00:00
|
|
|
|
2003-08-29 08:44:55 +00:00
|
|
|
ObMenuFrame* find_active_menu()
|
|
|
|
{
|
|
|
|
GList *it;
|
2003-09-28 09:47:17 +00:00
|
|
|
ObMenuFrame *ret = NULL;
|
2003-08-29 08:44:55 +00:00
|
|
|
|
|
|
|
for (it = menu_frame_visible; it; it = g_list_next(it)) {
|
2003-09-28 09:47:17 +00:00
|
|
|
ret = it->data;
|
|
|
|
if (ret->selected)
|
2003-08-29 08:44:55 +00:00
|
|
|
break;
|
2003-09-28 09:47:17 +00:00
|
|
|
ret = NULL;
|
2003-08-29 08:44:55 +00:00
|
|
|
}
|
2003-09-28 09:47:17 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ObMenuFrame* find_active_or_last_menu()
|
|
|
|
{
|
|
|
|
ObMenuFrame *ret = NULL;
|
|
|
|
|
|
|
|
ret = find_active_menu();
|
|
|
|
if (!ret && menu_frame_visible)
|
|
|
|
ret = menu_frame_visible->data;
|
|
|
|
return ret;
|
2003-08-29 08:44:55 +00:00
|
|
|
}
|
|
|
|
|
2003-08-28 02:10:23 +00:00
|
|
|
static void event_handle_menu(XEvent *ev)
|
|
|
|
{
|
|
|
|
ObMenuFrame *f;
|
|
|
|
ObMenuEntryFrame *e;
|
|
|
|
|
|
|
|
switch (ev->type) {
|
|
|
|
case ButtonRelease:
|
2003-09-28 09:31:23 +00:00
|
|
|
if (menu_can_hide) {
|
|
|
|
if ((e = menu_entry_frame_under(ev->xbutton.x_root,
|
|
|
|
ev->xbutton.y_root)))
|
2007-03-11 04:44:15 +00:00
|
|
|
menu_entry_frame_execute(e, ev->xbutton.state,
|
|
|
|
ev->xbutton.time);
|
2003-09-28 09:31:23 +00:00
|
|
|
else
|
|
|
|
menu_frame_hide_all();
|
|
|
|
}
|
2003-08-28 02:10:23 +00:00
|
|
|
break;
|
2007-04-22 00:31:03 +00:00
|
|
|
case EnterNotify:
|
|
|
|
if ((e = g_hash_table_lookup(menu_frame_map, &ev->xcrossing.window))) {
|
|
|
|
if (e->ignore_enters)
|
|
|
|
--e->ignore_enters;
|
|
|
|
else
|
|
|
|
menu_frame_select(e->frame, e);
|
2003-08-28 02:10:23 +00:00
|
|
|
}
|
2007-04-22 00:31:03 +00:00
|
|
|
break;
|
|
|
|
case LeaveNotify:
|
2007-04-22 00:53:21 +00:00
|
|
|
if ((e = g_hash_table_lookup(menu_frame_map, &ev->xcrossing.window)) &&
|
|
|
|
(f = find_active_menu()) && f->selected == e &&
|
|
|
|
e->entry->type != OB_MENU_ENTRY_TYPE_SUBMENU)
|
|
|
|
{
|
|
|
|
menu_frame_select(e->frame, NULL);
|
2003-09-15 08:29:50 +00:00
|
|
|
}
|
2007-04-22 03:18:55 +00:00
|
|
|
case MotionNotify:
|
|
|
|
if ((e = menu_entry_frame_under(ev->xmotion.x_root,
|
|
|
|
ev->xmotion.y_root)))
|
|
|
|
menu_frame_select(e->frame, e);
|
|
|
|
break;
|
2003-08-29 08:44:55 +00:00
|
|
|
case KeyPress:
|
|
|
|
if (ev->xkey.keycode == ob_keycode(OB_KEY_ESCAPE))
|
|
|
|
menu_frame_hide_all();
|
|
|
|
else if (ev->xkey.keycode == ob_keycode(OB_KEY_RETURN)) {
|
|
|
|
ObMenuFrame *f;
|
|
|
|
if ((f = find_active_menu()))
|
2007-03-11 04:44:15 +00:00
|
|
|
menu_entry_frame_execute(f->selected, ev->xkey.state,
|
|
|
|
ev->xkey.time);
|
2003-08-29 08:44:55 +00:00
|
|
|
} else if (ev->xkey.keycode == ob_keycode(OB_KEY_LEFT)) {
|
|
|
|
ObMenuFrame *f;
|
2003-09-28 09:47:17 +00:00
|
|
|
if ((f = find_active_or_last_menu()) && f->parent)
|
2003-08-29 08:44:55 +00:00
|
|
|
menu_frame_select(f, NULL);
|
|
|
|
} else if (ev->xkey.keycode == ob_keycode(OB_KEY_RIGHT)) {
|
|
|
|
ObMenuFrame *f;
|
2003-09-28 09:47:17 +00:00
|
|
|
if ((f = find_active_or_last_menu()) && f->child)
|
2003-08-29 08:52:12 +00:00
|
|
|
menu_frame_select_next(f->child);
|
2003-08-29 08:44:55 +00:00
|
|
|
} else if (ev->xkey.keycode == ob_keycode(OB_KEY_UP)) {
|
|
|
|
ObMenuFrame *f;
|
2003-09-28 09:47:17 +00:00
|
|
|
if ((f = find_active_or_last_menu()))
|
2003-08-29 08:44:55 +00:00
|
|
|
menu_frame_select_previous(f);
|
|
|
|
} else if (ev->xkey.keycode == ob_keycode(OB_KEY_DOWN)) {
|
|
|
|
ObMenuFrame *f;
|
2003-09-28 09:47:17 +00:00
|
|
|
if ((f = find_active_or_last_menu()))
|
2003-08-29 08:44:55 +00:00
|
|
|
menu_frame_select_next(f);
|
|
|
|
}
|
2003-08-29 08:49:41 +00:00
|
|
|
break;
|
2003-08-28 02:10:23 +00:00
|
|
|
}
|
|
|
|
}
|
2003-09-03 08:12:07 +00:00
|
|
|
|
2003-09-10 19:37:52 +00:00
|
|
|
static gboolean menu_hide_delay_func(gpointer data)
|
|
|
|
{
|
|
|
|
menu_can_hide = TRUE;
|
|
|
|
return FALSE; /* no repeat */
|
|
|
|
}
|
|
|
|
|
2007-04-22 04:16:00 +00:00
|
|
|
static void focus_delay_dest(gpointer data)
|
|
|
|
{
|
|
|
|
g_free(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean focus_delay_cmp(gconstpointer d1, gconstpointer d2)
|
|
|
|
{
|
2007-04-22 18:26:05 +00:00
|
|
|
const ObFocusDelayData *f1 = d1;
|
|
|
|
return f1->client == d2;
|
2007-04-22 04:16:00 +00:00
|
|
|
}
|
|
|
|
|
2007-04-22 02:34:05 +00:00
|
|
|
static gboolean focus_delay_func(gpointer data)
|
|
|
|
{
|
2007-04-22 04:16:00 +00:00
|
|
|
ObFocusDelayData *d = data;
|
2007-04-22 02:34:05 +00:00
|
|
|
Time old = event_curtime;
|
2007-04-22 04:16:00 +00:00
|
|
|
|
|
|
|
event_curtime = d->time;
|
|
|
|
if (focus_client != d->client) {
|
|
|
|
if (client_focus(d->client) && config_focus_raise)
|
|
|
|
client_raise(d->client);
|
2003-09-29 08:02:16 +00:00
|
|
|
}
|
2007-04-22 02:34:05 +00:00
|
|
|
event_curtime = old;
|
2003-09-03 08:12:07 +00:00
|
|
|
return FALSE; /* no repeat */
|
|
|
|
}
|
|
|
|
|
2003-09-28 06:31:00 +00:00
|
|
|
static void focus_delay_client_dest(ObClient *client, gpointer data)
|
2003-09-03 08:12:07 +00:00
|
|
|
{
|
2007-04-22 04:16:00 +00:00
|
|
|
ob_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func,
|
|
|
|
client, FALSE);
|
2003-09-03 08:12:07 +00:00
|
|
|
}
|
2003-09-21 18:10:39 +00:00
|
|
|
|
2003-10-09 18:48:44 +00:00
|
|
|
void event_halt_focus_delay()
|
|
|
|
{
|
|
|
|
ob_main_loop_timeout_remove(ob_main_loop, focus_delay_func);
|
|
|
|
}
|
|
|
|
|
2003-09-22 04:18:54 +00:00
|
|
|
void event_ignore_queued_enters()
|
2003-09-21 18:10:39 +00:00
|
|
|
{
|
2003-09-22 04:18:54 +00:00
|
|
|
GSList *saved = NULL, *it;
|
|
|
|
XEvent *e;
|
|
|
|
|
|
|
|
XSync(ob_display, FALSE);
|
|
|
|
|
|
|
|
/* count the events */
|
|
|
|
while (TRUE) {
|
|
|
|
e = g_new(XEvent, 1);
|
|
|
|
if (XCheckTypedEvent(ob_display, EnterNotify, e)) {
|
2003-10-02 04:06:40 +00:00
|
|
|
ObWindow *win;
|
|
|
|
|
|
|
|
win = g_hash_table_lookup(window_map, &e->xany.window);
|
2003-10-03 04:20:23 +00:00
|
|
|
if (win && WINDOW_IS_CLIENT(win))
|
2003-10-02 04:06:40 +00:00
|
|
|
++ignore_enter_focus;
|
|
|
|
|
2003-09-22 04:18:54 +00:00
|
|
|
saved = g_slist_append(saved, e);
|
|
|
|
} else {
|
|
|
|
g_free(e);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* put the events back */
|
|
|
|
for (it = saved; it; it = g_slist_next(it)) {
|
|
|
|
XPutBackEvent(ob_display, it->data);
|
|
|
|
g_free(it->data);
|
|
|
|
}
|
|
|
|
g_slist_free(saved);
|
2003-09-21 18:10:39 +00:00
|
|
|
}
|
2007-03-28 01:52:06 +00:00
|
|
|
|
|
|
|
gboolean event_time_after(Time t1, Time t2)
|
|
|
|
{
|
2007-04-18 19:21:14 +00:00
|
|
|
g_assert(t1 != CurrentTime);
|
|
|
|
g_assert(t2 != CurrentTime);
|
|
|
|
|
2007-03-28 01:52:06 +00:00
|
|
|
/*
|
|
|
|
Timestamp values wrap around (after about 49.7 days). The server, given
|
|
|
|
its current time is represented by timestamp T, always interprets
|
|
|
|
timestamps from clients by treating half of the timestamp space as being
|
|
|
|
later in time than T.
|
|
|
|
- http://tronche.com/gui/x/xlib/input/pointer-grabbing.html
|
|
|
|
*/
|
2007-03-28 04:07:27 +00:00
|
|
|
|
|
|
|
/* TIME_HALF is half of the number space of a Time type variable */
|
|
|
|
#define TIME_HALF (Time)(1 << (sizeof(Time)*8-1))
|
|
|
|
|
|
|
|
if (t2 >= TIME_HALF)
|
|
|
|
/* t2 is in the second half so t1 might wrap around and be smaller than
|
|
|
|
t2 */
|
|
|
|
return t1 >= t2 || t1 < (t2 + TIME_HALF);
|
|
|
|
else
|
|
|
|
/* t2 is in the first half so t1 has to come after it */
|
|
|
|
return t1 >= t2 && t1 < (t2 + TIME_HALF);
|
2007-03-28 01:52:06 +00:00
|
|
|
}
|