diff --git a/README.md b/README.md index 41ac82f..8faedca 100755 --- a/README.md +++ b/README.md @@ -6,9 +6,9 @@ `ryudo` is a fork of Russ Cox's Rio, itself a fork of David Hogan's 9wm. The primary additions I've made are: -- `urxvt` is detected as a proper terminal program for sweeping out new windows +- `urxvt`, `konsole`, and `Alacritty` are detected as proper terminal programs for sweeping out new windows - `urxvt` is the default terminal emulator (still tries `9term` and then `xterm` if no dice) -- Customizable colors, borders, fonts, and keybinds in `config.h` +- Customizable colors, borders, fonts, gaps, and keybinds in `config.h` - Default keybindings: + New Terminal: Super+Slash + Destroy: Super+D @@ -31,8 +31,9 @@ The primary additions I've made are: + Virtual Desk--: Super+Left - Other new features customizable by `config.h`: + Show/hide 'Stick' Button3 menuitem - + `AUTOSTICK` list of windows to spawn sticky by default + + `AUTOSTICK` list of windows to spawn sticky by default and not focus (pseudo-panel/dock windows) + Optionally notify with `notify-send` which desktop is switched to (I use it with `dunst`) + + Gaps for pseudo-tiling The name "Ryudo" is a nod to "Rio" and a Japanese word for "flow." Using Ryudo should feel very natural -- you can do things with keyboard or @@ -41,15 +42,16 @@ using the popup menu, or using the keyboard, which will spawn a terminal window centered taking up 9/25 of the screen (3/5 width, 3/5 height). ### Dependencies, Building, Installation -Being forked from Rio, Ryudo requires **plan9port**, **Xlib**, and **Xt**. -Make it with **mk ryudo** and then copy the resulting executable **ryudo** to +Being forked from Rio, Ryudo requires `plan9port`, `Xlib`, and `Xt`. +If you enable notifications, it of course requires `notify-send`. +Make it with `mk ryudo` and then copy the resulting executable `ryudo` to somewhere in your **PATH** -If you try to install it with **mk install** it will probably install -to **$PLAN9/bin/** under the name **rio**. This is less than ideal but I'm -not a master of mk, so my protocol is to use a mk target **ryudo** which -builds the program as **o.rio**, then calls **ryudomagic.sh** to rename -the program. +If you try to install it with `mk install` it will probably install +to `$PLAN9/bin/` under the name `rio`. This is less than ideal but I'm +not a master of mk, so my protocol is to use a mk target `ryudo` which +builds the program as `o.rio`, then calls `ryudomagic.sh` to rename +the program. A proper mkfile is planned before version 1.0. If you have trouble building, you might need to edit the **mkfile** at line 2 to point to the proper location of your plan9port's **mkwsysrules.sh**. @@ -57,8 +59,8 @@ to point to the proper location of your plan9port's **mkwsysrules.sh**. ### Bugs and Caveats Of the bugs and caveats not already mentioned in Rio's readme: - Rendering of windows with RGBA surfaces is bound to RGB space (xshove and transset can be leveraged to get transparent terminals if you want it) -- Since maximization doesn't use the EWM Hint for maximization, programs like Firefox will remember their window size as the maximized size and probably start offset so they aren't completely onscreen. There is probably a rule we can put in newwindow() to mitigate this, but it's not super important. -- Sticky windows may show their borders with the active color regardless of their state. +- Since maximization doesn't use the EWM Hint for maximization, programs like Firefox will remember their window size as the maximized size and probably start offset so they aren't completely onscreen. Smarter window placement to fix this is on the short list. +- Multimonitor setups are treated like one giant monitor. This is on the short list also. - Probably more! ### Legacy diff --git a/client.c b/client.c index c5f78e7..c55d41e 100755 --- a/client.c +++ b/client.c @@ -302,7 +302,7 @@ isautostick(Client *c) char **a = autostick; while(*a){ - if(strstr(c->class, *a)) { + if(c && c->class && strstr(c->class, *a)) { return 1; } ++a; diff --git a/config.h b/config.h index 76ee110..8cbd523 100755 --- a/config.h +++ b/config.h @@ -15,6 +15,15 @@ #define SMENUFGCOL 0x000000 #define SMENUBGCOL 0x1F9B92 +/* This sets the size ratio for windows spawned via keyboard or + * center-snapped + */ +#define CENTERNUM 2 +#define CENTERDEN 3 + +/* Centered windows should maximize vertically? */ +#define CENTERVMAX + /* Show 'Stick' menuitem? */ //#define SHOWSTICK diff --git a/fns.h b/fns.h index 565d071..2dcf5ca 100755 --- a/fns.h +++ b/fns.h @@ -67,6 +67,7 @@ void keyrelease(); void keysetup(); void quickreshape(Client *c, int x, int y, int dx, int dy); void stickystack(int); +void centercurrent(XWindowAttributes ra); /* menu.c */ void button(); diff --git a/key.c b/key.c index 9d7ab08..fe269a4 100755 --- a/key.c +++ b/key.c @@ -166,8 +166,9 @@ keypress(XKeyEvent *e) quickreshape(current, ra.width/2 + 0.5*GAPSZ, GAPSZ, ra.width/2 - 1.5*GAPSZ, ra.height/2 - 1.5*GAPSZ); /* center snap */ - else if (e->keycode == ccode && (e->state&SHORTCUTMOD) == (MODBITS)) - quickreshape(current, ra.width/6, GAPSZ, 2*ra.width/3, ra.height - 2*GAPSZ); + else if (e->keycode == ccode && (e->state&SHORTCUTMOD) == (MODBITS)){ + centercurrent(ra); +} #ifdef DEVEL /* manage autostuck windows */ @@ -238,6 +239,24 @@ quickreshape(Client *c, int x, int y, int dx, int dy) sendconfig(c); } +void +centercurrent(XWindowAttributes ra) +{ + static int centeroffsetnum = CENTERNUM%2 == 0 ? + CENTERDEN - CENTERNUM : + (CENTERDEN - CENTERNUM)/2; + + static int centeroffsetden = CENTERNUM%2 == 0 ? + CENTERDEN*2 : + CENTERDEN; + + #ifdef CENTERVMAX + quickreshape(current, centeroffsetnum*ra.width/centeroffsetden, GAPSZ, CENTERNUM*ra.width/CENTERDEN, ra.height - 2*GAPSZ); + #else + quickreshape(current, centeroffsetnum*ra.width/centerofsetden, centeroffsetnum*ra.height/centeroffsetden, CENTERNUM*ra.width/CENTERDEN, CENTERNUM*ra.height/CENTERDEN); + #endif +} + static void alttab(int shift) { diff --git a/manage.c b/manage.c index 7fbf03d..698bac2 100755 --- a/manage.c +++ b/manage.c @@ -30,6 +30,11 @@ manage(Client *c, int mapped) XClassHint class; XWMHints *hints; XSetWindowAttributes attrs; + + + static XWindowAttributes ra; + XGetWindowAttributes(dpy, DefaultRootWindow(dpy), &ra); + trace("manage", c, 0); XSelectInput(dpy, c->window, ColormapChangeMask | EnterWindowMask | PropertyChangeMask | FocusChangeMask | KeyPressMask); @@ -180,14 +185,11 @@ manage(Client *c, int mapped) XMapWindow(dpy, c->parent); XUnmapWindow(dpy, c->screen->sweepwin); #ifdef AUTOSTICK - if(c->class && !isautostick(c)) - active(c); -#else - if(c->class) - active(c); + if(!isautostick(c)) #endif - else if(c->trans != None && current && current->window == c->trans) active(c); + /*else if(c->trans != None && current && current->window == c->trans) + active(c);*/ else setactive(c, 0); setstate(c, NormalState); @@ -196,6 +198,31 @@ manage(Client *c, int mapped) cmapfocus(current); c->init = 1; + /* If the window is out of bounds of the screen, try to wrangle it */ + + /* If it's bigger than the screen, try to set it maximized */ + if (c->dx >= ra.width || c->dy >= ra.width){ + if (c->dx >= ra.width) + quickreshape(c, -BORDER, c->y - BORDER, ra.width + 2*BORDER, c->dy + 2*BORDER); + if (c->dy >= ra.height) + quickreshape(c, c->x - BORDER, -BORDER, c->dx + 2*BORDER, ra.height + 2*BORDER); + + /* and if it's got an edge out of bounds, nudge it into bounds */ + } else { + if (c->x < BORDER){ + quickreshape(c, 0, c->y - BORDER, c->dx + 2*BORDER, c->dy + 2*BORDER); + } + if (c->y < BORDER){ + quickreshape(c, c->x - BORDER, 0, c->dx + 2*BORDER, c->dy + 2*BORDER); + } + if (c->x + c->dx + BORDER > ra.width){ + quickreshape(c, ra.width - (c->dx + 2*BORDER), c->y - BORDER, c->dx + 2*BORDER, c->dy + 2*BORDER); + } + if (c->y + c->dy + BORDER > ra.height){ + quickreshape(c, c->x - BORDER, ra.height - (c->dy + 2*BORDER), c->dx + 2*BORDER, c->dy + 2*BORDER); + } + } + /* * If we swept the window, let's send a resize event to the * guy who just got resized. It's not clear whether the apps