initial
This commit is contained in:
commit
1210b5b7be
18 changed files with 1661 additions and 0 deletions
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
/result
|
||||||
|
/build
|
||||||
|
/.vscode
|
||||||
|
/.cache
|
||||||
|
*build*
|
||||||
|
*rel*
|
||||||
|
.idea
|
||||||
29
CMakeLists.txt
Normal file
29
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
cmake_minimum_required(VERSION 3.19)
|
||||||
|
project(Hycov VERSION "0.2")
|
||||||
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
|
add_compile_definitions(WLR_USE_UNSTABLE)
|
||||||
|
add_compile_options(-g -Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith)
|
||||||
|
|
||||||
|
# nix workaround
|
||||||
|
if(CMAKE_EXPORT_COMPILE_COMMANDS)
|
||||||
|
set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES
|
||||||
|
${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(DEPS REQUIRED hyprland pixman-1 libdrm pango pangocairo)
|
||||||
|
|
||||||
|
add_library(hycov SHARED
|
||||||
|
src/main.cpp
|
||||||
|
src/Plugin.cpp
|
||||||
|
src/OverviewManager.cpp
|
||||||
|
src/OverviewLayout.cpp
|
||||||
|
src/DwindleSwitcher.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(hycov PRIVATE ${DEPS_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
install(TARGETS hycov LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||||
|
|
||||||
|
# set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||||
|
# set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 GreamMaoMao
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
352
README.md
Normal file
352
README.md
Normal file
|
|
@ -0,0 +1,352 @@
|
||||||
|
# update info
|
||||||
|
|
||||||
|
**for hyprland v 0.4.0**
|
||||||
|
checkout to tag `v0.4.0`
|
||||||
|
|
||||||
|
**for hyprland v0.45.0**
|
||||||
|
checkout to tag `v0.45.0`
|
||||||
|
|
||||||
|
**for hyprland v0.45.2^**
|
||||||
|
in the `main` branch
|
||||||
|
|
||||||
|
no more than hyprland v0.46.1
|
||||||
|
|
||||||
|
# hycov
|
||||||
|
|
||||||
|
A Hyprland overview mode plugin, a new tiling WM workflow.
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> This repository only maintains the hyprland version corresponding to each hycov release, please do not bring up the issue of non-release versions, because I do not have enough time to track every commit.
|
||||||
|
|
||||||
|
### What can it do?
|
||||||
|
|
||||||
|
- Hycov can tile all of your windows in a single workspace via grid layout.
|
||||||
|
|
||||||
|
- After quitting the overview mode, hycov can perfectly recover a window's previous state (fullscreen, floating, size, positon, etc.)
|
||||||
|
|
||||||
|
- Hycov supports a variety of trigger methods, such as touch pad gestures, hot corners, and keyboard shortcuts.
|
||||||
|
|
||||||
|
- Supports multiple monitors.
|
||||||
|
|
||||||
|
- You can change the way that Hycov focuses a window, whether directional or cyclical. (single-shortcut)
|
||||||
|
|
||||||
|
https://github.com/DreamMaoMao/hycov/assets/30348075/59121362-21a8-4143-be95-72ce79ee8e95
|
||||||
|
|
||||||
|
Anyone is welcome to fork. If you end up improving the plugin, please let me know, and I'll be happy to use your fork.
|
||||||
|
|
||||||
|
### Manual Installation
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
>
|
||||||
|
> 1. After Hycov is installed, you will need to logout, then log back in. This may happen automatically, but do not worry. This behaviour is normal.
|
||||||
|
> 2. Only supports hyprland source code after 2023-10-22, because the plugin requires this [commit](https://github.com/hyprwm/Hyprland/commit/a61eb7694df25a75f45502ed64b1536fda370c1d) in [hyprland](https://github.com/hyprwm/Hyprland).
|
||||||
|
> 3. Each release of hycov corresponds to each release of hyprland. If you are using a release version of hycov, but you are using the latest hyprland-git, this may not be available.
|
||||||
|
|
||||||
|
##### Using meson and ninja:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git clone https://github.com/DreamMaoMao/hycov.git
|
||||||
|
cd hycov
|
||||||
|
sudo meson setup build --prefix=/usr
|
||||||
|
sudo ninja -C build
|
||||||
|
sudo ninja -C build install # `libhycov.so` path: /usr/lib/libhycov.so
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Using CMake:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git clone https://github.com/DreamMaoMao/hycov.git
|
||||||
|
cd hycov
|
||||||
|
bash install.sh # `libhycov.so` path: /usr/lib/libhycov.so
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Using hyprpm:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
hyprpm update
|
||||||
|
hyprpm add https://github.com/DreamMaoMao/hycov
|
||||||
|
hyprpm enable hycov
|
||||||
|
```
|
||||||
|
|
||||||
|
### Usage (hyprland.conf)
|
||||||
|
|
||||||
|
```conf
|
||||||
|
# When entering overview mode, you can use left-button to jump, right-button to kill or use keybind
|
||||||
|
|
||||||
|
# If you are installing hycov with hyprpm, you should comment out this
|
||||||
|
plugin = /usr/lib/libhycov.so
|
||||||
|
|
||||||
|
# If you are installing hycov by manually compile , you should comment out this
|
||||||
|
exec-once = hyprpm reload
|
||||||
|
|
||||||
|
# bind key to toggle overview (normal)
|
||||||
|
bind = ALT,tab,hycov:toggleoverview
|
||||||
|
|
||||||
|
# bind key to toggle overview (force mode, not affected by `only_active_workspace` or `only_active_monitor`)
|
||||||
|
bind = ALT,grave,hycov:toggleoverview,forceall #grave key is the '~' key
|
||||||
|
|
||||||
|
# bind key to toggle overview (force mode, not affected by `only_active_workspace` or `only_active_monitor`)
|
||||||
|
bind = ALT,c,hycov:toggleoverview,onlycurrentworkspace
|
||||||
|
|
||||||
|
# bind key to toggle overview (shows all windows in one monitor, not affected by `only_active_workspace` or `only_active_monitor`)
|
||||||
|
bind = ALT,g,hycov:toggleoverview,forceallinone
|
||||||
|
|
||||||
|
# The key binding for directional switch mode.
|
||||||
|
# Calculate the window closest to the direction to switch focus.
|
||||||
|
# This keybind is applicable not only to the overview, but also to the general layout.
|
||||||
|
bind=ALT,left,hycov:movefocus,l
|
||||||
|
bind=ALT,right,hycov:movefocus,r
|
||||||
|
bind=ALT,up,hycov:movefocus,u
|
||||||
|
bind=ALT,down,hycov:movefocus,d
|
||||||
|
|
||||||
|
# if you want that focusmove can cross monitor, use this
|
||||||
|
bind=ALT,left,hycov:movefocus,leftcross
|
||||||
|
bind=ALT,right,hycov:movefocus,rightcross
|
||||||
|
bind=ALT,up,hycov:movefocus,upcross
|
||||||
|
bind=ALT,down,hycov:movefocus,downcross
|
||||||
|
|
||||||
|
plugin {
|
||||||
|
hycov {
|
||||||
|
overview_gappo = 60 # gaps width from screen edge
|
||||||
|
overview_gappi = 24 # gaps width from clients
|
||||||
|
enable_hotarea = 1 # enable mouse cursor hotarea, when cursor enter hotarea, it will toggle overview
|
||||||
|
enable_click_action = 1 # enable mouse left button jump and right button kill in overview mode
|
||||||
|
hotarea_monitor = all # monitor name which hotarea is in, default is all
|
||||||
|
hotarea_pos = 1 # position of hotarea (1: bottom left, 2: bottom right, 3: top left, 4: top right)
|
||||||
|
hotarea_size = 10 # hotarea size, 10x10
|
||||||
|
swipe_fingers = 4 # finger number of gesture,move any directory
|
||||||
|
move_focus_distance = 100 # distance for movefocus,only can use 3 finger to move
|
||||||
|
enable_gesture = 0 # enable gesture
|
||||||
|
auto_exit = 1 # enable auto exit when no client in overview
|
||||||
|
auto_fullscreen = 0 # auto make active window maximize after exit overview
|
||||||
|
only_active_workspace = 0 # only overview the active workspace
|
||||||
|
only_active_monitor = 0 # only overview the active monitor
|
||||||
|
enable_alt_release_exit = 0 # alt swith mode arg,see readme for detail
|
||||||
|
alt_replace_key = Alt_L # alt swith mode arg,see readme for detail
|
||||||
|
alt_toggle_auto_next = 0 # auto focus next window when toggle overview in alt swith mode
|
||||||
|
click_in_cursor = 1 # when click to jump,the target windwo is find by cursor, not the current foucus window.
|
||||||
|
hight_of_titlebar = 0 # height deviation of title bar height
|
||||||
|
show_special = 0 # show windwos in special workspace in overview.
|
||||||
|
raise_float_to_top = 1 # raise the window that is floating before to top after leave overview mode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
# suggested additional configuration
|
||||||
|
|
||||||
|
- when `auto_fullscreen=1` is set, you can also set the border color to mark the maximize state and bind key to control fullscreen maximize state.
|
||||||
|
|
||||||
|
```
|
||||||
|
windowrulev2 = bordercolor rgb(158833),fullscreen:1 # set bordercolor to green if window is fullscreen maximize
|
||||||
|
# toggle fullscreen maximize
|
||||||
|
bind = ALT,a,fullscreen,1
|
||||||
|
```
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>detail video</summary>
|
||||||
|
|
||||||
|
https://github.com/DreamMaoMao/hycov/assets/30348075/15ba36c2-1782-4ae0-8ac1-d0ca98e01e0f
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
- if you use the `hyprland/workspaces` module in waybar,you should change field {id} to {name}. It will let you know you are in overview mode.
|
||||||
|
|
||||||
|
```
|
||||||
|
"hyprland/workspaces": {
|
||||||
|
"format": "{name}",
|
||||||
|
"on-click":"activate",
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>detail picture</summary>
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
# Alt switch mode
|
||||||
|
|
||||||
|
```conf
|
||||||
|
enable_alt_release_exit = 1
|
||||||
|
alt_toggle_auto_next = 0 # auto focus next window when enter overview in alt mode
|
||||||
|
# alt_replace_key = Alt_L # If your MainKey of toggleoverview is ALt, you can ignore it
|
||||||
|
```
|
||||||
|
|
||||||
|
## operation
|
||||||
|
|
||||||
|
such as `alt + tab`:
|
||||||
|
|
||||||
|
- 1.`alt + tab` will enter overview when you not in overview(please hold alt,don't make it release)
|
||||||
|
|
||||||
|
- 2.`alt + tab` will switch window focus circularly when you in overview. (please hold alt,don't make it release)
|
||||||
|
|
||||||
|
- 3.when you release `alt` , it will auto exit overview.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary> If you don't want to use `alt` as MainKey in alt mode</summary>
|
||||||
|
|
||||||
|
such as use `super` to repalce `alt`
|
||||||
|
|
||||||
|
- 1.bind toggleoverview
|
||||||
|
|
||||||
|
```
|
||||||
|
bind = SUPER,tab,hycov:toggleoverview
|
||||||
|
```
|
||||||
|
|
||||||
|
- 2.use `alt_replace_key` to specify what is the detection key on release.
|
||||||
|
|
||||||
|
```
|
||||||
|
# use keyname
|
||||||
|
alt_replace_key = Super_L # Alt_L,Alt_R,Super_L,Super_R,Control_L,Control_R,Shift_L,Shift_R
|
||||||
|
|
||||||
|
# use keycode
|
||||||
|
alt_replace_key = code:133 # use `xev` command to get keycode
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### NixOS with home—manager
|
||||||
|
|
||||||
|
```nix
|
||||||
|
# flake.nix
|
||||||
|
|
||||||
|
{
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
|
||||||
|
home-manager = {
|
||||||
|
url = "github:nix-community/home-manager";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
|
||||||
|
hyprland.url = "github:hyprwm/Hyprland";
|
||||||
|
|
||||||
|
hycov={
|
||||||
|
url = "github:DreamMaoMao/hycov";
|
||||||
|
inputs.hyprland.follows = "hyprland";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { nixpkgs, home-manager, hyprland, hycov, ... }:
|
||||||
|
let
|
||||||
|
system = "x86_64-linux";
|
||||||
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
homeConfigurations."user@hostname" = home-manager.lib.homeManagerConfiguration {
|
||||||
|
pkgs = nixpkgs.legacyPackages.x86_64-linux;
|
||||||
|
|
||||||
|
modules = [
|
||||||
|
hyprland.homeManagerModules.default
|
||||||
|
{
|
||||||
|
wayland.windowManager.hyprland = {
|
||||||
|
enable = true;
|
||||||
|
package = hyprland.packages."${pkgs.system}".hyprland;
|
||||||
|
plugins = [
|
||||||
|
hycov.packages.${pkgs.system}.hycov
|
||||||
|
];
|
||||||
|
extraConfig = ''
|
||||||
|
bind = ALT,tab,hycov:toggleoverview
|
||||||
|
bind=ALT,left,hycov:movefocus,l
|
||||||
|
bind=ALT,right,hycov:movefocus,r
|
||||||
|
bind=ALT,up,hycov:movefocus,u
|
||||||
|
bind=ALT,down,hycov:movefocus,d
|
||||||
|
|
||||||
|
plugin {
|
||||||
|
hycov {
|
||||||
|
overview_gappo = 60 #gaps width from screen
|
||||||
|
overview_gappi = 24 #gaps width from clients
|
||||||
|
hotarea_size = 10 #hotarea size in bottom left,10x10
|
||||||
|
enable_hotarea = 1 # enable mouse cursor hotarea
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'' + ''
|
||||||
|
# your othor config
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
# ...
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Frequently Asked Questions
|
||||||
|
|
||||||
|
- some config not work, or the plugin not work.
|
||||||
|
|
||||||
|
```
|
||||||
|
if you use install hycov at first time,please try logout and relogin again.
|
||||||
|
```
|
||||||
|
|
||||||
|
- The numbers on the waybar are confused
|
||||||
|
|
||||||
|
```
|
||||||
|
1.Please pull the latest waybar source code compilation,
|
||||||
|
this issue has been fixed in the waybar project, fix date (2023-10-27)
|
||||||
|
|
||||||
|
2.Change the {id} field in hyprland/workspace field to {name}
|
||||||
|
```
|
||||||
|
|
||||||
|
- Compilation failure
|
||||||
|
|
||||||
|
```
|
||||||
|
Please pull the latest hyprland source code to compile and install.
|
||||||
|
The plugin relies on a hyprland pr,pr submission date (2023-10-21)
|
||||||
|
```
|
||||||
|
|
||||||
|
- Unable to load
|
||||||
|
|
||||||
|
```
|
||||||
|
Check whether hyprland has been updated,
|
||||||
|
and if so, please recompile hyprcov
|
||||||
|
```
|
||||||
|
|
||||||
|
- build fail with message `No such file or directory #include <wlr/xxx>`
|
||||||
|
|
||||||
|
```
|
||||||
|
#step1
|
||||||
|
yay -R hyprland-git wlroots-git
|
||||||
|
|
||||||
|
#step2
|
||||||
|
sudo rm -rf /usr/include/hyprland
|
||||||
|
sudo rm -rf /usr/include/wlr
|
||||||
|
sudo rm -rf/usr/local/include/hyprland
|
||||||
|
sudo rm -rf /usr/local/include/wlr
|
||||||
|
|
||||||
|
#step3
|
||||||
|
yay -S wlroots-git hyprland-git
|
||||||
|
```
|
||||||
|
|
||||||
|
## Some cool use cases
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary> hycov + [hyprland-easymotion](https://github.com/zakk4223/hyprland-easymotion) </summary>
|
||||||
|
|
||||||
|
https://github.com/DreamMaoMao/hycov/assets/30348075/486b08f1-be0d-4647-90a3-2029961402cd
|
||||||
|
|
||||||
|
```conf
|
||||||
|
bind = ALT,tab, exec, ~/.config/hypr/scripts/hycov-easymotion.sh
|
||||||
|
submap=__easymotionsubmap__
|
||||||
|
bind = ALT, Tab, exec, ~/.config/hypr/scripts/hycov-easymotion.sh
|
||||||
|
submap=reset
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
workspace_name=$(hyprctl -j activeworkspace | jq -r '.name')
|
||||||
|
|
||||||
|
if [ "$workspace_name" = "OVERVIEW" ]; then
|
||||||
|
hyprctl dispatch hycov:leaveoverview
|
||||||
|
else
|
||||||
|
hyprctl dispatch hycov:enteroverview
|
||||||
|
hyprctl dispatch 'easymotion action:hyprctl --batch "dispatch focuswindow address:{} ; dispatch hycov:leaveoverview"'
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
20
default.nix
Normal file
20
default.nix
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
{ lib
|
||||||
|
, stdenv
|
||||||
|
, hyprland
|
||||||
|
}:
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
pname = "hycov";
|
||||||
|
version = "0.2";
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
inherit (hyprland) nativeBuildInputs;
|
||||||
|
|
||||||
|
buildInputs = [ hyprland ] ++ hyprland.buildInputs;
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
homepage = "https://github.com/DreamMaoMao/hycov";
|
||||||
|
description = "clients overview for hyprland plugin";
|
||||||
|
license = licenses.mit;
|
||||||
|
platforms = platforms.linux;
|
||||||
|
};
|
||||||
|
}
|
||||||
424
flake.lock
generated
Normal file
424
flake.lock
generated
Normal file
|
|
@ -0,0 +1,424 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"aquamarine": {
|
||||||
|
"inputs": {
|
||||||
|
"hyprutils": [
|
||||||
|
"hyprland",
|
||||||
|
"hyprutils"
|
||||||
|
],
|
||||||
|
"hyprwayland-scanner": [
|
||||||
|
"hyprland",
|
||||||
|
"hyprwayland-scanner"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"hyprland",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"hyprland",
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1734906446,
|
||||||
|
"narHash": "sha256-6OWluVE2A8xi+8V3jN9KA72RCgJjYdyyuLBUjxZ2q2U=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "aquamarine",
|
||||||
|
"rev": "eecb74dc79bb6752a2a507e6edee3042390a6091",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "aquamarine",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-compat": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1696426674,
|
||||||
|
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"gitignore": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"hyprland",
|
||||||
|
"pre-commit-hooks",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1709087332,
|
||||||
|
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "gitignore.nix",
|
||||||
|
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "gitignore.nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hyprcursor": {
|
||||||
|
"inputs": {
|
||||||
|
"hyprlang": [
|
||||||
|
"hyprland",
|
||||||
|
"hyprlang"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"hyprland",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"hyprland",
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1734906540,
|
||||||
|
"narHash": "sha256-vQ/L9hZFezC0LquLo4TWXkyniWtYBlFHAKIsDc7PYJE=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprcursor",
|
||||||
|
"rev": "69270ba8f057d55b0e6c2dca0e165d652856e613",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprcursor",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hyprgraphics": {
|
||||||
|
"inputs": {
|
||||||
|
"hyprutils": [
|
||||||
|
"hyprland",
|
||||||
|
"hyprutils"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"hyprland",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"hyprland",
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1734906236,
|
||||||
|
"narHash": "sha256-vH/ysV2ONGQgYZPtcJKwc8jJivzyVxru2aaOxC20ZOE=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprgraphics",
|
||||||
|
"rev": "6dea3fba08fd704dd624b6d4b261638fb4003c9c",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprgraphics",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hyprland": {
|
||||||
|
"inputs": {
|
||||||
|
"aquamarine": "aquamarine",
|
||||||
|
"hyprcursor": "hyprcursor",
|
||||||
|
"hyprgraphics": "hyprgraphics",
|
||||||
|
"hyprland-protocols": "hyprland-protocols",
|
||||||
|
"hyprland-qtutils": "hyprland-qtutils",
|
||||||
|
"hyprlang": "hyprlang",
|
||||||
|
"hyprutils": "hyprutils",
|
||||||
|
"hyprwayland-scanner": "hyprwayland-scanner",
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"pre-commit-hooks": "pre-commit-hooks",
|
||||||
|
"systems": "systems",
|
||||||
|
"xdph": "xdph"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1735585949,
|
||||||
|
"narHash": "sha256-vCGG4tGMvzCzz+ZIsiNtpoFW9+f+itYLTAVW41qk/Hk=",
|
||||||
|
"ref": "refs/heads/main",
|
||||||
|
"rev": "1989b0049f7fb714a2417dfb14d6b4f3d2a079d3",
|
||||||
|
"revCount": 5607,
|
||||||
|
"submodules": true,
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/hyprwm/Hyprland"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"submodules": true,
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/hyprwm/Hyprland"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hyprland-protocols": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"hyprland",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"hyprland",
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1728345020,
|
||||||
|
"narHash": "sha256-xGbkc7U/Roe0/Cv3iKlzijIaFBNguasI31ynL2IlEoM=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprland-protocols",
|
||||||
|
"rev": "a7c183800e74f337753de186522b9017a07a8cee",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprland-protocols",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hyprland-qtutils": {
|
||||||
|
"inputs": {
|
||||||
|
"hyprutils": [
|
||||||
|
"hyprland",
|
||||||
|
"hyprutils"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"hyprland",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"hyprland",
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1734906472,
|
||||||
|
"narHash": "sha256-pWPRv/GA/X/iAwoE6gMNUqn/ZeJX1IeLPRpZI0tTPK0=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprland-qtutils",
|
||||||
|
"rev": "c77109d7e1ddbcdb87cafd32ce411f76328ae152",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprland-qtutils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hyprlang": {
|
||||||
|
"inputs": {
|
||||||
|
"hyprutils": [
|
||||||
|
"hyprland",
|
||||||
|
"hyprutils"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"hyprland",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"hyprland",
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1734906259,
|
||||||
|
"narHash": "sha256-P79t/7HbACO4/PuJBroGpTptvCWJtXTv+gWsF+sM6MI=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprlang",
|
||||||
|
"rev": "0404833ea18d543df44df935ebf1b497310eb046",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprlang",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hyprutils": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"hyprland",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"hyprland",
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1735316583,
|
||||||
|
"narHash": "sha256-AiiUwHWHfEdpFzXy7l1x3zInCUa1xcRMrbZ1XRSkzwU=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprutils",
|
||||||
|
"rev": "8f15d45b120b33712f6db477fe5ffb18034d0ea8",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprutils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hyprwayland-scanner": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"hyprland",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"hyprland",
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1734793513,
|
||||||
|
"narHash": "sha256-rrrHcXapXJvGFqX+L/Bb0182L25jofAZ0fm1FInvrTQ=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprwayland-scanner",
|
||||||
|
"rev": "4d7367b6eee87397e2dbca2e78078dd0a4ef4c61",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprwayland-scanner",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1735291276,
|
||||||
|
"narHash": "sha256-NYVcA06+blsLG6wpAbSPTCyLvxD/92Hy4vlY9WxFI1M=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "634fd46801442d760e09493a794c4f15db2d0cbb",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-stable": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1730741070,
|
||||||
|
"narHash": "sha256-edm8WG19kWozJ/GqyYx2VjW99EdhjKwbY3ZwdlPAAlo=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "d063c1dd113c91ab27959ba540c0d9753409edf3",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-24.05",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pre-commit-hooks": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
|
"gitignore": "gitignore",
|
||||||
|
"nixpkgs": [
|
||||||
|
"hyprland",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"nixpkgs-stable": "nixpkgs-stable"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1734797603,
|
||||||
|
"narHash": "sha256-ulZN7ps8nBV31SE+dwkDvKIzvN6hroRY8sYOT0w+E28=",
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "git-hooks.nix",
|
||||||
|
"rev": "f0f0dc4920a903c3e08f5bdb9246bb572fcae498",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "git-hooks.nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"hyprland": "hyprland",
|
||||||
|
"nixpkgs": [
|
||||||
|
"hyprland",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"hyprland",
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1689347949,
|
||||||
|
"narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default-linux",
|
||||||
|
"rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default-linux",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"xdph": {
|
||||||
|
"inputs": {
|
||||||
|
"hyprland-protocols": [
|
||||||
|
"hyprland",
|
||||||
|
"hyprland-protocols"
|
||||||
|
],
|
||||||
|
"hyprlang": [
|
||||||
|
"hyprland",
|
||||||
|
"hyprlang"
|
||||||
|
],
|
||||||
|
"hyprutils": [
|
||||||
|
"hyprland",
|
||||||
|
"hyprutils"
|
||||||
|
],
|
||||||
|
"hyprwayland-scanner": [
|
||||||
|
"hyprland",
|
||||||
|
"hyprwayland-scanner"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"hyprland",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"hyprland",
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1734907020,
|
||||||
|
"narHash": "sha256-p6HxwpRKVl1KIiY5xrJdjcEeK3pbmc///UOyV6QER+w=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "xdg-desktop-portal-hyprland",
|
||||||
|
"rev": "d7f18dda5e511749fa1511185db3536208fb1a63",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "xdg-desktop-portal-hyprland",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
55
flake.nix
Normal file
55
flake.nix
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
{
|
||||||
|
description = "Hyprland Plugins (Hycov)";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
hyprland.url = "git+https://github.com/hyprwm/Hyprland?submodules=1";
|
||||||
|
nixpkgs.follows = "hyprland/nixpkgs";
|
||||||
|
systems.follows = "hyprland/systems";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs =
|
||||||
|
{ self
|
||||||
|
, hyprland
|
||||||
|
, nixpkgs
|
||||||
|
, systems
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (nixpkgs) lib;
|
||||||
|
withPkgsFor = fn: lib.genAttrs (import systems) (system:
|
||||||
|
let
|
||||||
|
pkgs = import nixpkgs {
|
||||||
|
localSystem.system = system;
|
||||||
|
overlays = [
|
||||||
|
hyprland.overlays.hyprland-packages
|
||||||
|
self.overlays.default
|
||||||
|
];
|
||||||
|
};
|
||||||
|
in
|
||||||
|
fn system pkgs);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
overlays = {
|
||||||
|
default = self.overlays.hycov;
|
||||||
|
hycov = final: prev: {
|
||||||
|
hyprlandPlugins = prev.hyprlandPlugins or {} // {
|
||||||
|
hycov = final.callPackage ./default.nix {
|
||||||
|
stdenv = final.gcc14Stdenv;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
packages = withPkgsFor (system: pkgs: {
|
||||||
|
default = self.packages.${system}.hycov;
|
||||||
|
inherit (pkgs.hyprlandPlugins) hycov;
|
||||||
|
});
|
||||||
|
|
||||||
|
devShells = withPkgsFor (system: pkgs: {
|
||||||
|
default = pkgs.mkShell.override { stdenv = pkgs.gcc14Stdenv; } {
|
||||||
|
name = "hyprland-plugins";
|
||||||
|
# buildInputs = [ pkgs.hyprland ];
|
||||||
|
inputsFrom = [ pkgs.hycov ];
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
26
hyprpm.toml
Normal file
26
hyprpm.toml
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
[repository]
|
||||||
|
name = "hycov"
|
||||||
|
authors = ["DreamMaoMao"]
|
||||||
|
commit_pins = [
|
||||||
|
["03ebbe18ed8517ee22591eac82cd54322f42cb7d", "b14e35d8c08ca2e946b7249f9024c2b1787398e6"],
|
||||||
|
["cbadf3e3f31ab5ad5d192daac5f2ca930d08b8fb", "c5c314d2e4ca44011cc9f64f13ff9071eda751dd"],
|
||||||
|
["84ab8d11e8951a6551d1e1bf87796a8589da6d47", "06c3ec69171e1937a889bc20b84bbc33a70b4400"],
|
||||||
|
["13f6f0b923ff3ec94a3bec886c28b90402ceef91", "2c88820384c78b13ce92ef61fa0822369c9c6ecf"],
|
||||||
|
["1c460e98f870676b15871fe4e5bfeb1a32a3d6d8", "7d48cff8364a7b6ae52a3472ad1dfe01b9f728ae"],
|
||||||
|
["e93fbd7c4f991cb8ef03e433ccc4d43587923e15", "05fb15703d07a372b14a3260a337de13d1c16b91"],
|
||||||
|
["fe7b748eb668136dd0558b7c8279bfcd7ab4d759", "05fb15703d07a372b14a3260a337de13d1c16b91"],
|
||||||
|
["cba1ade848feac44b2eda677503900639581c3f4", "89fc3dc62d4aca3745d2b1aa6ab81dab541c232c"],
|
||||||
|
["ea2501d4556f84d3de86a4ae2f4b22a474555b9f", "7b1f51d005c5f477c763f1031b807787f2f6b449"],
|
||||||
|
["9e781040d9067c2711ec2e9f5b47b76ef70762b3","a1c4287c2ebb5f5596dc53571993725be9d63cb0"],
|
||||||
|
["918d8340afd652b011b937d29d5eea0be08467f5","a1c4287c2ebb5f5596dc53571993725be9d63cb0"]
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[hycov]
|
||||||
|
description = "hyprland overview mode"
|
||||||
|
authors = ["DreamMaoMao"]
|
||||||
|
output = "build/libhycov.so"
|
||||||
|
build = [
|
||||||
|
"cmake -DCMAKE_BUILD_TYPE=Release -B build",
|
||||||
|
"cmake --build build -j $(nproc)"
|
||||||
|
]
|
||||||
5
install.sh
Normal file
5
install.sh
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
sudo rm build/* -rf
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=Debug -B build
|
||||||
|
cmake --build build -j $(nproc)
|
||||||
|
sudo cp build/libhycov.so /usr/lib
|
||||||
|
|
||||||
171
src/DwindleSwitcher.cpp
Normal file
171
src/DwindleSwitcher.cpp
Normal file
|
|
@ -0,0 +1,171 @@
|
||||||
|
|
||||||
|
#include "DwindleSwitcher.hpp"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#define private public
|
||||||
|
#include "src/managers/LayoutManager.hpp"
|
||||||
|
#undef private
|
||||||
|
|
||||||
|
#include "src/Compositor.hpp"
|
||||||
|
#include "src/helpers/Monitor.hpp"
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
struct DwindleSwitcher::PrivateContext {
|
||||||
|
struct AdditionalState {
|
||||||
|
bool fullscreen = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
CHyprDwindleLayout* layout = nullptr;
|
||||||
|
std::map<PHLWINDOW, AdditionalState> additional;
|
||||||
|
std::list<SDwindleNodeData> dwindleNodes;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool canRestore(std::list<SDwindleNodeData>& target, std::list<SDwindleNodeData>& backup);
|
||||||
|
auto findNodePointerByData(std::list<SDwindleNodeData>& nodes, SDwindleNodeData *node) -> SDwindleNodeData *;
|
||||||
|
void remapPointers(std::list<SDwindleNodeData>& source, std::list<SDwindleNodeData>& target);
|
||||||
|
|
||||||
|
|
||||||
|
std::string DwindleSwitcher::getName() const { return "dwindle"; }
|
||||||
|
|
||||||
|
DwindleSwitcher::DwindleSwitcher() {
|
||||||
|
context = new PrivateContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
DwindleSwitcher::~DwindleSwitcher() {
|
||||||
|
delete context;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DwindleSwitcher::onEnterOverviewBefore() {
|
||||||
|
context->layout = dynamic_cast<CHyprDwindleLayout*>(g_pLayoutManager->getCurrentLayout());
|
||||||
|
if (!context->layout) return;
|
||||||
|
remapPointers(context->layout->m_dwindleNodesData, context->dwindleNodes);
|
||||||
|
|
||||||
|
for (const auto& window : g_pCompositor->m_windows) {
|
||||||
|
context->additional[window] = {};
|
||||||
|
if (window->isFullscreen()) {
|
||||||
|
context->additional[window].fullscreen = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LayoutSwitcher::onEnterOverviewBefore();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DwindleSwitcher::onEnterOverviewAfter() {}
|
||||||
|
|
||||||
|
void DwindleSwitcher::onLeaveOverviewBefore() {}
|
||||||
|
|
||||||
|
void DwindleSwitcher::onLeaveOverviewAfter() {
|
||||||
|
if (!context->layout) return;
|
||||||
|
|
||||||
|
if (canRestore(context->layout->m_dwindleNodesData, context->dwindleNodes)) {
|
||||||
|
remapPointers(context->dwindleNodes, context->layout->m_dwindleNodesData);
|
||||||
|
|
||||||
|
for (auto& node : context->layout->m_dwindleNodesData) {
|
||||||
|
context->layout->applyNodeDataToWindow(&node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& [window, data] : context->additional) {
|
||||||
|
if (!window)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (data.fullscreen) {
|
||||||
|
// if selected window is in the same workspace as fullscreen window then don't restore fullscreen
|
||||||
|
if (g_pCompositor->m_lastWindow != window) {
|
||||||
|
if (g_pCompositor->m_lastWindow->m_workspace == window->m_workspace) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_pCompositor->setWindowFullscreenState(window, {FSMODE_FULLSCREEN, FSMODE_FULLSCREEN});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context->layout = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool canRestore(std::list<SDwindleNodeData>& target, std::list<SDwindleNodeData>& backup) {
|
||||||
|
|
||||||
|
std::set<long> rootsTarget;
|
||||||
|
std::set<long> rootsBackup;
|
||||||
|
|
||||||
|
std::set<PHLWINDOW> windowsTarget;
|
||||||
|
std::set<PHLWINDOW> windowsBackup;
|
||||||
|
|
||||||
|
for (auto& node : backup) {
|
||||||
|
if (!node.isNode) {
|
||||||
|
if (node.pWindow.expired())
|
||||||
|
return false;
|
||||||
|
windowsBackup.insert(node.pWindow.lock());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node.pParent)
|
||||||
|
rootsBackup.insert(node.workspaceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& node : target) {
|
||||||
|
if (!node.isNode) {
|
||||||
|
windowsTarget.insert(node.pWindow.lock());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node.pParent)
|
||||||
|
rootsTarget.insert(node.workspaceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rootsBackup != rootsTarget) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return windowsTarget == windowsBackup;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto findNodePointerByData(std::list<SDwindleNodeData>& nodes, SDwindleNodeData *node) -> SDwindleNodeData * {
|
||||||
|
for (auto &iter : nodes) {
|
||||||
|
if (iter.pWindow) {
|
||||||
|
if (node->pWindow == iter.pWindow) {
|
||||||
|
return &iter;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (node->children == iter.children) {
|
||||||
|
return &iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void remapPointers(std::list<SDwindleNodeData>& source, std::list<SDwindleNodeData>& target) {
|
||||||
|
target.clear();
|
||||||
|
for (auto node : source) {
|
||||||
|
target.push_back(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<SDwindleNodeData*, SDwindleNodeData*> targetToSourceMap;
|
||||||
|
|
||||||
|
for (auto& node : target) {
|
||||||
|
if (node.pParent) {
|
||||||
|
targetToSourceMap[node.pParent] = findNodePointerByData(target, node.pParent);
|
||||||
|
}
|
||||||
|
if (node.children[0]) {
|
||||||
|
targetToSourceMap[node.children[0]] = findNodePointerByData(target, node.children[0]);
|
||||||
|
}
|
||||||
|
if (node.children[1]) {
|
||||||
|
targetToSourceMap[node.children[1]] = findNodePointerByData(target, node.children[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& node : target) {
|
||||||
|
if (node.pParent) {
|
||||||
|
node.pParent = targetToSourceMap[node.pParent];
|
||||||
|
}
|
||||||
|
if (node.children[0]) {
|
||||||
|
node.children[0] = targetToSourceMap[node.children[0]];
|
||||||
|
}
|
||||||
|
if (node.children[1]) {
|
||||||
|
node.children[1] = targetToSourceMap[node.children[1]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!std::any_of(targetToSourceMap.begin(), targetToSourceMap.end(), [](auto& pair){ return !pair.second;}));
|
||||||
|
}
|
||||||
23
src/DwindleSwitcher.hpp
Normal file
23
src/DwindleSwitcher.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "OverviewManager.hpp"
|
||||||
|
|
||||||
|
struct DwindleSwitcher : public LayoutSwitcher {
|
||||||
|
public:
|
||||||
|
struct PrivateContext;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DwindleSwitcher();
|
||||||
|
~DwindleSwitcher();
|
||||||
|
|
||||||
|
[[nodiscard]] std::string getName() const;
|
||||||
|
|
||||||
|
void onEnterOverviewBefore() override;
|
||||||
|
void onEnterOverviewAfter() override;
|
||||||
|
|
||||||
|
void onLeaveOverviewBefore() override;
|
||||||
|
void onLeaveOverviewAfter() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
PrivateContext* context = nullptr;
|
||||||
|
};
|
||||||
245
src/OverviewLayout.cpp
Normal file
245
src/OverviewLayout.cpp
Normal file
|
|
@ -0,0 +1,245 @@
|
||||||
|
|
||||||
|
#include "OverviewLayout.hpp"
|
||||||
|
|
||||||
|
#include "src/desktop/Workspace.hpp"
|
||||||
|
#include "src/helpers/Monitor.hpp"
|
||||||
|
#include "src/managers/LayoutManager.hpp"
|
||||||
|
#include "src/render/Renderer.hpp"
|
||||||
|
#include "src/Compositor.hpp"
|
||||||
|
|
||||||
|
std::string OverviewLayout::getLayoutName() { return "grid"; }
|
||||||
|
|
||||||
|
OverviewLayout::OverviewWindowNode::OverviewWindowNode(PHLWINDOW window_) {
|
||||||
|
window = std::move(window_);
|
||||||
|
savedState.monitorId = window->monitorID();
|
||||||
|
savedState.workspaceId = window->workspaceID();
|
||||||
|
savedState.workspaceName = g_pCompositor->getWorkspaceByID(savedState.workspaceId)->m_name;
|
||||||
|
|
||||||
|
savedState.pos = window->m_position;
|
||||||
|
savedState.size = window->m_size;
|
||||||
|
savedState.ratio = (float) (savedState.size.y / savedState.size.x);
|
||||||
|
|
||||||
|
savedState.posReal = window->m_realPosition->goal();
|
||||||
|
savedState.sizeReal = window->m_realSize->goal();
|
||||||
|
|
||||||
|
savedState.floating = window->m_isFloating;
|
||||||
|
|
||||||
|
if (!savedState.size.x || !savedState.size.y) {
|
||||||
|
savedState.size = savedState.sizeReal;
|
||||||
|
savedState.size.clamp({10, 10});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OverviewLayout::OverviewLayout(OverviewManager* overviewManager) {
|
||||||
|
mOverviewManager = overviewManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverviewLayout::onEnable() {
|
||||||
|
for (auto &window: g_pCompositor->m_windows) {
|
||||||
|
if (!window->m_isMapped || window->isHidden())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (window->m_workspace->m_isSpecialWorkspace) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
onWindowCreatedTiling(window, DIRECTION_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateWorkspaces();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverviewLayout::updateWorkspaces() {
|
||||||
|
std::map<PHLMONITOR, std::set<PHLWORKSPACE>> activeMonitorMap;
|
||||||
|
|
||||||
|
for (auto& node : m_windowNodes) {
|
||||||
|
if (!node.second.window->m_workspace->m_isSpecialWorkspace) {
|
||||||
|
activeMonitorMap[node.second.window->m_monitor.lock()].insert(node.second.window->m_workspace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto underCursorWorkspace = g_pCompositor->getMonitorFromCursor()->m_activeWorkspace;
|
||||||
|
for (auto& monitor : activeMonitorMap) {
|
||||||
|
if (monitor.second.contains(underCursorWorkspace)) {
|
||||||
|
monitor.first->changeWorkspace(underCursorWorkspace);
|
||||||
|
} else {
|
||||||
|
monitor.first->changeWorkspace(*monitor.second.begin());
|
||||||
|
}
|
||||||
|
monitor.first->setSpecialWorkspace(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& node : m_windowNodes) {
|
||||||
|
auto monitor = node.second.window->m_monitor;
|
||||||
|
auto workspace = monitor->m_activeWorkspace;
|
||||||
|
|
||||||
|
node.second.window->m_workspace = workspace;
|
||||||
|
node.second.window->m_monitor = monitor;
|
||||||
|
node.second.window->m_isFloating = false; // this it needed to disable minSize clamping
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverviewLayout::onDisable() {
|
||||||
|
|
||||||
|
for (auto& [window, node] : m_windowNodes) {
|
||||||
|
auto monitor = g_pCompositor->getMonitorFromID(node.savedState.monitorId);
|
||||||
|
auto workspace = g_pCompositor->getWorkspaceByID(node.savedState.workspaceId);
|
||||||
|
|
||||||
|
if (!workspace) {
|
||||||
|
workspace = g_pCompositor->createNewWorkspace(node.savedState.workspaceId, node.savedState.monitorId, node.savedState.workspaceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
window->m_workspace = workspace;
|
||||||
|
window->m_monitor = monitor;
|
||||||
|
|
||||||
|
window->m_position = node.savedState.pos;
|
||||||
|
window->m_size = node.savedState.size;
|
||||||
|
|
||||||
|
*window->m_realPosition = node.savedState.posReal;
|
||||||
|
*window->m_realSize = node.savedState.sizeReal;
|
||||||
|
|
||||||
|
window->m_isFloating = node.savedState.floating;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_windowNodes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverviewLayout::onWindowRemoved(PHLWINDOW pWindow) {
|
||||||
|
onWindowRemovedTiling(pWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverviewLayout::onWindowRemovedTiling(PHLWINDOW pWindow) {
|
||||||
|
m_windowNodes.erase(pWindow.get());
|
||||||
|
updateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverviewLayout::updateLayout() {
|
||||||
|
for (auto &monitor: g_pCompositor->m_monitors) {
|
||||||
|
recalculateMonitor(monitor->m_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverviewLayout::onWindowCreatedTiling(PHLWINDOW window, eDirection direction) {
|
||||||
|
if (m_windowNodes.contains(window.get())) return;
|
||||||
|
|
||||||
|
auto newNode = OverviewWindowNode(window);
|
||||||
|
m_windowNodes.insert({ window.get(), newNode });
|
||||||
|
|
||||||
|
updateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverviewLayout::recalculateMonitor(const MONITORID &monitorId) {
|
||||||
|
auto monitor = g_pCompositor->getMonitorFromID(monitorId);
|
||||||
|
|
||||||
|
if (!monitor || !monitor->m_activeWorkspace) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<OverviewWindowNode*> nodes;
|
||||||
|
for (auto& node : m_windowNodes) {
|
||||||
|
if (node.second.window->monitorID() == monitorId) {
|
||||||
|
nodes.push_back(&node.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateOverviewGrid(nodes, g_pCompositor->getWorkspaceByID(monitor->activeWorkspaceID()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverviewLayout::calculateOverviewGrid(const std::vector<OverviewWindowNode*>& windows, const PHLWORKSPACE& workspace) const {
|
||||||
|
if (windows.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto monitor = g_pCompositor->getMonitorFromID(workspace->m_monitor->m_id);
|
||||||
|
|
||||||
|
auto monitorX = (int) (monitor->m_position.x + monitor->m_reservedTopLeft.x);
|
||||||
|
auto monitorY = (int) (monitor->m_position.y + monitor->m_reservedTopLeft.y);
|
||||||
|
auto monitorW = (int) (monitor->m_size.x - monitor->m_reservedTopLeft.x);
|
||||||
|
auto monitorH = (int) (monitor->m_size.y - monitor->m_reservedTopLeft.y);
|
||||||
|
|
||||||
|
auto numNodes = (int) windows.size();
|
||||||
|
|
||||||
|
// Calculate the integer part of the square root of the number of nodes
|
||||||
|
int columns = 0;
|
||||||
|
while (columns <= numNodes / 2) {
|
||||||
|
if (columns * columns >= numNodes) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
columns++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The number of rows and columns multiplied by the number of nodes must be greater than the number of nodes to fit all the Windows
|
||||||
|
int rows = (columns && (columns - 1) * columns >= numNodes) ? columns - 1 : columns;
|
||||||
|
|
||||||
|
// If the nodes do not exactly fill all rows, the number of Windows in the unfilled rows is
|
||||||
|
int numLeftOvers = numNodes % columns;
|
||||||
|
|
||||||
|
// Calculate the width and height of the layout area based on the number of rows and columns
|
||||||
|
int height = (int) ((monitorH - 2 * (gapOut) - (rows - 1) * (gapIn)) / rows);
|
||||||
|
int width = (int) ((monitorW - 2 * (gapOut) - (columns - 1) * (gapIn)) / columns);
|
||||||
|
|
||||||
|
int leftOversOffsetX = 0;
|
||||||
|
if (numLeftOvers) {
|
||||||
|
leftOversOffsetX = (monitorW - numLeftOvers * width - (numLeftOvers - 1) * gapIn) / 2 - gapOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < numNodes; i++) {
|
||||||
|
auto node = windows[i];
|
||||||
|
|
||||||
|
int posX = monitorX + (i % columns) * (width + gapIn) + gapOut;
|
||||||
|
int posY = monitorY + (int) (i / columns) * (height + gapIn) + gapOut;
|
||||||
|
|
||||||
|
if (i >= numNodes - numLeftOvers) {
|
||||||
|
posX += leftOversOffsetX;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cellPos = Vector2D(posX + border, posY + border);
|
||||||
|
auto cellSize = Vector2D(width - border * 2, height - border * 2);
|
||||||
|
|
||||||
|
auto windowPos = cellPos;
|
||||||
|
auto windowSize = cellSize;
|
||||||
|
|
||||||
|
if (1) {
|
||||||
|
if (cellSize.x > node->savedState.size.x && cellSize.y > node->savedState.size.y) {
|
||||||
|
windowPos = cellPos + (cellSize / 2) - (node->savedState.size / 2);
|
||||||
|
windowSize = node->savedState.size;
|
||||||
|
} else {
|
||||||
|
// apply ratio scaling
|
||||||
|
auto cellRatio = (float) (cellSize.y / cellSize.x);
|
||||||
|
if (cellRatio < node->savedState.ratio) {
|
||||||
|
windowSize.x = cellSize.y / node->savedState.ratio;
|
||||||
|
windowPos.x += (cellSize.x - windowSize.x) / 2;
|
||||||
|
} else if (cellRatio > node->savedState.ratio) {
|
||||||
|
windowSize.y = cellSize.x * node->savedState.ratio;
|
||||||
|
windowPos.y += (cellSize.y - windowSize.y) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node->window->m_position = windowPos;
|
||||||
|
*node->window->m_realPosition = windowPos;
|
||||||
|
node->window->m_size = windowSize;
|
||||||
|
*node->window->m_realSize = windowSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PHLWINDOW OverviewLayout::getNextWindowCandidate(PHLWINDOW) {
|
||||||
|
if (!m_windowNodes.empty())
|
||||||
|
return m_windowNodes.begin()->second.window;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverviewLayout::onBeginDragWindow() {
|
||||||
|
mOverviewManager->leaveOverview();
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2D OverviewLayout::predictSizeForNewWindowTiled() { return {}; }
|
||||||
|
bool OverviewLayout::isWindowTiled(PHLWINDOW pWindow) { return true; }
|
||||||
|
void OverviewLayout::recalculateWindow(PHLWINDOW pWindow) {}
|
||||||
|
void OverviewLayout::resizeActiveWindow(const Vector2D &pixResize, eRectCorner corner, PHLWINDOW pWindow) {}
|
||||||
|
void OverviewLayout::fullscreenRequestForWindow( PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE) {}
|
||||||
|
std::any OverviewLayout::layoutMessage(SLayoutMessageHeader header, std::string content) { return ""; }
|
||||||
|
SWindowRenderLayoutHints OverviewLayout::requestRenderHints(PHLWINDOW pWindow) { return {}; }
|
||||||
|
void OverviewLayout::switchWindows(PHLWINDOW pWindowA, PHLWINDOW pWindowB) {}
|
||||||
|
void OverviewLayout::alterSplitRatio(PHLWINDOW pWindow, float delta, bool exact) {}
|
||||||
|
void OverviewLayout::replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to) {}
|
||||||
|
void OverviewLayout::moveWindowTo(PHLWINDOW, const std::string &dir, bool silent) {}
|
||||||
82
src/OverviewLayout.hpp
Normal file
82
src/OverviewLayout.hpp
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "OverviewManager.hpp"
|
||||||
|
|
||||||
|
#include <hyprland/src/layout/IHyprLayout.hpp>
|
||||||
|
#include <hyprland/src/SharedDefs.hpp>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
|
||||||
|
class OverviewLayout : public IHyprLayout {
|
||||||
|
|
||||||
|
struct WindowState {
|
||||||
|
Vector2D pos;
|
||||||
|
Vector2D size;
|
||||||
|
|
||||||
|
Vector2D posReal;
|
||||||
|
Vector2D sizeReal;
|
||||||
|
|
||||||
|
long monitorId = 0;
|
||||||
|
long workspaceId = 0;
|
||||||
|
std::string workspaceName;
|
||||||
|
|
||||||
|
float ratio = 1.f;
|
||||||
|
bool floating = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OverviewWindowNode {
|
||||||
|
explicit OverviewWindowNode(PHLWINDOW window_);
|
||||||
|
|
||||||
|
bool operator==(const OverviewWindowNode &in) const {
|
||||||
|
return window == in.window;
|
||||||
|
}
|
||||||
|
|
||||||
|
PHLWINDOW window = nullptr;
|
||||||
|
WindowState savedState;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit OverviewLayout(OverviewManager* overviewManager);
|
||||||
|
|
||||||
|
void onEnable() override;
|
||||||
|
void onDisable() override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void onWindowCreatedTiling(PHLWINDOW, eDirection direction) override;
|
||||||
|
void onWindowRemovedTiling(PHLWINDOW) override;
|
||||||
|
void onWindowRemoved(PHLWINDOW) override;
|
||||||
|
|
||||||
|
void onBeginDragWindow() override;
|
||||||
|
|
||||||
|
bool isWindowTiled(PHLWINDOW) override;
|
||||||
|
PHLWINDOW getNextWindowCandidate(PHLWINDOW) override;
|
||||||
|
void recalculateMonitor(const MONITORID &) override;
|
||||||
|
void recalculateWindow(PHLWINDOW) override;
|
||||||
|
void resizeActiveWindow(const Vector2D &, eRectCorner corner, PHLWINDOW pWindow) override;
|
||||||
|
void fullscreenRequestForWindow(PHLWINDOW pWindow, eFullscreenMode CURRENT_EFFECTIVE_MODE, eFullscreenMode EFFECTIVE_MODE) override;
|
||||||
|
std::any layoutMessage(SLayoutMessageHeader, std::string) override;
|
||||||
|
SWindowRenderLayoutHints requestRenderHints(PHLWINDOW) override;
|
||||||
|
void switchWindows(PHLWINDOW, PHLWINDOW) override;
|
||||||
|
void alterSplitRatio(PHLWINDOW, float, bool) override;
|
||||||
|
std::string getLayoutName() override;
|
||||||
|
Vector2D predictSizeForNewWindowTiled() override;
|
||||||
|
void replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to) override;
|
||||||
|
void moveWindowTo(PHLWINDOW, const std::string &direction, bool silent) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateLayout();
|
||||||
|
void calculateOverviewGrid(const std::vector<OverviewWindowNode*>& windows, const PHLWORKSPACE& workspace) const;
|
||||||
|
void updateWorkspaces();
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::map<CWindow*, OverviewWindowNode> m_windowNodes;
|
||||||
|
|
||||||
|
const int border = 5;
|
||||||
|
const int gapIn = 20;
|
||||||
|
const int gapOut = 150;
|
||||||
|
|
||||||
|
private:
|
||||||
|
OverviewManager* mOverviewManager = nullptr;
|
||||||
|
};
|
||||||
77
src/OverviewManager.cpp
Normal file
77
src/OverviewManager.cpp
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
#include "OverviewManager.hpp"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "src/Compositor.hpp"
|
||||||
|
#include "src/managers/LayoutManager.hpp"
|
||||||
|
|
||||||
|
void LayoutSwitcher::onEnterOverviewBefore() {
|
||||||
|
for (auto& window : g_pCompositor->m_windows) {
|
||||||
|
g_pCompositor->setWindowFullscreenState(window, SFullscreenState());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OverviewManager::OverviewManager() {
|
||||||
|
registerSwitcher(std::make_shared<LayoutSwitcher>());
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverviewManager::registerSwitcher(const std::shared_ptr<LayoutSwitcher> &switcher) {
|
||||||
|
mSwitchers[switcher->getName()] = switcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverviewManager::setCurrentSwitcher(const std::string& name) {
|
||||||
|
if (mSwitchers.contains(name)) {
|
||||||
|
mCurrentSwitcher = mSwitchers[name];
|
||||||
|
} else {
|
||||||
|
mCurrentSwitcher = mSwitchers["all"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverviewManager::toggle() {
|
||||||
|
auto currentName = g_pLayoutManager->getCurrentLayout()->getLayoutName();
|
||||||
|
auto overviewName = mOverviewLayout->getLayoutName();
|
||||||
|
|
||||||
|
if (currentName == overviewName) {
|
||||||
|
leaveOverview();
|
||||||
|
} else {
|
||||||
|
enterOverview();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverviewManager::leaveOverview() {
|
||||||
|
auto currentName = g_pLayoutManager->getCurrentLayout()->getLayoutName();
|
||||||
|
auto overviewName = mOverviewLayout->getLayoutName();
|
||||||
|
|
||||||
|
if (currentName != overviewName) return;
|
||||||
|
|
||||||
|
mCurrentSwitcher->onLeaveOverviewBefore();
|
||||||
|
g_pLayoutManager->switchToLayout(mFallbackLayout->getLayoutName());
|
||||||
|
mCurrentSwitcher->onLeaveOverviewAfter();
|
||||||
|
|
||||||
|
onLastActiveWindow(g_pCompositor->m_lastWindow.lock());
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverviewManager::enterOverview() {
|
||||||
|
auto currentName = g_pLayoutManager->getCurrentLayout()->getLayoutName();
|
||||||
|
auto overviewName = mOverviewLayout->getLayoutName();
|
||||||
|
|
||||||
|
if (currentName == overviewName) return;
|
||||||
|
|
||||||
|
mFallbackLayout = g_pLayoutManager->getCurrentLayout();
|
||||||
|
|
||||||
|
setCurrentSwitcher(mFallbackLayout->getLayoutName());
|
||||||
|
|
||||||
|
mCurrentSwitcher->onEnterOverviewBefore();
|
||||||
|
g_pLayoutManager->switchToLayout(mOverviewLayout->getLayoutName());
|
||||||
|
mCurrentSwitcher->onEnterOverviewAfter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverviewManager::onLastActiveWindow(PHLWINDOW windowToFocus) {
|
||||||
|
g_pCompositor->changeWindowZOrder(windowToFocus, true);
|
||||||
|
g_pCompositor->focusWindow(std::move(windowToFocus));
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverviewManager::setOverviewLayout(IHyprLayout *layout) {
|
||||||
|
mOverviewLayout = layout;
|
||||||
|
}
|
||||||
|
|
||||||
40
src/OverviewManager.hpp
Normal file
40
src/OverviewManager.hpp
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "src/layout/IHyprLayout.hpp"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
struct LayoutSwitcher {
|
||||||
|
virtual std::string getName() const { return "all"; }
|
||||||
|
virtual void onEnterOverviewBefore();
|
||||||
|
virtual void onEnterOverviewAfter() {}
|
||||||
|
virtual void onLeaveOverviewBefore() {}
|
||||||
|
virtual void onLeaveOverviewAfter() {}
|
||||||
|
|
||||||
|
virtual ~LayoutSwitcher() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OverviewManager {
|
||||||
|
public:
|
||||||
|
OverviewManager();
|
||||||
|
void setOverviewLayout(IHyprLayout* layout);
|
||||||
|
void registerSwitcher(const std::shared_ptr<LayoutSwitcher>& switcher);
|
||||||
|
void toggle();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void leaveOverview();
|
||||||
|
void enterOverview();
|
||||||
|
|
||||||
|
static void onLastActiveWindow(PHLWINDOW windowToFocus);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setCurrentSwitcher(const std::string &name);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<LayoutSwitcher> mCurrentSwitcher = nullptr;
|
||||||
|
std::map<std::string, std::shared_ptr<LayoutSwitcher>> mSwitchers;
|
||||||
|
|
||||||
|
IHyprLayout* mFallbackLayout = nullptr;
|
||||||
|
IHyprLayout* mOverviewLayout = nullptr;
|
||||||
|
};
|
||||||
30
src/Plugin.cpp
Normal file
30
src/Plugin.cpp
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
|
||||||
|
#include "Plugin.hpp"
|
||||||
|
|
||||||
|
#include "DwindleSwitcher.hpp"
|
||||||
|
|
||||||
|
#include <src/managers/LayoutManager.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
PluginState::PluginState(HANDLE _handle) {
|
||||||
|
handle = _handle;
|
||||||
|
manager = new OverviewManager();
|
||||||
|
layout = new OverviewLayout(manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginState::~PluginState() {
|
||||||
|
delete layout;
|
||||||
|
delete manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PluginState::bind() {
|
||||||
|
manager->setOverviewLayout(layout);
|
||||||
|
manager->registerSwitcher(std::make_shared<DwindleSwitcher>());
|
||||||
|
|
||||||
|
HyprlandAPI::addLayout(handle, layout->getLayoutName(), layout);
|
||||||
|
|
||||||
|
HyprlandAPI::addDispatcherV2(handle, "overview:toggle", [this](const std::string&){
|
||||||
|
manager->toggle();
|
||||||
|
return SDispatchResult();
|
||||||
|
});
|
||||||
|
}
|
||||||
17
src/Plugin.hpp
Normal file
17
src/Plugin.hpp
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "OverviewLayout.hpp"
|
||||||
|
#include "OverviewManager.hpp"
|
||||||
|
|
||||||
|
#include <hyprland/src/plugins/PluginAPI.hpp>
|
||||||
|
|
||||||
|
struct PluginState {
|
||||||
|
explicit PluginState(HANDLE handle);
|
||||||
|
~PluginState();
|
||||||
|
|
||||||
|
HANDLE handle = nullptr;
|
||||||
|
OverviewLayout* layout = nullptr;
|
||||||
|
OverviewManager* manager = nullptr;
|
||||||
|
|
||||||
|
void bind();
|
||||||
|
};
|
||||||
37
src/main.cpp
Normal file
37
src/main.cpp
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
#include "Plugin.hpp"
|
||||||
|
|
||||||
|
#include <src/devices/IPointer.hpp>
|
||||||
|
#include <src/managers/input/InputManager.hpp>
|
||||||
|
|
||||||
|
typedef void (*CInputManager_onMouseButton)(void* , IPointer::SButtonEvent e);
|
||||||
|
|
||||||
|
static PluginState* gPluginState = nullptr;
|
||||||
|
static CFunctionHook* mouseHook = nullptr;
|
||||||
|
|
||||||
|
APICALL EXPORT std::string PLUGIN_API_VERSION() {
|
||||||
|
return HYPRLAND_API_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mouseButtonHook(void* self, IPointer::SButtonEvent buttonEvent) {
|
||||||
|
if (buttonEvent.button == BTN_LEFT ) {
|
||||||
|
gPluginState->manager->leaveOverview();
|
||||||
|
}
|
||||||
|
|
||||||
|
(*(CInputManager_onMouseButton)mouseHook->m_original)(self, buttonEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||||
|
gPluginState = new PluginState(handle);
|
||||||
|
|
||||||
|
gPluginState->bind();
|
||||||
|
|
||||||
|
|
||||||
|
mouseHook = HyprlandAPI::createFunctionHook(gPluginState->handle, (void*)&CInputManager::onMouseButton, (void*)&mouseButtonHook);
|
||||||
|
mouseHook->hook();
|
||||||
|
|
||||||
|
return {"overview", "overview mode", "ilusha", "0.0"};
|
||||||
|
}
|
||||||
|
|
||||||
|
APICALL EXPORT void PLUGIN_EXIT() {
|
||||||
|
delete gPluginState;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue