# Virtual desktops for Hyprland ![hyprico](.github/hyprland.ico)
`virtual-desktops` is a plugin for the [Hyprland](https://github.com/hyprwm/Hyprland) compositor. `virtual-desktops` manages multiple screens workspaces as if they were a single virtual desktop.
In Hyprland, each screen has its own set of workspaces. For instance, say you have two monitors, with workspace 1 on screen 1
and workspace 2 on screen 2:
- When you switch from workspace 1 to 2, Hyprland will simply focus your second screen;
- If you switch to workspace 3, your active screen will go to workspace 3, whereas the other screen will stay on whichever workspace it is currently on.
You may think of a virtual desktop, instead, as a "single"
workspace which extends across your screens (even though, internally, you will still have _n_ different workspaces on your _n_ monitors). If you've ever used KDE Plasma (or Gnome, I think) with
- When you switch to virtual desktop 2, both screens will switch to empty workspaces. Let's say here you open your email client and your favourite chat application;
- If you switch back to virtual desktop 1, you will get back your web browser and the IDE on screen 1 and 2; and viceversa when you go back to virtual desktop 2.
Internally, this simply ties _n_ workspaces to your _n_ screens, for each virtual desktop. That is, on virtual desktop 1 you will have workspace 1 on screen 1 and workspace 2 on screen 2;
on virtual desktop 2, you will have workspace 3 on screen 1 and workspace 4 on screen 2, and so on.
However, if you focus another workspace on a given virtual desktop, the plugin will remember this and you will keep this layout (see [Layouts](#Layouts)).
**Notice**: screen 1 and screen 2 are not necessarily what you expect your first and second screen to be, e.g., screen 1 is not necessarily your left screen, and screen 2 is not necessarily your right screen.
| movetolastdesk (window) | Moves the active/selected window to the last visited `vdesk` | optional window | `movetolastdesk` or `movetolastdesk title:kitty` |
| movetolastdesksilent (window) | same as `movetolastdesk`, but doesn't switch to desk | same as above | same as above |
| movetoprevdesk (cycleback)(,window) | Moves the active/selected window to the previous `vdesk`. If `cycleback == 1 and vdesk == 1`, moves to vdesk with max id | optional 1 for true, optional window | `movetoprevdesk 1` or `movetodesk ,title:kitty` |
| movetoprevdesksilent (cycleback)(,window) | same as `movetoprevdesk`, but doesn't switch to desk | same as above | same as above |
| movetonextdesk (cycle)(, window) | Moves the active/selected window to the next `vdesk`. If `cycle == 1 and vdesk == max`, moves to vdesk 1 | optional 1 for true, optional window | `movetonextdesk 1` or `movetonextdesk ,title:kitty` |
| movetonextdesksilent (cycle)(, window) | same as `movetonextdesk`, but doesn't switch to desk | same as above | same as above |
| vdeskreset (vdesk) | reset layouts on `vdesk` or on all vdesks if no argument is given (see [Layouts](#Layouts)) | optional vdesk, see below | `vdeskreset` or `vdeskreset 2` or `vdeskreset coding` |
> BREAKING v2.1.0: `prevdesk` dispatcher was renamed to `lastdesk`. `prevdesk` has a new functionality: it goes to the previous desk. If you were using `prevdesk`, please update your config.
The `movetodesk` and `movetodesksilent` dispatchers work similarly to
Hyprland's `movetoworkspace` and `movetoworkspacesilent` dispatchers. See [Hyprland's wiki](https://wiki.hyprland.org/Configuring/Dispatchers/#list-of-dispatchers). Of course, make sure to use the `vdesk` syntax above instead of Hyprland's.
any workspace related configuration, such as `wsbind`. If you want to leverage [workspace-specific rules](https://wiki.hyprland.org/Configuring/Workspace-Rules/), you can: workspaces are always assigned
The vdesk a workspace will end up to is easily computed by doing `ceil(workspace_id / n_monitors)`. You know where I'm going with this one...you can easily script it.
Since version 2.2, this plugin exposes a couple of `hyprctl` commands. That is, you can use them by calling `hyprctl {command} {args}`.
**NOTICE**: some of these used to be dispatchers.
| Command | description | args | example|
|------------|-------------|------|--------|
| printdesk (vdesk)| Prints to Hyprland log the specified vdesk or the currently active vdesk* (if no argument is given) | optional vdesk, see [above](#hyprctl-dispatchers) | `hyprctl printdesk` or `hyprctl printdesk 2` or `hyprctl printdesk coding`|
| printlayout | print to Hyprland logs the current layout | `none` | `hyprctl printlayout` |
A window matched by a sticky rule will be moved to the matched vdesk:
1. When the window is created (similar to [Hyprland's `workspace` windowrule](https://wiki.hyprland.org/Configuring/Window-Rules/#window-rules-v2), but with virtual desks);
2. Every time a monitor is connected/disconnected.
**BE CAREFUL**:
1.**NOT** to mix this with Hyprland's `workspace` windowrule (it wouldn't make sense right?);
2. This is not a plugin config, but an Hyprland keyword. Place it in the top level of Hyprland's config (i.e., where you'd put windowrules too).
#### Syntax
```bash
stickyrule = window,vdesk
```
-`window` identifier has the same syntax as [Hyprland's windowrule window](https://wiki.hyprland.org/Configuring/Window-Rules/#window-rules-v2) identifier;
-`vdesk` identifier has the same syntax specified above.
| names | map a vdesk id with a name | map[int:string], see below| `names = 1:coding, 2:internet, 3:mail and chats`|
| cycleworkspaces | if set to 1 and switching to the currently active vdesk, workspaces will be swapped between your monitors (see [swapactiveworkspaces](https://wiki.hyprland.org/Configuring/Dispatchers/#list-of-dispatchers))| `0` or `1`| `cycleworkspaces = 1`|
| rememberlayout | chooses how layouts should be remembered (see [Layouts](#Layouts)), defaults to `size` | `none`, `size` or `monitors` | `remember = size` |
| notifyinit | chooses whether to display the startup notification, defaults to 1 | `0` or `1` | `notifyinit = 0` |
| verbose_logging | whether to log more stuff, defaults to 0 | `0` or `1` | `verbose_logging = 0` |
Version 2.0 of this plugin introduced the concept of a *layout*, with the meaning of "a specific combination of workspaces on a (more or less) specific combination of monitors".
In other words, `virtual-desktops` remembers if you focused another workspace on your vdesk, even if you switch to another vdesk and then come back to this one
#### Example
Say you have 2 monitors A and B, and you're on vdesk 1:
- On monitor A you have workspace 1, and on monitor B you have workspace 2;
- Now, say you focus workspace 4 with `hyprctl dispatch workspace 4` on monitor B.
- If you switch to vdesk 2 and back to vdesk 1, you will see workspace 4 on monitor B instead of workspace 2.
**Notice** that, in this case, workspace 4 would also be shown on vdesk 2.
### Layouts are cached and restored if you disconnect/reconnect monitors
Internally, every vdesk will cache all the previous layouts. Once a monitor is connected/disconnected, the plugin will try to look for a previously existing layout for this configuration
and it will apply it.
#### Example
Continuing from the previous example, say you now disconnect monitor B and then you reconnect it, while being on vdesk 1:
- the previous layout will be matched and you will get back workspace 1 on monitor A and workspace 4 on monitor B.
This would work also if instead of disconnecting and reconnecting monitor B, you connected a third monitor C and then disconnect it.
### Choosing how to remember, or choosing to forget
Version 2.0 also introduced the `rememberlayout` config option: with this option, we can choose if we want to match a layout by number of monitors (`size`) or by unique monitor descriptions (`monitors`). There is also the third and final option to not remember layouts at all (`none`).
#### Example
Continuing from the previous example. Say we now disconnect monitor B and connect monitor C: our connected monitors are A and C.
- if `rememberlayout = size` (the default), the existing layout will still be matched, we will have workspace 1 on monitor A, workspace 4 on monitor C;
- if `rememberlayout = monitors`, a new layout will be created with defaults: workspace 1 on monitor A, workspace 2 on monitor C;
- if `rememberlayout = none`, same as above.
If we now disconnect monitor C and reconnect monitor B: our connected monitors are A and B.
- if `rememberlayout = size` (the default), the existing layout will be matched, we will have workspace 1 on monitor A, workspace 4 on monitor B;
- if `rememberlayout = monitors`, the existing layout will be matched, we will have workspace 1 on monitor A, workspace 4 on monitor B;
- if `rememberlayout = none`, a new layout will be created with defaults: workspace 1 on monitor A, workspace 2 on monitor C.
this will compile and copy the compiled `.so` plugin in the `$HOME/.local/share/hyprload/plugins/bin` path (useful if you use [hyprload](https://github.com/Duckonaut/hyprload)).
You can also use `make virtual-desktops.so` to output the compiled plugin in the repo directory.
Once compiled, you can tell Hyprland to load the plugin as described in the [Hyprland wiki](https://wiki.hyprland.org/Plugins/Using-Plugins/#installing--using-plugins).