X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fevent.c;h=e07d6a31217f14feaaf8c9edaa4f40344673ccad;hb=07126124c9242a5a20883c3145464730e50afe94;hp=f41140eb7cd07477a1a0d71dd5f7a281511a62d4;hpb=c313b219a226c3b968ff312b96120eef0c527d91;p=chaz%2Fopenbox diff --git a/openbox/event.c b/openbox/event.c index f41140eb..e07d6a31 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -89,6 +89,7 @@ static void event_process(const XEvent *e, gpointer data); static void event_handle_root(XEvent *e); static gboolean event_handle_menu_keyboard(XEvent *e); static gboolean event_handle_menu(XEvent *e); +static gboolean event_handle_prompt(ObPrompt *p, 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); @@ -477,6 +478,8 @@ static void event_process(const XEvent *ec, gpointer data) break; case Window_Client: client = WINDOW_AS_CLIENT(obwin); + /* events on clients can be events on prompt windows too */ + prompt = client->prompt; break; case Window_Menu: /* not to be used for events */ @@ -644,14 +647,16 @@ static void event_process(const XEvent *ec, gpointer data) else if (window == RootWindow(ob_display, ob_screen)) event_handle_root(e); else if (e->type == MapRequest) - client_manage(window); + client_manage(window, NULL); else if (e->type == MappingNotify) { /* keyboard layout changes for modifier mapping changes. reload the modifier map, and rebind all the key bindings as appropriate */ - ob_debug("Kepboard map changed. Reloading keyboard bindings.\n"); + ob_debug("Keyboard map changed. Reloading keyboard bindings.\n"); + ob_set_state(OB_STATE_RECONFIGURING); modkeys_shutdown(TRUE); modkeys_startup(TRUE); keyboard_rebind(); + ob_set_state(OB_STATE_RUNNING); } else if (e->type == ClientMessage) { /* This is for _NET_WM_REQUEST_FRAME_EXTENTS messages. They come for @@ -704,7 +709,9 @@ static void event_process(const XEvent *ec, gpointer data) } #endif - if (e->type == ButtonPress || e->type == ButtonRelease) { + if (prompt && event_handle_prompt(prompt, e)) + ; + else if (e->type == ButtonPress || e->type == ButtonRelease) { /* If the button press was on some non-root window, or was physically on the root window, then process it */ if (window != RootWindow(ob_display, ob_screen) || @@ -831,13 +838,66 @@ void event_enter_client(ObClient *client) } } +static gboolean *context_to_button(ObFrame *f, ObFrameContext con, gboolean press) +{ + if (press) { + switch (con) { + case OB_FRAME_CONTEXT_MAXIMIZE: + return &f->max_press; + case OB_FRAME_CONTEXT_CLOSE: + return &f->close_press; + case OB_FRAME_CONTEXT_ICONIFY: + return &f->iconify_press; + case OB_FRAME_CONTEXT_ALLDESKTOPS: + return &f->desk_press; + case OB_FRAME_CONTEXT_SHADE: + return &f->shade_press; + default: + return NULL; + } + } else { + switch (con) { + case OB_FRAME_CONTEXT_MAXIMIZE: + return &f->max_hover; + case OB_FRAME_CONTEXT_CLOSE: + return &f->close_hover; + case OB_FRAME_CONTEXT_ICONIFY: + return &f->iconify_hover; + case OB_FRAME_CONTEXT_ALLDESKTOPS: + return &f->desk_hover; + case OB_FRAME_CONTEXT_SHADE: + return &f->shade_hover; + default: + return NULL; + } + } +} + +static void compress_client_message_event(XEvent *e, XEvent *ce, Window window, + Atom msgtype) +{ + /* compress changes into a single change */ + while (XCheckTypedWindowEvent(ob_display, 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. */ + if (ce->xclient.message_type != msgtype) { + XPutBackEvent(ob_display, ce); + break; + } + e->xclient = ce->xclient; + } +} + static void event_handle_client(ObClient *client, XEvent *e) { XEvent ce; Atom msgtype; ObFrameContext con; + gboolean *but; static gint px = -1, py = -1; static guint pb = 0; + static ObFrameContext pcon = OB_FRAME_CONTEXT_NONE; switch (e->type) { case ButtonPress: @@ -846,11 +906,15 @@ static void event_handle_client(ObClient *client, XEvent *e) pb = e->xbutton.button; px = e->xbutton.x; py = e->xbutton.y; + + pcon = frame_context(client, e->xbutton.window, px, py); + pcon = mouse_button_frame_context(pcon, e->xbutton.button, + e->xbutton.state); } 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 the user is doing an intereactive thing, or has a menu open then + if the user is doing an interactive thing, or has a menu open then the mouse is grabbed (possibly) and if we get these events we don't want to deal with them */ @@ -862,33 +926,16 @@ static void event_handle_client(ObClient *client, XEvent *e) 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; + /* button presses on CLIENT_CONTEXTs are not accompanied by a + release because they are Replayed to the client */ + if ((e->type == ButtonRelease || CLIENT_CONTEXT(con, client)) && + e->xbutton.button == pb) + pb = 0, px = py = -1, pcon = OB_FRAME_CONTEXT_NONE; - switch (con) { - case OB_FRAME_CONTEXT_MAXIMIZE: - client->frame->max_press = (e->type == ButtonPress); - frame_adjust_state(client->frame); - break; - case OB_FRAME_CONTEXT_CLOSE: - client->frame->close_press = (e->type == ButtonPress); + but = context_to_button(client->frame, con, TRUE); + if (but) { + *but = (e->type == ButtonPress); frame_adjust_state(client->frame); - break; - case OB_FRAME_CONTEXT_ICONIFY: - client->frame->iconify_press = (e->type == ButtonPress); - frame_adjust_state(client->frame); - break; - case OB_FRAME_CONTEXT_ALLDESKTOPS: - client->frame->desk_press = (e->type == ButtonPress); - frame_adjust_state(client->frame); - break; - case OB_FRAME_CONTEXT_SHADE: - client->frame->shade_press = (e->type == ButtonPress); - frame_adjust_state(client->frame); - break; - default: - /* nothing changes with clicks for any other contexts */ - break; } } break; @@ -908,46 +955,21 @@ static void event_handle_client(ObClient *client, XEvent *e) 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; + client->frame->max_hover = + client->frame->desk_hover = + client->frame->shade_hover = + client->frame->iconify_hover = + client->frame->close_hover = FALSE; 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; + default: + but = context_to_button(client->frame, con, FALSE); + if (but && !*but && !pb) { + *but = TRUE; frame_adjust_state(client->frame); } break; - default: - break; } break; case LeaveNotify: @@ -958,38 +980,19 @@ static void event_handle_client(ObClient *client, XEvent *e) 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->max_hover = + client->frame->desk_hover = + client->frame->shade_hover = + client->frame->iconify_hover = client->frame->close_hover = FALSE; - frame_adjust_state(client->frame); + if (e->xcrossing.mode == NotifyGrab) { + client->frame->max_press = + client->frame->desk_press = + client->frame->shade_press = + client->frame->iconify_press = + client->frame->close_press = FALSE; } break; - case OB_FRAME_CONTEXT_MAXIMIZE: - client->frame->max_hover = FALSE; - frame_adjust_state(client->frame); - break; - case OB_FRAME_CONTEXT_ALLDESKTOPS: - client->frame->desk_hover = FALSE; - frame_adjust_state(client->frame); - break; - case OB_FRAME_CONTEXT_SHADE: - client->frame->shade_hover = FALSE; - frame_adjust_state(client->frame); - break; - case OB_FRAME_CONTEXT_ICONIFY: - client->frame->iconify_hover = FALSE; - frame_adjust_state(client->frame); - break; - case OB_FRAME_CONTEXT_CLOSE: - client->frame->close_hover = FALSE; - frame_adjust_state(client->frame); - break; case OB_FRAME_CONTEXT_FRAME: /* When the mouse leaves an animating window, don't use the corresponding enter events. Pretend like the animating window @@ -1016,6 +1019,15 @@ static void event_handle_client(ObClient *client, XEvent *e) } break; default: + but = context_to_button(client->frame, con, FALSE); + if (but) { + *but = FALSE; + if (e->xcrossing.mode == NotifyGrab) { + but = context_to_button(client->frame, con, TRUE); + *but = FALSE; + } + frame_adjust_state(client->frame); + } break; } break; @@ -1024,26 +1036,6 @@ static void event_handle_client(ObClient *client, XEvent *e) 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; - frame_adjust_state(client->frame); - break; - case OB_FRAME_CONTEXT_ALLDESKTOPS: - client->frame->desk_hover = TRUE; - frame_adjust_state(client->frame); - break; - case OB_FRAME_CONTEXT_SHADE: - client->frame->shade_hover = TRUE; - frame_adjust_state(client->frame); - break; - case OB_FRAME_CONTEXT_ICONIFY: - client->frame->iconify_hover = TRUE; - frame_adjust_state(client->frame); - break; - case OB_FRAME_CONTEXT_CLOSE: - client->frame->close_hover = TRUE; - frame_adjust_state(client->frame); - break; case OB_FRAME_CONTEXT_FRAME: if (grab_on_keyboard()) break; @@ -1075,6 +1067,15 @@ static void event_handle_client(ObClient *client, XEvent *e) } break; default: + but = context_to_button(client->frame, con, FALSE); + if (but) { + *but = TRUE; + if (e->xcrossing.mode == NotifyUngrab) { + but = context_to_button(client->frame, con, TRUE); + *but = (con == pcon); + } + frame_adjust_state(client->frame); + } break; } break; @@ -1095,7 +1096,7 @@ static void event_handle_client(ObClient *client, XEvent *e) RECT_TO_DIMS(client->area, x, y, w, h); ob_debug("ConfigureRequest for \"%s\" desktop %d wmstate %d " - "visibile %d\n" + "visible %d\n" " x %d y %d w %d h %d b %d\n", client->title, screen_desktop, client->wmstate, client->frame->visible, @@ -1108,12 +1109,11 @@ static void event_handle_client(ObClient *client, XEvent *e) /* 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 + coordinates (since they include the border width) and we need to a notify then */ move = TRUE; } - if (e->xconfigurerequest.value_mask & CWStackMode) { ObClient *sibling = NULL; gulong ignore_start; @@ -1153,16 +1153,14 @@ static void event_handle_client(ObClient *client, XEvent *e) (e->xconfigurerequest.value_mask & CWWidth) || (e->xconfigurerequest.value_mask & CWHeight)) { + /* don't allow clients to move shaded windows (fvwm does this) + */ 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; @@ -1216,7 +1214,7 @@ static void event_handle_client(ObClient *client, XEvent *e) } { - gint lw,lh; + gint lw, lh; client_try_configure(client, &x, &y, &w, &h, &lw, &lh, FALSE); @@ -1225,8 +1223,7 @@ static void event_handle_client(ObClient *client, XEvent *e) 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 */ + /* same for y */ if ((e->xconfigurerequest.value_mask & CWHeight && !(e->xconfigurerequest.value_mask & CWY))) client_gravity_resize_h(client, &y, client->area.height,h); @@ -1289,32 +1286,10 @@ static void event_handle_client(ObClient *client, XEvent *e) msgtype = e->xclient.message_type; if (msgtype == prop_atoms.wm_change_state) { - /* compress changes into a single change */ - 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. */ - if (ce.xclient.message_type != msgtype) { - XPutBackEvent(ob_display, &ce); - break; - } - e->xclient = ce.xclient; - } + compress_client_message_event(e, &ce, client->window, msgtype); 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, 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. */ - if (ce.xclient.message_type != msgtype) { - XPutBackEvent(ob_display, &ce); - break; - } - e->xclient = ce.xclient; - } + compress_client_message_event(e, &ce, client->window, msgtype); if ((unsigned)e->xclient.data.l[0] < screen_num_desktops || (unsigned)e->xclient.data.l[0] == DESKTOP_ALL) client_set_desktop(client, (unsigned)e->xclient.data.l[0], @@ -1348,10 +1323,7 @@ static void event_handle_client(ObClient *client, XEvent *e) (e->xclient.data.l[0] == 2 ? "user" : "INVALID")))); /* XXX make use of data.l[2] !? */ if (e->xclient.data.l[0] == 1 || e->xclient.data.l[0] == 2) { - /* don't use the user's timestamp for client_focus, cuz if it's - an old broken timestamp (happens all the time) then focus - won't move even though we're trying to move it - event_curtime = e->xclient.data.l[1];*/ + event_curtime = e->xclient.data.l[1]; if (e->xclient.data.l[1] == 0) ob_debug_type(OB_DEBUG_APP_BUGS, "_NET_ACTIVE_WINDOW message for window %s is" @@ -1359,8 +1331,8 @@ static void event_handle_client(ObClient *client, XEvent *e) } else ob_debug_type(OB_DEBUG_APP_BUGS, "_NET_ACTIVE_WINDOW message for window %s is " - "missing source indication\n"); - client_activate(client, TRUE, TRUE, TRUE, + "missing source indication\n", client->title); + client_activate(client, FALSE, TRUE, TRUE, (e->xclient.data.l[0] == 0 || e->xclient.data.l[0] == 2)); } else if (msgtype == prop_atoms.net_wm_moveresize) { @@ -1429,8 +1401,7 @@ static void event_handle_client(ObClient *client, XEvent *e) 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 */ + /* same for y */ if (!(e->xclient.data.l[0] & 1 << 9)) client_gravity_resize_h(client, &y, client->area.height,h); } @@ -1543,6 +1514,13 @@ static void event_handle_client(ObClient *client, XEvent *e) reconfigure the window if it needs to. emacs will update its normal hints every time it receives a conigurenotify */ client_reconfigure(client, FALSE); + } else if (msgtype == prop_atoms.motif_wm_hints) { + client_get_mwm_hints(client); + /* This can override some mwm hints */ + client_get_type_and_transientness(client); + + /* Apply the changes to the window */ + client_setup_decor_and_functions(client, TRUE); } else if (msgtype == XA_WM_HINTS) { client_update_wmhints(client); } else if (msgtype == XA_WM_TRANSIENT_FOR) { @@ -1560,10 +1538,8 @@ static void event_handle_client(ObClient *client, XEvent *e) client_update_protocols(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) { + else if (msgtype == prop_atoms.net_wm_strut || + msgtype == prop_atoms.net_wm_strut_partial) { client_update_strut(client); } else if (msgtype == prop_atoms.net_wm_icon) { @@ -1595,9 +1571,22 @@ static void event_handle_client(ObClient *client, XEvent *e) default: ; #ifdef SHAPE - if (extensions_shape && e->type == extensions_shape_event_basep) { - client->shaped = ((XShapeEvent*)e)->shaped; - frame_adjust_shape(client->frame); + { + int kind; + if (extensions_shape && e->type == extensions_shape_event_basep) { + switch (((XShapeEvent*)e)->kind) { + case ShapeBounding: + case ShapeClip: + client->shaped = ((XShapeEvent*)e)->shaped; + kind = ShapeBounding; + break; + case ShapeInput: + client->shaped_input = ((XShapeEvent*)e)->shaped; + kind = ShapeInput; + break; + } + frame_adjust_shape_kind(client->frame, kind); + } } #endif } @@ -1637,8 +1626,6 @@ static void event_handle_dockapp(ObDockApp *app, XEvent *e) dock_remove(app, TRUE); break; case DestroyNotify: - dock_remove(app, FALSE); - break; case ReparentNotify: dock_remove(app, FALSE); break; @@ -1672,6 +1659,21 @@ static ObMenuFrame* find_active_or_last_menu(void) return ret; } +static gboolean event_handle_prompt(ObPrompt *p, XEvent *e) +{ + switch (e->type) { + case ButtonPress: + case ButtonRelease: + case MotionNotify: + return prompt_mouse_event(p, e); + break; + case KeyPress: + return prompt_key_event(p, e); + break; + } + return FALSE; +} + static gboolean event_handle_menu_keyboard(XEvent *ev) { guint keycode, state; @@ -1698,7 +1700,8 @@ static gboolean event_handle_menu_keyboard(XEvent *ev) else if (keycode == ob_keycode(OB_KEY_LEFT)) { /* Left goes to the parent menu */ - menu_frame_select(frame, NULL, TRUE); + if (frame->parent) + menu_frame_select(frame, NULL, TRUE); ret = TRUE; } @@ -2013,7 +2016,7 @@ void event_cancel_all_key_grabs(void) XSync(ob_display, FALSE); } -gboolean event_time_after(Time t1, Time t2) +gboolean event_time_after(guint32 t1, guint32 t2) { g_assert(t1 != CurrentTime); g_assert(t2 != CurrentTime); @@ -2026,8 +2029,10 @@ gboolean event_time_after(Time t1, Time t2) - http://tronche.com/gui/x/xlib/input/pointer-grabbing.html */ - /* TIME_HALF is half of the number space of a Time type variable */ -#define TIME_HALF (Time)(1 << (sizeof(Time)*8-1)) + /* TIME_HALF is not half of the number space of a Time type variable. + * Rather, it is half the number space of a timestamp value, which is + * always 32 bits. */ +#define TIME_HALF (guint32)(1 << 31) if (t2 >= TIME_HALF) /* t2 is in the second half so t1 might wrap around and be smaller than