XEvent ce;
while (XCheckTypedWindowEvent(ob_display, e->xmotion.window,
e->type, &ce)) {
+ e->xmotion.x = ce.xmotion.x;
+ e->xmotion.y = ce.xmotion.y;
e->xmotion.x_root = ce.xmotion.x_root;
e->xmotion.y_root = ce.xmotion.y_root;
}
/* This means focus reverted off of a client */
else if (detail == NotifyPointerRoot ||
detail == NotifyDetailNone ||
- detail == NotifyInferior)
+ detail == NotifyInferior ||
+ /* This means focus got here from another screen */
+ detail == NotifyNonlinear)
return TRUE;
else
return FALSE;
if (!w || !WINDOW_IS_CLIENT(w))
return FALSE;
}
+ else {
+ /* This means focus reverted to parent from the client (this
+ happens often during iconify animation) */
+ if (detail == NotifyInferior)
+ return TRUE;
+ }
/* This means focus moved from the root window to a client */
if (detail == NotifyVirtual)
/* This means focus was taken by a keyboard/mouse grab. */
if (mode == NotifyGrab)
return FALSE;
+ /* This means focus was grabbed on a window and it was released. */
+ if (mode == NotifyUngrab)
+ return FALSE;
/* Focus left the root window revertedto state */
if (win == RootWindow(ob_display, ob_screen))
} else if (e->type == FocusIn) {
if (e->xfocus.detail == NotifyPointerRoot ||
e->xfocus.detail == NotifyDetailNone ||
- e->xfocus.detail == NotifyInferior)
+ e->xfocus.detail == NotifyInferior ||
+ e->xfocus.detail == NotifyNonlinear)
{
XEvent ce;
- ob_debug_type(OB_DEBUG_FOCUS, "Focus went to pointer root/none\n");
+ ob_debug_type(OB_DEBUG_FOCUS, "Focus went to root, "
+ "pointer root/none or "
+ "the frame window\n");
+
+ if (e->xfocus.detail == NotifyInferior ||
+ e->xfocus.detail == NotifyNonlinear)
+ {
+ focus_left_screen = FALSE;
+ }
/* If another FocusIn is in the queue then don't fallback yet. This
fixes the fun case of:
ob_debug_type(OB_DEBUG_FOCUS,
" but another FocusIn is coming\n");
} else {
- /* Focus has been reverted to the root window or nothing.
+ /* Focus has been reverted.
FocusOut events come after UnmapNotify, so we don't need to
worry about focusing an invalid window
*/
if (!focus_left_screen)
- focus_fallback(TRUE);
+ focus_fallback(TRUE, FALSE);
}
}
else if (!client)
client_bring_helper_windows(client);
}
} else if (e->type == FocusOut) {
- gboolean nomove = FALSE;
XEvent ce;
/* Look for the followup FocusIn */
xerror_set_ignore(FALSE);
/* nothing is focused */
focus_set_client(NULL);
- } else if (ce.xany.window == e->xany.window) {
- ob_debug_type(OB_DEBUG_FOCUS, "Focus didn't go anywhere\n");
- /* If focus didn't actually move anywhere, there is nothing to do*/
- nomove = TRUE;
} else {
- /* Focus did move, so process the FocusIn event */
+ /* Focus moved, so process the FocusIn event */
ObEventData ed = { .ignored = FALSE };
event_process(&ce, &ed);
if (ed.ignored) {
ob_debug_type(OB_DEBUG_FOCUS,
"Focus went to an unmanaged window 0x%x !\n",
ce.xfocus.window);
- focus_fallback(TRUE);
+ focus_fallback(TRUE, FALSE);
}
}
- if (client && !nomove) {
+ if (client && client != focus_client) {
frame_adjust_focus(client->frame, FALSE);
- if (client == focus_client)
- focus_set_client(NULL);
+ /* focus_set_client(NULL) has already been called in this
+ section or by focus_fallback */
client_calc_layer(client);
}
} else if (timewinclients)
}
} else if (msgtype == prop_atoms.net_number_of_desktops) {
guint d = e->xclient.data.l[0];
- if (d > 0)
+ if (d > 0 && d <= 1000)
screen_set_num_desktops(d);
} else if (msgtype == prop_atoms.net_showing_desktop) {
screen_show_desktop(e->xclient.data.l[0] != 0, NULL);
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);
*/
gint x, y, w, h;
+ gboolean move = FALSE;
+ gboolean resize = FALSE;
- /* if nothing is changed, then a configurenotify is needed */
- gboolean config = TRUE;
-
- x = client->area.x;
- y = client->area.y;
- w = client->area.width;
- h = client->area.height;
+ /* get the current area */
+ RECT_TO_DIMS(client->area, x, y, w, h);
- ob_debug("ConfigureRequest desktop %d wmstate %d visibile %d\n",
- screen_desktop, client->wmstate, client->frame->visible);
+ ob_debug("ConfigureRequest for \"%s\" desktop %d wmstate %d "
+ "visibile %d\n"
+ " x %d y %d w %d h %d b %d\n",
+ client->title,
+ screen_desktop, client->wmstate, client->frame->visible,
+ x, y, w, h, client->border_width);
if (e->xconfigurerequest.value_mask & CWBorderWidth)
if (client->border_width != e->xconfigurerequest.border_width) {
client->border_width = e->xconfigurerequest.border_width;
- /* if only the border width is changing, then it's not needed*/
- config = FALSE;
+
+ /* if the border width is changing then that is the same
+ as requesting a resize, but we don't actually change
+ the client's border, so it will change their root
+ coordiantes (since they include the border width) and
+ we need to a notify then */
+ move = TRUE;
}
stacking_restack_request(client, sibling,
e->xconfigurerequest.detail, TRUE);
- /* if a stacking change is requested then it is needed */
- config = TRUE;
+ /* if a stacking change moves the window without resizing */
+ move = TRUE;
}
- /* don't allow clients to move shaded windows (fvwm does this) */
- if (client->shaded && (e->xconfigurerequest.value_mask & CWX ||
- e->xconfigurerequest.value_mask & CWY))
+ if ((e->xconfigurerequest.value_mask & CWX) ||
+ (e->xconfigurerequest.value_mask & CWY) ||
+ (e->xconfigurerequest.value_mask & CWWidth) ||
+ (e->xconfigurerequest.value_mask & CWHeight))
{
- e->xconfigurerequest.value_mask &= ~CWX;
- e->xconfigurerequest.value_mask &= ~CWY;
-
- /* if the client tried to move and we aren't letting it then a
- synthetic event is needed */
- config = TRUE;
- }
+ if (e->xconfigurerequest.value_mask & CWX) {
+ /* don't allow clients to move shaded windows (fvwm does this)
+ */
+ if (!client->shaded)
+ x = e->xconfigurerequest.x;
+ move = TRUE;
+ }
+ if (e->xconfigurerequest.value_mask & CWY) {
+ /* don't allow clients to move shaded windows (fvwm does this)
+ */
+ if (!client->shaded)
+ y = e->xconfigurerequest.y;
+ move = TRUE;
+ }
- if (e->xconfigurerequest.value_mask & CWX ||
- e->xconfigurerequest.value_mask & CWY ||
- e->xconfigurerequest.value_mask & CWWidth ||
- e->xconfigurerequest.value_mask & CWHeight)
- {
- if (e->xconfigurerequest.value_mask & CWX)
- x = e->xconfigurerequest.x;
- if (e->xconfigurerequest.value_mask & CWY)
- y = e->xconfigurerequest.y;
- if (e->xconfigurerequest.value_mask & CWWidth)
+ if (e->xconfigurerequest.value_mask & CWWidth) {
w = e->xconfigurerequest.width;
- if (e->xconfigurerequest.value_mask & CWHeight)
+ resize = TRUE;
+ }
+ if (e->xconfigurerequest.value_mask & CWHeight) {
h = e->xconfigurerequest.height;
-
- /* if a new position or size is requested, then a configure is
- needed */
- config = TRUE;
+ resize = TRUE;
+ }
}
- ob_debug("ConfigureRequest x(%d) %d y(%d) %d w(%d) %d h(%d) %d\n",
+ ob_debug("ConfigureRequest x(%d) %d y(%d) %d w(%d) %d h(%d) %d "
+ "move %d resize %d\n",
e->xconfigurerequest.value_mask & CWX, x,
e->xconfigurerequest.value_mask & CWY, y,
e->xconfigurerequest.value_mask & CWWidth, w,
- e->xconfigurerequest.value_mask & CWHeight, h);
+ e->xconfigurerequest.value_mask & CWHeight, h,
+ move, resize);
/* check for broken apps moving to their root position
desktop. eg. open amarok window on desktop 1, switch to desktop
2, click amarok tray icon. it will move by its decoration size.
*/
- if (x != client->area.x &&
+ if (move && !resize &&
+ x != client->area.x &&
x == (client->frame->area.x + client->frame->size.left -
(gint)client->border_width) &&
y != client->area.y &&
/* don't move it */
x = client->area.x;
y = client->area.y;
+
+ /* they still requested a move, so don't change whether a
+ notify is sent or not */
}
- if (config) {
+ if (move || resize) {
+ gint lw,lh;
+
+ client_try_configure(client, &x, &y, &w, &h, &lw, &lh, FALSE);
+
+ /* if x was not given, then use gravity to figure out the new
+ x. the reference point should not be moved */
+ if ((e->xconfigurerequest.value_mask & CWWidth &&
+ !(e->xconfigurerequest.value_mask & CWX)))
+ client_gravity_resize_w(client, &x, client->area.width, w);
+ /* if y was not given, then use gravity to figure out the new
+ y. the reference point should not be moved */
+ if ((e->xconfigurerequest.value_mask & CWHeight &&
+ !(e->xconfigurerequest.value_mask & CWY)))
+ client_gravity_resize_h(client, &y, client->area.height,h);
+
client_find_onscreen(client, &x, &y, w, h, FALSE);
- client_configure(client, x, y, w, h, FALSE, TRUE);
+
+ /* if they requested something that moves the window, or if
+ the window is actually being changed then configure it and
+ send a configure notify to them */
+ if (move || !RECT_EQUAL_DIMS(client->area, x, y, w, h)) {
+ ob_debug("Granting ConfigureRequest x %d y %d w %d h %d\n",
+ x, y, w, h);
+ client_configure(client, x, y, w, h, FALSE, TRUE);
+ }
/* ignore enter events caused by these like ob actions do */
event_ignore_all_queued_enters();
break;
case ReparentNotify:
/* this is when the client is first taken captive in the frame */
- if (e->xreparent.parent == client->frame->plate) break;
+ if (e->xreparent.parent == client->frame->window) break;
/*
This event is quite rare and is usually handled in unmapHandler.
(e->xclient.data.l[0] == 1 ? "application" :
(e->xclient.data.l[0] == 2 ? "user" : "INVALID"))));
/* XXX make use of data.l[2] !? */
- event_curtime = e->xclient.data.l[1];
- if (event_curtime == 0)
+ if (e->xclient.data.l[0] == 1 || e->xclient.data.l[0] == 2) {
+ event_curtime = e->xclient.data.l[1];
+ if (event_curtime == 0)
+ ob_debug_type(OB_DEBUG_APP_BUGS,
+ "_NET_ACTIVE_WINDOW message for window %s is"
+ " missing a timestamp\n", client->title);
+ } else
ob_debug_type(OB_DEBUG_APP_BUGS,
"_NET_ACTIVE_WINDOW message for window %s is "
- "missing a timestamp\n", client->title);
+ "missing source indication\n");
client_activate(client, FALSE,
(e->xclient.data.l[0] == 0 ||
e->xclient.data.l[0] == 2));
prop_atoms.net_wm_moveresize_cancel)
moveresize_end(TRUE);
} else if (msgtype == prop_atoms.net_moveresize_window) {
- gint grav, x, y, w, h;
+ gint ograv, x, y, w, h;
+
+ ograv = client->gravity;
if (e->xclient.data.l[0] & 0xff)
- grav = e->xclient.data.l[0] & 0xff;
- else
- grav = client->gravity;
+ client->gravity = e->xclient.data.l[0] & 0xff;
if (e->xclient.data.l[0] & 1 << 8)
x = e->xclient.data.l[1];
y = e->xclient.data.l[2];
else
y = client->area.y;
- if (e->xclient.data.l[0] & 1 << 10)
+
+ if (e->xclient.data.l[0] & 1 << 10) {
w = e->xclient.data.l[3];
+
+ /* if x was not given, then use gravity to figure out the new
+ x. the reference point should not be moved */
+ if (!(e->xclient.data.l[0] & 1 << 8))
+ client_gravity_resize_w(client, &x, client->area.width, w);
+ }
else
w = client->area.width;
- if (e->xclient.data.l[0] & 1 << 11)
+
+ if (e->xclient.data.l[0] & 1 << 11) {
h = e->xclient.data.l[4];
+
+ /* if y was not given, then use gravity to figure out the new
+ y. the reference point should not be moved */
+ if (!(e->xclient.data.l[0] & 1 << 9))
+ client_gravity_resize_h(client, &y, client->area.height,h);
+ }
else
h = client->area.height;
- ob_debug("MOVERESIZE x %d %d y %d %d\n",
+ ob_debug("MOVERESIZE x %d %d y %d %d (gravity %d)\n",
e->xclient.data.l[0] & 1 << 8, x,
- e->xclient.data.l[0] & 1 << 9, y);
- client_convert_gravity(client, grav, &x, &y, w, h);
+ e->xclient.data.l[0] & 1 << 9, y,
+ client->gravity);
+
client_find_onscreen(client, &x, &y, w, h, FALSE);
client_configure(client, x, y, w, h, FALSE, TRUE);
+ client->gravity = ograv;
+
/* ignore enter events caused by these like ob actions do */
event_ignore_all_queued_enters();
} else if (msgtype == prop_atoms.net_restack_window) {
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);
+ client_setup_decor_and_functions(client, TRUE);
} else if (msgtype == XA_WM_HINTS) {
client_update_wmhints(client);
} else if (msgtype == XA_WM_TRANSIENT_FOR) {
client_get_type_and_transientness(client);
/* type may have changed, so update the layer */
client_calc_layer(client);
- client_setup_decor_and_functions(client);
+ client_setup_decor_and_functions(client, TRUE);
} else if (msgtype == prop_atoms.net_wm_name ||
msgtype == prop_atoms.wm_name ||
msgtype == prop_atoms.net_wm_icon_name ||
client_update_title(client);
} else if (msgtype == prop_atoms.wm_protocols) {
client_update_protocols(client);
- client_setup_decor_and_functions(client);
+ client_setup_decor_and_functions(client, TRUE);
}
else if (msgtype == prop_atoms.net_wm_strut) {
client_update_strut(client);
}
+ else if (msgtype == prop_atoms.net_wm_strut_partial) {
+ client_update_strut(client);
+ }
else if (msgtype == prop_atoms.net_wm_icon) {
client_update_icons(client);
}
client_update_sync_request_counter(client);
}
#endif
+ break;
case ColormapNotify:
client_update_colormap(client, e->xcolormap.colormap);
break;
Control-Enter runs it without closing the menu. */
if (frame->child)
menu_frame_select_next(frame->child);
- else
+ else if (frame->selected)
menu_entry_frame_execute(frame->selected, state, ev->xkey.time);
}
menu_frame_select_next(frame);
}
- /* keyboard accelerator shortcuts. */
- else if (ev->xkey.state == 0 &&
+ /* keyboard accelerator shortcuts. (allow controlmask) */
+ else if ((ev->xkey.state & ~ControlMask) == 0 &&
/* was it a valid key? */
unikey != 0 &&
/* don't bother if the menu is empty. */
{
if ((e = menu_entry_frame_under(ev->xbutton.x_root,
ev->xbutton.y_root)))
+ {
+ menu_frame_select(e->frame, e, TRUE);
menu_entry_frame_execute(e, ev->xbutton.state,
ev->xbutton.time);
+ }
else
menu_frame_hide_all();
}
if ((e = g_hash_table_lookup(menu_frame_map, &ev->xcrossing.window))) {
if (e->ignore_enters)
--e->ignore_enters;
- else
+ 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 MotionNotify:
if ((e = menu_entry_frame_under(ev->xmotion.x_root,
ev->xmotion.y_root)))
- menu_frame_select(e->frame, e, FALSE);
+ 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 KeyPress:
ret = event_handle_menu_keyboard(ev);
return FALSE;
}
+void event_cancel_all_key_grabs()
+{
+ if (keyboard_interactively_grabbed())
+ keyboard_interactive_cancel();
+ else if (menu_frame_visible)
+ menu_frame_hide_all();
+ else if (grab_on_keyboard())
+ ungrab_keyboard();
+ else
+ /* If we don't have the keyboard grabbed, then ungrab it with
+ XUngrabKeyboard, so that there is not a passive grab left
+ on from the KeyPress. If the grab is left on, and focus
+ moves during that time, it will be NotifyWhileGrabbed, and
+ applications like to ignore those! */
+ if (!keyboard_interactively_grabbed())
+ XUngrabKeyboard(ob_display, CurrentTime);
+
+}
+
gboolean event_time_after(Time t1, Time t2)
{
g_assert(t1 != CurrentTime);