mirror of
https://github.com/Llewellynvdm/conky.git
synced 2024-12-25 12:10:03 +00:00
Fix X11 area enter & leave bug
Signed-off-by: Tin <tin.svagelj@live.com>
This commit is contained in:
parent
bf900545c0
commit
a4ac632db7
@ -169,7 +169,6 @@ if(BUILD_X11)
|
||||
option(BUILD_XINERAMA "Build Xinerama support" true)
|
||||
option(BUILD_XDBE "Build Xdbe (double-buffer) support" true)
|
||||
option(BUILD_XFT "Build Xft (freetype fonts) support" true)
|
||||
option(BUILD_IMLIB2 "Enable Imlib2 support" true)
|
||||
option(BUILD_XSHAPE "Enable Xshape support" true)
|
||||
else(BUILD_X11)
|
||||
set(OWN_WINDOW false CACHE BOOL "Enable own_window support" FORCE)
|
||||
@ -178,7 +177,6 @@ else(BUILD_X11)
|
||||
set(BUILD_XINERAMA false CACHE BOOL "Build Xinerama support" FORCE)
|
||||
set(BUILD_XDBE false CACHE BOOL "Build Xdbe (double-buffer) support" FORCE)
|
||||
set(BUILD_XFT false CACHE BOOL "Build Xft (freetype fonts) support" FORCE)
|
||||
set(BUILD_IMLIB2 false CACHE BOOL "Enable Imlib2 support" FORCE)
|
||||
set(BUILD_XSHAPE false CACHE BOOL "Enable Xshape support" FORCE)
|
||||
set(BUILD_NVIDIA false)
|
||||
endif(BUILD_X11)
|
||||
@ -192,9 +190,14 @@ if(BUILD_WAYLAND)
|
||||
endif(BUILD_WAYLAND)
|
||||
|
||||
if(BUILD_GUI)
|
||||
option(BUILD_IMLIB2 "Enable Imlib2 support" true)
|
||||
option(BUILD_MOUSE_EVENTS "Enable mouse event support" true)
|
||||
endif(BUILD_GUI)
|
||||
|
||||
if(BUILD_GUI AND BUILD_MOUSE_EVENTS)
|
||||
option(BUILD_XINPUT "Build Xinput 2 support" true)
|
||||
endif(BUILD_GUI AND BUILD_MOUSE_EVENTS)
|
||||
|
||||
if(OWN_WINDOW)
|
||||
option(BUILD_ARGB "Build ARGB (real transparency) support" true)
|
||||
else(OWN_WINDOW)
|
||||
|
@ -402,6 +402,29 @@ if(BUILD_X11)
|
||||
|
||||
set(conky_libs ${conky_libs} ${X11_Xfixes_LIB})
|
||||
endif(BUILD_XFIXES)
|
||||
|
||||
# check for Xinput
|
||||
if(BUILD_XINPUT)
|
||||
if(NOT X11_Xinput_FOUND)
|
||||
message(FATAL_ERROR "Unable to find Xinput library")
|
||||
endif(NOT X11_Xinput_FOUND)
|
||||
|
||||
set(conky_libs ${conky_libs} ${X11_Xinput_LIB})
|
||||
endif(BUILD_XINPUT)
|
||||
|
||||
|
||||
if(X11_xcb_FOUND)
|
||||
set(HAVE_XCB true)
|
||||
set(conky_libs ${conky_libs} ${X11_xcb_LIB})
|
||||
if(X11_xcb_errors_FOUND)
|
||||
set(HAVE_XCB_ERRORS true)
|
||||
set(conky_libs ${conky_libs} ${X11_xcb_LIB} ${X11_xcb_errors_LIB})
|
||||
else(X11_xcb_errors_FOUND)
|
||||
set(HAVE_XCB_ERRORS false)
|
||||
endif(X11_xcb_errors_FOUND)
|
||||
else(X11_xcb_FOUND)
|
||||
set(HAVE_XCB false)
|
||||
endif(X11_xcb_FOUND)
|
||||
else(X11_FOUND)
|
||||
message(FATAL_ERROR "Unable to find X11 library")
|
||||
endif(X11_FOUND)
|
||||
|
@ -42,6 +42,9 @@
|
||||
|
||||
#cmakedefine HAVE_CLOCK_GETTIME 1
|
||||
|
||||
#cmakedefine HAVE_XCB 1
|
||||
#cmakedefine HAVE_XCB_ERRORS 1
|
||||
|
||||
#cmakedefine BUILD_WAYLAND 1
|
||||
|
||||
#cmakedefine BUILD_X11 1
|
||||
@ -60,6 +63,8 @@
|
||||
|
||||
#cmakedefine BUILD_XFIXES 1
|
||||
|
||||
#cmakedefine BUILD_XINPUT 1
|
||||
|
||||
#cmakedefine BUILD_ARGB 1
|
||||
|
||||
#cmakedefine BUILD_XDBE 1
|
||||
|
@ -24,6 +24,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <X11/extensions/XI2.h>
|
||||
#include <config.h>
|
||||
|
||||
#ifdef BUILD_X11
|
||||
@ -44,6 +45,9 @@
|
||||
#endif /* BUILD_IMLIB2 */
|
||||
#ifdef BUILD_MOUSE_EVENTS
|
||||
#include "mouse-events.h"
|
||||
#ifdef BUILD_XINPUT
|
||||
#include <X11/extensions/XInput2.h>
|
||||
#endif /* BUILD_XINPUT */
|
||||
#endif /* BUILD_MOUSE_EVENTS */
|
||||
#endif /* BUILD_X11 */
|
||||
|
||||
@ -51,6 +55,7 @@
|
||||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "colours.h"
|
||||
#include "conky.h"
|
||||
@ -229,27 +234,6 @@ bool display_output_x11::shutdown() {
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void propagate_unconsumed_event(XEvent &ev, bool is_consumed) {
|
||||
const uint32_t capture_mask = ButtonPressMask | ButtonReleaseMask | ButtonMotionMask;
|
||||
|
||||
// SAFETY: XEvent is a union and all event types this function gets called for
|
||||
// share same alignment and accessed fields share same offsets.
|
||||
if (!is_consumed) {
|
||||
/* forward the event to the desktop window */
|
||||
ev.xmotion.window = window.desktop;
|
||||
ev.xmotion.x = ev.xmotion.x_root;
|
||||
ev.xmotion.y = ev.xmotion.y_root;
|
||||
XSendEvent(display, window.desktop, False, capture_mask, &ev);
|
||||
if (false && ev.type == ButtonPress) {
|
||||
XSetInputFocus(display, window.desktop, RevertToNone, ev.xmotion.time);
|
||||
} else if (false && ev.type == MotionNotify) {
|
||||
XSetInputFocus(display, window.window, RevertToParent, ev.xmotion.time);
|
||||
}
|
||||
} else {
|
||||
XSetInputFocus(display, window.window, RevertToParent, ev.xmotion.time);
|
||||
}
|
||||
}
|
||||
|
||||
bool display_output_x11::main_loop_wait(double t) {
|
||||
/* wait for X event or timeout */
|
||||
if (!display || !window.gc) return true;
|
||||
@ -397,6 +381,50 @@ bool display_output_x11::main_loop_wait(double t) {
|
||||
bool consumed = false;
|
||||
|
||||
XNextEvent(display, &ev);
|
||||
|
||||
#ifdef BUILD_XINPUT
|
||||
if (ev.type == GenericEvent && ev.xcookie.extension == window.xi_opcode) {
|
||||
XGetEventData(display, &ev.xcookie);
|
||||
if (ev.xcookie.evtype == XI_Motion) {
|
||||
auto *data = reinterpret_cast<XIDeviceEvent*>(ev.xcookie.data);
|
||||
|
||||
// XQueryPointer returns wrong results because conky is a weird window
|
||||
Window query_result = query_x11_window_at_pos(display, data->root_x, data->root_y);
|
||||
|
||||
//printf("over: %#x w:%#x d:%#x r:%#x\n", query_result, window.window, window.desktop, window.root);
|
||||
|
||||
static bool cursor_inside = false;
|
||||
if ((query_result != 0 && query_result == window.window) ||
|
||||
((query_result == window.desktop || query_result == window.root || query_result == 0) && data->root_x >= window.x && data->root_x < (window.x + window.width) &&
|
||||
data->root_y >= window.y && data->root_y < (window.y + window.height))) {
|
||||
//puts("over self");
|
||||
if (!cursor_inside) {
|
||||
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) {
|
||||
//puts("left");
|
||||
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;
|
||||
} else {
|
||||
//printf("not over self\n");
|
||||
}
|
||||
}
|
||||
XFreeEventData(display, &ev.xcookie);
|
||||
continue;
|
||||
}
|
||||
#endif /* BUILD_XINPUT */
|
||||
|
||||
// Any of the remaining events apply to conky window
|
||||
if (ev.xany.window != window.window) continue;
|
||||
switch (ev.type) {
|
||||
case Expose: {
|
||||
XRectangle r;
|
||||
@ -406,6 +434,10 @@ bool display_output_x11::main_loop_wait(double t) {
|
||||
r.height = ev.xexpose.height;
|
||||
XUnionRectWithRegion(&r, x11_stuff.region, x11_stuff.region);
|
||||
XSync(display, False);
|
||||
|
||||
// modify for propagation
|
||||
ev.xexpose.x += window.x;
|
||||
ev.xexpose.y += window.y;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -427,7 +459,7 @@ bool display_output_x11::main_loop_wait(double t) {
|
||||
#ifdef USE_ARGB
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef OWN_WINDOW
|
||||
@ -436,7 +468,7 @@ bool display_output_x11::main_loop_wait(double t) {
|
||||
if (own_window.get(*state)) {
|
||||
set_transparent_background(window.window);
|
||||
}
|
||||
break;
|
||||
continue;
|
||||
|
||||
case ConfigureNotify:
|
||||
if (own_window.get(*state)) {
|
||||
@ -477,7 +509,7 @@ bool display_output_x11::main_loop_wait(double t) {
|
||||
fixed_pos = 1;
|
||||
} */
|
||||
}
|
||||
break;
|
||||
continue;
|
||||
|
||||
case ButtonPress:
|
||||
#ifdef BUILD_MOUSE_EVENTS
|
||||
@ -519,7 +551,6 @@ bool display_output_x11::main_loop_wait(double t) {
|
||||
/* allow conky to hold input focus. */
|
||||
break;
|
||||
}
|
||||
propagate_unconsumed_event(ev, consumed);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -553,7 +584,6 @@ bool display_output_x11::main_loop_wait(double t) {
|
||||
/* allow conky to hold input focus. */
|
||||
break;
|
||||
}
|
||||
propagate_unconsumed_event(ev, consumed);
|
||||
}
|
||||
break;
|
||||
#ifdef BUILD_MOUSE_EVENTS
|
||||
@ -565,30 +595,25 @@ bool display_output_x11::main_loop_wait(double t) {
|
||||
consumed = llua_mouse_hook(mouse_move_event(
|
||||
ev.xmotion.x, ev.xmotion.y, ev.xmotion.x_root, ev.xmotion.y_root, ev.xmotion.state
|
||||
));
|
||||
propagate_unconsumed_event(ev, consumed);
|
||||
break;
|
||||
case LeaveNotify:
|
||||
XUngrabPointer(display, ev.xcrossing.time);
|
||||
case EnterNotify:
|
||||
{
|
||||
if (window.xi_opcode == 0) {
|
||||
bool not_over_conky = ev.xcrossing.x_root <= window.x || ev.xcrossing.y_root <= window.y ||
|
||||
ev.xcrossing.x_root >= window.x + window.width || ev.xcrossing.y_root >= window.y + window.height;
|
||||
static bool pointer_inside = false;
|
||||
|
||||
if ((not_over_conky && ev.xcrossing.type == LeaveNotify) ||
|
||||
(!pointer_inside && ev.xcrossing.type == EnterNotify)) {
|
||||
(!not_over_conky && ev.xcrossing.type == EnterNotify)) {
|
||||
llua_mouse_hook(mouse_crossing_event(
|
||||
ev.xcrossing.type == EnterNotify ? mouse_event_t::AREA_ENTER: mouse_event_t::AREA_LEAVE,
|
||||
ev.xcrossing.type == EnterNotify ? mouse_event_t::AREA_ENTER : mouse_event_t::AREA_LEAVE,
|
||||
ev.xcrossing.x, ev.xcrossing.y, ev.xcrossing.x_root, ev.xcrossing.y_root
|
||||
));
|
||||
pointer_inside = ev.xcrossing.type == EnterNotify;
|
||||
// can't propagate these events in a way that makes sense
|
||||
}
|
||||
}
|
||||
break;
|
||||
// can't propagate these events in a way that makes sense for desktop
|
||||
continue;
|
||||
#endif /* BUILD_MOUSE_EVENTS */
|
||||
#endif
|
||||
|
||||
#endif /* OWN_WINDOW */
|
||||
default:
|
||||
#ifdef BUILD_XDAMAGE
|
||||
if (ev.type == x11_stuff.event_base + XDamageNotify) {
|
||||
@ -597,10 +622,20 @@ bool display_output_x11::main_loop_wait(double t) {
|
||||
XFixesSetRegion(display, x11_stuff.part, &dev->area, 1);
|
||||
XFixesUnionRegion(display, x11_stuff.region2, x11_stuff.region2,
|
||||
x11_stuff.part);
|
||||
continue; // TODO: Propagate damage
|
||||
}
|
||||
#endif /* BUILD_XDAMAGE */
|
||||
break;
|
||||
}
|
||||
|
||||
if (!consumed) {
|
||||
propagate_x11_event(ev);
|
||||
} else {
|
||||
InputEvent *i_ev = xev_as_input_event(ev);
|
||||
if (i_ev != nullptr) {
|
||||
XSetInputFocus(display, window.window, RevertToParent, i_ev->common.time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BUILD_XDAMAGE
|
||||
@ -648,6 +683,7 @@ bool display_output_x11::main_loop_wait(double t) {
|
||||
}
|
||||
|
||||
void display_output_x11::sigterm_cleanup() {
|
||||
puts("sigtermed");
|
||||
XDestroyRegion(x11_stuff.region);
|
||||
x11_stuff.region = nullptr;
|
||||
#ifdef BUILD_XDAMAGE
|
||||
@ -660,6 +696,7 @@ void display_output_x11::sigterm_cleanup() {
|
||||
}
|
||||
|
||||
void display_output_x11::cleanup() {
|
||||
puts("normal cleanup");
|
||||
if (window_created == 1) {
|
||||
int border_total = get_border_total();
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
#define _LOGGING_H
|
||||
|
||||
#include <cstdio>
|
||||
#include <cinttypes>
|
||||
#include <stdexcept>
|
||||
#include "config.h"
|
||||
#include "i18n.h"
|
||||
@ -81,6 +82,7 @@ void NORM_ERR(const char *format, Args &&...args) {
|
||||
|
||||
/* critical error with additional cleanup */
|
||||
template <typename... Args>
|
||||
__attribute__((noreturn))
|
||||
inline void CRIT_ERR_FREE(void *memtofree1, void *memtofree2,
|
||||
const char *format, Args &&...args) {
|
||||
NORM_ERR(format, args...);
|
||||
@ -92,6 +94,7 @@ inline void CRIT_ERR_FREE(void *memtofree1, void *memtofree2,
|
||||
|
||||
/* critical error */
|
||||
template <typename... Args>
|
||||
__attribute__((noreturn))
|
||||
inline void CRIT_ERR(const char *format, Args &&...args) {
|
||||
CRIT_ERR_FREE(nullptr, nullptr, format, args...);
|
||||
}
|
||||
|
215
src/x11.cc
215
src/x11.cc
@ -28,10 +28,18 @@
|
||||
*/
|
||||
|
||||
#include <X11/X.h>
|
||||
#include <sys/types.h>
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
#include "conky.h"
|
||||
#include "logging.h"
|
||||
#include "x11.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wvariadic-macros"
|
||||
@ -61,10 +69,24 @@
|
||||
#ifdef BUILD_XFIXES
|
||||
#include <X11/extensions/Xfixes.h>
|
||||
#endif /* BUILD_XFIXES */
|
||||
#ifdef BUILD_XINPUT
|
||||
#include <vector>
|
||||
#include <X11/extensions/XInput2.h>
|
||||
#endif /* BUILD_XINPUT */
|
||||
#ifdef HAVE_XCB_ERRORS
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xcb_errors.h>
|
||||
#endif
|
||||
|
||||
/* some basic X11 stuff */
|
||||
Display *display = nullptr;
|
||||
|
||||
|
||||
#ifdef HAVE_XCB_ERRORS
|
||||
xcb_connection_t *xcb_connection;
|
||||
xcb_errors_context_t *xcb_errors_ctx;
|
||||
#endif
|
||||
|
||||
/* Window stuff */
|
||||
struct conky_x11_window window;
|
||||
|
||||
@ -215,20 +237,77 @@ imlib_cache_size_setting imlib_cache_size;
|
||||
/******************** </SETTINGS> ************************/
|
||||
|
||||
/* WARNING, this type not in Xlib spec */
|
||||
static int __attribute__((noreturn))
|
||||
static int
|
||||
x11_error_handler(Display *d, XErrorEvent *err) {
|
||||
char *error_name = nullptr;
|
||||
bool name_allocated = false;
|
||||
|
||||
char *code_description = nullptr;
|
||||
bool code_allocated = false;
|
||||
|
||||
#ifdef HAVE_XCB_ERRORS
|
||||
if (xcb_errors_ctx != nullptr) {
|
||||
const char *extension;
|
||||
const char *base_name = xcb_errors_get_name_for_error(xcb_errors_ctx, err->error_code, &extension);
|
||||
if (extension != nullptr) {
|
||||
error_name = new char(strlen(base_name) + strlen(extension) + 4);
|
||||
sprintf(error_name, "%s (%s)", base_name, extension);
|
||||
name_allocated = true;
|
||||
} else {
|
||||
error_name = const_cast<char*>(base_name);
|
||||
}
|
||||
|
||||
const char *major = xcb_errors_get_name_for_major_code(xcb_errors_ctx, err->request_code);
|
||||
const char *minor = xcb_errors_get_name_for_minor_code(xcb_errors_ctx, err->request_code, err->minor_code);
|
||||
if (minor != nullptr) {
|
||||
code_description = new char(strlen(base_name) + strlen(extension) + 4);
|
||||
sprintf(code_description, "%s - %s", major, minor);
|
||||
code_allocated = true;
|
||||
} else {
|
||||
code_description = const_cast<char*>(major);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (error_name == nullptr) {
|
||||
if (err->error_code > 0 && err->error_code < 17) {
|
||||
static std::array<std::string, 17> NAMES = {
|
||||
"request", "value", "window", "pixmap", "atom", "cursor", "font", "match",
|
||||
"drawable", "access", "alloc", "colormap", "G context", "ID choice",
|
||||
"name", "length", "implementation"
|
||||
};
|
||||
error_name = const_cast<char*>(NAMES[err->error_code].c_str());
|
||||
} else {
|
||||
static char code_name_buffer[3];
|
||||
error_name = reinterpret_cast<char*>(&code_name_buffer);
|
||||
sprintf(error_name, "%d", err->error_code);
|
||||
}
|
||||
}
|
||||
if (code_description == nullptr) {
|
||||
code_description = new char(30 + 6 + 1);
|
||||
sprintf(code_description, "error code: [major: %i, minor: %i]", err->request_code, err->minor_code);
|
||||
code_allocated = true;
|
||||
}
|
||||
|
||||
NORM_ERR(
|
||||
"X Error: type %i Display %lx XID %li serial %lu error_code %i "
|
||||
"request_code %i minor_code %i other Display: %lx\n",
|
||||
err->type, (long unsigned)err->display,
|
||||
static_cast<long>(err->resourceid), err->serial, err->error_code,
|
||||
err->request_code, err->minor_code, (long unsigned)d);
|
||||
abort();
|
||||
"X %s Error:\n"
|
||||
"Display: %lx, XID: %li, Serial: %lu\n"
|
||||
"%s",
|
||||
error_name,
|
||||
reinterpret_cast<uint64_t>(err->display),
|
||||
static_cast<int64_t>(err->resourceid), err->serial,
|
||||
code_description
|
||||
);
|
||||
|
||||
if (name_allocated) free(error_name);
|
||||
if (code_allocated) free(code_description);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __attribute__((noreturn)) x11_ioerror_handler(Display *d) {
|
||||
NORM_ERR("X Error: Display %lx\n", (long unsigned)d);
|
||||
exit(1);
|
||||
__attribute__((noreturn))
|
||||
static int x11_ioerror_handler(Display *d) {
|
||||
CRIT_ERR("X IO Error: Display %lx\n", reinterpret_cast<uint64_t>(d));
|
||||
}
|
||||
|
||||
/* X11 initializer */
|
||||
@ -267,6 +346,15 @@ static void init_x11() {
|
||||
|
||||
update_workarea();
|
||||
|
||||
#ifdef HAVE_XCB_ERRORS
|
||||
auto connection = xcb_connect(NULL, NULL);
|
||||
if (!xcb_connection_has_error(connection)) {
|
||||
if (xcb_errors_context_new(connection, &xcb_errors_ctx) != Success) {
|
||||
xcb_errors_ctx = nullptr;
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_XCB_ERRORS */
|
||||
|
||||
/* WARNING, this type not in Xlib spec */
|
||||
XSetErrorHandler(&x11_error_handler);
|
||||
XSetIOErrorHandler(&x11_ioerror_handler);
|
||||
@ -854,7 +942,7 @@ void x11_init_window(lua::state &l __attribute__((unused)), bool own) {
|
||||
|
||||
XFlush(display);
|
||||
|
||||
long input_mask = ExposureMask | PropertyChangeMask;
|
||||
int64_t input_mask = ExposureMask | PropertyChangeMask;
|
||||
#ifdef OWN_WINDOW
|
||||
if (own_window.get(l)) {
|
||||
input_mask |= StructureNotifyMask | ButtonPressMask | ButtonReleaseMask;
|
||||
@ -864,10 +952,40 @@ void x11_init_window(lua::state &l __attribute__((unused)), bool own) {
|
||||
/* it's not recommended to add event masks to special windows in X; causes a
|
||||
* crash */
|
||||
if (own_window_type.get(l) != TYPE_DESKTOP) {
|
||||
input_mask |= ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
|
||||
EnterWindowMask | LeaveWindowMask;
|
||||
input_mask |= ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
|
||||
}
|
||||
bool xinput_ok = false;
|
||||
#ifdef BUILD_XINPUT
|
||||
do { // not loop
|
||||
int _ignored; // segfault if NULL
|
||||
if (!XQueryExtension(display, "XInputExtension", &window.xi_opcode, &_ignored, &_ignored)) {
|
||||
// events will still ~work but let the user know why they're buggy
|
||||
NORM_ERR("XInput extension is not supported by X11!");
|
||||
break;
|
||||
}
|
||||
|
||||
int32_t major = 2, minor = 0;
|
||||
uint32_t retval = XIQueryVersion(display, &major, &minor);
|
||||
if (retval != Success) {
|
||||
NORM_ERR("Error: XInput 2.0 is not supported!");
|
||||
break;
|
||||
}
|
||||
unsigned char mask_bytes[(XI_LASTEVENT + 7) / 8] = {0}; /* must be zeroed! */
|
||||
XISetMask(mask_bytes, XI_Motion);
|
||||
|
||||
XIEventMask ev_masks[1];
|
||||
ev_masks[0].deviceid = XIAllDevices;
|
||||
ev_masks[0].mask_len = sizeof(mask_bytes);
|
||||
ev_masks[0].mask = mask_bytes;
|
||||
XISelectEvents(display, window.root, ev_masks, 1);
|
||||
xinput_ok = true;
|
||||
} while (false);
|
||||
#endif /* BUILD_XINPUT */
|
||||
if (!xinput_ok && own_window_type.get(l) != TYPE_DESKTOP) {
|
||||
input_mask |= EnterWindowMask | LeaveWindowMask;
|
||||
}
|
||||
#endif /* BUILD_MOUSE_EVENTS */
|
||||
window.event_mask = input_mask;
|
||||
XSelectInput(display, window.window, input_mask);
|
||||
|
||||
window_created = 1;
|
||||
@ -1229,3 +1347,74 @@ void print_mouse_speed(struct text_object *obj, char *p,
|
||||
XGetPointerControl(display, &acc_num, &acc_denom, &threshold);
|
||||
snprintf(p, p_max_size, "%d%%", (110 - threshold));
|
||||
}
|
||||
|
||||
InputEvent *xev_as_input_event(XEvent &ev) {
|
||||
if (ev.type == KeyPress || ev.type == KeyRelease ||
|
||||
ev.type == ButtonPress || ev.type == ButtonRelease || ev.type == MotionNotify ||
|
||||
ev.type == EnterNotify || ev.type == LeaveNotify) {
|
||||
return reinterpret_cast<InputEvent*>(&ev);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void propagate_x11_event(XEvent &ev) {
|
||||
InputEvent *i_ev = xev_as_input_event(ev);
|
||||
/* forward the event to the desktop window */
|
||||
if (i_ev != nullptr) {
|
||||
i_ev->common.window = window.desktop;
|
||||
i_ev->common.x = i_ev->common.x_root;
|
||||
i_ev->common.y = i_ev->common.y_root;
|
||||
}
|
||||
XSendEvent(display, window.desktop, False, window.event_mask, &ev);
|
||||
// FIXME (before-merge): Should we be setting input focus after forwarding
|
||||
// events?
|
||||
if (false && ev.type == ButtonPress) {
|
||||
XSetInputFocus(display, window.desktop, RevertToNone, i_ev->common.time);
|
||||
} else if (false && ev.type == MotionNotify) {
|
||||
XSetInputFocus(display, window.window, RevertToParent, i_ev->common.time);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BUILD_MOUSE_EVENTS
|
||||
Window last_descendant(Display* display, Window parent) {
|
||||
Window ignored, *children;
|
||||
uint32_t count;
|
||||
|
||||
Window current = parent;
|
||||
|
||||
while (XQueryTree(display, current, &ignored, &ignored, &children, &count) && count != 0) {
|
||||
current = children[count - 1];
|
||||
XFree(children);
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
Window query_x11_window_at_pos(Display* display, int x, int y) {
|
||||
Window root = DefaultRootWindow(display);
|
||||
|
||||
Window root_return, parent_return, *windows;
|
||||
unsigned int count;
|
||||
|
||||
Window last = None;
|
||||
|
||||
XWindowAttributes attrs;
|
||||
if (XQueryTree(display, root, &root_return, &parent_return, &windows, &count) != 0) {
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
if (XGetWindowAttributes(display, windows[i], &attrs)) {
|
||||
if (attrs.map_state == IsViewable && x >= attrs.x && x < (attrs.x + attrs.width) && y >= attrs.y && y < (attrs.y + attrs.height)) {
|
||||
last = windows[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count != 0) {
|
||||
XFree(windows);
|
||||
}
|
||||
}
|
||||
|
||||
return last_descendant(display, last);
|
||||
}
|
||||
|
||||
#endif /* BUILD_MOUSE_EVENTS */
|
||||
|
50
src/x11.h
50
src/x11.h
@ -5,7 +5,7 @@
|
||||
* Please see COPYING for details
|
||||
*
|
||||
* Copyright (c) 2005-2021 Brenden Matthews, Philip Kovacs, et. al.
|
||||
* (see AUTHORS)
|
||||
* (see AUTHORS)
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
@ -38,6 +38,7 @@
|
||||
#endif
|
||||
|
||||
#include "setting.hh"
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef BUILD_ARGB
|
||||
/* true if use_argb_visual=true and argb visual was found*/
|
||||
@ -78,6 +79,9 @@ struct conky_x11_window {
|
||||
Colormap colourmap;
|
||||
GC gc;
|
||||
|
||||
// Mask containing all events captured by conky
|
||||
int64_t event_mask;
|
||||
|
||||
#ifdef BUILD_XDBE
|
||||
XdbeBackBuffer back_buffer;
|
||||
#else /*BUILD_XDBE*/
|
||||
@ -86,6 +90,9 @@ struct conky_x11_window {
|
||||
#ifdef BUILD_XFT
|
||||
XftDraw *xftdraw;
|
||||
#endif /*BUILD_XFT*/
|
||||
#ifdef BUILD_XINPUT
|
||||
int32_t xi_opcode;
|
||||
#endif /* BUILD_XINPUT */
|
||||
|
||||
int width;
|
||||
int height;
|
||||
@ -106,6 +113,47 @@ void set_struts(int);
|
||||
void x11_init_window(lua::state &l, bool own);
|
||||
void deinit_x11();
|
||||
|
||||
// Fields common to all X11 input events
|
||||
struct InputEventCommon {
|
||||
int type; /* event type */
|
||||
uint64_t serial; /* # of last request processed by server */
|
||||
Bool send_event; /* true if this came from a SendEvent request */
|
||||
Display *display; /* Display the event was read from */
|
||||
Window window; /* "event" window reported relative to */
|
||||
Window root; /* root window that the event occurred on */
|
||||
Window subwindow; /* child window */
|
||||
Time time; /* milliseconds */
|
||||
int32_t x, y; /* pointer x, y coordinates in event window */
|
||||
int32_t x_root, y_root; /* coordinates relative to root */
|
||||
uint32_t state; /* key or button mask */
|
||||
};
|
||||
|
||||
union InputEvent {
|
||||
int type; // event type
|
||||
|
||||
InputEventCommon common;
|
||||
|
||||
// Discrete interfaces
|
||||
XAnyEvent xany; // common event interface
|
||||
XKeyEvent xkey; // KeyPress & KeyRelease events
|
||||
XButtonEvent xbutton; // ButtonPress & ButtonRelease events
|
||||
XMotionEvent xmotion; // MotionNotify event
|
||||
XCrossingEvent xcrossing; // EnterNotify & LeaveNotify events
|
||||
|
||||
// Ensures InputEvent matches memory layout of XEvent.
|
||||
// Accessing base variant is as code smell.
|
||||
XEvent base;
|
||||
};
|
||||
|
||||
// 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);
|
||||
|
||||
#ifdef BUILD_MOUSE_EVENTS
|
||||
|
||||
Window query_x11_window_at_pos(Display* display, int x, int y);
|
||||
#endif /* BUILD_MOUSE_EVENTS */
|
||||
|
||||
#ifdef BUILD_XDBE
|
||||
void xdbe_swap_buffers(void);
|
||||
#else
|
||||
|
Loading…
Reference in New Issue
Block a user