+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+ event.c for the Openbox window manager
+ Copyright (c) 2003 Ben 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 "debug.h"
#include "openbox.h"
#include "dock.h"
#include "screen.h"
#include "frame.h"
#include "menu.h"
+#include "menuframe.h"
+#include "keyboard.h"
+#include "mouse.h"
+#include "mainloop.h"
#include "framerender.h"
#include "focus.h"
#include "moveresize.h"
+#include "group.h"
#include "stacking.h"
#include "extensions.h"
-#include "timer.h"
-#include "dispatch.h"
#include "event.h"
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <glib.h>
-#ifdef USE_LIBSN
-# include <libsn/sn.h>
-#endif
-
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
#endif
#include <X11/ICE/ICElib.h>
#endif
-static void event_process(XEvent *e);
+typedef struct
+{
+ gboolean ignored;
+} ObEventData;
+
+static void event_process(const XEvent *e, gpointer data);
static void event_handle_root(XEvent *e);
+static void event_handle_menu(XEvent *e);
static void event_handle_dock(ObDock *s, XEvent *e);
static void event_handle_dockapp(ObDockApp *app, XEvent *e);
static void event_handle_client(ObClient *c, XEvent *e);
-static void event_handle_menu(ObClient *c, XEvent *e);
-static void fd_event_handle();
-#ifdef USE_SM
-static void ice_watch(IceConn conn, IcePointer data, Bool opening,
- IcePointer *watch_data);
-#endif
-static void find_max_fd();
+static void event_handle_group(ObGroup *g, XEvent *e);
+
+static gboolean focus_delay_func(gpointer data);
+static void focus_delay_client_dest(gpointer data);
+
+static gboolean menu_hide_delay_func(gpointer data);
#define INVALID_FOCUSIN(e) ((e)->xfocus.detail == NotifyInferior || \
(e)->xfocus.detail == NotifyAncestor || \
};
static int mask_table_size;
-static fd_set selset, allset;
-#ifdef USE_SM
-static IceConn ice_conn;
-static int ice_fd;
-#endif
-static int max_fd, x_fd;
-static GData *fd_handler_list;
+static ObClient *focus_delay_client;
+static gboolean menu_can_hide;
#ifdef USE_SM
+static void ice_handler(int fd, gpointer conn)
+{
+ Bool b;
+ IceProcessMessages(conn, NULL, &b);
+}
+
static void ice_watch(IceConn conn, IcePointer data, Bool opening,
IcePointer *watch_data)
{
+ static gint fd = -1;
+
if (opening) {
- g_assert (ice_fd < 0);
- ice_conn = conn;
- ice_fd = IceConnectionNumber(conn);
- FD_SET(ice_fd, &allset);
+ fd = IceConnectionNumber(conn);
+ ob_main_loop_fd_add(ob_main_loop, fd, ice_handler, conn, NULL);
} else {
- FD_CLR(ice_fd, &allset);
- ice_fd = -1;
+ ob_main_loop_fd_remove(ob_main_loop, fd);
+ fd = -1;
}
- find_max_fd();
}
#endif
-void event_startup()
+void event_startup(gboolean reconfig)
{
+ if (reconfig) return;
+
mask_table_size = sizeof(mask_table) / sizeof(mask_table[0]);
/* get lock masks that are defined by the display (not constant) */
}
}
- FD_ZERO(&allset);
- max_fd = x_fd = ConnectionNumber(ob_display);
- FD_SET(x_fd, &allset);
+ ob_main_loop_x_add(ob_main_loop, event_process, NULL, NULL);
#ifdef USE_SM
- ice_fd = -1;
IceAddConnectionWatch(ice_watch, NULL);
#endif
- g_datalist_init(&fd_handler_list);
+ client_add_destructor(focus_delay_client_dest);
}
-void event_shutdown()
+void event_shutdown(gboolean reconfig)
{
- XFreeModifiermap(modmap);
- g_datalist_clear(&fd_handler_list);
-}
-
-void event_loop()
-{
- XEvent e;
- struct timeval *wait;
- gboolean had_event = FALSE;
-
- while (XPending(ob_display)) {
- XNextEvent(ob_display, &e);
-
-#ifdef USE_LIBSN
- sn_display_process_event(ob_sn_display, &e);
-#endif
-
- event_process(&e);
- had_event = TRUE;
- }
-
- if (!had_event) {
- timer_dispatch((GTimeVal**)&wait);
- selset = allset;
- select(max_fd + 1, &selset, NULL, NULL, wait);
-
- /* handle the X events as soon as possible? */
- if (FD_ISSET(x_fd, &selset))
- return;
+ if (reconfig) return;
#ifdef USE_SM
- if (ice_fd >= 0 && FD_ISSET(ice_fd, &selset)) {
- Bool b;
- IceProcessMessages(ice_conn, NULL, &b);
- }
+ IceRemoveConnectionWatch(ice_watch, NULL);
#endif
- fd_event_handle();
- }
+ client_remove_destructor(focus_delay_client_dest);
+ XFreeModifiermap(modmap);
}
static Window event_get_window(XEvent *e)
default:
#ifdef XKB
if (extensions_xkb && e->type == extensions_xkb_event_basep) {
- switch (((XkbAnyEvent*)&e)->xkb_type) {
+ switch (((XkbAnyEvent*)e)->xkb_type) {
case XkbBellNotify:
- window = ((XkbBellNotifyEvent*)&e)->window;
+ window = ((XkbBellNotifyEvent*)e)->window;
default:
window = None;
}
static void event_set_lasttime(XEvent *e)
{
+ Time t = 0;
+
/* grab the lasttime and hack up the state */
switch (e->type) {
case ButtonPress:
case ButtonRelease:
- event_lasttime = e->xbutton.time;
+ t = e->xbutton.time;
break;
case KeyPress:
- event_lasttime = e->xkey.time;
+ t = e->xkey.time;
break;
case KeyRelease:
- event_lasttime = e->xkey.time;
+ t = e->xkey.time;
break;
case MotionNotify:
- event_lasttime = e->xmotion.time;
+ t = e->xmotion.time;
break;
case PropertyNotify:
- event_lasttime = e->xproperty.time;
+ t = e->xproperty.time;
break;
case EnterNotify:
case LeaveNotify:
- event_lasttime = e->xcrossing.time;
+ t = e->xcrossing.time;
break;
default:
- event_lasttime = CurrentTime;
+ /* if more event types are anticipated, get their timestamp
+ explicitly */
break;
}
+
+ if (t > event_lasttime)
+ event_lasttime = t;
}
#define STRIP_MODS(s) \
if (INVALID_FOCUSIN(e) ||
client == NULL) {
#ifdef DEBUG_FOCUS
- ob_debug("FocusIn on %lx mode %d detail %d IGNORED\n",
- e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
+ ob_debug("FocusIn on %lx mode %d detail %d IGNORED\n",
+ e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
#endif
/* says a client was not found for the event (or a valid FocusIn
event was not found.
gboolean fallback = TRUE;
while (TRUE) {
- if (!XCheckTypedWindowEvent(ob_display, FocusOut,
- e->xfocus.window,&fe))
+ if (!XCheckTypedWindowEvent(ob_display, e->xfocus.window,
+ FocusOut, &fe))
if (!XCheckTypedEvent(ob_display, FocusIn, &fe))
break;
if (fe.type == FocusOut) {
#ifdef DEBUG_FOCUS
- ob_debug("found pending FocusOut");
+ ob_debug("found pending FocusOut\n");
#endif
if (!INVALID_FOCUSOUT(&fe)) {
/* if there is a VALID FocusOut still coming, don't
}
} else {
#ifdef DEBUG_FOCUS
- ob_debug("found pending FocusIn");
+ ob_debug("found pending FocusIn\n");
#endif
/* is the focused window getting a FocusOut/In back to
itself?
if (focus_client) {
#ifdef DEBUG_FOCUS
ob_debug("focused window got an Out/In back to "
- "itself IGNORED both");
+ "itself IGNORED both\n");
#endif
return TRUE;
} else {
- event_process(&fe);
+ event_process(&fe, NULL);
#ifdef DEBUG_FOCUS
ob_debug("focused window got an Out/In back to "
"itself but focus_client was null "
- "IGNORED just the Out");
+ "IGNORED just the Out\n");
#endif
return TRUE;
}
}
- /* once all the FocusOut's have been dealt with, if there
- is a FocusIn still left and it is valid, then use it */
- event_process(&fe);
- /* secret magic way of event_process telling us that no
- client was found for the FocusIn event. ^_^ */
- if (fe.xfocus.window != None) {
- fallback = FALSE;
- break;
+ {
+ ObEventData d;
+
+ /* once all the FocusOut's have been dealt with, if
+ there is a FocusIn still left and it is valid, then
+ use it */
+ event_process(&fe, &d);
+ if (!d.ignored) {
+#ifdef DEBUG_FOCUS
+ ob_debug("FocusIn was OK, so don't fallback\n");
+#endif
+ fallback = FALSE;
+ break;
+ }
}
}
}
if (fallback) {
#ifdef DEBUG_FOCUS
ob_debug("no valid FocusIn and no FocusOut events found, "
- "falling back");
+ "falling back\n");
#endif
focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS);
}
case LeaveNotify:
/* NotifyUngrab occurs when a mouse button is released and the event is
caused, like when lowering a window */
- /* NotifyVirtual occurs when ungrabbing the pointer */
+ /* NotifyVirtual and NotifyAncestor occurs when ungrabbing the
+ pointer (Ancestor happens when the pointer is on a window border) */
if (e->xcrossing.mode == NotifyGrab ||
e->xcrossing.detail == NotifyInferior ||
(e->xcrossing.mode == NotifyUngrab &&
- e->xcrossing.detail == NotifyVirtual)) {
+ (e->xcrossing.detail == NotifyAncestor ||
+ e->xcrossing.detail == NotifyNonlinearVirtual ||
+ e->xcrossing.detail == NotifyVirtual))) {
#ifdef DEBUG_FOCUS
- ob_debug("%sNotify mode %d detail %d on %lx IGNORED",
+ ob_debug("%sNotify mode %d detail %d on %lx IGNORED\n",
(e->type == EnterNotify ? "Enter" : "Leave"),
e->xcrossing.mode,
e->xcrossing.detail, client?client->window:0);
return TRUE;
}
#ifdef DEBUG_FOCUS
- ob_debug("%sNotify mode %d detail %d on %lx",
+ ob_debug("%sNotify mode %d detail %d on %lx\n",
(e->type == EnterNotify ? "Enter" : "Leave"),
e->xcrossing.mode,
e->xcrossing.detail, client?client->window:0);
return FALSE;
}
-static void event_process(XEvent *e)
+static void event_process(const XEvent *ec, gpointer data)
{
Window window;
+ ObGroup *group = NULL;
ObClient *client = NULL;
ObDock *dock = NULL;
ObDockApp *dockapp = NULL;
- ObMenu *menu = NULL;
ObWindow *obwin = NULL;
+ XEvent ee, *e;
+ ObEventData *ed = data;
+
+ /* make a copy we can mangle */
+ ee = *ec;
+ e = ⅇ
window = event_get_window(e);
- 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_Menu:
- menu = WINDOW_AS_MENU(obwin);
- break;
- case Window_Client:
- client = WINDOW_AS_CLIENT(obwin);
- break;
- case Window_Internal:
- /* not to be used for events */
- g_assert_not_reached();
- break;
+ 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;
+ }
}
- }
event_set_lasttime(e);
event_hack_mods(e);
- if (event_ignore(e, client))
+ if (event_ignore(e, client)) {
+ if (ed)
+ ed->ignored = TRUE;
return;
+ } else if (ed)
+ ed->ignored = FALSE;
/* deal with it in the kernel */
- if (client)
+ if (group)
+ event_handle_group(group, e);
+ else if (client)
event_handle_client(client, e);
else if (dockapp)
event_handle_dockapp(dockapp, e);
xerror_set_ignore(FALSE);
}
- if (menu_visible)
- if (e->type == MotionNotify || e->type == ButtonRelease ||
- e->type == ButtonPress ||
- e->type == KeyPress || e->type == KeyRelease) {
- event_handle_menu(client, e);
-
- return; /* no dispatch! */
- }
-
- if (moveresize_in_progress)
- if (e->type == MotionNotify || e->type == ButtonRelease ||
- e->type == ButtonPress ||
- e->type == KeyPress || e->type == KeyRelease) {
- moveresize_event(e);
-
- return; /* no dispatch! */
-
- }
-
/* user input (action-bound) events */
- /*
if (e->type == ButtonPress || e->type == ButtonRelease ||
- e->type == MotionNotify)
- mouse_event(e, client);
- else if (e->type == KeyPress || e->type == KeyRelease)
- ;
- */
-
- /* dispatch the event to registered handlers */
- dispatch_x(e, client);
+ e->type == MotionNotify || e->type == KeyPress ||
+ e->type == KeyRelease)
+ {
+ if (menu_frame_visible)
+ event_handle_menu(e);
+ else {
+ if (!keyboard_process_interactive_grab(e, &client)) {
+ if (moveresize_in_progress)
+ moveresize_event(e);
+
+ menu_can_hide = FALSE;
+ ob_main_loop_timeout_add(ob_main_loop,
+ G_USEC_PER_SEC / 4,
+ menu_hide_delay_func,
+ NULL, NULL);
+
+ if (e->type == ButtonPress || e->type == ButtonRelease ||
+ e->type == MotionNotify)
+ mouse_event(client, e);
+ else if (e->type == KeyPress)
+ /* when in the middle of a focus cycling action, this
+ causes the window which appears to be focused to be
+ the one on which the actions will be executed */
+ keyboard_event((focus_cycle_target ?
+ focus_cycle_target :
+ (client ? client : focus_client)), e);
+ }
+ }
+ }
}
static void event_handle_root(XEvent *e)
switch(e->type) {
case SelectionClear:
ob_debug("Another WM has requested to replace us. Exiting.\n");
- ob_exit();
+ ob_exit(0);
break;
case ClientMessage:
}
}
+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);
+}
+
static void event_handle_client(ObClient *client, XEvent *e)
{
XEvent ce;
ObFrameContext con;
switch (e->type) {
+ case VisibilityNotify:
+ client->frame->obscured = e->xvisibility.state != VisibilityUnobscured;
+ break;
case ButtonPress:
case ButtonRelease:
/* 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)) {
- switch (frame_context(client, e->xbutton.window)) {
+ con = frame_context(client, e->xbutton.window);
+ con = mouse_button_frame_context(con, e->xbutton.button);
+ switch (con) {
case OB_FRAME_CONTEXT_MAXIMIZE:
client->frame->max_press = (e->type == ButtonPress);
framerender_frame(client->frame);
client->frame->close_hover = FALSE;
frame_adjust_state(client->frame);
break;
+ case OB_FRAME_CONTEXT_FRAME:
+ /* XXX if doing a 'reconfigure' make sure you kill this timer,
+ maybe all timers.. */
+ if (config_focus_delay && client == focus_delay_client) {
+ ob_main_loop_timeout_remove_data(ob_main_loop,
+ focus_delay_func,
+ focus_delay_client);
+ focus_delay_client = NULL;
+ }
default:
break;
}
break;
case OB_FRAME_CONTEXT_FRAME:
if (client_normal(client)) {
- if (ob_state() == OB_STATE_STARTING) {
- /* move it to the top of the focus order */
- guint desktop = client->desktop;
- if (desktop == DESKTOP_ALL) desktop = screen_desktop;
- focus_order[desktop] = g_list_remove(focus_order[desktop],
- client);
- focus_order[desktop] = g_list_prepend(focus_order[desktop],
- client);
- } else if (config_focus_follow) {
+ if (config_focus_follow) {
#ifdef DEBUG_FOCUS
ob_debug("EnterNotify on %lx, focusing window\n",
client->window);
#endif
- client_focus(client);
+ if (config_focus_delay) {
+ ob_main_loop_timeout_add(ob_main_loop,
+ config_focus_delay,
+ focus_delay_func,
+ client, NULL);
+ focus_delay_client = client;
+ } else
+ client_focus(client);
}
}
break;
/* if we are iconic (or shaded (fvwm does this)) ignore the event */
if (client->iconic || client->shaded) return;
- if (e->xconfigurerequest.value_mask & CWBorderWidth)
- client->border_width = e->xconfigurerequest.border_width;
-
/* resize, then move, as specified in the EWMH section 7.7 */
if (e->xconfigurerequest.value_mask & (CWWidth | CWHeight |
- CWX | CWY)) {
+ CWX | CWY |
+ CWBorderWidth)) {
int x, y, w, h;
ObCorner corner;
+ if (e->xconfigurerequest.value_mask & CWBorderWidth)
+ client->border_width = e->xconfigurerequest.border_width;
+
x = (e->xconfigurerequest.value_mask & CWX) ?
e->xconfigurerequest.x : client->area.x;
y = (e->xconfigurerequest.value_mask & CWY) ?
{
int newx = x;
int newy = y;
- client_find_onscreen(client, &newx, &newy, w, h, TRUE);
+ int fw = w +
+ client->frame->size.left + client->frame->size.right;
+ int fh = h +
+ client->frame->size.top + client->frame->size.bottom;
+ client_find_onscreen(client, &newx, &newy, fw, fh,
+ client_normal(client));
if (e->xconfigurerequest.value_mask & CWX)
x = newx;
if (e->xconfigurerequest.value_mask & CWY)
corner = OB_CORNER_TOPLEFT;
}
- client_configure(client, corner, x, y, w, h, FALSE, TRUE);
+ client_configure_full(client, corner, x, y, w, h, FALSE, TRUE,
+ TRUE);
}
if (e->xconfigurerequest.value_mask & CWStackMode) {
msgtype = e->xclient.message_type;
if (msgtype == prop_atoms.wm_change_state) {
/* compress changes into a single change */
- while (XCheckTypedWindowEvent(ob_display, e->type,
- client->window, &ce)) {
+ 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. */
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, e->type,
- client->window, &ce)) {
+ 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. */
client_close(client);
} else if (msgtype == prop_atoms.net_active_window) {
ob_debug("net_active_window for 0x%lx\n", client->window);
- client_activate(client);
+ client_activate(client, FALSE);
} else if (msgtype == prop_atoms.net_wm_moveresize) {
ob_debug("net_wm_moveresize for 0x%lx\n", client->window);
if ((Atom)e->xclient.data.l[2] ==
if (e->xclient.data.l[0] & 1 << 10)
w = e->xclient.data.l[3];
else
- w = client->area.y;
+ w = client->area.width;
if (e->xclient.data.l[0] & 1 << 11)
h = e->xclient.data.l[4];
else
- h = client->area.y;
+ h = client->area.height;
client->gravity = tmpg;
{
int newx = x;
int newy = y;
- client_find_onscreen(client, &newx, &newy, w, h, TRUE);
+ int fw = w +
+ client->frame->size.left + client->frame->size.right;
+ int fh = h +
+ client->frame->size.top + client->frame->size.bottom;
+ client_find_onscreen(client, &newx, &newy, fw, fh,
+ client_normal(client));
if (e->xclient.data.l[0] & 1 << 8)
x = newx;
if (e->xclient.data.l[0] & 1 << 9)
if (!client_validate(client)) break;
/* compress changes to a single property into a single change */
- while (XCheckTypedWindowEvent(ob_display, e->type,
- client->window, &ce)) {
- /* XXX: it would be nice to compress ALL changes to a property,
+ while (XCheckTypedWindowEvent(ob_display, client->window,
+ e->type, &ce)) {
+ Atom a, b;
+
+ /* XXX: it would be nice to compress ALL changes to a property,
not just changes in a row without other props between. */
- if (ce.xproperty.atom != e->xproperty.atom) {
- XPutBackEvent(ob_display, &ce);
- break;
- }
+
+ 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;
+ }
+ if ((a == prop_atoms.net_wm_icon ||
+ a == prop_atoms.kwm_win_icon)
+ &&
+ (b == prop_atoms.net_wm_icon ||
+ b == prop_atoms.kwm_win_icon))
+ continue;
+
+ XPutBackEvent(ob_display, &ce);
+ break;
}
msgtype = e->xproperty.atom;
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)
+ } else if (msgtype == XA_WM_HINTS) {
client_update_wmhints(client);
- else if (msgtype == XA_WM_TRANSIENT_FOR) {
+ } 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 ||
- msgtype == prop_atoms.wm_name ||
- msgtype == prop_atoms.net_wm_icon_name ||
- msgtype == prop_atoms.wm_icon_name)
+ } else if (msgtype == prop_atoms.net_wm_name ||
+ msgtype == prop_atoms.wm_name ||
+ msgtype == prop_atoms.net_wm_icon_name ||
+ msgtype == prop_atoms.wm_icon_name) {
client_update_title(client);
- else if (msgtype == prop_atoms.wm_class)
+ } else if (msgtype == prop_atoms.wm_class) {
client_update_class(client);
- else if (msgtype == prop_atoms.wm_protocols) {
+ } else if (msgtype == prop_atoms.wm_protocols) {
client_update_protocols(client);
client_setup_decor_and_functions(client);
}
else if (msgtype == prop_atoms.net_wm_strut) {
- g_message("strut change");
client_update_strut(client);
}
else if (msgtype == prop_atoms.net_wm_icon ||
- msgtype == prop_atoms.kwm_win_icon)
+ msgtype == prop_atoms.kwm_win_icon) {
client_update_icons(client);
+ }
+ else if (msgtype == prop_atoms.sm_client_id) {
+ client_update_sm_client_id(client);
+ }
default:
;
#ifdef SHAPE
}
}
-static void event_handle_menu(ObClient *client, XEvent *e)
-{
- ObMenuEntry *entry;
- ObMenu *top;
- GList *it = NULL;
-
- top = g_list_nth_data(menu_visible, 0);
-
- ob_debug("EVENT %d\n", e->type);
- switch (e->type) {
- case KeyPress:
- menu_control_keyboard_nav(e->xkey.keycode);
- break;
- case ButtonPress:
- ob_debug("BUTTON PRESS\n");
-
- break;
- case ButtonRelease:
- ob_debug("BUTTON RELEASED\n");
-
- for (it = menu_visible; it; it = g_list_next(it)) {
- ObMenu *m = it->data;
- if (e->xbutton.x_root >= m->location.x - ob_rr_theme->bwidth &&
- e->xbutton.y_root >= m->location.y - ob_rr_theme->bwidth &&
- e->xbutton.x_root < m->location.x + m->size.width +
- ob_rr_theme->bwidth &&
- e->xbutton.y_root < m->location.y + m->size.height +
- ob_rr_theme->bwidth) {
- if ((entry = menu_find_entry_by_pos(it->data,
- e->xbutton.x_root -
- m->location.x,
- e->xbutton.y_root -
- m->location.y))) {
- m->selected(entry, e->xbutton.button,
- e->xbutton.x_root,
- e->xbutton.y_root);
- break;
- }
- break;
- }
- }
-
- /* will call the menu_hide() for each submenu as well */
- if (!it)
- menu_control_keyboard_nav(ob_keycode(OB_KEY_ESCAPE));
-
- break;
- case MotionNotify:
- ob_debug("motion\n");
- for (it = menu_visible; it; it = g_list_next(it)) {
- ObMenu *m = it->data;
- if ((entry = menu_find_entry_by_pos(it->data,
- e->xmotion.x_root -
- m->location.x,
- e->xmotion.y_root -
- m->location.y))) {
- if (m->over && m->over->data != entry)
- m->mouseover(m->over->data, FALSE);
-
- m->mouseover(entry, TRUE);
- break;
- }
- }
-
- break;
- }
-}
-
-void event_add_fd_handler(event_fd_handler *h) {
- g_datalist_id_set_data(&fd_handler_list, h->fd, h);
- FD_SET(h->fd, &allset);
- max_fd = MAX(max_fd, h->fd);
-}
-
-static void find_max_fd_foreach(GQuark n, gpointer data, gpointer max)
-{
- *((unsigned int *)max) = MAX(*((unsigned int *)max), n);
-}
-
-static void find_max_fd()
-{
- int tmpmax = -1;
- g_datalist_foreach(&fd_handler_list, find_max_fd_foreach,
- (gpointer)&tmpmax);
- max_fd = MAX(x_fd, tmpmax);
-#ifdef USE_SM
- max_fd = MAX(ice_fd, tmpmax);
-#endif
-}
-
-void event_remove_fd(int n)
-{
- FD_CLR(n, &allset);
- g_datalist_id_remove_data(&fd_handler_list, (GQuark)n);
- find_max_fd();
-}
-
-static void fd_event_handle_foreach(GQuark n, gpointer data, gpointer user_data)
-{
- if (FD_ISSET( (int)n, &selset)) {
- event_fd_handler *h = (event_fd_handler *)data;
- g_assert(h->fd == (int)n);
- h->handler(h->fd, h->data);
- }
-}
-
-static void fd_event_handle()
-{
- g_datalist_foreach(&fd_handler_list, fd_event_handle_foreach, NULL);
-}
-
static void event_handle_dock(ObDock *s, XEvent *e)
{
switch (e->type) {
break;
}
}
+
+ObMenuFrame* find_active_menu()
+{
+ GList *it;
+ ObMenuFrame *f;
+
+ for (it = menu_frame_visible; it; it = g_list_next(it)) {
+ f = it->data;
+ if (f->selected)
+ break;
+ }
+ return it ? it->data : NULL;
+}
+
+static void event_handle_menu(XEvent *ev)
+{
+ ObMenuFrame *f;
+ ObMenuEntryFrame *e;
+
+ switch (ev->type) {
+ case ButtonRelease:
+ if ((e = menu_entry_frame_under(ev->xbutton.x_root,
+ ev->xbutton.y_root)))
+ menu_entry_frame_execute(e, ev->xbutton.state);
+ else if (menu_can_hide)
+ menu_frame_hide_all();
+ break;
+ case MotionNotify:
+ if ((f = menu_frame_under(ev->xmotion.x_root,
+ ev->xmotion.y_root))) {
+ menu_frame_move_on_screen(f);
+ if ((e = menu_entry_frame_under(ev->xmotion.x_root,
+ ev->xmotion.y_root)))
+ menu_frame_select(f, e);
+ }
+ {
+ ObMenuFrame *a;
+
+ a = find_active_menu();
+ if (a && a != f &&
+ a->selected->entry->type != OB_MENU_ENTRY_TYPE_SUBMENU)
+ {
+ menu_frame_select(a, NULL);
+ }
+ }
+ break;
+ 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()))
+ menu_entry_frame_execute(f->selected, ev->xkey.state);
+ } else if (ev->xkey.keycode == ob_keycode(OB_KEY_LEFT)) {
+ ObMenuFrame *f;
+ if ((f = find_active_menu()) && f->parent)
+ menu_frame_select(f, NULL);
+ } else if (ev->xkey.keycode == ob_keycode(OB_KEY_RIGHT)) {
+ ObMenuFrame *f;
+ if ((f = find_active_menu()) && f->child)
+ menu_frame_select_next(f->child);
+ } else if (ev->xkey.keycode == ob_keycode(OB_KEY_UP)) {
+ ObMenuFrame *f;
+ if ((f = find_active_menu()))
+ menu_frame_select_previous(f);
+ } else if (ev->xkey.keycode == ob_keycode(OB_KEY_DOWN)) {
+ ObMenuFrame *f;
+ if ((f = find_active_menu()))
+ menu_frame_select_next(f);
+ }
+ break;
+ }
+}
+
+static gboolean menu_hide_delay_func(gpointer data)
+{
+ menu_can_hide = TRUE;
+ return FALSE; /* no repeat */
+}
+
+static gboolean focus_delay_func(gpointer data)
+{
+ client_focus(focus_delay_client);
+ return FALSE; /* no repeat */
+}
+
+static void focus_delay_client_dest(gpointer data)
+{
+ ObClient *c = data;
+ if (c == focus_delay_client) {
+ ob_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func,
+ focus_delay_client);
+ focus_delay_client = NULL;
+ }
+}