diff options
-rw-r--r-- | meson.build | 4 | ||||
-rw-r--r-- | project.conf | 2 | ||||
-rw-r--r-- | src/main.cpp | 161 |
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"; |