static void event_ignore_enter_range(gulong start, gulong end);
static void focus_delay_dest(gpointer data);
-static gboolean focus_delay_cmp(gconstpointer d1, gconstpointer d2);
+static void unfocus_delay_dest(gpointer data);
static gboolean focus_delay_func(gpointer data);
static gboolean unfocus_delay_func(gpointer data);
static void focus_delay_client_dest(ObClient *client, gpointer data);
-Time event_last_user_time;
+Time event_last_user_time = CurrentTime;
/*! The time of the current X event (if it had a timestamp) */
-static Time event_curtime;
+static Time event_curtime = CurrentTime;
/*! The source time that started the current X event (user-provided, so not
to be trusted) */
-static Time event_sourcetime;
+static Time event_sourcetime = CurrentTime;
/*! The serial of the current X event */
static gulong event_curserial;
static gboolean waiting_for_focusin = FALSE;
/*! A list of ObSerialRanges which are to be ignored for mouse enter events */
static GSList *ignore_serials = NULL;
+static guint focus_delay_timeout_id = 0;
+static ObClient *focus_delay_timeout_client = NULL;
+static guint unfocus_delay_timeout_id = 0;
+static ObClient *unfocus_delay_timeout_client = NULL;
#ifdef USE_SM
-static void ice_handler(gint fd, gpointer conn)
+static gboolean ice_handler(GIOChannel *source, GIOCondition cond,
+ gpointer conn)
{
Bool b;
IceProcessMessages(conn, NULL, &b);
+ return TRUE; /* don't remove the event source */
}
static void ice_watch(IceConn conn, IcePointer data, Bool opening,
IcePointer *watch_data)
{
- static gint fd = -1;
+ static guint id = 0;
if (opening) {
- fd = IceConnectionNumber(conn);
- obt_main_loop_fd_add(ob_main_loop, fd, ice_handler, conn, NULL);
- } else {
- obt_main_loop_fd_remove(ob_main_loop, fd);
- fd = -1;
+ GIOChannel *ch;
+
+ ch = g_io_channel_unix_new(IceConnectionNumber(conn));
+ id = g_io_add_watch(ch, G_IO_IN, ice_handler, conn);
+ g_io_channel_unref(ch);
+ } else if (id) {
+ g_source_remove(id);
+ id = 0;
}
}
#endif
{
if (reconfig) return;
- obt_main_loop_x_add(ob_main_loop, event_process, NULL, NULL);
+ xqueue_add_callback(event_process, NULL);
#ifdef USE_SM
IceAddConnectionWatch(ice_watch, NULL);
#endif
client_add_destroy_notify(focus_delay_client_dest, NULL);
-
- event_curtime = CurrentTime;
- event_sourcetime = CurrentTime;
- event_last_user_time = CurrentTime;
}
void event_shutdown(gboolean reconfig)
which can happen if the clock goes backwards, we erase the last
specified user_time */
if (t && event_last_user_time && event_time_after(event_last_user_time, t))
- event_last_user_time = CurrentTime;
+ event_reset_user_time();
event_sourcetime = CurrentTime;
event_curtime = t;
static guint pressed = 0;
static Window pressed_win = None;
+ event_sourcetime = event_curtime;
+
/* If the button press was on some non-root window, or was physically
on the root window... */
if (window != obt_root(ob_screen) ||
/* ...or it if it was physically on an openbox
internal window... */
((w = window_find(e->xbutton.subwindow)) &&
- WINDOW_IS_INTERNAL(w)))
+ (WINDOW_IS_INTERNAL(w) || WINDOW_IS_DOCK(w))))
/* ...then process the event, otherwise ignore it */
{
used = event_handle_user_input(client, e);
+ if (prompt && !used)
+ used = event_handle_prompt(prompt, e);
+
if (e->type == ButtonPress) {
pressed = e->xbutton.button;
pressed_win = e->xbutton.subwindow;
else if (e->type == KeyPress || e->type == KeyRelease ||
e->type == MotionNotify)
{
+ event_sourcetime = event_curtime;
+
used = event_handle_user_input(client, e);
if (prompt && !used)
used = event_handle_prompt(prompt, e);
}
+ /* show any debug prompts that are queued */
+ ob_debug_show_prompts();
+
/* if something happens and it's not from an XEvent, then we don't know
the time, so clear it here until the next event is handled */
event_curtime = event_sourcetime = CurrentTime;
g_assert(config_focus_follow);
if (is_enter_focus_event_ignored(event_curserial)) {
- ob_debug_type(OB_DEBUG_FOCUS, "Ignoring enter event with serial %lu\n"
+ ob_debug_type(OB_DEBUG_FOCUS, "Ignoring enter event with serial %lu "
"on client 0x%x", event_curserial, client->window);
return;
}
+ ob_debug_type(OB_DEBUG_FOCUS, "using enter event with serial %lu "
+ "on client 0x%x", event_curserial, client->window);
+
if (client_enter_focusable(client) && client_can_focus(client)) {
if (config_focus_delay) {
ObFocusDelayData *data;
- obt_main_loop_timeout_remove(ob_main_loop, focus_delay_func);
+ if (focus_delay_timeout_id)
+ g_source_remove(focus_delay_timeout_id);
data = g_slice_new(ObFocusDelayData);
data->client = client;
data->time = event_time();
data->serial = event_curserial;
- obt_main_loop_timeout_add(ob_main_loop,
- config_focus_delay * 1000,
- focus_delay_func,
- data, focus_delay_cmp, focus_delay_dest);
+ focus_delay_timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT,
+ config_focus_delay,
+ focus_delay_func,
+ data,
+ focus_delay_dest);
+ focus_delay_timeout_client = client;
} else {
ObFocusDelayData data;
data.client = client;
if (config_focus_delay) {
ObFocusDelayData *data;
- obt_main_loop_timeout_remove(ob_main_loop, unfocus_delay_func);
+ if (unfocus_delay_timeout_id)
+ g_source_remove(unfocus_delay_timeout_id);
data = g_slice_new(ObFocusDelayData);
data->client = client;
data->time = event_time();
data->serial = event_curserial;
- obt_main_loop_timeout_add(ob_main_loop,
- config_focus_delay * 1000,
- unfocus_delay_func,
- data, focus_delay_cmp, focus_delay_dest);
+ unfocus_delay_timeout_id = g_timeout_add_full(G_PRIORITY_DEFAULT,
+ config_focus_delay,
+ unfocus_delay_func,
+ data,
+ unfocus_delay_dest);
+ unfocus_delay_timeout_client = client;
} else {
ObFocusDelayData data;
data.client = client;
delay is up */
e->xcrossing.detail != NotifyInferior)
{
- if (config_focus_delay)
- obt_main_loop_timeout_remove_data(ob_main_loop,
- focus_delay_func,
- client, FALSE);
+ if (config_focus_delay && focus_delay_timeout_id)
+ g_source_remove(focus_delay_timeout_id);
if (config_unfocus_leave)
event_leave_client(client);
}
if (grab_on_keyboard())
break;
if (e->xcrossing.mode == NotifyGrab ||
- e->xcrossing.mode == NotifyUngrab ||
+ (e->xcrossing.mode == NotifyUngrab &&
+ /* ungrab enters are used when _under_ mouse is being used */
+ !(config_focus_follow && config_focus_under_mouse)) ||
/*ignore enters when we're already in the window */
e->xcrossing.detail == NotifyInferior)
{
e->xcrossing.serial,
(client?client->window:0));
if (config_focus_follow) {
- if (config_focus_delay)
- obt_main_loop_timeout_remove_data(ob_main_loop,
- unfocus_delay_func,
- client, FALSE);
+ if (config_focus_delay && unfocus_delay_timeout_id)
+ g_source_remove(unfocus_delay_timeout_id);
event_enter_client(client);
}
}
ob_debug_type(OB_DEBUG_APP_BUGS,
"_NET_ACTIVE_WINDOW message for window %s is "
"missing source indication", client->title);
- client_activate(client, FALSE, FALSE, TRUE, TRUE,
- (e->xclient.data.l[0] == 0 ||
- e->xclient.data.l[0] == 2));
+ /* TODO(danakj) This should use
+ (e->xclient.data.l[0] == 0 ||
+ e->xclient.data.l[0] == 2)
+ to determine if a user requested the activation, however GTK+
+ applications seem unable to make this distinction ever
+ (including panels such as xfce4-panel and gnome-panel).
+ So we are left just assuming all activations are from the user.
+ */
+ client_activate(client, FALSE, FALSE, TRUE, TRUE, TRUE);
} else if (msgtype == OBT_PROP_ATOM(NET_WM_MOVERESIZE)) {
ob_debug("net_wm_moveresize for 0x%lx direction %d",
client->window, e->xclient.data.l[2]);
}
else if ((Atom)e->xclient.data.l[2] ==
OBT_PROP_ATOM(NET_WM_MOVERESIZE_CANCEL))
- moveresize_end(TRUE);
+ if (moveresize_client)
+ moveresize_end(TRUE);
} else if (msgtype == OBT_PROP_ATOM(NET_MOVERESIZE_WINDOW)) {
gint ograv, x, y, w, h;
client_update_title(client);
} else if (msgtype == OBT_PROP_ATOM(WM_PROTOCOLS)) {
client_update_protocols(client);
- client_setup_decor_and_functions(client, TRUE);
}
else if (msgtype == OBT_PROP_ATOM(NET_WM_STRUT) ||
msgtype == OBT_PROP_ATOM(NET_WM_STRUT_PARTIAL)) {
event_last_user_time = t;
}
}
+ else if (msgtype == OBT_PROP_ATOM(NET_WM_WINDOW_OPACITY)) {
+ client_update_opacity(client);
+ }
#ifdef SYNC
else if (msgtype == OBT_PROP_ATOM(NET_WM_SYNC_REQUEST_COUNTER)) {
+ /* if they are resizing right now this would cause weird behaviour.
+ if one day a user reports clients stop resizing, then handle
+ this better by resetting a new XSync alarm and stuff on the
+ new counter, but I expect it will never happen */
+ if (moveresize_client == client)
+ moveresize_end(FALSE);
client_update_sync_request_counter(client);
}
#endif
client->shaped = ((XShapeEvent*)e)->shaped;
kind = ShapeBounding;
break;
+#ifdef ShapeInput
case ShapeInput:
client->shaped_input = ((XShapeEvent*)e)->shaped;
kind = ShapeInput;
break;
+#endif
default:
g_assert_not_reached();
}
static void event_handle_dock(ObDock *s, XEvent *e)
{
switch (e->type) {
- case ButtonPress:
- if (e->xbutton.button == 1)
- stacking_raise(DOCK_AS_WINDOW(s));
- else if (e->xbutton.button == 2)
- stacking_lower(DOCK_AS_WINDOW(s));
- break;
case EnterNotify:
dock_hide(FALSE);
break;
if (ev->type == ButtonRelease || ev->type == ButtonPress) {
ObMenuEntryFrame *e;
- if (menu_hide_delay_reached() &&
- (ev->xbutton.button < 4 || ev->xbutton.button > 5))
+ if ((ev->xbutton.button < 4 || ev->xbutton.button > 5) &&
+ ((ev->type == ButtonRelease && menu_hide_delay_reached()) ||
+ ev->type == ButtonPress))
{
if ((e = menu_entry_frame_under(ev->xbutton.x_root,
ev->xbutton.y_root)))
if (ev->type == ButtonRelease)
menu_entry_frame_execute(e, ev->xbutton.state);
}
- else if (ev->type == ButtonRelease)
+ else
menu_frame_hide_all();
}
ret = TRUE;
}
- else if (ev->type == MotionNotify) {
- ObMenuFrame *f;
- ObMenuEntryFrame *e;
-
- if ((e = menu_entry_frame_under(ev->xmotion.x_root,
- ev->xmotion.y_root)))
- if (!(f = find_active_menu()) ||
- f == e->frame ||
- f->parent == e->frame ||
- f->child == e->frame)
- menu_frame_select(e->frame, e, FALSE);
- }
else if (ev->type == KeyPress || ev->type == KeyRelease) {
guint mods;
ObMenuFrame *frame;
ret = TRUE;
}
- else if (sym == XK_Right) {
- /* Right goes to the selected submenu */
- if (frame->selected->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)
- {
- /* make sure it is visible */
- menu_frame_select(frame, frame->selected, TRUE);
- menu_frame_select_next(frame->child);
+ else if (sym == XK_Right || sym == XK_Return || sym == XK_KP_Enter)
+ {
+ /* Right and enter goes to the selected submenu.
+ Enter executes instead if it's not on a submenu. */
+
+ if (frame->selected) {
+ const ObMenuEntryType t = frame->selected->entry->type;
+
+ if (t == OB_MENU_ENTRY_TYPE_SUBMENU) {
+ /* make sure it is visible */
+ menu_frame_select(frame, frame->selected, TRUE);
+ /* move focus to the child menu */
+ menu_frame_select_next(frame->child);
+ }
+ else if (sym != XK_Right) {
+ frame->press_doexec = TRUE;
+ }
}
ret = TRUE;
}
ret = TRUE;
}
- else if (sym == XK_Return || sym == XK_KP_Enter) {
- frame->press_doexec = TRUE;
- ret = TRUE;
- }
-
/* keyboard accelerator shortcuts. (if it was a valid key) */
else if (frame->entries &&
(unikey =
if (found) {
menu_frame_select(frame, found, TRUE);
- if (num_found == 1)
- frame->press_doexec = TRUE;
+ if (num_found == 1) {
+ if (found->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU) {
+ /* move focus to the child menu */
+ menu_frame_select_next(frame->child);
+ }
+ else {
+ frame->press_doexec = TRUE;
+ }
+ }
ret = TRUE;
}
}
frame->got_press &&
frame->press_doexec)
{
- if (frame->child)
- menu_frame_select_next(frame->child);
- else if (frame->selected)
+ if (frame->selected)
menu_entry_frame_execute(frame->selected, ev->xkey.state);
}
}
ObMenuEntryFrame *e;
switch (ev->type) {
+ case MotionNotify:
+ // We need to catch MotionNotify in addition to EnterNotify because
+ // it is possible for the menu to be opened under the mouse cursor, and
+ // moving the mouse should select the item.
+ if ((e = g_hash_table_lookup(menu_frame_map, &ev->xmotion.window))) {
+ if (e->ignore_enters)
+ --e->ignore_enters;
+ else if (!(f = find_active_menu()) ||
+ f == e->frame ||
+ f->parent == e->frame ||
+ f->child == e->frame)
+ menu_frame_select(e->frame, e, FALSE);
+ }
+ break;
case EnterNotify:
if ((e = g_hash_table_lookup(menu_frame_map, &ev->xcrossing.window))) {
if (e->ignore_enters)
static void focus_delay_dest(gpointer data)
{
g_slice_free(ObFocusDelayData, data);
+ focus_delay_timeout_id = 0;
+ focus_delay_timeout_client = NULL;
}
-static gboolean focus_delay_cmp(gconstpointer d1, gconstpointer d2)
+static void unfocus_delay_dest(gpointer data)
{
- const ObFocusDelayData *f1 = d1;
- return f1->client == d2;
+ g_slice_free(ObFocusDelayData, data);
+ unfocus_delay_timeout_id = 0;
+ unfocus_delay_timeout_client = NULL;
}
static gboolean focus_delay_func(gpointer data)
static void focus_delay_client_dest(ObClient *client, gpointer data)
{
- obt_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func,
- client, FALSE);
- obt_main_loop_timeout_remove_data(ob_main_loop, unfocus_delay_func,
- client, FALSE);
+ if (focus_delay_timeout_client == client && focus_delay_timeout_id)
+ g_source_remove(focus_delay_timeout_id);
+ if (unfocus_delay_timeout_client == client && unfocus_delay_timeout_id)
+ g_source_remove(unfocus_delay_timeout_id);
}
void event_halt_focus_delay(void)
{
/* ignore all enter events up till the event which caused this to occur */
if (event_curserial) event_ignore_enter_range(1, event_curserial);
- obt_main_loop_timeout_remove(ob_main_loop, focus_delay_func);
- obt_main_loop_timeout_remove(ob_main_loop, unfocus_delay_func);
+ if (focus_delay_timeout_id) g_source_remove(focus_delay_timeout_id);
+ if (unfocus_delay_timeout_id) g_source_remove(unfocus_delay_timeout_id);
}
gulong event_start_ignore_all_enters(void)
gboolean find_timestamp(XEvent *e, gpointer data)
{
const Time t = event_get_timestamp(e);
- if (t != CurrentTime) {
+ if (t && t >= event_curtime) {
event_curtime = t;
return TRUE;
}
return FALSE;
}
-Time event_time(void)
+static Time next_time(void)
{
- if (event_curtime) return event_curtime;
-
/* Some events don't come with timestamps :(
...but we can get one anyways >:) */
return event_curtime;
}
+Time event_time(void)
+{
+ if (event_curtime) return event_curtime;
+
+ return next_time();
+}
+
Time event_source_time(void)
{
return event_sourcetime;
}
+
+void event_reset_time(void)
+{
+ next_time();
+}
+
+void event_update_user_time(void)
+{
+ event_last_user_time = event_time();
+}
+
+void event_reset_user_time(void)
+{
+ event_last_user_time = CurrentTime;
+}