diff --git a/src/display-x11.cc b/src/display-x11.cc index 78a9144e6c..3dade66a66 100644 --- a/src/display-x11.cc +++ b/src/display-x11.cc @@ -234,6 +234,9 @@ bool display_output_x11::shutdown() { return true; } +void process_surface_events(conky::display_output_x11 *surface, + Display *display); + bool display_output_x11::main_loop_wait(double t) { /* wait for X event or timeout */ if (!display || !window.gc) return true; @@ -423,12 +426,11 @@ bool display_output_x11::main_loop_wait(double t) { #define EV_HANDLER(name) \ bool _conky_ev_handle_##name(conky::display_output_x11 *surface, \ Display *display, XEvent &ev, bool *consumed, \ - bool *focus) + void **cookie) #ifdef OWN_WINDOW -#ifdef BUILD_MOUSE_EVENTS #ifdef BUILD_XINPUT -EV_HANDLER(mouse_input) { +EV_HANDLER(xinput_motion) { if (ev.type != GenericEvent || ev.xcookie.extension != window.xi_opcode) return false; @@ -470,30 +472,29 @@ EV_HANDLER(mouse_input) { data->root_y < (window.y + window.height))); if (cursor_over_conky) { if (!cursor_inside) { - *consumed = llua_mouse_hook(mouse_crossing_event( + llua_mouse_hook(mouse_crossing_event( mouse_event_t::AREA_ENTER, data->root_x - window.x, data->root_y - window.x, data->root_x, data->root_y)); } cursor_inside = true; } else if (cursor_inside) { - *consumed = llua_mouse_hook(mouse_crossing_event( + llua_mouse_hook(mouse_crossing_event( mouse_event_t::AREA_LEAVE, data->root_x - window.x, data->root_y - window.x, data->root_x, data->root_y)); cursor_inside = false; } } - // TODO: Handle other events - XFreeEventData(display, &ev.xcookie); return true; } -#else /* BUILD_XINPUT */ +#endif /* BUILD_XINPUT */ EV_HANDLER(mouse_input) { if (ev.type != ButtonPress && ev.type != ButtonRelease && ev.type != MotionNotify) return false; if (ev.xany.window != window.window) return true; // Skip other windows +#ifdef BUILD_MOUSE_EVENTS switch (ev.type) { case ButtonPress: { modifier_state_t mods = x11_modifier_state(ev.xbutton.state); @@ -509,7 +510,6 @@ EV_HANDLER(mouse_input) { mouse_event_t::MOUSE_PRESS, ev.xbutton.x, ev.xbutton.y, ev.xbutton.x_root, ev.xbutton.y_root, button, mods)); } - return true; } case ButtonRelease: { /* don't report scroll release events */ @@ -520,49 +520,37 @@ EV_HANDLER(mouse_input) { *consumed = llua_mouse_hook(mouse_button_event( mouse_event_t::MOUSE_RELEASE, ev.xbutton.x, ev.xbutton.y, ev.xbutton.x_root, ev.xbutton.y_root, button, mods)); - return true; } case MotionNotify: { modifier_state_t mods = x11_modifier_state(ev.xmotion.state); *consumed = llua_mouse_hook(mouse_move_event(ev.xmotion.x, ev.xmotion.y, ev.xmotion.x_root, ev.xmotion.y_root, mods)); - return true; } - default: - return false; // unreachable } -} -#endif /* BUILD_XINPUT */ #else /* BUILD_MOUSE_EVENTS */ -EV_HANDLER(mouse_input) { - if (ev.type != ButtonPress && ev.type != ButtonRelease && - ev.type != MotionNotify) - return false; - if (ev.xany.window != window.window) return true; // Skip other windows // always propagate mouse input if not handling mouse events *consumed = false; +#endif /* BUILD_MOUSE_EVENTS */ - // don't focus if not a click - if (ev.type != ButtonPress) return true; - - // skip if not own_window if (!own_window.get(*state)) return true; - - // don't focus if normal but undecorated - if (own_window_type.get(*state) == TYPE_NORMAL && - TEST_HINT(own_window_hints.get(*state), HINT_UNDECORATED)) - return true; - - // don't force focus if desktop window - if (own_window_type.get(*state) == TYPE_DESKTOP) return true; - - // finally, else focus - *focus = true; + switch (own_window_type.get(*state)) { + case window_type::TYPE_NORMAL: + case window_type::TYPE_UTILITY: + // decorated normal windows always consume events + if (!TEST_HINT(own_window_hints.get(*state), HINT_UNDECORATED)) { + *consumed = true; + } + break; + case window_type::TYPE_DESKTOP: + // assume conky is always on bottom; nothing to propagate events to + *consumed = true; + default: + break; + } return true; } -#endif /* BUILD_MOUSE_EVENTS */ #endif /* OWN_WINDOW */ EV_HANDLER(property_notify) { if (ev.type != PropertyNotify) return false; @@ -690,16 +678,20 @@ EV_HANDLER(damage) { return false; } /// /// @return true if event should move input focus to conky bool process_event(conky::display_output_x11 *surface, Display *display, - XEvent ev, bool *consumed, bool *focus) { -#define HANDLE_EV(handler) \ - if (_conky_ev_handle_##handler(surface, display, ev, consumed, focus)) \ + XEvent ev, bool *consumed, void **cookie) { +#define HANDLE_EV(handler) \ + if (_conky_ev_handle_##handler(surface, display, ev, consumed, cookie)) \ return true +#ifdef BUILD_XINPUT + // handles enter & leave events better + HANDLE_EV(xinput_motion); +#endif /* BUILD_XINPUT */ HANDLE_EV(mouse_input); HANDLE_EV(property_notify); // only accept remaining events if they're sent to Conky. - if (ev.xany.window != window.window) return; + if (ev.xany.window != window.window) return false; HANDLE_EV(expose); HANDLE_EV(reparent); @@ -707,10 +699,6 @@ bool process_event(conky::display_output_x11 *surface, Display *display, HANDLE_EV(damage); // event not handled - - // *consumed = false; // old behavior - // we don't want to forward majoriy of events though - return false; } @@ -732,14 +720,12 @@ void process_surface_events(conky::display_output_x11 *surface, consumed. */ bool consumed = true; - bool focus = false; - process_event(surface, display, ev, &consumed, &focus); + void *cookie = nullptr; + bool handled = process_event(surface, display, ev, &consumed, &cookie); - if (!consumed) { - propagate_x11_event(ev); - } else if (focus) { - XSetInputFocus(display, window.window, RevertToParent, CurrentTime); - } + if (!consumed) { propagate_x11_event(ev, cookie); } + + if (cookie != nullptr) { free(cookie); } } DBGP2("Done processing %d events.", pending); diff --git a/src/x11.cc b/src/x11.cc index 9acdfe3c57..d6500673af 100644 --- a/src/x11.cc +++ b/src/x11.cc @@ -1376,7 +1376,9 @@ int ev_to_mask(int event_type) { } } -void propagate_x11_event(XEvent &ev) { +void propagate_x11_event(XEvent &ev, void *cookie) { + bool focus = ev.type == ButtonPress; + InputEvent *i_ev = xev_as_input_event(ev); if (i_ev == nullptr) { // Not a known input event; blindly propagating them causes loops and all @@ -1410,7 +1412,10 @@ void propagate_x11_event(XEvent &ev) { } XUngrabPointer(display, CurrentTime); - XSendEvent(display, i_ev->common.window, False, ev_to_mask(i_ev->type), &ev); + XSendEvent(display, i_ev->common.window, True, ev_to_mask(i_ev->type), &ev); + if (focus) { + XSetInputFocus(display, i_ev->common.window, RevertToParent, CurrentTime); + } } /// @brief This function returns the last descendant of a window (leaf) on the diff --git a/src/x11.h b/src/x11.h index 48ccad425a..d18dff39a4 100644 --- a/src/x11.h +++ b/src/x11.h @@ -157,7 +157,7 @@ union InputEvent { // Returns InputEvent pointer to provided XEvent is an input event; nullptr // otherwise. InputEvent *xev_as_input_event(XEvent &ev); -void propagate_x11_event(XEvent &ev); +void propagate_x11_event(XEvent &ev, void *cookie); /// @brief Tries getting a list of windows ordered from bottom to top. ///