2020-10-31 20:14:15 +02:00
|
|
|
// Taken from https://github.com/mackstann/tinywm
|
|
|
|
|
|
|
|
#include <X11/Xlib.h>
|
2020-11-01 01:42:15 +02:00
|
|
|
#include <X11/keysym.h>
|
2020-11-02 02:02:09 +02:00
|
|
|
#include <X11/XKBlib.h>
|
2020-10-31 20:14:15 +02:00
|
|
|
|
|
|
|
#define MODMASK Mod1Mask
|
|
|
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
|
|
|
|
2020-11-02 02:20:04 +02:00
|
|
|
static Window root;
|
|
|
|
|
2020-11-02 02:02:09 +02:00
|
|
|
static Display* dpy;
|
|
|
|
static XWindowAttributes attr;
|
|
|
|
static XButtonEvent start;
|
2020-10-31 20:14:15 +02:00
|
|
|
|
2020-11-02 02:20:04 +02:00
|
|
|
void grab_input(Window* root) {
|
|
|
|
XGrabKey(dpy, XKeysymToKeycode(dpy, XStringToKeysym("1")), MODMASK, *root, True, GrabModeAsync, GrabModeAsync);
|
|
|
|
XGrabKey(dpy, XKeysymToKeycode(dpy, XStringToKeysym("Q")), MODMASK, *root, True, GrabModeAsync, GrabModeAsync);
|
|
|
|
XGrabButton(dpy, 1, MODMASK, *root, True, ButtonPressMask|ButtonReleaseMask|PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None);
|
|
|
|
XGrabButton(dpy, 3, MODMASK, *root, True, ButtonPressMask|ButtonReleaseMask|PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None);
|
|
|
|
}
|
|
|
|
|
2020-11-02 02:02:09 +02:00
|
|
|
void handle_event_keypress(XEvent *e) {
|
|
|
|
if (e->xkey.subwindow != None) {
|
|
|
|
KeySym keysym = XkbKeycodeToKeysym(dpy, e->xkey.keycode, 0, 0);
|
|
|
|
if (keysym == XK_q) {
|
|
|
|
XKillClient(dpy, e->xkey.subwindow);
|
|
|
|
} else if (keysym == XK_1) {
|
|
|
|
XRaiseWindow(dpy, e->xkey.subwindow);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-10-31 20:14:15 +02:00
|
|
|
|
2020-11-02 02:02:09 +02:00
|
|
|
void handle_event_buttonpress(XEvent *e) {
|
|
|
|
if (e->xkey.subwindow != None) {
|
|
|
|
XGetWindowAttributes(dpy, e->xbutton.subwindow, &attr);
|
|
|
|
start = e->xbutton;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void handle_event_motionnotify(XEvent *e) {
|
|
|
|
if (start.subwindow != None) {
|
|
|
|
int xdiff = e->xbutton.x_root - start.x_root;
|
|
|
|
int ydiff = e->xbutton.y_root - start.y_root;
|
|
|
|
XMoveResizeWindow(dpy, start.subwindow,
|
|
|
|
attr.x + (start.button==1 ? xdiff : 0),
|
|
|
|
attr.y + (start.button==1 ? ydiff : 0),
|
|
|
|
MAX(1, attr.width + (start.button==3 ? xdiff : 0)),
|
|
|
|
MAX(1, attr.height + (start.button==3 ? ydiff : 0)));
|
|
|
|
}
|
|
|
|
}
|
2020-10-31 20:14:15 +02:00
|
|
|
|
2020-11-02 02:02:09 +02:00
|
|
|
void handle_event_buttonrelease(XEvent *e) {
|
|
|
|
start.subwindow = None;
|
|
|
|
}
|
|
|
|
|
2020-11-02 02:20:04 +02:00
|
|
|
void handle_event_mappingnotify(XEvent *e) {
|
|
|
|
XMappingEvent *ev = &e->xmapping;
|
|
|
|
|
|
|
|
if (ev->request == MappingKeyboard || ev->request == MappingModifier) {
|
|
|
|
XRefreshKeyboardMapping(ev);
|
|
|
|
grab_input(&root);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-02 02:02:09 +02:00
|
|
|
static void (*event_handlers[LASTEvent])(XEvent *e) = {
|
|
|
|
[KeyPress] = handle_event_keypress,
|
|
|
|
[ButtonPress] = handle_event_buttonpress,
|
|
|
|
[ButtonRelease] = handle_event_buttonrelease,
|
2020-11-02 02:20:04 +02:00
|
|
|
[MotionNotify] = handle_event_motionnotify,
|
|
|
|
|
|
|
|
// Below are events that are not 100% needed but without them some programs may break!
|
|
|
|
// TODO: MapRequest, ConfigureRequest
|
|
|
|
[MappingNotify] = handle_event_mappingnotify
|
2020-11-02 02:02:09 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
int main() {
|
2020-10-31 20:14:15 +02:00
|
|
|
if(!(dpy = XOpenDisplay(0x0))) return 1;
|
|
|
|
|
2020-11-02 02:02:09 +02:00
|
|
|
XEvent ev;
|
2020-11-02 02:20:04 +02:00
|
|
|
root = DefaultRootWindow(dpy);
|
|
|
|
grab_input(&root);
|
2020-10-31 20:14:15 +02:00
|
|
|
start.subwindow = None;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
XNextEvent(dpy, &ev);
|
2020-11-02 02:02:09 +02:00
|
|
|
if (event_handlers[ev.type]) event_handlers[ev.type](&ev);
|
2020-10-31 20:14:15 +02:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|