diff options
| author | BossCode45 <human.cyborg42@gmail.com> | 2022-08-22 20:17:41 +1200 |
|---|---|---|
| committer | BossCode45 <human.cyborg42@gmail.com> | 2022-08-22 20:17:41 +1200 |
| commit | 3cb6b1583417c47c72e542604a8636d3410067fe (patch) | |
| tree | 841c3682d8b372e471f4f6e5a41add2d949b375c | |
| parent | ce211d76831a178b7197998764d2983140d204bb (diff) | |
| download | YATwm-3cb6b1583417c47c72e542604a8636d3410067fe.tar.gz YATwm-3cb6b1583417c47c72e542604a8636d3410067fe.zip | |
Better keybind support - and credits in readme
| -rw-r--r-- | \ | 325 | ||||
| -rw-r--r-- | config.h | 32 | ||||
| -rw-r--r-- | main.cpp | 73 | ||||
| -rw-r--r-- | readme.org | 15 |
4 files changed, 423 insertions, 22 deletions
@@ -0,0 +1,325 @@ +#include <X11/Xlib.h> + +#include <cstdlib> +#include <iostream> +#include <map> +#include <vector> +#include <unistd.h> +#include <cstring> +#include <algorithm> + +#include "structs.h" +#include "config.h" + +using std::cout; +using std::map; +using std::pair; +using std::vector; + +Display* dpy; +Window root; +int sW, sH; +TileDir nextDir = horizontal; + + +bool keepGoing = true; + +map<int, Client> clients; +int currClientID = 0; +map<int, Frame> frames; +int currFrameID = 0; +map<Window, int> frameIDS; + +void keyPress(XKeyEvent e); +void configureRequest(XConfigureRequestEvent e); +void mapRequest(XMapRequestEvent e); +void destroyNotify(XDestroyWindowEvent e); + +static int OnXError(Display* display, XErrorEvent* e); + +void tile(int frameID, int x, int y, int w, int h); + +//Keybind commands +void exit(const KeyArg arg) +{ + keepGoing = false; +} +void spawn(const KeyArg arg) +{ + if(fork() == 0) + { + execvp((char*)arg.str[0], (char**)arg.str); + exit(0); + } +} +void toggle(const KeyArg arg) +{ + nextDir = nextDir = (nextDir==horizontal)? vertical : horizontal; +} +void kill(const KeyArg arg) +{ + Window w; + int revertToReturn; + XGetInputFocus(dpy, &w, &revertToReturn); + Atom* supported_protocols; + int num_supported_protocols; + if (XGetWMProtocols(dpy, + w, + &supported_protocols, + &num_supported_protocols) && + (std::find(supported_protocols, + supported_protocols + num_supported_protocols, + XInternAtom(dpy, "WM_DELETE_WINDOW", false)) != + supported_protocols + num_supported_protocols)) { + // 1. Construct message. + XEvent msg; + memset(&msg, 0, sizeof(msg)); + msg.xclient.type = ClientMessage; + msg.xclient.message_type = XInternAtom(dpy, "WM_PROTOCOLS", false); + msg.xclient.window = w; + msg.xclient.format = 32; + msg.xclient.data.l[0] = XInternAtom(dpy, "WM_DELETE_WINDOW", false); + // 2. Send message to window to be closed. + cout << "Nice kill\n"; + XSendEvent(dpy, w, false, 0, &msg); + } else { + cout << "Mean kill\n"; + XKillClient(dpy, w); + } +} + +void keyPress(XKeyEvent e) +{ + if(e.same_screen!=1) return; + //TODO: Make this into a for loop + KeySym keysym = XLookupKeysym(&e, 1); + for(int i = 0; i < sizeof(keyBinds)/sizeof(keyBinds[0]); i++) + { + if(keyBinds[i].keysym == keysym && keyBinds[i].modifiers == e.state) + { + keyBinds[i].function(keyBinds[i].arg); + } + } +} + +void configureRequest(XConfigureRequestEvent e) +{ + XWindowChanges changes; + changes.x = e.x; + changes.y = e.y; + changes.width = e.width; + changes.height = e.height; + changes.border_width = e.border_width; + changes.sibling = e.above; + changes.stack_mode = e.detail; + XConfigureWindow(dpy, e.window, e.value_mask, &changes); +} + +void mapRequest(XMapRequestEvent e) +{ + XMapWindow(dpy, e.window); + Window focusedWindow; + int revertToReturn; + XGetInputFocus(dpy, &focusedWindow, &revertToReturn); + XSetInputFocus(dpy, e.window, RevertToNone, CurrentTime); + XSelectInput(dpy, e.window, EnterWindowMask); + + //Make client + Client c = {currClientID, e.window}; + currClientID++; + + //Add to clients map + clients.insert(pair<int, Client>(c.ID, c)); + + //Make frame + int pID = (frameIDS.count(focusedWindow)>0)? frames.find(frameIDS.find(focusedWindow)->second)->second.pID : 0; + vector<int> v; + Frame f = {currFrameID, pID, true, c.ID, noDir, v}; + currFrameID++; + + + //Add ID to frameIDS map + frameIDS.insert(pair<Window, int>(e.window, f.ID)); + + //Check how to add + if(nextDir == frames.find(pID)->second.dir) + { + //Add to focused parent + frames.find(pID)->second.subFrameIDs.push_back(f.ID); + } + else + { + //Get parent sub frames for later use + vector<int>& pS = frames.find(pID)->second.subFrameIDs; + + //Get index of focused frame in parent sub frames + int index; + for(index = 0; index < pS.size(); index++) + { + if(pS[index] == frames.find(frameIDS.find(focusedWindow)->second)->second.ID) + break; + } + + //Make new frame + vector<int> v; + v.push_back(frames.find(frameIDS.find(focusedWindow)->second)->second.ID); + v.push_back(f.ID); + Frame pF = {currFrameID, pID, false, noID, nextDir, v}; + + //Update the IDS + f.pID = currFrameID; + frames.find(frames.find(frameIDS.find(focusedWindow)->second)->second.ID)->second.pID = currFrameID; + pS[index] = currFrameID; + + currFrameID++; + + //Insert the new frame into the frames map + frames.insert(pair<int, Frame>(pF.ID, pF)); + } + + //Add to frames map + frames.insert(pair<int, Frame>(f.ID, f)); + + tile(0, 0, 0, sW, sH); +} + +void destroyNotify(XDestroyWindowEvent e) +{ + if(frameIDS.count(e.window)<1) + return; + cout << "Destroy notif\n"; + int fID = frameIDS.find(e.window)->second; + int pID = frames.find(fID)->second.pID; + vector<int>& pS = frames.find(pID)->second.subFrameIDs; + for(int i = 0; i < pS.size(); i++) + { + if(frames.find(pS[i])->second.ID == fID) + { + pS.erase(pS.begin() + i); + clients.erase(frames.find(fID)->second.cID); + frames.erase(fID); + frameIDS.erase(e.window); + + if(pS.size() < 2 && pID != 0) + { + //Erase parent frame + int lastChildID = frames.find(frames.find(pID)->second.subFrameIDs[0])->second.ID; + int parentParentID = frames.find(pID)->second.pID; + vector<int>& parentParentSubFrameIDs = frames.find(parentParentID)->second.subFrameIDs; + for(int j = 0; j < parentParentSubFrameIDs.size(); j++) + { + if(parentParentSubFrameIDs[j] == pID) + { + parentParentSubFrameIDs[j] = lastChildID; + frames.find(lastChildID)->second.pID = parentParentID; + frames.erase(pID); + break; + } + } + } + break; + } + } + tile(0, 0, 0, sW, sH); +} + +static int OnXError(Display* display, XErrorEvent* e) +{ + cout << "XError\n"; + return 0; +} + +void tile(int frameID, int x, int y, int w, int h) +{ + if(frameID == 0) + { + printf("\nTILING ROOT:\n"); + } + printf("Tiling frame - ID: %i\n\tx: %i, y: %i, w: %i, h: %i\n", frameID, x, y, w, h); + int i = 0; + vector<int>& subFrameIDs = frames.find(frameID)->second.subFrameIDs; + TileDir dir = frames.find(frameID)->second.dir; + for(int fID : subFrameIDs) + { + Frame f = frames.find(fID)->second; + int wX = (dir==horizontal) ? x + i * (w/subFrameIDs.size()) : x; + int wY = (dir==vertical) ? y + i * (h/subFrameIDs.size()) : y; + int wW = (dir==horizontal) ? w/subFrameIDs.size() : w; + int wH = (dir==vertical) ? h/subFrameIDs.size() : h; + i++; + if(!f.isClient) + { + tile(fID, wX, wY, wW, wH); + continue; + } + Client c = clients.find(f.cID)->second; + printf("Arranging client with frame ID %i, client ID %i:\n\tx: %i, y: %i, w: %i, h: %i\n", fID, c.ID, wX, wY, wW, wH); + XMoveWindow(dpy, c.w, + wX, wY); + XResizeWindow(dpy, c.w, + wW, wH); + } + if(frameID == 0) + { + printf("DONE TILING ROOT\n\n"); + } +} + +int main(int argc, char** argv) +{ + dpy = XOpenDisplay(nullptr); + root = Window(DefaultRootWindow(dpy)); + + int screenNum = DefaultScreen(dpy); + sW = DisplayWidth(dpy, screenNum); + sH = DisplayHeight(dpy, screenNum); + + XSetErrorHandler(OnXError); + XSelectInput(dpy, root, SubstructureRedirectMask | SubstructureNotifyMask); + + for(int i = 0; i < sizeof(keyBinds)/sizeof(keyBinds[0]); i++) + { + XGrabKey(dpy, XKeysymToKeycode(dpy, keyBinds[i].keysym), keyBinds[i].modifiers, root, false, GrabModeAsync, GrabModeAsync); + } + + + vector<int> v; + Frame rootFrame = {0, noID, false, noID, horizontal, v}; + currFrameID++; + frames.insert(pair<int, Frame>(0, rootFrame)); + + cout << "Begin mainloop\n"; + + while(keepGoing) + { + XEvent e; + XNextEvent(dpy, &e); + + switch(e.type) + { + case KeyPress: + cout << "Keypress\n"; + keyPress(e.xkey); + break; + case ConfigureRequest: + configureRequest(e.xconfigurerequest); + break; + case MapRequest: + mapRequest(e.xmaprequest); + break; + case DestroyNotify: + destroyNotify(e.xdestroywindow); + case EnterNotify: + //cout << e.xcrossing.window << "\n"; + if(e.xcrossing.window == root) + break; + XSetInputFocus(dpy, e.xcrossing.window, RevertToNone, CurrentTime); + break; + default: + //cout << "Unhandled event, code: " << e.type << "!\n"; + break; + } + } + + XCloseDisplay(dpy); +} @@ -1,15 +1,35 @@ #include <X11/keysym.h> +typedef union +{ + const char** str; + const int* num; +} KeyArg; + struct Key { KeySym keysym; unsigned int modifiers; + void (*function)(const KeyArg arg); + const KeyArg arg; }; -Key keyBinds[] = { - {XK_E, Mod1Mask}, - {XK_Return, Mod1Mask}, - {XK_D, Mod1Mask}, - {XK_T, Mod1Mask} +//Keybind commands +void exit(const KeyArg arg); +void spawn(const KeyArg arg); +void toggle(const KeyArg arg); +void kill(const KeyArg arg); + +const char* alacritty[] = {"alacritty", NULL}; +const char* rofi[] = {"rofi", "-i", "-show" "drun", NULL}; + +unsigned int mod = Mod1Mask; + +static struct Key keyBinds[] = { + //Key //Modifiers //Func //Args + {XK_E, mod, exit, {NULL}}, + {XK_Return, mod, spawn, {alacritty}}, + {XK_D, mod, spawn, {rofi}}, + {XK_T, mod, toggle, {NULL}}, + {XK_Q, mod, kill, {NULL}} }; - @@ -4,6 +4,9 @@ #include <iostream> #include <map> #include <vector> +#include <unistd.h> +#include <cstring> +#include <algorithm> #include "structs.h" #include "config.h" @@ -36,16 +39,66 @@ static int OnXError(Display* display, XErrorEvent* e); void tile(int frameID, int x, int y, int w, int h); +//Keybind commands +void exit(const KeyArg arg) +{ + keepGoing = false; +} +void spawn(const KeyArg arg) +{ + if(fork() == 0) + { + execvp((char*)arg.str[0], (char**)arg.str); + exit(0); + } +} +void toggle(const KeyArg arg) +{ + nextDir = nextDir = (nextDir==horizontal)? vertical : horizontal; +} +void kill(const KeyArg arg) +{ + Window w; + int revertToReturn; + XGetInputFocus(dpy, &w, &revertToReturn); + Atom* supported_protocols; + int num_supported_protocols; + if (XGetWMProtocols(dpy, + w, + &supported_protocols, + &num_supported_protocols) && + (std::find(supported_protocols, + supported_protocols + num_supported_protocols, + XInternAtom(dpy, "WM_DELETE_WINDOW", false)) != + supported_protocols + num_supported_protocols)) { + // 1. Construct message. + XEvent msg; + memset(&msg, 0, sizeof(msg)); + msg.xclient.type = ClientMessage; + msg.xclient.message_type = XInternAtom(dpy, "WM_PROTOCOLS", false); + msg.xclient.window = w; + msg.xclient.format = 32; + msg.xclient.data.l[0] = XInternAtom(dpy, "WM_DELETE_WINDOW", false); + // 2. Send message to window to be closed. + cout << "Nice kill\n"; + XSendEvent(dpy, w, false, 0, &msg); + } else { + cout << "Mean kill\n"; + XKillClient(dpy, w); + } +} + void keyPress(XKeyEvent e) { if(e.same_screen!=1) return; //TODO: Make this into a for loop - switch(XLookupKeysym(&e, 1)) + KeySym keysym = XLookupKeysym(&e, 1); + for(int i = 0; i < sizeof(keyBinds)/sizeof(keyBinds[0]); i++) { - case XK_E: keepGoing = false; break; - case XK_Return: std::system("alacritty &"); break; - case XK_D: std::system("rofi -i -show drun &"); break; - case XK_T: nextDir = (nextDir==horizontal)? vertical : horizontal; break; + if(keyBinds[i].keysym == keysym && keyBinds[i].modifiers == e.state) + { + keyBinds[i].function(keyBinds[i].arg); + } } } @@ -180,9 +233,9 @@ void tile(int frameID, int x, int y, int w, int h) { if(frameID == 0) { - printf("\nTILING ROOT:\n"); + //printf("\nTILING ROOT:\n"); } - printf("Tiling frame - ID: %i\n\tx: %i, y: %i, w: %i, h: %i\n", frameID, x, y, w, h); + //printf("Tiling frame - ID: %i\n\tx: %i, y: %i, w: %i, h: %i\n", frameID, x, y, w, h); int i = 0; vector<int>& subFrameIDs = frames.find(frameID)->second.subFrameIDs; TileDir dir = frames.find(frameID)->second.dir; @@ -200,7 +253,7 @@ void tile(int frameID, int x, int y, int w, int h) continue; } Client c = clients.find(f.cID)->second; - printf("Arranging client with frame ID %i, client ID %i:\n\tx: %i, y: %i, w: %i, h: %i\n", fID, c.ID, wX, wY, wW, wH); + //printf("Arranging client with frame ID %i, client ID %i:\n\tx: %i, y: %i, w: %i, h: %i\n", fID, c.ID, wX, wY, wW, wH); XMoveWindow(dpy, c.w, wX, wY); XResizeWindow(dpy, c.w, @@ -208,7 +261,7 @@ void tile(int frameID, int x, int y, int w, int h) } if(frameID == 0) { - printf("DONE TILING ROOT\n\n"); + //printf("DONE TILING ROOT\n\n"); } } @@ -229,7 +282,6 @@ int main(int argc, char** argv) XGrabKey(dpy, XKeysymToKeycode(dpy, keyBinds[i].keysym), keyBinds[i].modifiers, root, false, GrabModeAsync, GrabModeAsync); } - vector<int> v; Frame rootFrame = {0, noID, false, noID, horizontal, v}; currFrameID++; @@ -260,7 +312,6 @@ int main(int argc, char** argv) if(e.xcrossing.window == root) break; XSetInputFocus(dpy, e.xcrossing.window, RevertToNone, CurrentTime); - break; default: //cout << "Unhandled event, code: " << e.type << "!\n"; @@ -10,8 +10,13 @@ I wouldn't suggest using this at all and it may undergo heavy changes as the cod * For people that have brain damage (anyone who wants to use it) ** Keybinds mod1 is alt -- mod1 + enter : alacritty -- mod1 + d : rofi -- mod1 + t : change next tile direction -- mod1 + e : exit -There is currently no good system for keybinds, but it is coming later. +- mod1 + enter : alacritty +- mod1 + d : rofi +- mod1 + t : change next tile direction +- mod1 + e : exit +- mod1 + q : quit focused window +Add new keybinds reffering to the pre existing ones - docs coming later + +* Credits +Catwm (https://github.com/pyknite/catwm) +basic_wm (https://github.com/jichu4n/basic_wm) |
