aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--meson.build4
-rw-r--r--project.conf2
-rw-r--r--src/main.cpp161
3 files changed, 153 insertions, 14 deletions
diff --git a/meson.build b/meson.build
index 88da653..18a0eb9 100644
--- a/meson.build
+++ b/meson.build
@@ -1,4 +1,4 @@
-project('gsr-notify', ['cpp'], version : '1.0.0', default_options : ['warning_level=2'], subproject_dir : 'depends')
+project('gsr-notify', ['cpp'], version : '1.0.1', default_options : ['warning_level=2'], subproject_dir : 'depends')
if get_option('buildtype') == 'debug'
add_project_arguments('-g3', language : ['cpp'])
@@ -31,4 +31,4 @@ executable(
)
install_subdir('images', install_dir : gsr_notify_resources_path)
-install_subdir('fonts', install_dir : gsr_notify_resources_path) \ No newline at end of file
+install_subdir('fonts', install_dir : gsr_notify_resources_path)
diff --git a/project.conf b/project.conf
index ecaf34e..14f1939 100644
--- a/project.conf
+++ b/project.conf
@@ -1,7 +1,7 @@
[package]
name = "gsr-notify"
type = "executable"
-version = "1.0.0"
+version = "1.0.1"
platforms = ["posix"]
[config]
diff --git a/src/main.cpp b/src/main.cpp
index 210e747..b8e8375 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -169,14 +169,65 @@ static const mgl_monitor* find_monitor_at_position(mgl::Window &window, mgl::vec
return &win->monitors[0];
}
-static mgl::vec2i create_window_get_center_position(Display *display) {
- const int size = 16;
+static mgl::vec2i get_cursor_position(Display *dpy, Window *window) {
+ Window root_window = None;
+ *window = None;
+ int dummy_i;
+ unsigned int dummy_u;
+ mgl::vec2i root_pos;
+ XQueryPointer(dpy, DefaultRootWindow(dpy), &root_window, window, &root_pos.x, &root_pos.y, &dummy_i, &dummy_i, &dummy_u);
+
+ // This dumb shit is done to satisfy gnome wayland. Only set |window| if a valid x11 window is focused
+ if(window) {
+ XWindowAttributes attr;
+ if(XGetWindowAttributes(dpy, *window, &attr) && attr.override_redirect)
+ *window = None;
+
+ int revert_to = 0;
+ Window input_focus_window = None;
+ if(XGetInputFocus(dpy, &input_focus_window, &revert_to)) {
+ if(input_focus_window) {
+ if(XGetWindowAttributes(dpy, input_focus_window, &attr) && attr.override_redirect)
+ *window = None;
+ } else {
+ *window = None;
+ }
+ }
+ }
+
+ return root_pos;
+}
+
+typedef struct {
+ unsigned long flags;
+ unsigned long functions;
+ unsigned long decorations;
+ long input_mode;
+ unsigned long status;
+} MotifHints;
+
+#define MWM_HINTS_DECORATIONS 2
+
+#define MWM_DECOR_NONE 0
+#define MWM_DECOR_ALL 1
+
+static void window_set_decorations_visible(Display *display, Window window, bool visible) {
+ const Atom motif_wm_hints_atom = XInternAtom(display, "_MOTIF_WM_HINTS", False);
+ MotifHints motif_hints;
+ memset(&motif_hints, 0, sizeof(motif_hints));
+ motif_hints.flags = MWM_HINTS_DECORATIONS;
+ motif_hints.decorations = visible ? MWM_DECOR_ALL : MWM_DECOR_NONE;
+ XChangeProperty(display, window, motif_wm_hints_atom, motif_wm_hints_atom, 32, PropModeReplace, (unsigned char*)&motif_hints, sizeof(motif_hints) / sizeof(long));
+}
+
+static bool create_window_get_center_position_kde(Display *display, mgl::vec2i &position) {
+ const int size = 1;
XSetWindowAttributes window_attr;
window_attr.event_mask = StructureNotifyMask;
window_attr.background_pixel = 0;
const Window window = XCreateWindow(display, DefaultRootWindow(display), 0, 0, size, size, 0, CopyFromParent, InputOutput, CopyFromParent, CWBackPixel | CWEventMask, &window_attr);
if(!window)
- return {0, 0};
+ return false;
const Atom net_wm_window_type_atom = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
const Atom net_wm_window_type_notification_atom = XInternAtom(display, "_NET_WM_WINDOW_TYPE_NOTIFICATION", False);
@@ -193,12 +244,14 @@ static mgl::vec2i create_window_get_center_position(Display *display) {
const unsigned long opacity = (unsigned long)(0xFFFFFFFFul * alpha);
XChangeProperty(display, window, net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&opacity, 1L);
+ window_set_decorations_visible(display, window, false);
+
XSizeHints *size_hints = XAllocSizeHints();
size_hints->width = size;
- size_hints->min_width = size;
- size_hints->max_width = size;
size_hints->height = size;
+ size_hints->min_width = size;
size_hints->min_height = size;
+ size_hints->max_width = size;
size_hints->max_height = size;
size_hints->flags = PSize | PMinSize | PMaxSize;
XSetWMNormalHints(display, window, size_hints);
@@ -207,8 +260,8 @@ static mgl::vec2i create_window_get_center_position(Display *display) {
XMapWindow(display, window);
XFlush(display);
+ bool got_data = false;
const int x_fd = XConnectionNumber(display);
- mgl::vec2i window_pos;
XEvent xev;
while(true) {
struct pollfd poll_fd;
@@ -224,17 +277,101 @@ static mgl::vec2i create_window_get_center_position(Display *display) {
}
XNextEvent(display, &xev);
- if(xev.type == ConfigureNotify) {
- window_pos.x = xev.xconfigure.x + xev.xconfigure.width / 2;
- window_pos.y = xev.xconfigure.y + xev.xconfigure.height / 2;
+ if(xev.type == ConfigureNotify && xev.xconfigure.window == window) {
+ got_data = xev.xconfigure.x > 0 && xev.xconfigure.y > 0;
+ position.x = xev.xconfigure.x + xev.xconfigure.width / 2;
+ position.y = xev.xconfigure.y + xev.xconfigure.height / 2;
+ break;
+ }
+ }
+
+ XDestroyWindow(display, window);
+ XFlush(display);
+
+ return got_data;
+}
+
+static bool create_window_get_center_position_gnome(Display *display, mgl::vec2i &position) {
+ const int size = 32;
+ XSetWindowAttributes window_attr;
+ window_attr.event_mask = StructureNotifyMask | ExposureMask;
+ window_attr.background_pixel = 0;
+ const Window window = XCreateWindow(display, DefaultRootWindow(display), 0, 0, size, size, 0, CopyFromParent, InputOutput, CopyFromParent, CWBackPixel | CWEventMask, &window_attr);
+ if(!window)
+ return false;
+
+ const Atom net_wm_window_opacity = XInternAtom(display, "_NET_WM_WINDOW_OPACITY", False);
+ const double alpha = 0.0;
+ const unsigned long opacity = (unsigned long)(0xFFFFFFFFul * alpha);
+ XChangeProperty(display, window, net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&opacity, 1L);
+
+ window_set_decorations_visible(display, window, false);
+
+ XSizeHints *size_hints = XAllocSizeHints();
+ size_hints->width = size;
+ size_hints->height = size;
+ size_hints->min_width = size;
+ size_hints->min_height = size;
+ size_hints->max_width = size;
+ size_hints->max_height = size;
+ size_hints->flags = PSize | PMinSize | PMaxSize;
+ XSetWMNormalHints(display, window, size_hints);
+ XFree(size_hints);
+
+ XMapWindow(display, window);
+ XFlush(display);
+
+ bool got_data = false;
+ const int x_fd = XConnectionNumber(display);
+ XEvent xev;
+ while(true) {
+ struct pollfd poll_fd;
+ poll_fd.fd = x_fd;
+ poll_fd.events = POLLIN;
+ poll_fd.revents = 0;
+ const int fds_ready = poll(&poll_fd, 1, 1000);
+ if(fds_ready == 0) {
+ fprintf(stderr, "Error: timed out waiting for MapNotify/ConfigureNotify after XCreateWindow\n");
break;
+ } else if(fds_ready == -1 || !(poll_fd.revents & POLLIN)) {
+ continue;
+ }
+
+ XNextEvent(display, &xev);
+ if(xev.type == MapNotify && xev.xmap.window == window) {
+ int x = 0;
+ int y = 0;
+ Window w = None;
+ XTranslateCoordinates(display, window, DefaultRootWindow(display), 0, 0, &x, &y, &w);
+
+ got_data = x > 0 && y > 0;
+ position.x = x + size / 2;
+ position.y = y + size / 2;
+ if(got_data)
+ break;
+ } else if(xev.type == ConfigureNotify && xev.xconfigure.window == window) {
+ got_data = xev.xconfigure.x > 0 && xev.xconfigure.y > 0;
+ position.x = xev.xconfigure.x + xev.xconfigure.width / 2;
+ position.y = xev.xconfigure.y + xev.xconfigure.height / 2;
+ if(got_data)
+ break;
}
}
XDestroyWindow(display, window);
XFlush(display);
- return window_pos;
+ return got_data;
+}
+
+static mgl::vec2i create_window_get_center_position(Display *display) {
+ mgl::vec2i pos;
+ if(!create_window_get_center_position_kde(display, pos)) {
+ pos.x = 0;
+ pos.y = 0;
+ create_window_get_center_position_gnome(display, pos);
+ }
+ return pos;
}
int main(int argc, char **argv) {
@@ -330,7 +467,9 @@ int main(int argc, char **argv) {
}
// The cursor position is wrong on wayland if an x11 window is not focused. On wayland we instead create a window and get the position where the wayland compositor puts it
- const mgl::vec2i monitor_position_query_value = wayland ? create_window_get_center_position(display) : mgl::vec2i(win->cursor_position.x, win->cursor_position.y);
+ Window x11_cursor_window = None;
+ const mgl::vec2i cursor_position = get_cursor_position(display, &x11_cursor_window);
+ const mgl::vec2i monitor_position_query_value = (x11_cursor_window || !wayland) ? cursor_position : create_window_get_center_position(display);
const mgl_monitor *focused_monitor = find_monitor_at_position(window, monitor_position_query_value);
const std::string noto_sans_bold_filepath = resources_path + "fonts/NotoSans-Bold.ttf";