#include #include #include #include #include #include #include #include #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 clients; int currClientID = 0; map frames; int currFrameID = 0; map 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(c.ID, c)); //Make frame int pID = (frameIDS.count(focusedWindow)>0)? frames.find(frameIDS.find(focusedWindow)->second)->second.pID : 0; vector v; Frame f = {currFrameID, pID, true, c.ID, noDir, v}; currFrameID++; //Add ID to frameIDS map frameIDS.insert(pair(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& 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 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(pF.ID, pF)); } //Add to frames map frames.insert(pair(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& 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& 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& 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 v; Frame rootFrame = {0, noID, false, noID, horizontal, v}; currFrameID++; frames.insert(pair(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); }