#include "menuframe.h"
#include "keyboard.h"
#include "modkeys.h"
+#include "propwin.h"
#include "mouse.h"
#include "mainloop.h"
#include "framerender.h"
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_user_time_window_client(ObClient *c, XEvent *e);
+static void event_handle_user_time_window_clients(GSList *l, XEvent *e);
static void event_handle_user_input(ObClient *client, XEvent *e);
static void focus_delay_dest(gpointer data);
ObDock *dock = NULL;
ObDockApp *dockapp = NULL;
ObWindow *obwin = NULL;
- ObClient *timewinclient = NULL;
+ GSList *timewinclients = NULL;
XEvent ee, *e;
ObEventData *ed = data;
window = event_get_window(e);
if (e->type != PropertyNotify ||
- !(timewinclient =
- g_hash_table_lookup(client_user_time_window_map, &window)))
+ !(timewinclients = propwin_get_clients(window,
+ OB_PROPWIN_USER_TIME)))
if ((obwin = g_hash_table_lookup(window_map, &window))) {
switch (obwin->type) {
case Window_Dock:
/* focus_set_client has already been called for sure */
client_calc_layer(client);
}
- } else if (timewinclient)
- event_handle_user_time_window_client(timewinclient, e);
+ } else if (timewinclients)
+ event_handle_user_time_window_clients(timewinclients, e);
else if (client)
event_handle_client(client, e);
else if (dockapp)
event_handle_root(e);
else if (e->type == MapRequest)
client_manage(window);
+ else if (e->type == ClientMessage) {
+ /* This is for _NET_WM_REQUEST_FRAME_EXTENTS messages. They come for
+ windows that are not managed yet. */
+ if (e->xclient.message_type == prop_atoms.net_request_frame_extents) {
+ /* Pretend to manage the client, getting information used to
+ determine its decorations */
+ ObClient *c = client_fake_manage(e->xclient.window);
+ gulong vals[4];
+
+ /* set the frame extents on the window */
+ vals[0] = c->frame->size.left;
+ vals[1] = c->frame->size.right;
+ vals[2] = c->frame->size.top;
+ vals[3] = c->frame->size.bottom;
+ PROP_SETA32(e->xclient.window, net_frame_extents,
+ cardinal, vals, 4);
+
+ /* Free the pretend client */
+ client_fake_unmanage(c);
+ }
+ }
else if (e->type == ConfigureRequest) {
/* unhandled configure requests must be used to configure the
window directly */
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, TRUE);
+ screen_show_desktop(e->xclient.data.l[0] != 0, NULL);
} else if (msgtype == prop_atoms.openbox_control) {
if (e->xclient.data.l[0] == 1)
ob_reconfigure();
}
}
-static void event_handle_user_time_window_client(ObClient *client, XEvent *e)
+static void event_handle_user_time_window_clients(GSList *l, XEvent *e)
{
g_assert(e->type == PropertyNotify);
- if (e->xproperty.atom == prop_atoms.net_wm_user_time)
- client_update_user_time(client);
+ if (e->xproperty.atom == prop_atoms.net_wm_user_time) {
+ for (; l; l = g_slist_next(l))
+ client_update_user_time(l->data);
+ }
}
static void event_handle_client(ObClient *client, XEvent *e)
XEvent ce;
Atom msgtype;
ObFrameContext con;
+ static gint px = -1, py = -1;
+ static guint pb = 0;
switch (e->type) {
case ButtonPress:
+ /* save where the press occured for the first button pressed */
+ if (!pb) {
+ pb = e->xbutton.button;
+ px = e->xbutton.x;
+ py = e->xbutton.y;
+ }
case ButtonRelease:
/* Wheel buttons don't draw because they are an instant click, so it
is a waste of resources to go drawing it.
!keyboard_interactively_grabbed() &&
!menu_frame_visible)
{
- con = frame_context(client, e->xbutton.window);
+ /* use where the press occured */
+ con = frame_context(client, e->xbutton.window, px, py);
con = mouse_button_frame_context(con, e->xbutton.button);
+
+ if (e->type == ButtonRelease && e->xbutton.button == pb)
+ pb = 0, px = py = -1;
+
switch (con) {
case OB_FRAME_CONTEXT_MAXIMIZE:
client->frame->max_press = (e->type == ButtonPress);
}
}
break;
+ case MotionNotify:
+ con = frame_context(client, e->xmotion.window,
+ e->xmotion.x, e->xmotion.y);
+ switch (con) {
+ case OB_FRAME_CONTEXT_TITLEBAR:
+ /* 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:
+ if (!client->frame->max_hover) {
+ client->frame->max_hover = TRUE;
+ frame_adjust_state(client->frame);
+ }
+ break;
+ case OB_FRAME_CONTEXT_ALLDESKTOPS:
+ if (!client->frame->desk_hover) {
+ client->frame->desk_hover = TRUE;
+ frame_adjust_state(client->frame);
+ }
+ break;
+ case OB_FRAME_CONTEXT_SHADE:
+ if (!client->frame->shade_hover) {
+ client->frame->shade_hover = TRUE;
+ frame_adjust_state(client->frame);
+ }
+ break;
+ case OB_FRAME_CONTEXT_ICONIFY:
+ if (!client->frame->iconify_hover) {
+ client->frame->iconify_hover = TRUE;
+ frame_adjust_state(client->frame);
+ }
+ break;
+ case OB_FRAME_CONTEXT_CLOSE:
+ if (!client->frame->close_hover) {
+ client->frame->close_hover = TRUE;
+ frame_adjust_state(client->frame);
+ }
+ break;
+ default:
+ break;
+ }
+ break;
case LeaveNotify:
- con = frame_context(client, e->xcrossing.window);
+ con = frame_context(client, e->xcrossing.window,
+ e->xcrossing.x, e->xcrossing.y);
switch (con) {
case OB_FRAME_CONTEXT_MAXIMIZE:
client->frame->max_hover = FALSE;
nofocus = TRUE;
}
- con = frame_context(client, e->xcrossing.window);
+ con = frame_context(client, e->xcrossing.window,
+ e->xcrossing.x, e->xcrossing.y);
switch (con) {
case OB_FRAME_CONTEXT_MAXIMIZE:
client->frame->max_hover = TRUE;
}
if (e->xconfigurerequest.value_mask & CWStackMode) {
- switch (e->xconfigurerequest.detail) {
- case Below:
- case BottomIf:
- /* Apps are so rude. And this is totally disconnected from
- activation/focus. Bleh. */
- /*client_lower(client);*/
- break;
-
- case Above:
- case TopIf:
- default:
- /* Apps are so rude. And this is totally disconnected from
- activation/focus. Bleh. */
- /*client_raise(client);*/
- break;
+ ObClient *sibling = NULL;
+
+ /* get the sibling */
+ if (e->xconfigurerequest.value_mask & CWSibling) {
+ ObWindow *win;
+ win = g_hash_table_lookup(window_map,
+ &e->xconfigurerequest.above);
+ if (WINDOW_IS_CLIENT(win) && WINDOW_AS_CLIENT(win) != client)
+ sibling = WINDOW_AS_CLIENT(win);
}
+
+ /* activate it rather than just focus it */
+ stacking_restack_request(client, sibling,
+ e->xconfigurerequest.detail, TRUE);
}
break;
case UnmapNotify:
client_convert_gravity(client, grav, &x, &y, w, h);
client_find_onscreen(client, &x, &y, w, h, FALSE);
client_configure(client, x, y, w, h, FALSE, TRUE);
+ } else if (msgtype == prop_atoms.net_restack_window) {
+ if (e->xclient.data.l[0] != 2) {
+ ob_debug_type(OB_DEBUG_APP_BUGS,
+ "_NET_RESTACK_WINDOW sent for window %s with "
+ "invalid source indication %ld\n",
+ client->title, e->xclient.data.l[0]);
+ } else {
+ ObClient *sibling = NULL;
+ if (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)
+ {
+ sibling = WINDOW_AS_CLIENT(win);
+ }
+ if (sibling == NULL)
+ ob_debug_type(OB_DEBUG_APP_BUGS,
+ "_NET_RESTACK_WINDOW sent for window %s "
+ "with invalid sibling 0x%x\n",
+ client->title, e->xclient.data.l[1]);
+ }
+ if (e->xclient.data.l[2] == Below ||
+ e->xclient.data.l[2] == BottomIf ||
+ e->xclient.data.l[2] == Above ||
+ e->xclient.data.l[2] == TopIf ||
+ e->xclient.data.l[2] == Opposite)
+ {
+ /* just raise, don't activate */
+ stacking_restack_request(client, sibling,
+ e->xclient.data.l[2], FALSE);
+ } else
+ ob_debug_type(OB_DEBUG_APP_BUGS,
+ "_NET_RESTACK_WINDOW sent for window %s "
+ "with invalid detail %d\n",
+ client->title, e->xclient.data.l[2]);
+ }
}
break;
case PropertyNotify:
client_update_wmhints(client);
} else if (msgtype == XA_WM_TRANSIENT_FOR) {
client_update_transient_for(client);
- client_get_type(client);
+ client_get_type_and_transientness(client);
/* type may have changed, so update the layer */
client_calc_layer(client);
client_setup_decor_and_functions(client);
event_curtime = d->time;
if (focus_client != d->client) {
if (client_focus(d->client) && config_focus_raise)
- client_raise(d->client);
+ stacking_raise(CLIENT_AS_WINDOW(d->client));
}
event_curtime = old;
return FALSE; /* no repeat */