Compare commits

...

252 Commits

Author SHA1 Message Date
vaxerski
0b525cdc63 default to multisample on 2022-06-26 20:09:42 +02:00
vaxerski
6a47a305f8 fix some xwayland popups 2022-06-26 20:08:19 +02:00
vaxerski
1a0b2c4ade rewritten borders, fixed msaa 2022-06-26 19:39:56 +02:00
Vaxry
f1a5cb4979 Merge pull request #252 from squidgyberries/ex-conf-improvements
Made some settings' comments clearer
2022-06-26 14:53:46 +01:00
vaxerski
f5c2dfc706 a bit of fixes to cursor hiding 2022-06-26 13:43:32 +02:00
Vaxry
4d09101e23 oops 2022-06-26 12:53:56 +02:00
Vaxry
314e1f8fbe added funding 2022-06-26 12:53:22 +02:00
vaxerski
78bf88ba60 Added fullscreen rule 2022-06-26 12:12:29 +02:00
vaxerski
29aab21033 fix up some stupid default settings (internal) 2022-06-25 23:57:23 +02:00
vaxerski
adead82778 some changes to the sens and use in autogen 2022-06-25 23:40:52 +02:00
vaxerski
45898a57c8 guard windows' validity in focuswindowbyclass 2022-06-25 21:18:33 +02:00
vaxerski
2c8cf6afc4 notify of wiki in case of crashes 2022-06-25 21:16:52 +02:00
vaxerski
316b49eee2 added log level info 2022-06-25 20:50:29 +02:00
vaxerski
8de8f6667e add system info logging 2022-06-25 20:49:06 +02:00
Vaxry
648b2c892c mention shadows in readme 2022-06-25 20:36:48 +02:00
vaxerski
2955698f28 fix fade with deco 2022-06-25 20:31:54 +02:00
vaxerski
747ff3369d added drop shadows 2022-06-25 20:28:40 +02:00
vaxerski
b46f45befa additional keymap reload safety 2022-06-25 11:50:09 +02:00
vaxerski
3842b1641f allow move to 0 0 2022-06-25 11:20:03 +02:00
vaxerski
72c86b99eb added general:cursor_inactive_timeout 2022-06-24 23:27:02 +02:00
vaxerski
eb13be1240 fix one of the stupidest things i've ever written I am embarrassed. 2022-06-24 22:45:30 +02:00
vaxerski
45a44f9690 added noblur 2022-06-24 22:28:54 +02:00
Mihai Fufezan
e95e01416e flake, meson: manually update version
version update workflow: temporarily disable running on push
2022-06-24 19:48:11 +03:00
fufexan
94e8234ac9 [gha] bump flake and meson version 2022-06-24 16:45:11 +00:00
Mihai Fufezan
c78b811b49 Nix & Meson: fix update workflow 2022-06-24 19:44:53 +03:00
vaxerski
3053f99db6 guard dragging windows in dwindle 2022-06-24 18:37:04 +02:00
vaxerski
e7467c60f9 fix windowrule regex logic and add title: 2022-06-24 16:25:57 +02:00
vaxerski
3e8842e1f8 fix janky pixel maths with scaled textures 2022-06-24 15:59:59 +02:00
vaxerski
81e36298bf dont scale thick in border 2022-06-24 15:52:42 +02:00
vaxerski
218675246f guard pkeyboard in onMouseButton 2022-06-23 21:46:36 +02:00
vaxerski
e4e323a0df dwindle: disallow swaps between workspaces 2022-06-23 20:51:01 +02:00
vaxerski
f76b9c4852 fix: ignore reserved in getWindowInDirection 2022-06-23 20:39:48 +02:00
vaxerski
ae60075226 fix calculating damage offset for oversized popups 2022-06-23 19:32:00 +02:00
vaxerski
b25bafda08 guard null context in applyConfigToKeyboard 2022-06-23 18:52:05 +02:00
thinkingwithberries
a8e2595534 Update hyprland.conf 2022-06-23 21:52:17 +08:00
thinkingwithberries
3c6526dbbe Merge branch 'hyprwm:main' into ex-conf-improvements 2022-06-23 21:51:40 +08:00
vaxerski
4945c5887d reload all keyboards and not only the active 2022-06-23 15:48:31 +02:00
thinkingwithberries
ccdb03391e removed unused max fps option 2022-06-23 20:30:28 +08:00
thinkingwithberries
6ba5edd13e Made some settings' comments clearer 2022-06-23 18:26:48 +08:00
vaxerski
31dc70a41a Added exact to resizeActive and added moveactive 2022-06-23 10:14:59 +02:00
vaxerski
f9745b0d3b allow getWindowInDirection to scan other mons 2022-06-23 09:56:16 +02:00
Kainoa Kanter
64f6818a13 :finnadie:
https://www.youtube.com/watch?v=_asNhzXq72w
2022-06-22 15:22:22 -07:00
ThatOneCalculator
2631489a18 Syntax error in CI 2022-06-22 15:17:21 -07:00
ThatOneCalculator
5614f28dfd T1C: CMake Release Pipeline (CI) 2022-06-23 00:11:57 +02:00
ThatOneCalculator
a98c07cd00 Merge branch 'main' of https://github.com/hyprwm/Hyprland 2022-06-22 13:24:31 -07:00
Mihai Fufezan
11a5e6bcbf nix: revert to original wlroots repo 2022-06-22 23:23:46 +03:00
ThatOneCalculator
6eefd294af Upload release archive 2022-06-22 13:18:09 -07:00
ThatOneCalculator
606f4b0794 Fix release action 2022-06-22 13:09:37 -07:00
Kainoa Kanter
ff6e3a4d24 T1C: Releases pipeline 2022-06-22 22:04:55 +02:00
Kainoa Kanter
c21b062fe5 Delete aur directory 2022-06-22 11:25:41 -07:00
vaxerski
19d94b87ab Added keybind submaps 2022-06-22 20:23:20 +02:00
Vaxry
bd41776a5a Merge pull request #227 from fufexan/meson
Nix: use meson for builds
2022-06-22 16:20:02 +01:00
vaxerski
c2ff3d9e76 more shadow for readme banner 2022-06-22 16:01:51 +02:00
vaxerski
dbd060247e README better banner 2022-06-22 16:00:52 +02:00
vaxerski
0ec903808b don't use sudo in make config 2022-06-22 15:52:36 +02:00
vaxerski
770bada5d5 Fixed oversized apps' incorrect layout 2022-06-22 15:45:56 +02:00
vaxerski
499d2e41bf default apply_sens_to_raw to 0 2022-06-22 13:01:59 +02:00
vaxerski
d614fa895e Merge pull request #245 from taylor85345/main
Fixed crash on movetoworkspacesilent
2022-06-22 00:14:36 +01:00
taylor85345
b9f542a60f Fixed crash on movetoworkspacesilent 2022-06-21 16:13:05 -07:00
vaxerski
4c2459861b fix borders sometimes disappearing on certain windows 2022-06-21 23:09:20 +02:00
vaxerski
0f1ad16aec added general:no_border_on_floating 2022-06-21 22:54:41 +02:00
vaxerski
5541098f20 Added bindl 2022-06-21 22:47:27 +02:00
vaxerski
48e33023af fix crash on number workspace with null mon 2022-06-21 22:42:54 +02:00
vaxerski
0b6c04355a Merge pull request #239 from SebOuellette/main
Optimize cursor constraints for games
2022-06-21 21:34:31 +01:00
vaxerski
33abb6a5bf dang it autoformat 2022-06-21 22:30:07 +02:00
vaxerski
1810725a0c cleaner code 2022-06-21 22:29:11 +02:00
vaxerski
84d6e640ff support all workspace types in workspace keyword 2022-06-21 22:25:54 +02:00
SebOuellette
20ad9d3e7d Passes all constraint tests!
So a summary of what's been done in this fork/PR. Instead of moving the cursor, we're warp_closest ing. warp_absolute didn't work, so warp closest has kindof an auto constrain feature so it works beautifully. I'm also contraining to the right side of the window - 1, because the cursors are treating that pixel as the next pixel over, so it was actually thinking it was on the next monitor (assuming fullscreen) when the cursor got to the right or bottom of the window. TL;DR rounding issue.

This fix didn't work when you had a fullscreen video playing on a monitor beside, so I also fixed that by ignoring all focus changes or whatever when a constraint actually occured, we obviously just don't want to focus another monitor when constrained, so why not just *disable it when a constraint happened*

The PR is now ready, I love Hyprland, and I can't wait to contribute more :)
2022-06-21 16:25:40 -04:00
vaxerski
4a3f9ccba2 move ignore to eventmanager and fix double focus in changeworkspace 2022-06-21 22:17:30 +02:00
vaxerski
ff49f22440 fix rapid blinking on launch 2022-06-21 22:13:13 +02:00
vaxerski
a2fa1bc80d fix CMake debug mode 2022-06-21 22:09:46 +02:00
Mihai Fufezan
593f24a2ec workflows: add meson version updater and update versions 2022-06-21 22:28:20 +03:00
Mihai Fufezan
8bd7234d72 nix: change build system to meson
flake.nix: change wlroots url to mirror, update version
flake.lock: update wlroots & nixpkgs
nix/update-inputs.sh: update wlroots url
2022-06-21 22:11:46 +03:00
vaxerski
f58bb0187b Merge pull request #241 from viperML/main
Nix: refactor packages and overlays
2022-06-21 11:29:35 +01:00
SebOuellette
3dc2277fd0 Actually, mostly working.
One failure case: When there is a fullscreen window directly to the right of a game, for example, in a multimonitor setup, then the cursor will bug out in between the monitors. sometimes it will get constrained to the border, but just outside the window (which is what this PR fixes, so it's unusual) and sometimes the cursor will just ignore the constraint entirely. However this is only in the one case.
2022-06-21 02:23:57 -04:00
SebOuellette
ee7900f819 Mouse no longer removes focus from constraining window
The window properly constrains the mouse now

I do still notice a bug with moving the mouse in games, if you don't move the mouse fast enough, some games will not register the mouse movement. This doesn't happen in KDE so I know it's related somehow
2022-06-20 23:15:16 -04:00
Sebastian Ouellette
f7e9a27c0a Merge branch 'vaxerski:main' into main 2022-06-20 22:05:02 -04:00
vaxerski
f5f531562b Merge pull request #205 from sp1ritCS/meson
Added meson buildfiles
2022-06-20 13:56:58 +01:00
Fernando Ayats
4efd913de8 nix: use the overlay in the module 2022-06-20 13:04:40 +02:00
Fernando Ayats
bd95301188 nix: no pseudo-overlay 2022-06-20 12:16:07 +02:00
Fernando Ayats
d6b324306b nix: add a proper overlay and cleanup flake 2022-06-20 11:50:06 +02:00
Sebastian Ouellette
dc84935059 Set the constraint position to the window center (properly)
Missed one expression, it was set to the bottom middle. I missed it because i don't have an extra monitor extending from the bottom of that screen.
2022-06-19 16:54:59 -04:00
Sebastian Ouellette
95e083dbd3 Converted tabs to spaces. Now ready for PR 2022-06-19 16:51:03 -04:00
SebOuellette
39d03fc196 Removed the log file which was causing conflicts 2022-06-19 16:24:30 -04:00
SebOuellette
5058a74453 Cleaned up some old debug 2022-06-19 16:23:49 -04:00
Sebastian Ouellette
ae1bcc909d Invisible cursors are constrained to center
This is a first version of my test to properly constrain cursors. This is mostly working in the buggy applications I had before, but I feel that the cursor needs to actually move around, instead of being locked to the center of the window. 

This may cause problems when locking to the edge, but yeah.
2022-06-19 16:07:41 -04:00
Florian "sp1rit"​
7c3626f15e meson: ensure non-debug builds will use proper configuration
meson will set add -DHYPRLAND_DEBUG to CXXFLAGS during compilation of
debug builds. this avoids NDEBUG issues with wlroots and ensures asserts
will also work on release builds.
2022-06-18 13:09:38 +02:00
vaxerski
f7bdc2e870 Merge pull request #234 from alba4k/main
revised makefile, newline after execution
2022-06-17 21:23:48 +01:00
alba4k
faa1b5a44f Update main.cpp 2022-06-17 22:02:57 +02:00
Yoni FIRROLONI
f428604b6f undo formatting 2022-06-17 19:51:34 +01:00
Yoni FIRROLONI
2feca08a67 move, set active, recalc, anim on monitor connected 2022-06-17 19:51:34 +01:00
vaxerski
837d4af8f6 Merge pull request #231 from CcydtN/main
Fix zombie process problem
2022-06-17 17:53:47 +01:00
alba4k
9c6c5481bb revised makefile, newline after execution 2022-06-17 12:18:25 +02:00
Florian "sp1rit"​
75918c14d7 meson: added wayland dependencies to main executable 2022-06-16 23:30:30 +02:00
Florian "sp1rit"​
d179501c4f meson: added default_library=static as default option 2022-06-16 23:30:30 +02:00
Florian "sp1rit"​
8e203b0da3 added assets/wallpapers to install 2022-06-16 23:30:30 +02:00
Florian "sp1rit"​
09cd8c45a6 dropped emoticons from meson workflow 2022-06-16 23:30:30 +02:00
Florian "sp1rit"​
43065657c9 actions: added meson workflow 2022-06-16 23:30:30 +02:00
Florian "sp1rit"​
89454ada6c added runtime tag to the wayland-session launchable and sample config
this allows for a small-install footprint by running
    meson install -C _build --tags runtime
2022-06-16 23:30:30 +02:00
Florian "sp1rit"​
c169f94895 moved wlroots/xwayland definitions to the main meson file
prevents build-failure when xwayland is disabled to to
    add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
beeing called after the required wayland protocols have been built.
2022-06-16 23:30:30 +02:00
Florian "sp1rit"​
b3ef1fcc54 replaced source list with globber script
See:
  - https://mesonbuild.com/FAQ.html#why-cant-i-specify-target-files-with-a-wildcard
  - https://github.com/vaxerski/Hyprland/pull/205#issuecomment-1154158918
2022-06-16 23:30:30 +02:00
Florian "sp1rit"​
fd0112425f Added meson buildfiles
this makes for a far better experience in combination with wlroots,
since that whole makefile mess is not required.
Additionaly, handling of wayland protocol sources is also slightly
better, but could be improved with mesons inbuilt wayland module.

To build Hyprland using meson:
    meson _build -Ddefault_library=static
    ninja -C _build
    ninja -C _build install
2022-06-16 23:30:28 +02:00
CcydtN
b69375a918 Fixing format issue 2022-06-17 03:25:08 +08:00
vaxerski
354e265128 Merge pull request #230 from bazuin-32/main
Resolves #204. Enables numlock on startup when configured to do so
2022-06-16 18:33:37 +01:00
CcydtN
5fa61e5a54 Fix generating zombie process 2022-06-17 01:14:10 +08:00
bazuin-32
1926bb4659 Resolves #204. Enables numlock on startup when configured to do so. 2022-06-16 10:49:16 -06:00
vaxerski
36ea12b315 Merge pull request #223 from PowerBall253/main
Create config directory if it doesn't exist
2022-06-15 07:41:05 +01:00
Bruno Ancona
0c5d2f04b4 Create config directory if it doesn't exist 2022-06-15 01:29:51 -05:00
vaxerski
fa6530c7e8 Merge pull request #213 from ThatOneCalculator/mirror
Change wlroots submodule url to github mirror
2022-06-13 22:16:28 +01:00
ThatOneCalculator
e97b83167f Change wlroots submodule url to github mirror 2022-06-13 14:10:49 -07:00
vaxerski
9aec355727 update contrib link in readme 2022-06-13 21:30:01 +01:00
vaxerski
a4e21a25f4 Merge pull request #200 from siemato/main
Added Touchpad Config options
2022-06-13 17:30:17 +01:00
Marco Siedentopf
f13217f698 Codestyle 2022-06-12 15:06:58 +00:00
Marco Siedentopf
85d2c1d5a6 Merge branch 'vaxerski:main' into main 2022-06-12 15:04:02 +00:00
vaxerski
2208be5175 Merge pull request #197 from spectreseven1138/main
Add loose follow_mouse option
2022-06-12 14:31:07 +02:00
spectreseven1138
46d11f7646 Access config value statically 2022-06-12 16:31:56 +09:00
Marco Siedentopf
16d1b44ef9 Implemented Config options for Touchpads
Implemented Options to 1. toggle between clickfinger behavior and software buttons, 2. button emulation and 3. tap-to-click
2022-06-12 05:40:06 +00:00
Marco Siedentopf
e69f2ab4c3 Added Config options for Touchpads
Added Options to 1. toggle between clickfinger behavior and software buttons, 2. middle button emulation and 3. tap-to-click
2022-06-12 05:40:01 +00:00
spectreseven1138
95a626f72e Add loose (2) option to follow_mouse config 2022-06-12 09:14:22 +09:00
vaxerski
70eb5053fb Note Hypr and Hyprland's differences in readme 2022-06-11 21:10:41 +01:00
vaxerski
48ab282a69 Merge pull request #195 from PowerBall253/main
Add natural_scrolling option for touchpads only
2022-06-11 18:26:24 +02:00
Bruno Ancona
018b0684dd Add natural_scrolling option for touchpads only 2022-06-11 10:24:00 -05:00
vaxerski
94528bcdbc Merge pull request #194 from frigaut/main
fullscreen fix
2022-06-11 17:06:19 +02:00
Francois Rigaut
4fa69497ca fullscreen fix 2022-06-11 16:37:40 +02:00
vaxerski
dc5cc15474 find surfaces in reverse for focus 2022-06-10 15:18:30 +02:00
vaxerski
3a2ac11e3e added focuswindowbyclass 2022-06-10 12:06:27 +02:00
vaxerski
90a859af27 cyclenext 2022-06-10 11:41:52 +02:00
vaxerski
c6953329d5 Added circlenext 2022-06-10 11:39:06 +02:00
vaxerski
c451e13e4f Merge pull request #174 from ThatOneCalculator/main
Change features section in readme
2022-06-09 22:13:46 +02:00
vaxerski
d68e09a707 remove unfocusall 2022-06-09 22:07:33 +02:00
Kainoa Kanter
b4de91111a Update README.md 2022-06-09 12:59:30 -07:00
Kainoa Kanter
750961e9c1 Merge branch 'vaxerski:main' into main 2022-06-09 12:58:07 -07:00
vaxerski
b5a446ddfd Merge pull request #177 from vaxerski/tablets
Added Tablets support
2022-06-09 21:54:10 +02:00
vaxerski
fbc7853459 de-focusify on lost proximity 2022-06-09 21:39:03 +02:00
vaxerski
53146ccf69 oopsie 2022-06-09 21:39:03 +02:00
vaxerski
506977c13d unfocus on destroy 2022-06-09 19:40:16 +02:00
vaxerski
09b130374d unfocus tablets 2022-06-09 19:38:39 +02:00
vaxerski
b53c093b88 log tablets in hyprctl 2022-06-09 19:25:26 +02:00
vaxerski
8929172bc2 remove redundant logs 2022-06-09 19:19:42 +02:00
vaxerski
6317f64ba0 set proximity in tablets 2022-06-09 18:09:09 +02:00
vaxerski
824d8b954d logify even more 2022-06-09 17:40:05 +02:00
vaxerski
49fc1ccdb4 oops 2022-06-09 17:32:58 +02:00
vaxerski
c218ed4432 notify tablet motion 2022-06-09 17:16:01 +02:00
vaxerski
f97b90859a Add envvars to exec cfg 2022-06-09 15:03:34 +02:00
vaxerski
1841d244f0 log shit in tablets 2022-06-09 14:40:56 +02:00
vaxerski
47404534d0 added tablet v2 support (alpha alpha) 2022-06-09 12:46:55 +02:00
Kainoa Kanter
b7e21d0fa9 Update README.md 2022-06-08 14:05:06 -07:00
Kainoa Kanter
90024e534d Features 2022-06-08 14:03:54 -07:00
vaxerski
248ce66459 warn unrecognized input devices 2022-06-08 22:11:24 +02:00
vaxerski
638b44cabd Attach touch devices raw 2022-06-08 22:09:35 +02:00
vaxerski
8f0b963729 refocus after movetoworkspace 2022-06-08 15:52:38 +02:00
vaxerski
7b73570f11 fix a crash in monitorDestroy 2022-06-08 15:13:47 +02:00
vaxerski
a0f3fc794e [gha] bump flake inputs 2022-06-08 12:43:34 +00:00
vaxerski
263664c58a updated wlroots dep 2022-06-08 14:42:27 +02:00
vaxerski
da80eb8e57 Added the tablet manager and tablet v2 protocol 2022-06-08 14:29:49 +02:00
vaxerski
0b8fe2a0aa fix incorrect animationmanager behavior without anims 2022-06-07 22:27:15 +02:00
vaxerski
1642b1ff66 optimize config calls in often called areas 2022-06-07 20:41:40 +02:00
vaxerski
7b9583c1f2 Mention source in issue guidelines 2022-06-07 20:11:05 +02:00
vaxerski
cc80b68545 fixed a typo, will boost performance on opaque windows with blur 2022-06-07 20:10:14 +02:00
vaxerski
2bddfa81bc Merge pull request #169 from ThatOneCalculator/main
AUR go brrr
2022-06-07 00:12:30 +02:00
Kainoa Kanter
85d91c3d3c Update PKGBUILD-git 2022-06-06 15:07:48 -07:00
Kainoa Kanter
d80c90233b Update PKGBUILD-bin 2022-06-06 15:07:35 -07:00
Kainoa Kanter
d0ca043122 Update PKGBUILD-git 2022-06-06 15:05:29 -07:00
Kainoa Kanter
92da453d4d Update PKGBUILD-git 2022-06-06 15:05:16 -07:00
Kainoa Kanter
433e4a0eef Update PKGBUILD 2022-06-06 15:05:00 -07:00
vaxerski
b62e530fdb Force window style tiled on all xdg windows 2022-06-06 19:43:44 +02:00
vaxerski
663fba76ae Added resizeactive 2022-06-06 19:32:14 +02:00
vaxerski
d73e05cc68 fix XDELTA and YDELTA with empty geometry 2022-06-06 18:56:16 +02:00
vaxerski
066ea296ff dont report unmanaged x11 windows in hyprctl clients 2022-06-06 15:22:25 +02:00
vaxerski
72c967aa89 fix class crash with unmanaged x11 2022-06-06 15:03:06 +02:00
vaxerski
c474e8253a Update issue templates 2022-06-06 15:00:24 +02:00
vaxerski
20936ad2a4 added issue guidelines 2022-06-06 14:58:50 +02:00
vaxerski
d743ac7bb1 added forcerendererreload and some more vt changes 2022-06-06 13:48:17 +02:00
vaxerski
322a495412 Merge pull request #167 from JamesReynolds/main
Fix error: attribute 'lastModifiedDate' missing
2022-06-06 13:06:40 +02:00
vaxerski
63d6c594b9 fix possible crash in hyprctl clients 2022-06-06 12:58:39 +02:00
vaxerski
09e77bf844 added force_no_accel 2022-06-06 12:08:33 +02:00
James Reynolds
3d4832990c Fix error: attribute 'lastModifiedDate' missing
Only applies to some versions of flakes, tested on nix 2.8.1.
2022-06-06 10:20:56 +01:00
vaxerski
84a0fa0f34 fix subsurfaces not damaging on unmap 2022-06-05 23:23:16 +02:00
vaxerski
2cd2f8b5b5 add class to window hyprctl requests 2022-06-04 20:32:27 +02:00
vaxerski
172d6cd498 Merge pull request #160 from ThatOneCalculator/main
Hooray, more AUR stuff!
2022-06-03 20:41:10 +02:00
Kainoa Kanter
02269af777 Update PKGBUILD-git 2022-06-03 11:33:32 -07:00
Kainoa Kanter
e2592522d3 Update PKGBUILD 2022-06-03 11:33:14 -07:00
Kainoa Kanter
d76c982d2e Update PKGBUILD-bin 2022-06-03 11:32:48 -07:00
vaxerski
ef855440c6 keyboard code further cleanup 2022-06-03 19:15:39 +02:00
vaxerski
246aa000f5 Added dwindle:special_scale_factor 2022-06-03 19:03:33 +02:00
vaxerski
1a93b2a756 Handle keyboards better
Also fixes some crashes of apps on reload
2022-06-03 18:59:39 +02:00
vaxerski
10c2bd0686 make shaders cleaner 2022-06-03 18:45:18 +02:00
vaxerski
f99ad521a4 Updated issue templates 2022-06-03 17:52:22 +02:00
vaxerski
9486a230c7 Log to the instance folder 2022-06-03 17:48:07 +02:00
vaxerski
6f3b004199 IPC and log changes, introduce signature 2022-06-03 17:41:57 +02:00
vaxerski
19b17b590c fix moveactivetoworkspace with same workspace 2022-06-03 11:19:17 +02:00
vaxerski
f9c8a72e46 dont enable AA by default 2022-06-02 23:03:13 +02:00
vaxerski
e11cb8b328 Added antialiasing to outer edges
simplified, stupidly fast MSAA for rounded edges
2022-06-02 22:58:54 +02:00
vaxerski
7b568d7ad8 configure keyboards one by one 2022-06-02 20:31:47 +02:00
vaxerski
a2f718059b fucking typo 2022-06-02 19:50:46 +02:00
vaxerski
feb0499597 Merge pull request #144 from fufexan/main
Fix Nix build and add updater
2022-06-02 19:47:54 +02:00
vaxerski
601abc7e92 Added locking numlock 2022-06-02 19:47:11 +02:00
Mihai Fufezan
7451890fd7 nix: replace paths dynamically 2022-06-02 19:10:56 +03:00
vaxerski
f5cdb5b95e Fix special in m+1 m-1 2022-06-02 16:54:19 +02:00
vaxerski
7afcf656bd Added hyprctl devices 2022-06-02 13:59:33 +02:00
Mihai Fufezan
6daa866beb nix/updater: only update wlroots on rev change 2022-06-02 00:09:28 +03:00
Mihai Fufezan
9447fcd603 fix Nix build and add updater
- move unnecessary toplevel files to nix/
- added patch that ignores the submodule (revert)
- add update script run by a workflow
2022-06-01 23:52:08 +03:00
vaxerski
9acf15efd7 README changes 2022-06-01 22:00:46 +02:00
vaxerski
b5a100379e reject drag on fullscreen workspace 2022-06-01 21:13:10 +02:00
vaxerski
4f76d5d8d7 destroy monitor on disabled 2022-06-01 21:10:12 +02:00
vaxerski
8d850b0ce1 Added workspace/monitor unset and workspace silent rules 2022-06-01 21:04:06 +02:00
vaxerski
0f28d2ae55 fix stupid error in anim styles 2022-06-01 20:51:21 +02:00
vaxerski
d2451aea4b use overflowing coords when surface unmaps 2022-06-01 13:38:33 +02:00
vaxerski
680705ff91 [gha] bump flake inputs 2022-06-01 00:50:00 +00:00
vaxerski
300fc2ab0f Merge pull request #140 from ThatOneCalculator/main
More AUR stuff
2022-05-31 22:49:15 +02:00
Kainoa Kanter
02210d3d96 Update PKGBUILD-bin 2022-05-31 13:46:09 -07:00
Kainoa Kanter
879345c1e9 Update PKGBUILD-git 2022-05-31 13:46:00 -07:00
Kainoa Kanter
1e3bea5e70 Update PKGBUILD 2022-05-31 13:45:51 -07:00
Kainoa Kanter
f64cae2b7f Update PKGBUILD-bin 2022-05-31 13:32:59 -07:00
Kainoa Kanter
c433b14e3d Update PKGBUILD 2022-05-31 13:32:38 -07:00
Kainoa Kanter
8d1c495878 Update PKGBUILD-git 2022-05-31 13:32:26 -07:00
Kainoa Kanter
4264a0b08d Update PKGBUILD 2022-05-31 13:26:03 -07:00
Kainoa Kanter
40ab062a3c Update PKGBUILD-bin 2022-05-31 13:25:49 -07:00
Kainoa Kanter
35bcea38e3 0.2.1beta 2022-05-31 13:19:26 -07:00
Kainoa Kanter
1ccb944509 0.2.1beta 2022-05-31 13:19:15 -07:00
Kainoa Kanter
c600249aee Merge branch 'vaxerski:main' into main 2022-05-31 13:18:36 -07:00
Kainoa Kanter
6d6e967a8d Update PKGBUILD-git 2022-05-31 13:17:02 -07:00
vaxerski
970018248f Don't damage surfaces coming from not rendered windows 2022-05-31 22:16:13 +02:00
Kainoa Kanter
f6b8a96621 Update PKGBUILD 2022-05-31 13:15:57 -07:00
Kainoa Kanter
8e8d5a99c2 Add bin 2022-05-31 13:15:41 -07:00
vaxerski
471654d791 remove monitor recommended dt from config 2022-05-31 21:05:46 +02:00
vaxerski
679e36d82e fix border size on scaled outputs 2022-05-31 20:38:45 +02:00
vaxerski
0f8712ed64 fix crash in moveWorkspaceToMonitor 2022-05-31 18:47:32 +02:00
vaxerski
3e28a8b690 added slidevert for workspaces 2022-05-31 17:56:33 +02:00
vaxerski
8de7cc5a8d opacity windowrule support 2 values 2022-05-31 17:35:50 +02:00
vaxerski
e73df80782 Add mon in mon out events and fix crash 2022-05-31 17:17:44 +02:00
vaxerski
0d7131d30e fix typo in hyprctl clients and activewindow 2022-05-31 16:52:28 +02:00
vaxerski
d2e0b7c22a render special over fullscreen 2022-05-31 14:20:41 +02:00
vaxerski
c1193ee483 updated readme features 2022-05-31 14:15:28 +02:00
vaxerski
042e79b888 fix fatal crash 2022-05-31 14:04:11 +02:00
vaxerski
0055efc4f1 Added a special workspace 2022-05-31 14:01:00 +02:00
vaxerski
df722cbb86 Added relative monitor workspace offset 2022-05-31 12:33:08 +02:00
vaxerski
68f7e565e6 Use existing default mon workspace if available on connect 2022-05-31 12:10:34 +02:00
vaxerski
48a3b1c514 fix oopsie 2022-05-31 11:02:54 +02:00
vaxerski
85128ebb7d Merge pull request #130 from vaxerski/bundle-wlroots
Bundle wlroots
2022-05-31 10:50:55 +02:00
vaxerski
ad98b96891 add submodules to CI 2022-05-31 10:47:56 +02:00
vaxerski
2e7586e841 fix up config and includes 2022-05-31 10:43:41 +02:00
vaxerski
f6ba9909d6 added submodule 2022-05-31 10:08:57 +02:00
vaxerski
c9041bf5c9 notify workspace protocol of workspace group change 2022-05-30 20:51:45 +02:00
vaxerski
b2474d406a don't duplicate workspaces on connect 2022-05-30 20:45:39 +02:00
vaxerski
eee9698ec9 move workspaces and not windows on mon disconnect 2022-05-30 20:44:14 +02:00
vaxerski
1f4c938c67 Added moving workspaces 2022-05-30 20:05:38 +02:00
vaxerski
c44c79abb2 fix monitor cleanups on removed 2022-05-30 17:11:35 +02:00
vaxerski
1e096f6fcd fix moveactivetoworkspace 2022-05-30 15:28:23 +02:00
vaxerski
b1c11f3d2e consider the full bb with deco in rendering 2022-05-30 14:55:42 +02:00
vaxerski
da63503d5f updated issue templates
dont submit aur coredumps plox
2022-05-30 14:21:33 +02:00
vaxerski
7167be9c48 Fix relative IDs in movetoworkspace crashing 2022-05-30 14:18:46 +02:00
92 changed files with 4818 additions and 1038 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1 @@
ko_fi: vaxry

View File

@@ -3,13 +3,10 @@ name: Bug report
about: Found a bug? Report it here! about: Found a bug? Report it here!
title: '' title: ''
labels: bug labels: bug
assignees: ''
--- ---
**Describe the bug** Please consult the issue guidelines at
https://github.com/vaxerski/Hyprland/blob/main/docs/ISSUE_GUIDELINES.md
BEFORE submitting.
**Images/videos/anything that would help**
Please attach a log (it's in /tmp/hypr/hyprland.log) and, if crashing, a crashdump (coredumpctl, then coredumpctl info <pid>)

View File

@@ -3,7 +3,10 @@ name: Feature request
about: Suggest a feature/change/idea about: Suggest a feature/change/idea
title: '' title: ''
labels: enhancement labels: enhancement
assignees: ''
--- ---
**Describe in detail your idea.** Please consult the issue guidelines at
https://github.com/vaxerski/Hyprland/blob/main/docs/ISSUE_GUIDELINES.md
BEFORE submitting.

View File

@@ -13,29 +13,73 @@ jobs:
sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
pacman --noconfirm --noprogressbar -Syyu pacman --noconfirm --noprogressbar -Syyu
pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers xcb-util-errors xcb-util-renderutil xcb-util-wm xorg-fonts-encodings xorg-server-common xorg-setxkbmap xorg-xkbcomp xorg-xwayland git cmake go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers xcb-util-errors xcb-util-renderutil xcb-util-wm xorg-fonts-encodings xorg-server-common xorg-setxkbmap xorg-xkbcomp xorg-xwayland git cmake go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd
- name: Set up user - name: Set up user
run: | run: |
useradd -m githubuser useradd -m githubuser
echo -e "root ALL=(ALL:ALL) ALL\ngithubuser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers echo -e "root ALL=(ALL:ALL) ALL\ngithubuser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers
- name: Build wlroots - name: Build wlroots
run: | run: |
su githubuser -c "cd ~ && git clone https://gitlab.freedesktop.org/wlroots/wlroots" su githubuser -c "cd ~ && git clone https://gitlab.freedesktop.org/wlroots/wlroots"
su githubuser -c "cd ~/wlroots && meson build/ --prefix=/usr && ninja -C build/ && sudo ninja -C build/ install && cd .." su githubuser -c "cd ~/wlroots && meson build/ --prefix=/usr && ninja -C build/ && sudo ninja -C build/ install && cd .."
- name: Fix permissions for git - name: Fix permissions for git
run: | run: |
git config --global --add safe.directory /__w/Hyprland/Hyprland git config --global --add safe.directory /__w/Hyprland/Hyprland
- name: Checkout Hyprland - name: Checkout Hyprland
uses: actions/checkout@v3 uses: actions/checkout@v3
with:
- name: Build Hyprland With default settings submodules: recursive
- name: Build Hyprland
run: | run: |
git submodule sync --recursive && git submodule update --init --force --recursive git submodule sync --recursive && git submodule update --init --force --recursive
make all make all
- name: Compress and package artifacts
- name: Build Hyprland with LEGACY_RENDERER
run: | run: |
make legacyrenderer mkdir x86_64-pc-linux-gnu
mkdir hyprland
mkdir hyprland/example
mkdir hyprland/assets
cp ./LICENSE hyprland/
cp build/Hyprland hyprland/
cp hyprctl/hyprctl hyprland/
cp subprojects/wlroots/build/libwlroots.so.11032 hyprland/
cp build/Hyprland hyprland/
cp -r example/ hyprland/
cp -r assets/ hyprland/
tar -cvf Hyprland.tar.xz hyprland
- name: Release
uses: actions/upload-artifact@v3
with:
name: Build archive
path: Hyprland.tar.xz
meson:
name: "Build Hyprland with Meson (Arch)"
runs-on: ubuntu-latest
container:
image: archlinux
steps:
- name: Download dependencies
run: |
sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
pacman --noconfirm --noprogressbar -Syyu
pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers xcb-util-errors xcb-util-renderutil xcb-util-wm xorg-fonts-encodings xorg-server-common xorg-setxkbmap xorg-xkbcomp xorg-xwayland git go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd
- name: Checkout Hyprland
uses: actions/checkout@v3
with:
submodules: true
- name: Configure
run: |
meson obj-x86_64-pc-linux-gnu \
-Ddefault_library=static
- name: Compile
run: ninja -C obj-x86_64-pc-linux-gnu
# - name: Compress artifacts
# run: |
# mkdir x86_64-pc-linux-gnu
# DESTDIR=$PWD/x86_64-pc-linux-gnu meson install -C obj-x86_64-pc-linux-gnu --tags runtime
# tar -cvf x86_64-pc-linux-gnu.tar.xz x86_64-pc-linux-gnu
# - name: Upload artifacts
# uses: actions/upload-artifact@v3
# with:
# name: Build artifacts (x86_64-pc-linux-gnu)
# path: x86_64-pc-linux-gnu.tar.xz

View File

@@ -8,6 +8,8 @@ jobs:
steps: steps:
- name: Clone repository - name: Clone repository
uses: actions/checkout@v3 uses: actions/checkout@v3
with:
submodules: recursive
- name: Install nix - name: Install nix
uses: cachix/install-nix-action@v17 uses: cachix/install-nix-action@v17
with: with:

View File

@@ -0,0 +1,26 @@
name: "Nix & Meson: update version"
on: [workflow_dispatch]
jobs:
update:
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v3
- name: Update flake and meson version
run: |
REGEX="([0-9]+(\.[0-9a-zA-Z]+)+)"
CRT_REV=$(git show-ref --tags --head --abbrev | head -n 1 | head -c 7)
TAG_REV=$(git show-ref --tags --abbrev | tail -n 1 | head -c 7)
CRT_VER=$(sed -nEe "/$REGEX/{p;q;}" meson.build | awk -F\' '{print $2}')
VERSION=$(git show-ref --tags --abbrev | tail -n 1 | tail -c +20)
if [[ $TAG_REV = $CRT_REV ]] || [[ $CRT_VER != $VERSION ]]; then
sed -Ei "s/$REGEX/$VERSION/g" meson.build
sed -Ei "s/$REGEX/$VERSION/g" flake.nix
fi
- uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: "[gha] bump flake and meson version"

View File

@@ -1,9 +1,6 @@
name: "Nix: update lockfile" name: "Nix: update lockfile"
on: on: [push, workflow_dispatch]
schedule:
- cron: '0 0 */14 * *'
workflow_dispatch:
jobs: jobs:
update: update:
@@ -19,7 +16,7 @@ jobs:
auto-optimise-store = true auto-optimise-store = true
experimental-features = nix-command flakes experimental-features = nix-command flakes
- name: Update lockfile - name: Update lockfile
run: nix flake update run: nix/update-inputs.sh
- uses: stefanzweifel/git-auto-commit-action@v4 - uses: stefanzweifel/git-auto-commit-action@v4
with: with:
commit_message: "[gha] bump flake inputs" commit_message: "[gha] bump flake inputs"

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "wlroots"]
path = subprojects/wlroots
url = https://gitlab.freedesktop.org/wlroots/wlroots.git

View File

@@ -35,7 +35,7 @@ execute_process(
# #
# #
include_directories(.) include_directories(. PRIVATE "subprojects/wlroots/include/")
add_compile_options(-std=c++20 -DWLR_USE_UNSTABLE ) add_compile_options(-std=c++20 -DWLR_USE_UNSTABLE )
add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing) add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
@@ -59,6 +59,7 @@ ENDIF(NO_XWAYLAND MATCHES true)
IF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) IF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
message(STATUS "Configuring Hyprland in Debug with CMake!") message(STATUS "Configuring Hyprland in Debug with CMake!")
add_definitions( -DHYPRLAND_DEBUG )
ELSE() ELSE()
# add_compile_options(-O3) # may crash for some # add_compile_options(-O3) # may crash for some
message(STATUS "Configuring Hyprland in Release with CMake!") message(STATUS "Configuring Hyprland in Release with CMake!")

View File

@@ -59,6 +59,16 @@ pointer-constraints-unstable-v1-protocol.c:
pointer-constraints-unstable-v1-protocol.o: pointer-constraints-unstable-v1-protocol.h pointer-constraints-unstable-v1-protocol.o: pointer-constraints-unstable-v1-protocol.h
tablet-unstable-v2-protocol.h:
$(WAYLAND_SCANNER) server-header \
protocols/tablet-unstable-v2.xml $@
tablet-unstable-v2-protocol.c:
$(WAYLAND_SCANNER) private-code \
protocols/tablet-unstable-v2.xml $@
tablet-unstable-v2-protocol.o: tablet-unstable-v2-protocol.h
idle-protocol.h: idle-protocol.h:
$(WAYLAND_SCANNER) server-header \ $(WAYLAND_SCANNER) server-header \
protocols/idle.xml $@ protocols/idle.xml $@
@@ -89,6 +99,7 @@ clear:
rm -rf build rm -rf build
rm -f *.o *-protocol.h *-protocol.c rm -f *.o *-protocol.h *-protocol.c
rm -f ./hyprctl/hyprctl rm -f ./hyprctl/hyprctl
rm -rf ./wlroots/build
all: all:
make config make config
@@ -113,4 +124,16 @@ uninstall:
rm -f ${PREFIX}/bin/hyprctl rm -f ${PREFIX}/bin/hyprctl
rm -rf ${PREFIX}/share/hyprland rm -rf ${PREFIX}/share/hyprland
config: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o wlr-screencopy-unstable-v1-protocol.o idle-protocol.o ext-workspace-unstable-v1-protocol.o pointer-constraints-unstable-v1-protocol.o protocols: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o wlr-screencopy-unstable-v1-protocol.o idle-protocol.o ext-workspace-unstable-v1-protocol.o pointer-constraints-unstable-v1-protocol.o tablet-unstable-v2-protocol.o
config:
make protocols
sed -i -E 's/(soversion = 11)([^032]|$$)/soversion = 11032/g' subprojects/wlroots/meson.build
rm -rf ./subprojects/wlroots/build
cd subprojects/wlroots && meson ./build --prefix=/usr --buildtype=release
cd subprojects/wlroots && ninja -C build/
cd subprojects/wlroots && ninja -C build/ install

View File

@@ -1,6 +1,6 @@
<div align = center> <div align = center>
![Banner] <img src="https://raw.githubusercontent.com/vaxerski/Hyprland/main/assets/header.svg" width="1000" height="500" alt="banner">
<br> <br>
@@ -19,6 +19,7 @@ Hyprland is a dynamic tiling Wayland compositor based on wlroots that doesn't sa
For Hyprland without the `land` part, see [Hypr], the Xorg window manager. For Hyprland without the `land` part, see [Hypr], the Xorg window manager.
Please note, especially for folks moving from Hypr, that Hyprland and Hypr share a very different feature set and are not 1:1 experiences.
<br> <br>
<br> <br>
@@ -37,10 +38,9 @@ For Hyprland without the `land` part, see [Hypr], the Xorg window manager.
# Notice # Notice
This project is still in its early development, expect bugs. Hyprland is still in pretty early development compared to some other Wayland compositors.
Once you get it working though, it's pretty stable.<br/>
Although Hyprland is pretty stable, it may have some bugs.
### Help Wanted ### Help Wanted
@@ -51,18 +51,24 @@ Try it out and report bugs / suggestions!
- Easily expandable and readable codebase - Easily expandable and readable codebase
- Config reloaded instantly upon saving - Config reloaded instantly upon saving
- Bezier-curve window animations
- Custom bezier curve based animations - Custom bezier curve based animations
- Workspaces protocol support - `wlr_ext` workspaces protocol support
- Dual Kawase blur - Dual Kawase blur
- Window fade in / out - Drop shadows
- Tiling/floating/fullscreen windows - Fully dynamic workspaces
- Window/monitor rules - Closely follows `wlroots-git`
- Bundled wlroots
- Window/layer fade in/out
- Tiling/pseudotiling/floating/fullscreen windows
- Switching workspaces between window modes on the fly
- Special workspace (scratchpad)
- Window/monitor rules
- Socket-based IPC - Socket-based IPC
- Event system for bash scripts
- Rounded corners - Rounded corners
- Damage tracking(*Experimental*) - Full damage tracking
- Moving/resizing
- Docks support - Docks support
- Drawing tablet support
<br> <br>
<br> <br>
@@ -125,7 +131,7 @@ Try it out and report bugs / suggestions!
[Issues]: https://github.com/vaxerski/Hyprland/issues [Issues]: https://github.com/vaxerski/Hyprland/issues
[Todo]: https://github.com/vaxerski/Hyprland/projects?type=beta [Todo]: https://github.com/vaxerski/Hyprland/projects?type=beta
[Contribute]: docs/Contribute.md [Contribute]: https://github.com/vaxerski/Hyprland/wiki/Contributing-&-Debugging
[Install]: https://github.com/vaxerski/Hyprland/wiki/Installation [Install]: https://github.com/vaxerski/Hyprland/wiki/Installation
[Quick Start]: https://github.com/vaxerski/Hyprland/wiki/Quick-start [Quick Start]: https://github.com/vaxerski/Hyprland/wiki/Quick-start
[License]: LICENSE [License]: LICENSE
@@ -146,7 +152,6 @@ Try it out and report bugs / suggestions!
[Preview A]: https://i.imgur.com/NbrTnZH.png [Preview A]: https://i.imgur.com/NbrTnZH.png
[Preview B]: https://i.imgur.com/ZA4Fa8R.png [Preview B]: https://i.imgur.com/ZA4Fa8R.png
[Preview C]: https://i.imgur.com/BpXxM8H.png [Preview C]: https://i.imgur.com/BpXxM8H.png
[Banner]: https://raw.githubusercontent.com/vaxerski/Hyprland/main/assets/hyprland.png
<!----------------------------------{ Badges }---------------------------------> <!----------------------------------{ Badges }--------------------------------->

83
assets/header.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 798 KiB

5
assets/meson.build Normal file
View File

@@ -0,0 +1,5 @@
wallpapers = ['wall_2K.png', 'wall_4K.png', 'wall_8K.png']
foreach wallpaper : wallpapers
install_data(wallpapers, install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime')
endforeach

View File

@@ -1,32 +0,0 @@
# Maintainer: ThatOneCalculator <kainoa@t1c.dev>
_pkgname="hyprland"
pkgname="${_pkgname}"
pkgver="0.1.1beta"
pkgrel=2
pkgdesc="Hyprland is a dynamic tiling Wayland compositor based on wlroots that doesn't sacrifice on its looks."
arch=(any)
url="https://github.com/vaxerski/Hyprland"
license=('BSD')
depends=(libxcb xcb-proto xcb-util xcb-util-keysyms libxfixes libx11 libxcomposite xorg-xinput libxrender pixman wayland-protocols wlroots-git cairo pango)
makedepends=(git cmake ninja gcc gdb)
source=("${pkgname}-${pkgver}.tar.gz::https://github.com/vaxerski/hyprland/archive/v${pkgver}.tar.gz")
sha256sums=('SKIP')
options=(!makeflags !buildflags)
build() {
cd "$srcdir/Hyprland-$pkgver"
make all
}
package() {
cd "$srcdir/Hyprland-$pkgver"
mkdir -p "${pkgdir}/usr/share/wayland-sessions"
mkdir -p "${pkgdir}/usr/share/hyprland"
install -Dm755 build/Hyprland -t "${pkgdir}/usr/bin"
install -Dm755 hyprctl/hyprctl -t "${pkgdir}/usr/bin"
install -Dm644 assets/*.png -t "${pkgdir}/usr/share/hyprland"
install -Dm644 example/hyprland.desktop -t "${pkgdir}/usr/share/wayland-sessions"
install -Dm644 example/hyprland.conf -t "${pkgdir}/usr/share/hyprland"
install -Dm644 LICENSE -t "${pkgdir}/usr/share/licenses/${_pkgname}"
}

View File

@@ -1,40 +0,0 @@
# Maintainer: ThatOneCalculator <kainoa@t1c.dev>, Sander van Kasteel <info@sandervankasteel.nl>
_pkgname="hyprland"
pkgname="${_pkgname}-git"
pkgver=r568.g632d00c
pkgrel=1
pkgdesc="Hyprland is a dynamic tiling Wayland compositor based on wlroots that doesn't sacrifice on its looks."
arch=(any)
url="https://github.com/vaxerski/Hyprland"
license=('BSD')
depends=(libxcb xcb-proto xcb-util xcb-util-keysyms libxfixes libx11 libxcomposite xorg-xinput libxrender pixman wayland-protocols wlroots-git cairo pango)
makedepends=(git cmake ninja gcc gdb)
source=("${_pkgname}::git+https://github.com/vaxerski/Hyprland.git")
sha256sums=('SKIP')
options=(!makeflags !buildflags)
pkgver() {
cd "$_pkgname"
( set -o pipefail
git describe --long 2>/dev/null | sed 's/\([^-]*-g\)/r\1/;s/-/./g' ||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
)
}
build() {
cd "${srcdir}/${_pkgname}"
make all
}
package() {
cd "${srcdir}/${_pkgname}"
mkdir -p "${pkgdir}/usr/share/wayland-sessions"
mkdir -p "${pkgdir}/usr/share/hyprland"
install -Dm755 build/Hyprland -t "${pkgdir}/usr/bin"
install -Dm755 hyprctl/hyprctl -t "${pkgdir}/usr/bin"
install -Dm644 assets/*.png -t "${pkgdir}/usr/share/hyprland"
install -Dm644 example/hyprland.desktop -t "${pkgdir}/usr/share/wayland-sessions"
install -Dm644 example/hyprland.conf -t "${pkgdir}/usr/share/hyprland"
install -Dm644 LICENSE -t "${pkgdir}/usr/share/licenses/${_pkgname}"
}

View File

@@ -1,32 +0,0 @@
# Contributing
*Thank you for considering contributing to Hyprland.*
## Development
Check the[Wiki]for debugging instructions.
Afterwards, pick yourself an[Issue] orimplement your own suggestion.
An good place to search for things to contribute is the [Projects Page]
*As Hyprlandis still in its early stages of development, I'd recommend you stick to bug fixes first.*
## Pull Requests
- Please follow the code style
- Code must be readable
- Features should be useful
- Test your changes!
*Run it on bare metal and check if everything works.*
<!----------------------------------------------------------------------------->
[Issue]: https://github.com/vaxerski/Hyprland/issues
[Wiki]: https://github.com/vaxerski/Hyprland/wiki/Contributing-&-Debugging
[Projects page]: https://github.com/vaxerski/Hyprland/projects?type=beta

58
docs/ISSUE_GUIDELINES.md Normal file
View File

@@ -0,0 +1,58 @@
# Issue Guidelines
First of all, please remember to:
- Check that your issue is not a duplicate
- Read the [FAQ](https://github.com/vaxerski/Hyprland/wiki/FAQ)
- Read the [Configuring Page](https://github.com/vaxerski/Hyprland/wiki/Configuring-Hyprland)
<br/>
# Reporting suggestions
Suggestions are welcome.
Many features can be implemented using bash scripts and Hyprland sockets, read up on those [Here](https://github.com/vaxerski/Hyprland/wiki/IPC). Please do not suggest features that can be implemented as such.
<br/>
# Reporting bugs
All bug reports should have the following:
- Steps to reproduce
- Expected outcome
- Noted outcome
If your bug is one that doesn't crash Hyprland, but feels like invalid behavior, that's all you need to say.
If your bug crashes Hyprland, append additionally:
- The Hyprland log
- Coredump / Coredump analysis (with a stacktrace)
**Important**: Please do NOT use any package for reporting bugs! Clone and compile from source.
## Obtaining the Hyprland log
If you are in a TTY, and the hyprland session that crashed was the last one you launched, the log will be printed with
```
cat /tmp/hypr/$(ls -t /tmp/hypr/ | head -n 1)/hyprland.log
```
feel free to send it to a file, save, copy, etc.
if you are in a Hyprland session, and you want the log of the last session, use
```
cat /tmp/hypr/$(ls -t /tmp/hypr/ | head -n 2 | tail -n 1)/hyprland.log
```
basically, directories in /tmp/hypr are your sessions.
## Obtaining the Hyprland coredump
If you are on systemd, you can simply use
```
coredumpctl
```
then go to the end (press END on your keyboard) and remember the PID of the last `Hyprland` occurrence. It's the first number after the time, for example `2891`.
exit coredumpctl (ctrl+c) and use
```
coredumpctl info [PID]
```
where `[PID]` is the PID you remembered.

View File

@@ -1,35 +0,0 @@
# Installation
## Packages
*I do not maintain any packages, but some kind people have made them for me.*
**If I missed any, please let me know.**
## Notice
Since I am not the maintainer, I cannot guarantee that those packages will always work and be up to date.
***Use at your own disclosure.*** <br>
*If they don't work, try building manually.*
#### Arch(AUR/-git)
```sh
yay -S hyprland-git
```
---
## Building / No XWayland / other
If your distro doesn't have **Hyprland** in its repositories, you want to modify it, or use custom build flags, please refer to the **[Wiki Page][Install]** for the installation instructions.
<!----------------------------------------------------------------------------->
[Install]: https://github.com/vaxerski/Hyprland/wiki/Installation

View File

@@ -17,8 +17,7 @@ input {
} }
general { general {
max_fps=60 # deprecated, unused sensitivity=1.0 # for mouse cursor
sensitivity=0.25
main_mod=SUPER main_mod=SUPER
gaps_in=5 gaps_in=5
@@ -27,7 +26,9 @@ general {
col.active_border=0x66ee1111 col.active_border=0x66ee1111
col.inactive_border=0x66333333 col.inactive_border=0x66333333
damage_tracking=full # experimental, monitor is 100% fine, but full might have some minor bugs, especially with high blur settings! apply_sens_to_raw=0 # whether to apply the sensitivity to raw input (e.g. used by games where you aim using your mouse)
damage_tracking=full # leave it on full unless you hate your GPU and want to make it suffer
} }
decoration { decoration {
@@ -95,4 +96,4 @@ bind=ALT,6,movetoworkspace,6
bind=ALT,7,movetoworkspace,7 bind=ALT,7,movetoworkspace,7
bind=ALT,8,movetoworkspace,8 bind=ALT,8,movetoworkspace,8
bind=ALT,9,movetoworkspace,9 bind=ALT,9,movetoworkspace,9
bind=ALT,0,movetoworkspace,10 bind=ALT,0,movetoworkspace,10

2
example/meson.build Normal file
View File

@@ -0,0 +1,2 @@
install_data('hyprland.conf', install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime')
install_data('hyprland.desktop', install_dir: join_paths(get_option('datadir'), 'wayland-sessions'), install_tag: 'runtime')

12
flake.lock generated
View File

@@ -2,11 +2,11 @@
"nodes": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1653581809, "lastModified": 1655807518,
"narHash": "sha256-Uvka0V5MTGbeOfWte25+tfRL3moECDh1VwokWSZUdoY=", "narHash": "sha256-5YV29Ry/DpAJc/0Hc/+ISVBAjwHpJvAkeKkcUG5lWsc=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "83658b28fe638a170a19b8933aa008b30640fbd1", "rev": "a72d7811be1162dd6804c4e36e5402d76fb6e921",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -26,11 +26,11 @@
"flake": false, "flake": false,
"locked": { "locked": {
"host": "gitlab.freedesktop.org", "host": "gitlab.freedesktop.org",
"lastModified": 1653733431, "lastModified": 1654618691,
"narHash": "sha256-0JwNH2E9XlMVa7ZCsqxazpKwpZ2rW5QQjbk0DdZxa48=", "narHash": "sha256-8y3u8CoigjoZOVbA2wCWBHlDNEakv0AVxU46/cOC00s=",
"owner": "wlroots", "owner": "wlroots",
"repo": "wlroots", "repo": "wlroots",
"rev": "93ee4c7684050807e959bb3b6d57826a72fba8c2", "rev": "b89ed9015c3fbe8d339e9d65cf70fdca6e5645bc",
"type": "gitlab" "type": "gitlab"
}, },
"original": { "original": {

View File

@@ -16,40 +16,37 @@
}: let }: let
inherit (nixpkgs) lib; inherit (nixpkgs) lib;
genSystems = lib.genAttrs [ genSystems = lib.genAttrs [
# Add more systems if they are supported
"x86_64-linux" "x86_64-linux"
]; ];
pkgsFor = nixpkgs.legacyPackages; pkgsFor = nixpkgs.legacyPackages;
# https://github.com/NixOS/rfcs/pull/107 mkDate = longDate: (lib.concatStringsSep "-" [
mkVersion = longDate: (__substring 0 4 longDate)
lib.concatStrings [ (__substring 4 2 longDate)
"0.pre" (__substring 6 2 longDate)
"+date=" ]);
(lib.concatStringsSep "-" [
(__substring 0 4 longDate)
(__substring 4 2 longDate)
(__substring 6 2 longDate)
])
];
in { in {
packages = genSystems (system: { overlays.default = _: prev: rec {
wlroots = pkgsFor.${system}.wlroots.overrideAttrs (prev: { wlroots-hyprland = prev.wlroots.overrideAttrs (__: {
version = mkVersion inputs.wlroots.lastModifiedDate; version = mkDate (inputs.wlroots.lastModifiedDate or "19700101");
src = inputs.wlroots; src = inputs.wlroots;
}); });
default = pkgsFor.${system}.callPackage ./default.nix { hyprland = prev.callPackage ./nix/default.nix {
version = mkVersion self.lastModifiedDate; version = "0.6.0beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101"));
inherit (self.packages.${system}) wlroots; wlroots = wlroots-hyprland;
}; };
}); };
packages = genSystems (system:
(self.overlays.default null pkgsFor.${system})
// {
default = self.packages.${system}.hyprland;
});
formatter = genSystems (system: pkgsFor.${system}.alejandra); formatter = genSystems (system: pkgsFor.${system}.alejandra);
nixosModules.default = import ./module.nix self; nixosModules.default = import ./nix/module.nix self;
# Deprecated overlay = throw "Hyprland: .overlay output is deprecated, please use the .overlays.default output";
overlays.default = _: prev: {
hyprland = self.packages.${prev.system}.default;
};
overlay = self.overlays.default;
}; };
} }

View File

@@ -1,4 +1,4 @@
clean:
rm -rf ./hyprctl ./hyprctl
all: all:
g++ -std=c++20 ./main.cpp -o ./hyprctl g++ -std=c++20 ./main.cpp -o ./hyprctl
clean:
rm ./hyprctl

View File

@@ -15,19 +15,18 @@
#include <fstream> #include <fstream>
#include <string> #include <string>
const std::string USAGE = R"#( const std::string USAGE = R"#(usage: hyprctl [command] [(opt)args]
usage: hyprctl [command] [(opt)args]
monitors monitors
workspaces workspaces
clients clients
activewindow activewindow
layers layers
devices
dispatch dispatch
keyword keyword
version version
reload reload)#";
)#";
void request(std::string arg) { void request(std::string arg) {
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0); const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
@@ -44,12 +43,25 @@ void request(std::string arg) {
return; return;
} }
// get the instance signature
auto instanceSig = getenv("HYPRLAND_INSTANCE_SIGNATURE");
if (!instanceSig) {
std::cout << "HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)";
return;
}
std::string instanceSigStr = std::string(instanceSig);
sockaddr_un serverAddress = {0}; sockaddr_un serverAddress = {0};
serverAddress.sun_family = AF_UNIX; serverAddress.sun_family = AF_UNIX;
strcpy(serverAddress.sun_path, "/tmp/hypr/.socket.sock");
std::string socketPath = "/tmp/hypr/" + instanceSigStr + "/.socket.sock";
strcpy(serverAddress.sun_path, socketPath.c_str());
if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) { if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) {
std::cout << "Couldn't connect to /tmp/hypr/.socket.sock. (3) Is Hyprland running?"; std::cout << "Couldn't connect to " << socketPath << ". (3)";
return; return;
} }
@@ -107,7 +119,7 @@ int main(int argc, char** argv) {
int bflag = 0, sflag = 0, index, c; int bflag = 0, sflag = 0, index, c;
if (argc < 2) { if (argc < 2) {
printf("%s", USAGE.c_str()); printf("%s\n", USAGE.c_str());
return 1; return 1;
} }
@@ -117,14 +129,17 @@ int main(int argc, char** argv) {
else if (!strcmp(argv[1], "activewindow")) request("activewindow"); else if (!strcmp(argv[1], "activewindow")) request("activewindow");
else if (!strcmp(argv[1], "layers")) request("layers"); else if (!strcmp(argv[1], "layers")) request("layers");
else if (!strcmp(argv[1], "version")) request("version"); else if (!strcmp(argv[1], "version")) request("version");
else if (!strcmp(argv[1], "devices")) request("devices");
else if (!strcmp(argv[1], "reload")) request("reload"); else if (!strcmp(argv[1], "reload")) request("reload");
else if (!strcmp(argv[1], "dispatch")) dispatchRequest(argc, argv); else if (!strcmp(argv[1], "dispatch")) dispatchRequest(argc, argv);
else if (!strcmp(argv[1], "keyword")) keywordRequest(argc, argv); else if (!strcmp(argv[1], "keyword")) keywordRequest(argc, argv);
else if (!strcmp(argv[1], "--batch")) batchRequest(argc, argv); else if (!strcmp(argv[1], "--batch")) batchRequest(argc, argv);
else if (!strcmp(argv[1], "--help")) printf("%s", USAGE.c_str());
else { else {
printf("%s", USAGE.c_str()); printf("%s\n", USAGE.c_str());
return 1; return 1;
} }
printf("\n");
return 0; return 0;
} }

3
hyprctl/meson.build Normal file
View File

@@ -0,0 +1,3 @@
executable('hyprctl', 'main.cpp',
install: true
)

26
meson.build Normal file
View File

@@ -0,0 +1,26 @@
project('Hyprland', 'cpp', 'c',
version : '0.6.0beta',
default_options : ['warning_level=3', 'cpp_std=c++20', 'default_library=static'])
wlroots = subproject('wlroots', default_options: ['examples=false'])
have_xwlr = wlroots.get_variable('features').get('xwayland')
xcb_dep = dependency('xcb', required: get_option('xwayland'))
if get_option('xwayland').enabled() and not have_xwlr
error('Cannot enable Xwayland in Hyprland: wlroots has been built without Xwayland support')
endif
have_xwayland = xcb_dep.found() and have_xwlr
if not have_xwayland
add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
endif
if get_option('buildtype') == 'debug'
add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp')
endif
subdir('protocols')
subdir('src')
subdir('hyprctl')
subdir('assets')
subdir('example')

1
meson_options.txt Normal file
View File

@@ -0,0 +1 @@
option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications')

View File

@@ -3,7 +3,7 @@
stdenv, stdenv,
fetchFromGitHub, fetchFromGitHub,
pkg-config, pkg-config,
cmake, meson,
ninja, ninja,
libdrm, libdrm,
libinput, libinput,
@@ -24,10 +24,10 @@
stdenv.mkDerivation { stdenv.mkDerivation {
pname = "hyprland"; pname = "hyprland";
inherit version; inherit version;
src = ./.; src = ../.;
nativeBuildInputs = [ nativeBuildInputs = [
cmake meson
ninja ninja
pkg-config pkg-config
]; ];
@@ -48,29 +48,14 @@ stdenv.mkDerivation {
] ]
++ lib.optional enableXWayland xwayland; ++ lib.optional enableXWayland xwayland;
cmakeFlags = mesonBuildType = "release";
["-DCMAKE_BUILD_TYPE=Release"]
++ lib.optional (!enableXWayland) "-DNO_XWAYLAND=true";
prePatch = '' mesonFlags = lib.optional (!enableXWayland) "-DNO_XWAYLAND=true";
make config
'';
postBuild = '' patches = [
pushd ../hyprctl # make meson use the provided wlroots instead of the git submodule
make all ./meson-build.patch
popd ];
'';
installPhase = ''
pushd ..
install -Dm644 ./example/hyprland.desktop -t $out/share/wayland-sessions
install -Dm755 ./build/Hyprland -t $out/bin
install -Dm755 ./hyprctl/hyprctl -t $out/bin
install -Dm644 ./assets/* -t $out/share/hyprland
install -Dm644 ./example/hyprland.conf -t $out/share/hyprland
popd
'';
passthru.providedSessions = ["hyprland"]; passthru.providedSessions = ["hyprland"];

36
nix/meson-build.patch Normal file
View File

@@ -0,0 +1,36 @@
diff --git a/meson.build b/meson.build
index 22ee4bf..5528613 100644
--- a/meson.build
+++ b/meson.build
@@ -2,16 +2,10 @@ project('Hyprland', 'cpp', 'c',
version : '0.1',
default_options : ['warning_level=3', 'cpp_std=c++20', 'default_library=static'])
-wlroots = subproject('wlroots', default_options: ['examples=false'])
-have_xwlr = wlroots.get_variable('features').get('xwayland')
+wlroots = dependency('wlroots', version: '>=0.16.0')
xcb_dep = dependency('xcb', required: get_option('xwayland'))
-if get_option('xwayland').enabled() and not have_xwlr
- error('Cannot enable Xwayland in Hyprland: wlroots has been built without Xwayland support')
-endif
-have_xwayland = xcb_dep.found() and have_xwlr
-
-if not have_xwayland
+if not xcb_dep.found()
add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
endif
diff --git a/src/meson.build b/src/meson.build
index 5d64188..a676333 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -7,7 +7,7 @@ executable('Hyprland', src,
server_protos,
dependency('wayland-server'),
dependency('wayland-client'),
- wlroots.get_variable('wlroots'),
+ wlroots,
dependency('cairo'),
dependency('pango'),
dependency('pangocairo'),

View File

@@ -19,7 +19,7 @@ in {
package = mkOption { package = mkOption {
type = types.package; type = types.package;
default = self.packages.${pkgs.system}.default; default = pkgs.hyprland or self.packages.${pkgs.system}.default;
defaultText = literalExpression "<Hyprland flake>.packages.<system>.default"; defaultText = literalExpression "<Hyprland flake>.packages.<system>.default";
example = literalExpression "<Hyprland flake>.packages.<system>.default.override { }"; example = literalExpression "<Hyprland flake>.packages.<system>.default.override { }";
description = '' description = ''

19
nix/update-inputs.sh Executable file
View File

@@ -0,0 +1,19 @@
#!/usr/bin/env -S nix shell nixpkgs#gawk nixpkgs#git nixpkgs#moreutils nixpkgs#jq -c bash
# get wlroots revision from submodule
SUB_REV=$(git submodule status | awk '{ print substr($1,2)}')
# and from lockfile
CRT_REV=$(jq < flake.lock '.nodes.wlroots.locked.rev' -r)
if [ $SUB_REV != $CRT_REV ]; then
# update nixpkgs to latest version
nix flake lock --update-input nixpkgs
# update wlroots to submodule revision
nix flake lock --override-input wlroots "gitlab:wlroots/wlroots/$SUB_REV?host=gitlab.freedesktop.org"
# remove "dirty" mark from lockfile
jq < flake.lock 'del(.nodes.wlroots.original.rev)' | sponge flake.lock
else
echo "wlroots is up to date!"
fi

51
protocols/meson.build Normal file
View File

@@ -0,0 +1,51 @@
wayland_protos = dependency('wayland-protocols',
version: '>=1.25',
fallback: 'wayland-protocols',
default_options: ['tests=false'],
)
wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
wayland_scanner_dep = dependency('wayland-scanner', native: true)
wayland_scanner = find_program(
wayland_scanner_dep.get_variable('wayland_scanner'),
native: true,
)
protocols = [
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
['wlr-layer-shell-unstable-v1.xml'],
['ext-workspace-unstable-v1.xml'],
['pointer-constraints-unstable-v1.xml'],
['tablet-unstable-v2.xml'],
['idle.xml']
]
wl_protos_src = []
wl_protos_headers = []
foreach p : protocols
xml = join_paths(p)
wl_protos_src += custom_target(
xml.underscorify() + '_server_c',
input: xml,
output: '@BASENAME@-protocol.c',
command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'],
)
wl_protos_headers += custom_target(
xml.underscorify() + '_server_h',
input: xml,
output: '@BASENAME@-protocol.h',
command: [wayland_scanner, 'server-header', '@INPUT@', '@OUTPUT@'],
)
endforeach
wayland_server = dependency('wayland-server', version: '>=1.20.0')
lib_server_protos = static_library(
'server_protos',
wl_protos_src + wl_protos_headers,
dependencies: wayland_server.partial_dependency(compile_args: true),
)
server_protos = declare_dependency(
link_with: lib_server_protos,
sources: wl_protos_headers,
)

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,26 @@
#include "Compositor.hpp" #include "Compositor.hpp"
CCompositor::CCompositor() { CCompositor::CCompositor() {
unlink("/tmp/hypr/hyprland.log"); m_szInstanceSignature = GIT_COMMIT_HASH + std::string("_") + std::to_string(time(NULL));
unlink("/tmp/hypr/hyprlandd.log");
unlink("/tmp/hypr/.hyprlandrq");
system("mkdir -p /tmp/hypr"); Debug::init(m_szInstanceSignature);
Debug::log(LOG, "Instance Signature: %s", m_szInstanceSignature.c_str());
Debug::log(LOG, "===== SYSTEM INFO: =====");
logSystemInfo();
Debug::log(LOG, "========================");
Debug::log(NONE, "\n\n"); // pad
Debug::log(INFO, "If you are crashing, or encounter any bugs, please consult https://github.com/hyprwm/Hyprland/wiki/Crashing-and-bugs\n\n");
setenv("HYPRLAND_INSTANCE_SIGNATURE", m_szInstanceSignature.c_str(), true);
const auto INSTANCEPATH = "/tmp/hypr/" + m_szInstanceSignature;
mkdir(INSTANCEPATH.c_str(), S_IRWXU | S_IRWXG);
m_sWLDisplay = wl_display_create(); m_sWLDisplay = wl_display_create();
@@ -104,6 +119,8 @@ CCompositor::CCompositor() {
m_sWLRVirtPtrMgr = wlr_virtual_pointer_manager_v1_create(m_sWLDisplay); m_sWLRVirtPtrMgr = wlr_virtual_pointer_manager_v1_create(m_sWLDisplay);
m_sWLRToplevelMgr = wlr_foreign_toplevel_manager_v1_create(m_sWLDisplay); m_sWLRToplevelMgr = wlr_foreign_toplevel_manager_v1_create(m_sWLDisplay);
m_sWLRTabletManager = wlr_tablet_v2_create(m_sWLDisplay);
} }
CCompositor::~CCompositor() { CCompositor::~CCompositor() {
@@ -137,6 +154,7 @@ void CCompositor::initAllSignals() {
addWLSignal(&m_sWLRPointerConstraints->events.new_constraint, &Events::listen_newConstraint, m_sWLRPointerConstraints, "PointerConstraints"); addWLSignal(&m_sWLRPointerConstraints->events.new_constraint, &Events::listen_newConstraint, m_sWLRPointerConstraints, "PointerConstraints");
addWLSignal(&m_sWLRXDGDecoMgr->events.new_toplevel_decoration, &Events::listen_NewXDGDeco, m_sWLRXDGDecoMgr, "XDGDecoMgr"); addWLSignal(&m_sWLRXDGDecoMgr->events.new_toplevel_decoration, &Events::listen_NewXDGDeco, m_sWLRXDGDecoMgr, "XDGDecoMgr");
addWLSignal(&m_sWLRVirtPtrMgr->events.new_virtual_pointer, &Events::listen_newVirtPtr, m_sWLRVirtPtrMgr, "VirtPtrMgr"); addWLSignal(&m_sWLRVirtPtrMgr->events.new_virtual_pointer, &Events::listen_newVirtPtr, m_sWLRVirtPtrMgr, "VirtPtrMgr");
addWLSignal(&m_sWLRRenderer->events.destroy, &Events::listen_RendererDestroy, m_sWLRRenderer, "WLRRenderer");
signal(SIGINT, handleCritSignal); signal(SIGINT, handleCritSignal);
signal(SIGTERM, handleCritSignal); signal(SIGTERM, handleCritSignal);
@@ -314,6 +332,15 @@ bool CCompositor::windowExists(CWindow* pWindow) {
CWindow* CCompositor::vectorToWindow(const Vector2D& pos) { CWindow* CCompositor::vectorToWindow(const Vector2D& pos) {
const auto PMONITOR = getMonitorFromVector(pos); const auto PMONITOR = getMonitorFromVector(pos);
if (PMONITOR->specialWorkspaceOpen) {
for (auto& w : m_lWindows) {
wlr_box box = {w.m_vRealPosition.vec().x, w.m_vRealPosition.vec().y, w.m_vRealSize.vec().x, w.m_vRealSize.vec().y};
if (w.m_iWorkspaceID == SPECIAL_WORKSPACE_ID && wlr_box_contains_point(&box, pos.x, pos.y) && w.m_bIsMapped && !w.m_bIsFloating && !w.m_bHidden)
return &w;
}
}
// first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter. // first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
for (auto w = m_lWindows.rbegin(); w != m_lWindows.rend(); w++) { for (auto w = m_lWindows.rbegin(); w != m_lWindows.rend(); w++) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y}; wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
@@ -332,6 +359,15 @@ CWindow* CCompositor::vectorToWindow(const Vector2D& pos) {
CWindow* CCompositor::vectorToWindowTiled(const Vector2D& pos) { CWindow* CCompositor::vectorToWindowTiled(const Vector2D& pos) {
const auto PMONITOR = getMonitorFromVector(pos); const auto PMONITOR = getMonitorFromVector(pos);
if (PMONITOR->specialWorkspaceOpen) {
for (auto& w : m_lWindows) {
wlr_box box = {w.m_vPosition.x, w.m_vPosition.y, w.m_vSize.x, w.m_vSize.y};
if (w.m_iWorkspaceID == SPECIAL_WORKSPACE_ID && wlr_box_contains_point(&box, pos.x, pos.y) && !w.m_bIsFloating && !w.m_bHidden)
return &w;
}
}
for (auto& w : m_lWindows) { for (auto& w : m_lWindows) {
wlr_box box = {w.m_vPosition.x, w.m_vPosition.y, w.m_vSize.x, w.m_vSize.y}; wlr_box box = {w.m_vPosition.x, w.m_vPosition.y, w.m_vSize.x, w.m_vSize.y};
if (w.m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && w.m_iWorkspaceID == PMONITOR->activeWorkspace && !w.m_bIsFloating && !w.m_bHidden) if (w.m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && w.m_iWorkspaceID == PMONITOR->activeWorkspace && !w.m_bIsFloating && !w.m_bHidden)
@@ -343,6 +379,16 @@ CWindow* CCompositor::vectorToWindowTiled(const Vector2D& pos) {
CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) { CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
const auto PMONITOR = getMonitorFromVector(pos); const auto PMONITOR = getMonitorFromVector(pos);
// special workspace
if (PMONITOR->specialWorkspaceOpen) {
for (auto& w : m_lWindows) {
wlr_box box = {w.m_vPosition.x, w.m_vPosition.y, w.m_vSize.x, w.m_vSize.y};
if (w.m_iWorkspaceID == SPECIAL_WORKSPACE_ID && w.m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !w.m_bHidden)
return &w;
}
}
// first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter. // first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
for (auto w = m_lWindows.rbegin(); w != m_lWindows.rend(); w++) { for (auto w = m_lWindows.rbegin(); w != m_lWindows.rend(); w++) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y}; wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
@@ -362,6 +408,14 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
CWindow* CCompositor::windowFromCursor() { CWindow* CCompositor::windowFromCursor() {
const auto PMONITOR = getMonitorFromCursor(); const auto PMONITOR = getMonitorFromCursor();
if (PMONITOR->specialWorkspaceOpen) {
for (auto& w : m_lWindows) {
wlr_box box = {w.m_vPosition.x, w.m_vPosition.y, w.m_vSize.x, w.m_vSize.y};
if (w.m_iWorkspaceID == SPECIAL_WORKSPACE_ID && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w.m_bIsMapped)
return &w;
}
}
// first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter. // first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
for (auto w = m_lWindows.rbegin(); w != m_lWindows.rend(); w++) { for (auto w = m_lWindows.rbegin(); w != m_lWindows.rend(); w++) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y}; wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
@@ -399,7 +453,11 @@ wlr_surface* CCompositor::vectorWindowToSurface(const Vector2D& pos, CWindow* pW
double subx, suby; double subx, suby;
const auto PFOUND = wlr_xdg_surface_surface_at(PSURFACE, pos.x - pWindow->m_vRealPosition.vec().x, pos.y - pWindow->m_vRealPosition.vec().y, &subx, &suby); // calc for oversized windows... fucking bullshit, again.
wlr_box geom;
wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, &geom);
const auto PFOUND = wlr_xdg_surface_surface_at(PSURFACE, pos.x - pWindow->m_vRealPosition.vec().x + geom.x, pos.y - pWindow->m_vRealPosition.vec().y + geom.y, &subx, &suby);
if (PFOUND) { if (PFOUND) {
sl.x = subx; sl.x = subx;
@@ -410,6 +468,9 @@ wlr_surface* CCompositor::vectorWindowToSurface(const Vector2D& pos, CWindow* pW
sl.x = pos.x - pWindow->m_vRealPosition.vec().x; sl.x = pos.x - pWindow->m_vRealPosition.vec().x;
sl.y = pos.y - pWindow->m_vRealPosition.vec().y; sl.y = pos.y - pWindow->m_vRealPosition.vec().y;
sl.x += geom.x;
sl.y += geom.y;
return PSURFACE->surface; return PSURFACE->surface;
} }
@@ -541,11 +602,11 @@ CWindow* CCompositor::getWindowForPopup(wlr_xdg_popup* popup) {
} }
wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::list<SLayerSurface*>* layerSurfaces, Vector2D* sCoords) { wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::list<SLayerSurface*>* layerSurfaces, Vector2D* sCoords) {
for (auto& l : *layerSurfaces) { for (auto it = layerSurfaces->rbegin(); it != layerSurfaces->rend(); it++) {
if (l->fadingOut || (l->layerSurface && !l->layerSurface->mapped)) if ((*it)->fadingOut || !(*it)->layerSurface || ((*it)->layerSurface && !(*it)->layerSurface->mapped))
continue; continue;
const auto SURFACEAT = wlr_layer_surface_v1_surface_at(l->layerSurface, pos.x - l->geometry.x, pos.y - l->geometry.y, &sCoords->x, &sCoords->y); const auto SURFACEAT = wlr_layer_surface_v1_surface_at((*it)->layerSurface, pos.x - (*it)->geometry.x, pos.y - (*it)->geometry.y, &sCoords->x, &sCoords->y);
if (SURFACEAT) if (SURFACEAT)
return SURFACEAT; return SURFACEAT;
@@ -576,6 +637,9 @@ bool CCompositor::isWorkspaceVisible(const int& w) {
for (auto& m : m_lMonitors) { for (auto& m : m_lMonitors) {
if (m.activeWorkspace == w) if (m.activeWorkspace == w)
return true; return true;
if (m.specialWorkspaceOpen && w == SPECIAL_WORKSPACE_ID)
return true;
} }
return false; return false;
@@ -592,7 +656,15 @@ CWorkspace* CCompositor::getWorkspaceByID(const int& id) {
void CCompositor::sanityCheckWorkspaces() { void CCompositor::sanityCheckWorkspaces() {
for (auto it = m_lWorkspaces.begin(); it != m_lWorkspaces.end(); ++it) { for (auto it = m_lWorkspaces.begin(); it != m_lWorkspaces.end(); ++it) {
if (getWindowsOnWorkspace(it->m_iID) == 0 && !isWorkspaceVisible(it->m_iID)) { if ((getWindowsOnWorkspace(it->m_iID) == 0 && !isWorkspaceVisible(it->m_iID))) {
it = m_lWorkspaces.erase(it);
}
if (it->m_iID == SPECIAL_WORKSPACE_ID && getWindowsOnWorkspace(it->m_iID) == 0) {
for (auto& m : m_lMonitors) {
m.specialWorkspaceOpen = false;
}
it = m_lWorkspaces.erase(it); it = m_lWorkspaces.erase(it);
} }
} }
@@ -622,6 +694,9 @@ void CCompositor::fixXWaylandWindowsOnWorkspace(const int& id) {
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id);
if (!PWORKSPACE)
return;
for (auto& w : m_lWindows) { for (auto& w : m_lWindows) {
if (w.m_iWorkspaceID == id) { if (w.m_iWorkspaceID == id) {
@@ -705,18 +780,24 @@ void CCompositor::cleanupFadingOut() {
} }
CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) { CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
const auto POSA = pWindow->m_vPosition;
const auto SIZEA = pWindow->m_vSize; const auto WINDOWIDEALBB = pWindow->getWindowIdealBoundingBoxIgnoreReserved();
const auto POSA = Vector2D(WINDOWIDEALBB.x, WINDOWIDEALBB.y);
const auto SIZEA = Vector2D(WINDOWIDEALBB.width, WINDOWIDEALBB.height);
auto longestIntersect = -1; auto longestIntersect = -1;
CWindow* longestIntersectWindow = nullptr; CWindow* longestIntersectWindow = nullptr;
for (auto& w : m_lWindows) { for (auto& w : m_lWindows) {
if (&w == pWindow || !windowValidMapped(&w) || w.m_bIsFloating || w.m_iWorkspaceID != pWindow->m_iWorkspaceID) if (&w == pWindow || !windowValidMapped(&w) || w.m_bIsFloating || !isWorkspaceVisible(w.m_iWorkspaceID))
continue; continue;
const auto POSB = w.m_vPosition; const auto BWINDOWIDEALBB = w.getWindowIdealBoundingBoxIgnoreReserved();
const auto SIZEB = w.m_vSize;
const auto POSB = Vector2D(BWINDOWIDEALBB.x, BWINDOWIDEALBB.y);
const auto SIZEB = Vector2D(BWINDOWIDEALBB.width, BWINDOWIDEALBB.height);
switch (dir) { switch (dir) {
case 'l': case 'l':
if (STICKS(POSA.x, POSB.x + SIZEB.x)) { if (STICKS(POSA.x, POSB.x + SIZEB.x)) {
@@ -820,8 +901,8 @@ CWorkspace* CCompositor::getWorkspaceByString(const std::string& str) {
} }
try { try {
int id = std::stoi(str); std::string name = "";
return getWorkspaceByID(id); return getWorkspaceByID(getWorkspaceIDFromString(str, name));
} catch (std::exception& e) { } catch (std::exception& e) {
Debug::log(ERR, "Error in getWorkspaceByString, invalid id"); Debug::log(ERR, "Error in getWorkspaceByString, invalid id");
} }
@@ -936,4 +1017,116 @@ void CCompositor::updateWindowBorderColor(CWindow* pWindow) {
pWindow->m_cRealBorderColor = RENDERDATA.borderColor; pWindow->m_cRealBorderColor = RENDERDATA.borderColor;
else else
pWindow->m_cRealBorderColor = CColor(pWindow == m_pLastWindow ? *ACTIVECOL : *INACTIVECOL); pWindow->m_cRealBorderColor = CColor(pWindow == m_pLastWindow ? *ACTIVECOL : *INACTIVECOL);
}
void CCompositor::moveWindowToWorkspace(CWindow* pWindow, const std::string& work) {
m_pLastWindow = pWindow;
g_pKeybindManager->moveActiveToWorkspace(work);
g_pInputManager->refocus();
}
int CCompositor::getNextAvailableMonitorID() {
int64_t topID = -1;
for (auto& m : m_lMonitors) {
if ((int64_t)m.ID > topID)
topID = m.ID;
}
return topID + 1;
}
void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, SMonitor* pMonitor) {
// We trust the workspace and monitor to be correct.
if (pWorkspace->m_iMonitorID == pMonitor->ID)
return;
Debug::log(LOG, "moveWorkspaceToMonitor: Moving %d to monitor %d", pWorkspace->m_iID, pMonitor->ID);
const auto POLDMON = getMonitorFromID(pWorkspace->m_iMonitorID);
const bool SWITCHINGISACTIVE = POLDMON->activeWorkspace == pWorkspace->m_iID;
// fix old mon
int nextWorkspaceOnMonitorID = -1;
for (auto& w : m_lWorkspaces) {
if (w.m_iMonitorID == POLDMON->ID && w.m_iID != pWorkspace->m_iID) {
nextWorkspaceOnMonitorID = w.m_iID;
break;
}
}
if (nextWorkspaceOnMonitorID == -1) {
nextWorkspaceOnMonitorID = 1;
while (getWorkspaceByID(nextWorkspaceOnMonitorID))
nextWorkspaceOnMonitorID++;
Debug::log(LOG, "moveWorkspaceToMonitor: Plugging gap with new %d", nextWorkspaceOnMonitorID);
}
Debug::log(LOG, "moveWorkspaceToMonitor: Plugging gap with existing %d", nextWorkspaceOnMonitorID);
g_pKeybindManager->focusMonitor(std::to_string(POLDMON->ID));
g_pKeybindManager->changeworkspace(std::to_string(nextWorkspaceOnMonitorID));
// move the workspace
pWorkspace->m_iMonitorID = pMonitor->ID;
pWorkspace->moveToMonitor(pMonitor->ID);
for (auto& w : m_lWindows) {
if (w.m_iWorkspaceID == pWorkspace->m_iID)
w.m_iMonitorID = pMonitor->ID;
}
if (SWITCHINGISACTIVE) { // if it was active, preserve its' status. If it wasn't, don't.
Debug::log(LOG, "moveWorkspaceToMonitor: SWITCHINGISACTIVE, active %d -> %d", pMonitor->activeWorkspace, pWorkspace->m_iID);
if (const auto PWORKSPACE = getWorkspaceByID(pMonitor->activeWorkspace); PWORKSPACE)
getWorkspaceByID(pMonitor->activeWorkspace)->startAnim(false, false);
pMonitor->activeWorkspace = pWorkspace->m_iID;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(pMonitor->ID);
pWorkspace->startAnim(true, true, true);
wlr_cursor_warp(m_sWLRCursor, m_sSeat.mouse->mouse, pMonitor->vecPosition.x + pMonitor->vecTransformedSize.x / 2, pMonitor->vecPosition.y + pMonitor->vecTransformedSize.y / 2);
}
// finalize
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(POLDMON->ID);
g_pInputManager->refocus();
}
bool CCompositor::workspaceIDOutOfBounds(const int& id) {
int lowestID = 99999;
int highestID = -99999;
for (auto& w : m_lWorkspaces) {
if (w.m_iID < lowestID)
lowestID = w.m_iID;
if (w.m_iID > highestID)
highestID = w.m_iID;
}
return std::clamp(id, lowestID, highestID) != id;
}
void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode mode) {
if (!windowValidMapped(pWindow))
return;
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(pWindow, mode, on);
g_pXWaylandManager->setWindowFullscreen(pWindow, pWindow->m_bIsFullscreen && mode == FULLSCREEN_FULL);
// make all windows on the same workspace under the fullscreen window
for (auto& w : g_pCompositor->m_lWindows) {
if (w.m_iWorkspaceID == pWindow->m_iWorkspaceID)
w.m_bCreatedOverFullscreen = false;
}
} }

View File

@@ -10,7 +10,7 @@
#include "config/ConfigManager.hpp" #include "config/ConfigManager.hpp"
#include "managers/ThreadManager.hpp" #include "managers/ThreadManager.hpp"
#include "managers/XWaylandManager.hpp" #include "managers/XWaylandManager.hpp"
#include "managers/InputManager.hpp" #include "managers/input/InputManager.hpp"
#include "managers/LayoutManager.hpp" #include "managers/LayoutManager.hpp"
#include "managers/KeybindManager.hpp" #include "managers/KeybindManager.hpp"
#include "managers/AnimationManager.hpp" #include "managers/AnimationManager.hpp"
@@ -59,10 +59,12 @@ public:
wlr_xdg_decoration_manager_v1* m_sWLRXDGDecoMgr; wlr_xdg_decoration_manager_v1* m_sWLRXDGDecoMgr;
wlr_virtual_pointer_manager_v1* m_sWLRVirtPtrMgr; wlr_virtual_pointer_manager_v1* m_sWLRVirtPtrMgr;
wlr_foreign_toplevel_manager_v1* m_sWLRToplevelMgr; wlr_foreign_toplevel_manager_v1* m_sWLRToplevelMgr;
wlr_tablet_manager_v2* m_sWLRTabletManager;
// ------------------------------------------------- // // ------------------------------------------------- //
const char* m_szWLDisplaySocket; const char* m_szWLDisplaySocket;
std::string m_szInstanceSignature = "";
std::list<SMonitor> m_lMonitors; std::list<SMonitor> m_lMonitors;
std::list<CWindow> m_lWindows; std::list<CWindow> m_lWindows;
@@ -126,6 +128,11 @@ public:
SMonitor* getMonitorInDirection(const char&); SMonitor* getMonitorInDirection(const char&);
void updateAllWindowsBorders(); void updateAllWindowsBorders();
void updateWindowBorderColor(CWindow*); void updateWindowBorderColor(CWindow*);
void moveWindowToWorkspace(CWindow*, const std::string&);
int getNextAvailableMonitorID();
void moveWorkspaceToMonitor(CWorkspace*, SMonitor*);
bool workspaceIDOutOfBounds(const int&);
void setWindowFullscreen(CWindow*, bool, eFullscreenMode);
private: private:
void initAllSignals(); void initAllSignals();

View File

@@ -1,11 +1,14 @@
#include "Window.hpp" #include "Window.hpp"
#include "Compositor.hpp" #include "Compositor.hpp"
#include "render/decorations/CHyprDropShadowDecoration.hpp"
CWindow::CWindow() { CWindow::CWindow() {
m_vRealPosition.create(AVARTYPE_VECTOR, &g_pConfigManager->getConfigValuePtr("animations:windows_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:windows")->intValue, &g_pConfigManager->getConfigValuePtr("animations:windows_curve")->strValue, (void*) this, AVARDAMAGE_ENTIRE); m_vRealPosition.create(AVARTYPE_VECTOR, &g_pConfigManager->getConfigValuePtr("animations:windows_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:windows")->intValue, &g_pConfigManager->getConfigValuePtr("animations:windows_curve")->strValue, (void*) this, AVARDAMAGE_ENTIRE);
m_vRealSize.create(AVARTYPE_VECTOR, &g_pConfigManager->getConfigValuePtr("animations:windows_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:windows")->intValue, &g_pConfigManager->getConfigValuePtr("animations:windows_curve")->strValue, (void*)this, AVARDAMAGE_ENTIRE); m_vRealSize.create(AVARTYPE_VECTOR, &g_pConfigManager->getConfigValuePtr("animations:windows_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:windows")->intValue, &g_pConfigManager->getConfigValuePtr("animations:windows_curve")->strValue, (void*)this, AVARDAMAGE_ENTIRE);
m_cRealBorderColor.create(AVARTYPE_COLOR, &g_pConfigManager->getConfigValuePtr("animations:borders_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:borders")->intValue, &g_pConfigManager->getConfigValuePtr("animations:borders_curve")->strValue, (void*)this, AVARDAMAGE_BORDER); m_cRealBorderColor.create(AVARTYPE_COLOR, &g_pConfigManager->getConfigValuePtr("animations:borders_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:borders")->intValue, &g_pConfigManager->getConfigValuePtr("animations:borders_curve")->strValue, (void*)this, AVARDAMAGE_BORDER);
m_fAlpha.create(AVARTYPE_FLOAT, &g_pConfigManager->getConfigValuePtr("animations:fadein_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:fadein")->intValue, &g_pConfigManager->getConfigValuePtr("animations:fadein_curve")->strValue, (void*)this, AVARDAMAGE_ENTIRE); m_fAlpha.create(AVARTYPE_FLOAT, &g_pConfigManager->getConfigValuePtr("animations:fadein_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:fadein")->intValue, &g_pConfigManager->getConfigValuePtr("animations:fadein_curve")->strValue, (void*)this, AVARDAMAGE_ENTIRE);
m_dWindowDecorations.emplace_back(std::make_unique<CHyprDropShadowDecoration>(this)); // put the shadow so it's the first deco (has to be rendered first)
} }
CWindow::~CWindow() { CWindow::~CWindow() {
@@ -13,4 +16,60 @@ CWindow::~CWindow() {
g_pCompositor->m_pLastFocus = nullptr; g_pCompositor->m_pLastFocus = nullptr;
g_pCompositor->m_pLastWindow = nullptr; g_pCompositor->m_pLastWindow = nullptr;
} }
}
wlr_box CWindow::getFullWindowBoundingBox() {
static auto* const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
SWindowDecorationExtents maxExtents = {{*PBORDERSIZE + 1, *PBORDERSIZE + 1}, {*PBORDERSIZE + 1, *PBORDERSIZE + 1}};
for (auto& wd : m_dWindowDecorations) {
const auto EXTENTS = wd->getWindowDecorationExtents();
if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
maxExtents.topLeft.x = EXTENTS.topLeft.x;
if (EXTENTS.topLeft.y > maxExtents.topLeft.y)
maxExtents.topLeft.y = EXTENTS.topLeft.y;
if (EXTENTS.bottomRight.x > maxExtents.bottomRight.x)
maxExtents.bottomRight.x = EXTENTS.bottomRight.x;
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
}
// Add extents to the real base BB and return
wlr_box finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x,
m_vRealPosition.vec().y - maxExtents.topLeft.y,
m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x,
m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
return finalBox;
}
wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
auto POS = m_vPosition;
auto SIZE = m_vSize;
if (DELTALESSTHAN(POS.y - PMONITOR->vecPosition.y, PMONITOR->vecReservedTopLeft.y, 1)) {
POS.y = PMONITOR->vecPosition.y;
SIZE.y += PMONITOR->vecReservedTopLeft.y;
}
if (DELTALESSTHAN(POS.x - PMONITOR->vecPosition.x, PMONITOR->vecReservedTopLeft.x, 1)) {
POS.x = PMONITOR->vecPosition.x;
SIZE.x += PMONITOR->vecReservedTopLeft.x;
}
if (DELTALESSTHAN(POS.x + SIZE.x - PMONITOR->vecPosition.x, PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x, 1)) {
SIZE.x += PMONITOR->vecReservedBottomRight.x;
}
if (DELTALESSTHAN(POS.y + SIZE.y - PMONITOR->vecPosition.y, PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y, 1)) {
SIZE.y += PMONITOR->vecReservedBottomRight.y;
}
return wlr_box{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
} }

View File

@@ -9,11 +9,13 @@
struct SWindowSpecialRenderData { struct SWindowSpecialRenderData {
float alpha = 1.f; float alpha = 1.f;
float alphaInactive = -1.f; // -1 means unset
}; };
struct SWindowAdditionalConfigData { struct SWindowAdditionalConfigData {
std::string animationStyle = ""; std::string animationStyle = "";
int rounding = -1; // -1 means no int rounding = -1; // -1 means no
bool forceNoBlur = false;
}; };
class CWindow { class CWindow {
@@ -74,6 +76,7 @@ public:
// For nofocus // For nofocus
bool m_bNoFocus = false; bool m_bNoFocus = false;
bool m_bNoInitialFocus = false;
SSurfaceTreeNode* m_pSurfaceTree = nullptr; SSurfaceTreeNode* m_pSurfaceTree = nullptr;
@@ -105,4 +108,8 @@ public:
return m_uSurface.xdg == rhs.m_uSurface.xdg && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && m_bFadingOut == rhs.m_bFadingOut; return m_uSurface.xdg == rhs.m_uSurface.xdg && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && m_bFadingOut == rhs.m_bFadingOut;
} }
}; // methods
wlr_box getFullWindowBoundingBox();
wlr_box getWindowIdealBoundingBoxIgnoreReserved();
};

View File

@@ -18,20 +18,22 @@ CConfigManager::CConfigManager() {
} }
void CConfigManager::setDefaultVars() { void CConfigManager::setDefaultVars() {
configValues["general:max_fps"].intValue = 240; configValues["general:max_fps"].intValue = 60;
configValues["general:sensitivity"].floatValue = 0.25f; configValues["general:sensitivity"].floatValue = 1.0f;
configValues["general:apply_sens_to_raw"].intValue = 1; configValues["general:apply_sens_to_raw"].intValue = 0;
configValues["general:main_mod"].strValue = "SUPER"; // exposed to the user for easier configuring configValues["general:main_mod"].strValue = "SUPER"; // exposed to the user for easier configuring
configValues["general:main_mod_internal"].intValue = g_pKeybindManager->stringToModMask("SUPER"); // actually used and automatically calculated configValues["general:main_mod_internal"].intValue = g_pKeybindManager->stringToModMask("SUPER"); // actually used and automatically calculated
configValues["general:damage_tracking"].strValue = "none"; configValues["general:damage_tracking"].strValue = "full";
configValues["general:damage_tracking_internal"].intValue = DAMAGE_TRACKING_NONE; configValues["general:damage_tracking_internal"].intValue = DAMAGE_TRACKING_FULL;
configValues["general:border_size"].intValue = 1; configValues["general:border_size"].intValue = 1;
configValues["general:no_border_on_floating"].intValue = 0;
configValues["general:gaps_in"].intValue = 5; configValues["general:gaps_in"].intValue = 5;
configValues["general:gaps_out"].intValue = 20; configValues["general:gaps_out"].intValue = 20;
configValues["general:col.active_border"].intValue = 0xffffffff; configValues["general:col.active_border"].intValue = 0xffffffff;
configValues["general:col.inactive_border"].intValue = 0xff444444; configValues["general:col.inactive_border"].intValue = 0xff444444;
configValues["general:cursor_inactive_timeout"].intValue = 0;
configValues["debug:int"].intValue = 0; configValues["debug:int"].intValue = 0;
configValues["debug:log_damage"].intValue = 0; configValues["debug:log_damage"].intValue = 0;
@@ -45,12 +47,20 @@ void CConfigManager::setDefaultVars() {
configValues["decoration:active_opacity"].floatValue = 1; configValues["decoration:active_opacity"].floatValue = 1;
configValues["decoration:inactive_opacity"].floatValue = 1; configValues["decoration:inactive_opacity"].floatValue = 1;
configValues["decoration:fullscreen_opacity"].floatValue = 1; configValues["decoration:fullscreen_opacity"].floatValue = 1;
configValues["decoration:multisample_edges"].intValue = 1;
configValues["decoration:no_blur_on_oversized"].intValue = 1;
configValues["decoration:drop_shadow"].intValue = 1;
configValues["decoration:shadow_range"].intValue = 4;
configValues["decoration:shadow_render_power"].intValue = 3;
configValues["decoration:shadow_ignore_window"].intValue = 1;
configValues["decoration:col.shadow"].intValue = 0xee1a1a1a;
configValues["dwindle:pseudotile"].intValue = 0; configValues["dwindle:pseudotile"].intValue = 0;
configValues["dwindle:col.group_border"].intValue = 0x66777700; configValues["dwindle:col.group_border"].intValue = 0x66777700;
configValues["dwindle:col.group_border_active"].intValue = 0x66ffff00; configValues["dwindle:col.group_border_active"].intValue = 0x66ffff00;
configValues["dwindle:force_split"].intValue = 0; configValues["dwindle:force_split"].intValue = 0;
configValues["dwindle:preserve_split"].intValue = 0; configValues["dwindle:preserve_split"].intValue = 0;
configValues["dwindle:special_scale_factor"].floatValue = 0.8f;
configValues["animations:enabled"].intValue = 1; configValues["animations:enabled"].intValue = 1;
configValues["animations:speed"].floatValue = 7.f; configValues["animations:speed"].floatValue = 7.f;
@@ -72,7 +82,7 @@ void CConfigManager::setDefaultVars() {
configValues["animations:workspaces_speed"].floatValue = 0.f; configValues["animations:workspaces_speed"].floatValue = 0.f;
configValues["animations:workspaces"].intValue = 1; configValues["animations:workspaces"].intValue = 1;
configValues["input:kb_layout"].strValue = "en"; configValues["input:kb_layout"].strValue = "us";
configValues["input:kb_variant"].strValue = STRVAL_EMPTY; configValues["input:kb_variant"].strValue = STRVAL_EMPTY;
configValues["input:kb_options"].strValue = STRVAL_EMPTY; configValues["input:kb_options"].strValue = STRVAL_EMPTY;
configValues["input:kb_rules"].strValue = STRVAL_EMPTY; configValues["input:kb_rules"].strValue = STRVAL_EMPTY;
@@ -80,7 +90,13 @@ void CConfigManager::setDefaultVars() {
configValues["input:repeat_rate"].intValue = 25; configValues["input:repeat_rate"].intValue = 25;
configValues["input:repeat_delay"].intValue = 600; configValues["input:repeat_delay"].intValue = 600;
configValues["input:natural_scroll"].intValue = 0; configValues["input:natural_scroll"].intValue = 0;
configValues["input:numlock_by_default"].intValue = 0;
configValues["input:force_no_accel"].intValue = 0;
configValues["input:touchpad:natural_scroll"].intValue = 0;
configValues["input:touchpad:disable_while_typing"].intValue = 1; configValues["input:touchpad:disable_while_typing"].intValue = 1;
configValues["input:touchpad:clickfinger_behavior"].intValue = 0;
configValues["input:touchpad:middle_button_emulation"].intValue = 0;
configValues["input:touchpad:tap-to-click"].intValue = 1;
configValues["input:follow_mouse"].intValue = 1; configValues["input:follow_mouse"].intValue = 1;
@@ -152,11 +168,57 @@ void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::s
void CConfigManager::handleRawExec(const std::string& command, const std::string& args) { void CConfigManager::handleRawExec(const std::string& command, const std::string& args) {
// Exec in the background dont wait for it. // Exec in the background dont wait for it.
if (fork() == 0) {
execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr);
std::string toExec = args;
if (g_pXWaylandManager->m_sWLRXWayland)
toExec = std::string("WAYLAND_DISPLAY=") + std::string(g_pCompositor->m_szWLDisplaySocket) + " DISPLAY=" + std::string(g_pXWaylandManager->m_sWLRXWayland->display_name) + " " + toExec;
else
toExec = std::string("WAYLAND_DISPLAY=") + std::string(g_pCompositor->m_szWLDisplaySocket) + " " + toExec;
Debug::log(LOG, "Config executing %s", toExec.c_str());
int socket[2];
if (pipe(socket) != 0) {
Debug::log(LOG, "Unable to create pipe for fork");
}
pid_t child, grandchild;
child = fork();
if (child < 0) {
close(socket[0]);
close(socket[1]);
Debug::log(LOG, "Fail to create the first fork");
return;
}
if (child == 0) {
// run in child
grandchild = fork();
if (grandchild == 0) {
// run in grandchild
close(socket[0]);
close(socket[1]);
execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr);
// exit grandchild
_exit(0);
}
close(socket[0]);
write(socket[1], &grandchild, sizeof(grandchild));
close(socket[1]);
// exit child
_exit(0); _exit(0);
} }
// run in parent
close(socket[1]);
read(socket[0], &grandchild, sizeof(grandchild));
close(socket[0]);
// clear child and leave child to init
waitpid(child, NULL, 0);
if (child < 0) {
Debug::log(LOG, "Fail to create the second fork");
return;
}
Debug::log(LOG, "Process created with pid %d", grandchild);
} }
void CConfigManager::handleMonitor(const std::string& command, const std::string& args) { void CConfigManager::handleMonitor(const std::string& command, const std::string& args) {
@@ -361,7 +423,7 @@ void CConfigManager::handleAnimation(const std::string& command, const std::stri
configSetValueSafe("animations:" + ANIMNAME + "_style", curitem); configSetValueSafe("animations:" + ANIMNAME + "_style", curitem);
} }
void CConfigManager::handleBind(const std::string& command, const std::string& value) { void CConfigManager::handleBind(const std::string& command, const std::string& value, bool locked) {
// example: // example:
// bind=SUPER,G,exec,dmenu_run <args> // bind=SUPER,G,exec,dmenu_run <args>
@@ -394,7 +456,7 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v
} }
if (KEY != "") if (KEY != "")
g_pKeybindManager->addKeybind(SKeybind{KEY, MOD, HANDLER, COMMAND}); g_pKeybindManager->addKeybind(SKeybind{KEY, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap});
} }
void CConfigManager::handleUnbind(const std::string& command, const std::string& value) { void CConfigManager::handleUnbind(const std::string& command, const std::string& value) {
@@ -425,7 +487,9 @@ void CConfigManager::handleWindowRule(const std::string& command, const std::str
&& RULE.find("size") != 0 && RULE.find("size") != 0
&& RULE.find("pseudo") != 0 && RULE.find("pseudo") != 0
&& RULE.find("monitor") != 0 && RULE.find("monitor") != 0
&& RULE.find("nofocus") != 0 && RULE != "nofocus"
&& RULE != "noblur"
&& RULE != "fullscreen"
&& RULE.find("animation") != 0 && RULE.find("animation") != 0
&& RULE.find("rounding") != 0 && RULE.find("rounding") != 0
&& RULE.find("workspace") != 0) { && RULE.find("workspace") != 0) {
@@ -441,16 +505,23 @@ void CConfigManager::handleWindowRule(const std::string& command, const std::str
void CConfigManager::handleDefaultWorkspace(const std::string& command, const std::string& value) { void CConfigManager::handleDefaultWorkspace(const std::string& command, const std::string& value) {
const auto DISPLAY = value.substr(0, value.find_first_of(',')); const auto DISPLAY = value.substr(0, value.find_first_of(','));
const auto WORKSPACEID = stoi(value.substr(value.find_first_of(',') + 1)); const auto WORKSPACE = value.substr(value.find_first_of(',') + 1);
for (auto& mr : m_dMonitorRules) { for (auto& mr : m_dMonitorRules) {
if (mr.name == DISPLAY) { if (mr.name == DISPLAY) {
mr.defaultWorkspaceID = WORKSPACEID; mr.defaultWorkspace = WORKSPACE;
break; break;
} }
} }
} }
void CConfigManager::handleSubmap(const std::string& command, const std::string& submap) {
if (submap == "reset")
m_szCurrentSubmap = "";
else
m_szCurrentSubmap = submap;
}
void CConfigManager::handleSource(const std::string& command, const std::string& rawpath) { void CConfigManager::handleSource(const std::string& command, const std::string& rawpath) {
static const char* const ENVHOME = getenv("HOME"); static const char* const ENVHOME = getenv("HOME");
@@ -524,12 +595,14 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
} }
else if (COMMAND == "monitor") handleMonitor(COMMAND, VALUE); else if (COMMAND == "monitor") handleMonitor(COMMAND, VALUE);
else if (COMMAND == "bind") handleBind(COMMAND, VALUE); else if (COMMAND == "bind") handleBind(COMMAND, VALUE);
else if (COMMAND == "bindl") handleBind(COMMAND, VALUE, true);
else if (COMMAND == "unbind") handleUnbind(COMMAND, VALUE); else if (COMMAND == "unbind") handleUnbind(COMMAND, VALUE);
else if (COMMAND == "workspace") handleDefaultWorkspace(COMMAND, VALUE); else if (COMMAND == "workspace") handleDefaultWorkspace(COMMAND, VALUE);
else if (COMMAND == "windowrule") handleWindowRule(COMMAND, VALUE); else if (COMMAND == "windowrule") handleWindowRule(COMMAND, VALUE);
else if (COMMAND == "bezier") handleBezier(COMMAND, VALUE); else if (COMMAND == "bezier") handleBezier(COMMAND, VALUE);
else if (COMMAND == "animation") handleAnimation(COMMAND, VALUE); else if (COMMAND == "animation") handleAnimation(COMMAND, VALUE);
else if (COMMAND == "source") handleSource(COMMAND, VALUE); else if (COMMAND == "source") handleSource(COMMAND, VALUE);
else if (COMMAND == "submap") handleSubmap(COMMAND, VALUE);
else else
configSetValueSafe(currentCategory + (currentCategory == "" ? "" : ":") + COMMAND, VALUE); configSetValueSafe(currentCategory + (currentCategory == "" ? "" : ":") + COMMAND, VALUE);
@@ -636,7 +709,8 @@ void CConfigManager::loadConfigLoadVars() {
configPaths.clear(); configPaths.clear();
static const char* const ENVHOME = getenv("HOME"); static const char* const ENVHOME = getenv("HOME");
const std::string CONFIGPATH = ENVHOME + (ISDEBUG ? (std::string) "/.config/hypr/hyprlandd.conf" : (std::string) "/.config/hypr/hyprland.conf"); const std::string CONFIGPARENTPATH = ENVHOME + (std::string) "/.config/hypr/";
const std::string CONFIGPATH = CONFIGPARENTPATH + (ISDEBUG ? "hyprlandd.conf" : "hyprland.conf");
configPaths.push_back(CONFIGPATH); configPaths.push_back(CONFIGPATH);
@@ -649,6 +723,15 @@ void CConfigManager::loadConfigLoadVars() {
std::filesystem::rename(CONFIGPATH, CONFIGPATH + ".backup"); std::filesystem::rename(CONFIGPATH, CONFIGPATH + ".backup");
} catch(...) { /* Probably doesn't exist */} } catch(...) { /* Probably doesn't exist */}
try {
if (!std::filesystem::is_directory(CONFIGPARENTPATH))
std::filesystem::create_directories(CONFIGPARENTPATH);
}
catch (...) {
parseError = "Broken config file! (Could not create directory)";
return;
}
std::ofstream ofs; std::ofstream ofs;
ofs.open(CONFIGPATH, std::ios::trunc); ofs.open(CONFIGPATH, std::ios::trunc);
@@ -836,15 +919,26 @@ std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
std::string title = g_pXWaylandManager->getTitle(pWindow); std::string title = g_pXWaylandManager->getTitle(pWindow);
std::string appidclass = g_pXWaylandManager->getAppIDClass(pWindow); std::string appidclass = g_pXWaylandManager->getAppIDClass(pWindow);
Debug::log(LOG, "Searching for matching rules for %s (title: %s)", appidclass.c_str(), title.c_str());
for (auto& rule : m_dWindowRules) { for (auto& rule : m_dWindowRules) {
// check if we have a matching rule // check if we have a matching rule
try { try {
std::regex classCheck(rule.szValue); if (rule.szValue.find("title:") == 0) {
// we have a title rule.
std::regex RULECHECK(rule.szValue.substr(6));
if (!std::regex_search(title, classCheck) && !std::regex_search(appidclass, classCheck)) if (!std::regex_search(title, RULECHECK))
continue; continue;
} else {
std::regex classCheck(rule.szValue);
if (!std::regex_search(appidclass, classCheck))
continue;
}
} catch (...) { } catch (...) {
Debug::log(ERR, "Regex error at %s", rule.szValue.c_str()); Debug::log(ERR, "Regex error at %s", rule.szValue.c_str());
continue;
} }
// applies. Read the rule and behave accordingly // applies. Read the rule and behave accordingly

View File

@@ -28,7 +28,7 @@ struct SMonitorRule {
Vector2D offset = Vector2D(0,0); Vector2D offset = Vector2D(0,0);
float scale = 1; float scale = 1;
float refreshRate = 60; float refreshRate = 60;
int defaultWorkspaceID = -1; std::string defaultWorkspace = "";
bool disabled = false; bool disabled = false;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
}; };
@@ -88,6 +88,8 @@ private:
std::string parseError = ""; // For storing a parse error to display later std::string parseError = ""; // For storing a parse error to display later
std::string m_szCurrentSubmap = ""; // For storing the current keybind submap
bool isFirstLaunch = true; // For exec-once bool isFirstLaunch = true; // For exec-once
std::deque<SMonitorRule> m_dMonitorRules; std::deque<SMonitorRule> m_dMonitorRules;
@@ -106,13 +108,14 @@ private:
void configSetValueSafe(const std::string&, const std::string&); void configSetValueSafe(const std::string&, const std::string&);
void handleRawExec(const std::string&, const std::string&); void handleRawExec(const std::string&, const std::string&);
void handleMonitor(const std::string&, const std::string&); void handleMonitor(const std::string&, const std::string&);
void handleBind(const std::string&, const std::string&); void handleBind(const std::string&, const std::string&, bool locked = false);
void handleUnbind(const std::string&, const std::string&); void handleUnbind(const std::string&, const std::string&);
void handleWindowRule(const std::string&, const std::string&); void handleWindowRule(const std::string&, const std::string&);
void handleDefaultWorkspace(const std::string&, const std::string&); void handleDefaultWorkspace(const std::string&, const std::string&);
void handleBezier(const std::string&, const std::string&); void handleBezier(const std::string&, const std::string&);
void handleAnimation(const std::string&, const std::string&); void handleAnimation(const std::string&, const std::string&);
void handleSource(const std::string&, const std::string&); void handleSource(const std::string&, const std::string&);
void handleSubmap(const std::string&, const std::string&);
}; };
inline std::unique_ptr<CConfigManager> g_pConfigManager; inline std::unique_ptr<CConfigManager> g_pConfigManager;

View File

@@ -24,8 +24,7 @@ input {
} }
general { general {
max_fps=60 # deprecated, unused sensitivity=1.0 # for mouse cursor
sensitivity=0.25
main_mod=SUPER main_mod=SUPER
gaps_in=5 gaps_in=5
@@ -34,7 +33,9 @@ general {
col.active_border=0x66ee1111 col.active_border=0x66ee1111
col.inactive_border=0x66333333 col.inactive_border=0x66333333
damage_tracking=full # experimental, monitor is 100% fine, but full might have some minor bugs, especially with high blur settings! apply_sens_to_raw=0 # whether to apply the sensitivity to raw input (e.g. used by games where you aim using your mouse)
damage_tracking=full # leave it on full unless you hate your GPU and want to make it suffer
} }
decoration { decoration {

View File

@@ -26,8 +26,9 @@ std::string monitorsRequest() {
std::string clientsRequest() { std::string clientsRequest() {
std::string result = ""; std::string result = "";
for (auto& w : g_pCompositor->m_lWindows) { for (auto& w : g_pCompositor->m_lWindows) {
result += getFormat("Window %x -> %s:\n\tat: %i,%i\n\tsize: %i, %i\n\tworkspace: %i (%s)\n\tfloating: %i\n\n", if (w.m_bIsMapped)
&w, w.m_szTitle.c_str(), (int)w.m_vRealPosition.vec().x, (int)w.m_vRealPosition.vec().y, (int)w.m_vRealSize.vec().x, (int)w.m_vRealSize.vec().y, w.m_iWorkspaceID, (w.m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(w.m_iWorkspaceID)->m_szName.c_str()), (int)w.m_bIsFloating); result += getFormat("Window %x -> %s:\n\tat: %i,%i\n\tsize: %i,%i\n\tworkspace: %i (%s)\n\tfloating: %i\n\tmonitor: %i\n\tclass: %s\n\n",
&w, w.m_szTitle.c_str(), (int)w.m_vRealPosition.vec().x, (int)w.m_vRealPosition.vec().y, (int)w.m_vRealSize.vec().x, (int)w.m_vRealSize.vec().y, w.m_iWorkspaceID, (w.m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(w.m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w.m_iWorkspaceID)->m_szName.c_str() : std::string("Invalid workspace " + std::to_string(w.m_iWorkspaceID)).c_str()), (int)w.m_bIsFloating, w.m_iMonitorID, g_pXWaylandManager->getAppIDClass(&w).c_str());
} }
return result; return result;
} }
@@ -47,8 +48,8 @@ std::string activeWindowRequest() {
if (!g_pCompositor->windowValidMapped(PWINDOW)) if (!g_pCompositor->windowValidMapped(PWINDOW))
return "Invalid"; return "Invalid";
return getFormat("Window %x -> %s:\n\tat: %i,%i\n\tsize: %i, %i\n\tworkspace: %i (%s)\n\tfloating: %i\n\n", return getFormat("Window %x -> %s:\n\tat: %i,%i\n\tsize: %i,%i\n\tworkspace: %i (%s)\n\tfloating: %i\n\tmonitor: %i\n\tclass: %s\n\n",
PWINDOW, PWINDOW->m_szTitle.c_str(), (int)PWINDOW->m_vRealPosition.vec().x, (int)PWINDOW->m_vRealPosition.vec().y, (int)PWINDOW->m_vRealSize.vec().x, (int)PWINDOW->m_vRealSize.vec().y, PWINDOW->m_iWorkspaceID, (PWINDOW->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_szName.c_str()), (int)PWINDOW->m_bIsFloating); PWINDOW, PWINDOW->m_szTitle.c_str(), (int)PWINDOW->m_vRealPosition.vec().x, (int)PWINDOW->m_vRealPosition.vec().y, (int)PWINDOW->m_vRealSize.vec().x, (int)PWINDOW->m_vRealSize.vec().y, PWINDOW->m_iWorkspaceID, (PWINDOW->m_iWorkspaceID == -1 ? "" : g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID)->m_szName.c_str()), (int)PWINDOW->m_bIsFloating, (int)PWINDOW->m_iMonitorID, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str());
} }
std::string layersRequest() { std::string layersRequest() {
@@ -72,6 +73,38 @@ std::string layersRequest() {
return result; return result;
} }
std::string devicesRequest() {
std::string result = "";
result += "mice:\n";
for (auto& m : g_pInputManager->m_lMice) {
result += getFormat("\tMouse at %x:\n\t\t%s\n", &m, m.mouse->name);
}
result += "\n\nKeyboards:\n";
for (auto& k : g_pInputManager->m_lKeyboards) {
result += getFormat("\tKeyboard at %x:\n\t\t%s\n", &k, k.keyboard->name);
}
result += "\n\nTablets:\n";
for (auto& d : g_pInputManager->m_lTabletPads) {
result += getFormat("\tTablet Pad at %x (belongs to %x -> %s)\n", &d, d.pTabletParent, d.pTabletParent ? d.pTabletParent->wlrDevice ? d.pTabletParent->wlrDevice->name : "" : "");
}
for (auto& d : g_pInputManager->m_lTablets) {
result += getFormat("\tTablet at %x:\n\t\t%s\n", &d, d.wlrDevice ? d.wlrDevice->name : "");
}
for (auto& d : g_pInputManager->m_lTabletTools) {
result += getFormat("\tTablet Tool at %x (belongs to %x)\n", &d, d.wlrTabletTool ? d.wlrTabletTool->data : 0);
}
return result;
}
std::string versionRequest() { std::string versionRequest() {
std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + GIT_DIRTY + " (" + GIT_COMMIT_MESSAGE + ").\nflags: (if any)\n"; std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + GIT_DIRTY + " (" + GIT_COMMIT_MESSAGE + ").\nflags: (if any)\n";
@@ -81,6 +114,9 @@ std::string versionRequest() {
#ifndef NDEBUG #ifndef NDEBUG
result += "debug\n"; result += "debug\n";
#endif #endif
#ifdef HYPRLAND_DEBUG
result += "debug\n";
#endif
#ifdef NO_XWAYLAND #ifdef NO_XWAYLAND
result += "no xwayland\n"; result += "no xwayland\n";
#endif #endif
@@ -186,6 +222,8 @@ std::string getReply(std::string request) {
return versionRequest(); return versionRequest();
else if (request == "reload") else if (request == "reload")
return reloadRequest(); return reloadRequest();
else if (request == "devices")
return devicesRequest();
else if (request.find("dispatch") == 0) else if (request.find("dispatch") == 0)
return dispatchRequest(request); return dispatchRequest(request);
else if (request.find("keyword") == 0) else if (request.find("keyword") == 0)
@@ -246,11 +284,11 @@ void HyprCtl::startHyprCtlSocket() {
return; return;
} }
unlink("/tmp/hypr/.socket.sock");
sockaddr_un SERVERADDRESS = {.sun_family = AF_UNIX}; sockaddr_un SERVERADDRESS = {.sun_family = AF_UNIX};
strcpy(SERVERADDRESS.sun_path, "/tmp/hypr/.socket.sock"); std::string socketPath = "/tmp/hypr/" + g_pCompositor->m_szInstanceSignature + "/.socket.sock";
strcpy(SERVERADDRESS.sun_path, socketPath.c_str());
bind(SOCKET, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)); bind(SOCKET, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS));
@@ -262,7 +300,7 @@ void HyprCtl::startHyprCtlSocket() {
char readBuffer[1024] = {0}; char readBuffer[1024] = {0};
Debug::log(LOG, "Hypr socket started."); Debug::log(LOG, "Hypr socket started at %s", socketPath.c_str());
while(1) { while(1) {
const auto ACCEPTEDCONNECTION = accept(SOCKET, (sockaddr*)&clientAddress, &clientSize); const auto ACCEPTEDCONNECTION = accept(SOCKET, (sockaddr*)&clientAddress, &clientSize);

View File

@@ -1,15 +1,22 @@
#include "Log.hpp" #include "Log.hpp"
#include "../defines.hpp" #include "../defines.hpp"
#include "../Compositor.hpp"
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
void Debug::init(std::string IS) {
if (ISDEBUG)
logFile = "/tmp/hypr/" + IS + "/hyprlandd.log";
else
logFile = "/tmp/hypr/" + IS + "/hyprland.log";
}
void Debug::log(LogLevel level, const char* fmt, ...) { void Debug::log(LogLevel level, const char* fmt, ...) {
// log to a file // log to a file
const std::string DEBUGPATH = ISDEBUG ? "/tmp/hypr/hyprlandd.log" : "/tmp/hypr/hyprland.log";
std::ofstream ofs; std::ofstream ofs;
ofs.open(DEBUGPATH, std::ios::out | std::ios::app); ofs.open(logFile, std::ios::out | std::ios::app);
switch (level) { switch (level) {
case LOG: case LOG:
@@ -24,6 +31,9 @@ void Debug::log(LogLevel level, const char* fmt, ...) {
case CRIT: case CRIT:
ofs << "[CRITICAL] "; ofs << "[CRITICAL] ";
break; break;
case INFO:
ofs << "[INFO] ";
break;
default: default:
break; break;
} }

View File

@@ -8,9 +8,13 @@ enum LogLevel {
LOG = 0, LOG = 0,
WARN, WARN,
ERR, ERR,
CRIT CRIT,
INFO
}; };
namespace Debug { namespace Debug {
void init(std::string IS);
void log(LogLevel level, const char* fmt, ...); void log(LogLevel level, const char* fmt, ...);
inline std::string logFile;
}; };

View File

@@ -7,10 +7,14 @@
#include "wlrunstable/wlr_ext_workspace_v1.hpp" #include "wlrunstable/wlr_ext_workspace_v1.hpp"
#ifndef NDEBUG #ifndef NDEBUG
#ifdef HYPRLAND_DEBUG
#define ISDEBUG true #define ISDEBUG true
#else #else
#define ISDEBUG false #define ISDEBUG false
#endif #endif
#else
#define ISDEBUG false
#endif
#define RIP(format, ... ) { fprintf(stderr, format "\n", ##__VA_ARGS__); exit(EXIT_FAILURE); } #define RIP(format, ... ) { fprintf(stderr, format "\n", ##__VA_ARGS__); exit(EXIT_FAILURE); }
@@ -64,4 +68,6 @@
#endif #endif
#ifndef GIT_DIRTY #ifndef GIT_DIRTY
#define GIT_DIRTY "?" #define GIT_DIRTY "?"
#endif #endif
#define SPECIAL_WORKSPACE_ID -99

View File

@@ -2,7 +2,7 @@
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../helpers/WLClasses.hpp" #include "../helpers/WLClasses.hpp"
#include "../managers/InputManager.hpp" #include "../managers/input/InputManager.hpp"
#include "../render/Renderer.hpp" #include "../render/Renderer.hpp"
// ---------------------------------------------------- // // ---------------------------------------------------- //
@@ -56,7 +56,16 @@ void Events::listener_mouseAxis(wl_listener* listener, void* data) {
void Events::listener_requestMouse(wl_listener* listener, void* data) { void Events::listener_requestMouse(wl_listener* listener, void* data) {
const auto EVENT = (wlr_seat_pointer_request_set_cursor_event*)data; const auto EVENT = (wlr_seat_pointer_request_set_cursor_event*)data;
if (!g_pHyprRenderer->shouldRenderCursor())
return;
if (!EVENT->surface) {
g_pHyprRenderer->m_bWindowRequestedCursorHide = true;
} else {
g_pHyprRenderer->m_bWindowRequestedCursorHide = false;
}
if (EVENT->seat_client == g_pCompositor->m_sSeat.seat->pointer_state.focused_client) if (EVENT->seat_client == g_pCompositor->m_sSeat.seat->pointer_state.focused_client)
wlr_cursor_set_surface(g_pCompositor->m_sWLRCursor, EVENT->surface, EVENT->hotspot_x, EVENT->hotspot_y); wlr_cursor_set_surface(g_pCompositor->m_sWLRCursor, EVENT->surface, EVENT->hotspot_x, EVENT->hotspot_y);
} }
@@ -73,13 +82,25 @@ void Events::listener_newInput(wl_listener* listener, void* data) {
Debug::log(LOG, "Attached a mouse with name %s", DEVICE->name); Debug::log(LOG, "Attached a mouse with name %s", DEVICE->name);
g_pInputManager->newMouse(DEVICE); g_pInputManager->newMouse(DEVICE);
break; break;
case WLR_INPUT_DEVICE_TOUCH:
Debug::log(LOG, "Attached a touch device with name %s", DEVICE->name);
Debug::log(WARN, "!!!! Hyprland does not directly support touchscreens, bugs may occur !!!!");
wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, DEVICE);
break;
case WLR_INPUT_DEVICE_TABLET_TOOL:
Debug::log(LOG, "Attached a tablet tool with name %s", DEVICE->name);
g_pInputManager->newTabletTool(DEVICE);
break;
case WLR_INPUT_DEVICE_TABLET_PAD:
Debug::log(LOG, "Attached a tablet pad with name %s", DEVICE->name);
g_pInputManager->newTabletPad(DEVICE);
break;
default: default:
Debug::log(WARN, "Unrecognized input device plugged in: %s", DEVICE->name);
break; break;
} }
uint32_t capabilities = WL_SEAT_CAPABILITY_POINTER | WL_SEAT_CAPABILITY_KEYBOARD; g_pInputManager->updateCapabilities(DEVICE);
wlr_seat_set_capabilities(g_pCompositor->m_sSeat.seat, capabilities);
} }
void Events::listener_newConstraint(wl_listener* listener, void* data) { void Events::listener_newConstraint(wl_listener* listener, void* data) {

View File

@@ -109,4 +109,7 @@ namespace Events {
// Deco XDG // Deco XDG
LISTENER(NewXDGDeco); LISTENER(NewXDGDeco);
// Renderer destroy
LISTENER(RendererDestroy);
}; };

View File

@@ -1,6 +1,6 @@
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../helpers/WLClasses.hpp" #include "../helpers/WLClasses.hpp"
#include "../managers/InputManager.hpp" #include "../managers/input/InputManager.hpp"
#include "../render/Renderer.hpp" #include "../render/Renderer.hpp"
#include "Events.hpp" #include "Events.hpp"
@@ -26,7 +26,7 @@ void Events::listener_newLayerSurface(wl_listener* listener, void* data) {
return; return;
} }
Debug::log(LOG, "New LayerSurface has no preferred monitor. Assigning Monitor %s", PMONITOR->szName); Debug::log(LOG, "New LayerSurface has no preferred monitor. Assigning Monitor %s", PMONITOR->szName.c_str());
WLRLAYERSURFACE->output = PMONITOR->output; WLRLAYERSURFACE->output = PMONITOR->output;
} }
@@ -58,7 +58,12 @@ void Events::listener_destroyLayerSurface(void* owner, void* data) {
Debug::log(LOG, "LayerSurface %x destroyed", layersurface->layerSurface); Debug::log(LOG, "LayerSurface %x destroyed", layersurface->layerSurface);
if (!layersurface->fadingOut) { const auto PMONITOR = g_pCompositor->getMonitorFromID(layersurface->monitorID);
if (!g_pCompositor->getMonitorFromID(layersurface->monitorID))
Debug::log(WARN, "Layersurface destroyed on an invalid monitor (removed?)");
if (!layersurface->fadingOut && PMONITOR) {
Debug::log(LOG, "Removing LayerSurface that wasn't mapped."); Debug::log(LOG, "Removing LayerSurface that wasn't mapped.");
layersurface->alpha.setValueAndWarp(0.f); layersurface->alpha.setValueAndWarp(0.f);
layersurface->fadingOut = true; layersurface->fadingOut = true;
@@ -70,8 +75,6 @@ void Events::listener_destroyLayerSurface(void* owner, void* data) {
layersurface->hyprListener_unmapLayerSurface.removeCallback(); layersurface->hyprListener_unmapLayerSurface.removeCallback();
layersurface->hyprListener_newPopup.removeCallback(); layersurface->hyprListener_newPopup.removeCallback();
const auto PMONITOR = g_pCompositor->getMonitorFromID(layersurface->monitorID);
// rearrange to fix the reserved areas // rearrange to fix the reserved areas
if (PMONITOR) { if (PMONITOR) {
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID); g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID);
@@ -131,6 +134,11 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
Debug::log(LOG, "LayerSurface %x unmapped", layersurface->layerSurface); Debug::log(LOG, "LayerSurface %x unmapped", layersurface->layerSurface);
if (!g_pCompositor->getMonitorFromID(layersurface->monitorID)) {
Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring.");
return;
}
// make a snapshot and start fade // make a snapshot and start fade
g_pHyprOpenGL->makeLayerSnapshot(layersurface); g_pHyprOpenGL->makeLayerSnapshot(layersurface);
layersurface->alpha = 0.f; layersurface->alpha = 0.f;
@@ -152,6 +160,12 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
wlr_box geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width, layersurface->geometry.height}; wlr_box geomFixed = {layersurface->geometry.x + PMONITOR->vecPosition.x, layersurface->geometry.y + PMONITOR->vecPosition.y, layersurface->geometry.width, layersurface->geometry.height};
g_pHyprRenderer->damageBox(&geomFixed); g_pHyprRenderer->damageBox(&geomFixed);
geomFixed = {layersurface->geometry.x + (int)PMONITOR->vecPosition.x, layersurface->geometry.y + (int)PMONITOR->vecPosition.y, (int)layersurface->layerSurface->surface->current.width, (int)layersurface->layerSurface->surface->current.height};
g_pHyprRenderer->damageBox(&geomFixed);
geomFixed = {layersurface->geometry.x, layersurface->geometry.y, (int)layersurface->layerSurface->surface->current.width, (int)layersurface->layerSurface->surface->current.height};
layersurface->geometry = geomFixed; // because the surface can overflow... for some reason?
} }
void Events::listener_commitLayerSurface(void* owner, void* data) { void Events::listener_commitLayerSurface(void* owner, void* data) {

View File

@@ -2,7 +2,7 @@
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../helpers/WLClasses.hpp" #include "../helpers/WLClasses.hpp"
#include "../managers/InputManager.hpp" #include "../managers/input/InputManager.hpp"
#include "../render/Renderer.hpp" #include "../render/Renderer.hpp"
// ------------------------------ // // ------------------------------ //
@@ -153,4 +153,8 @@ void Events::listener_InhibitDeactivate(wl_listener* listener, void* data) {
g_pCompositor->m_sSeat.exclusiveClient = nullptr; g_pCompositor->m_sSeat.exclusiveClient = nullptr;
g_pInputManager->refocus(); g_pInputManager->refocus();
}
void Events::listener_RendererDestroy(wl_listener* listener, void* data) {
Debug::log(LOG, "!!Renderer destroyed!!");
} }

View File

@@ -1,6 +1,6 @@
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../helpers/WLClasses.hpp" #include "../helpers/WLClasses.hpp"
#include "../managers/InputManager.hpp" #include "../managers/input/InputManager.hpp"
#include "../render/Renderer.hpp" #include "../render/Renderer.hpp"
#include "Events.hpp" #include "Events.hpp"
#include "../debug/HyprCtl.hpp" #include "../debug/HyprCtl.hpp"
@@ -65,12 +65,16 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
if (monitorRule.disabled) { if (monitorRule.disabled) {
wlr_output_enable(OUTPUT, 0); wlr_output_enable(OUTPUT, 0);
wlr_output_commit(OUTPUT); wlr_output_commit(OUTPUT);
if (const auto PMONITOR = g_pCompositor->getMonitorFromName(std::string(OUTPUT->name)); PMONITOR) {
listener_monitorDestroy(nullptr, PMONITOR->output);
}
return; return;
} }
SMonitor newMonitor; SMonitor newMonitor;
newMonitor.output = OUTPUT; newMonitor.output = OUTPUT;
newMonitor.ID = g_pCompositor->m_lMonitors.size(); newMonitor.ID = g_pCompositor->getNextAvailableMonitorID();
newMonitor.szName = OUTPUT->name; newMonitor.szName = OUTPUT->name;
wlr_output_init_render(OUTPUT, g_pCompositor->m_sWLRAllocator, g_pCompositor->m_sWLRRenderer); wlr_output_init_render(OUTPUT, g_pCompositor->m_sWLRAllocator, g_pCompositor->m_sWLRRenderer);
@@ -110,20 +114,41 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
wlr_ext_workspace_group_handle_v1_output_enter(PNEWMONITOR->pWLRWorkspaceGroupHandle, PNEWMONITOR->output); wlr_ext_workspace_group_handle_v1_output_enter(PNEWMONITOR->pWLRWorkspaceGroupHandle, PNEWMONITOR->output);
// Workspace // Workspace
const auto WORKSPACEID = monitorRule.defaultWorkspaceID == -1 ? g_pCompositor->m_lWorkspaces.size() + 1 /* Cuz workspaces doesnt have the new one yet and we start with 1 */ : monitorRule.defaultWorkspaceID; std::string newDefaultWorkspaceName = "";
g_pCompositor->m_lWorkspaces.emplace_back(newMonitor.ID); auto WORKSPACEID = monitorRule.defaultWorkspace == "" ? g_pCompositor->m_lWorkspaces.size() + 1 : getWorkspaceIDFromString(monitorRule.defaultWorkspace, newDefaultWorkspaceName);
const auto PNEWWORKSPACE = &g_pCompositor->m_lWorkspaces.back();
if (WORKSPACEID == INT_MAX || WORKSPACEID == (long unsigned int)SPECIAL_WORKSPACE_ID) {
WORKSPACEID = g_pCompositor->m_lWorkspaces.size() + 1;
newDefaultWorkspaceName = std::to_string(WORKSPACEID);
// We are required to set the name here immediately Debug::log(LOG, "Invalid workspace= directive name in monitor parsing, workspace name \"%s\" is invalid.", monitorRule.defaultWorkspace);
wlr_ext_workspace_handle_v1_set_name(PNEWWORKSPACE->m_pWlrHandle, std::to_string(WORKSPACEID).c_str()); }
PNEWWORKSPACE->m_iID = WORKSPACEID; auto PNEWWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
PNEWWORKSPACE->m_szName = std::to_string(WORKSPACEID);
Debug::log(LOG, "New monitor: WORKSPACEID %d, exists: %d", WORKSPACEID, (int)(PNEWWORKSPACE != nullptr));
if (PNEWWORKSPACE) {
// workspace exists, move it to the newly connected monitor
g_pCompositor->moveWorkspaceToMonitor(PNEWWORKSPACE, PNEWMONITOR);
PNEWMONITOR->activeWorkspace = PNEWWORKSPACE->m_iID;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PNEWMONITOR->ID);
PNEWWORKSPACE->startAnim(true,true,true);
} else {
PNEWWORKSPACE = &g_pCompositor->m_lWorkspaces.emplace_back(newMonitor.ID);
// We are required to set the name here immediately
wlr_ext_workspace_handle_v1_set_name(PNEWWORKSPACE->m_pWlrHandle, newDefaultWorkspaceName.c_str());
PNEWWORKSPACE->m_iID = WORKSPACEID;
PNEWWORKSPACE->m_szName = newDefaultWorkspaceName;
}
PNEWMONITOR->activeWorkspace = PNEWWORKSPACE->m_iID; PNEWMONITOR->activeWorkspace = PNEWWORKSPACE->m_iID;
PNEWMONITOR->scale = monitorRule.scale; PNEWMONITOR->scale = monitorRule.scale;
PNEWMONITOR->forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering.
g_pCompositor->deactivateAllWLRWorkspaces(PNEWWORKSPACE->m_pWlrHandle); g_pCompositor->deactivateAllWLRWorkspaces(PNEWWORKSPACE->m_pWlrHandle);
PNEWWORKSPACE->setActive(true); PNEWWORKSPACE->setActive(true);
@@ -132,7 +157,9 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
// //
if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet
g_pCompositor->m_pLastMonitor = PNEWMONITOR; g_pCompositor->m_pLastMonitor = PNEWMONITOR;
g_pEventManager->postEvent(SHyprIPCEvent("monitoradded", PNEWMONITOR->szName));
// ready to process cuz we have a monitor // ready to process cuz we have a monitor
g_pCompositor->m_bReadyToProcess = true; g_pCompositor->m_bReadyToProcess = true;
@@ -145,7 +172,10 @@ void Events::listener_monitorFrame(void* owner, void* data) {
static std::chrono::high_resolution_clock::time_point startRenderOverlay = std::chrono::high_resolution_clock::now(); static std::chrono::high_resolution_clock::time_point startRenderOverlay = std::chrono::high_resolution_clock::now();
static std::chrono::high_resolution_clock::time_point endRenderOverlay = std::chrono::high_resolution_clock::now(); static std::chrono::high_resolution_clock::time_point endRenderOverlay = std::chrono::high_resolution_clock::now();
if (g_pConfigManager->getInt("debug:overlay") == 1) { static auto *const PDEBUGOVERLAY = &g_pConfigManager->getConfigValuePtr("debug:overlay")->intValue;
static auto *const PDAMAGETRACKINGMODE = &g_pConfigManager->getConfigValuePtr("general:damage_tracking_internal")->intValue;
if (*PDEBUGOVERLAY == 1) {
startRender = std::chrono::high_resolution_clock::now(); startRender = std::chrono::high_resolution_clock::now();
g_pDebugOverlay->frameData(PMONITOR); g_pDebugOverlay->frameData(PMONITOR);
} }
@@ -163,11 +193,18 @@ void Events::listener_monitorFrame(void* owner, void* data) {
if (g_pConfigManager->m_bWantsMonitorReload) if (g_pConfigManager->m_bWantsMonitorReload)
g_pConfigManager->performMonitorReload(); g_pConfigManager->performMonitorReload();
g_pHyprRenderer->ensureCursorRenderingMode(); // so that the cursor gets hidden/shown if the user requested timeouts
} }
if (PMONITOR->needsFrameSkip) { if (PMONITOR->framesToSkip > 0) {
PMONITOR->needsFrameSkip = false; PMONITOR->framesToSkip -= 1;
wlr_output_schedule_frame(PMONITOR->output);
if (!PMONITOR->noFrameSchedule)
wlr_output_schedule_frame(PMONITOR->output);
else {
Debug::log(LOG, "NoFrameSchedule hit for %s.", PMONITOR->szName.c_str());
}
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
return; return;
} }
@@ -180,9 +217,7 @@ void Events::listener_monitorFrame(void* owner, void* data) {
bool hasChanged; bool hasChanged;
pixman_region32_init(&damage); pixman_region32_init(&damage);
const auto DTMODE = g_pConfigManager->getInt("general:damage_tracking_internal"); if (*PDAMAGETRACKINGMODE == -1) {
if (DTMODE == -1) {
Debug::log(CRIT, "Damage tracking mode -1 ????"); Debug::log(CRIT, "Damage tracking mode -1 ????");
return; return;
} }
@@ -192,7 +227,7 @@ void Events::listener_monitorFrame(void* owner, void* data) {
return; return;
} }
if (!hasChanged && DTMODE != DAMAGE_TRACKING_NONE) { if (!hasChanged && *PDAMAGETRACKINGMODE != DAMAGE_TRACKING_NONE && PMONITOR->forceFullFrames == 0) {
pixman_region32_fini(&damage); pixman_region32_fini(&damage);
wlr_output_rollback(PMONITOR->output); wlr_output_rollback(PMONITOR->output);
wlr_output_schedule_frame(PMONITOR->output); // we update shit at the monitor's Hz so we need to schedule frames because rollback wont wlr_output_schedule_frame(PMONITOR->output); // we update shit at the monitor's Hz so we need to schedule frames because rollback wont
@@ -200,19 +235,19 @@ void Events::listener_monitorFrame(void* owner, void* data) {
} }
// if we have no tracking or full tracking, invalidate the entire monitor // if we have no tracking or full tracking, invalidate the entire monitor
if (DTMODE == DAMAGE_TRACKING_NONE || DTMODE == DAMAGE_TRACKING_MONITOR) { if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR || PMONITOR->forceFullFrames > 0) {
pixman_region32_union_rect(&damage, &damage, 0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y); pixman_region32_union_rect(&damage, &damage, 0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y);
pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage); pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage);
} else { } else {
static auto* const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue;
// if we use blur we need to expand the damage for proper blurring // if we use blur we need to expand the damage for proper blurring
if (g_pConfigManager->getInt("decoration:blur") == 1) { if (*PBLURENABLED == 1) {
// TODO: can this be optimized? // TODO: can this be optimized?
const auto BLURSIZE = g_pConfigManager->getInt("decoration:blur_size"); static auto* const PBLURSIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_size")->intValue;
const auto BLURPASSES = g_pConfigManager->getInt("decoration:blur_passes"); static auto* const PBLURPASSES = &g_pConfigManager->getConfigValuePtr("decoration:blur_passes")->intValue;
const auto BLURRADIUS = *PBLURSIZE * pow(2, *PBLURPASSES); // is this 2^pass? I don't know but it works... I think.
const auto BLURRADIUS = BLURSIZE * pow(2, BLURPASSES); // is this 2^pass? I don't know but it works... I think.
pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage); pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage);
@@ -223,6 +258,9 @@ void Events::listener_monitorFrame(void* owner, void* data) {
} }
} }
if (PMONITOR->forceFullFrames > 0)
PMONITOR->forceFullFrames -= 1;
// TODO: this is getting called with extents being 0,0,0,0 should it be? // TODO: this is getting called with extents being 0,0,0,0 should it be?
// potentially can save on resources. // potentially can save on resources.
@@ -237,7 +275,7 @@ void Events::listener_monitorFrame(void* owner, void* data) {
g_pHyprError->draw(); g_pHyprError->draw();
// for drawing the debug overlay // for drawing the debug overlay
if (PMONITOR->ID == 0 && g_pConfigManager->getInt("debug:overlay") == 1) { if (PMONITOR->ID == 0 && *PDEBUGOVERLAY == 1) {
startRenderOverlay = std::chrono::high_resolution_clock::now(); startRenderOverlay = std::chrono::high_resolution_clock::now();
g_pDebugOverlay->draw(); g_pDebugOverlay->draw();
endRenderOverlay = std::chrono::high_resolution_clock::now(); endRenderOverlay = std::chrono::high_resolution_clock::now();
@@ -258,7 +296,7 @@ void Events::listener_monitorFrame(void* owner, void* data) {
const auto TRANSFORM = wlr_output_transform_invert(PMONITOR->output->transform); const auto TRANSFORM = wlr_output_transform_invert(PMONITOR->output->transform);
wlr_region_transform(&frameDamage, &PMONITOR->damage->current, TRANSFORM, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y); wlr_region_transform(&frameDamage, &PMONITOR->damage->current, TRANSFORM, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y);
if (DTMODE == DAMAGE_TRACKING_NONE || DTMODE == DAMAGE_TRACKING_MONITOR) if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR)
pixman_region32_union_rect(&frameDamage, &frameDamage, 0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y); pixman_region32_union_rect(&frameDamage, &frameDamage, 0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y);
wlr_output_set_damage(PMONITOR->output, &frameDamage); wlr_output_set_damage(PMONITOR->output, &frameDamage);
@@ -269,7 +307,7 @@ void Events::listener_monitorFrame(void* owner, void* data) {
wlr_output_schedule_frame(PMONITOR->output); wlr_output_schedule_frame(PMONITOR->output);
if (g_pConfigManager->getInt("debug:overlay") == 1) { if (*PDEBUGOVERLAY == 1) {
const float µs = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - startRender).count() / 1000.f; const float µs = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - startRender).count() / 1000.f;
g_pDebugOverlay->renderData(PMONITOR, µs); g_pDebugOverlay->renderData(PMONITOR, µs);
if (PMONITOR->ID == 0) { if (PMONITOR->ID == 0) {
@@ -296,7 +334,60 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
if (!pMonitor) if (!pMonitor)
return; return;
// Cleanup everything. Move windows back, snap cursor, shit.
const auto BACKUPMON = &g_pCompositor->m_lMonitors.front();
if (!BACKUPMON) {
Debug::log(CRIT, "No monitors! Unplugged last! Exiting.");
g_pCompositor->cleanupExit();
exit(1);
return;
}
const auto BACKUPWORKSPACE = BACKUPMON->activeWorkspace > 0 ? std::to_string(BACKUPMON->activeWorkspace) : "name:" + g_pCompositor->getWorkspaceByID(BACKUPMON->activeWorkspace)->m_szName;
// snap cursor
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, BACKUPMON->vecPosition.x + BACKUPMON->vecTransformedSize.x / 2.f, BACKUPMON->vecPosition.y + BACKUPMON->vecTransformedSize.y / 2.f);
// move workspaces
std::deque<CWorkspace*> wspToMove;
for (auto& w : g_pCompositor->m_lWorkspaces) {
if (w.m_iMonitorID == pMonitor->ID) {
wspToMove.push_back(&w);
}
}
for (auto& w : wspToMove) {
g_pCompositor->moveWorkspaceToMonitor(w, BACKUPMON);
w->startAnim(true, true, true);
}
pMonitor->activeWorkspace = -1;
for (auto it = g_pCompositor->m_lWorkspaces.begin(); it != g_pCompositor->m_lWorkspaces.end(); ++it) {
if (it->m_iMonitorID == pMonitor->ID) {
it = g_pCompositor->m_lWorkspaces.erase(it);
}
}
Debug::log(LOG, "Removed monitor %s!", pMonitor->szName.c_str());
g_pEventManager->postEvent(SHyprIPCEvent("monitorremoved", pMonitor->szName));
g_pCompositor->m_lMonitors.remove(*pMonitor); g_pCompositor->m_lMonitors.remove(*pMonitor);
// TODO: cleanup windows // update the pMostHzMonitor
if (pMostHzMonitor == pMonitor) {
int mostHz = 0;
SMonitor* pMonitorMostHz = nullptr;
for (auto& m : g_pCompositor->m_lMonitors) {
if (m.refreshRate > mostHz) {
pMonitorMostHz = &m;
mostHz = m.refreshRate;
}
}
pMostHzMonitor = pMonitorMostHz;
}
} }

View File

@@ -2,7 +2,7 @@
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../helpers/WLClasses.hpp" #include "../helpers/WLClasses.hpp"
#include "../managers/InputManager.hpp" #include "../managers/input/InputManager.hpp"
#include "../render/Renderer.hpp" #include "../render/Renderer.hpp"
// --------------------------------------------- // // --------------------------------------------- //
@@ -26,6 +26,14 @@ void addPopupGlobalCoords(void* pPopup, int* x, int* y) {
px += curPopup->popup->current.geometry.x; px += curPopup->popup->current.geometry.x;
py += curPopup->popup->current.geometry.y; py += curPopup->popup->current.geometry.y;
// fix oversized fucking popups
// kill me
if (curPopup->pSurfaceTree && curPopup->pSurfaceTree->pSurface && !curPopup->parentPopup) {
const auto EXTENTSSURFACE = pixman_region32_extents(&curPopup->pSurfaceTree->pSurface->input_region);
px -= EXTENTSSURFACE->x1;
py -= EXTENTSSURFACE->y1;
}
if (curPopup->parentPopup) { if (curPopup->parentPopup) {
curPopup = curPopup->parentPopup; curPopup = curPopup->parentPopup;
} else { } else {
@@ -134,7 +142,7 @@ void Events::listener_mapPopupXDG(void* owner, void* data) {
Debug::log(LOG, "New XDG Popup mapped at %d %d", (int)PPOPUP->lx, (int)PPOPUP->ly); Debug::log(LOG, "New XDG Popup mapped at %d %d", (int)PPOPUP->lx, (int)PPOPUP->ly);
PPOPUP->pSurfaceTree = SubsurfaceTree::createTreeRoot(PPOPUP->popup->base->surface, addPopupGlobalCoords, PPOPUP); PPOPUP->pSurfaceTree = SubsurfaceTree::createTreeRoot(PPOPUP->popup->base->surface, addPopupGlobalCoords, PPOPUP, PPOPUP->parentWindow);
Debug::log(LOG, "XDG Popup got assigned a surfaceTreeNode %x", PPOPUP->pSurfaceTree); Debug::log(LOG, "XDG Popup got assigned a surfaceTreeNode %x", PPOPUP->pSurfaceTree);
} }

View File

@@ -2,7 +2,7 @@
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include "../helpers/WLClasses.hpp" #include "../helpers/WLClasses.hpp"
#include "../managers/InputManager.hpp" #include "../managers/input/InputManager.hpp"
#include "../render/Renderer.hpp" #include "../render/Renderer.hpp"
// ------------------------------------------------------------ // // ------------------------------------------------------------ //
@@ -19,22 +19,33 @@ void addViewCoords(void* pWindow, int* x, int* y) {
const auto PWINDOW = (CWindow*)pWindow; const auto PWINDOW = (CWindow*)pWindow;
*x += PWINDOW->m_vRealPosition.goalv().x; *x += PWINDOW->m_vRealPosition.goalv().x;
*y += PWINDOW->m_vRealPosition.goalv().y; *y += PWINDOW->m_vRealPosition.goalv().y;
if (!PWINDOW->m_bIsX11) {
wlr_box geom;
wlr_xdg_surface_get_geometry(PWINDOW->m_uSurface.xdg, &geom);
*x -= geom.x;
*y -= geom.y;
}
} }
void Events::listener_mapWindow(void* owner, void* data) { void Events::listener_mapWindow(void* owner, void* data) {
CWindow* PWINDOW = (CWindow*)owner; CWindow* PWINDOW = (CWindow*)owner;
const auto PMONITOR = g_pCompositor->getMonitorFromCursor(); const auto PMONITOR = g_pCompositor->getMonitorFromCursor();
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace); const auto PWORKSPACE = PMONITOR->specialWorkspaceOpen ? g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID) : g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
PWINDOW->m_iMonitorID = PMONITOR->ID; PWINDOW->m_iMonitorID = PMONITOR->ID;
PWINDOW->m_bMappedX11 = true; PWINDOW->m_bMappedX11 = true;
PWINDOW->m_iWorkspaceID = PMONITOR->activeWorkspace; PWINDOW->m_iWorkspaceID = PMONITOR->specialWorkspaceOpen ? SPECIAL_WORKSPACE_ID : PMONITOR->activeWorkspace;
PWINDOW->m_bIsMapped = true; PWINDOW->m_bIsMapped = true;
PWINDOW->m_bReadyToDelete = false; PWINDOW->m_bReadyToDelete = false;
PWINDOW->m_bFadingOut = false; PWINDOW->m_bFadingOut = false;
PWINDOW->m_szTitle = g_pXWaylandManager->getTitle(PWINDOW); PWINDOW->m_szTitle = g_pXWaylandManager->getTitle(PWINDOW);
PWINDOW->m_fAlpha = 255.f; PWINDOW->m_fAlpha = 255.f;
// Set all windows tiled regardless of anything
g_pXWaylandManager->setWindowStyleTiled(PWINDOW, WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP | WLR_EDGE_BOTTOM);
// Foreign Toplevel // Foreign Toplevel
PWINDOW->m_phForeignToplevel = wlr_foreign_toplevel_handle_v1_create(g_pCompositor->m_sWLRToplevelMgr); PWINDOW->m_phForeignToplevel = wlr_foreign_toplevel_handle_v1_create(g_pCompositor->m_sWLRToplevelMgr);
// TODO: handle foreign events (requests) // TODO: handle foreign events (requests)
@@ -67,22 +78,30 @@ void Events::listener_mapWindow(void* owner, void* data) {
if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->m_bIsFloating) { if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->m_bIsFloating) {
const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PFULLWINDOW, FULLSCREEN_FULL); g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PFULLWINDOW, FULLSCREEN_FULL, false);
g_pXWaylandManager->setWindowFullscreen(PFULLWINDOW, PFULLWINDOW->m_bIsFullscreen); g_pXWaylandManager->setWindowFullscreen(PFULLWINDOW, PFULLWINDOW->m_bIsFullscreen);
} }
// window rules // window rules
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW); const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW);
std::string requestedWorkspace = "";
bool workspaceSilent = false;
bool requestsFullscreen = false;
for (auto& r : WINDOWRULES) { for (auto& r : WINDOWRULES) {
if (r.szRule.find("monitor") == 0) { if (r.szRule.find("monitor") == 0) {
try { try {
const long int MONITOR = std::stoi(r.szRule.substr(r.szRule.find(" "))); const auto MONITORSTR = r.szRule.substr(r.szRule.find(" "));
if (MONITOR >= (long int)g_pCompositor->m_lMonitors.size() || MONITOR < (long int)0) if (MONITORSTR == "unset") {
PWINDOW->m_iMonitorID = 0; PWINDOW->m_iMonitorID = PMONITOR->ID;
else } else {
PWINDOW->m_iMonitorID = MONITOR; const long int MONITOR = std::stoi(MONITORSTR);
if (MONITOR >= (long int)g_pCompositor->m_lMonitors.size() || MONITOR < (long int)0)
PWINDOW->m_iMonitorID = 0;
else
PWINDOW->m_iMonitorID = MONITOR;
}
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->activeWorkspace; PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->activeWorkspace;
@@ -91,11 +110,14 @@ void Events::listener_mapWindow(void* owner, void* data) {
Debug::log(ERR, "Rule monitor failed, rule: %s -> %s | err: %s", r.szRule.c_str(), r.szValue.c_str(), e.what()); Debug::log(ERR, "Rule monitor failed, rule: %s -> %s | err: %s", r.szRule.c_str(), r.szValue.c_str(), e.what());
} }
} else if (r.szRule.find("workspace") == 0) { } else if (r.szRule.find("workspace") == 0) {
// switch to workspace // check if it isnt unset
g_pKeybindManager->m_mDispatchers["workspace"](r.szRule.substr(r.szRule.find_first_of(' ') + 1)); const auto WORKSPACERQ = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
PWINDOW->m_iMonitorID = g_pCompositor->m_pLastMonitor->ID; if (WORKSPACERQ == "unset") {
PWINDOW->m_iWorkspaceID = g_pCompositor->m_pLastMonitor->activeWorkspace; requestedWorkspace = "";
} else {
requestedWorkspace = WORKSPACERQ;
}
Debug::log(LOG, "Rule workspace matched by window %x, %s applied.", PWINDOW, r.szValue.c_str()); Debug::log(LOG, "Rule workspace matched by window %x, %s applied.", PWINDOW, r.szValue.c_str());
} else if (r.szRule.find("float") == 0) { } else if (r.szRule.find("float") == 0) {
@@ -106,6 +128,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_bIsPseudotiled = true; PWINDOW->m_bIsPseudotiled = true;
} else if (r.szRule.find("nofocus") == 0) { } else if (r.szRule.find("nofocus") == 0) {
PWINDOW->m_bNoFocus = true; PWINDOW->m_bNoFocus = true;
} else if (r.szRule == "noblur") {
PWINDOW->m_sAdditionalConfigData.forceNoBlur = true;
} else if (r.szRule == "fullscreen") {
requestsFullscreen = true;
} else if (r.szRule.find("rounding") == 0) { } else if (r.szRule.find("rounding") == 0) {
try { try {
PWINDOW->m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1)); PWINDOW->m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
@@ -114,7 +140,15 @@ void Events::listener_mapWindow(void* owner, void* data) {
} }
} else if (r.szRule.find("opacity") == 0) { } else if (r.szRule.find("opacity") == 0) {
try { try {
PWINDOW->m_sSpecialRenderData.alpha = std::stof(r.szRule.substr(r.szRule.find_first_of(' ') + 1)); std::string alphaPart = r.szRule.substr(r.szRule.find_first_of(' ') + 1);
if (alphaPart.find_first_of(' ') != std::string::npos) {
// we have a comma, 2 values
PWINDOW->m_sSpecialRenderData.alpha = std::stof(alphaPart.substr(0, alphaPart.find_first_of(' ')));
PWINDOW->m_sSpecialRenderData.alphaInactive = std::stof(alphaPart.substr(alphaPart.find_first_of(' ') + 1));
} else {
PWINDOW->m_sSpecialRenderData.alpha = std::stof(alphaPart);
}
} catch(std::exception& e) { } catch(std::exception& e) {
Debug::log(ERR, "Opacity rule \"%s\" failed with: %s", r.szRule.c_str(), e.what()); Debug::log(ERR, "Opacity rule \"%s\" failed with: %s", r.szRule.c_str(), e.what());
} }
@@ -124,6 +158,25 @@ void Events::listener_mapWindow(void* owner, void* data) {
} }
} }
if (requestedWorkspace != "") {
// process requested workspace
if (requestedWorkspace.find_first_of(' ') != std::string::npos) {
// check for silent
if (requestedWorkspace.find("silent") != std::string::npos) {
workspaceSilent = true;
}
requestedWorkspace = requestedWorkspace.substr(0, requestedWorkspace.find_first_of(' '));
}
if (!workspaceSilent) {
g_pKeybindManager->m_mDispatchers["workspace"](requestedWorkspace);
PWINDOW->m_iMonitorID = g_pCompositor->m_pLastMonitor->ID;
PWINDOW->m_iWorkspaceID = g_pCompositor->m_pLastMonitor->activeWorkspace;
}
}
if (PWINDOW->m_bIsFloating) { if (PWINDOW->m_bIsFloating) {
g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(PWINDOW); g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(PWINDOW);
PWINDOW->m_bCreatedOverFullscreen = true; PWINDOW->m_bCreatedOverFullscreen = true;
@@ -175,10 +228,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goalv() - Vector2D(10,10); PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goalv() - Vector2D(10,10);
} }
if (!PWINDOW->m_bNoFocus) if (!PWINDOW->m_bNoFocus && !PWINDOW->m_bNoInitialFocus)
g_pCompositor->focusWindow(PWINDOW); g_pCompositor->focusWindow(PWINDOW);
PWINDOW->m_pSurfaceTree = SubsurfaceTree::createTreeRoot(g_pXWaylandManager->getWindowSurface(PWINDOW), addViewCoords, PWINDOW); PWINDOW->m_pSurfaceTree = SubsurfaceTree::createTreeRoot(g_pXWaylandManager->getWindowSurface(PWINDOW), addViewCoords, PWINDOW, PWINDOW);
Debug::log(LOG, "Window got assigned a surfaceTreeNode %x", PWINDOW->m_pSurfaceTree); Debug::log(LOG, "Window got assigned a surfaceTreeNode %x", PWINDOW->m_pSurfaceTree);
@@ -197,6 +250,19 @@ void Events::listener_mapWindow(void* owner, void* data) {
// do the animation thing // do the animation thing
g_pAnimationManager->onWindowPostCreateClose(PWINDOW, false); g_pAnimationManager->onWindowPostCreateClose(PWINDOW, false);
if (workspaceSilent) {
// move the window
if (g_pCompositor->m_pLastWindow == PWINDOW) {
g_pKeybindManager->m_mDispatchers["movetoworkspacesilent"](requestedWorkspace);
} else {
Debug::log(ERR, "Tried to set workspace silent rule to a nofocus window!");
}
}
if (requestsFullscreen) {
g_pCompositor->setWindowFullscreen(PWINDOW, true, FULLSCREEN_FULL);
}
Debug::log(LOG, "Map request dispatched, monitor %s, xywh: %f %f %f %f", PMONITOR->szName.c_str(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y, PWINDOW->m_vRealSize.goalv().x, PWINDOW->m_vRealSize.goalv().y); Debug::log(LOG, "Map request dispatched, monitor %s, xywh: %f %f %f %f", PMONITOR->szName.c_str(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y, PWINDOW->m_vRealSize.goalv().x, PWINDOW->m_vRealSize.goalv().y);
} }
@@ -327,9 +393,9 @@ void Events::listener_fullscreenWindow(void* owner, void* data) {
const auto REQUESTED = &PWINDOW->m_uSurface.xdg->toplevel->requested; const auto REQUESTED = &PWINDOW->m_uSurface.xdg->toplevel->requested;
if (REQUESTED->fullscreen != PWINDOW->m_bIsFullscreen) if (REQUESTED->fullscreen != PWINDOW->m_bIsFullscreen)
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, FULLSCREEN_FULL); g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, FULLSCREEN_FULL, true);
} else { } else {
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, FULLSCREEN_FULL); g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, FULLSCREEN_FULL, true);
} }
Debug::log(LOG, "Window %x fullscreen to %i", PWINDOW, PWINDOW->m_bIsFullscreen); Debug::log(LOG, "Window %x fullscreen to %i", PWINDOW, PWINDOW->m_bIsFullscreen);

View File

@@ -149,8 +149,6 @@ public:
return false; // unreachable return false; // unreachable
} }
private:
void warp() { void warp() {
switch (m_eVarType) { switch (m_eVarType) {
case AVARTYPE_FLOAT: { case AVARTYPE_FLOAT: {
@@ -170,6 +168,8 @@ private:
} }
} }
private:
Vector2D m_vValue = Vector2D(0,0); Vector2D m_vValue = Vector2D(0,0);
float m_fValue = 0; float m_fValue = 0;
CColor m_cValue; CColor m_cValue;

View File

@@ -2,6 +2,7 @@
#include "../defines.hpp" #include "../defines.hpp"
#include <algorithm> #include <algorithm>
#include "../Compositor.hpp" #include "../Compositor.hpp"
#include <sys/utsname.h>
void addWLSignal(wl_signal* pSignal, wl_listener* pListener, void* pOwner, std::string ownerString) { void addWLSignal(wl_signal* pSignal, wl_listener* pListener, void* pOwner, std::string ownerString) {
ASSERT(pSignal); ASSERT(pSignal);
@@ -46,16 +47,35 @@ void wlr_signal_emit_safe(struct wl_signal *signal, void *data) {
} }
std::string getFormat(const char *fmt, ...) { std::string getFormat(const char *fmt, ...) {
char buf[2048] = ""; char buf[LOGMESSAGESIZE] = "";
char* outputStr;
int logLen;
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
logLen = vsnprintf(buf, sizeof buf, fmt, args);
vsprintf(buf, fmt, args);
va_end(args); va_end(args);
return std::string(buf); if ((long unsigned int)logLen < sizeof buf) {
outputStr = strdup(buf);
} else {
outputStr = (char*)malloc(logLen + 1);
if (!outputStr) {
printf("CRITICAL: Cannot alloc size %d for log! (Out of memory?)", logLen + 1);
return "";
}
va_start(args, fmt);
vsnprintf(outputStr, logLen + 1U, fmt, args);
va_end(args);
}
std::string output = std::string(outputStr);
free(outputStr);
return output;
} }
void scaleBox(wlr_box* box, float scale) { void scaleBox(wlr_box* box, float scale) {
@@ -116,7 +136,7 @@ float getPlusMinusKeywordResult(std::string source, float relative) {
} }
bool isNumber(const std::string& str) { bool isNumber(const std::string& str) {
return std::ranges::all_of(str.begin(), str.end(), [](char c) { return isdigit(c) != 0; }); return std::ranges::all_of(str.begin(), str.end(), [](char c) { return isdigit(c) != 0 || c == '-'; });
} }
bool isDirection(const std::string& arg) { bool isDirection(const std::string& arg) {
@@ -125,7 +145,10 @@ bool isDirection(const std::string& arg) {
int getWorkspaceIDFromString(const std::string& in, std::string& outName) { int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
int result = INT_MAX; int result = INT_MAX;
if (in.find("name:") == 0) { if (in.find("special") == 0) {
outName = "special";
return SPECIAL_WORKSPACE_ID;
} else if (in.find("name:") == 0) {
const auto WORKSPACENAME = in.substr(in.find_first_of(':') + 1); const auto WORKSPACENAME = in.substr(in.find_first_of(':') + 1);
const auto WORKSPACE = g_pCompositor->getWorkspaceByName(WORKSPACENAME); const auto WORKSPACE = g_pCompositor->getWorkspaceByName(WORKSPACENAME);
if (!WORKSPACE) { if (!WORKSPACE) {
@@ -135,8 +158,72 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
} }
outName = WORKSPACENAME; outName = WORKSPACENAME;
} else { } else {
result = std::clamp((int)getPlusMinusKeywordResult(in, g_pCompositor->m_pLastMonitor->activeWorkspace), 1, INT_MAX); if (in[0] == 'm') {
outName = std::to_string(result); if (!g_pCompositor->m_pLastMonitor) {
Debug::log(ERR, "Relative monitor workspace on monitor null!");
result = INT_MAX;
return result;
}
// monitor relative
result = (int)getPlusMinusKeywordResult(in.substr(1), 0);
// result now has +/- what we should move on mon
int remains = (int)result;
int currentID = g_pCompositor->m_pLastMonitor->activeWorkspace;
int searchID = currentID;
while (remains != 0) {
if (remains < 0)
searchID--;
else
searchID++;
if (g_pCompositor->workspaceIDOutOfBounds(searchID)){
// means we need to wrap around
int lowestID = 99999;
int highestID = -99999;
for (auto& w : g_pCompositor->m_lWorkspaces) {
if (w.m_iID < lowestID)
lowestID = w.m_iID;
if (w.m_iID > highestID)
highestID = w.m_iID;
}
if (remains < 0)
searchID = highestID;
else
searchID = lowestID;
}
if (const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(searchID); PWORKSPACE && PWORKSPACE->m_iID != SPECIAL_WORKSPACE_ID) {
if (PWORKSPACE->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID) {
currentID = PWORKSPACE->m_iID;
if (remains < 0)
remains++;
else
remains--;
}
}
}
result = currentID;
outName = g_pCompositor->getWorkspaceByID(currentID)->m_szName;
} else {
if (g_pCompositor->m_pLastMonitor)
result = std::clamp((int)getPlusMinusKeywordResult(in, g_pCompositor->m_pLastMonitor->activeWorkspace), 1, INT_MAX);
else if (isNumber(in))
result = std::clamp(std::stoi(in), 1, INT_MAX);
else {
Debug::log(ERR, "Relative workspace on no mon!");
result = INT_MAX;
}
outName = std::to_string(result);
}
} }
return result; return result;
@@ -146,4 +233,35 @@ float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Ve
const float DX = std::max((double)0, std::max(p1.x - vec.x, vec.x - p2.x)); const float DX = std::max((double)0, std::max(p1.x - vec.x, vec.x - p2.x));
const float DY = std::max((double)0, std::max(p1.y - vec.y, vec.y - p2.y)); const float DY = std::max((double)0, std::max(p1.y - vec.y, vec.y - p2.y));
return DX * DX + DY * DY; return DX * DX + DY * DY;
}
// Execute a shell command and get the output
std::string execAndGet(const char* cmd) {
std::array<char, 128> buffer;
std::string result;
const std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
if (!pipe) {
Debug::log(ERR, "execAndGet: failed in pipe");
return "";
}
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
result += buffer.data();
}
return result;
}
void logSystemInfo() {
struct utsname unameInfo;
uname(&unameInfo);
Debug::log(LOG, "System name: %s", unameInfo.sysname);
Debug::log(LOG, "Node name: %s", unameInfo.nodename);
Debug::log(LOG, "Release: %s", unameInfo.release);
Debug::log(LOG, "Version: %s", unameInfo.version);
// log etc
Debug::log(LOG, "os-release:");
Debug::log(NONE, "%s", execAndGet("cat /etc/os-release").c_str());
} }

View File

@@ -11,5 +11,7 @@ bool isNumber(const std::string&);
bool isDirection(const std::string&); bool isDirection(const std::string&);
int getWorkspaceIDFromString(const std::string&, std::string&); int getWorkspaceIDFromString(const std::string&, std::string&);
float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2); float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2);
void logSystemInfo();
std::string execAndGet(const char*);
float getPlusMinusKeywordResult(std::string in, float relative); float getPlusMinusKeywordResult(std::string in, float relative);

View File

@@ -27,8 +27,13 @@ struct SMonitor {
wlr_output* output = nullptr; wlr_output* output = nullptr;
float refreshRate = 60; float refreshRate = 60;
wlr_output_damage* damage = nullptr; wlr_output_damage* damage = nullptr;
bool needsFrameSkip = false; int framesToSkip = 0;
int forceFullFrames = 0;
bool noFrameSchedule = false;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
// for the special workspace
bool specialWorkspaceOpen = false;
// Double-linked list because we need to have constant mem addresses for signals // Double-linked list because we need to have constant mem addresses for signals
// We have to store pointers and use raw new/delete because they might be moved between them // We have to store pointers and use raw new/delete because they might be moved between them

View File

@@ -20,12 +20,13 @@ void addSurfaceGlobalOffset(SSurfaceTreeNode* node, int* lx, int* ly) {
} }
} }
SSurfaceTreeNode* createTree(wlr_surface* pSurface) { SSurfaceTreeNode* createTree(wlr_surface* pSurface, CWindow* pWindow) {
SubsurfaceTree::surfaceTreeNodes.push_back(SSurfaceTreeNode()); SubsurfaceTree::surfaceTreeNodes.push_back(SSurfaceTreeNode());
const auto PNODE = &SubsurfaceTree::surfaceTreeNodes.back(); const auto PNODE = &SubsurfaceTree::surfaceTreeNodes.back();
PNODE->pSurface = pSurface; PNODE->pSurface = pSurface;
PNODE->pWindowOwner = pWindow;
PNODE->hyprListener_newSubsurface.initCallback(&pSurface->events.new_subsurface, &Events::listener_newSubsurfaceNode, PNODE, "SurfaceTreeNode"); PNODE->hyprListener_newSubsurface.initCallback(&pSurface->events.new_subsurface, &Events::listener_newSubsurfaceNode, PNODE, "SurfaceTreeNode");
PNODE->hyprListener_commit.initCallback(&pSurface->events.commit, &Events::listener_commitSubsurface, PNODE, "SurfaceTreeNode"); PNODE->hyprListener_commit.initCallback(&pSurface->events.commit, &Events::listener_commitSubsurface, PNODE, "SurfaceTreeNode");
@@ -42,16 +43,21 @@ SSurfaceTreeNode* createTree(wlr_surface* pSurface) {
return PNODE; return PNODE;
} }
SSurfaceTreeNode* createSubsurfaceNode(SSurfaceTreeNode* pParent, SSubsurface* pSubsurface, wlr_surface* surface) { SSurfaceTreeNode* createSubsurfaceNode(SSurfaceTreeNode* pParent, SSubsurface* pSubsurface, wlr_surface* surface, CWindow* pWindow) {
const auto PNODE = createTree(surface); const auto PNODE = createTree(surface, pWindow);
PNODE->pParent = pParent; PNODE->pParent = pParent;
PNODE->pSubsurface = pSubsurface; PNODE->pSubsurface = pSubsurface;
Debug::log(LOG, "Creating a subsurface Node! (pWindow: %x)", pWindow);
return PNODE; return PNODE;
} }
SSurfaceTreeNode* SubsurfaceTree::createTreeRoot(wlr_surface* pSurface, applyGlobalOffsetFn fn, void* data) { SSurfaceTreeNode* SubsurfaceTree::createTreeRoot(wlr_surface* pSurface, applyGlobalOffsetFn fn, void* data, CWindow* pWindow) {
const auto PNODE = createTree(pSurface); const auto PNODE = createTree(pSurface, pWindow);
Debug::log(LOG, "Creating a surfaceTree Root! (pWindow: %x)", pWindow);
PNODE->offsetfn = fn; PNODE->offsetfn = fn;
PNODE->globalOffsetData = data; PNODE->globalOffsetData = data;
@@ -83,6 +89,20 @@ void SubsurfaceTree::destroySurfaceTree(SSurfaceTreeNode* pNode) {
pNode->hyprListener_destroy.removeCallback(); pNode->hyprListener_destroy.removeCallback();
pNode->hyprListener_newSubsurface.removeCallback(); pNode->hyprListener_newSubsurface.removeCallback();
// damage
if (pNode->pSurface) {
wlr_box extents = {};
wlr_surface_get_extends(pNode->pSurface, &extents);
int lx = 0, ly = 0;
addSurfaceGlobalOffset(pNode, &lx, &ly);
extents.x += lx;
extents.y += ly;
g_pHyprRenderer->damageBox(&extents);
}
surfaceTreeNodes.remove(*pNode); surfaceTreeNodes.remove(*pNode);
Debug::log(LOG, "SurfaceTree Node removed"); Debug::log(LOG, "SurfaceTree Node removed");
@@ -120,6 +140,8 @@ void Events::listener_newSubsurfaceNode(void* owner, void* data) {
PNEWSUBSURFACE->hyprListener_unmap.initCallback(&PSUBSURFACE->events.unmap, &Events::listener_unmapSubsurface, PNEWSUBSURFACE, "Subsurface"); PNEWSUBSURFACE->hyprListener_unmap.initCallback(&PSUBSURFACE->events.unmap, &Events::listener_unmapSubsurface, PNEWSUBSURFACE, "Subsurface");
PNEWSUBSURFACE->hyprListener_destroy.initCallback(&PSUBSURFACE->events.destroy, &Events::listener_destroySubsurface, PNEWSUBSURFACE, "Subsurface"); PNEWSUBSURFACE->hyprListener_destroy.initCallback(&PSUBSURFACE->events.destroy, &Events::listener_destroySubsurface, PNEWSUBSURFACE, "Subsurface");
PNEWSUBSURFACE->pWindowOwner = pNode->pWindowOwner;
wlr_subsurface* existingWlrSubsurface; wlr_subsurface* existingWlrSubsurface;
wl_list_for_each(existingWlrSubsurface, &PSUBSURFACE->surface->current.subsurfaces_below, current.link) { wl_list_for_each(existingWlrSubsurface, &PSUBSURFACE->surface->current.subsurfaces_below, current.link) {
listener_newSubsurfaceNode(pNode, existingWlrSubsurface); listener_newSubsurfaceNode(pNode, existingWlrSubsurface);
@@ -134,7 +156,7 @@ void Events::listener_mapSubsurface(void* owner, void* data) {
Debug::log(LOG, "Subsurface %x mapped", subsurface->pSubsurface); Debug::log(LOG, "Subsurface %x mapped", subsurface->pSubsurface);
subsurface->pChild = createSubsurfaceNode(subsurface->pParent, subsurface, subsurface->pSubsurface->surface); subsurface->pChild = createSubsurfaceNode(subsurface->pParent, subsurface, subsurface->pSubsurface->surface, subsurface->pWindowOwner);
} }
void Events::listener_unmapSubsurface(void* owner, void* data) { void Events::listener_unmapSubsurface(void* owner, void* data) {
@@ -154,6 +176,8 @@ void Events::listener_unmapSubsurface(void* owner, void* data) {
extents.x += lx; extents.x += lx;
extents.y += ly; extents.y += ly;
g_pHyprRenderer->damageBox(&extents);
SubsurfaceTree::destroySurfaceTree(subsurface->pChild); SubsurfaceTree::destroySurfaceTree(subsurface->pChild);
subsurface->pChild = nullptr; subsurface->pChild = nullptr;
} }
@@ -162,6 +186,14 @@ void Events::listener_unmapSubsurface(void* owner, void* data) {
void Events::listener_commitSubsurface(void* owner, void* data) { void Events::listener_commitSubsurface(void* owner, void* data) {
SSurfaceTreeNode* pNode = (SSurfaceTreeNode*)owner; SSurfaceTreeNode* pNode = (SSurfaceTreeNode*)owner;
// no damaging if it's not visible
if (!g_pHyprRenderer->shouldRenderWindow(pNode->pWindowOwner)) {
if (g_pConfigManager->getInt("debug:log_damage"))
Debug::log(LOG, "Refusing to commit damage from %x because it's invisible.", pNode->pWindowOwner);
return;
}
int lx = 0, ly = 0; int lx = 0, ly = 0;
addSurfaceGlobalOffset(pNode, &lx, &ly); addSurfaceGlobalOffset(pNode, &lx, &ly);

View File

@@ -4,6 +4,7 @@
#include <list> #include <list>
struct SSubsurface; struct SSubsurface;
class CWindow;
typedef void (*applyGlobalOffsetFn)(void *, int *, int *); typedef void (*applyGlobalOffsetFn)(void *, int *, int *);
@@ -21,6 +22,7 @@ struct SSurfaceTreeNode {
applyGlobalOffsetFn offsetfn; applyGlobalOffsetFn offsetfn;
void *globalOffsetData; void *globalOffsetData;
CWindow* pWindowOwner = nullptr;
bool operator==(const SSurfaceTreeNode& rhs) { bool operator==(const SSurfaceTreeNode& rhs) {
return pSurface == rhs.pSurface; return pSurface == rhs.pSurface;
@@ -37,13 +39,15 @@ struct SSubsurface {
DYNLISTENER(unmap); DYNLISTENER(unmap);
DYNLISTENER(destroy); DYNLISTENER(destroy);
CWindow* pWindowOwner = nullptr;
bool operator==(const SSubsurface& rhs) { bool operator==(const SSubsurface& rhs) {
return pSubsurface == rhs.pSubsurface; return pSubsurface == rhs.pSubsurface;
} }
}; };
namespace SubsurfaceTree { namespace SubsurfaceTree {
SSurfaceTreeNode* createTreeRoot(wlr_surface*, applyGlobalOffsetFn, void*); SSurfaceTreeNode* createTreeRoot(wlr_surface*, applyGlobalOffsetFn, void*, CWindow* pWindow = nullptr);
void destroySurfaceTree(SSurfaceTreeNode*); void destroySurfaceTree(SSurfaceTreeNode*);
inline std::list<SSurfaceTreeNode> surfaceTreeNodes; inline std::list<SSurfaceTreeNode> surfaceTreeNodes;

17
src/helpers/Timer.cpp Normal file
View File

@@ -0,0 +1,17 @@
#include "Timer.hpp"
void CTimer::reset() {
m_tpLastReset = std::chrono::system_clock::now();
}
std::chrono::system_clock::duration CTimer::getDuration() {
return std::chrono::system_clock::now() - m_tpLastReset;
}
int CTimer::getMillis() {
return std::chrono::duration_cast<std::chrono::milliseconds>(getDuration()).count();
}
float CTimer::getSeconds() {
return std::chrono::duration_cast<std::chrono::milliseconds>(getDuration()).count() / 1000.f;
}

15
src/helpers/Timer.hpp Normal file
View File

@@ -0,0 +1,15 @@
#pragma once
#include "../defines.hpp"
class CTimer {
public:
void reset();
float getSeconds();
int getMillis();
private:
std::chrono::system_clock::time_point m_tpLastReset;
std::chrono::system_clock::duration getDuration();
};

View File

@@ -2,7 +2,7 @@
#include "../events/Events.hpp" #include "../events/Events.hpp"
#include "../defines.hpp" #include "../defines.hpp"
#include "../../wlr-layer-shell-unstable-v1-protocol.h" #include "wlr-layer-shell-unstable-v1-protocol.h"
#include "../Window.hpp" #include "../Window.hpp"
#include "SubsurfaceTree.hpp" #include "SubsurfaceTree.hpp"
#include "AnimatedVariable.hpp" #include "AnimatedVariable.hpp"
@@ -69,6 +69,10 @@ struct SKeyboard {
DYNLISTENER(keyboardKey); DYNLISTENER(keyboardKey);
DYNLISTENER(keyboardDestroy); DYNLISTENER(keyboardDestroy);
bool active = false;
xkb_rule_names currentRules;
// For the list lookup // For the list lookup
bool operator==(const SKeyboard& rhs) { bool operator==(const SKeyboard& rhs) {
return keyboard == rhs.keyboard; return keyboard == rhs.keyboard;
@@ -151,4 +155,56 @@ struct SDrag {
DYNLISTENER(mapIcon); DYNLISTENER(mapIcon);
DYNLISTENER(unmapIcon); DYNLISTENER(unmapIcon);
DYNLISTENER(commitIcon); DYNLISTENER(commitIcon);
}; };
struct STablet {
DYNLISTENER(Tip);
DYNLISTENER(Axis);
DYNLISTENER(Button);
DYNLISTENER(Proximity);
DYNLISTENER(Destroy);
wlr_tablet* wlrTablet = nullptr;
wlr_tablet_v2_tablet* wlrTabletV2 = nullptr;
wlr_input_device* wlrDevice = nullptr;
bool operator==(const STablet& b) {
return wlrDevice == b.wlrDevice;
}
};
struct STabletTool {
wlr_tablet_tool* wlrTabletTool = nullptr;
wlr_tablet_v2_tablet_tool* wlrTabletToolV2 = nullptr;
wlr_tablet_v2_tablet* wlrTabletOwnerV2 = nullptr;
wlr_surface* pSurface = nullptr;
double tiltX = 0;
double tiltY = 0;
bool active = true;
DYNLISTENER(TabletToolDestroy);
DYNLISTENER(TabletToolSetCursor);
bool operator==(const STabletTool& b) {
return wlrTabletTool == b.wlrTabletTool;
}
};
struct STabletPad {
wlr_tablet_v2_tablet_pad* wlrTabletPadV2 = nullptr;
STablet* pTabletParent = nullptr;
DYNLISTENER(Attach);
DYNLISTENER(Button);
DYNLISTENER(Strip);
DYNLISTENER(Ring);
DYNLISTENER(Destroy);
bool operator==(const STabletPad& b) {
return wlrTabletPadV2 == b.wlrTabletPadV2;
}
};

View File

@@ -1,7 +1,7 @@
#include "Workspace.hpp" #include "Workspace.hpp"
#include "../Compositor.hpp" #include "../Compositor.hpp"
CWorkspace::CWorkspace(int monitorID) { CWorkspace::CWorkspace(int monitorID, bool special) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
if (!PMONITOR) { if (!PMONITOR) {
@@ -10,16 +10,20 @@ CWorkspace::CWorkspace(int monitorID) {
} }
m_iMonitorID = monitorID; m_iMonitorID = monitorID;
m_pWlrHandle = wlr_ext_workspace_handle_v1_create(PMONITOR->pWLRWorkspaceGroupHandle);
// set geometry here cuz we can m_bIsSpecialWorkspace = special;
wl_array_init(&m_wlrCoordinateArr);
*reinterpret_cast<int*>(wl_array_add(&m_wlrCoordinateArr, sizeof(int))) = (int)PMONITOR->vecPosition.x; if (!special) {
*reinterpret_cast<int*>(wl_array_add(&m_wlrCoordinateArr, sizeof(int))) = (int)PMONITOR->vecPosition.y; m_pWlrHandle = wlr_ext_workspace_handle_v1_create(PMONITOR->pWLRWorkspaceGroupHandle);
wlr_ext_workspace_handle_v1_set_coordinates(m_pWlrHandle, &m_wlrCoordinateArr);
wlr_ext_workspace_handle_v1_set_hidden(m_pWlrHandle, false); // set geometry here cuz we can
wlr_ext_workspace_handle_v1_set_urgent(m_pWlrHandle, false); wl_array_init(&m_wlrCoordinateArr);
*reinterpret_cast<int*>(wl_array_add(&m_wlrCoordinateArr, sizeof(int))) = (int)PMONITOR->vecPosition.x;
*reinterpret_cast<int*>(wl_array_add(&m_wlrCoordinateArr, sizeof(int))) = (int)PMONITOR->vecPosition.y;
wlr_ext_workspace_handle_v1_set_coordinates(m_pWlrHandle, &m_wlrCoordinateArr);
wlr_ext_workspace_handle_v1_set_hidden(m_pWlrHandle, false);
wlr_ext_workspace_handle_v1_set_urgent(m_pWlrHandle, false);
}
m_vRenderOffset.m_pWorkspace = this; m_vRenderOffset.m_pWorkspace = this;
m_vRenderOffset.create(AVARTYPE_VECTOR, &g_pConfigManager->getConfigValuePtr("animations:workspaces_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:workspaces")->intValue, &g_pConfigManager->getConfigValuePtr("animations:workspaces_curve")->strValue, nullptr, AVARDAMAGE_ENTIRE); m_vRenderOffset.create(AVARTYPE_VECTOR, &g_pConfigManager->getConfigValuePtr("animations:workspaces_speed")->floatValue, &g_pConfigManager->getConfigValuePtr("animations:workspaces")->intValue, &g_pConfigManager->getConfigValuePtr("animations:workspaces_curve")->strValue, nullptr, AVARDAMAGE_ENTIRE);
@@ -31,6 +35,8 @@ CWorkspace::CWorkspace(int monitorID) {
CWorkspace::~CWorkspace() { CWorkspace::~CWorkspace() {
m_vRenderOffset.unregister(); m_vRenderOffset.unregister();
Debug::log(LOG, "Destroying workspace ID %d", m_iID);
if (m_pWlrHandle) { if (m_pWlrHandle) {
wlr_ext_workspace_handle_v1_set_active(m_pWlrHandle, false); wlr_ext_workspace_handle_v1_set_active(m_pWlrHandle, false);
wlr_ext_workspace_handle_v1_destroy(m_pWlrHandle); wlr_ext_workspace_handle_v1_destroy(m_pWlrHandle);
@@ -38,7 +44,7 @@ CWorkspace::~CWorkspace() {
} }
} }
void CWorkspace::startAnim(bool in, bool left) { void CWorkspace::startAnim(bool in, bool left, bool instant) {
const auto ANIMSTYLE = g_pConfigManager->getString("animations:workspaces_style"); const auto ANIMSTYLE = g_pConfigManager->getString("animations:workspaces_style");
if (ANIMSTYLE == "fade") { if (ANIMSTYLE == "fade") {
@@ -51,6 +57,18 @@ void CWorkspace::startAnim(bool in, bool left) {
m_fAlpha.setValueAndWarp(255.f); m_fAlpha.setValueAndWarp(255.f);
m_fAlpha = 0.f; m_fAlpha = 0.f;
} }
} else if (ANIMSTYLE == "slidevert") {
// fallback is slide
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
m_fAlpha.setValueAndWarp(255.f); // fix a bug, if switching from fade -> slide.
if (in) {
m_vRenderOffset.setValueAndWarp(Vector2D(0, left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y));
m_vRenderOffset = Vector2D(0, 0);
} else {
m_vRenderOffset = Vector2D(0, left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y);
}
} else { } else {
// fallback is slide // fallback is slide
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
@@ -64,10 +82,37 @@ void CWorkspace::startAnim(bool in, bool left) {
m_vRenderOffset = Vector2D(left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x, 0); m_vRenderOffset = Vector2D(left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x, 0);
} }
} }
if (instant) {
m_vRenderOffset.warp();
m_fAlpha.warp();
}
} }
void CWorkspace::setActive(bool on) { void CWorkspace::setActive(bool on) {
if (m_pWlrHandle) { if (m_pWlrHandle) {
wlr_ext_workspace_handle_v1_set_active(m_pWlrHandle, on); wlr_ext_workspace_handle_v1_set_active(m_pWlrHandle, on);
} }
}
void CWorkspace::moveToMonitor(const int& id) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(id);
if (!PMONITOR || m_bIsSpecialWorkspace)
return;
wlr_ext_workspace_handle_v1_set_active(m_pWlrHandle, false);
wlr_ext_workspace_handle_v1_destroy(m_pWlrHandle);
m_pWlrHandle = wlr_ext_workspace_handle_v1_create(PMONITOR->pWLRWorkspaceGroupHandle);
// set geometry here cuz we can
wl_array_init(&m_wlrCoordinateArr);
*reinterpret_cast<int*>(wl_array_add(&m_wlrCoordinateArr, sizeof(int))) = (int)PMONITOR->vecPosition.x;
*reinterpret_cast<int*>(wl_array_add(&m_wlrCoordinateArr, sizeof(int))) = (int)PMONITOR->vecPosition.y;
wlr_ext_workspace_handle_v1_set_coordinates(m_pWlrHandle, &m_wlrCoordinateArr);
wlr_ext_workspace_handle_v1_set_hidden(m_pWlrHandle, false);
wlr_ext_workspace_handle_v1_set_urgent(m_pWlrHandle, false);
wlr_ext_workspace_handle_v1_set_name(m_pWlrHandle, m_szName.c_str());
} }

View File

@@ -10,7 +10,7 @@ enum eFullscreenMode : uint8_t {
class CWorkspace { class CWorkspace {
public: public:
CWorkspace(int monitorID); CWorkspace(int monitorID, bool special = false);
~CWorkspace(); ~CWorkspace();
// Workspaces ID-based have IDs > 0 // Workspaces ID-based have IDs > 0
@@ -29,10 +29,15 @@ public:
CAnimatedVariable m_vRenderOffset; CAnimatedVariable m_vRenderOffset;
CAnimatedVariable m_fAlpha; CAnimatedVariable m_fAlpha;
// "scratchpad"
bool m_bIsSpecialWorkspace = false;
// user-set // user-set
bool m_bDefaultFloating = false; bool m_bDefaultFloating = false;
bool m_bDefaultPseudo = false; bool m_bDefaultPseudo = false;
void startAnim(bool in, bool left); void startAnim(bool in, bool left, bool instant = false);
void setActive(bool on); void setActive(bool on);
void moveToMonitor(const int&);
}; };

View File

@@ -77,6 +77,9 @@ extern "C" {
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include <wlr/xwayland.h> #include <wlr/xwayland.h>
#include <wlr/util/region.h> #include <wlr/util/region.h>
#include <wlr/types/wlr_tablet_pad.h>
#include <wlr/types/wlr_tablet_tool.h>
#include <wlr/types/wlr_tablet_v2.h>
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
#include <X11/Xproto.h> #include <X11/Xproto.h>
#include <wlr/render/egl.h> #include <wlr/render/egl.h>
@@ -84,6 +87,7 @@ extern "C" {
#include <wlr/render/wlr_texture.h> #include <wlr/render/wlr_texture.h>
#include <wlr/types/wlr_pointer_constraints_v1.h> #include <wlr/types/wlr_pointer_constraints_v1.h>
#include <wlr/types/wlr_relative_pointer_v1.h> #include <wlr/types/wlr_relative_pointer_v1.h>
#include <wlr/interfaces/wlr_keyboard.h>
} }
#undef class #undef class
@@ -109,4 +113,4 @@ extern "C" {
#include "helpers/Vector2D.hpp" #include "helpers/Vector2D.hpp"
#include "../ext-workspace-unstable-v1-protocol.h" #include "ext-workspace-unstable-v1-protocol.h"

View File

@@ -160,10 +160,22 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode) {
} }
} }
PWINDOW->m_vRealSize = calcSize; const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID);
PWINDOW->m_vRealPosition = calcPos;
g_pXWaylandManager->setWindowSize(PWINDOW, calcSize); if (PWORKSPACE->m_bIsSpecialWorkspace) {
// if special, we adjust the coords a bit
static auto *const PSCALEFACTOR = &g_pConfigManager->getConfigValuePtr("dwindle:special_scale_factor")->floatValue;
PWINDOW->m_vRealPosition = calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f;
PWINDOW->m_vRealSize = calcSize * *PSCALEFACTOR;
g_pXWaylandManager->setWindowSize(PWINDOW, calcSize * *PSCALEFACTOR);
} else {
PWINDOW->m_vRealSize = calcSize;
PWINDOW->m_vRealPosition = calcPos;
g_pXWaylandManager->setWindowSize(PWINDOW, calcSize);
}
} }
void CHyprDwindleLayout::onWindowCreated(CWindow* pWindow) { void CHyprDwindleLayout::onWindowCreated(CWindow* pWindow) {
@@ -184,7 +196,7 @@ void CHyprDwindleLayout::onWindowCreated(CWindow* pWindow) {
SDwindleNodeData* OPENINGON; SDwindleNodeData* OPENINGON;
const auto MONFROMCURSOR = g_pCompositor->getMonitorFromCursor(); const auto MONFROMCURSOR = g_pCompositor->getMonitorFromCursor();
if (PMONITOR->ID == MONFROMCURSOR->ID && PNODE->workspaceID == PMONITOR->activeWorkspace) { if (PMONITOR->ID == MONFROMCURSOR->ID && (PNODE->workspaceID == PMONITOR->activeWorkspace || (PNODE->workspaceID == SPECIAL_WORKSPACE_ID && PMONITOR->specialWorkspaceOpen))) {
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(g_pInputManager->getMouseCoordsInternal())); OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(g_pInputManager->getMouseCoordsInternal()));
// happens on reserved area // happens on reserved area
@@ -196,6 +208,11 @@ void CHyprDwindleLayout::onWindowCreated(CWindow* pWindow) {
Debug::log(LOG, "OPENINGON: %x, Workspace: %i, Monitor: %i", OPENINGON, PNODE->workspaceID, PMONITOR->ID); Debug::log(LOG, "OPENINGON: %x, Workspace: %i, Monitor: %i", OPENINGON, PNODE->workspaceID, PMONITOR->ID);
if (OPENINGON && OPENINGON->workspaceID != PNODE->workspaceID) {
// special workspace handling
OPENINGON = getFirstNodeOnWorkspace(PNODE->workspaceID);
}
// if it's the first, it's easy. Make it fullscreen. // if it's the first, it's easy. Make it fullscreen.
if (!OPENINGON || OPENINGON->pWindow == pWindow) { if (!OPENINGON || OPENINGON->pWindow == pWindow) {
PNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft; PNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
@@ -356,6 +373,19 @@ void CHyprDwindleLayout::recalculateMonitor(const int& monid) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(monid); const auto PMONITOR = g_pCompositor->getMonitorFromID(monid);
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
if (!PWORKSPACE)
return;
if (PMONITOR->specialWorkspaceOpen) {
const auto TOPNODE = getMasterNodeOnWorkspace(SPECIAL_WORKSPACE_ID);
if (TOPNODE && PMONITOR) {
TOPNODE->position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft;
TOPNODE->size = PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight;
TOPNODE->recalcSizePosRecursive();
}
}
// Ignore any recalc events if we have a fullscreen window. // Ignore any recalc events if we have a fullscreen window.
if (PWORKSPACE->m_bHasFullscreenWindow) if (PWORKSPACE->m_bHasFullscreenWindow)
return; return;
@@ -424,6 +454,13 @@ void CHyprDwindleLayout::onBeginDragWindow() {
return; return;
} }
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(DRAGGINGWINDOW->m_iWorkspaceID);
if (PWORKSPACE->m_bHasFullscreenWindow) {
Debug::log(LOG, "Rejecting drag on a fullscreen workspace.");
return;
}
DRAGGINGWINDOW->m_bDraggingTiled = false; DRAGGINGWINDOW->m_bDraggingTiled = false;
if (!DRAGGINGWINDOW->m_bIsFloating) { if (!DRAGGINGWINDOW->m_bIsFloating) {
@@ -445,6 +482,9 @@ void CHyprDwindleLayout::onBeginDragWindow() {
void CHyprDwindleLayout::onEndDragWindow() { void CHyprDwindleLayout::onEndDragWindow() {
const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow; const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow;
if (!g_pCompositor->windowValidMapped(DRAGGINGWINDOW))
return;
if (DRAGGINGWINDOW->m_bDraggingTiled) { if (DRAGGINGWINDOW->m_bDraggingTiled) {
DRAGGINGWINDOW->m_bIsFloating = false; DRAGGINGWINDOW->m_bIsFloating = false;
changeWindowFloatingMode(DRAGGINGWINDOW); changeWindowFloatingMode(DRAGGINGWINDOW);
@@ -457,8 +497,10 @@ void CHyprDwindleLayout::onMouseMove(const Vector2D& mousePos) {
const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow; const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow;
// Window invalid or drag begin size 0,0 meaning we rejected it. // Window invalid or drag begin size 0,0 meaning we rejected it.
if (!g_pCompositor->windowValidMapped(DRAGGINGWINDOW) || m_vBeginDragSizeXY == Vector2D()) if (!g_pCompositor->windowValidMapped(DRAGGINGWINDOW) || m_vBeginDragSizeXY == Vector2D()) {
g_pInputManager->currentlyDraggedWindow = nullptr;
return; return;
}
const auto DELTA = Vector2D(mousePos.x - m_vBeginDragXY.x, mousePos.y - m_vBeginDragXY.y); const auto DELTA = Vector2D(mousePos.x - m_vBeginDragXY.x, mousePos.y - m_vBeginDragXY.y);
const auto TICKDELTA = Vector2D(mousePos.x - m_vLastDragXY.x, mousePos.y - m_vLastDragXY.y); const auto TICKDELTA = Vector2D(mousePos.x - m_vLastDragXY.x, mousePos.y - m_vLastDragXY.y);
@@ -480,80 +522,7 @@ void CHyprDwindleLayout::onMouseMove(const Vector2D& mousePos) {
g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv()); g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goalv());
} else { } else {
// we need to adjust the splitratio resizeActiveWindow(TICKDELTA, DRAGGINGWINDOW);
// get some data about our window
const auto PNODE = getNodeFromWindow(DRAGGINGWINDOW);
const auto PMONITOR = g_pCompositor->getMonitorFromID(DRAGGINGWINDOW->m_iMonitorID);
const bool DISPLAYLEFT = STICKS(DRAGGINGWINDOW->m_vPosition.x, PMONITOR->vecPosition.x + PMONITOR->vecReservedTopLeft.x);
const bool DISPLAYRIGHT = STICKS(DRAGGINGWINDOW->m_vPosition.x + DRAGGINGWINDOW->m_vSize.x, PMONITOR->vecPosition.x + PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x);
const bool DISPLAYTOP = STICKS(DRAGGINGWINDOW->m_vPosition.y, PMONITOR->vecPosition.y + PMONITOR->vecReservedTopLeft.y);
const bool DISPLAYBOTTOM = STICKS(DRAGGINGWINDOW->m_vPosition.y + DRAGGINGWINDOW->m_vSize.y, PMONITOR->vecPosition.y + PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y);
// construct allowed movement
Vector2D allowedMovement = TICKDELTA;
if (DISPLAYLEFT && DISPLAYRIGHT)
allowedMovement.x = 0;
if (DISPLAYBOTTOM && DISPLAYTOP)
allowedMovement.y = 0;
// get the correct containers to apply splitratio to
const auto PPARENT = PNODE->pParent;
if (!PPARENT)
return; // the only window on a workspace, ignore
const bool PARENTSIDEBYSIDE = !PPARENT->splitTop;
// Get the parent's parent
auto PPARENT2 = PPARENT->pParent;
// No parent means we have only 2 windows, and thus one axis of freedom
if (!PPARENT2) {
if (PARENTSIDEBYSIDE) {
allowedMovement.x *= 2.f / PPARENT->size.x;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, (double)0.1f, (double)1.9f);
PPARENT->recalcSizePosRecursive();
} else {
allowedMovement.y *= 2.f / PPARENT->size.y;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, (double)0.1f, (double)1.9f);
PPARENT->recalcSizePosRecursive();
}
return;
}
// Get first parent with other split
while(PPARENT2 && PPARENT2->splitTop == !PARENTSIDEBYSIDE)
PPARENT2 = PPARENT2->pParent;
// no parent, one axis of freedom
if (!PPARENT2) {
if (PARENTSIDEBYSIDE) {
allowedMovement.x *= 2.f / PPARENT->size.x;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, (double)0.1f, (double)1.9f);
PPARENT->recalcSizePosRecursive();
} else {
allowedMovement.y *= 2.f / PPARENT->size.y;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, (double)0.1f, (double)1.9f);
PPARENT->recalcSizePosRecursive();
}
return;
}
// 2 axes of freedom
const auto SIDECONTAINER = PARENTSIDEBYSIDE ? PPARENT : PPARENT2;
const auto TOPCONTAINER = PARENTSIDEBYSIDE ? PPARENT2 : PPARENT;
allowedMovement.x *= 2.f / SIDECONTAINER->size.x;
allowedMovement.y *= 2.f / TOPCONTAINER->size.y;
SIDECONTAINER->splitRatio = std::clamp(SIDECONTAINER->splitRatio + allowedMovement.x, (double)0.1f, (double)1.9f);
TOPCONTAINER->splitRatio = std::clamp(TOPCONTAINER->splitRatio + allowedMovement.y, (double)0.1f, (double)1.9f);
SIDECONTAINER->recalcSizePosRecursive();
TOPCONTAINER->recalcSizePosRecursive();
} }
} }
@@ -571,6 +540,93 @@ void CHyprDwindleLayout::onMouseMove(const Vector2D& mousePos) {
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
} }
void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow* pWindow) {
const auto PWINDOW = pWindow ? pWindow : g_pCompositor->m_pLastWindow;
if (!g_pCompositor->windowValidMapped(PWINDOW))
return;
const auto PNODE = getNodeFromWindow(PWINDOW);
if (!PNODE) {
PWINDOW->m_vRealSize = Vector2D(std::clamp((PWINDOW->m_vRealSize.goalv() + pixResize).x, (double)20, (double)999999), std::clamp((PWINDOW->m_vRealSize.goalv() + pixResize).y, (double)20, (double)999999));
return;
}
// get some data about our window
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
const bool DISPLAYLEFT = STICKS(PWINDOW->m_vPosition.x, PMONITOR->vecPosition.x + PMONITOR->vecReservedTopLeft.x);
const bool DISPLAYRIGHT = STICKS(PWINDOW->m_vPosition.x + PWINDOW->m_vSize.x, PMONITOR->vecPosition.x + PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x);
const bool DISPLAYTOP = STICKS(PWINDOW->m_vPosition.y, PMONITOR->vecPosition.y + PMONITOR->vecReservedTopLeft.y);
const bool DISPLAYBOTTOM = STICKS(PWINDOW->m_vPosition.y + PWINDOW->m_vSize.y, PMONITOR->vecPosition.y + PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y);
// construct allowed movement
Vector2D allowedMovement = pixResize;
if (DISPLAYLEFT && DISPLAYRIGHT)
allowedMovement.x = 0;
if (DISPLAYBOTTOM && DISPLAYTOP)
allowedMovement.y = 0;
// get the correct containers to apply splitratio to
const auto PPARENT = PNODE->pParent;
if (!PPARENT)
return; // the only window on a workspace, ignore
const bool PARENTSIDEBYSIDE = !PPARENT->splitTop;
// Get the parent's parent
auto PPARENT2 = PPARENT->pParent;
// No parent means we have only 2 windows, and thus one axis of freedom
if (!PPARENT2) {
if (PARENTSIDEBYSIDE) {
allowedMovement.x *= 2.f / PPARENT->size.x;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, (double)0.1f, (double)1.9f);
PPARENT->recalcSizePosRecursive();
} else {
allowedMovement.y *= 2.f / PPARENT->size.y;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, (double)0.1f, (double)1.9f);
PPARENT->recalcSizePosRecursive();
}
return;
}
// Get first parent with other split
while (PPARENT2 && PPARENT2->splitTop == !PARENTSIDEBYSIDE)
PPARENT2 = PPARENT2->pParent;
// no parent, one axis of freedom
if (!PPARENT2) {
if (PARENTSIDEBYSIDE) {
allowedMovement.x *= 2.f / PPARENT->size.x;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.x, (double)0.1f, (double)1.9f);
PPARENT->recalcSizePosRecursive();
} else {
allowedMovement.y *= 2.f / PPARENT->size.y;
PPARENT->splitRatio = std::clamp(PPARENT->splitRatio + allowedMovement.y, (double)0.1f, (double)1.9f);
PPARENT->recalcSizePosRecursive();
}
return;
}
// 2 axes of freedom
const auto SIDECONTAINER = PARENTSIDEBYSIDE ? PPARENT : PPARENT2;
const auto TOPCONTAINER = PARENTSIDEBYSIDE ? PPARENT2 : PPARENT;
allowedMovement.x *= 2.f / SIDECONTAINER->size.x;
allowedMovement.y *= 2.f / TOPCONTAINER->size.y;
SIDECONTAINER->splitRatio = std::clamp(SIDECONTAINER->splitRatio + allowedMovement.x, (double)0.1f, (double)1.9f);
TOPCONTAINER->splitRatio = std::clamp(TOPCONTAINER->splitRatio + allowedMovement.y, (double)0.1f, (double)1.9f);
SIDECONTAINER->recalcSizePosRecursive();
TOPCONTAINER->recalcSizePosRecursive();
}
void CHyprDwindleLayout::onWindowCreatedFloating(CWindow* pWindow) { void CHyprDwindleLayout::onWindowCreatedFloating(CWindow* pWindow) {
wlr_box desiredGeometry = {0}; wlr_box desiredGeometry = {0};
g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry); g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry);
@@ -620,21 +676,24 @@ void CHyprDwindleLayout::onWindowCreatedFloating(CWindow* pWindow) {
g_pCompositor->moveWindowToTop(pWindow); g_pCompositor->moveWindowToTop(pWindow);
} }
void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode fullscreenMode) { void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode fullscreenMode, bool on) {
if (!g_pCompositor->windowValidMapped(pWindow)) if (!g_pCompositor->windowValidMapped(pWindow))
return; return;
if (on == pWindow->m_bIsFullscreen)
return; // ignore
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
if (PWORKSPACE->m_bHasFullscreenWindow && !pWindow->m_bIsFullscreen) { if (PWORKSPACE->m_bHasFullscreenWindow && on) {
// if the window wants to be fullscreen but there already is one, // if the window wants to be fullscreen but there already is one,
// ignore the request. // ignore the request.
return; return;
} }
// otherwise, accept it. // otherwise, accept it.
pWindow->m_bIsFullscreen = !pWindow->m_bIsFullscreen; pWindow->m_bIsFullscreen = on;
PWORKSPACE->m_bHasFullscreenWindow = !PWORKSPACE->m_bHasFullscreenWindow; PWORKSPACE->m_bHasFullscreenWindow = !PWORKSPACE->m_bHasFullscreenWindow;
if (!pWindow->m_bIsFullscreen) { if (!pWindow->m_bIsFullscreen) {
@@ -851,6 +910,11 @@ void CHyprDwindleLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
if (!PNODE2 || !PNODE) if (!PNODE2 || !PNODE)
return; return;
if (PNODE->workspaceID != PNODE2->workspaceID) {
Debug::log(ERR, "Dwindle: Rejecting a swap between workspaces");
return;
}
// we will not delete the nodes, just fix the tree // we will not delete the nodes, just fix the tree
if (PNODE2->pParent == PNODE->pParent) { if (PNODE2->pParent == PNODE->pParent) {
const auto PPARENT = PNODE->pParent; const auto PPARENT = PNODE->pParent;
@@ -937,4 +1001,20 @@ void CHyprDwindleLayout::toggleSplit(CWindow* pWindow) {
std::string CHyprDwindleLayout::getLayoutName() { std::string CHyprDwindleLayout::getLayoutName() {
return "dwindle"; return "dwindle";
}
void CHyprDwindleLayout::moveActiveWindow(const Vector2D& delta, CWindow* pWindow) {
const auto PWINDOW = pWindow ? pWindow : g_pCompositor->m_pLastWindow;
if (!g_pCompositor->windowValidMapped(PWINDOW))
return;
if (!PWINDOW->m_bIsFloating) {
Debug::log(LOG, "Dwindle cannot move a tiled window in moveActiveWindow!");
return;
}
PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goalv() + delta;
g_pHyprRenderer->damageWindow(PWINDOW);
} }

View File

@@ -48,10 +48,12 @@ public:
virtual void recalculateWindow(CWindow*); virtual void recalculateWindow(CWindow*);
virtual void changeWindowFloatingMode(CWindow*); virtual void changeWindowFloatingMode(CWindow*);
virtual void onBeginDragWindow(); virtual void onBeginDragWindow();
virtual void resizeActiveWindow(const Vector2D&, CWindow* pWindow = nullptr);
virtual void moveActiveWindow(const Vector2D&, CWindow* pWindow = nullptr);
virtual void onEndDragWindow(); virtual void onEndDragWindow();
virtual void onMouseMove(const Vector2D&); virtual void onMouseMove(const Vector2D&);
virtual void onWindowCreatedFloating(CWindow*); virtual void onWindowCreatedFloating(CWindow*);
virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode); virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode, bool);
virtual std::any layoutMessage(SLayoutMessageHeader, std::string); virtual std::any layoutMessage(SLayoutMessageHeader, std::string);
virtual SWindowRenderLayoutHints requestRenderHints(CWindow*); virtual SWindowRenderLayoutHints requestRenderHints(CWindow*);
virtual void switchWindows(CWindow*, CWindow*); virtual void switchWindows(CWindow*, CWindow*);

View File

@@ -49,6 +49,18 @@ public:
as. as.
*/ */
virtual void onBeginDragWindow() = 0; virtual void onBeginDragWindow() = 0;
/*
Called when a user requests a resize of the current window by a vec
Vector2D holds pixel values
Optional pWindow for a specific window
*/
virtual void resizeActiveWindow(const Vector2D&, CWindow* pWindow = nullptr) = 0;
/*
Called when a user requests a move of the current window by a vec
Vector2D holds pixel values
Optional pWindow for a specific window
*/
virtual void moveActiveWindow(const Vector2D&, CWindow* pWindow = nullptr) = 0;
/* /*
Called when a window is ended being dragged Called when a window is ended being dragged
(mouse up) (mouse up)
@@ -72,7 +84,7 @@ public:
The layout sets all the fullscreen flags. The layout sets all the fullscreen flags.
It can either accept or ignore. It can either accept or ignore.
*/ */
virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode) = 0; virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode, bool) = 0;
/* /*
Called when a dispatcher requests a custom message Called when a dispatcher requests a custom message

View File

@@ -3,6 +3,7 @@
#include "Compositor.hpp" #include "Compositor.hpp"
#include "config/ConfigManager.hpp" #include "config/ConfigManager.hpp"
#include "init/initHelpers.hpp" #include "init/initHelpers.hpp"
#include <iostream>
// I am a bad bad boy and have used some global vars here, // I am a bad bad boy and have used some global vars here,
// just for this file // just for this file
@@ -19,17 +20,19 @@ int main(int argc, char** argv) {
ignoreSudo = true; ignoreSudo = true;
} }
system("mkdir -p /tmp/hypr");
if (!ignoreSudo) { if (!ignoreSudo) {
if (Init::isSudo()) { if (Init::isSudo()) {
Debug::log(CRIT, "Hyprland shall not be run as the root user. If you really want to, use the --i-am-really-stupid flag."); std::cout << "Hyprland shall not be run as the root user. If you really want to, use the --i-am-really-stupid flag.\n";
return 1; return 1;
} }
} else { } else {
Debug::log(WARN, "Running with ignored root checks, I surely hope you know what you're doing."); std::cout << "Running with ignored root checks, I surely hope you know what you're doing.\n";
sleep(1); sleep(1);
} }
Debug::log(LOG, "Welcome to Hyprland!"); std::cout << "Welcome to Hyprland!\n";
// let's init the compositor. // let's init the compositor.
// it initializes basic Wayland stuff in the constructor. // it initializes basic Wayland stuff in the constructor.

View File

@@ -23,20 +23,22 @@ void CAnimationManager::tick() {
bool animationsDisabled = false; bool animationsDisabled = false;
if (!g_pConfigManager->getInt("animations:enabled")) static auto *const PANIMENABLED = &g_pConfigManager->getConfigValuePtr("animations:enabled")->intValue;
if (!*PANIMENABLED)
animationsDisabled = true; animationsDisabled = true;
const float ANIMSPEED = g_pConfigManager->getFloat("animations:speed"); static auto *const PANIMSPEED = &g_pConfigManager->getConfigValuePtr("animations:speed")->floatValue;
const auto BORDERSIZE = g_pConfigManager->getInt("general:border_size"); static auto *const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
const auto BEZIERSTR = g_pConfigManager->getString("animations:curve"); static auto *const BEZIERSTR = &g_pConfigManager->getConfigValuePtr("animations:curve")->strValue;
auto DEFAULTBEZIER = m_mBezierCurves.find(BEZIERSTR); auto DEFAULTBEZIER = m_mBezierCurves.find(*BEZIERSTR);
if (DEFAULTBEZIER == m_mBezierCurves.end()) if (DEFAULTBEZIER == m_mBezierCurves.end())
DEFAULTBEZIER = m_mBezierCurves.find("default"); DEFAULTBEZIER = m_mBezierCurves.find("default");
for (auto& av : m_lAnimatedVariables) { for (auto& av : m_lAnimatedVariables) {
// get speed // get speed
const auto SPEED = *av->m_pSpeed == 0 ? ANIMSPEED : *av->m_pSpeed; const auto SPEED = *av->m_pSpeed == 0 ? *PANIMSPEED : *av->m_pSpeed;
// window stuff // window stuff
const auto PWINDOW = (CWindow*)av->m_pWindow; const auto PWINDOW = (CWindow*)av->m_pWindow;
@@ -45,28 +47,13 @@ void CAnimationManager::tick() {
wlr_box WLRBOXPREV = {0,0,0,0}; wlr_box WLRBOXPREV = {0,0,0,0};
if (PWINDOW) { if (PWINDOW) {
WLRBOXPREV = {(int)PWINDOW->m_vRealPosition.vec().x - BORDERSIZE - 1, (int)PWINDOW->m_vRealPosition.vec().y - BORDERSIZE - 1, (int)PWINDOW->m_vRealSize.vec().x + 2 * BORDERSIZE + 2, (int)PWINDOW->m_vRealSize.vec().y + 2 * BORDERSIZE + 2}; WLRBOXPREV = {(int)PWINDOW->m_vRealPosition.vec().x - (int)*PBORDERSIZE - 1, (int)PWINDOW->m_vRealPosition.vec().y - (int)*PBORDERSIZE - 1, (int)PWINDOW->m_vRealSize.vec().x + 2 * (int)*PBORDERSIZE + 2, (int)PWINDOW->m_vRealSize.vec().y + 2 * (int)*PBORDERSIZE + 2};
} else if (PWORKSPACE) { } else if (PWORKSPACE) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID); const auto PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
WLRBOXPREV = {(int)PMONITOR->vecPosition.x, (int)PMONITOR->vecPosition.y, (int)PMONITOR->vecSize.x, (int)PMONITOR->vecSize.y}; WLRBOXPREV = {(int)PMONITOR->vecPosition.x, (int)PMONITOR->vecPosition.y, (int)PMONITOR->vecSize.x, (int)PMONITOR->vecSize.y};
} else if (PLAYER) { } else if (PLAYER) {
WLRBOXPREV = PLAYER->geometry; WLRBOXPREV = PLAYER->geometry;
} }
// check if it's disabled, if so, warp
if (av->m_pEnabled == 0 || animationsDisabled) {
av->warp();
g_pHyprRenderer->damageBox(&WLRBOXPREV);
if (PWINDOW) {
g_pHyprRenderer->damageWindow(PWINDOW);
// set size and pos if valid
if (g_pCompositor->windowValidMapped(PWINDOW))
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
}
continue;
}
// beziers are with a switch unforto // beziers are with a switch unforto
// TODO: maybe do something cleaner // TODO: maybe do something cleaner
@@ -78,6 +65,13 @@ void CAnimationManager::tick() {
switch (av->m_eVarType) { switch (av->m_eVarType) {
case AVARTYPE_FLOAT: { case AVARTYPE_FLOAT: {
if (!deltazero(av->m_fValue, av->m_fGoal)) { if (!deltazero(av->m_fValue, av->m_fGoal)) {
// for disabled anims just warp
if (av->m_pEnabled == 0 || animationsDisabled) {
av->warp();
break;
}
const auto DELTA = av->m_fGoal - av->m_fBegun; const auto DELTA = av->m_fGoal - av->m_fBegun;
const auto BEZIER = m_mBezierCurves.find(*av->m_pBezier); const auto BEZIER = m_mBezierCurves.find(*av->m_pBezier);
@@ -96,6 +90,13 @@ void CAnimationManager::tick() {
} }
case AVARTYPE_VECTOR: { case AVARTYPE_VECTOR: {
if (!deltazero(av->m_vValue, av->m_vGoal)) { if (!deltazero(av->m_vValue, av->m_vGoal)) {
// for disabled anims just warp
if (av->m_pEnabled == 0 || animationsDisabled) {
av->warp();
break;
}
const auto DELTA = av->m_vGoal - av->m_vBegun; const auto DELTA = av->m_vGoal - av->m_vBegun;
const auto BEZIER = m_mBezierCurves.find(*av->m_pBezier); const auto BEZIER = m_mBezierCurves.find(*av->m_pBezier);
@@ -114,6 +115,13 @@ void CAnimationManager::tick() {
} }
case AVARTYPE_COLOR: { case AVARTYPE_COLOR: {
if (!deltazero(av->m_cValue, av->m_cGoal)) { if (!deltazero(av->m_cValue, av->m_cGoal)) {
// for disabled anims just warp
if (av->m_pEnabled == 0 || animationsDisabled) {
av->warp();
break;
}
const auto DELTA = av->m_cGoal - av->m_cBegun; const auto DELTA = av->m_cGoal - av->m_cBegun;
const auto BEZIER = m_mBezierCurves.find(*av->m_pBezier); const auto BEZIER = m_mBezierCurves.find(*av->m_pBezier);
@@ -152,8 +160,9 @@ void CAnimationManager::tick() {
RASSERT(PWINDOW, "Tried to AVARDAMAGE_BORDER a non-window AVAR!"); RASSERT(PWINDOW, "Tried to AVARDAMAGE_BORDER a non-window AVAR!");
// damage only the border. // damage only the border.
const auto BORDERSIZE = g_pConfigManager->getInt("general:border_size") + 1; // +1 for padding and shit static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
const auto ROUNDINGSIZE = g_pConfigManager->getInt("decoration:rounding") + 1; const auto ROUNDINGSIZE = *PROUNDING + 1;
const auto BORDERSIZE = *PBORDERSIZE;
// damage for old box // damage for old box
g_pHyprRenderer->damageBox(WLRBOXPREV.x - BORDERSIZE, WLRBOXPREV.y - BORDERSIZE, WLRBOXPREV.width + 2 * BORDERSIZE, BORDERSIZE + ROUNDINGSIZE); // top g_pHyprRenderer->damageBox(WLRBOXPREV.x - BORDERSIZE, WLRBOXPREV.y - BORDERSIZE, WLRBOXPREV.width + 2 * BORDERSIZE, BORDERSIZE + ROUNDINGSIZE); // top

View File

@@ -1,4 +1,5 @@
#include "EventManager.hpp" #include "EventManager.hpp"
#include "../Compositor.hpp"
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
@@ -26,10 +27,9 @@ void CEventManager::startThread() {
return; return;
} }
unlink("/tmp/hypr/.socket2.sock");
sockaddr_un SERVERADDRESS = {.sun_family = AF_UNIX}; sockaddr_un SERVERADDRESS = {.sun_family = AF_UNIX};
strcpy(SERVERADDRESS.sun_path, "/tmp/hypr/.socket2.sock"); std::string socketPath = "/tmp/hypr/" + g_pCompositor->m_szInstanceSignature + "/.socket2.sock";
strcpy(SERVERADDRESS.sun_path, socketPath.c_str());
bind(SOCKET, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)); bind(SOCKET, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS));
@@ -41,7 +41,7 @@ void CEventManager::startThread() {
sockaddr_in clientAddress; sockaddr_in clientAddress;
socklen_t clientSize = sizeof(clientAddress); socklen_t clientSize = sizeof(clientAddress);
Debug::log(LOG, "Hypr socket 2 started."); Debug::log(LOG, "Hypr socket 2 started at %s", socketPath.c_str());
// set the socket nonblock // set the socket nonblock
int flags = fcntl(SOCKET, F_GETFL, 0); int flags = fcntl(SOCKET, F_GETFL, 0);
@@ -105,9 +105,15 @@ void CEventManager::startThread() {
} }
void CEventManager::postEvent(const SHyprIPCEvent event) { void CEventManager::postEvent(const SHyprIPCEvent event) {
if (m_bIgnoreEvents) {
Debug::log(WARN, "Suppressed (ignoreevents true) event of type %s, content: %s",event.event.c_str(), event.data.c_str());
return;
}
std::thread([&](const SHyprIPCEvent ev) { std::thread([&](const SHyprIPCEvent ev) {
eventQueueMutex.lock(); eventQueueMutex.lock();
m_dQueuedEvents.push_back(ev); m_dQueuedEvents.push_back(ev);
eventQueueMutex.unlock(); eventQueueMutex.unlock();
}, event).detach(); }, event).detach();
} }

View File

@@ -19,6 +19,8 @@ public:
void startThread(); void startThread();
bool m_bIgnoreEvents = false;
private: private:
std::mutex eventQueueMutex; std::mutex eventQueueMutex;

View File

@@ -1,5 +1,7 @@
#include "KeybindManager.hpp" #include "KeybindManager.hpp"
#include <regex>
CKeybindManager::CKeybindManager() { CKeybindManager::CKeybindManager() {
// initialize all dispatchers // initialize all dispatchers
@@ -21,6 +23,15 @@ CKeybindManager::CKeybindManager() {
m_mDispatchers["movecursortocorner"] = moveCursorToCorner; m_mDispatchers["movecursortocorner"] = moveCursorToCorner;
m_mDispatchers["workspaceopt"] = workspaceOpt; m_mDispatchers["workspaceopt"] = workspaceOpt;
m_mDispatchers["exit"] = exitHyprland; m_mDispatchers["exit"] = exitHyprland;
m_mDispatchers["movecurrentworkspacetomonitor"] = moveCurrentWorkspaceToMonitor;
m_mDispatchers["moveworkspacetomonitor"] = moveWorkspaceToMonitor;
m_mDispatchers["togglespecialworkspace"] = toggleSpecialWorkspace;
m_mDispatchers["forcerendererreload"] = forceRendererReload;
m_mDispatchers["resizeactive"] = resizeActive;
m_mDispatchers["moveactive"] = moveActive;
m_mDispatchers["cyclenext"] = circleNext;
m_mDispatchers["focuswindowbyclass"] = focusWindowByClass;
m_mDispatchers["submap"] = setSubmap;
} }
void CKeybindManager::addKeybind(SKeybind kb) { void CKeybindManager::addKeybind(SKeybind kb) {
@@ -63,13 +74,11 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const xkb_keysym_t
if (handleInternalKeybinds(key)) if (handleInternalKeybinds(key))
return true; return true;
if (g_pCompositor->m_sSeat.exclusiveClient){ if (g_pCompositor->m_sSeat.exclusiveClient)
Debug::log(LOG, "Not handling keybinds due to there being an exclusive inhibited client."); Debug::log(LOG, "Keybind handling only locked (inhibitor)");
return false;
}
for (auto& k : m_lKeybinds) { for (auto& k : m_lKeybinds) {
if (modmask != k.modmask) if (modmask != k.modmask || (g_pCompositor->m_sSeat.exclusiveClient && !k.locked) || k.submap != m_szCurrentSelectedSubmap)
continue; continue;
// oMg such performance hit!!11! // oMg such performance hit!!11!
@@ -106,8 +115,17 @@ bool CKeybindManager::handleInternalKeybinds(xkb_keysym_t keysym) {
const auto PSESSION = wlr_backend_get_session(g_pCompositor->m_sWLRBackend); const auto PSESSION = wlr_backend_get_session(g_pCompositor->m_sWLRBackend);
if (PSESSION) { if (PSESSION) {
const auto TTY = keysym - XKB_KEY_XF86Switch_VT_1 + 1; const int TTY = keysym - XKB_KEY_XF86Switch_VT_1 + 1;
wlr_session_change_vt(PSESSION, TTY); wlr_session_change_vt(PSESSION, TTY);
for (auto& m : g_pCompositor->m_lMonitors) {
g_pHyprOpenGL->destroyMonitorResources(&m); // mark resources as unusable anymore
m.noFrameSchedule = true;
m.framesToSkip = 2;
}
Debug::log(LOG, "Switched to VT %i, destroyed all render data, frames to skip for each: 2", TTY);
return true; return true;
} }
@@ -123,11 +141,48 @@ void CKeybindManager::spawn(std::string args) {
args = "WAYLAND_DISPLAY=" + std::string(g_pCompositor->m_szWLDisplaySocket) + " " + args; args = "WAYLAND_DISPLAY=" + std::string(g_pCompositor->m_szWLDisplaySocket) + " " + args;
Debug::log(LOG, "Executing %s", args.c_str()); Debug::log(LOG, "Executing %s", args.c_str());
if (fork() == 0) {
execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr);
int socket[2];
if (pipe(socket) != 0) {
Debug::log(LOG, "Unable to create pipe for fork");
}
pid_t child, grandchild;
child = fork();
if (child < 0) {
close(socket[0]);
close(socket[1]);
Debug::log(LOG, "Fail to create the first fork");
return;
}
if (child == 0) {
// run in child
grandchild = fork();
if (grandchild == 0) {
// run in grandchild
close(socket[0]);
close(socket[1]);
execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr);
// exit grandchild
_exit(0);
}
close(socket[0]);
write(socket[1], &grandchild, sizeof(grandchild));
close(socket[1]);
// exit child
_exit(0); _exit(0);
} }
// run in parent
close(socket[1]);
read(socket[0], &grandchild, sizeof(grandchild));
close(socket[0]);
// clear child and leave child to init
waitpid(child, NULL, 0);
if (child < 0) {
Debug::log(LOG, "Fail to create the second fork");
return;
}
Debug::log(LOG, "Process Created with pid %d", grandchild);
} }
void CKeybindManager::killActive(std::string args) { void CKeybindManager::killActive(std::string args) {
@@ -151,6 +206,10 @@ void CKeybindManager::toggleActiveFloating(std::string args) {
if (g_pCompositor->windowValidMapped(ACTIVEWINDOW)) { if (g_pCompositor->windowValidMapped(ACTIVEWINDOW)) {
ACTIVEWINDOW->m_bIsFloating = !ACTIVEWINDOW->m_bIsFloating; ACTIVEWINDOW->m_bIsFloating = !ACTIVEWINDOW->m_bIsFloating;
if (ACTIVEWINDOW->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) {
moveActiveToWorkspace(std::to_string(g_pCompositor->getMonitorFromID(ACTIVEWINDOW->m_iMonitorID)->activeWorkspace));
}
ACTIVEWINDOW->m_vRealPosition.setValue(ACTIVEWINDOW->m_vRealPosition.vec() + Vector2D(5, 5)); ACTIVEWINDOW->m_vRealPosition.setValue(ACTIVEWINDOW->m_vRealPosition.vec() + Vector2D(5, 5));
ACTIVEWINDOW->m_vSize = ACTIVEWINDOW->m_vRealPosition.vec() - Vector2D(10, 10); ACTIVEWINDOW->m_vSize = ACTIVEWINDOW->m_vRealPosition.vec() - Vector2D(10, 10);
@@ -189,12 +248,20 @@ void CKeybindManager::changeworkspace(std::string args) {
const auto PWORKSPACETOCHANGETO = g_pCompositor->getWorkspaceByID(workspaceToChangeTo); const auto PWORKSPACETOCHANGETO = g_pCompositor->getWorkspaceByID(workspaceToChangeTo);
if (workspaceToChangeTo == SPECIAL_WORKSPACE_ID)
PWORKSPACETOCHANGETO->m_iMonitorID = PMONITOR->ID;
// if it's not visible, make it visible. // if it's not visible, make it visible.
if (!g_pCompositor->isWorkspaceVisible(workspaceToChangeTo)) { if (!g_pCompositor->isWorkspaceVisible(workspaceToChangeTo)) {
const auto OLDWORKSPACEID = PMONITOR->activeWorkspace; const auto OLDWORKSPACEID = PMONITOR->activeWorkspace;
// change it // change it
PMONITOR->activeWorkspace = workspaceToChangeTo; PMONITOR->specialWorkspaceOpen = false;
if (workspaceToChangeTo != SPECIAL_WORKSPACE_ID)
PMONITOR->activeWorkspace = workspaceToChangeTo;
else
PMONITOR->specialWorkspaceOpen = true;
// we need to move XWayland windows to narnia or otherwise they will still process our cursor and shit // we need to move XWayland windows to narnia or otherwise they will still process our cursor and shit
// and that'd be annoying as hell // and that'd be annoying as hell
@@ -213,11 +280,8 @@ void CKeybindManager::changeworkspace(std::string args) {
// start anim on new workspace // start anim on new workspace
PWORKSPACETOCHANGETO->startAnim(true, ANIMTOLEFT); PWORKSPACETOCHANGETO->startAnim(true, ANIMTOLEFT);
// Event ONLY if workspace is actually "changed" and we arent just focusing g_pEventManager->postEvent(SHyprIPCEvent("workspace", PWORKSPACETOCHANGETO->m_szName));
if (!m_bSuppressWorkspaceChangeEvents)
g_pEventManager->postEvent(SHyprIPCEvent("workspace", PWORKSPACETOCHANGETO->m_szName));
} }
// If the monitor is not the one our cursor's at, warp to it. // If the monitor is not the one our cursor's at, warp to it.
if (PMONITOR != g_pCompositor->getMonitorFromCursor()) { if (PMONITOR != g_pCompositor->getMonitorFromCursor()) {
@@ -225,13 +289,13 @@ void CKeybindManager::changeworkspace(std::string args) {
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, middle.x, middle.y); wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, middle.x, middle.y);
} }
// focus the first window
g_pCompositor->focusWindow(g_pCompositor->getFirstWindowOnWorkspace(workspaceToChangeTo));
// set active and deactivate all other in wlr // set active and deactivate all other in wlr
g_pCompositor->deactivateAllWLRWorkspaces(PWORKSPACETOCHANGETO->m_pWlrHandle); g_pCompositor->deactivateAllWLRWorkspaces(PWORKSPACETOCHANGETO->m_pWlrHandle);
PWORKSPACETOCHANGETO->setActive(true); PWORKSPACETOCHANGETO->setActive(true);
// recalc layout
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWORKSPACETOCHANGETO->m_iMonitorID);
Debug::log(LOG, "Changed to workspace %i", workspaceToChangeTo); Debug::log(LOG, "Changed to workspace %i", workspaceToChangeTo);
// focus // focus
@@ -252,22 +316,29 @@ void CKeybindManager::changeworkspace(std::string args) {
const auto ANIMTOLEFT = workspaceToChangeTo > OLDWORKSPACE; const auto ANIMTOLEFT = workspaceToChangeTo > OLDWORKSPACE;
// start anim on old workspace // start anim on old workspace
g_pCompositor->getWorkspaceByID(OLDWORKSPACE)->startAnim(false, ANIMTOLEFT); if (const auto POLDWORKSPACE = g_pCompositor->getWorkspaceByID(OLDWORKSPACE); POLDWORKSPACE)
POLDWORKSPACE->startAnim(false, ANIMTOLEFT);
g_pCompositor->m_lWorkspaces.emplace_back(PMONITOR->ID); g_pCompositor->m_lWorkspaces.emplace_back(PMONITOR->ID, workspaceToChangeTo == SPECIAL_WORKSPACE_ID);
const auto PWORKSPACE = &g_pCompositor->m_lWorkspaces.back(); const auto PWORKSPACE = &g_pCompositor->m_lWorkspaces.back();
// start anim on new workspace // start anim on new workspace
PWORKSPACE->startAnim(true, ANIMTOLEFT); PWORKSPACE->startAnim(true, ANIMTOLEFT);
// We are required to set the name here immediately // We are required to set the name here immediately
wlr_ext_workspace_handle_v1_set_name(PWORKSPACE->m_pWlrHandle, workspaceName.c_str()); if (workspaceToChangeTo != SPECIAL_WORKSPACE_ID)
wlr_ext_workspace_handle_v1_set_name(PWORKSPACE->m_pWlrHandle, workspaceName.c_str());
PWORKSPACE->m_iID = workspaceToChangeTo; PWORKSPACE->m_iID = workspaceToChangeTo;
PWORKSPACE->m_iMonitorID = PMONITOR->ID; PWORKSPACE->m_iMonitorID = PMONITOR->ID;
PWORKSPACE->m_szName = workspaceName; PWORKSPACE->m_szName = workspaceName;
PMONITOR->activeWorkspace = workspaceToChangeTo; PMONITOR->specialWorkspaceOpen = false;
if (workspaceToChangeTo != SPECIAL_WORKSPACE_ID)
PMONITOR->activeWorkspace = workspaceToChangeTo;
else
PMONITOR->specialWorkspaceOpen = true;
// we need to move XWayland windows to narnia or otherwise they will still process our cursor and shit // we need to move XWayland windows to narnia or otherwise they will still process our cursor and shit
// and that'd be annoying as hell // and that'd be annoying as hell
@@ -284,8 +355,7 @@ void CKeybindManager::changeworkspace(std::string args) {
g_pInputManager->refocus(); g_pInputManager->refocus();
// Event // Event
if (!m_bSuppressWorkspaceChangeEvents) g_pEventManager->postEvent(SHyprIPCEvent("workspace", PWORKSPACE->m_szName));
g_pEventManager->postEvent(SHyprIPCEvent("workspace", PWORKSPACE->m_szName));
Debug::log(LOG, "Changed to workspace %i", workspaceToChangeTo); Debug::log(LOG, "Changed to workspace %i", workspaceToChangeTo);
} }
@@ -296,15 +366,7 @@ void CKeybindManager::fullscreenActive(std::string args) {
if (!g_pCompositor->windowValidMapped(PWINDOW)) if (!g_pCompositor->windowValidMapped(PWINDOW))
return; return;
g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, args == "1" ? eFullscreenMode::FULLSCREEN_MAXIMIZED : eFullscreenMode::FULLSCREEN_FULL); g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen, args == "1" ? FULLSCREEN_MAXIMIZED : FULLSCREEN_FULL);
g_pXWaylandManager->setWindowFullscreen(PWINDOW, PWINDOW->m_bIsFullscreen && args == "0");
// make all windows on the same workspace under the fullscreen window
for (auto& w : g_pCompositor->m_lWindows) {
if (w.m_iWorkspaceID == PWINDOW->m_iWorkspaceID)
w.m_bCreatedOverFullscreen = false;
}
} }
void CKeybindManager::moveActiveToWorkspace(std::string args) { void CKeybindManager::moveActiveToWorkspace(std::string args) {
@@ -313,20 +375,33 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
if (!g_pCompositor->windowValidMapped(PWINDOW)) if (!g_pCompositor->windowValidMapped(PWINDOW))
return; return;
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW);
const auto OLDWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID); const auto OLDWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID);
// hack // hack
std::string unusedName;
const auto WORKSPACEID = getWorkspaceIDFromString(args, unusedName);
if (WORKSPACEID == PWINDOW->m_iWorkspaceID) {
Debug::log(LOG, "Not moving to workspace because it didn't change.");
return;
}
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW);
g_pKeybindManager->changeworkspace(args); g_pKeybindManager->changeworkspace(args);
const auto PWORKSPACE = g_pCompositor->getWorkspaceByString(args); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
if (PWORKSPACE == OLDWORKSPACE) { if (PWORKSPACE == OLDWORKSPACE) {
Debug::log(LOG, "Not moving to workspace because it didn't change."); Debug::log(LOG, "Not moving to workspace because it didn't change.");
return; return;
} }
if (!PWORKSPACE) {
Debug::log(ERR, "Workspace null in moveActiveToWorkspace?");
return;
}
OLDWORKSPACE->m_bHasFullscreenWindow = false; OLDWORKSPACE->m_bHasFullscreenWindow = false;
PWINDOW->m_iWorkspaceID = PWORKSPACE->m_iID; PWINDOW->m_iWorkspaceID = PWORKSPACE->m_iID;
@@ -354,6 +429,19 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) {
PWINDOW->m_vRealPosition.setValue(PWINDOW->m_vRealPosition.vec() + g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID)->vecPosition); PWINDOW->m_vRealPosition.setValue(PWINDOW->m_vRealPosition.vec() + g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID)->vecPosition);
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.vec(); PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.vec();
} }
// undo the damage if we are moving to the special workspace
if (WORKSPACEID == SPECIAL_WORKSPACE_ID) {
changeworkspace(std::to_string(OLDWORKSPACE->m_iID));
OLDWORKSPACE->startAnim(true, true, true);
toggleSpecialWorkspace("");
g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID)->startAnim(false, false, true);
for (auto& m : g_pCompositor->m_lMonitors)
m.specialWorkspaceOpen = false;
}
g_pInputManager->refocus();
} }
void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
@@ -390,7 +478,7 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
const auto POLDWORKSPACEONMON = g_pCompositor->getWorkspaceByID(OLDWORKSPACEIDONMONITOR); const auto POLDWORKSPACEONMON = g_pCompositor->getWorkspaceByID(OLDWORKSPACEIDONMONITOR);
const auto POLDWORKSPACEIDRETURN = g_pCompositor->getWorkspaceByID(OLDWORKSPACEIDRETURN); const auto POLDWORKSPACEIDRETURN = g_pCompositor->getWorkspaceByID(OLDWORKSPACEIDRETURN);
m_bSuppressWorkspaceChangeEvents = true; g_pEventManager->m_bIgnoreEvents = true;
moveActiveToWorkspace(args); moveActiveToWorkspace(args);
@@ -409,7 +497,9 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
POLDWORKSPACEONMON->m_vRenderOffset.setValueAndWarp(Vector2D(0, 0)); POLDWORKSPACEONMON->m_vRenderOffset.setValueAndWarp(Vector2D(0, 0));
POLDWORKSPACEONMON->m_fAlpha.setValueAndWarp(255.f); POLDWORKSPACEONMON->m_fAlpha.setValueAndWarp(255.f);
m_bSuppressWorkspaceChangeEvents = false; g_pEventManager->m_bIgnoreEvents = false;
g_pInputManager->refocus();
} }
void CKeybindManager::moveFocusTo(std::string args) { void CKeybindManager::moveFocusTo(std::string args) {
@@ -681,4 +771,263 @@ void CKeybindManager::workspaceOpt(std::string args) {
void CKeybindManager::exitHyprland(std::string argz) { void CKeybindManager::exitHyprland(std::string argz) {
g_pCompositor->cleanupExit(); g_pCompositor->cleanupExit();
exit(0); exit(0);
} }
void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) {
if (!isNumber(args) && !isDirection(args)) {
Debug::log(ERR, "moveCurrentWorkspaceToMonitor arg not a number or direction!");
return;
}
const auto PMONITOR = isDirection(args) ? g_pCompositor->getMonitorInDirection(args[0]) : g_pCompositor->getMonitorFromID(std::stoi(args));
if (!PMONITOR) {
Debug::log(ERR, "Ignoring moveCurrentWorkspaceToMonitor: monitor doesnt exist");
return;
}
// get the current workspace
const auto PCURRENTWORKSPACE = g_pCompositor->getWorkspaceByID(g_pCompositor->m_pLastMonitor->activeWorkspace);
if (!PCURRENTWORKSPACE)
return;
g_pCompositor->moveWorkspaceToMonitor(PCURRENTWORKSPACE, PMONITOR);
}
void CKeybindManager::moveWorkspaceToMonitor(std::string args) {
if (args.find_first_of(' ') == std::string::npos)
return;
std::string workspace = args.substr(0, args.find_first_of(' '));
std::string monitor = args.substr(args.find_first_of(' ') + 1);
if (!isNumber(monitor) && !isDirection(monitor)) {
Debug::log(ERR, "moveWorkspaceToMonitor monitor arg not a number or direction!");
return;
}
const auto PMONITOR = isDirection(monitor) ? g_pCompositor->getMonitorInDirection(monitor[0]) : g_pCompositor->getMonitorFromID(std::stoi(monitor));
if (!PMONITOR){
Debug::log(ERR, "Ignoring moveWorkspaceToMonitor: monitor doesnt exist");
return;
}
std::string workspaceName;
const int WORKSPACEID = getWorkspaceIDFromString(workspace, workspaceName);
if (WORKSPACEID == INT_MAX) {
Debug::log(ERR, "moveWorkspaceToMonitor invalid workspace!");
return;
}
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
if (!PWORKSPACE) {
Debug::log(ERR, "moveWorkspaceToMonitor workspace doesn't exist!");
return;
}
g_pCompositor->moveWorkspaceToMonitor(PWORKSPACE, PMONITOR);
}
void CKeybindManager::toggleSpecialWorkspace(std::string args) {
if (g_pCompositor->getWindowsOnWorkspace(SPECIAL_WORKSPACE_ID) == 0) {
Debug::log(LOG, "Can't open empty special workspace!");
return;
}
bool open = false;
for (auto& m : g_pCompositor->m_lMonitors) {
if (m.specialWorkspaceOpen) {
open = true;
break;
}
}
if (open)
Debug::log(LOG, "Toggling special workspace to closed");
else
Debug::log(LOG, "Toggling special workspace to open");
if (open) {
for (auto& m : g_pCompositor->m_lMonitors) {
if (m.specialWorkspaceOpen != !open) {
m.specialWorkspaceOpen = !open;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m.ID);
g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID)->startAnim(false, false);
}
}
} else {
g_pCompositor->m_pLastMonitor->specialWorkspaceOpen = true;
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(g_pCompositor->m_pLastMonitor->ID);
g_pCompositor->getWorkspaceByID(SPECIAL_WORKSPACE_ID)->startAnim(true, true);
}
g_pInputManager->refocus();
}
void CKeybindManager::forceRendererReload(std::string args) {
for (auto& m : g_pCompositor->m_lMonitors) {
auto rule = g_pConfigManager->getMonitorRuleFor(m.szName);
g_pHyprRenderer->applyMonitorRule(&m, &rule, true);
}
}
void CKeybindManager::resizeActive(std::string args) {
if (args.find_first_of(' ') == std::string::npos)
return;
std::string x = args.substr(0, args.find_first_of(' '));
std::string y = args.substr(args.find_first_of(' ') + 1);
if (x == "exact") {
std::string newX = y.substr(0, y.find_first_of(' '));
std::string newY = y.substr(y.find_first_of(' ') + 1);
if (!isNumber(newX) || !isNumber(newY)) {
Debug::log(ERR, "resizeTiledWindow: exact args not numbers");
return;
}
const int X = std::stoi(newX);
const int Y = std::stoi(newY);
if (X < 10 || Y < 10) {
Debug::log(ERR, "resizeTiledWindow: exact args cannot be < 10");
return;
}
// calc the delta
if (!g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow))
return; // ignore
const auto PWINDOW = g_pCompositor->m_pLastWindow;
const int DX = X - PWINDOW->m_vRealSize.goalv().x;
const int DY = Y - PWINDOW->m_vRealSize.goalv().y;
g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(Vector2D(DX, DY));
return;
}
if (!isNumber(x) || !isNumber(y)) {
Debug::log(ERR, "resizeTiledWindow: args not numbers");
return;
}
const int X = std::stoi(x);
const int Y = std::stoi(y);
g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(Vector2D(X, Y));
}
void CKeybindManager::moveActive(std::string args) {
if (args.find_first_of(' ') == std::string::npos)
return;
std::string x = args.substr(0, args.find_first_of(' '));
std::string y = args.substr(args.find_first_of(' ') + 1);
if (x == "exact") {
std::string newX = y.substr(0, y.find_first_of(' '));
std::string newY = y.substr(y.find_first_of(' ') + 1);
if (!isNumber(newX) || !isNumber(newY)) {
Debug::log(ERR, "moveActive: exact args not numbers");
return;
}
const int X = std::stoi(newX);
const int Y = std::stoi(newY);
if (X < 0 || Y < 0) {
Debug::log(ERR, "moveActive: exact args cannot be < 0");
return;
}
// calc the delta
if (!g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow))
return; // ignore
const auto PWINDOW = g_pCompositor->m_pLastWindow;
const int DX = X - PWINDOW->m_vRealPosition.goalv().x;
const int DY = Y - PWINDOW->m_vRealPosition.goalv().y;
g_pLayoutManager->getCurrentLayout()->moveActiveWindow(Vector2D(DX, DY));
return;
}
if (!isNumber(x) || !isNumber(y)) {
Debug::log(ERR, "moveActive: args not numbers");
return;
}
const int X = std::stoi(x);
const int Y = std::stoi(y);
g_pLayoutManager->getCurrentLayout()->moveActiveWindow(Vector2D(X, Y));
}
void CKeybindManager::circleNext(std::string) {
if (!g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow))
return;
g_pCompositor->focusWindow(g_pCompositor->getNextWindowOnWorkspace(g_pCompositor->m_pLastWindow));
const auto MIDPOINT = g_pCompositor->m_pLastWindow->m_vRealPosition.goalv() + g_pCompositor->m_pLastWindow->m_vRealSize.goalv() / 2.f;
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, MIDPOINT.x, MIDPOINT.y);
}
void CKeybindManager::focusWindowByClass(std::string clazz) {
std::regex classCheck(clazz);
for (auto& w : g_pCompositor->m_lWindows) {
if (!w.m_bIsMapped || w.m_bHidden)
continue;
const auto windowClass = g_pXWaylandManager->getAppIDClass(&w);
if (!std::regex_search(windowClass, classCheck))
continue;
Debug::log(LOG, "Focusing to window name: %s", w.m_szTitle.c_str());
changeworkspace(std::to_string(w.m_iWorkspaceID));
g_pCompositor->focusWindow(&w);
const auto MIDPOINT = w.m_vRealPosition.goalv() + w.m_vRealSize.goalv() / 2.f;
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, MIDPOINT.x, MIDPOINT.y);
break;
}
}
void CKeybindManager::setSubmap(std::string submap) {
if (submap == "reset" || submap == "") {
m_szCurrentSelectedSubmap = "";
Debug::log(LOG, "Reset active submap to the default one.");
return;
}
for (auto& k : g_pKeybindManager->m_lKeybinds) {
if (k.submap == submap) {
m_szCurrentSelectedSubmap = submap;
Debug::log(LOG, "Changed keybind submap to %s", submap.c_str());
return;
}
}
Debug::log(ERR, "Cannot set submap %s, submap doesn't exist (wasn't registered!)", submap.c_str());
}

View File

@@ -11,6 +11,8 @@ struct SKeybind {
uint32_t modmask = 0; uint32_t modmask = 0;
std::string handler = ""; std::string handler = "";
std::string arg = ""; std::string arg = "";
bool locked = false;
std::string submap = "";
}; };
class CKeybindManager { class CKeybindManager {
@@ -28,9 +30,9 @@ public:
private: private:
std::list<SKeybind> m_lKeybinds; std::list<SKeybind> m_lKeybinds;
bool handleInternalKeybinds(xkb_keysym_t); inline static std::string m_szCurrentSelectedSubmap = "";
inline static bool m_bSuppressWorkspaceChangeEvents = false; bool handleInternalKeybinds(xkb_keysym_t);
// -------------- Dispatchers -------------- // // -------------- Dispatchers -------------- //
static void killActive(std::string); static void killActive(std::string);
@@ -51,6 +53,17 @@ private:
static void moveCursorToCorner(std::string); static void moveCursorToCorner(std::string);
static void workspaceOpt(std::string); static void workspaceOpt(std::string);
static void exitHyprland(std::string); static void exitHyprland(std::string);
static void moveCurrentWorkspaceToMonitor(std::string);
static void moveWorkspaceToMonitor(std::string);
static void toggleSpecialWorkspace(std::string);
static void forceRendererReload(std::string);
static void resizeActive(std::string);
static void moveActive(std::string);
static void circleNext(std::string);
static void focusWindowByClass(std::string);
static void setSubmap(std::string);
friend class CCompositor;
}; };
inline std::unique_ptr<CKeybindManager> g_pKeybindManager; inline std::unique_ptr<CKeybindManager> g_pKeybindManager;

View File

@@ -94,6 +94,9 @@ std::string CHyprXWaylandManager::getAppIDClass(CWindow* pWindow) {
try { try {
if (pWindow->m_bIsX11) { if (pWindow->m_bIsX11) {
if (pWindow->m_uSurface.xwayland) { if (pWindow->m_uSurface.xwayland) {
if (!pWindow->m_bMappedX11 || !pWindow->m_bIsMapped)
return "unmanaged X11";
return std::string(pWindow->m_uSurface.xwayland->_class); return std::string(pWindow->m_uSurface.xwayland->_class);
} }
} else if (pWindow->m_uSurface.xdg) { } else if (pWindow->m_uSurface.xdg) {
@@ -121,13 +124,8 @@ void CHyprXWaylandManager::sendCloseWindow(CWindow* pWindow) {
void CHyprXWaylandManager::setWindowSize(CWindow* pWindow, const Vector2D& size) { void CHyprXWaylandManager::setWindowSize(CWindow* pWindow, const Vector2D& size) {
if (pWindow->m_bIsX11) if (pWindow->m_bIsX11)
wlr_xwayland_surface_configure(pWindow->m_uSurface.xwayland, pWindow->m_vRealPosition.vec().x, pWindow->m_vRealPosition.vec().y, size.x, size.y); wlr_xwayland_surface_configure(pWindow->m_uSurface.xwayland, pWindow->m_vRealPosition.vec().x, pWindow->m_vRealPosition.vec().y, size.x, size.y);
else { else
// I don't know if this is fucking correct, but the fucking idea of putting shadows into a window's surface is borderline criminal. wlr_xdg_toplevel_set_size(pWindow->m_uSurface.xdg->toplevel, size.x, size.y);
const auto XDELTA = pWindow->m_uSurface.xdg->surface->current.width - pWindow->m_uSurface.xdg->current.geometry.width;
const auto YDELTA = pWindow->m_uSurface.xdg->surface->current.height - pWindow->m_uSurface.xdg->current.geometry.height;
wlr_xdg_toplevel_set_size(pWindow->m_uSurface.xdg->toplevel, size.x - XDELTA, size.y - YDELTA);
}
} }
void CHyprXWaylandManager::setWindowStyleTiled(CWindow* pWindow, uint32_t edgez) { void CHyprXWaylandManager::setWindowStyleTiled(CWindow* pWindow, uint32_t edgez) {
@@ -148,8 +146,10 @@ bool CHyprXWaylandManager::shouldBeFloated(CWindow* pWindow) {
if (pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DIALOG"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"] || if (pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DIALOG"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLBAR"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_UTILITY"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLBAR"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_UTILITY"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_POPUP_MENU"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_POPUP_MENU"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DOCK"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"]) pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DOCK"] || pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] ||
pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"])
{ {
pWindow->m_bNoInitialFocus = true;
return true; return true;
} }

View File

@@ -1,24 +1,29 @@
#include "InputManager.hpp" #include "InputManager.hpp"
#include "../Compositor.hpp" #include "../../Compositor.hpp"
void CInputManager::onMouseMoved(wlr_pointer_motion_event* e) { void CInputManager::onMouseMoved(wlr_pointer_motion_event* e) {
float sensitivity = g_pConfigManager->getFloat("general:sensitivity"); float sensitivity = g_pConfigManager->getFloat("general:sensitivity");
if (g_pConfigManager->getInt("general:apply_sens_to_raw") == 1) const auto DELTA = g_pConfigManager->getInt("input:force_no_accel") == 1 ? Vector2D(e->unaccel_dx, e->unaccel_dy) : Vector2D(e->delta_x, e->delta_y);
wlr_relative_pointer_manager_v1_send_relative_motion(g_pCompositor->m_sWLRRelPointerMgr, g_pCompositor->m_sSeat.seat, (uint64_t)e->time_msec * 1000, e->delta_x * sensitivity, e->delta_y * sensitivity, e->unaccel_dx * sensitivity, e->unaccel_dy * sensitivity);
else
wlr_relative_pointer_manager_v1_send_relative_motion(g_pCompositor->m_sWLRRelPointerMgr, g_pCompositor->m_sSeat.seat, (uint64_t)e->time_msec * 1000, e->delta_x, e->delta_y, e->unaccel_dx, e->unaccel_dy);
wlr_cursor_move(g_pCompositor->m_sWLRCursor, &e->pointer->base, e->delta_x * sensitivity, e->delta_y * sensitivity); if (g_pConfigManager->getInt("general:apply_sens_to_raw") == 1)
wlr_relative_pointer_manager_v1_send_relative_motion(g_pCompositor->m_sWLRRelPointerMgr, g_pCompositor->m_sSeat.seat, (uint64_t)e->time_msec * 1000, DELTA.x * sensitivity, DELTA.y * sensitivity, e->unaccel_dx * sensitivity, e->unaccel_dy * sensitivity);
else
wlr_relative_pointer_manager_v1_send_relative_motion(g_pCompositor->m_sWLRRelPointerMgr, g_pCompositor->m_sSeat.seat, (uint64_t)e->time_msec * 1000, DELTA.x, DELTA.y, e->unaccel_dx, e->unaccel_dy);
wlr_cursor_move(g_pCompositor->m_sWLRCursor, &e->pointer->base, DELTA.x * sensitivity, DELTA.y * sensitivity);
mouseMoveUnified(e->time_msec); mouseMoveUnified(e->time_msec);
m_tmrLastCursorMovement.reset();
} }
void CInputManager::onMouseWarp(wlr_pointer_motion_absolute_event* e) { void CInputManager::onMouseWarp(wlr_pointer_motion_absolute_event* e) {
wlr_cursor_warp_absolute(g_pCompositor->m_sWLRCursor, &e->pointer->base, e->x, e->y); wlr_cursor_warp_absolute(g_pCompositor->m_sWLRCursor, &e->pointer->base, e->x, e->y);
mouseMoveUnified(e->time_msec); mouseMoveUnified(e->time_msec);
m_tmrLastCursorMovement.reset();
} }
void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
@@ -34,6 +39,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
Vector2D mouseCoords = getMouseCoordsInternal(); Vector2D mouseCoords = getMouseCoordsInternal();
const auto PMONITOR = g_pCompositor->getMonitorFromCursor(); const auto PMONITOR = g_pCompositor->getMonitorFromCursor();
bool didConstraintOnCursor = false;
// constraints // constraints
// All constraints TODO: multiple mice? // All constraints TODO: multiple mice?
if (g_pCompositor->m_sSeat.mouse->currentConstraint) { if (g_pCompositor->m_sSeat.mouse->currentConstraint) {
@@ -49,23 +56,25 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
const auto CONSTRAINTPOS = CONSTRAINTWINDOW->m_bIsX11 ? Vector2D(CONSTRAINTWINDOW->m_uSurface.xwayland->x, CONSTRAINTWINDOW->m_uSurface.xwayland->y) : CONSTRAINTWINDOW->m_vRealPosition.vec(); const auto CONSTRAINTPOS = CONSTRAINTWINDOW->m_bIsX11 ? Vector2D(CONSTRAINTWINDOW->m_uSurface.xwayland->x, CONSTRAINTWINDOW->m_uSurface.xwayland->y) : CONSTRAINTWINDOW->m_vRealPosition.vec();
const auto CONSTRAINTSIZE = CONSTRAINTWINDOW->m_bIsX11 ? Vector2D(CONSTRAINTWINDOW->m_uSurface.xwayland->width, CONSTRAINTWINDOW->m_uSurface.xwayland->height) : CONSTRAINTWINDOW->m_vRealSize.vec(); const auto CONSTRAINTSIZE = CONSTRAINTWINDOW->m_bIsX11 ? Vector2D(CONSTRAINTWINDOW->m_uSurface.xwayland->width, CONSTRAINTWINDOW->m_uSurface.xwayland->height) : CONSTRAINTWINDOW->m_vRealSize.vec();
if (!VECINRECT(mouseCoords, CONSTRAINTPOS.x, CONSTRAINTPOS.y, CONSTRAINTPOS.x + CONSTRAINTSIZE.x, CONSTRAINTPOS.y + CONSTRAINTSIZE.y)) { if (!VECINRECT(mouseCoords, CONSTRAINTPOS.x, CONSTRAINTPOS.y, CONSTRAINTPOS.x + CONSTRAINTSIZE.x - 1.0, CONSTRAINTPOS.y + CONSTRAINTSIZE.y - 1.0)) {
if (g_pCompositor->m_sSeat.mouse->constraintActive) { if (g_pCompositor->m_sSeat.mouse->constraintActive) {
Vector2D deltaToFit; Vector2D newConstrainedCoords = mouseCoords;
if (mouseCoords.x < CONSTRAINTPOS.x) if (mouseCoords.x < CONSTRAINTPOS.x)
deltaToFit.x = CONSTRAINTPOS.x - mouseCoords.x; newConstrainedCoords.x = CONSTRAINTPOS.x;
else if (mouseCoords.x > CONSTRAINTPOS.x + CONSTRAINTSIZE.x) else if (mouseCoords.x >= CONSTRAINTPOS.x + CONSTRAINTSIZE.x)
deltaToFit.x = CONSTRAINTPOS.x + CONSTRAINTSIZE.x - mouseCoords.x; newConstrainedCoords.x = CONSTRAINTPOS.x + CONSTRAINTSIZE.x - 1.0;
if (mouseCoords.y < CONSTRAINTPOS.y) if (mouseCoords.y < CONSTRAINTPOS.y)
deltaToFit.y = CONSTRAINTPOS.y - mouseCoords.y; newConstrainedCoords.y = CONSTRAINTPOS.y;
else if (mouseCoords.y > CONSTRAINTPOS.y + CONSTRAINTSIZE.y) else if (mouseCoords.y >= CONSTRAINTPOS.y + CONSTRAINTSIZE.y)
deltaToFit.y = CONSTRAINTPOS.y + CONSTRAINTSIZE.y - mouseCoords.y; newConstrainedCoords.y = CONSTRAINTPOS.y + CONSTRAINTSIZE.y - 1.0;
wlr_cursor_move(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, deltaToFit.x, deltaToFit.y); wlr_cursor_warp_closest(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, newConstrainedCoords.x, newConstrainedCoords.y);
mouseCoords = mouseCoords + deltaToFit; mouseCoords = newConstrainedCoords;
didConstraintOnCursor = true;
} }
} else { } else {
if ((!CONSTRAINTWINDOW->m_bIsX11 && PMONITOR && CONSTRAINTWINDOW->m_iWorkspaceID == PMONITOR->activeWorkspace) || (CONSTRAINTWINDOW->m_bIsX11)) { if ((!CONSTRAINTWINDOW->m_bIsX11 && PMONITOR && CONSTRAINTWINDOW->m_iWorkspaceID == PMONITOR->activeWorkspace) || (CONSTRAINTWINDOW->m_bIsX11)) {
@@ -83,6 +92,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
// focus // focus
wlr_surface* foundSurface = nullptr; wlr_surface* foundSurface = nullptr;
if (didConstraintOnCursor)
return; // don't process when cursor constrained
if (PMONITOR && PMONITOR != g_pCompositor->m_pLastMonitor) { if (PMONITOR && PMONITOR != g_pCompositor->m_pLastMonitor) {
g_pCompositor->m_pLastMonitor = PMONITOR; g_pCompositor->m_pLastMonitor = PMONITOR;
@@ -105,7 +117,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
// then, we check if the workspace doesnt have a fullscreen window // then, we check if the workspace doesnt have a fullscreen window
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace);
if (PWORKSPACE->m_bHasFullscreenWindow && !foundSurface) { if (PWORKSPACE->m_bHasFullscreenWindow && !foundSurface && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) {
pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
foundSurface = g_pXWaylandManager->getWindowSurface(pFoundWindow); foundSurface = g_pXWaylandManager->getWindowSurface(pFoundWindow);
surfacePos = pFoundWindow->m_vRealPosition.vec(); surfacePos = pFoundWindow->m_vRealPosition.vec();
@@ -113,9 +125,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
// only check floating because tiled cant be over fullscreen // only check floating because tiled cant be over fullscreen
for (auto w = g_pCompositor->m_lWindows.rbegin(); w != g_pCompositor->m_lWindows.rend(); w++) { for (auto w = g_pCompositor->m_lWindows.rbegin(); w != g_pCompositor->m_lWindows.rend(); w++) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y}; wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
if (w->m_bIsFloating && w->m_bIsMapped && w->m_bCreatedOverFullscreen && wlr_box_contains_point(&box, mouseCoords.x, mouseCoords.y) && g_pCompositor->isWorkspaceVisible(w->m_iWorkspaceID) && !w->m_bHidden) { if (((w->m_bIsFloating && w->m_bIsMapped && w->m_bCreatedOverFullscreen) || (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && PMONITOR->specialWorkspaceOpen)) && wlr_box_contains_point(&box, mouseCoords.x, mouseCoords.y) && g_pCompositor->isWorkspaceVisible(w->m_iWorkspaceID) && !w->m_bHidden) {
pFoundWindow = &(*w); pFoundWindow = &(*w);
if (!pFoundWindow->m_bIsX11) { if (!pFoundWindow->m_bIsX11) {
foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords); foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords);
} else { } else {
@@ -151,7 +163,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (!foundSurface) if (!foundSurface)
foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &surfaceCoords); foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &surfaceCoords);
if (!foundSurface) { if (!foundSurface) {
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", g_pCompositor->m_sWLRCursor); wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", g_pCompositor->m_sWLRCursor);
@@ -165,20 +176,30 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
Vector2D surfaceLocal = surfacePos == Vector2D(-1337, -1337) ? surfaceCoords : mouseCoords - surfacePos; Vector2D surfaceLocal = surfacePos == Vector2D(-1337, -1337) ? surfaceCoords : mouseCoords - surfacePos;
if (pFoundWindow && !pFoundWindow->m_bIsX11 && surfacePos != Vector2D(-1337, -1337)) {
// calc for oversized windows... fucking bullshit.
wlr_box geom;
wlr_xdg_surface_get_geometry(pFoundWindow->m_uSurface.xdg, &geom);
surfaceLocal = mouseCoords - surfacePos + Vector2D(geom.x, geom.y);
}
if (pFoundWindow) { if (pFoundWindow) {
if (g_pConfigManager->getInt("input:follow_mouse") == 0 && !refocus) { static auto *const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
if (*PFOLLOWMOUSE != 1 && !refocus) {
if (pFoundWindow != g_pCompositor->m_pLastWindow && g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow) && (g_pCompositor->m_pLastWindow->m_bIsFloating != pFoundWindow->m_bIsFloating)) { if (pFoundWindow != g_pCompositor->m_pLastWindow && g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow) && (g_pCompositor->m_pLastWindow->m_bIsFloating != pFoundWindow->m_bIsFloating)) {
// enter if change floating style // enter if change floating style
g_pCompositor->focusWindow(pFoundWindow, foundSurface); g_pCompositor->focusWindow(pFoundWindow, foundSurface);
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y); wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
} else if (*PFOLLOWMOUSE == 2) {
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
} }
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y); wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y);
return; // don't enter any new surfaces return; // don't enter any new surfaces
} else { } else {
g_pCompositor->focusWindow(pFoundWindow, foundSurface); g_pCompositor->focusWindow(pFoundWindow, foundSurface);
} }
} } else
else
g_pCompositor->focusSurface(foundSurface); g_pCompositor->focusSurface(foundSurface);
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y); wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
@@ -188,8 +209,15 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
void CInputManager::onMouseButton(wlr_pointer_button_event* e) { void CInputManager::onMouseButton(wlr_pointer_button_event* e) {
wlr_idle_notify_activity(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat); wlr_idle_notify_activity(g_pCompositor->m_sWLRIdle, g_pCompositor->m_sSeat.seat);
m_tmrLastCursorMovement.reset();
const auto PKEYBOARD = wlr_seat_get_keyboard(g_pCompositor->m_sSeat.seat); const auto PKEYBOARD = wlr_seat_get_keyboard(g_pCompositor->m_sSeat.seat);
if (!PKEYBOARD) { // ???
Debug::log(ERR, "No active keyboard in onMouseButton??");
return;
}
switch (e->state) { switch (e->state) {
case WLR_BUTTON_PRESSED: case WLR_BUTTON_PRESSED:
if (!g_pCompositor->m_sSeat.mouse->currentConstraint) if (!g_pCompositor->m_sSeat.mouse->currentConstraint)
@@ -236,64 +264,96 @@ void CInputManager::newKeyboard(wlr_input_device* keyboard) {
PNEWKEYBOARD->keyboard = keyboard; PNEWKEYBOARD->keyboard = keyboard;
xkb_rule_names rules;
const auto CONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
const auto KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
const auto REPEATRATE = g_pConfigManager->getInt("input:repeat_rate"); const auto REPEATRATE = g_pConfigManager->getInt("input:repeat_rate");
const auto REPEATDELAY = g_pConfigManager->getInt("input:repeat_delay"); const auto REPEATDELAY = g_pConfigManager->getInt("input:repeat_delay");
wlr_keyboard_set_keymap(keyboard->keyboard, KEYMAP);
xkb_keymap_unref(KEYMAP);
xkb_context_unref(CONTEXT);
wlr_keyboard_set_repeat_info(keyboard->keyboard, std::max(0, REPEATRATE), std::max(0, REPEATDELAY)); wlr_keyboard_set_repeat_info(keyboard->keyboard, std::max(0, REPEATRATE), std::max(0, REPEATDELAY));
PNEWKEYBOARD->hyprListener_keyboardMod.initCallback(&keyboard->keyboard->events.modifiers, &Events::listener_keyboardMod, PNEWKEYBOARD, "Keyboard"); PNEWKEYBOARD->hyprListener_keyboardMod.initCallback(&keyboard->keyboard->events.modifiers, &Events::listener_keyboardMod, PNEWKEYBOARD, "Keyboard");
PNEWKEYBOARD->hyprListener_keyboardKey.initCallback(&keyboard->keyboard->events.key, &Events::listener_keyboardKey, PNEWKEYBOARD, "Keyboard"); PNEWKEYBOARD->hyprListener_keyboardKey.initCallback(&keyboard->keyboard->events.key, &Events::listener_keyboardKey, PNEWKEYBOARD, "Keyboard");
PNEWKEYBOARD->hyprListener_keyboardDestroy.initCallback(&keyboard->events.destroy, &Events::listener_keyboardDestroy, PNEWKEYBOARD, "Keyboard"); PNEWKEYBOARD->hyprListener_keyboardDestroy.initCallback(&keyboard->events.destroy, &Events::listener_keyboardDestroy, PNEWKEYBOARD, "Keyboard");
if (m_pActiveKeyboard)
m_pActiveKeyboard->active = false;
m_pActiveKeyboard = PNEWKEYBOARD;
applyConfigToKeyboard(PNEWKEYBOARD);
wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, keyboard->keyboard); wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, keyboard->keyboard);
Debug::log(LOG, "New keyboard created, pointers Hypr: %x and WLR: %x", PNEWKEYBOARD, keyboard); Debug::log(LOG, "New keyboard created, pointers Hypr: %x and WLR: %x", PNEWKEYBOARD, keyboard);
setKeyboardLayout();
} }
void CInputManager::setKeyboardLayout() { void CInputManager::setKeyboardLayout() {
for (auto& k : m_lKeyboards)
applyConfigToKeyboard(&k);
}
const auto RULES = g_pConfigManager->getString("input:kb_rules"); void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
const auto MODEL = g_pConfigManager->getString("input:kb_model");
const auto LAYOUT = g_pConfigManager->getString("input:kb_layout"); ASSERT(pKeyboard);
const auto VARIANT = g_pConfigManager->getString("input:kb_variant");
const auto OPTIONS = g_pConfigManager->getString("input:kb_options"); const auto RULES = g_pConfigManager->getString("input:kb_rules");
const auto MODEL = g_pConfigManager->getString("input:kb_model");
const auto LAYOUT = g_pConfigManager->getString("input:kb_layout");
const auto VARIANT = g_pConfigManager->getString("input:kb_variant");
const auto OPTIONS = g_pConfigManager->getString("input:kb_options");
if (RULES != "" && RULES == pKeyboard->currentRules.rules && MODEL == pKeyboard->currentRules.model && LAYOUT == pKeyboard->currentRules.layout && VARIANT == pKeyboard->currentRules.variant && OPTIONS == pKeyboard->currentRules.options) {
Debug::log(LOG, "Not applying config to keyboard, it did not change.");
return;
}
xkb_rule_names rules = { xkb_rule_names rules = {
.rules = RULES.c_str(), .rules = RULES.c_str(),
.model = MODEL.c_str(), .model = MODEL.c_str(),
.layout = LAYOUT.c_str(), .layout = LAYOUT.c_str(),
.variant = VARIANT.c_str(), .variant = VARIANT.c_str(),
.options = OPTIONS.c_str() .options = OPTIONS.c_str()};
};
pKeyboard->currentRules = rules;
const auto CONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS); const auto CONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
const auto KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!KEYMAP) { if (!CONTEXT) {
Debug::log(ERR, "Keyboard layout %s with variant %s (rules: %s, model: %s, options: %s) couldn't have been loaded.", rules.layout, rules.variant, rules.rules, rules.model, rules.options); Debug::log(ERR, "applyConfigToKeyboard: CONTEXT null??");
xkb_context_unref(CONTEXT);
return; return;
} }
// TODO: configure devices one by one Debug::log(LOG, "Attempting to create a keymap for layout %s with variant %s (rules: %s, model: %s, options: %s)", rules.layout, rules.variant, rules.rules, rules.model, rules.options);
for (auto& k : m_lKeyboards)
wlr_keyboard_set_keymap(k.keyboard->keyboard, KEYMAP); auto KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!KEYMAP) {
Debug::log(ERR, "Keyboard layout %s with variant %s (rules: %s, model: %s, options: %s) couldn't have been loaded.", rules.layout, rules.variant, rules.rules, rules.model, rules.options);
memset(&rules, 0, sizeof(rules));
pKeyboard->currentRules = rules;
KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
}
wlr_keyboard_set_keymap(pKeyboard->keyboard->keyboard, KEYMAP);
wlr_keyboard_modifiers wlrMods = {0};
if (g_pConfigManager->getInt("input:numlock_by_default") == 1) {
// lock numlock
const auto IDX = xkb_map_mod_get_index(KEYMAP, XKB_MOD_NAME_NUM);
if (IDX != XKB_MOD_INVALID)
wlrMods.locked |= (uint32_t)1 << IDX;
}
if (wlrMods.locked != 0) {
wlr_keyboard_notify_modifiers(pKeyboard->keyboard->keyboard, 0, 0, wlrMods.locked, 0);
}
xkb_keymap_unref(KEYMAP); xkb_keymap_unref(KEYMAP);
xkb_context_unref(CONTEXT); xkb_context_unref(CONTEXT);
Debug::log(LOG, "Set the keyboard layout to %s and variant to %s", rules.layout, rules.variant); Debug::log(LOG, "Set the keyboard layout to %s and variant to %s for keyboard \"%s\"", rules.layout, rules.variant, pKeyboard->keyboard->name);
} }
void CInputManager::newMouse(wlr_input_device* mouse) { void CInputManager::newMouse(wlr_input_device* mouse) {
m_lMice.emplace_back(); m_lMice.emplace_back();
@@ -304,11 +364,30 @@ void CInputManager::newMouse(wlr_input_device* mouse) {
if (wlr_input_device_is_libinput(mouse)) { if (wlr_input_device_is_libinput(mouse)) {
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(mouse); const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(mouse);
if (libinput_device_config_tap_get_finger_count(LIBINPUTDEV)) // this is for tapping (like on a laptop) if (g_pConfigManager->getInt("input:touchpad:clickfinger_behavior") == 0) // toggle software buttons or clickfinger
libinput_device_config_tap_set_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_TAP_ENABLED); libinput_device_config_click_set_method(LIBINPUTDEV, LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
else
libinput_device_config_click_set_method(LIBINPUTDEV, LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
if (libinput_device_config_middle_emulation_is_available(LIBINPUTDEV)) { // middleclick on r+l mouse button pressed
if (g_pConfigManager->getInt("input:touchpad:middle_button_emulation") == 1)
libinput_device_config_middle_emulation_set_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED);
else
libinput_device_config_middle_emulation_set_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED);
}
if (libinput_device_config_scroll_has_natural_scroll(LIBINPUTDEV)) if (libinput_device_config_tap_get_finger_count(LIBINPUTDEV)) // this is for tapping (like on a laptop)
libinput_device_config_scroll_set_natural_scroll_enabled(LIBINPUTDEV, g_pConfigManager->getInt("input:natural_scroll")); if (g_pConfigManager->getInt("input:touchpad:tap-to-click") == 1)
libinput_device_config_tap_set_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_TAP_ENABLED);
if (libinput_device_config_scroll_has_natural_scroll(LIBINPUTDEV)) {
double w = 0, h = 0;
if (libinput_device_has_capability(LIBINPUTDEV, LIBINPUT_DEVICE_CAP_POINTER) && libinput_device_get_size(LIBINPUTDEV, &w, &h) == 0) // pointer with size is a touchpad
libinput_device_config_scroll_set_natural_scroll_enabled(LIBINPUTDEV, g_pConfigManager->getInt("input:touchpad:natural_scroll"));
else
libinput_device_config_scroll_set_natural_scroll_enabled(LIBINPUTDEV, g_pConfigManager->getInt("input:natural_scroll"));
}
if (libinput_device_config_dwt_is_available(LIBINPUTDEV)) { if (libinput_device_config_dwt_is_available(LIBINPUTDEV)) {
const auto DWT = static_cast<enum libinput_config_dwt_state>(g_pConfigManager->getInt("input:touchpad:disable_while_typing") != 0); const auto DWT = static_cast<enum libinput_config_dwt_state>(g_pConfigManager->getInt("input:touchpad:disable_while_typing") != 0);
@@ -322,6 +401,8 @@ void CInputManager::newMouse(wlr_input_device* mouse) {
g_pCompositor->m_sSeat.mouse = PMOUSE; g_pCompositor->m_sSeat.mouse = PMOUSE;
m_tmrLastCursorMovement.reset();
Debug::log(LOG, "New mouse created, pointer WLR: %x", mouse); Debug::log(LOG, "New mouse created, pointer WLR: %x", mouse);
} }
@@ -330,6 +411,17 @@ void CInputManager::destroyKeyboard(SKeyboard* pKeyboard) {
pKeyboard->hyprListener_keyboardMod.removeCallback(); pKeyboard->hyprListener_keyboardMod.removeCallback();
pKeyboard->hyprListener_keyboardKey.removeCallback(); pKeyboard->hyprListener_keyboardKey.removeCallback();
if (pKeyboard->active) {
m_lKeyboards.remove(*pKeyboard);
if (m_lKeyboards.size() > 0) {
m_pActiveKeyboard = &m_lKeyboards.back();
m_pActiveKeyboard->active = true;
} else {
m_pActiveKeyboard = nullptr;
}
}
m_lKeyboards.remove(*pKeyboard); m_lKeyboards.remove(*pKeyboard);
} }
@@ -469,3 +561,23 @@ void CInputManager::constrainMouse(SMouse* pMouse, wlr_pointer_constraint_v1* co
void Events::listener_commitConstraint(void* owner, void* data) { void Events::listener_commitConstraint(void* owner, void* data) {
//g_pInputManager->recheckConstraint((SMouse*)owner); //g_pInputManager->recheckConstraint((SMouse*)owner);
} }
void CInputManager::updateCapabilities(wlr_input_device* pDev) {
// TODO: this is dumb
switch (pDev->type) {
case WLR_INPUT_DEVICE_KEYBOARD:
m_uiCapabilities |= WL_SEAT_CAPABILITY_KEYBOARD;
break;
case WLR_INPUT_DEVICE_POINTER:
m_uiCapabilities |= WL_SEAT_CAPABILITY_POINTER;
break;
case WLR_INPUT_DEVICE_TOUCH:
m_uiCapabilities |= WL_SEAT_CAPABILITY_TOUCH;
break;
default:
break;
}
wlr_seat_set_capabilities(g_pCompositor->m_sSeat.seat, m_uiCapabilities);
}

View File

@@ -1,9 +1,10 @@
#pragma once #pragma once
#include "../defines.hpp" #include "../../defines.hpp"
#include <list> #include <list>
#include "../helpers/WLClasses.hpp" #include "../../helpers/WLClasses.hpp"
#include "../Window.hpp" #include "../../Window.hpp"
#include "../../helpers/Timer.hpp"
class CInputManager { class CInputManager {
public: public:
@@ -28,6 +29,7 @@ public:
void setKeyboardLayout(); void setKeyboardLayout();
void updateDragIcon(); void updateDragIcon();
void updateCapabilities(wlr_input_device*);
// for dragging floating windows // for dragging floating windows
@@ -36,14 +38,32 @@ public:
SDrag m_sDrag; SDrag m_sDrag;
std::list<SConstraint> m_lConstraints; std::list<SConstraint> m_lConstraints;
std::list<SKeyboard> m_lKeyboards;
std::list<SMouse> m_lMice;
// tablets
std::list<STablet> m_lTablets;
std::list<STabletTool> m_lTabletTools;
std::list<STabletPad> m_lTabletPads;
void newTabletTool(wlr_input_device*);
void newTabletPad(wlr_input_device*);
void focusTablet(STablet*, wlr_tablet_tool*, bool motion = false);
SKeyboard* m_pActiveKeyboard = nullptr;
CTimer m_tmrLastCursorMovement;
private: private:
std::list<SKeyboard> m_lKeyboards; uint32_t m_uiCapabilities = 0;
std::list<SMouse> m_lMice;
void mouseMoveUnified(uint32_t, bool refocus = false); void mouseMoveUnified(uint32_t, bool refocus = false);
STabletTool* ensureTabletToolPresent(wlr_tablet_tool*);
void applyConfigToKeyboard(SKeyboard*);
}; };
inline std::unique_ptr<CInputManager> g_pInputManager; inline std::unique_ptr<CInputManager> g_pInputManager;

View File

@@ -0,0 +1,229 @@
#include "InputManager.hpp"
#include "../../Compositor.hpp"
void CInputManager::newTabletTool(wlr_input_device* pDevice) {
const auto PNEWTABLET = &m_lTablets.emplace_back();
PNEWTABLET->wlrTablet = pDevice->tablet;
PNEWTABLET->wlrDevice = pDevice;
PNEWTABLET->wlrTabletV2 = wlr_tablet_create(g_pCompositor->m_sWLRTabletManager, g_pCompositor->m_sSeat.seat, pDevice);
PNEWTABLET->wlrTablet->data = PNEWTABLET;
Debug::log(LOG, "Attaching tablet to cursor!");
wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, pDevice);
PNEWTABLET->hyprListener_Destroy.initCallback(&pDevice->events.destroy, [](void* owner, void* data) {
const auto PTAB = (STablet*)owner;
g_pInputManager->m_lTablets.remove(*PTAB);
Debug::log(LOG, "Removed a tablet");
}, PNEWTABLET, "Tablet");
PNEWTABLET->hyprListener_Axis.initCallback(&pDevice->tablet->events.axis, [](void* owner, void* data) {
const auto EVENT = (wlr_tablet_tool_axis_event*)data;
const auto PTAB = (STablet*)owner;
switch (EVENT->tool->type) {
case WLR_TABLET_TOOL_TYPE_MOUSE:
wlr_cursor_move(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, EVENT->dx, EVENT->dy);
g_pInputManager->refocus();
break;
default:
double x = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_X) ? EVENT->x : NAN;
double y = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_Y) ? EVENT->y : NAN;
wlr_cursor_warp_absolute(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, x, y);
g_pInputManager->refocus();
break;
}
const auto PTOOL = g_pInputManager->ensureTabletToolPresent(EVENT->tool);
// TODO: this might be wrong
if (PTOOL->active) {
g_pInputManager->refocus();
g_pInputManager->focusTablet(PTAB, EVENT->tool, true);
}
if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_PRESSURE)
wlr_tablet_v2_tablet_tool_notify_pressure(PTOOL->wlrTabletToolV2, EVENT->pressure);
if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_DISTANCE)
wlr_tablet_v2_tablet_tool_notify_distance(PTOOL->wlrTabletToolV2, EVENT->distance);
if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_ROTATION)
wlr_tablet_v2_tablet_tool_notify_rotation(PTOOL->wlrTabletToolV2, EVENT->rotation);
if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_SLIDER)
wlr_tablet_v2_tablet_tool_notify_slider(PTOOL->wlrTabletToolV2, EVENT->slider);
if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_WHEEL)
wlr_tablet_v2_tablet_tool_notify_wheel(PTOOL->wlrTabletToolV2, EVENT->wheel_delta, 0);
if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_X)
PTOOL->tiltX = EVENT->tilt_x;
if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_Y)
PTOOL->tiltY = EVENT->tilt_y;
if (EVENT->updated_axes & (WLR_TABLET_TOOL_AXIS_TILT_X | WLR_TABLET_TOOL_AXIS_TILT_Y))
wlr_tablet_v2_tablet_tool_notify_tilt(PTOOL->wlrTabletToolV2, PTOOL->tiltX, PTOOL->tiltY);
}, PNEWTABLET, "Tablet");
PNEWTABLET->hyprListener_Tip.initCallback(&pDevice->tablet->events.tip, [](void* owner, void* data) {
const auto EVENT = (wlr_tablet_tool_tip_event*)data;
const auto PTAB = (STablet*)owner;
const auto PTOOL = g_pInputManager->ensureTabletToolPresent(EVENT->tool);
// TODO: this might be wrong
if (EVENT->state == WLR_TABLET_TOOL_TIP_DOWN) {
g_pInputManager->refocus();
g_pInputManager->focusTablet(PTAB, EVENT->tool);
wlr_send_tablet_v2_tablet_tool_down(PTOOL->wlrTabletToolV2);
}
else {
wlr_send_tablet_v2_tablet_tool_up(PTOOL->wlrTabletToolV2);
}
}, PNEWTABLET, "Tablet");
PNEWTABLET->hyprListener_Button.initCallback(&pDevice->tablet->events.button, [](void* owner, void* data) {
const auto EVENT = (wlr_tablet_tool_button_event*)data;
const auto PTOOL = g_pInputManager->ensureTabletToolPresent(EVENT->tool);
wlr_tablet_v2_tablet_tool_notify_button(PTOOL->wlrTabletToolV2, (zwp_tablet_pad_v2_button_state)EVENT->button, (zwp_tablet_pad_v2_button_state)EVENT->state);
}, PNEWTABLET, "Tablet");
PNEWTABLET->hyprListener_Proximity.initCallback(&pDevice->tablet->events.proximity, [](void* owner, void* data) {
const auto EVENT = (wlr_tablet_tool_proximity_event*)data;
const auto PTAB = (STablet*)owner;
const auto PTOOL = g_pInputManager->ensureTabletToolPresent(EVENT->tool);
if (EVENT->state == WLR_TABLET_TOOL_PROXIMITY_OUT) {
PTOOL->active = false;
if (PTOOL->pSurface) {
wlr_tablet_v2_tablet_tool_notify_proximity_out(PTOOL->wlrTabletToolV2);
PTOOL->pSurface = nullptr;
}
} else {
PTOOL->active = true;
g_pInputManager->refocus();
g_pInputManager->focusTablet(PTAB, EVENT->tool);
}
}, PNEWTABLET, "Tablet");
}
STabletTool* CInputManager::ensureTabletToolPresent(wlr_tablet_tool* pTool) {
if (pTool->data == nullptr) {
const auto PTOOL = &m_lTabletTools.emplace_back();
Debug::log(LOG, "Creating tablet tool v2 for %x", pTool);
PTOOL->wlrTabletTool = pTool;
pTool->data = PTOOL;
PTOOL->wlrTabletToolV2 = wlr_tablet_tool_create(g_pCompositor->m_sWLRTabletManager, g_pCompositor->m_sSeat.seat, pTool);
PTOOL->hyprListener_TabletToolDestroy.initCallback(&pTool->events.destroy, [](void* owner, void* data) {
const auto PTOOL = (STabletTool*)owner;
PTOOL->wlrTabletTool->data = nullptr;
g_pInputManager->m_lTabletTools.remove(*PTOOL);
}, PTOOL, "Tablet Tool V1");
//TODO: set cursor request
}
return (STabletTool*)pTool->data;
}
void CInputManager::newTabletPad(wlr_input_device* pDevice) {
const auto PNEWPAD = &m_lTabletPads.emplace_back();
PNEWPAD->wlrTabletPadV2 = wlr_tablet_pad_create(g_pCompositor->m_sWLRTabletManager, g_pCompositor->m_sSeat.seat, pDevice);
PNEWPAD->hyprListener_Button.initCallback(&pDevice->tablet_pad->events.button, [](void* owner, void* data) {
const auto EVENT = (wlr_tablet_pad_button_event*)data;
const auto PPAD = (STabletPad*)owner;
wlr_tablet_v2_tablet_pad_notify_mode(PPAD->wlrTabletPadV2, EVENT->group, EVENT->mode, EVENT->time_msec);
wlr_tablet_v2_tablet_pad_notify_button(PPAD->wlrTabletPadV2, EVENT->button, EVENT->time_msec, (zwp_tablet_pad_v2_button_state)EVENT->state);
}, PNEWPAD, "Tablet Pad");
PNEWPAD->hyprListener_Strip.initCallback(&pDevice->tablet_pad->events.strip, [](void* owner, void* data) {
const auto EVENT = (wlr_tablet_pad_strip_event*)data;
const auto PPAD = (STabletPad*)owner;
wlr_tablet_v2_tablet_pad_notify_strip(PPAD->wlrTabletPadV2, EVENT->strip, EVENT->position, EVENT->source == WLR_TABLET_PAD_STRIP_SOURCE_FINGER, EVENT->time_msec);
}, PNEWPAD, "Tablet Pad");
PNEWPAD->hyprListener_Ring.initCallback(&pDevice->tablet_pad->events.strip, [](void* owner, void* data) {
const auto EVENT = (wlr_tablet_pad_ring_event*)data;
const auto PPAD = (STabletPad*)owner;
wlr_tablet_v2_tablet_pad_notify_ring(PPAD->wlrTabletPadV2, EVENT->ring, EVENT->position, EVENT->source == WLR_TABLET_PAD_RING_SOURCE_FINGER, EVENT->time_msec);
}, PNEWPAD, "Tablet Pad");
PNEWPAD->hyprListener_Attach.initCallback(&pDevice->tablet_pad->events.strip, [](void* owner, void* data) {
const auto TABLET = (wlr_tablet_tool*)data;
const auto PPAD = (STabletPad*)owner;
PPAD->pTabletParent = (STablet*)TABLET->data;
if (!PPAD->pTabletParent)
Debug::log(ERR, "tabletpad got attached to a nullptr tablet!! this might be bad.");
}, PNEWPAD, "Tablet Pad");
PNEWPAD->hyprListener_Destroy.initCallback(&pDevice->events.destroy, [](void* owner, void* data) {
const auto PPAD = (STabletPad*)owner;
g_pInputManager->m_lTabletPads.remove(*PPAD);
Debug::log(LOG, "Removed a tablet pad");
}, PNEWPAD, "Tablet Pad");
}
void CInputManager::focusTablet(STablet* pTab, wlr_tablet_tool* pTool, bool motion) {
const auto PTOOL = g_pInputManager->ensureTabletToolPresent(pTool);
if (const auto PWINDOW = g_pCompositor->m_pLastWindow; g_pCompositor->windowValidMapped(PWINDOW)) {
const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal();
const auto LOCAL = CURSORPOS - PWINDOW->m_vRealPosition.goalv();
if (PTOOL->pSurface != g_pCompositor->m_pLastFocus)
wlr_tablet_v2_tablet_tool_notify_proximity_out(PTOOL->wlrTabletToolV2);
if (g_pCompositor->m_pLastFocus) {
PTOOL->pSurface = g_pCompositor->m_pLastFocus;
wlr_tablet_v2_tablet_tool_notify_proximity_in(PTOOL->wlrTabletToolV2, pTab->wlrTabletV2, g_pCompositor->m_pLastFocus);
}
if (motion)
wlr_tablet_v2_tablet_tool_notify_motion(PTOOL->wlrTabletToolV2, LOCAL.x, LOCAL.y);
} else {
if (PTOOL->pSurface)
wlr_tablet_v2_tablet_tool_notify_proximity_out(PTOOL->wlrTabletToolV2);
}
}

25
src/meson.build Normal file
View File

@@ -0,0 +1,25 @@
globber = run_command('find', '-name', '*.cpp', check: true)
src = globber.stdout().strip().split('\n')
executable('Hyprland', src,
cpp_args: ['-DWLR_USE_UNSTABLE'],
dependencies: [
server_protos,
dependency('wayland-server'),
dependency('wayland-client'),
wlroots.get_variable('wlroots'),
dependency('cairo'),
dependency('pango'),
dependency('pangocairo'),
dependency('libdrm'),
dependency('egl'),
dependency('xkbcommon'),
dependency('libinput'),
xcb_dep,
dependency('pixman-1'),
dependency('GL'),
dependency('threads')
],
install : true
)

View File

@@ -75,6 +75,18 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
m_shBLUR2.posAttrib = glGetAttribLocation(prog, "pos"); m_shBLUR2.posAttrib = glGetAttribLocation(prog, "pos");
m_shBLUR2.texAttrib = glGetAttribLocation(prog, "texcoord"); m_shBLUR2.texAttrib = glGetAttribLocation(prog, "texcoord");
prog = createProgram(QUADVERTSRC, FRAGSHADOW);
m_shSHADOW.program = prog;
m_shSHADOW.proj = glGetUniformLocation(prog, "proj");
m_shSHADOW.posAttrib = glGetAttribLocation(prog, "pos");
m_shSHADOW.texAttrib = glGetAttribLocation(prog, "texcoord");
prog = createProgram(QUADVERTSRC, FRAGBORDER1);
m_shBORDER1.program = prog;
m_shBORDER1.proj = glGetUniformLocation(prog, "proj");
m_shBORDER1.posAttrib = glGetAttribLocation(prog, "pos");
m_shBORDER1.texAttrib = glGetAttribLocation(prog, "texcoord");
Debug::log(LOG, "Shaders initialized successfully."); Debug::log(LOG, "Shaders initialized successfully.");
// End shaders // End shaders
@@ -240,6 +252,10 @@ void CHyprOpenGLImpl::scissor(const int x, const int y, const int w, const int h
} }
void CHyprOpenGLImpl::renderRect(wlr_box* box, const CColor& col, int round) { void CHyprOpenGLImpl::renderRect(wlr_box* box, const CColor& col, int round) {
renderRectWithDamage(box, col, m_RenderData.pDamage, round);
}
void CHyprOpenGLImpl::renderRectWithDamage(wlr_box* box, const CColor& col, pixman_region32_t* damage, int round) {
RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!"); RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!");
RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!"); RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!");
@@ -264,11 +280,14 @@ void CHyprOpenGLImpl::renderRect(wlr_box* box, const CColor& col, int round) {
const auto BOTTOMRIGHT = Vector2D(box->width - round, box->height - round); const auto BOTTOMRIGHT = Vector2D(box->width - round, box->height - round);
const auto FULLSIZE = Vector2D(box->width, box->height); const auto FULLSIZE = Vector2D(box->width, box->height);
static auto *const PMULTISAMPLEEDGES = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue;
// Rounded corners // Rounded corners
glUniform2f(glGetUniformLocation(m_shQUAD.program, "topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y); glUniform2f(glGetUniformLocation(m_shQUAD.program, "topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y);
glUniform2f(glGetUniformLocation(m_shQUAD.program, "bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); glUniform2f(glGetUniformLocation(m_shQUAD.program, "bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
glUniform2f(glGetUniformLocation(m_shQUAD.program, "fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y); glUniform2f(glGetUniformLocation(m_shQUAD.program, "fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y);
glUniform1f(glGetUniformLocation(m_shQUAD.program, "radius"), round); glUniform1f(glGetUniformLocation(m_shQUAD.program, "radius"), round);
glUniform1i(glGetUniformLocation(m_shQUAD.program, "primitiveMultisample"), (int)(*PMULTISAMPLEEDGES == 1 && round != 0));
glVertexAttribPointer(m_shQUAD.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glVertexAttribPointer(m_shQUAD.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glVertexAttribPointer(m_shQUAD.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glVertexAttribPointer(m_shQUAD.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
@@ -276,8 +295,8 @@ void CHyprOpenGLImpl::renderRect(wlr_box* box, const CColor& col, int round) {
glEnableVertexAttribArray(m_shQUAD.posAttrib); glEnableVertexAttribArray(m_shQUAD.posAttrib);
glEnableVertexAttribArray(m_shQUAD.texAttrib); glEnableVertexAttribArray(m_shQUAD.texAttrib);
if (pixman_region32_not_empty(m_RenderData.pDamage)) { if (pixman_region32_not_empty(damage)) {
PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) { PIXMAN_DAMAGE_FOREACH(damage) {
const auto RECT = RECTSARR[i]; const auto RECT = RECTSARR[i];
scissor(&RECT); scissor(&RECT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
@@ -296,15 +315,15 @@ void CHyprOpenGLImpl::renderTexture(wlr_texture* tex, wlr_box* pBox, float alpha
renderTexture(CTexture(tex), pBox, alpha, round); renderTexture(CTexture(tex), pBox, alpha, round);
} }
void CHyprOpenGLImpl::renderTexture(const CTexture& tex, wlr_box* pBox, float alpha, int round, bool discardopaque, bool border) { void CHyprOpenGLImpl::renderTexture(const CTexture& tex, wlr_box* pBox, float alpha, int round, bool discardopaque, bool allowPrimary) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
renderTextureInternalWithDamage(tex, pBox, alpha, m_RenderData.pDamage, round, discardopaque, border); renderTextureInternalWithDamage(tex, pBox, alpha, m_RenderData.pDamage, round, discardopaque, false, allowPrimary);
scissor((wlr_box*)nullptr); scissor((wlr_box*)nullptr);
} }
void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_box* pBox, float alpha, pixman_region32_t* damage, int round, bool discardOpaque, bool border) { void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_box* pBox, float alpha, pixman_region32_t* damage, int round, bool discardOpaque, bool noAA, bool allowPrimary) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!"); RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!");
@@ -354,32 +373,35 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
// so we need to do some maf // so we need to do some maf
const auto TOPLEFT = Vector2D(round, round); const auto TOPLEFT = Vector2D(round, round);
const auto BOTTOMRIGHT = Vector2D(tex.m_vSize.x - round, tex.m_vSize.y - round); const auto BOTTOMRIGHT = Vector2D(pBox->width - round, pBox->height - round);
const auto FULLSIZE = tex.m_vSize; const auto FULLSIZE = Vector2D(pBox->width, pBox->height);
static auto *const PMULTISAMPLEEDGES = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue;
// Rounded corners // Rounded corners
glUniform2f(glGetUniformLocation(shader->program, "topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y); glUniform2f(glGetUniformLocation(shader->program, "topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y);
glUniform2f(glGetUniformLocation(shader->program, "bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); glUniform2f(glGetUniformLocation(shader->program, "bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
glUniform2f(glGetUniformLocation(shader->program, "fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y); glUniform2f(glGetUniformLocation(shader->program, "fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y);
glUniform1f(glGetUniformLocation(shader->program, "radius"), round); glUniform1f(glGetUniformLocation(shader->program, "radius"), round);
glUniform1i(glGetUniformLocation(shader->program, "primitiveMultisample"), (int)(*PMULTISAMPLEEDGES == 1 && round != 0 && !noAA));
glVertexAttribPointer(shader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glVertexAttribPointer(shader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glVertexAttribPointer(shader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
if (allowPrimary && m_RenderData.renderingPrimarySurface && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) {
const float verts[] = {
m_RenderData.primarySurfaceUVBottomRight.x, m_RenderData.primarySurfaceUVTopLeft.y, // top right
m_RenderData.primarySurfaceUVTopLeft.x, m_RenderData.primarySurfaceUVTopLeft.y, // top left
m_RenderData.primarySurfaceUVBottomRight.x, m_RenderData.primarySurfaceUVBottomRight.y, // bottom right
m_RenderData.primarySurfaceUVTopLeft.x, m_RenderData.primarySurfaceUVBottomRight.y, // bottom left
};
glVertexAttribPointer(shader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, verts);
} else {
glVertexAttribPointer(shader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
}
glEnableVertexAttribArray(shader->posAttrib); glEnableVertexAttribArray(shader->posAttrib);
glEnableVertexAttribArray(shader->texAttrib); glEnableVertexAttribArray(shader->texAttrib);
// stencil for when we want a border
if (border) {
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 1, -1);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
}
if (pixman_region32_not_empty(m_RenderData.pDamage)) { if (pixman_region32_not_empty(m_RenderData.pDamage)) {
PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) { PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) {
const auto RECT = RECTSARR[i]; const auto RECT = RECTSARR[i];
@@ -388,27 +410,10 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
} }
} }
if (border) {
glStencilFunc(GL_EQUAL, 1, -1);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
}
glDisableVertexAttribArray(shader->posAttrib); glDisableVertexAttribArray(shader->posAttrib);
glDisableVertexAttribArray(shader->texAttrib); glDisableVertexAttribArray(shader->texAttrib);
glBindTexture(tex.m_iTarget, 0); glBindTexture(tex.m_iTarget, 0);
// if border draw
// we dont disable stencil here if we havent touched it.
// some other func might be using it.
if (border) {
auto BORDERCOL = m_pCurrentWindow->m_cRealBorderColor.col();
BORDERCOL.a *= alpha / 255.f;
renderBorder(pBox, BORDERCOL, g_pConfigManager->getInt("general:border_size"), round);
glStencilMask(-1);
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glDisable(GL_STENCIL_TEST);
}
} }
// This probably isn't the fastest // This probably isn't the fastest
@@ -432,14 +437,14 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p
wlr_matrix_transpose(glMatrix, glMatrix); wlr_matrix_transpose(glMatrix, glMatrix);
// get the config settings // get the config settings
const auto BLURSIZE = g_pConfigManager->getInt("decoration:blur_size"); static auto *const PBLURSIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_size")->intValue;
const auto BLURPASSES = g_pConfigManager->getInt("decoration:blur_passes"); static auto *const PBLURPASSES = &g_pConfigManager->getConfigValuePtr("decoration:blur_passes")->intValue;
// prep damage // prep damage
pixman_region32_t damage; pixman_region32_t damage;
pixman_region32_init(&damage); pixman_region32_init(&damage);
pixman_region32_copy(&damage, originalDamage); pixman_region32_copy(&damage, originalDamage);
wlr_region_expand(&damage, &damage, pow(2, BLURPASSES) * BLURSIZE); wlr_region_expand(&damage, &damage, pow(2, *PBLURPASSES) * *PBLURSIZE);
// helper // helper
const auto PMIRRORFB = &m_mMonitorRenderResources[m_RenderData.pMonitor].mirrorFB; const auto PMIRRORFB = &m_mMonitorRenderResources[m_RenderData.pMonitor].mirrorFB;
@@ -464,7 +469,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p
// prep two shaders // prep two shaders
glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix); glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix);
glUniform1f(glGetUniformLocation(pShader->program, "radius"), BLURSIZE * (a / 255.f)); // this makes the blursize change with a glUniform1f(glGetUniformLocation(pShader->program, "radius"), *PBLURSIZE * (a / 255.f)); // this makes the blursize change with a
if (pShader == &m_shBLUR1) if (pShader == &m_shBLUR1)
glUniform2f(glGetUniformLocation(m_shBLUR1.program, "halfpixel"), 0.5f / (m_RenderData.pMonitor->vecPixelSize.x / 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y / 2.f)); glUniform2f(glGetUniformLocation(m_shBLUR1.program, "halfpixel"), 0.5f / (m_RenderData.pMonitor->vecPixelSize.x / 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y / 2.f));
else else
@@ -508,12 +513,12 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p
drawPass(&m_shBLUR1, &tempDamage); drawPass(&m_shBLUR1, &tempDamage);
// and draw // and draw
for (int i = 1; i < BLURPASSES; ++i) { for (int i = 1; i < *PBLURPASSES; ++i) {
wlr_region_scale(&tempDamage, &damage, 1.f / (1 << (i + 1))); wlr_region_scale(&tempDamage, &damage, 1.f / (1 << (i + 1)));
drawPass(&m_shBLUR1, &tempDamage); // down drawPass(&m_shBLUR1, &tempDamage); // down
} }
for (int i = BLURPASSES - 1; i >= 0; --i) { for (int i = *PBLURPASSES - 1; i >= 0; --i) {
wlr_region_scale(&tempDamage, &damage, 1.f / (1 << i)); // when upsampling we make the region twice as big wlr_region_scale(&tempDamage, &damage, 1.f / (1 << i)); // when upsampling we make the region twice as big
drawPass(&m_shBLUR2, &tempDamage); // up drawPass(&m_shBLUR2, &tempDamage); // up
} }
@@ -530,11 +535,14 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p
return currentRenderToFB; return currentRenderToFB;
} }
void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, float a, wlr_surface* pSurface, int round, bool border) { void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, float a, wlr_surface* pSurface, int round) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture with blur without begin()!"); RASSERT(m_RenderData.pMonitor, "Tried to render texture with blur without begin()!");
if (g_pConfigManager->getInt("decoration:blur") == 0) { static auto *const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue;
renderTexture(tex, pBox, a, round, false, border); static auto* const PNOBLUROVERSIZED = &g_pConfigManager->getConfigValuePtr("decoration:no_blur_on_oversized")->intValue;
if (*PBLURENABLED == 0 || (*PNOBLUROVERSIZED && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) || (m_pCurrentWindow && m_pCurrentWindow->m_sAdditionalConfigData.forceNoBlur)) {
renderTexture(tex, pBox, a, round, false, true);
return; return;
} }
@@ -556,8 +564,10 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox,
pixman_region32_copy(&inverseOpaque, &damage); pixman_region32_copy(&inverseOpaque, &damage);
} }
if (!pixman_region32_not_empty(&damage)) if (!pixman_region32_not_empty(&inverseOpaque)) {
return; // if its empty, reject. renderTexture(tex, pBox, a, round, false); // reject blurring a fully opaque window
return;
}
// blur the main FB, it will be rendered onto the mirror // blur the main FB, it will be rendered onto the mirror
const auto POUTFB = blurMainFramebufferWithDamage(a, pBox, &inverseOpaque); const auto POUTFB = blurMainFramebufferWithDamage(a, pBox, &inverseOpaque);
@@ -588,34 +598,20 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox,
wlr_box MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; wlr_box MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y};
if (pixman_region32_not_empty(&damage)) { if (pixman_region32_not_empty(&damage)) {
// render our great blurred FB // render our great blurred FB
renderTextureInternalWithDamage(POUTFB->m_cTex, &MONITORBOX, g_pConfigManager->getInt("decoration:blur_ignore_opacity") ? 255.f : a, &damage); static auto *const PBLURIGNOREOPACITY = &g_pConfigManager->getConfigValuePtr("decoration:blur_ignore_opacity")->intValue;
renderTextureInternalWithDamage(POUTFB->m_cTex, &MONITORBOX, *PBLURIGNOREOPACITY ? 255.f : a, &damage, 0, false, false, true);
// render the window, but clear stencil // render the window, but clear stencil
glClearStencil(0); glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT); glClear(GL_STENCIL_BUFFER_BIT);
// and write to it // draw window
glStencilFunc(GL_ALWAYS, 1, -1); glDisable(GL_STENCIL_TEST);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); renderTextureInternalWithDamage(tex, pBox, a, &damage, round, false, false, true);
renderTextureInternalWithDamage(tex, pBox, a, &damage, round);
// then stop
glStencilFunc(GL_EQUAL, 1, -1);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
} }
// disable the stencil (if no border), finalize everything glStencilMask(-1);
if (!border) { glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilMask(-1);
glStencilFunc(GL_ALWAYS, 1, 0xFF);
} else {
auto BORDERCOL = m_pCurrentWindow->m_cRealBorderColor.col();
BORDERCOL.a *= a / 255.f;
renderBorder(pBox, BORDERCOL, g_pConfigManager->getInt("general:border_size"), round);
}
glDisable(GL_STENCIL_TEST);
pixman_region32_fini(&damage); pixman_region32_fini(&damage);
scissor((wlr_box*)nullptr); scissor((wlr_box*)nullptr);
} }
@@ -627,23 +623,67 @@ void pushVert2D(float x, float y, float* arr, int& counter, wlr_box* box) {
counter++; counter++;
} }
void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int thick, int round) { void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int round) {
RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!"); RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!");
RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!"); RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!");
// this method assumes a set stencil and scaled box static auto *const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
box->x -= thick; static auto *const PMULTISAMPLE = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue;
box->y -= thick;
box->width += 2 * thick;
box->height += 2 * thick;
round += thick; // cuz yeah // adjust box
box->x -= *PBORDERSIZE;
box->y -= *PBORDERSIZE;
box->width += 2 * *PBORDERSIZE;
box->height += 2 * *PBORDERSIZE;
// only draw on non-stencild. round += *PBORDERSIZE;
glStencilFunc(GL_NOTEQUAL, 1, -1);
// draw a rounded rect float matrix[9];
renderRect(box, col, round); wlr_matrix_project_box(matrix, box, wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), 0, m_RenderData.pMonitor->output->transform_matrix); // TODO: write own, don't use WLR here
float glMatrix[9];
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
wlr_matrix_multiply(glMatrix, matrixFlip180, glMatrix);
wlr_matrix_transpose(glMatrix, glMatrix);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glUseProgram(m_shBORDER1.program);
glUniformMatrix3fv(m_shBORDER1.proj, 1, GL_FALSE, glMatrix);
glUniform4f(glGetUniformLocation(m_shBORDER1.program, "color"), col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f);
const auto TOPLEFT = Vector2D(round, round);
const auto BOTTOMRIGHT = Vector2D(box->width - round, box->height - round);
const auto FULLSIZE = Vector2D(box->width, box->height);
glUniform2f(glGetUniformLocation(m_shBORDER1.program, "topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y);
glUniform2f(glGetUniformLocation(m_shBORDER1.program, "bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
glUniform2f(glGetUniformLocation(m_shBORDER1.program, "fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y);
glUniform1f(glGetUniformLocation(m_shBORDER1.program, "radius"), round);
glUniform1f(glGetUniformLocation(m_shBORDER1.program, "thick"), *PBORDERSIZE);
glUniform1i(glGetUniformLocation(m_shBORDER1.program, "primitiveMultisample"), *PMULTISAMPLE);
glVertexAttribPointer(m_shBORDER1.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glVertexAttribPointer(m_shBORDER1.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glEnableVertexAttribArray(m_shBORDER1.posAttrib);
glEnableVertexAttribArray(m_shBORDER1.texAttrib);
if (pixman_region32_not_empty(m_RenderData.pDamage)) {
PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) {
const auto RECT = RECTSARR[i];
scissor(&RECT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
}
glDisableVertexAttribArray(m_shBORDER1.posAttrib);
glDisableVertexAttribArray(m_shBORDER1.texAttrib);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
} }
void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) { void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) {
@@ -812,6 +852,68 @@ void CHyprOpenGLImpl::renderSnapshot(SLayerSurface** pLayer) {
pixman_region32_fini(&fakeDamage); pixman_region32_fini(&fakeDamage);
} }
void CHyprOpenGLImpl::renderRoundedShadow(wlr_box* box, int round, int range, float a) {
RASSERT(m_RenderData.pMonitor, "Tried to render shadow without begin()!");
RASSERT((box->width > 0 && box->height > 0), "Tried to render shadow with width/height < 0!");
static auto *const PSHADOWCOL = &g_pConfigManager->getConfigValuePtr("decoration:col.shadow")->intValue;
static auto *const PSHADOWPOWER = &g_pConfigManager->getConfigValuePtr("decoration:shadow_render_power")->intValue;
static auto *const PSHADOWIGNOREWINDOW = &g_pConfigManager->getConfigValuePtr("decoration:shadow_ignore_window")->intValue;
const auto SHADOWPOWER = std::clamp((int)*PSHADOWPOWER, 1, 4);
const auto col = CColor(*PSHADOWCOL);
float matrix[9];
wlr_matrix_project_box(matrix, box, wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), 0, m_RenderData.pMonitor->output->transform_matrix); // TODO: write own, don't use WLR here
float glMatrix[9];
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
wlr_matrix_multiply(glMatrix, matrixFlip180, glMatrix);
wlr_matrix_transpose(glMatrix, glMatrix);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glUseProgram(m_shSHADOW.program);
glUniformMatrix3fv(m_shSHADOW.proj, 1, GL_FALSE, glMatrix);
glUniform4f(glGetUniformLocation(m_shSHADOW.program, "color"), col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f * a);
const auto TOPLEFT = Vector2D(range + round, range + round);
const auto BOTTOMRIGHT = Vector2D(box->width - (range + round), box->height - (range + round));
const auto FULLSIZE = Vector2D(box->width, box->height);
// Rounded corners
glUniform2f(glGetUniformLocation(m_shSHADOW.program, "topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y);
glUniform2f(glGetUniformLocation(m_shSHADOW.program, "bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y);
glUniform2f(glGetUniformLocation(m_shSHADOW.program, "fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y);
glUniform1f(glGetUniformLocation(m_shSHADOW.program, "radius"), range + round);
glUniform1f(glGetUniformLocation(m_shSHADOW.program, "range"), range);
glUniform1f(glGetUniformLocation(m_shSHADOW.program, "shadowPower"), SHADOWPOWER);
glUniform1i(glGetUniformLocation(m_shSHADOW.program, "ignoreWindow"), *PSHADOWIGNOREWINDOW);
glVertexAttribPointer(m_shSHADOW.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glVertexAttribPointer(m_shSHADOW.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
glEnableVertexAttribArray(m_shSHADOW.posAttrib);
glEnableVertexAttribArray(m_shSHADOW.texAttrib);
if (pixman_region32_not_empty(m_RenderData.pDamage)) {
PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) {
const auto RECT = RECTSARR[i];
scissor(&RECT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
}
glDisableVertexAttribArray(m_shSHADOW.posAttrib);
glDisableVertexAttribArray(m_shSHADOW.texAttrib);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
void CHyprOpenGLImpl::createBGTextureForMonitor(SMonitor* pMonitor) { void CHyprOpenGLImpl::createBGTextureForMonitor(SMonitor* pMonitor) {
RASSERT(m_RenderData.pMonitor, "Tried to createBGTex without begin()!"); RASSERT(m_RenderData.pMonitor, "Tried to createBGTex without begin()!");

View File

@@ -34,6 +34,10 @@ struct SCurrentRenderData {
float projection[9]; float projection[9];
pixman_region32_t* pDamage = nullptr; pixman_region32_t* pDamage = nullptr;
bool renderingPrimarySurface = false;
Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
}; };
struct SMonitorRenderData { struct SMonitorRenderData {
@@ -53,9 +57,12 @@ public:
void end(); void end();
void renderRect(wlr_box*, const CColor&, int round = 0); void renderRect(wlr_box*, const CColor&, int round = 0);
void renderRectWithDamage(wlr_box*, const CColor&, pixman_region32_t* damage, int round = 0);
void renderTexture(wlr_texture*, wlr_box*, float a, int round = 0); void renderTexture(wlr_texture*, wlr_box*, float a, int round = 0);
void renderTexture(const CTexture&, wlr_box*, float a, int round = 0, bool discardOpaque = false, bool border = false); void renderTexture(const CTexture&, wlr_box*, float a, int round = 0, bool discardOpaque = false, bool allowPrimary = false);
void renderTextureWithBlur(const CTexture&, wlr_box*, float a, wlr_surface* pSurface, int round = 0, bool border = false); void renderTextureWithBlur(const CTexture&, wlr_box*, float a, wlr_surface* pSurface, int round = 0);
void renderRoundedShadow(wlr_box*, int round, int range, float a = 1.0);
void renderBorder(wlr_box*, const CColor&, int round);
void makeWindowSnapshot(CWindow*); void makeWindowSnapshot(CWindow*);
void makeLayerSnapshot(SLayerSurface*); void makeLayerSnapshot(SLayerSurface*);
@@ -101,6 +108,8 @@ private:
CShader m_shEXT; CShader m_shEXT;
CShader m_shBLUR1; CShader m_shBLUR1;
CShader m_shBLUR2; CShader m_shBLUR2;
CShader m_shSHADOW;
CShader m_shBORDER1;
// //
GLuint createProgram(const std::string&, const std::string&); GLuint createProgram(const std::string&, const std::string&);
@@ -110,8 +119,7 @@ private:
// returns the out FB, can be either Mirror or MirrorSwap // returns the out FB, can be either Mirror or MirrorSwap
CFramebuffer* blurMainFramebufferWithDamage(float a, wlr_box* pBox, pixman_region32_t* damage); CFramebuffer* blurMainFramebufferWithDamage(float a, wlr_box* pBox, pixman_region32_t* damage);
void renderTextureInternalWithDamage(const CTexture&, wlr_box* pBox, float a, pixman_region32_t* damage, int round = 0, bool discardOpaque = false, bool border = false); void renderTextureInternalWithDamage(const CTexture&, wlr_box* pBox, float a, pixman_region32_t* damage, int round = 0, bool discardOpaque = false, bool noAA = false, bool allowPrimary = false);
void renderBorder(wlr_box*, const CColor&, int thick = 1, int round = 0);
}; };
inline std::unique_ptr<CHyprOpenGLImpl> g_pHyprOpenGL; inline std::unique_ptr<CHyprOpenGLImpl> g_pHyprOpenGL;

View File

@@ -19,10 +19,22 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
} }
scaleBox(&windowBox, RDATA->output->scale); scaleBox(&windowBox, RDATA->output->scale);
float rounding = RDATA->dontRound ? 0 : RDATA->rounding == -1 ? g_pConfigManager->getInt("decoration:rounding") : RDATA->rounding; static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
if (RDATA->surface && surface == RDATA->surface) float rounding = RDATA->dontRound ? 0 : RDATA->rounding == -1 ? *PROUNDING : RDATA->rounding;
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, rounding, RDATA->decorate);
g_pHyprOpenGL->m_RenderData.renderingPrimarySurface = false;
if (RDATA->surface && surface == RDATA->surface) {
g_pHyprOpenGL->m_RenderData.renderingPrimarySurface = true;
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, rounding);
if (RDATA->decorate) {
auto col = g_pHyprOpenGL->m_pCurrentWindow->m_cRealBorderColor.col();
col.a *= RDATA->fadeAlpha * RDATA->alpha / 255.f;
g_pHyprOpenGL->renderBorder(&windowBox, col, rounding);
}
}
else else
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, false, false); g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, false, false);
@@ -31,8 +43,8 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
wlr_presentation_surface_sampled_on_output(g_pCompositor->m_sWLRPresentation, surface, RDATA->output); wlr_presentation_surface_sampled_on_output(g_pCompositor->m_sWLRPresentation, surface, RDATA->output);
} }
bool shouldRenderWindow(CWindow* pWindow, SMonitor* pMonitor) { bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow, SMonitor* pMonitor) {
wlr_box geometry = {pWindow->m_vRealPosition.vec().x, pWindow->m_vRealPosition.vec().y, pWindow->m_vRealSize.vec().x, pWindow->m_vRealSize.vec().y}; wlr_box geometry = pWindow->getFullWindowBoundingBox();
if (!wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, &geometry)) if (!wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, &geometry))
return false; return false;
@@ -46,6 +58,30 @@ bool shouldRenderWindow(CWindow* pWindow, SMonitor* pMonitor) {
if (g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID) || (PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated()))) if (g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID) || (PWORKSPACE && PWORKSPACE->m_iMonitorID == pMonitor->ID && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated())))
return true; return true;
if (pMonitor->specialWorkspaceOpen && pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
return true;
return false;
}
bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow) {
if (!g_pCompositor->windowValidMapped(pWindow))
return false;
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
if (g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID))
return true;
for (auto& m : g_pCompositor->m_lMonitors) {
if (PWORKSPACE && PWORKSPACE->m_iMonitorID == m.ID && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated()))
return true;
if (m.specialWorkspaceOpen && pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
return true;
}
return false; return false;
} }
@@ -70,6 +106,21 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(SMonitor* pMonitor, CWor
renderWindow(&w, pMonitor, time, true); renderWindow(&w, pMonitor, time, true);
} }
// and then special windows
for (auto& w : g_pCompositor->m_lWindows) {
if (!g_pCompositor->windowValidMapped(&w) && !w.m_bFadingOut)
continue;
if (w.m_iWorkspaceID != SPECIAL_WORKSPACE_ID)
continue;
if (!shouldRenderWindow(&w, pMonitor))
continue;
// render the bad boy
renderWindow(&w, pMonitor, time, true);
}
// and the overlay layers // and the overlay layers
if (pWorkspace->m_efFullscreenMode != FULLSCREEN_FULL) { if (pWorkspace->m_efFullscreenMode != FULLSCREEN_FULL) {
// on non-full we draw the bar and shit // on non-full we draw the bar and shit
@@ -101,6 +152,8 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec*
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
const auto REALPOS = pWindow->m_vRealPosition.vec() + PWORKSPACE->m_vRenderOffset.vec(); const auto REALPOS = pWindow->m_vRealPosition.vec() + PWORKSPACE->m_vRenderOffset.vec();
static const auto PNOFLOATINGBORDERS = &g_pConfigManager->getConfigValuePtr("general:no_border_on_floating")->intValue;
SRenderData renderdata = {pMonitor->output, time, REALPOS.x, REALPOS.y}; SRenderData renderdata = {pMonitor->output, time, REALPOS.x, REALPOS.y};
renderdata.surface = g_pXWaylandManager->getWindowSurface(pWindow); renderdata.surface = g_pXWaylandManager->getWindowSurface(pWindow);
renderdata.w = std::clamp(pWindow->m_vRealSize.vec().x, (double)5, (double)1337420); // clamp the size to min 5, renderdata.w = std::clamp(pWindow->m_vRealSize.vec().x, (double)5, (double)1337420); // clamp the size to min 5,
@@ -108,26 +161,46 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec*
renderdata.dontRound = pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL; renderdata.dontRound = pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL;
renderdata.fadeAlpha = pWindow->m_fAlpha.fl() * (PWORKSPACE->m_fAlpha.fl() / 255.f); renderdata.fadeAlpha = pWindow->m_fAlpha.fl() * (PWORKSPACE->m_fAlpha.fl() / 255.f);
renderdata.alpha = pWindow->m_bIsFullscreen ? g_pConfigManager->getFloat("decoration:fullscreen_opacity") : pWindow == g_pCompositor->m_pLastWindow ? g_pConfigManager->getFloat("decoration:active_opacity") : g_pConfigManager->getFloat("decoration:inactive_opacity"); renderdata.alpha = pWindow->m_bIsFullscreen ? g_pConfigManager->getFloat("decoration:fullscreen_opacity") : pWindow == g_pCompositor->m_pLastWindow ? g_pConfigManager->getFloat("decoration:active_opacity") : g_pConfigManager->getFloat("decoration:inactive_opacity");
renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders; renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && (pWindow->m_bIsFloating ? *PNOFLOATINGBORDERS == 0 : true);
renderdata.rounding = pWindow->m_sAdditionalConfigData.rounding; renderdata.rounding = pWindow->m_sAdditionalConfigData.rounding;
// apply window special data // apply window special data
renderdata.alpha *= pWindow->m_sSpecialRenderData.alpha; if (pWindow->m_sSpecialRenderData.alphaInactive == -1)
renderdata.alpha *= pWindow->m_sSpecialRenderData.alpha;
else
renderdata.alpha *= pWindow == g_pCompositor->m_pLastWindow ? pWindow->m_sSpecialRenderData.alpha : pWindow->m_sSpecialRenderData.alphaInactive;
g_pHyprOpenGL->m_pCurrentWindow = pWindow; g_pHyprOpenGL->m_pCurrentWindow = pWindow;
// render window decorations first // render window decorations first
for (auto& wd : pWindow->m_dWindowDecorations) for (auto& wd : pWindow->m_dWindowDecorations)
wd->draw(pMonitor); wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha / 255.f);
if (!pWindow->m_bIsX11) {
// To everyone who makes apps with improperly aligned surfaces,
// For example chromium, or GTK devs who allow shadows on windows,
// a sincere FUCK YOU.
wlr_box geom;
wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, &geom);
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D((double)geom.x / (double)pWindow->m_uSurface.xdg->surface->current.width, (double)geom.y / (double)pWindow->m_uSurface.xdg->surface->current.height);
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D((double)(geom.width + geom.x) / (double)pWindow->m_uSurface.xdg->surface->current.width, (double)(geom.y + geom.height) / (double)pWindow->m_uSurface.xdg->surface->current.height);
if (g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft == Vector2D() && g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight == Vector2D(1, 1)) {
// No special UV mods needed
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
}
}
wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(pWindow), renderSurface, &renderdata); wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(pWindow), renderSurface, &renderdata);
if (pWindow->m_bIsX11) { g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
if (pWindow->m_uSurface.xwayland->surface) { g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
wlr_surface_for_each_surface(pWindow->m_uSurface.xwayland->surface, renderSurface, &renderdata);
} if (!pWindow->m_bIsX11) {
}
else {
renderdata.dontRound = false; // restore dontround renderdata.dontRound = false; // restore dontround
renderdata.pMonitor = pMonitor; renderdata.pMonitor = pMonitor;
wlr_xdg_surface_for_each_popup_surface(pWindow->m_uSurface.xdg, renderSurface, &renderdata); wlr_xdg_surface_for_each_popup_surface(pWindow->m_uSurface.xdg, renderSurface, &renderdata);
@@ -176,7 +249,10 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
continue; continue;
if (w.m_bIsFloating) if (w.m_bIsFloating)
continue; // floating are in second pass continue; // floating are in the second pass
if (w.m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
continue; // special are in the third pass
if (!shouldRenderWindow(&w, PMONITOR)) if (!shouldRenderWindow(&w, PMONITOR))
continue; continue;
@@ -193,6 +269,24 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
if (!w.m_bIsFloating) if (!w.m_bIsFloating)
continue; continue;
if (w.m_iWorkspaceID == SPECIAL_WORKSPACE_ID)
continue;
if (!shouldRenderWindow(&w, PMONITOR))
continue;
// render the bad boy
renderWindow(&w, PMONITOR, time, true);
}
// and then special
for (auto& w : g_pCompositor->m_lWindows) {
if (!g_pCompositor->windowValidMapped(&w) && !w.m_bFadingOut)
continue;
if (w.m_iWorkspaceID != SPECIAL_WORKSPACE_ID)
continue;
if (!shouldRenderWindow(&w, PMONITOR)) if (!shouldRenderWindow(&w, PMONITOR))
continue; continue;
@@ -470,7 +564,9 @@ void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y) {
pixman_region32_fini(&damageBox); pixman_region32_fini(&damageBox);
if (g_pConfigManager->getInt("debug:log_damage")) static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
if (*PLOGDAMAGE)
Debug::log(LOG, "Damage: Surface (extents): xy: %d, %d wh: %d, %d", damageBox.extents.x1, damageBox.extents.y1, damageBox.extents.x2 - damageBox.extents.x1, damageBox.extents.y2 - damageBox.extents.y1); Debug::log(LOG, "Damage: Surface (extents): xy: %d, %d wh: %d, %d", damageBox.extents.x1, damageBox.extents.y1, damageBox.extents.x2 - damageBox.extents.x1, damageBox.extents.y2 - damageBox.extents.y1);
} }
@@ -479,7 +575,7 @@ void CHyprRenderer::damageWindow(CWindow* pWindow) {
// damage by size & pos // damage by size & pos
// TODO TEMP: revise when added shadows/etc // TODO TEMP: revise when added shadows/etc
wlr_box damageBox = {pWindow->m_vRealPosition.vec().x, pWindow->m_vRealPosition.vec().y, pWindow->m_vRealSize.vec().x, pWindow->m_vRealSize.vec().y}; wlr_box damageBox = pWindow->getFullWindowBoundingBox();
for (auto& m : g_pCompositor->m_lMonitors) { for (auto& m : g_pCompositor->m_lMonitors) {
wlr_box fixedDamageBox = damageBox; wlr_box fixedDamageBox = damageBox;
fixedDamageBox.x -= m.vecPosition.x; fixedDamageBox.x -= m.vecPosition.x;
@@ -488,12 +584,13 @@ void CHyprRenderer::damageWindow(CWindow* pWindow) {
wlr_output_damage_add_box(m.damage, &fixedDamageBox); wlr_output_damage_add_box(m.damage, &fixedDamageBox);
} }
if (g_pConfigManager->getInt("debug:log_damage")) static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
if (*PLOGDAMAGE)
Debug::log(LOG, "Damage: Window floated (%s): xy: %d, %d wh: %d, %d", pWindow->m_szTitle.c_str(), damageBox.x, damageBox.y, damageBox.width, damageBox.height); Debug::log(LOG, "Damage: Window floated (%s): xy: %d, %d wh: %d, %d", pWindow->m_szTitle.c_str(), damageBox.x, damageBox.y, damageBox.width, damageBox.height);
} else { } else {
// damage by real size & pos + border size * 2 (JIC) // damage by real size & pos + border size * 2 (JIC)
const auto BORDERSIZE = g_pConfigManager->getInt("general:border_size"); wlr_box damageBox = pWindow->getFullWindowBoundingBox();
wlr_box damageBox = { pWindow->m_vRealPosition.vec().x - BORDERSIZE - 1, pWindow->m_vRealPosition.vec().y - BORDERSIZE - 1, pWindow->m_vRealSize.vec().x + 2 * BORDERSIZE + 2, pWindow->m_vRealSize.vec().y + 2 * BORDERSIZE + 2};
for (auto& m : g_pCompositor->m_lMonitors) { for (auto& m : g_pCompositor->m_lMonitors) {
wlr_box fixedDamageBox = damageBox; wlr_box fixedDamageBox = damageBox;
fixedDamageBox.x -= m.vecPosition.x; fixedDamageBox.x -= m.vecPosition.x;
@@ -502,7 +599,9 @@ void CHyprRenderer::damageWindow(CWindow* pWindow) {
wlr_output_damage_add_box(m.damage, &fixedDamageBox); wlr_output_damage_add_box(m.damage, &fixedDamageBox);
} }
if (g_pConfigManager->getInt("debug:log_damage")) static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
if (*PLOGDAMAGE)
Debug::log(LOG, "Damage: Window tiled (%s): xy: %d, %d wh: %d, %d", pWindow->m_szTitle.c_str(), damageBox.x, damageBox.y, damageBox.width, damageBox.height); Debug::log(LOG, "Damage: Window tiled (%s): xy: %d, %d wh: %d, %d", pWindow->m_szTitle.c_str(), damageBox.x, damageBox.y, damageBox.width, damageBox.height);
} }
} }
@@ -511,7 +610,9 @@ void CHyprRenderer::damageMonitor(SMonitor* pMonitor) {
wlr_box damageBox = {0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y}; wlr_box damageBox = {0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y};
wlr_output_damage_add_box(pMonitor->damage, &damageBox); wlr_output_damage_add_box(pMonitor->damage, &damageBox);
if (g_pConfigManager->getInt("debug:log_damage")) static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
if (*PLOGDAMAGE)
Debug::log(LOG, "Damage: Monitor %s", pMonitor->szName.c_str()); Debug::log(LOG, "Damage: Monitor %s", pMonitor->szName.c_str());
} }
@@ -522,7 +623,9 @@ void CHyprRenderer::damageBox(wlr_box* pBox) {
wlr_output_damage_add_box(m.damage, &damageBox); wlr_output_damage_add_box(m.damage, &damageBox);
} }
if (g_pConfigManager->getInt("debug:log_damage")) static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue;
if (*PLOGDAMAGE)
Debug::log(LOG, "Damage: Box: xy: %d, %d wh: %d, %d", pBox->x, pBox->y, pBox->width, pBox->height); Debug::log(LOG, "Damage: Box: xy: %d, %d wh: %d, %d", pBox->x, pBox->y, pBox->width, pBox->height);
} }
@@ -654,5 +757,40 @@ void CHyprRenderer::applyMonitorRule(SMonitor* pMonitor, SMonitorRule* pMonitorR
arrangeLayersForMonitor(pMonitor->ID); arrangeLayersForMonitor(pMonitor->ID);
// frame skip // frame skip
pMonitor->needsFrameSkip = true; pMonitor->framesToSkip = 1;
} }
void CHyprRenderer::ensureCursorRenderingMode() {
static auto *const PCURSORTIMEOUT = &g_pConfigManager->getConfigValuePtr("general:cursor_inactive_timeout")->intValue;
const auto PASSEDCURSORSECONDS = g_pInputManager->m_tmrLastCursorMovement.getSeconds();
if (*PCURSORTIMEOUT > 0) {
if (*PCURSORTIMEOUT < PASSEDCURSORSECONDS && m_bHasARenderedCursor) {
m_bHasARenderedCursor = false;
wlr_cursor_set_surface(g_pCompositor->m_sWLRCursor, nullptr, 0, 0); // hide
Debug::log(LOG, "Hiding the cursor (timeout)");
for (auto& m : g_pCompositor->m_lMonitors)
g_pHyprRenderer->damageMonitor(&m); // TODO: maybe just damage the cursor area?
} else if (*PCURSORTIMEOUT > PASSEDCURSORSECONDS && !m_bHasARenderedCursor) {
m_bHasARenderedCursor = true;
if (!m_bWindowRequestedCursorHide)
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", g_pCompositor->m_sWLRCursor);
Debug::log(LOG, "Showing the cursor (timeout)");
for (auto& m : g_pCompositor->m_lMonitors)
g_pHyprRenderer->damageMonitor(&m); // TODO: maybe just damage the cursor area?
}
} else {
m_bHasARenderedCursor = true;
}
}
bool CHyprRenderer::shouldRenderCursor() {
return m_bHasARenderedCursor;
}

View File

@@ -29,6 +29,12 @@ public:
void damageBox(const int& x, const int& y, const int& w, const int& h); void damageBox(const int& x, const int& y, const int& w, const int& h);
void damageMonitor(SMonitor*); void damageMonitor(SMonitor*);
void applyMonitorRule(SMonitor*, SMonitorRule*, bool force = false); void applyMonitorRule(SMonitor*, SMonitorRule*, bool force = false);
bool shouldRenderWindow(CWindow*, SMonitor*);
bool shouldRenderWindow(CWindow*);
void ensureCursorRenderingMode();
bool shouldRenderCursor();
bool m_bWindowRequestedCursorHide = false;
DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&); DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&);
@@ -39,6 +45,8 @@ private:
void renderLayer(SLayerSurface*, SMonitor*, timespec*); void renderLayer(SLayerSurface*, SMonitor*, timespec*);
void renderDragIcon(SMonitor*, timespec*); void renderDragIcon(SMonitor*, timespec*);
bool m_bHasARenderedCursor = true;
friend class CHyprOpenGLImpl; friend class CHyprOpenGLImpl;
}; };

View File

@@ -1,309 +1,5 @@
#pragma once #pragma once
#include <string> #include "shaders/Textures.hpp"
#include "shaders/Shadow.hpp"
inline const std::string QUADVERTSRC = R"#( #include "shaders/Border.hpp"
uniform mat3 proj;
uniform vec4 color;
attribute vec2 pos;
attribute vec2 texcoord;
varying vec4 v_color;
varying vec2 v_texcoord;
void main() {
gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);
v_color = color;
v_texcoord = texcoord;
})#";
inline const std::string QUADFRAGSRC = R"#(
precision mediump float;
varying vec4 v_color;
varying vec2 v_texcoord;
uniform vec2 topLeft;
uniform vec2 bottomRight;
uniform vec2 fullSize;
uniform float radius;
void main() {
if (radius == 0.0) {
gl_FragColor = v_color;
return;
}
vec2 pixCoord = fullSize * v_texcoord;
if (pixCoord[0] < topLeft[0]) {
// we're close left
if (pixCoord[1] < topLeft[1]) {
// top
if (distance(topLeft, pixCoord) > radius) {
discard;
return;
}
} else if (pixCoord[1] > bottomRight[1]) {
// bottom
if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord) > radius) {
discard;
return;
}
}
}
else if (pixCoord[0] > bottomRight[0]) {
// we're close right
if (pixCoord[1] < topLeft[1]) {
// top
if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord) > radius) {
discard;
return;
}
} else if (pixCoord[1] > bottomRight[1]) {
// bottom
if (distance(bottomRight, pixCoord) > radius) {
discard;
return;
}
}
}
gl_FragColor = v_color;
})#";
inline const std::string TEXVERTSRC = R"#(
uniform mat3 proj;
attribute vec2 pos;
attribute vec2 texcoord;
varying vec2 v_texcoord;
void main() {
gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);
v_texcoord = texcoord;
})#";
inline const std::string TEXFRAGSRCRGBA = R"#(
precision mediump float;
varying vec2 v_texcoord; // is in 0-1
uniform sampler2D tex;
uniform float alpha;
uniform vec2 topLeft;
uniform vec2 bottomRight;
uniform vec2 fullSize;
uniform float radius;
uniform int discardOpaque;
void main() {
vec4 pixColor = texture2D(tex, v_texcoord);
if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) {
discard;
return;
}
vec2 pixCoord = fullSize * v_texcoord;
if (pixCoord[0] < topLeft[0]) {
// we're close left
if (pixCoord[1] < topLeft[1]) {
// top
if (distance(topLeft, pixCoord) > radius) {
discard;
return;
}
} else if (pixCoord[1] > bottomRight[1]) {
// bottom
if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord) > radius) {
discard;
return;
}
}
}
else if (pixCoord[0] > bottomRight[0]) {
// we're close right
if (pixCoord[1] < topLeft[1]) {
// top
if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord) > radius) {
discard;
return;
}
} else if (pixCoord[1] > bottomRight[1]) {
// bottom
if (distance(bottomRight, pixCoord) > radius) {
discard;
return;
}
}
}
gl_FragColor = pixColor * alpha;
})#";
inline const std::string TEXFRAGSRCRGBX = R"#(
precision mediump float;
varying vec2 v_texcoord;
uniform sampler2D tex;
uniform float alpha;
uniform vec2 topLeft;
uniform vec2 bottomRight;
uniform vec2 fullSize;
uniform float radius;
uniform int discardOpaque;
void main() {
if (discardOpaque == 1 && alpha == 1.0) {
discard;
return;
}
vec2 pixCoord = fullSize * v_texcoord;
if (pixCoord[0] < topLeft[0]) {
// we're close left
if (pixCoord[1] < topLeft[1]) {
// top
if (distance(topLeft, pixCoord) > radius) {
discard;
return;
}
} else if (pixCoord[1] > bottomRight[1]) {
// bottom
if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord) > radius) {
discard;
return;
}
}
}
else if (pixCoord[0] > bottomRight[0]) {
// we're close right
if (pixCoord[1] < topLeft[1]) {
// top
if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord) > radius) {
discard;
return;
}
} else if (pixCoord[1] > bottomRight[1]) {
// bottom
if (distance(bottomRight, pixCoord) > radius) {
discard;
return;
}
}
}
gl_FragColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0) * alpha;
})#";
inline const std::string FRAGBLUR1 = R"#(
#version 100
precision mediump float;
varying mediump vec2 v_texcoord; // is in 0-1
uniform sampler2D tex;
uniform float radius;
uniform vec2 halfpixel;
void main() {
vec2 uv = v_texcoord * 2.0;
vec4 sum = texture2D(tex, uv) * 4.0;
sum += texture2D(tex, uv - halfpixel.xy * radius);
sum += texture2D(tex, uv + halfpixel.xy * radius);
sum += texture2D(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius);
sum += texture2D(tex, uv - vec2(halfpixel.x, -halfpixel.y) * radius);
gl_FragColor = sum / 8.0;
}
)#";
inline const std::string FRAGBLUR2 = R"#(
#version 100
precision mediump float;
varying mediump vec2 v_texcoord; // is in 0-1
uniform sampler2D tex;
uniform float radius;
uniform vec2 halfpixel;
void main() {
vec2 uv = v_texcoord / 2.0;
vec4 sum = texture2D(tex, uv + vec2(-halfpixel.x * 2.0, 0.0) * radius);
sum += texture2D(tex, uv + vec2(-halfpixel.x, halfpixel.y) * radius) * 2.0;
sum += texture2D(tex, uv + vec2(0.0, halfpixel.y * 2.0) * radius);
sum += texture2D(tex, uv + vec2(halfpixel.x, halfpixel.y) * radius) * 2.0;
sum += texture2D(tex, uv + vec2(halfpixel.x * 2.0, 0.0) * radius);
sum += texture2D(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius) * 2.0;
sum += texture2D(tex, uv + vec2(0.0, -halfpixel.y * 2.0) * radius);
sum += texture2D(tex, uv + vec2(-halfpixel.x, -halfpixel.y) * radius) * 2.0;
gl_FragColor = sum / 12.0;
}
)#";
inline const std::string TEXFRAGSRCEXT = R"#(
#extension GL_OES_EGL_image_external : require
precision mediump float;
varying vec2 v_texcoord;
uniform samplerExternalOES texture0;
uniform float alpha;
uniform vec2 topLeft;
uniform vec2 bottomRight;
uniform vec2 fullSize;
uniform float radius;
uniform int discardOpaque;
void main() {
vec4 pixColor = texture2D(texture0, v_texcoord);
if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) {
discard;
return;
}
vec2 pixCoord = fullSize * v_texcoord;
if (pixCoord[0] < topLeft[0]) {
// we're close left
if (pixCoord[1] < topLeft[1]) {
// top
if (distance(topLeft, pixCoord) > radius) {
discard;
return;
}
} else if (pixCoord[1] > bottomRight[1]) {
// bottom
if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord) > radius) {
discard;
return;
}
}
}
else if (pixCoord[0] > bottomRight[0]) {
// we're close right
if (pixCoord[1] < topLeft[1]) {
// top
if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord) > radius) {
discard;
return;
}
} else if (pixCoord[1] > bottomRight[1]) {
// bottom
if (distance(bottomRight, pixCoord) > radius) {
discard;
return;
}
}
}
gl_FragColor = pixColor * alpha;
})#";

View File

@@ -0,0 +1,66 @@
#include "CHyprDropShadowDecoration.hpp"
#include "../../Compositor.hpp"
CHyprDropShadowDecoration::CHyprDropShadowDecoration(CWindow* pWindow) {
m_pWindow = pWindow;
}
CHyprDropShadowDecoration::~CHyprDropShadowDecoration() {
updateWindow(m_pWindow);
}
SWindowDecorationExtents CHyprDropShadowDecoration::getWindowDecorationExtents() {
static auto *const PSHADOWS = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue;
if (*PSHADOWS != 1)
return {{}, {}};
return m_seExtents;
}
eDecorationType CHyprDropShadowDecoration::getDecorationType() {
return DECORATION_SHADOW;
}
void CHyprDropShadowDecoration::damageEntire() {
static auto *const PSHADOWS = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue;
if (*PSHADOWS != 1)
return; // disabled
wlr_box dm = {m_vLastWindowPos.x - m_seExtents.topLeft.x, m_vLastWindowPos.y - m_seExtents.topLeft.y, m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x, m_vLastWindowSize.y + m_seExtents.topLeft.y + m_seExtents.bottomRight.y};
g_pHyprRenderer->damageBox(&dm);
}
void CHyprDropShadowDecoration::updateWindow(CWindow* pWindow) {
damageEntire();
}
void CHyprDropShadowDecoration::draw(SMonitor* pMonitor, float a) {
if (!g_pCompositor->windowValidMapped(m_pWindow))
return;
static auto *const PSHADOWS = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue;
static auto *const PSHADOWSIZE = &g_pConfigManager->getConfigValuePtr("decoration:shadow_range")->intValue;
static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
if (*PSHADOWS != 1)
return; // disabled
// update the extents if needed
if (*PSHADOWSIZE != m_seExtents.topLeft.x)
m_seExtents = {{*PSHADOWSIZE + 2, *PSHADOWSIZE + 2}, {*PSHADOWSIZE + 2, *PSHADOWSIZE + 2}};
m_vLastWindowPos = m_pWindow->m_vRealPosition.vec();
m_vLastWindowSize = m_pWindow->m_vRealSize.vec();
// draw the shadow
wlr_box fullBox = {m_vLastWindowPos.x - m_seExtents.topLeft.x + 2, m_vLastWindowPos.y - m_seExtents.topLeft.y + 2, m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x - 4, m_vLastWindowSize.y + m_seExtents.topLeft.y + m_seExtents.bottomRight.y - 4};
fullBox.x -= pMonitor->vecPosition.x;
fullBox.y -= pMonitor->vecPosition.y;
g_pHyprOpenGL->renderRoundedShadow(&fullBox, *PROUNDING, *PSHADOWSIZE, a);
}

View File

@@ -0,0 +1,27 @@
#pragma once
#include "IHyprWindowDecoration.hpp"
class CHyprDropShadowDecoration : public IHyprWindowDecoration {
public:
CHyprDropShadowDecoration(CWindow*);
virtual ~CHyprDropShadowDecoration();
virtual SWindowDecorationExtents getWindowDecorationExtents();
virtual void draw(SMonitor*, float a);
virtual eDecorationType getDecorationType();
virtual void updateWindow(CWindow*);
virtual void damageEntire();
private:
SWindowDecorationExtents m_seExtents;
CWindow* m_pWindow = nullptr;
Vector2D m_vLastWindowPos;
Vector2D m_vLastWindowSize;
};

View File

@@ -68,7 +68,7 @@ void CHyprGroupBarDecoration::damageEntire() {
g_pHyprRenderer->damageBox(&dm); g_pHyprRenderer->damageBox(&dm);
} }
void CHyprGroupBarDecoration::draw(SMonitor* pMonitor) { void CHyprGroupBarDecoration::draw(SMonitor* pMonitor, float a) {
// get how many bars we will draw // get how many bars we will draw
int barsToDraw = m_dwGroupMembers.size(); int barsToDraw = m_dwGroupMembers.size();
@@ -88,6 +88,7 @@ void CHyprGroupBarDecoration::draw(SMonitor* pMonitor) {
break; break;
CColor color = m_dwGroupMembers[i] == g_pCompositor->m_pLastWindow ? CColor(g_pConfigManager->getInt("dwindle:col.group_border_active")) : CColor(g_pConfigManager->getInt("dwindle:col.group_border")); CColor color = m_dwGroupMembers[i] == g_pCompositor->m_pLastWindow ? CColor(g_pConfigManager->getInt("dwindle:col.group_border_active")) : CColor(g_pConfigManager->getInt("dwindle:col.group_border"));
color.a *= a;
g_pHyprOpenGL->renderRect(&rect, color); g_pHyprOpenGL->renderRect(&rect, color);
xoff += PAD + BARW; xoff += PAD + BARW;

View File

@@ -10,7 +10,7 @@ public:
virtual SWindowDecorationExtents getWindowDecorationExtents(); virtual SWindowDecorationExtents getWindowDecorationExtents();
virtual void draw(SMonitor*); virtual void draw(SMonitor*, float a);
virtual eDecorationType getDecorationType(); virtual eDecorationType getDecorationType();

View File

@@ -4,7 +4,8 @@
enum eDecorationType { enum eDecorationType {
DECORATION_NONE = -1, DECORATION_NONE = -1,
DECORATION_GROUPBAR DECORATION_GROUPBAR,
DECORATION_SHADOW
}; };
struct SWindowDecorationExtents { struct SWindowDecorationExtents {
@@ -21,7 +22,7 @@ public:
virtual SWindowDecorationExtents getWindowDecorationExtents() = 0; virtual SWindowDecorationExtents getWindowDecorationExtents() = 0;
virtual void draw(SMonitor*) = 0; virtual void draw(SMonitor*, float a) = 0;
virtual eDecorationType getDecorationType() = 0; virtual eDecorationType getDecorationType() = 0;

View File

@@ -0,0 +1,91 @@
#pragma once
#include <string>
// makes a stencil without corners
inline const std::string FRAGBORDER1 = R"#(
precision mediump float;
varying vec4 v_color;
varying vec2 v_texcoord;
uniform vec2 topLeft;
uniform vec2 bottomRight;
uniform vec2 fullSize;
uniform float radius;
uniform float thick;
uniform int primitiveMultisample;
float getOpacityForPixAndCorner(vec2 pix, vec2 corner) {
if (primitiveMultisample == 0) {
float dis = distance(pix + vec2(0.5, 0.5), corner);
return dis < radius && dis > radius - thick ? 1.0 : 0.0;
}
float distance1 = distance(pix + vec2(0.25, 0.25), corner);
float distance2 = distance(pix + vec2(0.75, 0.25), corner);
float distance3 = distance(pix + vec2(0.25, 0.75), corner);
float distance4 = distance(pix + vec2(0.75, 0.75), corner);
float v1 = distance1 < radius && distance1 > radius - thick ? 1.0 : 0.0;
float v2 = distance2 < radius && distance2 > radius - thick ? 1.0 : 0.0;
float v3 = distance3 < radius && distance3 > radius - thick ? 1.0 : 0.0;
float v4 = distance4 < radius && distance4 > radius - thick ? 1.0 : 0.0;
return (v1 + v2 + v3 + v4) / 4.0;
}
void main() {
vec2 pixCoord = fullSize * v_texcoord;
vec4 pixColor = v_color;
bool done = false;
// check for edges
if (pixCoord[0] < topLeft[0]) {
if (pixCoord[1] < topLeft[1]) {
// top left
pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, topLeft + vec2(1,1));
done = true;
} else if (pixCoord[1] > bottomRight[1]) {
// bottom left
pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, vec2(topLeft[0] + 1.0, bottomRight[1]));
done = true;
}
} else if (pixCoord[0] > bottomRight[0]) {
if (pixCoord[1] < topLeft[1]) {
// top right
pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, vec2(bottomRight[0], topLeft[1] + 1.0));
done = true;
} else if (pixCoord[1] > bottomRight[1]) {
// bottom right
pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, bottomRight);
done = true;
}
}
// now check for other shit
if (!done) {
// distance to all straight bb borders
float distanceT = pixCoord[1];
float distanceB = fullSize[1] - pixCoord[1];
float distanceL = pixCoord[0];
float distanceR = fullSize[0] - pixCoord[0];
// get the smallest
float smallest = min(min(distanceT, distanceB), min(distanceL, distanceR));
if (smallest > thick) {
discard; return;
}
}
if (pixColor[3] == 0.0) {
discard; return;
}
gl_FragColor = pixColor;
}
)#";

View File

@@ -0,0 +1,83 @@
#pragma once
#include <string>
inline const std::string FRAGSHADOW = R"#(
precision mediump float;
varying vec4 v_color;
varying vec2 v_texcoord;
uniform vec2 topLeft;
uniform vec2 bottomRight;
uniform vec2 fullSize;
uniform float radius;
uniform float range;
uniform float shadowPower;
uniform int ignoreWindow;
float pixAlphaRoundedDistance(float distanceToCorner) {
if (distanceToCorner > radius) {
return 0.0;
}
if (distanceToCorner > radius - range) {
return pow((range - (distanceToCorner - radius + range)) / range, shadowPower); // i think?
}
return 1.0;
}
void main() {
vec4 pixColor = v_color;
float originalAlpha = pixColor[3];
bool done = false;
vec2 pixCoord = fullSize * v_texcoord;
// ok, now we check the distance to a border.
if (pixCoord[0] < topLeft[0]) {
if (pixCoord[1] < topLeft[1]) {
// top left
pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, topLeft));
done = true;
} else if (pixCoord[1] > bottomRight[1]) {
// bottom left
pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, vec2(topLeft[0], bottomRight[1])));
done = true;
}
} else if (pixCoord[0] > bottomRight[0]) {
if (pixCoord[1] < topLeft[1]) {
// top right
pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, vec2(bottomRight[0], topLeft[1])));
done = true;
} else if (pixCoord[1] > bottomRight[1]) {
// bottom right
pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, bottomRight));
done = true;
}
}
if (!done) {
// distance to all straight bb borders
float distanceT = pixCoord[1];
float distanceB = fullSize[1] - pixCoord[1];
float distanceL = pixCoord[0];
float distanceR = fullSize[0] - pixCoord[0];
// get the smallest
float smallest = min(min(distanceT, distanceB), min(distanceL, distanceR));
if (smallest < range) {
pixColor[3] = pixColor[3] * pow((smallest / range), shadowPower);
}
}
if (pixColor[3] == 0.0 || (ignoreWindow == 1 && pixColor[3] == originalAlpha)) {
discard; return;
}
gl_FragColor = pixColor;
})#";

View File

@@ -0,0 +1,341 @@
#pragma once
#include <string>
inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVarName) -> std::string {
return R"#(
if (pixCoord[0] < topLeft[0]) {
// we're close left
if (pixCoord[1] < topLeft[1]) {
// top
if (ignoreCorners == 1) {
discard;
return;
}
float topLeftDistance = distance(topLeft, pixCoord);
if (topLeftDistance > radius - 1.0) {
if (primitiveMultisample == 0 && topLeftDistance > radius) {
discard;
return;
} else if (primitiveMultisample == 1) {
float distances = 0.0;
if (distance(topLeft, pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; }
if (distance(topLeft, pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; }
if (distance(topLeft, pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; }
if (distance(topLeft, pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; }
if (distances == 0.0) {
discard;
return;
}
distances = distances / 4.0;
gl_FragColor = )#" + colorVarName + R"#( * distances;
return;
}
}
} else if (pixCoord[1] > bottomRight[1]) {
// bottom
if (ignoreCorners == 1) {
discard;
return;
}
float topLeftDistance = distance(vec2(topLeft[0], bottomRight[1]), pixCoord);
if (topLeftDistance > radius - 1.0) {
if (primitiveMultisample == 0 && topLeftDistance > radius) {
discard;
return;
} else if (primitiveMultisample == 1) {
float distances = 0.0;
if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; }
if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; }
if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; }
if (distance(vec2(topLeft[0], bottomRight[1]), pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; }
if (distances == 0.0) {
discard;
return;
}
distances = distances / 4.0;
gl_FragColor = )#" + colorVarName + R"#( * distances;
return;
}
}
}
}
else if (pixCoord[0] > bottomRight[0]) {
// we're close right
if (pixCoord[1] < topLeft[1]) {
// top
if (ignoreCorners == 1) {
discard;
return;
}
float topLeftDistance = distance(vec2(bottomRight[0], topLeft[1]), pixCoord);
if (topLeftDistance > radius - 1.0) {
if (primitiveMultisample == 0 && topLeftDistance > radius) {
discard;
return;
} else if (primitiveMultisample == 1) {
float distances = 0.0;
if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; }
if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; }
if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; }
if (distance(vec2(bottomRight[0], topLeft[1]), pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; }
if (distances == 0.0) {
discard;
return;
}
distances = distances / 4.0;
gl_FragColor = )#" + colorVarName + R"#( * distances;
return;
}
}
} else if (pixCoord[1] > bottomRight[1]) {
// bottom
if (ignoreCorners == 1) {
discard;
return;
}
float topLeftDistance = distance(bottomRight, pixCoord);
if (topLeftDistance > radius - 1.0) {
if (primitiveMultisample == 0 && topLeftDistance > radius) {
discard;
return;
} else if (primitiveMultisample == 1) {
float distances = 0.0;
if (distance(bottomRight, pixCoord + vec2(0.25, 0.25)) < radius) { distances = distances + 1.0; }
if (distance(bottomRight, pixCoord + vec2(0.75, 0.25)) < radius) { distances = distances + 1.0; }
if (distance(bottomRight, pixCoord + vec2(0.25, 0.75)) < radius) { distances = distances + 1.0; }
if (distance(bottomRight, pixCoord + vec2(0.75, 0.75)) < radius) { distances = distances + 1.0; }
if (distances == 0.0) {
discard;
return;
}
distances = distances / 4.0;
gl_FragColor = )#" + colorVarName + R"#( * distances;
return;
}
}
}
}
)#";
};
inline const std::string QUADVERTSRC = R"#(
uniform mat3 proj;
uniform vec4 color;
attribute vec2 pos;
attribute vec2 texcoord;
varying vec4 v_color;
varying vec2 v_texcoord;
void main() {
gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);
v_color = color;
v_texcoord = texcoord;
})#";
inline const std::string QUADFRAGSRC = R"#(
precision mediump float;
varying vec4 v_color;
varying vec2 v_texcoord;
uniform vec2 topLeft;
uniform vec2 bottomRight;
uniform vec2 fullSize;
uniform float radius;
uniform int primitiveMultisample;
uniform int ignoreCorners;
void main() {
if (radius == 0.0) {
gl_FragColor = v_color;
return;
}
vec2 pixCoord = fullSize * v_texcoord;
)#" + ROUNDED_SHADER_FUNC("v_color") + R"#(
gl_FragColor = v_color;
})#";
inline const std::string TEXVERTSRC = R"#(
uniform mat3 proj;
attribute vec2 pos;
attribute vec2 texcoord;
varying vec2 v_texcoord;
void main() {
gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);
v_texcoord = texcoord;
})#";
inline const std::string TEXFRAGSRCRGBA = R"#(
precision mediump float;
varying vec2 v_texcoord; // is in 0-1
uniform sampler2D tex;
uniform float alpha;
uniform vec2 topLeft;
uniform vec2 bottomRight;
uniform vec2 fullSize;
uniform float radius;
uniform int discardOpaque;
uniform int primitiveMultisample;
uniform int ignoreCorners;
void main() {
vec4 pixColor = texture2D(tex, v_texcoord);
if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) {
discard;
return;
}
vec2 pixCoord = fullSize * v_texcoord;
)#" + ROUNDED_SHADER_FUNC("pixColor") +
R"#(
gl_FragColor = pixColor * alpha;
})#";
inline const std::string TEXFRAGSRCRGBX = R"#(
precision mediump float;
varying vec2 v_texcoord;
uniform sampler2D tex;
uniform float alpha;
uniform vec2 topLeft;
uniform vec2 bottomRight;
uniform vec2 fullSize;
uniform float radius;
uniform int discardOpaque;
uniform int primitiveMultisample;
uniform int ignoreCorners;
void main() {
if (discardOpaque == 1 && alpha == 1.0) {
discard;
return;
}
vec4 pixColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0);
vec2 pixCoord = fullSize * v_texcoord;
)#" + ROUNDED_SHADER_FUNC("pixColor") + R"#(
gl_FragColor = pixColor * alpha;
})#";
inline const std::string FRAGBLUR1 = R"#(
#version 100
precision mediump float;
varying mediump vec2 v_texcoord; // is in 0-1
uniform sampler2D tex;
uniform float radius;
uniform vec2 halfpixel;
void main() {
vec2 uv = v_texcoord * 2.0;
vec4 sum = texture2D(tex, uv) * 4.0;
sum += texture2D(tex, uv - halfpixel.xy * radius);
sum += texture2D(tex, uv + halfpixel.xy * radius);
sum += texture2D(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius);
sum += texture2D(tex, uv - vec2(halfpixel.x, -halfpixel.y) * radius);
gl_FragColor = sum / 8.0;
}
)#";
inline const std::string FRAGBLUR2 = R"#(
#version 100
precision mediump float;
varying mediump vec2 v_texcoord; // is in 0-1
uniform sampler2D tex;
uniform float radius;
uniform vec2 halfpixel;
void main() {
vec2 uv = v_texcoord / 2.0;
vec4 sum = texture2D(tex, uv + vec2(-halfpixel.x * 2.0, 0.0) * radius);
sum += texture2D(tex, uv + vec2(-halfpixel.x, halfpixel.y) * radius) * 2.0;
sum += texture2D(tex, uv + vec2(0.0, halfpixel.y * 2.0) * radius);
sum += texture2D(tex, uv + vec2(halfpixel.x, halfpixel.y) * radius) * 2.0;
sum += texture2D(tex, uv + vec2(halfpixel.x * 2.0, 0.0) * radius);
sum += texture2D(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius) * 2.0;
sum += texture2D(tex, uv + vec2(0.0, -halfpixel.y * 2.0) * radius);
sum += texture2D(tex, uv + vec2(-halfpixel.x, -halfpixel.y) * radius) * 2.0;
gl_FragColor = sum / 12.0;
}
)#";
inline const std::string TEXFRAGSRCEXT = R"#(
#extension GL_OES_EGL_image_external : require
precision mediump float;
varying vec2 v_texcoord;
uniform samplerExternalOES texture0;
uniform float alpha;
uniform vec2 topLeft;
uniform vec2 bottomRight;
uniform vec2 fullSize;
uniform float radius;
uniform int discardOpaque;
uniform int primitiveMultisample;
uniform int ignoreCorners;
void main() {
vec4 pixColor = texture2D(texture0, v_texcoord);
if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) {
discard;
return;
}
vec2 pixCoord = fullSize * v_texcoord;
)#" + ROUNDED_SHADER_FUNC("pixColor") + R"#(
gl_FragColor = pixColor * alpha;
})#";

View File

@@ -2,7 +2,7 @@
#include "../includes.hpp" #include "../includes.hpp"
#include "../helpers/MiscFunctions.hpp" #include "../helpers/MiscFunctions.hpp"
#include "../../ext-workspace-unstable-v1-protocol.h" #include "ext-workspace-unstable-v1-protocol.h"
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>

1
subprojects/wlroots Submodule

Submodule subprojects/wlroots added at b89ed9015c