From a34c161a6643f184348f42235bcda46352b68da0 Mon Sep 17 00:00:00 2001 From: BossCode45 Date: Sun, 18 Sep 2022 14:38:41 +1200 Subject: Starting work on multiple monitors --- config.h | 36 ++++++++++------- ewmh.cpp | 2 +- ewmh.h | 2 +- logs.txt | 19 --------- main.cpp | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- makefile | 2 +- notes.org | 24 ++++++++++++ structs.h | 8 ++++ test | 2 +- 9 files changed, 174 insertions(+), 54 deletions(-) delete mode 100644 logs.txt create mode 100644 notes.org diff --git a/config.h b/config.h index 72be653..d5d7ba5 100644 --- a/config.h +++ b/config.h @@ -5,16 +5,19 @@ #include //Startup -std::string startup[] = {"picom -fD 3", "feh --bg-scale /usr/share/backgrounds/vapor_trails_blue.png", "~/.config/polybar/launch.sh", "emacs --daemon"}; +const std::string startup[] = {"picom -fD 3", "feh --bg-scale /usr/share/backgrounds/vapor_trails_blue.png", "~/.config/polybar/launch.sh", "emacs --daemon"}; //Main config -int gaps = 3; -int outerGaps = 3; -std::string logFile = "/tmp/yatlog"; +const int gaps = 3; +const int outerGaps = 3; +const std::string logFile = "/tmp/yatlog.txt"; //WS config const int numWS = 10; -std::string workspaceNames[] = {"1: ", "2: 拾", "3: ", "4: ", "5: ", "6: ", "7: 拾", "8: ", "9: ", "10: "}; +const std::string workspaceNames[] = {"1: ", "2: 拾", "3: ", "4: ", "5: ", "6: ", "7: 拾", "8: ", "9: ", "10: "}; +//If you have more then 2 monitors change the number below +const int maxMonitors = 2; +const int screenPreferences[][maxMonitors] = {{0}, {0}, {0}, {0}, {0}, {1, 0}, {1, 0}, {1, 0}, {1, 0}, {1, 0}}; //Keys //The types and perhaps functions likely to be moved to seperate header file later @@ -35,8 +38,8 @@ typedef union struct Key { - unsigned int modifiers; - KeySym keysym; + const unsigned int modifiers; + const KeySym keysym; void (*function)(const KeyArg arg); const KeyArg arg; }; @@ -52,25 +55,28 @@ KEYCOM(changeWS); KEYCOM(wToWS); KEYCOM(focChange); KEYCOM(wMove); +KEYCOM(bashSpawn); +KEYCOM(screenTest); +//Super key mod +#define MOD Mod4Mask +//Alt key mod +//#define MOD Mod1Mask +#define SHIFT ShiftMask const char* alacritty[] = {"alacritty", NULL}; const char* rofi[] = {"rofi", "-i", "-show", "drun", NULL}; const char* qutebrowser[] = {"qutebrowser", NULL}; - const char* i3lock[] = {"i3lock", "-eti", "/usr/share/backgrounds/lockscreen.png", NULL}; const char* suspend[] = {"systemctl", "suspend", NULL}; -//Super key mod -//#define MOD Mod4Mask -//Alt key mod -#define MOD Mod1Mask -#define SHIFT ShiftMask +const char* monConfig[] = {"~/.i3_commands/monitor-config.sh"}; + #define WSKEY(K, X) \ {MOD, K, changeWS, {.num = X}}, \ {MOD|SHIFT, K, wToWS, {.num = X}} -static Key keyBinds[] = { +const Key keyBinds[] = { //Modifiers //Key //Func //Args //General {MOD, XK_e, exit, {NULL}}, @@ -82,6 +88,8 @@ static Key keyBinds[] = { {MOD, XK_x, spawn, {.str = i3lock}}, {MOD|SHIFT, XK_x, spawn, {.str = i3lock}}, {MOD|SHIFT, XK_x, spawn, {.str = suspend}}, + {MOD, XK_m, bashSpawn, {.str = monConfig}}, + {MOD|SHIFT, XK_t, screenTest, {NULL}}, //Focus {MOD, XK_h, focChange, {.dir = Left}}, {MOD, XK_j, focChange, {.dir = Down}}, diff --git a/ewmh.cpp b/ewmh.cpp index c1e5e75..eec5de9 100644 --- a/ewmh.cpp +++ b/ewmh.cpp @@ -5,7 +5,7 @@ Display** dpy_; Window* root_; -void initEWMH(Display** dpy, Window* root, int numWS, std::string workspaceNames[]) +void initEWMH(Display** dpy, Window* root, int numWS, const std::string workspaceNames[]) { dpy_ = dpy; root_ = root; diff --git a/ewmh.h b/ewmh.h index d7b0741..7b1b5f4 100644 --- a/ewmh.h +++ b/ewmh.h @@ -8,7 +8,7 @@ #include "structs.h" -void initEWMH(Display** dpy, Window* root, int numWS, std::string workspaceNames[]); +void initEWMH(Display** dpy, Window* root, int numWS, const std::string workspaceNames[]); void updateClientList(std::map clients); diff --git a/logs.txt b/logs.txt deleted file mode 100644 index ff03f10..0000000 --- a/logs.txt +++ /dev/null @@ -1,19 +0,0 @@ ---- -Bars launched... -Successfully wrote command 'quit' to PID 196086 ---- -Bars launched... -Successfully wrote command 'quit' to PID 204881 ---- -Bars launched... -Successfully wrote command 'quit' to PID 207764 ---- -Bars launched... ---- -Bars launched... ---- -Bars launched... -Successfully wrote command 'quit' to PID 215833 -Successfully wrote command 'quit' to PID 215841 ---- -Bars launched... diff --git a/main.cpp b/main.cpp index 950b26d..6553889 100644 --- a/main.cpp +++ b/main.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -48,6 +49,12 @@ map frames; int currFrameID = 1; map frameIDS; +ScreenInfo* screens; +int* focusedWorkspaces; +int focusedScreen; +int nscreens; +int mX, mY; + #define getClient(c) clients.find(c)->second #define getFrame(f) frames.find(f)->second @@ -55,6 +62,11 @@ Window bar; int currWS = 1; + +// Usefull functions +int FFCF(int sID); +void detectScreens(); + void keyPress(XKeyEvent e); void configureRequest(XConfigureRequestEvent e); void mapRequest(XMapRequestEvent e); @@ -63,9 +75,39 @@ void clientMessage(XClientMessageEvent e); static int OnXError(Display* display, XErrorEvent* e); +void tileRoots(); +void untileRoots(); void tile(int frameID, int x, int y, int w, int h); void untile(int frameID); +// Usefull functions +int FFCF(int sID) +{ + if(frames.find(sID)->second.isClient) + return sID; + return FFCF(frames.find(sID)->second.subFrameIDs[0]); +} +void detectScreens() +{ + delete[] screens; + delete[] focusedWorkspaces; + log("Detecting screens: "); + XRRMonitorInfo* monitors = XRRGetMonitors(dpy, root, true, &nscreens); + log("\t"<second.isClient) - return sID; - return FFCF(frames.find(sID)->second.subFrameIDs[0]); -} int dirFind(int fID, MoveDir dir) { vector& pSF = frames.find(frames.find(fID)->second.pID)->second.subFrameIDs; @@ -328,6 +364,22 @@ void wMove(const KeyArg arg) } XSetInputFocus(dpy, focusedWindow, RevertToPointerRoot, CurrentTime); } +void bashSpawn(const KeyArg arg) +{ + if(fork() == 0) + { + int null = open("log.txt", O_WRONLY); + dup2(null, 1); + dup2(null, 2); + system(arg.str[0]); + exit(0); + } + +} +void screenTest(const KeyArg arg) +{ + detectScreens(); +} void keyPress(XKeyEvent e) { @@ -335,7 +387,7 @@ void keyPress(XKeyEvent e) KeySym keysym = XLookupKeysym(&e, 0); for(int i = 0; i < sizeof(keyBinds)/sizeof(keyBinds[0]); i++) { - if(keyBinds[i].keysym == keysym && (e.state & keyBinds[i].modifiers) == keyBinds[i].modifiers) + if(keyBinds[i].keysym == keysym && e.state == keyBinds[i].modifiers) { keyBinds[i].function(keyBinds[i].arg); } @@ -361,9 +413,40 @@ void mapRequest(XMapRequestEvent e) XTextProperty name; XGetWMName(dpy, e.window, &name); + XWindowAttributes attr; + XGetWindowAttributes(dpy, e.window, &attr); log("Mapping window: " << name.value); log("\tWindow ID: " << e.window); - + + Window focusedWindow; + int revertToReturn; + XGetInputFocus(dpy, &focusedWindow, &revertToReturn); + if(focusedWindow && focusedWindow != root) + { + //Use focused to determine monitors + XWindowAttributes focAttr; + XGetWindowAttributes(dpy, focusedWindow, &focAttr); + log("\tFocused is at x: " << focAttr.x << ", y: " << focAttr.y); + } + else + { + Window rootRet, childRet; + int rX, rY, cX, cY; + unsigned int maskRet; + XQueryPointer(dpy, root, &rootRet, &childRet, &rX, &rY, &cX, &cY, &maskRet); + if(mX == rX && mY == rY) + { + //Use focused screen + log("\tFocused screen is: " << focusedScreen); + } + else + { + //Use mouse + log("\tMouse is at x: " << rX << ", y: " << rY); + mX = rX; + mY = rY; + } + } unsigned char* data; Atom type; @@ -371,8 +454,6 @@ void mapRequest(XMapRequestEvent e) if (status == Success && ((Atom*)data)[0] == XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", false)) { log("\tWindow was bar"); - XWindowAttributes attr; - XGetWindowAttributes(dpy, e.window, &attr); bH = attr.height; bar = e.window; XFree(data); @@ -382,9 +463,6 @@ void mapRequest(XMapRequestEvent e) - Window focusedWindow; - int revertToReturn; - XGetInputFocus(dpy, &focusedWindow, &revertToReturn); XSetInputFocus(dpy, e.window, RevertToNone, CurrentTime); XSelectInput(dpy, e.window, EnterWindowMask); @@ -515,9 +593,11 @@ void destroyNotify(XDestroyWindowEvent e) } void clientMessage(XClientMessageEvent e) { - log("Client message: " << XGetAtomName(dpy, e.message_type)); + char* name = XGetAtomName(dpy, e.message_type); + log("Client message: " << name); if(e.message_type == XInternAtom(dpy, "_NET_CURRENT_DESKTOP", false)) { + //Change desktop int nextWS = (long)e.data.l[0] + 1; int prevWS = currWS; currWS = nextWS; @@ -531,8 +611,8 @@ void clientMessage(XClientMessageEvent e) //EWMH setCurrentDesktop(currWS); - } + XFree(name); } static int OnXError(Display* display, XErrorEvent* e) @@ -541,6 +621,20 @@ static int OnXError(Display* display, XErrorEvent* e) return 0; } +void tileRoots() +{ + for(int i = 0; i < nscreens; i++) + { + tile(focusedWorkspaces[i], screens[i].x + outerGaps, screens[i].y + outerGaps, screens[i].w - outerGaps*2, screens[i].h - outerGaps*2 - bH); + } +} +void untileRoots() +{ + for(int i = 0; i < nscreens; i++) + { + untile(focusedWorkspaces[i]); + } +} void tile(int frameID, int x, int y, int w, int h) { for(int fID : frames.find(frameID)->second.floatingFrameIDs) @@ -606,6 +700,7 @@ void untile(int frameID) int main(int argc, char** argv) { + mX = mY = 0; dpy = XOpenDisplay(nullptr); root = Window(DefaultRootWindow(dpy)); @@ -613,7 +708,11 @@ int main(int argc, char** argv) auto timeUnformatted = std::chrono::system_clock::now(); std::time_t time = std::chrono::system_clock::to_time_t(timeUnformatted); - log("\nYAT STARTING: " << std::ctime(&time) << "--------------------------------------" ); + log("\nYAT STARTING: " << std::ctime(&time) << "--------------------------------------"); + + screens = new ScreenInfo[1]; + focusedWorkspaces = new int[1]; + detectScreens(); int screenNum = DefaultScreen(dpy); sW = DisplayWidth(dpy, screenNum); @@ -669,7 +768,7 @@ int main(int argc, char** argv) case DestroyNotify: destroyNotify(e.xdestroywindow); case EnterNotify: - //cout << e.xcrossing.window << "\n"; + log(e.xcrossing.x); if(e.xcrossing.window == root) break; XSetInputFocus(dpy, e.xcrossing.window, RevertToNone, CurrentTime); diff --git a/makefile b/makefile index 45b40df..e2d98b5 100644 --- a/makefile +++ b/makefile @@ -1,7 +1,7 @@ .PHONY: clean CXX := g++ CXXFLAGS := #-g -fsanitize=address -fno-omit-frame-pointer -LINKFLAGS := -lX11 +LINKFLAGS := -lX11 -lXrandr OBJS_DIR := . OUT_DIR := . SOURCE_DIR := . diff --git a/notes.org b/notes.org new file mode 100644 index 0000000..e67a9a0 --- /dev/null +++ b/notes.org @@ -0,0 +1,24 @@ +#+TITLE: Notes for myself to read + +* Multiple monitors +** How I tell which monitor +- First I should check the currently focsued window +- Seccondly I should get the current mouseX and mouseY + - If the mouseX and mouseY match the old ones then use the focusedScreen + - If not then use mouseX and mouseY +** When to update mouseX and mouseY +Whenever I change focus or focused screen or map a new window +** When to change focusedScreen +It should get changed when I change workspace to one that should go on a different screen +** How to tell which monitor to focus when changing workspace +There should be an array with the priorities. + +* Fullscreen windows +This should be another thing like floating windows except each workspace only gets one +I should check it first when tiling and if it exists then draw it to the size of the screeen then return + +* General EWMH things +I should really figure out what all the client messages mean + +* The eventual program to communicate with YAT +Use a unix socket diff --git a/structs.h b/structs.h index c238413..f58a8cd 100644 --- a/structs.h +++ b/structs.h @@ -2,6 +2,8 @@ #include +#include +#include #include #define noID -1 @@ -36,3 +38,9 @@ struct Frame bool isRoot; std::vector floatingFrameIDs; }; + +struct ScreenInfo +{ + std::string name; + int x, y, w, h; +}; diff --git a/test b/test index 5427e8e..6a49b10 100644 --- a/test +++ b/test @@ -2,7 +2,7 @@ make -Xephyr :100 -screen 1600x900 & +Xephyr -screen 1600x900+160+0 :100 & sleep 0.1 -- cgit v1.2.3 From bcf9e480629d3bca64fc356e82560848aacfdd13 Mon Sep 17 00:00:00 2001 From: BossCode45 Date: Mon, 17 Oct 2022 14:51:58 +1300 Subject: Ready to test multi monitor workspace switch --- config.h | 27 +++++++++++++++++++-------- main.cpp | 29 ++++++++++++++++++++++++++--- notes.org | 1 + test | 2 +- 4 files changed, 47 insertions(+), 12 deletions(-) diff --git a/config.h b/config.h index d5d7ba5..4b140ac 100644 --- a/config.h +++ b/config.h @@ -8,8 +8,15 @@ const std::string startup[] = {"picom -fD 3", "feh --bg-scale /usr/share/backgrounds/vapor_trails_blue.png", "~/.config/polybar/launch.sh", "emacs --daemon"}; //Main config +// Sensible gaps const int gaps = 3; const int outerGaps = 3; +// Huge gaps +/* +const int gaps = 20; +const int outerGaps = 30; +*/ + const std::string logFile = "/tmp/yatlog.txt"; //WS config @@ -58,18 +65,22 @@ KEYCOM(wMove); KEYCOM(bashSpawn); KEYCOM(screenTest); -//Super key mod +// Super key mod #define MOD Mod4Mask -//Alt key mod +// Alt key mod //#define MOD Mod1Mask #define SHIFT ShiftMask + +// Programs to run for keybinds const char* alacritty[] = {"alacritty", NULL}; const char* rofi[] = {"rofi", "-i", "-show", "drun", NULL}; const char* qutebrowser[] = {"qutebrowser", NULL}; const char* i3lock[] = {"i3lock", "-eti", "/usr/share/backgrounds/lockscreen.png", NULL}; const char* suspend[] = {"systemctl", "suspend", NULL}; -const char* monConfig[] = {"~/.i3_commands/monitor-config.sh"}; +// Script to run for keybinds +// Script I made to run an xrandr command +const char* monConfig[] = {"~/.yat_commands/monitor-config.sh"}; #define WSKEY(K, X) \ @@ -77,8 +88,8 @@ const char* monConfig[] = {"~/.i3_commands/monitor-config.sh"}; {MOD|SHIFT, K, wToWS, {.num = X}} const Key keyBinds[] = { - //Modifiers //Key //Func //Args - //General + // Modifiers //Key //Func //Args + // General {MOD, XK_e, exit, {NULL}}, {MOD, XK_Return, spawn, {.str = alacritty}}, {MOD, XK_d, spawn, {.str = rofi}}, @@ -90,17 +101,17 @@ const Key keyBinds[] = { {MOD|SHIFT, XK_x, spawn, {.str = suspend}}, {MOD, XK_m, bashSpawn, {.str = monConfig}}, {MOD|SHIFT, XK_t, screenTest, {NULL}}, - //Focus + // Focus {MOD, XK_h, focChange, {.dir = Left}}, {MOD, XK_j, focChange, {.dir = Down}}, {MOD, XK_k, focChange, {.dir = Up}}, {MOD, XK_l, focChange, {.dir = Right}}, - //Window moving + // Window moving {MOD|SHIFT, XK_h, wMove, {.dir = Left}}, {MOD|SHIFT, XK_j, wMove, {.dir = Down}}, {MOD|SHIFT, XK_k, wMove, {.dir = Up}}, {MOD|SHIFT, XK_l, wMove, {.dir = Right}}, - //Workspaces + // Workspaces WSKEY(XK_1, 1), WSKEY(XK_2, 2), WSKEY(XK_3, 3), diff --git a/main.cpp b/main.cpp index 6553889..bfbd22e 100644 --- a/main.cpp +++ b/main.cpp @@ -66,6 +66,7 @@ int currWS = 1; // Usefull functions int FFCF(int sID); void detectScreens(); +void updateMousePos(); void keyPress(XKeyEvent e); void configureRequest(XConfigureRequestEvent e); @@ -107,6 +108,15 @@ void detectScreens() } XFree(monitors); } +void updateMousePos() +{ + Window rootRet, childRet; + int rX, rY, cX, cY; + unsigned int maskRet; + XQueryPointer(dpy, root, &rootRet, &childRet, &rX, &rY, &cX, &cY, &maskRet); + mX = rX; + mY = rY; +} //Keybind commands void exit(const KeyArg arg) @@ -162,13 +172,23 @@ void kill(const KeyArg arg) void changeWS(const KeyArg arg) { int prevWS = currWS; - currWS = arg.num; + currWS = arg.num; if(prevWS == currWS) return; + for(int i = 0; i < maxMonitors; i++) + { + if(nscreens > screenPreferences[arg.num][i]) + { + focusedWorkspaces[screenPreferences[arg.num][i]] = arg.num; + focusedScreen = screenPreferences[arg.num][i]; + } + } + untile(prevWS); - tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); + //tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); + tileRoots(); XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); //EWMH @@ -384,6 +404,7 @@ void screenTest(const KeyArg arg) void keyPress(XKeyEvent e) { if(e.same_screen!=1) return; + updateMousePos(); KeySym keysym = XLookupKeysym(&e, 0); for(int i = 0; i < sizeof(keyBinds)/sizeof(keyBinds[0]); i++) { @@ -426,6 +447,7 @@ void mapRequest(XMapRequestEvent e) //Use focused to determine monitors XWindowAttributes focAttr; XGetWindowAttributes(dpy, focusedWindow, &focAttr); + //TODO: Make this find the monitor log("\tFocused is at x: " << focAttr.x << ", y: " << focAttr.y); } else @@ -442,6 +464,7 @@ void mapRequest(XMapRequestEvent e) else { //Use mouse + //TODO: Make this find the monitor log("\tMouse is at x: " << rX << ", y: " << rY); mX = rX; mY = rY; @@ -746,7 +769,7 @@ int main(int argc, char** argv) } } - XSetInputFocus(dpy, root, RevertToNone, CurrentTime); + XSetInputFocus(dpy, root, RevertToNone, CurrentTime); cout << "Begin mainloop\n"; while(keepGoing) diff --git a/notes.org b/notes.org index e67a9a0..4489102 100644 --- a/notes.org +++ b/notes.org @@ -8,6 +8,7 @@ - If not then use mouseX and mouseY ** When to update mouseX and mouseY Whenever I change focus or focused screen or map a new window +Or just updating every key press should work ** When to change focusedScreen It should get changed when I change workspace to one that should go on a different screen ** How to tell which monitor to focus when changing workspace diff --git a/test b/test index 6a49b10..81cab6f 100644 --- a/test +++ b/test @@ -2,7 +2,7 @@ make -Xephyr -screen 1600x900+160+0 :100 & +Xephyr -screen 1600x900+2080+90 :100 & sleep 0.1 -- cgit v1.2.3 From 599664b8c9d7754d5a073fe2e4e129535f5fbd73 Mon Sep 17 00:00:00 2001 From: BossCode45 Date: Tue, 18 Oct 2022 17:57:38 +1300 Subject: Progress... I hope --- config.h | 4 ++-- main.cpp | 43 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/config.h b/config.h index 4b140ac..c848778 100644 --- a/config.h +++ b/config.h @@ -63,7 +63,7 @@ KEYCOM(wToWS); KEYCOM(focChange); KEYCOM(wMove); KEYCOM(bashSpawn); -KEYCOM(screenTest); +KEYCOM(reload); // Super key mod #define MOD Mod4Mask @@ -100,7 +100,7 @@ const Key keyBinds[] = { {MOD|SHIFT, XK_x, spawn, {.str = i3lock}}, {MOD|SHIFT, XK_x, spawn, {.str = suspend}}, {MOD, XK_m, bashSpawn, {.str = monConfig}}, - {MOD|SHIFT, XK_t, screenTest, {NULL}}, + {MOD|SHIFT, XK_r, reload, {NULL}}, // Focus {MOD, XK_h, focChange, {.dir = Left}}, {MOD, XK_j, focChange, {.dir = Down}}, diff --git a/main.cpp b/main.cpp index bfbd22e..46cf540 100644 --- a/main.cpp +++ b/main.cpp @@ -51,7 +51,7 @@ map frameIDS; ScreenInfo* screens; int* focusedWorkspaces; -int focusedScreen; +int focusedScreen = 0; int nscreens; int mX, mY; @@ -94,11 +94,12 @@ void detectScreens() delete[] focusedWorkspaces; log("Detecting screens: "); XRRMonitorInfo* monitors = XRRGetMonitors(dpy, root, true, &nscreens); - log("\t"< screenPreferences[arg.num][i]) + if(nscreens > screenPreferences[arg.num - 1][i]) { - focusedWorkspaces[screenPreferences[arg.num][i]] = arg.num; - focusedScreen = screenPreferences[arg.num][i]; + //log("Found screen (screen " << screenPreferences[arg.num - 1][i] << ")"); + prevWS = focusedWorkspaces[screenPreferences[arg.num - 1][i]]; + //log("Changed prevWS"); + focusedWorkspaces[screenPreferences[arg.num - 1][i]] = arg.num; + //log("Changed focusedWorkspaces"); + focusedScreen = screenPreferences[arg.num - 1][i]; + //log("Changed focusedScreen"); + break; } } - untile(prevWS); + //log("Finished changes"); + + //log(prevWS); + if(prevWS < 1 || prevWS > numWS) + { + //untile(prevWS); + } + //log("Untiled"); //tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); tileRoots(); + //log("Roots tiled"); XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); //EWMH @@ -388,7 +413,7 @@ void bashSpawn(const KeyArg arg) { if(fork() == 0) { - int null = open("log.txt", O_WRONLY); + int null = open("/dev/null", O_WRONLY); dup2(null, 1); dup2(null, 2); system(arg.str[0]); @@ -396,7 +421,7 @@ void bashSpawn(const KeyArg arg) } } -void screenTest(const KeyArg arg) +void reload(const KeyArg arg) { detectScreens(); } @@ -791,7 +816,7 @@ int main(int argc, char** argv) case DestroyNotify: destroyNotify(e.xdestroywindow); case EnterNotify: - log(e.xcrossing.x); + //log(e.xcrossing.x); if(e.xcrossing.window == root) break; XSetInputFocus(dpy, e.xcrossing.window, RevertToNone, CurrentTime); -- cgit v1.2.3 From 6ea2604001ccfa597ae729681f37b3d7bbef3a1a Mon Sep 17 00:00:00 2001 From: BossCode45 Date: Wed, 14 Dec 2022 17:46:48 +1300 Subject: Multiple monitors kinda working --- config.h | 17 ++++++-- main.cpp | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- test | 5 ++- 3 files changed, 139 insertions(+), 25 deletions(-) diff --git a/config.h b/config.h index c848778..34b5704 100644 --- a/config.h +++ b/config.h @@ -5,7 +5,12 @@ #include //Startup -const std::string startup[] = {"picom -fD 3", "feh --bg-scale /usr/share/backgrounds/vapor_trails_blue.png", "~/.config/polybar/launch.sh", "emacs --daemon"}; +const std::string startup[] = { + //"picom -fD 3", + "feh --bg-scale /usr/share/backgrounds/vapor_trails_blue.png", + //"~/.config/polybar/launch.sh", + //"emacs --daemon" +}; //Main config // Sensible gaps @@ -64,11 +69,14 @@ KEYCOM(focChange); KEYCOM(wMove); KEYCOM(bashSpawn); KEYCOM(reload); +KEYCOM(wsDump); +KEYCOM(nextMonitor); // Super key mod #define MOD Mod4Mask +#define ALT Mod1Mask // Alt key mod -//#define MOD Mod1Mask +// #define MOD Mod1Mask #define SHIFT ShiftMask // Programs to run for keybinds @@ -78,7 +86,7 @@ const char* qutebrowser[] = {"qutebrowser", NULL}; const char* i3lock[] = {"i3lock", "-eti", "/usr/share/backgrounds/lockscreen.png", NULL}; const char* suspend[] = {"systemctl", "suspend", NULL}; -// Script to run for keybinds +// Scripts to run for keybinds // Script I made to run an xrandr command const char* monConfig[] = {"~/.yat_commands/monitor-config.sh"}; @@ -101,11 +109,14 @@ const Key keyBinds[] = { {MOD|SHIFT, XK_x, spawn, {.str = suspend}}, {MOD, XK_m, bashSpawn, {.str = monConfig}}, {MOD|SHIFT, XK_r, reload, {NULL}}, + // Testing + {MOD, XK_p, wsDump, {NULL}}, // Focus {MOD, XK_h, focChange, {.dir = Left}}, {MOD, XK_j, focChange, {.dir = Down}}, {MOD, XK_k, focChange, {.dir = Up}}, {MOD, XK_l, focChange, {.dir = Right}}, + {ALT, XK_Tab, nextMonitor, {NULL}}, // Window moving {MOD|SHIFT, XK_h, wMove, {.dir = Left}}, {MOD|SHIFT, XK_j, wMove, {.dir = Down}}, diff --git a/main.cpp b/main.cpp index 46cf540..ebec3f2 100644 --- a/main.cpp +++ b/main.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -67,11 +68,13 @@ int currWS = 1; int FFCF(int sID); void detectScreens(); void updateMousePos(); +void focusRoot(int root); void keyPress(XKeyEvent e); void configureRequest(XConfigureRequestEvent e); void mapRequest(XMapRequestEvent e); void destroyNotify(XDestroyWindowEvent e); +void enterNotify(XEnterWindowEvent e); void clientMessage(XClientMessageEvent e); static int OnXError(Display* display, XErrorEvent* e); @@ -125,6 +128,27 @@ void updateMousePos() mX = rX; mY = rY; } +int getClientChild(int fID) +{ + if(getFrame(fID).isClient) + return fID; + else + return getClientChild(getFrame(fID).subFrameIDs[0]); +} +void focusRoot(int root) +{ + //log("Focusing root: " << root); + if(getFrame(root).subFrameIDs.size() == 0) + { + //log("\tRoot has no children"); + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + return; + } + int client = getFrame(getClientChild(root)).cID; + Window w = getClient(client).w; + //log("\tFocusing window: " << w); + XSetInputFocus(dpy, w, RevertToPointerRoot, CurrentTime); +} //Keybind commands void exit(const KeyArg arg) @@ -180,11 +204,11 @@ void kill(const KeyArg arg) void changeWS(const KeyArg arg) { int prevWS = currWS; - untileRoots(); currWS = arg.num; if(prevWS == currWS) return; + untileRoots(); //log("Changing WS with keybind"); @@ -192,12 +216,17 @@ void changeWS(const KeyArg arg) { if(nscreens > screenPreferences[arg.num - 1][i]) { + int screen = screenPreferences[arg.num - 1][i]; //log("Found screen (screen " << screenPreferences[arg.num - 1][i] << ")"); prevWS = focusedWorkspaces[screenPreferences[arg.num - 1][i]]; //log("Changed prevWS"); focusedWorkspaces[screenPreferences[arg.num - 1][i]] = arg.num; //log("Changed focusedWorkspaces"); - focusedScreen = screenPreferences[arg.num - 1][i]; + if(focusedScreen != screenPreferences[arg.num - 1][i]) + { + focusedScreen = screenPreferences[arg.num - 1][i]; + XWarpPointer(dpy, root, root, 0, 0, 0, 0, screens[screen].x + screens[screen].w/2, screens[screen].y + screens[screen].h/2); + } //log("Changed focusedScreen"); break; } @@ -267,7 +296,9 @@ void wToWS(const KeyArg arg) setWindowDesktop(focusedWindow, arg.num); XUnmapWindow(dpy, focusedWindow); - tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); + //tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); + untileRoots(); + tileRoots(); XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); } int dirFind(int fID, MoveDir dir) @@ -403,7 +434,9 @@ void wMove(const KeyArg arg) std::swap(pSF[i], pSF[swapPos]); } - tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); + untileRoots(); + tileRoots(); + //tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); XSetInputFocus(dpy, focusedWindow, RevertToPointerRoot, CurrentTime); return; } @@ -425,6 +458,31 @@ void reload(const KeyArg arg) { detectScreens(); } +void wsDump(const KeyArg arg) +{ + log("Workspace dump:"); + for(int i = 1; i < currFrameID; i++) + { + if(getFrame(i).isClient) + { + int id = i; + while(!getFrame(id).isRoot) + { + id=getFrame(id).pID; + } + log("\tClient with ID: " << getClient(getFrame(i).cID).w << ", on worskapce " << id); + } + } +} +void nextMonitor(const KeyArg arg) +{ + focusedScreen++; + if(focusedScreen >= nscreens) + focusedScreen = 0; + + XWarpPointer(dpy, root, root, 0, 0, 0, 0, screens[focusedScreen].x + screens[focusedScreen].w/2, screens[focusedScreen].y + screens[focusedScreen].h/2); + focusRoot(focusedWorkspaces[focusedScreen]); +} void keyPress(XKeyEvent e) { @@ -466,14 +524,12 @@ void mapRequest(XMapRequestEvent e) Window focusedWindow; int revertToReturn; + int pID; XGetInputFocus(dpy, &focusedWindow, &revertToReturn); - if(focusedWindow && focusedWindow != root) + if(focusedWindow && focusedWindow != root && frameIDS.count(focusedWindow)>0) { - //Use focused to determine monitors - XWindowAttributes focAttr; - XGetWindowAttributes(dpy, focusedWindow, &focAttr); - //TODO: Make this find the monitor - log("\tFocused is at x: " << focAttr.x << ", y: " << focAttr.y); + //Use focused to determine parent + pID = frames.find(frameIDS.find(focusedWindow)->second)->second.pID; } else { @@ -481,6 +537,22 @@ void mapRequest(XMapRequestEvent e) int rX, rY, cX, cY; unsigned int maskRet; XQueryPointer(dpy, root, &rootRet, &childRet, &rX, &rY, &cX, &cY, &maskRet); + mX = rX; + mY = rY; + int monitor = 0; + for(int i = 0; i < nscreens; i++) + { + if(screens[i].x <= mX && mX < screens[i].x + screens[i].w) + { + if(screens[i].y <= mY && mY < screens[i].y + screens[i].h) + { + monitor = i; + } + } + } + pID = focusedWorkspaces[monitor]; + focusedScreen = monitor; + /* if(mX == rX && mY == rY) { //Use focused screen @@ -494,6 +566,7 @@ void mapRequest(XMapRequestEvent e) mX = rX; mY = rY; } + */ } unsigned char* data; @@ -522,7 +595,7 @@ void mapRequest(XMapRequestEvent e) clients.insert(pair(c.ID, c)); //Make frame - int pID = (frameIDS.count(focusedWindow)>0)? frames.find(frameIDS.find(focusedWindow)->second)->second.pID : currWS; + //pID = (frameIDS.count(focusedWindow)>0)? frames.find(frameIDS.find(focusedWindow)->second)->second.pID : currWS; vector v; vector floating; Frame f = {currFrameID, pID, true, c.ID, noDir, v, false, floating}; @@ -542,7 +615,8 @@ void mapRequest(XMapRequestEvent e) setWindowDesktop(e.window, currWS); updateClientList(clients); XFree(data); - tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); + //tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); + tileRoots(); return; } XFree(data); @@ -589,7 +663,8 @@ void mapRequest(XMapRequestEvent e) setWindowDesktop(e.window, currWS); updateClientList(clients); - tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); + //tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); + tileRoots(); } void destroyNotify(XDestroyWindowEvent e) @@ -635,16 +710,42 @@ void destroyNotify(XDestroyWindowEvent e) } } XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); - tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); + //tile(currWS, outerGaps, outerGaps, sW - outerGaps*2, sH - outerGaps*2 - bH); + tileRoots(); updateClientList(clients); } +void enterNotify(XEnterWindowEvent e) +{ + //log(e.xcrossing.x); + /* Cancel if crossing into root + if(e.xcrossing.window == root) + break; + */ + XWindowAttributes attr; + XGetWindowAttributes(dpy, e.window, &attr); + int monitor = 0; + for(int i = 0; i < nscreens; i++) + { + if(screens[i].x <= attr.x && attr.x < screens[i].x + screens[i].w) + { + if(screens[i].y <= attr.y && attr.y < screens[i].y + screens[i].h) + { + monitor = i; + } + } + } + focusedScreen = monitor; + XSetInputFocus(dpy, e.window, RevertToNone, CurrentTime); +} void clientMessage(XClientMessageEvent e) { char* name = XGetAtomName(dpy, e.message_type); log("Client message: " << name); if(e.message_type == XInternAtom(dpy, "_NET_CURRENT_DESKTOP", false)) { + changeWS({.num = (int)((long)e.data.l[0] + 1)}); + /* //Change desktop int nextWS = (long)e.data.l[0] + 1; int prevWS = currWS; @@ -659,6 +760,7 @@ void clientMessage(XClientMessageEvent e) //EWMH setCurrentDesktop(currWS); + */ } XFree(name); } @@ -767,13 +869,14 @@ int main(int argc, char** argv) sH = DisplayHeight(dpy, screenNum); XSetErrorHandler(OnXError); - XSelectInput(dpy, root, SubstructureRedirectMask | SubstructureNotifyMask | KeyPressMask); + XSelectInput(dpy, root, SubstructureRedirectMask | SubstructureNotifyMask | KeyPressMask | EnterWindowMask); 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); + //log("Grabbing " << XKeysymToString(keyBinds[i].keysym)); } - + XDefineCursor(dpy, root, XCreateFontCursor(dpy, XC_top_left_arrow)); //EWMH initEWMH(&dpy, &root, numWS, workspaceNames); setCurrentDesktop(1); @@ -795,6 +898,7 @@ int main(int argc, char** argv) } XSetInputFocus(dpy, root, RevertToNone, CurrentTime); + XWarpPointer(dpy, root, root, 0, 0, 0, 0, 960, 540); cout << "Begin mainloop\n"; while(keepGoing) @@ -815,11 +919,9 @@ int main(int argc, char** argv) break; case DestroyNotify: destroyNotify(e.xdestroywindow); + break; case EnterNotify: - //log(e.xcrossing.x); - if(e.xcrossing.window == root) - break; - XSetInputFocus(dpy, e.xcrossing.window, RevertToNone, CurrentTime); + enterNotify(e.xcrossing); break; case ClientMessage: clientMessage(e.xclient); diff --git a/test b/test index 81cab6f..49cbf49 100644 --- a/test +++ b/test @@ -2,10 +2,11 @@ make -Xephyr -screen 1600x900+2080+90 :100 & +#Xephyr +extension RANDR +xinerama -screen 1600x900 -screen 1600x900 -ac :1 & +Xephyr -screen 1600x900+2080+90 :1 & sleep 0.1 -DISPLAY=:100 ./YATwm +DISPLAY=:1 ./YATwm pkill Xephyr -- cgit v1.2.3 From 7ec43dd82b8507e1cc4d1b8b1ab1af2298c77c84 Mon Sep 17 00:00:00 2001 From: BossCode45 Date: Wed, 14 Dec 2022 20:02:16 +1300 Subject: Final commit before merge --- notes.org | 31 ++++++++++++++++--------------- structs.h | 1 + 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/notes.org b/notes.org index 4489102..a3b6bf1 100644 --- a/notes.org +++ b/notes.org @@ -1,18 +1,19 @@ -#+TITLE: Notes for myself to read +#+TITLE: Features to add -* Multiple monitors -** How I tell which monitor -- First I should check the currently focsued window -- Seccondly I should get the current mouseX and mouseY - - If the mouseX and mouseY match the old ones then use the focusedScreen - - If not then use mouseX and mouseY -** When to update mouseX and mouseY -Whenever I change focus or focused screen or map a new window -Or just updating every key press should work -** When to change focusedScreen -It should get changed when I change workspace to one that should go on a different screen -** How to tell which monitor to focus when changing workspace -There should be an array with the priorities. +* Remembering focus +Use the variable ~whichChildFocused~ for each non client frame, this is the index of the child that is focused. To then find focused child for a root recurse through all the frames going through the focused child. +** Where it should be updated ++ When focus is moved ++ When a client is moved (because it should retain focus) ++ When a client is deleted (if it had focus before) +** Where it should be used +Whenever I set focus I should use the focused client of whichever workspace is focused + +* Change focus and move between monitors +Perhaps I can just add something to the ~dirFind~ function + +* TOML config +put in ~/.config/YATwm/config.toml * Fullscreen windows This should be another thing like floating windows except each workspace only gets one @@ -21,5 +22,5 @@ I should check it first when tiling and if it exists then draw it to the size of * General EWMH things I should really figure out what all the client messages mean -* The eventual program to communicate with YAT +* The eventual program to communicate with YATwm Use a unix socket diff --git a/structs.h b/structs.h index f58a8cd..0ace524 100644 --- a/structs.h +++ b/structs.h @@ -37,6 +37,7 @@ struct Frame std::vector subFrameIDs; bool isRoot; std::vector floatingFrameIDs; + //int whichChildFocused = 0; }; struct ScreenInfo -- cgit v1.2.3