aboutsummaryrefslogtreecommitdiff
path: root/src/WindowUtils.cpp
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2025-03-15 00:39:37 +0100
committerdec05eba <dec05eba@protonmail.com>2025-03-15 00:56:38 +0100
commit63b2b6cbc34b9e34208f3bff96686b9bd3f54521 (patch)
treeb20334166fd064c6b35d29daea7350841a219897 /src/WindowUtils.cpp
parent6c7158c06d41fd7c77a8a8b9d186440904950f8c (diff)
Add region capture option
Diffstat (limited to 'src/WindowUtils.cpp')
-rw-r--r--src/WindowUtils.cpp211
1 files changed, 188 insertions, 23 deletions
diff --git a/src/WindowUtils.cpp b/src/WindowUtils.cpp
index d588374..49fd65b 100644
--- a/src/WindowUtils.cpp
+++ b/src/WindowUtils.cpp
@@ -1,8 +1,10 @@
#include "../include/WindowUtils.hpp"
-#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
+#include <X11/extensions/XInput2.h>
+#include <X11/extensions/Xfixes.h>
+#include <X11/extensions/shapeconst.h>
#include <mglpp/system/Utf8.hpp>
@@ -301,6 +303,21 @@ namespace gsr {
return get_window_name_at_position(dpy, cursor_position, ignore_window);
}
+ void set_window_size_not_resizable(Display *dpy, Window window, int width, int height) {
+ XSizeHints *size_hints = XAllocSizeHints();
+ if(size_hints) {
+ size_hints->width = width;
+ size_hints->height = height;
+ size_hints->min_width = width;
+ size_hints->min_height = height;
+ size_hints->max_width = width;
+ size_hints->max_height = height;
+ size_hints->flags = PSize | PMinSize | PMaxSize;
+ XSetWMNormalHints(dpy, window, size_hints);
+ XFree(size_hints);
+ }
+ }
+
typedef struct {
unsigned long flags;
unsigned long functions;
@@ -348,17 +365,7 @@ namespace gsr {
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);
+ set_window_size_not_resizable(display, window, size, size);
XMapWindow(display, window);
XFlush(display);
@@ -412,17 +419,7 @@ namespace gsr {
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);
+ set_window_size_not_resizable(display, window, size, size);
XMapWindow(display, window);
XFlush(display);
@@ -531,4 +528,172 @@ namespace gsr {
mgl_for_each_active_monitor_output(dpy, get_monitors_callback, &monitors);
return monitors;
}
+
+ static bool device_is_mouse(const XIDeviceInfo *dev) {
+ for(int i = 0; i < dev->num_classes; ++i) {
+ if(dev->classes[i]->type == XIMasterPointer || dev->classes[i]->type == XISlavePointer)
+ return true;
+ }
+ return false;
+ }
+
+ static void xi_grab_all_mouse_devices(Display *dpy, bool grab) {
+ if(!dpy)
+ return;
+
+ int num_devices = 0;
+ XIDeviceInfo *info = XIQueryDevice(dpy, XIAllDevices, &num_devices);
+ if(!info)
+ return;
+
+ unsigned char mask[XIMaskLen(XI_LASTEVENT)];
+ memset(mask, 0, sizeof(mask));
+ XISetMask(mask, XI_Motion);
+ //XISetMask(mask, XI_RawMotion);
+ XISetMask(mask, XI_ButtonPress);
+ XISetMask(mask, XI_ButtonRelease);
+ XISetMask(mask, XI_KeyPress);
+ XISetMask(mask, XI_KeyRelease);
+
+ for (int i = 0; i < num_devices; ++i) {
+ const XIDeviceInfo *dev = &info[i];
+ if(!device_is_mouse(dev))
+ continue;
+
+ XIEventMask xi_masks;
+ xi_masks.deviceid = dev->deviceid;
+ xi_masks.mask_len = sizeof(mask);
+ xi_masks.mask = mask;
+ if(grab)
+ XIGrabDevice(dpy, dev->deviceid, DefaultRootWindow(dpy), CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, XIOwnerEvents, &xi_masks);
+ else
+ XIUngrabDevice(dpy, dev->deviceid, CurrentTime);
+ }
+
+ XFlush(dpy);
+ XIFreeDeviceInfo(info);
+ }
+
+ void xi_grab_all_mouse_devices(Display *dpy) {
+ xi_grab_all_mouse_devices(dpy, true);
+ }
+
+ void xi_ungrab_all_mouse_devices(Display *dpy) {
+ xi_grab_all_mouse_devices(dpy, false);
+ }
+
+ void xi_warp_all_mouse_devices(Display *dpy, mgl::vec2i position) {
+ if(!dpy)
+ return;
+
+ int num_devices = 0;
+ XIDeviceInfo *info = XIQueryDevice(dpy, XIAllDevices, &num_devices);
+ if(!info)
+ return;
+
+ for (int i = 0; i < num_devices; ++i) {
+ const XIDeviceInfo *dev = &info[i];
+ if(!device_is_mouse(dev))
+ continue;
+
+ XIWarpPointer(dpy, dev->deviceid, DefaultRootWindow(dpy), DefaultRootWindow(dpy), 0, 0, 0, 0, position.x, position.y);
+ }
+
+ XFlush(dpy);
+ XIFreeDeviceInfo(info);
+ }
+
+ void window_set_fullscreen(Display *dpy, Window window, bool fullscreen) {
+ const Atom net_wm_state_atom = XInternAtom(dpy, "_NET_WM_STATE", False);
+ const Atom net_wm_state_fullscreen_atom = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
+
+ XEvent xev;
+ xev.type = ClientMessage;
+ xev.xclient.window = window;
+ xev.xclient.message_type = net_wm_state_atom;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = fullscreen ? 1 : 0;
+ xev.xclient.data.l[1] = net_wm_state_fullscreen_atom;
+ xev.xclient.data.l[2] = 0;
+ xev.xclient.data.l[3] = 1;
+ xev.xclient.data.l[4] = 0;
+
+ if(!XSendEvent(dpy, DefaultRootWindow(dpy), 0, SubstructureRedirectMask | SubstructureNotifyMask, &xev)) {
+ fprintf(stderr, "mgl warning: failed to change window fullscreen state\n");
+ return;
+ }
+
+ XFlush(dpy);
+ }
+
+ bool window_is_fullscreen(Display *display, Window window) {
+ const Atom wm_state_atom = XInternAtom(display, "_NET_WM_STATE", False);
+ const Atom wm_state_fullscreen_atom = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", False);
+
+ Atom type = None;
+ int format = 0;
+ unsigned long num_items = 0;
+ unsigned long bytes_after = 0;
+ unsigned char *properties = nullptr;
+ if(XGetWindowProperty(display, window, wm_state_atom, 0, 1024, False, XA_ATOM, &type, &format, &num_items, &bytes_after, &properties) < Success) {
+ fprintf(stderr, "Failed to get window wm state property\n");
+ return false;
+ }
+
+ if(!properties)
+ return false;
+
+ bool is_fullscreen = false;
+ Atom *atoms = (Atom*)properties;
+ for(unsigned long i = 0; i < num_items; ++i) {
+ if(atoms[i] == wm_state_fullscreen_atom) {
+ is_fullscreen = true;
+ break;
+ }
+ }
+
+ XFree(properties);
+ return is_fullscreen;
+ }
+
+ #define _NET_WM_STATE_REMOVE 0
+ #define _NET_WM_STATE_ADD 1
+ #define _NET_WM_STATE_TOGGLE 2
+
+ bool set_window_wm_state(Display *dpy, Window window, Atom atom) {
+ const Atom net_wm_state_atom = XInternAtom(dpy, "_NET_WM_STATE", False);
+
+ XClientMessageEvent xclient;
+ memset(&xclient, 0, sizeof(xclient));
+
+ xclient.type = ClientMessage;
+ xclient.window = window;
+ xclient.message_type = net_wm_state_atom;
+ xclient.format = 32;
+ xclient.data.l[0] = _NET_WM_STATE_ADD;
+ xclient.data.l[1] = atom;
+ xclient.data.l[2] = 0;
+ xclient.data.l[3] = 0;
+ xclient.data.l[4] = 0;
+
+ XSendEvent(dpy, DefaultRootWindow(dpy), False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xclient);
+ XFlush(dpy);
+ return true;
+ }
+
+ void make_window_click_through(Display *display, Window window) {
+ XRectangle rect;
+ memset(&rect, 0, sizeof(rect));
+ XserverRegion region = XFixesCreateRegion(display, &rect, 1);
+ XFixesSetWindowShapeRegion(display, window, ShapeInput, 0, 0, region);
+ XFixesDestroyRegion(display, region);
+ }
+
+ bool make_window_sticky(Display *dpy, Window window) {
+ return set_window_wm_state(dpy, window, XInternAtom(dpy, "_NET_WM_STATE_STICKY", False));
+ }
+
+ bool hide_window_from_taskbar(Display *dpy, Window window) {
+ return set_window_wm_state(dpy, window, XInternAtom(dpy, "_NET_WM_STATE_SKIP_TASKBAR", False));
+ }
} \ No newline at end of file