#include "mainloop.h"
#include "framerender.h"
#include "focus.h"
+#include "focus_cycle.h"
#include "moveresize.h"
#include "group.h"
#include "stacking.h"
/* The time for the current event being processed */
Time event_curtime = CurrentTime;
-#define NUM_IGNORE_SERIALS 20
-
static guint ignore_enter_focus = 0;
-/*! This is a 0 terminated list of ignored serials */
-static gulong ignore_enter_serials[NUM_IGNORE_SERIALS+1] = {0};
static gboolean menu_can_hide;
static gboolean focus_left_screen = FALSE;
{
/* use where the press occured */
con = frame_context(client, e->xbutton.window, px, py);
- con = mouse_button_frame_context(con, e->xbutton.button);
+ con = mouse_button_frame_context(con, e->xbutton.button,
+ e->xbutton.state);
if (e->type == ButtonRelease && e->xbutton.button == pb)
pb = 0, px = py = -1;
e->xmotion.x, e->xmotion.y);
switch (con) {
case OB_FRAME_CONTEXT_TITLEBAR:
+ case OB_FRAME_CONTEXT_TLCORNER:
+ case OB_FRAME_CONTEXT_TRCORNER:
/* we've left the button area inside the titlebar */
if (client->frame->max_hover || client->frame->desk_hover ||
client->frame->shade_hover || client->frame->iconify_hover ||
con = frame_context(client, e->xcrossing.window,
e->xcrossing.x, e->xcrossing.y);
switch (con) {
+ case OB_FRAME_CONTEXT_TITLEBAR:
+ case OB_FRAME_CONTEXT_TLCORNER:
+ case OB_FRAME_CONTEXT_TRCORNER:
+ /* we've left the button area inside the titlebar */
+ if (client->frame->max_hover || client->frame->desk_hover ||
+ client->frame->shade_hover || client->frame->iconify_hover ||
+ client->frame->close_hover)
+ {
+ client->frame->max_hover = FALSE;
+ client->frame->desk_hover = FALSE;
+ client->frame->shade_hover = FALSE;
+ client->frame->iconify_hover = FALSE;
+ client->frame->close_hover = FALSE;
+ frame_adjust_state(client->frame);
+ }
+ break;
case OB_FRAME_CONTEXT_MAXIMIZE:
client->frame->max_hover = FALSE;
frame_adjust_state(client->frame);
corresponding enter events. Pretend like the animating window
doesn't even exist..! */
if (frame_iconify_animating(client->frame))
- event_ignore_enters_leaving_window(client);
+ event_ignore_all_queued_enters();
ob_debug_type(OB_DEBUG_FOCUS,
"%sNotify mode %d detail %d on %lx\n",
break;
case EnterNotify:
{
- gboolean nofocus = FALSE;
-
- if (is_enter_focus_event_ignored(e))
- nofocus = TRUE;
-
con = frame_context(client, e->xcrossing.window,
e->xcrossing.x, e->xcrossing.y);
switch (con) {
if (e->xcrossing.mode == NotifyGrab ||
e->xcrossing.mode == NotifyUngrab ||
/*ignore enters when we're already in the window */
- e->xcrossing.detail == NotifyInferior)
+ e->xcrossing.detail == NotifyInferior ||
+ is_enter_focus_event_ignored(e))
{
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);
- } else {
+ }
+ else {
ob_debug_type(OB_DEBUG_FOCUS,
"%sNotify mode %d detail %d on %lx, "
- "focusing window: %d\n",
+ "focusing window\n",
(e->type == EnterNotify ? "Enter" : "Leave"),
e->xcrossing.mode,
- e->xcrossing.detail, (client?client->window:0),
- !nofocus);
- if (!nofocus && config_focus_follow)
+ e->xcrossing.detail, (client?client->window:0));
+ if (config_focus_follow)
event_enter_client(client);
}
break;
client_configure(client, x, y, w, h, FALSE, TRUE);
/* ignore enter events caused by these like ob actions do */
- event_ignore_enters_leaving_window(client);
+ event_ignore_all_queued_enters();
}
break;
}
e->xclient.data.l[1], e->xclient.data.l[2]);
/* ignore enter events caused by these like ob actions do */
- event_ignore_enters_leaving_window(client);
+ event_ignore_all_queued_enters();
} else if (msgtype == prop_atoms.net_close_window) {
ob_debug("net_close_window for 0x%lx\n", client->window);
client_close(client);
client_configure(client, x, y, w, h, FALSE, TRUE);
/* ignore enter events caused by these like ob actions do */
- event_ignore_enters_leaving_window(client);
+ event_ignore_all_queued_enters();
} else if (msgtype == prop_atoms.net_restack_window) {
if (e->xclient.data.l[0] != 2) {
ob_debug_type(OB_DEBUG_APP_BUGS,
} else {
ObClient *sibling = NULL;
if (e->xclient.data.l[1]) {
- ObWindow *win = g_hash_table_lookup(window_map,
- &e->xclient.data.l[1]);
+ ObWindow *win = g_hash_table_lookup
+ (window_map, &e->xclient.data.l[1]);
if (WINDOW_IS_CLIENT(win) &&
WINDOW_AS_CLIENT(win) != client)
{
ret = FALSE;
else if (keycode == ob_keycode(OB_KEY_ESCAPE) && state == 0) {
- /* Escape closes the active menu */
- menu_frame_hide(frame);
+ /* Escape goes to the parent menu or closes the last one */
+ if (frame->parent)
+ menu_frame_select(frame, NULL, TRUE);
+ else
+ menu_frame_hide_all();
}
else if (keycode == ob_keycode(OB_KEY_RETURN) && (state == 0 ||
}
break;
case LeaveNotify:
+ /*ignore leaves when we're already in the window */
+ if (ev->xcrossing.detail == NotifyInferior)
+ break;
+
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)
ob_main_loop_timeout_remove(ob_main_loop, focus_delay_func);
}
-struct ObLookForEnters
-{
- ObClient *c;
- gulong looking_for_enter;
-};
-
static Bool event_look_for_enters(Display *d, XEvent *e, XPointer arg)
{
- struct ObLookForEnters *lfe = (struct ObLookForEnters*)arg;
-
- if (lfe->c != NULL && e->type == LeaveNotify) {
- if (g_hash_table_lookup(window_map, &e->xany.window) == lfe->c)
- /* found an event leaving this window */
- lfe->looking_for_enter = e->xany.serial;
- } else if (e->type == EnterNotify &&
- (lfe->c == NULL || e->xany.serial == lfe->looking_for_enter))
+ if (e->type == EnterNotify &&
+ /* these types aren't used for focusing */
+ !(e->xcrossing.mode == NotifyGrab ||
+ e->xcrossing.mode == NotifyUngrab ||
+ e->xcrossing.detail == NotifyInferior))
{
ObWindow *win;
- gint i;
- gboolean ignored = FALSE;
- /* make sure the serial isn't already being ignored */
- for (i = 0; ignore_enter_serials[i] != 0 && !ignored; ++i) {
- if (ignore_enter_serials[i] == e->xany.serial)
- ignored = TRUE;
- }
-
- if (!ignored) {
- /* found an enter for that leave, ignore it if it's going to
- another window */
- win = g_hash_table_lookup(window_map, &e->xany.window);
- if (win && WINDOW_IS_CLIENT(win))
- ++ignore_enter_focus;
- }
-
- /* add it to the ignored list if there is room */
- if (i < NUM_IGNORE_SERIALS) {
- ignore_enter_serials[i] = e->xany.serial;
- ignore_enter_serials[i+1] = 0;
- }
+ /* found an enter for that leave, ignore it if it's going to
+ another window */
+ win = g_hash_table_lookup(window_map, &e->xany.window);
+ if (win && WINDOW_IS_CLIENT(win))
+ ++ignore_enter_focus;
}
return False; /* don't disrupt the queue order, just count them */
}
void event_ignore_all_queued_enters()
{
- event_ignore_enters_leaving_window(NULL);
-}
-
-void event_ignore_enters_leaving_window(ObClient *c)
-{
- struct ObLookForEnters lfe;
XEvent e;
XSync(ob_display, FALSE);
/* count the events without disrupting them */
ignore_enter_focus = 0;
- lfe.c = c;
- lfe.looking_for_enter = 0;
- XCheckIfEvent(ob_display, &e, event_look_for_enters, (XPointer)&lfe);
-
+ XCheckIfEvent(ob_display, &e, event_look_for_enters, NULL);
}
static gboolean is_enter_focus_event_ignored(XEvent *e)
{
- g_assert(e->type == EnterNotify);
+ g_assert(e->type == EnterNotify &&
+ !(e->xcrossing.mode == NotifyGrab ||
+ e->xcrossing.mode == NotifyUngrab ||
+ e->xcrossing.detail == NotifyInferior));
- if (ignore_enter_focus) {
- gint i;
+ ob_debug_type(OB_DEBUG_FOCUS, "# enters ignored: %d\n",
+ ignore_enter_focus);
+ if (ignore_enter_focus) {
--ignore_enter_focus;
-
- /* remove the serial */
- for (i = 0; ignore_enter_serials[i] != 0; ++i) {
- if (ignore_enter_serials[i] == e->xany.serial) {
- for (; ignore_enter_serials[i+1] != 0; ++i)
- ignore_enter_serials[i] = ignore_enter_serials[i+1];
- ignore_enter_serials[i] = 0;
- }
- }
return TRUE;
}
return FALSE;