summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBossCode45 <human.cyborg42@gmail.com>2022-08-22 20:17:41 +1200
committerBossCode45 <human.cyborg42@gmail.com>2022-08-22 20:17:41 +1200
commit3cb6b1583417c47c72e542604a8636d3410067fe (patch)
tree841c3682d8b372e471f4f6e5a41add2d949b375c
parentce211d76831a178b7197998764d2983140d204bb (diff)
downloadYATwm-3cb6b1583417c47c72e542604a8636d3410067fe.tar.gz
YATwm-3cb6b1583417c47c72e542604a8636d3410067fe.zip
Better keybind support - and credits in readme
-rw-r--r--\325
-rw-r--r--config.h32
-rw-r--r--main.cpp73
-rw-r--r--readme.org15
4 files changed, 423 insertions, 22 deletions
diff --git a/\ b/\
new file mode 100644
index 0000000..1a8944a
--- /dev/null
+++ b/\
@@ -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);
+}
diff --git a/config.h b/config.h
index 18d0a93..4fa6ee3 100644
--- a/config.h
+++ b/config.h
@@ -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}}
};
-
diff --git a/main.cpp b/main.cpp
index b5fa9fa..d81924e 100644
--- a/main.cpp
+++ b/main.cpp
@@ -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";
diff --git a/readme.org b/readme.org
index 1b47c4c..14383b5 100644
--- a/readme.org
+++ b/readme.org
@@ -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)