aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorVaxry <[email protected]>2023-04-09 00:46:13 +0100
committerGitHub <[email protected]>2023-04-09 00:46:13 +0100
commitdfc729c045a94b446fa467a511726258dcbb9040 (patch)
treec5c633d27b20e8fc31f779df3ef7c73fe92356f4
parentb9f8552b11db5babe80b9c62c31766a847f7b95d (diff)
parente4e653ada6fc729efad3f6a0d49cf72b94c43b6c (diff)
downloadHyprland-dfc729c045a94b446fa467a511726258dcbb9040.tar.gz
Hyprland-dfc729c045a94b446fa467a511726258dcbb9040.zip
Merge branch 'main' into global-shortcuts
-rw-r--r--CMakeLists.txt1
-rw-r--r--docs/Hyprland.12
-rw-r--r--docs/ISSUE_GUIDELINES.md18
-rw-r--r--docs/hyprctl.12
-rw-r--r--example/examplePlugin/Makefile2
-rw-r--r--example/examplePlugin/main.cpp6
-rw-r--r--flake.lock12
-rw-r--r--meson.build8
-rw-r--r--meson_options.txt1
-rw-r--r--nix/default.nix5
-rw-r--r--nix/xwayland-hidpi.patch191
-rw-r--r--props.json2
-rw-r--r--protocols/meson.build1
-rw-r--r--src/Compositor.cpp83
-rw-r--r--src/Window.cpp13
-rw-r--r--src/Window.hpp28
-rw-r--r--src/config/ConfigManager.cpp36
-rw-r--r--src/config/ConfigManager.hpp7
-rw-r--r--src/debug/CrashReporter.cpp26
-rw-r--r--src/debug/HyprCtl.cpp25
-rw-r--r--src/events/Events.hpp2
-rw-r--r--src/events/Layers.cpp2
-rw-r--r--src/events/Misc.cpp16
-rw-r--r--src/events/Monitors.cpp15
-rw-r--r--src/events/Popups.cpp3
-rw-r--r--src/events/Windows.cpp17
-rw-r--r--src/helpers/MiscFunctions.cpp6
-rw-r--r--src/helpers/Monitor.cpp32
-rw-r--r--src/helpers/Monitor.hpp11
-rw-r--r--src/helpers/SubsurfaceTree.cpp6
-rw-r--r--src/layout/IHyprLayout.cpp5
-rw-r--r--src/main.cpp71
-rw-r--r--src/managers/EventManager.cpp26
-rw-r--r--src/managers/KeybindManager.cpp13
-rw-r--r--src/managers/ProtocolManager.cpp1
-rw-r--r--src/managers/ProtocolManager.hpp2
-rw-r--r--src/managers/input/InputManager.cpp100
-rw-r--r--src/managers/input/InputManager.hpp19
-rw-r--r--src/managers/input/Swipe.cpp22
-rw-r--r--src/managers/input/Touch.cpp4
-rw-r--r--src/plugins/PluginAPI.cpp79
-rw-r--r--src/plugins/PluginAPI.hpp19
-rw-r--r--src/protocols/Screencopy.cpp414
-rw-r--r--src/protocols/Screencopy.hpp71
-rw-r--r--src/protocols/TextInputV1.cpp1
-rw-r--r--src/protocols/ToplevelExport.cpp46
-rw-r--r--src/protocols/ToplevelExportWlrFuncs.hpp17
-rw-r--r--src/render/OpenGL.cpp32
-rw-r--r--src/render/OpenGL.hpp4
-rw-r--r--src/render/Renderer.cpp81
-rw-r--r--src/render/Renderer.hpp13
-rw-r--r--src/render/Shader.hpp1
-rw-r--r--src/render/shaders/Textures.hpp67
m---------subprojects/wlroots0
54 files changed, 1342 insertions, 345 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3038d7ef..71a1437b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -145,5 +145,6 @@ target_link_libraries(Hyprland
${CMAKE_SOURCE_DIR}/hyprland-global-shortcuts-v1-protocol.o
${CMAKE_SOURCE_DIR}/fractional-scale-v1-protocol.o
${CMAKE_SOURCE_DIR}/text-input-unstable-v1-protocol.o
+ ${CMAKE_SOURCE_DIR}/wlr-screencopy-unstable-v1-protocol.o
${CMAKE_SOURCE_DIR}/subprojects/udis86/build/libudis86/liblibudis86.a
)
diff --git a/docs/Hyprland.1 b/docs/Hyprland.1
index 78a86b49..375a3a1a 100644
--- a/docs/Hyprland.1
+++ b/docs/Hyprland.1
@@ -1,6 +1,6 @@
.\" Automatically generated by Pandoc 2.9.2.1
.\"
-.TH "Hyprland" "1" "09 Mar 2023" "" "Hyprland User Manual"
+.TH "Hyprland" "1" "03 Apr 2023" "" "Hyprland User Manual"
.hy
.SH NAME
.PP
diff --git a/docs/ISSUE_GUIDELINES.md b/docs/ISSUE_GUIDELINES.md
index 05adbe89..57c5e735 100644
--- a/docs/ISSUE_GUIDELINES.md
+++ b/docs/ISSUE_GUIDELINES.md
@@ -45,6 +45,13 @@ 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 Crash Report (v0.22.0beta and up)
+
+If you have `$XDG_CACHE_HOME` set, the crash report directory is `$XDG_CACHE_HOME/hyprland`. If not, it's `~/.hyprland`
+
+Go to the crash report directory and you should find a file named `hyprlandCrashReport[XXXX].txt` where `[XXXX]` is the PID of the process that crashed.
+
+Attach that file to your issue.
## Obtaining the Hyprland coredump (v0.21.0beta and below)
If you are on systemd, you can simply use
```
@@ -58,13 +65,6 @@ coredumpctl info [PID]
```
where `[PID]` is the PID you remembered.
-## Obtaining the Hyprland Crash Report (v0.22.0beta and up)
-Go to `~/.hyprland/` and you should find a file named `hyprlandCrashReport[XXXX].txt` where `[XXXX]` is the PID of the process that crashed.
-
-If you do not see it, make sure you have "show hidden files" enabled in your file manager.
-
-Attach that file to your issue.
-
## Obtaining the debug Hyprland coredump
A debug coredump provides more information for debugging and may speed up the process of fixing the bug.
@@ -74,9 +74,7 @@ Make sure you're on latest git. Run `git pull --recurse-submodules` to sync ever
> Note: The config file used will be `hyprlandd.conf` instead of `hyprland.conf`
2. `cd ~`
-3. For your own convenience, launch Hyprland from a tty with the envvar `ASAN_OPTIONS="log_path=asan.log"`:
- - If using a wrapper, add `export ASAN_OPTIONS="log_path=asan.log"` in a separate line before the `exec Hyprland` line.
- - If launching straight from the tty, execute `ASAN_OPTIONS="log_path=asan.log" ~/path/to/Hyprland`
+3. For your own convenience, launch Hyprland from a tty with the envvar `ASAN_OPTIONS="log_path=asan.log" ~/path/to/Hyprland`
4. Reproduce the crash. Hyprland should instantly close.
5. Check out your `~` and find a file called `asan.log.XXXXX` where `XXXXX` will be a number corresponding to the PID of the Hyprland instance that crashed.
6. That is your coredump. Attach it to your issue.
diff --git a/docs/hyprctl.1 b/docs/hyprctl.1
index b76941be..27a9141a 100644
--- a/docs/hyprctl.1
+++ b/docs/hyprctl.1
@@ -1,6 +1,6 @@
.\" Automatically generated by Pandoc 2.9.2.1
.\"
-.TH "hyprctl" "1" "09 Mar 2023" "" "hyprctl User Manual"
+.TH "hyprctl" "1" "03 Apr 2023" "" "hyprctl User Manual"
.hy
.SH NAME
.PP
diff --git a/example/examplePlugin/Makefile b/example/examplePlugin/Makefile
index 3ccc2930..ea5f3e6d 100644
--- a/example/examplePlugin/Makefile
+++ b/example/examplePlugin/Makefile
@@ -3,6 +3,6 @@
# and that you have ran `make protocols` in the hl dir.
all:
- g++ -shared -fPIC --no-gnu-unique main.cpp customLayout.cpp customDecoration.cpp -o examplePlugin.so -g -I "/usr/include/pixman-1" -I "/usr/include/libdrm" -I "${HYPRLAND_HEADERS}" -std=c++23
+ g++ -shared -fPIC --no-gnu-unique main.cpp customLayout.cpp customDecoration.cpp -o examplePlugin.so -g -I "/usr/include/pixman-1" -I "/usr/include/libdrm" -I "${HYPRLAND_HEADERS}" -I "${HYPRLAND_HEADERS}/subprojects/wlroots/include" -I "${HYPRLAND_HEADERS}/subprojects/wlroots/include" -I "${HYPRLAND_HEADERS}/subprojects/wlroots/build/include" -std=c++23
clean:
rm ./examplePlugin.so
diff --git a/example/examplePlugin/main.cpp b/example/examplePlugin/main.cpp
index 6007a58b..ef829ae0 100644
--- a/example/examplePlugin/main.cpp
+++ b/example/examplePlugin/main.cpp
@@ -73,9 +73,9 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
g_pFocusHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CCompositor::focusWindow, (void*)&hkFocusWindow);
// Hook a public non-member
g_pMotionHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&wlr_seat_pointer_notify_motion, (void*)&hkNotifyMotion);
- // Hook a private member (!WARNING: the signature may differ in clang. This one is for gcc ONLY.)
- g_pMouseDownHook = HyprlandAPI::createFunctionHook(
- PHANDLE, HyprlandAPI::getFunctionAddressFromSignature(PHANDLE, "_ZN13CInputManager22processMouseDownNormalEP24wlr_pointer_button_event"), (void*)&hkProcessMouseDownNormal);
+ // Hook a private member
+ static const auto METHODS = HyprlandAPI::findFunctionsByName(PHANDLE, "processMouseDownNormal");
+ g_pMouseDownHook = HyprlandAPI::createFunctionHook(PHANDLE, METHODS[0].address, (void*)&hkProcessMouseDownNormal);
// fancy notifications
HyprlandAPI::addNotificationV2(PHANDLE, {{"text", "Example hint"}, {"time", (uint64_t)10000}, {"color", CColor(0.2, 0.2, 0.9, 1.0)}, {"icon", ICON_HINT}});
diff --git a/flake.lock b/flake.lock
index c77ef9a5..396c1da3 100644
--- a/flake.lock
+++ b/flake.lock
@@ -22,11 +22,11 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1679172431,
- "narHash": "sha256-XEh5gIt5otaUbEAPUY5DILUTyWe1goAyeqQtmwaFPyI=",
+ "lastModified": 1680669251,
+ "narHash": "sha256-AVNE+0u4HlI3v96KCXE9risH7NKqj0QDLLfSckYXIbA=",
"owner": "NixOS",
"repo": "nixpkgs",
- "rev": "1603d11595a232205f03d46e635d919d1e1ec5b9",
+ "rev": "9c8ff8b426a8b07b9e0a131ac3218740dc85ba1e",
"type": "github"
},
"original": {
@@ -48,11 +48,11 @@
"flake": false,
"locked": {
"host": "gitlab.freedesktop.org",
- "lastModified": 1679340088,
- "narHash": "sha256-/1KiYoBivDj8HC/eVK2Tr2WYkVdKJxq2Lb0tQs0qqJo=",
+ "lastModified": 1680810405,
+ "narHash": "sha256-LmI/4Yp/pOOoI4RxLRx9I90NBsiqdRLVOfbATKlgpkg=",
"owner": "wlroots",
"repo": "wlroots",
- "rev": "1d64e12391a638201c679e71d4e22bb45e5faa8e",
+ "rev": "7abda952d0000b72d240fe1d41457b9288f0b6e5",
"type": "gitlab"
},
"original": {
diff --git a/meson.build b/meson.build
index d9d06561..ce371ec3 100644
--- a/meson.build
+++ b/meson.build
@@ -59,14 +59,18 @@ endif
backtrace_dep = cpp_compiler.find_library('execinfo', required: false)
systemd_dep = dependency('libsystemd', required: get_option('systemd'))
-if get_option('systemd').enabled()
+if get_option('systemd').enabled()
if systemd_dep.found()
add_project_arguments('-DUSES_SYSTEMD', language: 'cpp')
- else
+ else
error('Cannot enable systemd in Hyprland: libsystemd was not found')
endif
endif
+if get_option('legacy_renderer').enabled()
+ add_project_arguments('-DLEGACY_RENDERER', language: 'cpp')
+endif
+
if get_option('buildtype') == 'debug'
add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp')
endif
diff --git a/meson_options.txt b/meson_options.txt
index e8e2b062..16a34a54 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -1,2 +1,3 @@
option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications')
option('systemd', type: 'feature', value: 'auto', description: 'Enable systemd integration')
+option('legacy_renderer', type: 'feature', value: 'disabled', description: 'Enable legacy renderer')
diff --git a/nix/default.nix b/nix/default.nix
index a240f803..9924dbb3 100644
--- a/nix/default.nix
+++ b/nix/default.nix
@@ -89,8 +89,9 @@ in
else "release";
mesonFlags = builtins.concatLists [
- (lib.optional (!enableXWayland) "-Dxwayland=disabled")
- (lib.optional legacyRenderer "-DLEGACY_RENDERER:STRING=true")
+ ["-Dauto_features=disabled"]
+ (lib.optional enableXWayland "-Dxwayland=enabled")
+ (lib.optional legacyRenderer "-Dlegacy_renderer=enabled")
(lib.optional withSystemd "-Dsystemd=enabled")
];
diff --git a/nix/xwayland-hidpi.patch b/nix/xwayland-hidpi.patch
index 85f56e02..a652ec85 100644
--- a/nix/xwayland-hidpi.patch
+++ b/nix/xwayland-hidpi.patch
@@ -1,8 +1,8 @@
diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c
-index c4457cc2a61b2103b47f996b51dbbe9eb87bd715..4a33e1f33e73c35c1691564ef4852e7501b02245 100644
+index e3c1aaa50..eba29b5ba 100644
--- a/hw/xwayland/xwayland-cursor.c
+++ b/hw/xwayland/xwayland-cursor.c
-@@ -171,6 +171,8 @@ xwl_cursor_attach_pixmap(struct xwl_seat *xwl_seat,
+@@ -164,6 +164,8 @@ xwl_cursor_attach_pixmap(struct xwl_seat *xwl_seat,
}
wl_surface_attach(xwl_cursor->surface, buffer, 0, 0);
@@ -11,7 +11,7 @@ index c4457cc2a61b2103b47f996b51dbbe9eb87bd715..4a33e1f33e73c35c1691564ef4852e75
xwl_surface_damage(xwl_seat->xwl_screen, xwl_cursor->surface, 0, 0,
xwl_seat->x_cursor->bits->width,
xwl_seat->x_cursor->bits->height);
-@@ -190,6 +192,7 @@ xwl_cursor_attach_pixmap(struct xwl_seat *xwl_seat,
+@@ -195,6 +197,7 @@ xwl_cursor_clear_frame_cb(struct xwl_cursor *xwl_cursor)
void
xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
{
@@ -19,7 +19,7 @@ index c4457cc2a61b2103b47f996b51dbbe9eb87bd715..4a33e1f33e73c35c1691564ef4852e75
struct xwl_cursor *xwl_cursor = &xwl_seat->cursor;
PixmapPtr pixmap;
CursorPtr cursor;
-@@ -220,8 +223,8 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
+@@ -225,8 +228,8 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat)
wl_pointer_set_cursor(xwl_seat->wl_pointer,
xwl_seat->pointer_enter_serial,
xwl_cursor->surface,
@@ -30,7 +30,7 @@ index c4457cc2a61b2103b47f996b51dbbe9eb87bd715..4a33e1f33e73c35c1691564ef4852e75
xwl_cursor_attach_pixmap(xwl_seat, xwl_cursor, pixmap);
}
-@@ -230,6 +233,7 @@ void
+@@ -235,6 +238,7 @@ void
xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool)
{
struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
@@ -38,24 +38,23 @@ index c4457cc2a61b2103b47f996b51dbbe9eb87bd715..4a33e1f33e73c35c1691564ef4852e75
struct xwl_cursor *xwl_cursor = &xwl_tablet_tool->cursor;
PixmapPtr pixmap;
CursorPtr cursor;
-@@ -258,9 +262,9 @@ xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool)
+@@ -263,8 +267,9 @@ xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool)
zwp_tablet_tool_v2_set_cursor(xwl_tablet_tool->tool,
xwl_tablet_tool->proximity_in_serial,
xwl_cursor->surface,
- xwl_seat->x_cursor->bits->xhot,
- xwl_seat->x_cursor->bits->yhot);
--
+ xwl_scale_to(xwl_screen, xwl_seat->x_cursor->bits->xhot),
+ xwl_scale_to(xwl_screen, xwl_seat->x_cursor->bits->yhot));
+ wl_surface_set_buffer_scale(xwl_cursor->surface, xwl_screen->global_output_scale);
+
xwl_cursor_attach_pixmap(xwl_seat, xwl_cursor, pixmap);
}
-
diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c
-index 26b3630c73b62514fe3ba7824371f79868e953f3..55cd8d466a55db03948abe93ffa03bf129b5e17a 100644
+index 6e0600e4e..4a22ebff0 100644
--- a/hw/xwayland/xwayland-input.c
+++ b/hw/xwayland/xwayland-input.c
-@@ -412,8 +412,8 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
+@@ -507,8 +507,8 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
DeviceIntPtr dev = get_pointer_device(xwl_seat);
DeviceIntPtr master;
int i;
@@ -66,7 +65,7 @@ index 26b3630c73b62514fe3ba7824371f79868e953f3..55cd8d466a55db03948abe93ffa03bf1
int dx, dy;
ScreenPtr pScreen = xwl_seat->xwl_screen->screen;
ValuatorMask mask;
-@@ -592,13 +592,14 @@ pointer_handle_motion(void *data, struct wl_pointer *pointer,
+@@ -731,13 +731,14 @@ pointer_handle_motion(void *data, struct wl_pointer *pointer,
uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
{
struct xwl_seat *xwl_seat = data;
@@ -83,17 +82,7 @@ index 26b3630c73b62514fe3ba7824371f79868e953f3..55cd8d466a55db03948abe93ffa03bf1
if (wl_proxy_get_version((struct wl_proxy *) xwl_seat->wl_pointer) < 5)
dispatch_pointer_motion_event(xwl_seat);
-@@ -672,7 +673,8 @@ pointer_handle_axis(void *data, struct wl_pointer *pointer,
- xorg_list_del(&pending->l);
- free(pending);
- } else {
-- valuator_mask_set_double(&mask, index, wl_fixed_to_double(value) / divisor);
-+ double scaled_value = wl_fixed_to_double(value);
-+ valuator_mask_set_double(&mask, index, scaled_value / divisor);
- }
-
- QueuePointerEvents(get_pointer_device(xwl_seat),
-@@ -740,12 +742,13 @@ relative_pointer_handle_relative_motion(void *data,
+@@ -887,12 +888,13 @@ relative_pointer_handle_relative_motion(void *data,
wl_fixed_t dy_unaccelf)
{
struct xwl_seat *xwl_seat = data;
@@ -111,7 +100,7 @@ index 26b3630c73b62514fe3ba7824371f79868e953f3..55cd8d466a55db03948abe93ffa03bf1
if (!xwl_seat->focus_window)
return;
-@@ -1057,8 +1060,8 @@ touch_handle_down(void *data, struct wl_touch *wl_touch,
+@@ -1382,8 +1384,8 @@ touch_handle_down(void *data, struct wl_touch *wl_touch,
xwl_touch->window = wl_surface_get_user_data(surface);
xwl_touch->id = id;
@@ -122,18 +111,18 @@ index 26b3630c73b62514fe3ba7824371f79868e953f3..55cd8d466a55db03948abe93ffa03bf1
xorg_list_add(&xwl_touch->link_touch, &xwl_seat->touches);
xwl_touch_send_event(xwl_touch, xwl_seat, XI_TouchBegin);
-@@ -1094,8 +1097,8 @@ touch_handle_motion(void *data, struct wl_touch *wl_touch,
+@@ -1419,8 +1421,8 @@ touch_handle_motion(void *data, struct wl_touch *wl_touch,
if (!xwl_touch)
return;
- xwl_touch->x = wl_fixed_to_int(sx_w);
- xwl_touch->y = wl_fixed_to_int(sy_w);
-+ xwl_touch->x = wl_fixed_to_int(sx_w) * xwl_seat->xwl_screen->global_output_scale;;
-+ xwl_touch->y = wl_fixed_to_int(sy_w) * xwl_seat->xwl_screen->global_output_scale;;
++ xwl_touch->x = wl_fixed_to_int(sx_w) * xwl_seat->xwl_screen->global_output_scale;
++ xwl_touch->y = wl_fixed_to_int(sy_w) * xwl_seat->xwl_screen->global_output_scale;
xwl_touch_send_event(xwl_touch, xwl_seat, XI_TouchUpdate);
}
-@@ -1726,8 +1729,8 @@ tablet_tool_motion(void *data, struct zwp_tablet_tool_v2 *tool,
+@@ -2110,8 +2112,8 @@ tablet_tool_motion(void *data, struct zwp_tablet_tool_v2 *tool,
struct xwl_tablet_tool *xwl_tablet_tool = data;
struct xwl_seat *xwl_seat = xwl_tablet_tool->seat;
int32_t dx, dy;
@@ -144,7 +133,7 @@ index 26b3630c73b62514fe3ba7824371f79868e953f3..55cd8d466a55db03948abe93ffa03bf1
if (!xwl_seat->tablet_focus_window)
return;
-@@ -2714,6 +2717,7 @@ xwl_pointer_warp_emulator_set_fake_pos(struct xwl_pointer_warp_emulator *warp_em
+@@ -3152,6 +3154,7 @@ xwl_pointer_warp_emulator_set_fake_pos(struct xwl_pointer_warp_emulator *warp_em
int x,
int y)
{
@@ -152,7 +141,7 @@ index 26b3630c73b62514fe3ba7824371f79868e953f3..55cd8d466a55db03948abe93ffa03bf1
struct zwp_locked_pointer_v1 *locked_pointer =
warp_emulator->locked_pointer;
WindowPtr window;
-@@ -2725,6 +2729,7 @@ xwl_pointer_warp_emulator_set_fake_pos(struct xwl_pointer_warp_emulator *warp_em
+@@ -3163,6 +3166,7 @@ xwl_pointer_warp_emulator_set_fake_pos(struct xwl_pointer_warp_emulator *warp_em
if (!warp_emulator->xwl_seat->focus_window)
return;
@@ -160,7 +149,7 @@ index 26b3630c73b62514fe3ba7824371f79868e953f3..55cd8d466a55db03948abe93ffa03bf1
window = warp_emulator->xwl_seat->focus_window->window;
if (x >= window->drawable.x ||
y >= window->drawable.y ||
-@@ -2733,8 +2738,8 @@ xwl_pointer_warp_emulator_set_fake_pos(struct xwl_pointer_warp_emulator *warp_em
+@@ -3171,8 +3175,8 @@ xwl_pointer_warp_emulator_set_fake_pos(struct xwl_pointer_warp_emulator *warp_em
sx = x - window->drawable.x;
sy = y - window->drawable.y;
zwp_locked_pointer_v1_set_cursor_position_hint(locked_pointer,
@@ -172,21 +161,21 @@ index 26b3630c73b62514fe3ba7824371f79868e953f3..55cd8d466a55db03948abe93ffa03bf1
}
}
diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c
-index ef705bc01bf8c2d2f170cda9ba21ed8293f50559..b8f6cd51bd240ed5e16271eb4749db18868bea7b 100644
+index 661e1828d..6c60aba34 100644
--- a/hw/xwayland/xwayland-output.c
+++ b/hw/xwayland/xwayland-output.c
-@@ -191,6 +191,9 @@ update_screen_size(struct xwl_output *xwl_output, int width, int height)
+@@ -186,6 +186,9 @@ update_backing_pixmaps(struct xwl_screen *xwl_screen, int width, int height)
+ static void
+ update_screen_size(struct xwl_screen *xwl_screen, int width, int height)
{
- struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
-
+ width *= xwl_screen->global_output_scale;
+ height *= xwl_screen->global_output_scale;
+
- if (xwl_screen->root_clip_mode == ROOT_CLIP_FULL)
- SetRootClip(xwl_screen->screen, ROOT_CLIP_NONE);
+ xwl_screen->width = width;
+ xwl_screen->height = height;
-@@ -497,14 +500,15 @@ xwl_output_set_emulated_mode(struct xwl_output *xwl_output, ClientPtr client,
- xwl_output_set_randr_emu_props(xwl_output->xwl_screen, client);
+@@ -597,14 +600,15 @@ xwl_output_set_emulated_mode(struct xwl_output *xwl_output, ClientPtr client,
+ new_emulated_height);
}
-static void
@@ -203,20 +192,20 @@ index ef705bc01bf8c2d2f170cda9ba21ed8293f50559..b8f6cd51bd240ed5e16271eb4749db18
/* Clear out the "done" received flags */
xwl_output->wl_output_done = FALSE;
-@@ -523,10 +527,10 @@ apply_output_change(struct xwl_output *xwl_output)
+@@ -623,10 +627,10 @@ apply_output_change(struct xwl_output *xwl_output)
}
-
- /* Build a fresh modes array using the current refresh rate */
-- randr_modes = output_get_rr_modes(xwl_output, mode_width, mode_height, &count);
-+ randr_modes = output_get_rr_modes(xwl_output, mode_width * scale, mode_height * scale, &count);
- RROutputSetModes(xwl_output->randr_output, randr_modes, count, 1);
- RRCrtcNotify(xwl_output->randr_crtc, randr_modes[0],
-- xwl_output->x, xwl_output->y,
-+ xwl_output->x * scale, xwl_output->y * scale,
- xwl_output->rotation, NULL, 1, &xwl_output->randr_output);
- /* RROutputSetModes takes ownership of the passed in modes, so we only
- * have to free the pointer array.
-@@ -567,7 +571,7 @@ output_handle_done(void *data, struct wl_output *wl_output)
+ if (xwl_output->randr_output) {
+ /* Build a fresh modes array using the current refresh rate */
+- randr_modes = output_get_rr_modes(xwl_output, mode_width, mode_height, &count);
++ randr_modes = output_get_rr_modes(xwl_output, mode_width * scale, mode_height * scale, &count);
+ RROutputSetModes(xwl_output->randr_output, randr_modes, count, 1);
+ RRCrtcNotify(xwl_output->randr_crtc, randr_modes[0],
+- xwl_output->x, xwl_output->y,
++ xwl_output->x * scale, xwl_output->y * scale,
+ xwl_output->rotation, NULL, 1, &xwl_output->randr_output);
+ /* RROutputSetModes takes ownership of the passed in modes, so we only
+ * have to free the pointer array.
+@@ -686,7 +690,7 @@ output_handle_done(void *data, struct wl_output *wl_output)
*/
if (xwl_output->xdg_output_done || !xwl_output->xdg_output ||
zxdg_output_v1_get_version(xwl_output->xdg_output) >= 3)
@@ -225,7 +214,7 @@ index ef705bc01bf8c2d2f170cda9ba21ed8293f50559..b8f6cd51bd240ed5e16271eb4749db18
}
static void
-@@ -610,7 +614,7 @@ xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output)
+@@ -746,7 +750,7 @@ xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output)
xwl_output->xdg_output_done = TRUE;
if (xwl_output->wl_output_done &&
zxdg_output_v1_get_version(xdg_output) < 3)
@@ -234,17 +223,17 @@ index ef705bc01bf8c2d2f170cda9ba21ed8293f50559..b8f6cd51bd240ed5e16271eb4749db18
}
static void
-@@ -678,6 +682,8 @@ xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id)
- RROutputSetConnection(xwl_output->randr_output, RR_Connected);
- RRTellChanged(xwl_screen->screen);
-
-+ xwl_output->scale = 1;
+@@ -857,6 +861,8 @@ xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id,
+ RRCrtcGammaSetSize(xwl_output->randr_crtc, 256);
+ RROutputSetCrtcs(xwl_output->randr_output, &xwl_output->randr_crtc, 1);
+ RROutputSetConnection(xwl_output->randr_output, RR_Connected);
+
++ xwl_output->scale = 1;
+ }
/* We want the output to be in the list as soon as created so we can
* use it when binding to the xdg-output protocol...
- */
diff --git a/hw/xwayland/xwayland-output.h b/hw/xwayland/xwayland-output.h
-index 02b9831083e82a33d85d4404e39d00f06f6c56fd..ec089757f44178dcd7f9c48907f790ce1b2a2729 100644
+index a95288e4f..46d1ead2a 100644
--- a/hw/xwayland/xwayland-output.h
+++ b/hw/xwayland/xwayland-output.h
@@ -53,7 +53,7 @@ struct xwl_output {
@@ -256,7 +245,7 @@ index 02b9831083e82a33d85d4404e39d00f06f6c56fd..ec089757f44178dcd7f9c48907f790ce
Rotation rotation;
Bool wl_output_done;
Bool xdg_output_done;
-@@ -100,6 +100,8 @@ void xwl_output_set_emulated_mode(struct xwl_output *xwl_output,
+@@ -102,6 +102,8 @@ void xwl_output_set_emulated_mode(struct xwl_output *xwl_output,
void xwl_output_set_window_randr_emu_props(struct xwl_screen *xwl_screen,
WindowPtr window);
@@ -266,20 +255,20 @@ index 02b9831083e82a33d85d4404e39d00f06f6c56fd..ec089757f44178dcd7f9c48907f790ce
#endif /* XWAYLAND_OUTPUT_H */
diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c
-index c9cf8c2f569a319034e0789e7587414e50237065..5be0c208ca46b1a53a136885fdc8ab44251fe7ff 100644
+index 189e7cfd6..555434031 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
-@@ -680,6 +680,8 @@ xwl_present_flip(WindowPtr present_window,
+@@ -764,6 +764,8 @@ xwl_present_flip(WindowPtr present_window,
/* We can flip directly to the main surface (full screen window without clips) */
wl_surface_attach(xwl_window->surface, buffer, 0, 0);
-+ wl_surface_set_buffer_scale(xwl_window->surface,
-+ xwl_window->xwl_screen->global_output_scale);
++ wl_surface_set_buffer_scale(xwl_window->surface,
++ xwl_window->xwl_screen->global_output_scale);
- if (!xwl_window->frame_callback)
- xwl_window_create_frame_callback(xwl_window);
+ if (xorg_list_is_empty(&xwl_present_window->frame_callback_list)) {
+ xorg_list_add(&xwl_present_window->frame_callback_list,
diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c
-index bb18e5c94fbc7134c801e4e1979e8184079d352e..4ec2de7d123dd36315df07a1e95b1f417925f0f8 100644
+index 46ab4fed7..b2d7022e6 100644
--- a/hw/xwayland/xwayland-screen.c
+++ b/hw/xwayland/xwayland-screen.c
@@ -51,6 +51,7 @@
@@ -290,7 +279,7 @@ index bb18e5c94fbc7134c801e4e1979e8184079d352e..4ec2de7d123dd36315df07a1e95b1f41
#ifdef MITSHM
#include "shmint.h"
-@@ -110,6 +111,12 @@ xwl_screen_has_resolution_change_emulation(struct xwl_screen *xwl_screen)
+@@ -111,6 +112,12 @@ xwl_screen_has_resolution_change_emulation(struct xwl_screen *xwl_screen)
return xwl_screen->rootless && xwl_screen_has_viewport_support(xwl_screen);
}
@@ -303,7 +292,7 @@ index bb18e5c94fbc7134c801e4e1979e8184079d352e..4ec2de7d123dd36315df07a1e95b1f41
/* Return the output @ 0x0, falling back to the first output in the list */
struct xwl_output *
xwl_screen_get_first_output(struct xwl_screen *xwl_screen)
-@@ -127,6 +134,37 @@ xwl_screen_get_first_output(struct xwl_screen *xwl_screen)
+@@ -128,6 +135,38 @@ xwl_screen_get_first_output(struct xwl_screen *xwl_screen)
return xorg_list_first_entry(&xwl_screen->output_list, struct xwl_output, link);
}
@@ -338,10 +327,11 @@ index bb18e5c94fbc7134c801e4e1979e8184079d352e..4ec2de7d123dd36315df07a1e95b1f41
+ }
+}
+
- static void
- xwl_property_callback(CallbackListPtr *pcbl, void *closure,
- void *calldata)
-@@ -134,19 +172,24 @@ xwl_property_callback(CallbackListPtr *pcbl, void *closure,
++
+ struct xwl_output *
+ xwl_screen_get_fixed_or_first_output(struct xwl_screen *xwl_screen)
+ {
+@@ -144,19 +183,24 @@ xwl_property_callback(CallbackListPtr *pcbl, void *closure,
ScreenPtr screen = closure;
PropertyStateRec *rec = calldata;
struct xwl_screen *xwl_screen;
@@ -357,6 +347,7 @@ index bb18e5c94fbc7134c801e4e1979e8184079d352e..4ec2de7d123dd36315df07a1e95b1f41
xwl_screen = xwl_screen_get(screen);
- if (rec->prop->propertyName == xwl_screen->allow_commits_prop)
+- xwl_window_update_property(xwl_window, rec);
+ if (rec->prop->propertyName == xwl_screen->allow_commits_prop) {
+ struct xwl_window *xwl_window;
+
@@ -364,15 +355,15 @@ index bb18e5c94fbc7134c801e4e1979e8184079d352e..4ec2de7d123dd36315df07a1e95b1f41
+ if (!xwl_window)
+ return;
+
- xwl_window_update_property(xwl_window, rec);
++ xwl_window_update_property(xwl_window, rec);
+ }
+ else if (rec->prop->propertyName == xwl_screen->global_output_scale_prop) {
+ xwl_screen_update_property(xwl_screen, rec);
+ }
}
- Bool
-@@ -521,8 +564,14 @@ void xwl_surface_damage(struct xwl_screen *xwl_screen,
+ static void
+@@ -638,8 +682,14 @@ void xwl_surface_damage(struct xwl_screen *xwl_screen,
{
if (wl_surface_get_version(surface) >= WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION)
wl_surface_damage_buffer(surface, x, y, width, height);
@@ -388,7 +379,7 @@ index bb18e5c94fbc7134c801e4e1979e8184079d352e..4ec2de7d123dd36315df07a1e95b1f41
}
void
-@@ -538,10 +587,34 @@ xwl_screen_roundtrip(struct xwl_screen *xwl_screen)
+@@ -655,6 +705,30 @@ xwl_screen_roundtrip(struct xwl_screen *xwl_screen)
xwl_give_up("could not connect to wayland server\n");
}
@@ -415,7 +406,11 @@ index bb18e5c94fbc7134c801e4e1979e8184079d352e..4ec2de7d123dd36315df07a1e95b1f41
+ }
+}
+
- Bool
++
+ static int
+ xwl_server_grab(ClientPtr client)
+ {
+@@ -712,6 +786,7 @@ Bool
xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
{
static const char allow_commits[] = "_XWAYLAND_ALLOW_COMMITS";
@@ -423,7 +418,7 @@ index bb18e5c94fbc7134c801e4e1979e8184079d352e..4ec2de7d123dd36315df07a1e95b1f41
struct xwl_screen *xwl_screen;
Pixel red_mask, blue_mask, green_mask;
int ret, bpc, green_bpc, i;
-@@ -573,6 +646,7 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
+@@ -746,6 +821,7 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
#ifdef XWL_HAS_GLAMOR
xwl_screen->glamor = 1;
#endif
@@ -431,7 +426,7 @@ index bb18e5c94fbc7134c801e4e1979e8184079d352e..4ec2de7d123dd36315df07a1e95b1f41
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-rootless") == 0) {
-@@ -743,6 +817,12 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
+@@ -988,6 +1064,13 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
if (xwl_screen->allow_commits_prop == BAD_RESOURCE)
return FALSE;
@@ -441,23 +436,23 @@ index bb18e5c94fbc7134c801e4e1979e8184079d352e..4ec2de7d123dd36315df07a1e95b1f41
+ if (xwl_screen->global_output_scale_prop == BAD_RESOURCE)
+ return FALSE;
+
++
AddCallback(&PropertyStateCallback, xwl_property_callback, pScreen);
+ AddCallback(&RootWindowFinalizeCallback, xwl_root_window_finalized_callback, pScreen);
- xwl_screen_roundtrip(xwl_screen);
diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h
-index b965dddd7f964b1d100bbb9d10da1c35ab39810e..7446829d098fbe235e605084a016daff1a8eaea2 100644
+index fadd0526e..2ce6ce5ab 100644
--- a/hw/xwayland/xwayland-screen.h
+++ b/hw/xwayland/xwayland-screen.h
-@@ -72,6 +72,8 @@ struct xwl_screen {
+@@ -87,6 +87,7 @@ struct xwl_screen {
struct xorg_list damage_window_list;
struct xorg_list window_list;
+ int32_t global_output_scale;
-+
int wayland_fd;
struct wl_display *display;
struct wl_registry *registry;
-@@ -107,6 +109,7 @@ struct xwl_screen {
+@@ -134,6 +135,7 @@ struct xwl_screen {
struct glamor_context *glamor_ctx;
Atom allow_commits_prop;
@@ -465,29 +460,30 @@ index b965dddd7f964b1d100bbb9d10da1c35ab39810e..7446829d098fbe235e605084a016daff
/* The preferred GLVND vendor. If NULL, "mesa" is assumed. */
const char *glvnd_vendor;
-@@ -134,5 +137,7 @@ void xwl_screen_roundtrip (struct xwl_screen *xwl_screen);
+@@ -166,6 +168,8 @@ void xwl_screen_roundtrip (struct xwl_screen *xwl_screen);
void xwl_surface_damage(struct xwl_screen *xwl_screen,
struct wl_surface *surface,
int32_t x, int32_t y, int32_t width, int32_t height);
+int xwl_scale_to(struct xwl_screen *xwl_screen, int value);
+void xwl_screen_set_global_scale(struct xwl_screen *xwl_screen, int32_t scale);
+ int xwl_screen_get_next_output_serial(struct xwl_screen * xwl_screen);
#endif /* XWAYLAND_SCREEN_H */
diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c
-index 00f161eda084e335ac07471a2198176d75d9fcf0..ed3903853f0dab1dad390cd8429639541546157d 100644
+index 6b7f38605..2f1e0dee1 100644
--- a/hw/xwayland/xwayland-window.c
+++ b/hw/xwayland/xwayland-window.c
-@@ -470,7 +470,8 @@ ensure_surface_for_window(WindowPtr window)
- }
-
- wl_region_add(region, 0, 0,
-- window->drawable.width, window->drawable.height);
-+ xwl_scale_to(xwl_screen, window->drawable.width),
-+ xwl_scale_to(xwl_screen, window->drawable.height));
- wl_surface_set_opaque_region(xwl_window->surface, region);
- wl_region_destroy(region);
+@@ -788,7 +788,8 @@ xwl_create_root_surface(struct xwl_window *xwl_window)
}
-@@ -820,6 +821,7 @@ xwl_window_post_damage(struct xwl_window *xwl_window)
+
+ wl_region_add(region, 0, 0,
+- window->drawable.width, window->drawable.height);
++ xwl_scale_to(xwl_screen, window->drawable.width),
++ xwl_scale_to(xwl_screen, window->drawable.height));
+ wl_surface_set_opaque_region(xwl_window->surface, region);
+ wl_region_destroy(region);
+
+@@ -1322,6 +1323,7 @@ xwl_window_post_damage(struct xwl_window *xwl_window)
#endif
wl_surface_attach(xwl_window->surface, buffer, 0, 0);
@@ -495,4 +491,3 @@ index 00f161eda084e335ac07471a2198176d75d9fcf0..ed3903853f0dab1dad390cd842963954
/* Arbitrary limit to try to avoid flooding the Wayland
* connection. If we flood it too much anyway, this could
-
diff --git a/props.json b/props.json
index 38694792..31c7215a 100644
--- a/props.json
+++ b/props.json
@@ -1,3 +1,3 @@
{
- "version": "0.23.0"
+ "version": "0.24.0"
} \ No newline at end of file
diff --git a/protocols/meson.build b/protocols/meson.build
index d4be76e3..458de862 100644
--- a/protocols/meson.build
+++ b/protocols/meson.build
@@ -26,6 +26,7 @@ protocols = [
['wlr-foreign-toplevel-management-unstable-v1.xml'],
['wlr-layer-shell-unstable-v1.xml'],
['wlr-output-power-management-unstable-v1.xml'],
+ ['wlr-screencopy-unstable-v1.xml'],
['ext-workspace-unstable-v1.xml'],
['pointer-constraints-unstable-v1.xml'],
['tablet-unstable-v2.xml'],
diff --git a/src/Compositor.cpp b/src/Compositor.cpp
index b145022c..14fd0c98 100644
--- a/src/Compositor.cpp
+++ b/src/Compositor.cpp
@@ -86,9 +86,6 @@ void CCompositor::setRandomSplash() {
void CCompositor::initServer() {
- Debug::log(LOG, "Disabling stdout logs! Check the log for further logs.");
- Debug::disableStdout = true;
-
m_sWLDisplay = wl_display_create();
m_sWLEventLoop = wl_display_get_event_loop(m_sWLDisplay);
@@ -155,7 +152,6 @@ void CCompositor::initServer() {
m_sWLRDataDevMgr = wlr_data_device_manager_create(m_sWLDisplay);
wlr_export_dmabuf_manager_v1_create(m_sWLDisplay);
- wlr_screencopy_manager_v1_create(m_sWLDisplay);
wlr_data_control_manager_v1_create(m_sWLDisplay);
wlr_gamma_control_manager_v1_create(m_sWLDisplay);
wlr_primary_selection_v1_device_manager_create(m_sWLDisplay);
@@ -252,6 +248,9 @@ void CCompositor::initServer() {
wlr_multi_backend_add(m_sWLRBackend, m_sWLRHeadlessBackend);
initManagers(STAGE_LATE);
+
+ Debug::log(LOG, "Disabling stdout logs! Check the log for further logs.");
+ Debug::disableStdout = true;
}
void CCompositor::initAllSignals() {
@@ -526,21 +525,8 @@ CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) {
}
void CCompositor::removeWindowFromVectorSafe(CWindow* pWindow) {
- if (windowExists(pWindow) && !pWindow->m_bFadingOut) {
- // if X11, also check its children
- // and delete any needed
- if (pWindow->m_bIsX11) {
- for (auto& w : m_vWindows) {
- if (!w->m_bIsX11)
- continue;
-
- if (w->m_pX11Parent == pWindow)
- std::erase_if(m_vWindows, [&](std::unique_ptr<CWindow>& el) { return el.get() == w.get(); });
- }
- }
-
+ if (windowExists(pWindow) && !pWindow->m_bFadingOut)
std::erase_if(m_vWindows, [&](std::unique_ptr<CWindow>& el) { return el.get() == pWindow; });
- }
}
bool CCompositor::windowExists(CWindow* pWindow) {
@@ -558,13 +544,15 @@ CWindow* CCompositor::vectorToWindow(const Vector2D& pos) {
if (PMONITOR->specialWorkspaceID) {
for (auto& w : m_vWindows | std::views::reverse) {
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_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !w->isHidden())
+ if (w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !w->isHidden() &&
+ !w->m_bNoFocus)
return w.get();
}
for (auto& w : m_vWindows) {
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 == PMONITOR->specialWorkspaceID && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && !w->m_bIsFloating && !w->isHidden())
+ if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && !w->m_bIsFloating && !w->isHidden() &&
+ !w->m_bNoFocus)
return w.get();
}
}
@@ -572,20 +560,21 @@ CWindow* CCompositor::vectorToWindow(const Vector2D& pos) {
// pinned
for (auto& w : m_vWindows | std::views::reverse) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
- if (wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && w->m_bIsFloating && !w->isHidden() && w->m_bPinned)
+ if (wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && w->m_bIsFloating && !w->isHidden() && w->m_bPinned && !w->m_bNoFocus)
return w.get();
}
// first loop over floating cuz they're above, m_vWindows should be sorted bottom->top, for tiled it doesn't matter.
for (auto& w : m_vWindows | std::views::reverse) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
- if (wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned)
+ if (wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned &&
+ !w->m_bNoFocus)
return w.get();
}
for (auto& w : m_vWindows) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
- if (wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && !w->m_bIsFloating && PMONITOR->activeWorkspace == w->m_iWorkspaceID && !w->isHidden())
+ if (wlr_box_contains_point(&box, pos.x, pos.y) && w->m_bIsMapped && !w->m_bIsFloating && PMONITOR->activeWorkspace == w->m_iWorkspaceID && !w->isHidden() && !w->m_bNoFocus)
return w.get();
}
@@ -598,14 +587,14 @@ CWindow* CCompositor::vectorToWindowTiled(const Vector2D& pos) {
if (PMONITOR->specialWorkspaceID) {
for (auto& w : m_vWindows) {
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
- if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && wlr_box_contains_point(&box, pos.x, pos.y) && !w->m_bIsFloating && !w->isHidden())
+ if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && wlr_box_contains_point(&box, pos.x, pos.y) && !w->m_bIsFloating && !w->isHidden() && !w->m_bNoFocus)
return w.get();
}
}
for (auto& w : m_vWindows) {
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->isHidden())
+ if (w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bIsFloating && !w->isHidden() && !w->m_bNoFocus)
return w.get();
}
@@ -625,14 +614,14 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
const auto BB = w->getWindowInputBox();
wlr_box box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
if (w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !w->isHidden() &&
- !w->m_bX11ShouldntFocus)
+ !w->m_bX11ShouldntFocus && !w->m_bNoFocus)
return w.get();
}
for (auto& w : m_vWindows) {
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (!w->m_bIsFloating && w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && !w->isHidden() &&
- !w->m_bX11ShouldntFocus)
+ !w->m_bX11ShouldntFocus && !w->m_bNoFocus)
return w.get();
}
}
@@ -641,7 +630,7 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
for (auto& w : m_vWindows | std::views::reverse) {
const auto BB = w->getWindowInputBox();
wlr_box box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
- if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned) {
+ if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_bNoFocus) {
if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y))
return w.get();
@@ -656,7 +645,7 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
for (auto& w : m_vWindows | std::views::reverse) {
const auto BB = w->getWindowInputBox();
wlr_box box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
- if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned) {
+ if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned && !w->m_bNoFocus) {
// OR windows should add focus to parent
if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2)
continue;
@@ -681,7 +670,7 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
// for windows, we need to check their extensions too, first.
for (auto& w : m_vWindows) {
- if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->isHidden() && !w->m_bX11ShouldntFocus) {
+ if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->isHidden() && !w->m_bX11ShouldntFocus && !w->m_bNoFocus) {
if ((w)->hasPopupAt(pos))
return w.get();
}
@@ -689,7 +678,7 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos) {
for (auto& w : m_vWindows) {
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
if (!w->m_bIsFloating && w->m_bIsMapped && wlr_box_contains_point(&box, pos.x, pos.y) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->isHidden() &&
- !w->m_bX11ShouldntFocus)
+ !w->m_bX11ShouldntFocus && !w->m_bNoFocus)
return w.get();
}
@@ -703,13 +692,13 @@ CWindow* CCompositor::windowFromCursor() {
for (auto& w : m_vWindows | std::views::reverse) {
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_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) &&
- !w->isHidden())
+ !w->isHidden() && !w->m_bNoFocus)
return w.get();
}
for (auto& w : m_vWindows) {
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
- if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped)
+ if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && !w->m_bNoFocus)
return w.get();
}
}
@@ -717,20 +706,21 @@ CWindow* CCompositor::windowFromCursor() {
// pinned
for (auto& w : m_vWindows | std::views::reverse) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
- if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && w->m_bIsFloating && w->m_bPinned)
+ if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && w->m_bIsFloating && w->m_bPinned && !w->m_bNoFocus)
return w.get();
}
// 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_vWindows | std::views::reverse) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
- if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->m_bPinned)
+ if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->m_bPinned &&
+ !w->m_bNoFocus)
return w.get();
}
for (auto& w : m_vWindows) {
wlr_box box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
- if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && w->m_iWorkspaceID == PMONITOR->activeWorkspace)
+ if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bNoFocus)
return w.get();
}
@@ -740,14 +730,14 @@ CWindow* CCompositor::windowFromCursor() {
CWindow* CCompositor::windowFloatingFromCursor() {
for (auto& w : m_vWindows | std::views::reverse) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
- if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && w->m_bIsFloating && !w->isHidden() && w->m_bPinned)
+ if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && w->m_bIsFloating && !w->isHidden() && w->m_bPinned && !w->m_bNoFocus)
return w.get();
}
for (auto& w : m_vWindows | std::views::reverse) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
if (wlr_box_contains_point(&box, m_sWLRCursor->x, m_sWLRCursor->y) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() &&
- !w->m_bPinned)
+ !w->m_bPinned && !w->m_bNoFocus)
return w.get();
}
@@ -2150,11 +2140,28 @@ void CCompositor::closeWindow(CWindow* pWindow) {
}
SLayerSurface* CCompositor::getLayerSurfaceFromSurface(wlr_surface* pSurface) {
+ std::pair<wlr_surface*, bool> result = {pSurface, false};
+
for (auto& m : m_vMonitors) {
for (auto& lsl : m->m_aLayerSurfaceLayers) {
for (auto& ls : lsl) {
if (ls->layerSurface && ls->layerSurface->surface == pSurface)
return ls.get();
+
+ static auto iter = [](wlr_surface* surf, int x, int y, void* data) -> void {
+ if (surf == ((std::pair<wlr_surface*, bool>*)data)->first) {
+ *(bool*)data = true;
+ return;
+ }
+ };
+
+ if (!ls->layerSurface || !ls->mapped)
+ continue;
+
+ wlr_surface_for_each_surface(ls->layerSurface->surface, iter, &result);
+
+ if (result.second)
+ return ls.get();
}
}
}
diff --git a/src/Window.cpp b/src/Window.cpp
index b8c7ab36..3942114b 100644
--- a/src/Window.cpp
+++ b/src/Window.cpp
@@ -284,6 +284,11 @@ void CWindow::moveToWorkspace(int workspaceID) {
EMIT_HOOK_EVENT("moveWindow", (std::vector<void*>{this, PWORKSPACE}));
}
+ if (m_pSwallowed) {
+ m_pSwallowed->moveToWorkspace(workspaceID);
+ m_pSwallowed->m_iMonitorID = m_iMonitorID;
+ }
+
if (PMONITOR)
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(m_pWLSurface.wlr(), PMONITOR->scale);
}
@@ -338,6 +343,8 @@ void CWindow::onUnmap() {
std::erase_if(g_pCompositor->m_vWindowFocusHistory, [&](const auto& other) { return other == this; });
m_pWLSurface.unassign();
+
+ hyprListener_unmapWindow.removeCallback();
}
void CWindow::onMap() {
@@ -369,6 +376,8 @@ void CWindow::onMap() {
m_fBorderAngleAnimationProgress = 1.f;
g_pCompositor->m_vWindowFocusHistory.push_back(this);
+
+ hyprListener_unmapWindow.initCallback(m_bIsX11 ? &m_uSurface.xwayland->events.unmap : &m_uSurface.xdg->events.unmap, &Events::listener_unmapWindow, this, "CWindow");
}
void CWindow::onBorderAngleAnimEnd(void* ptr) {
@@ -409,7 +418,7 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
} else if (r.szRule == "forcergbx") {
m_sAdditionalConfigData.forceRGBX = true;
} else if (r.szRule == "opaque") {
- if (!m_sAdditionalConfigData.forceOpaqueOverriden)
+ if (!m_sAdditionalConfigData.forceOpaqueOverridden)
m_sAdditionalConfigData.forceOpaque = true;
} else if (r.szRule.find("rounding") == 0) {
try {
@@ -466,7 +475,7 @@ void CWindow::updateDynamicRules() {
m_sAdditionalConfigData.forceNoBlur = false;
m_sAdditionalConfigData.forceNoBorder = false;
m_sAdditionalConfigData.forceNoShadow = false;
- if (!m_sAdditionalConfigData.forceOpaqueOverriden)
+ if (!m_sAdditionalConfigData.forceOpaqueOverridden)
m_sAdditionalConfigData.forceOpaque = false;
m_sAdditionalConfigData.forceNoAnims = false;
m_sAdditionalConfigData.animationStyle = std::string("");
diff --git a/src/Window.hpp b/src/Window.hpp
index e4cff0aa..b93f74b7 100644
--- a/src/Window.hpp
+++ b/src/Window.hpp
@@ -107,19 +107,19 @@ struct SWindowSpecialRenderData {
};
struct SWindowAdditionalConfigData {
- std::string animationStyle = std::string("");
- CWindowOverridableVar<int> rounding = -1; // -1 means no
- CWindowOverridableVar<bool> forceNoBlur = false;
- CWindowOverridableVar<bool> forceOpaque = false;
- CWindowOverridableVar<bool> forceOpaqueOverriden = false; // if true, a rule will not change the forceOpaque state. This is for the force opaque dispatcher.
- CWindowOverridableVar<bool> forceAllowsInput = false;
- CWindowOverridableVar<bool> forceNoAnims = false;
- CWindowOverridableVar<bool> forceNoBorder = false;
- CWindowOverridableVar<bool> forceNoShadow = false;
- CWindowOverridableVar<bool> windowDanceCompat = false;
- CWindowOverridableVar<bool> noMaxSize = false;
- CWindowOverridableVar<bool> dimAround = false;
- CWindowOverridableVar<bool> forceRGBX = false;
+ std::string animationStyle = std::string("");
+ CWindowOverridableVar<int> rounding = -1; // -1 means no
+ CWindowOverridableVar<bool> forceNoBlur = false;
+ CWindowOverridableVar<bool> forceOpaque = false;
+ CWindowOverridableVar<bool> forceOpaqueOverridden = false; // if true, a rule will not change the forceOpaque state. This is for the force opaque dispatcher.
+ CWindowOverridableVar<bool> forceAllowsInput = false;
+ CWindowOverridableVar<bool> forceNoAnims = false;
+ CWindowOverridableVar<bool> forceNoBorder = false;
+ CWindowOverridableVar<bool> forceNoShadow = false;
+ CWindowOverridableVar<bool> windowDanceCompat = false;
+ CWindowOverridableVar<bool> noMaxSize = false;
+ CWindowOverridableVar<bool> dimAround = false;
+ CWindowOverridableVar<bool> forceRGBX = false;
};
struct SWindowRule {
@@ -195,6 +195,8 @@ class CWindow {
bool m_bWasMaximized = false;
uint64_t m_iMonitorID = -1;
std::string m_szTitle = "";
+ std::string m_szInitialTitle = "";
+ std::string m_szInitialClass = "";
int m_iWorkspaceID = -1;
bool m_bIsMapped = false;
diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp
index 2283b61c..37554ff9 100644
--- a/src/config/ConfigManager.cpp
+++ b/src/config/ConfigManager.cpp
@@ -82,7 +82,7 @@ void CConfigManager::setDefaultVars() {
configValues["misc:enable_swallow"].intValue = 0;
configValues["misc:swallow_regex"].strValue = STRVAL_EMPTY;
configValues["misc:focus_on_activate"].intValue = 0;
- configValues["misc:no_direct_scanout"].intValue = 0;
+ configValues["misc:no_direct_scanout"].intValue = 1;
configValues["misc:hide_cursor_on_touch"].intValue = 1;
configValues["misc:mouse_move_focuses_monitor"].intValue = 1;
configValues["misc:suppress_portal_warnings"].intValue = 0;
@@ -97,6 +97,7 @@ void CConfigManager::setDefaultVars() {
configValues["debug:disable_time"].intValue = 1;
configValues["debug:enable_stdout_logs"].intValue = 0;
configValues["debug:damage_tracking"].intValue = DAMAGE_TRACKING_FULL;
+ configValues["debug:manual_crash"].intValue = 0;
configValues["decoration:rounding"].intValue = 0;
configValues["decoration:blur"].intValue = 1;
@@ -611,8 +612,8 @@ void CConfigManager::handleBezier(const std::string& command, const std::string&
void CConfigManager::setAnimForChildren(SAnimationPropertyConfig* const ANIM) {
for (auto& [name, anim] : animationConfig) {
- if (anim.pParentAnimation == ANIM && !anim.overriden) {
- // if a child isnt overriden, set the values of the parent
+ if (anim.pParentAnimation == ANIM && !anim.overridden) {
+ // if a child isnt overridden, set the values of the parent
anim.pValues = ANIM->pValues;
setAnimForChildren(&anim);
@@ -635,8 +636,8 @@ void CConfigManager::handleAnimation(const std::string& command, const std::stri
return;
}
- PANIM->second.overriden = true;
- PANIM->second.pValues = &PANIM->second;
+ PANIM->second.overridden = true;
+ PANIM->second.pValues = &PANIM->second;
// on/off
PANIM->second.internalEnabled = ARGS[1] == "1";
@@ -1160,6 +1161,18 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
// Update window border colors
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
+ // manual crash
+ if (configValues["debug:manual_crash"].intValue && !m_bManualCrashInitiated) {
+ m_bManualCrashInitiated = true;
+ if (g_pHyprNotificationOverlay) {
+ g_pHyprNotificationOverlay->addNotification("Manual crash has been set up. Set debug:manual_crash back to 0 in order to crash the compositor.", CColor(0), 5000,
+ ICON_INFO);
+ }
+ } else if (m_bManualCrashInitiated && !configValues["debug:manual_crash"].intValue) {
+ // cowabunga it is
+ g_pHyprRenderer->initiateManualCrash();
+ }
+
return retval;
}
@@ -1387,7 +1400,7 @@ void CConfigManager::loadConfigLoadVars() {
if (!isFirstLaunch && !m_bNoMonitorReload) {
// check
performMonitorReload();
- ensureDPMS();
+ ensureMonitorStatus();
ensureVRR();
}
@@ -1397,6 +1410,15 @@ void CConfigManager::loadConfigLoadVars() {
// update layout
g_pLayoutManager->switchToLayout(configValues["general:layout"].strValue);
+ // manual crash
+ if (configValues["debug:manual_crash"].intValue && !m_bManualCrashInitiated) {
+ m_bManualCrashInitiated = true;
+ g_pHyprNotificationOverlay->addNotification("Manual crash has been set up. Set debug:manual_crash back to 0 in order to crash the compositor.", CColor(0), 5000, ICON_INFO);
+ } else if (m_bManualCrashInitiated && !configValues["debug:manual_crash"].intValue) {
+ // cowabunga it is
+ g_pHyprRenderer->initiateManualCrash();
+ }
+
Debug::disableStdout = !configValues["debug:enable_stdout_logs"].intValue;
for (auto& m : g_pCompositor->m_vMonitors) {
@@ -1791,7 +1813,7 @@ bool CConfigManager::shouldBlurLS(const std::string& ns) {
return false;
}
-void CConfigManager::ensureDPMS() {
+void CConfigManager::ensureMonitorStatus() {
for (auto& rm : g_pCompositor->m_vRealMonitors) {
if (!rm->output)
continue;
diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp
index e5a5749d..cee6075e 100644
--- a/src/config/ConfigManager.hpp
+++ b/src/config/ConfigManager.hpp
@@ -53,7 +53,7 @@ struct SMonitorAdditionalReservedArea {
};
struct SAnimationPropertyConfig {
- bool overriden = true;
+ bool overridden = true;
std::string internalBezier = "";
std::string internalStyle = "";
@@ -171,7 +171,7 @@ class CConfigManager {
bool m_bWantsMonitorReload = false;
bool m_bForceReload = false;
bool m_bNoMonitorReload = false;
- void ensureDPMS();
+ void ensureMonitorStatus();
void ensureVRR(CMonitor* pMonitor = nullptr);
std::string parseKeyword(const std::string&, const std::string&, bool dynamic = false);
@@ -213,7 +213,8 @@ class CConfigManager {
std::deque<SLayerRule> m_dLayerRules;
std::deque<std::string> m_dBlurLSNamespaces;
- bool firstExecDispatched = false;
+ bool firstExecDispatched = false;
+ bool m_bManualCrashInitiated = false;
std::deque<std::string> firstExecRequests;
std::vector<std::pair<std::string, std::string>> environmentVariables;
diff --git a/src/debug/CrashReporter.cpp b/src/debug/CrashReporter.cpp
index 4037ad44..d553b7b0 100644
--- a/src/debug/CrashReporter.cpp
+++ b/src/debug/CrashReporter.cpp
@@ -129,18 +129,32 @@ void CrashReporter::createAndSaveCrash(int sig) {
finalCrashReport += execAndGet(("cat \"" + Debug::logFile + "\" | tail -n 50").c_str());
const auto HOME = getenv("HOME");
+ const auto CACHE_HOME = getenv("XDG_CACHE_HOME");
if (!HOME)
return;
- if (!std::filesystem::exists(std::string(HOME) + "/.hyprland")) {
- std::filesystem::create_directory(std::string(HOME) + "/.hyprland");
- std::filesystem::permissions(std::string(HOME) + "/.hyprland", std::filesystem::perms::all, std::filesystem::perm_options::replace);
- }
+ std::ofstream ofs;
+ if (!CACHE_HOME) {
+ if (!std::filesystem::exists(std::string(HOME) + "/.hyprland")) {
+ std::filesystem::create_directory(std::string(HOME) + "/.hyprland");
+ std::filesystem::permissions(std::string(HOME) + "/.hyprland", std::filesystem::perms::all, std::filesystem::perm_options::replace);
+ }
+
+ ofs.open(std::string(HOME) + "/.hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt", std::ios::trunc);
+
+ } else if (CACHE_HOME) {
+ if (!std::filesystem::exists(std::string(CACHE_HOME) + "/hyprland")) {
+ std::filesystem::create_directory(std::string(CACHE_HOME) + "/hyprland");
+ std::filesystem::permissions(std::string(CACHE_HOME) + "/hyprland", std::filesystem::perms::all, std::filesystem::perm_options::replace);
+ }
- std::ofstream ofs(std::string(HOME) + "/.hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt", std::ios::trunc);
+ ofs.open(std::string(CACHE_HOME) + "/hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt", std::ios::trunc);
+ } else {
+ return;
+ }
ofs << finalCrashReport;
ofs.close();
-} \ No newline at end of file
+}
diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp
index feafc5ef..bef7c68e 100644
--- a/src/debug/HyprCtl.cpp
+++ b/src/debug/HyprCtl.cpp
@@ -126,6 +126,8 @@ static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat forma
"monitor": %i,
"class": "%s",
"title": "%s",
+ "initialClass": "%s",
+ "initialTitle": "%s",
"pid": %i,
"xwayland": %s,
"pinned": %s,
@@ -142,13 +144,14 @@ static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat forma
std::string("Invalid workspace " + std::to_string(w->m_iWorkspaceID)))
.c_str(),
((int)w->m_bIsFloating == 1 ? "true" : "false"), w->m_iMonitorID, escapeJSONStrings(g_pXWaylandManager->getAppIDClass(w)).c_str(),
- escapeJSONStrings(g_pXWaylandManager->getTitle(w)).c_str(), w->getPID(), ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"),
- (w->m_bIsFullscreen ? "true" : "false"),
+ escapeJSONStrings(g_pXWaylandManager->getTitle(w)).c_str(), escapeJSONStrings(w->m_szInitialClass).c_str(), escapeJSONStrings(w->m_szInitialTitle).c_str(), w->getPID(),
+ ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), (w->m_bIsFullscreen ? "true" : "false"),
(w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0),
w->m_bFakeFullscreenState ? "true" : "false", getGroupedData(w, format).c_str(), (w->m_pSwallowed ? getFormat("\"0x%x\"", w->m_pSwallowed).c_str() : "null"));
} else {
return getFormat(
- "Window %x -> %s:\n\tmapped: %i\n\thidden: %i\n\tat: %i,%i\n\tsize: %i,%i\n\tworkspace: %i (%s)\n\tfloating: %i\n\tmonitor: %i\n\tclass: %s\n\ttitle: %s\n\tpid: "
+ "Window %x -> %s:\n\tmapped: %i\n\thidden: %i\n\tat: %i,%i\n\tsize: %i,%i\n\tworkspace: %i (%s)\n\tfloating: %i\n\tmonitor: %i\n\tclass: %s\n\ttitle: "
+ "%s\n\tinitialClass: %s\n\tinitialTitle: %s\n\tpid: "
"%i\n\txwayland: %i\n\tpinned: "
"%i\n\tfullscreen: %i\n\tfullscreenmode: %i\n\tfakefullscreen: %i\n\tgrouped: %s\n\tswallowing: %x\n\n",
w, w->m_szTitle.c_str(), (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goalv().x, (int)w->m_vRealPosition.goalv().y, (int)w->m_vRealSize.goalv().x,
@@ -156,8 +159,8 @@ static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat forma
(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(), g_pXWaylandManager->getTitle(w).c_str(), w->getPID(), (int)w->m_bIsX11,
- (int)w->m_bPinned, (int)w->m_bIsFullscreen,
+ (int)w->m_bIsFloating, w->m_iMonitorID, g_pXWaylandManager->getAppIDClass(w).c_str(), g_pXWaylandManager->getTitle(w).c_str(), w->m_szInitialClass.c_str(),
+ w->m_szInitialTitle.c_str(), w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen,
(w->m_bIsFullscreen ? (g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID) ? g_pCompositor->getWorkspaceByID(w->m_iWorkspaceID)->m_efFullscreenMode : 0) : 0),
(int)w->m_bFakeFullscreenState, getGroupedData(w, format).c_str(), w->m_pSwallowed);
}
@@ -486,7 +489,7 @@ std::string animationsRequest(HyprCtl::eHyprCtlOutputFormat format) {
ret += "animations:\n";
for (auto& ac : g_pConfigManager->getAnimationConfig()) {
- ret += getFormat("\n\tname: %s\n\t\toverriden: %i\n\t\tbezier: %s\n\t\tenabled: %i\n\t\tspeed: %.2f\n\t\tstyle: %s\n", ac.first.c_str(), (int)ac.second.overriden,
+ ret += getFormat("\n\tname: %s\n\t\toverriden: %i\n\t\tbezier: %s\n\t\tenabled: %i\n\t\tspeed: %.2f\n\t\tstyle: %s\n", ac.first.c_str(), (int)ac.second.overridden,
ac.second.internalBezier.c_str(), ac.second.internalEnabled, ac.second.internalSpeed, ac.second.internalStyle.c_str());
}
@@ -503,13 +506,13 @@ std::string animationsRequest(HyprCtl::eHyprCtlOutputFormat format) {
ret += getFormat(R"#(
{
"name": "%s",
- "overriden": %s,
+ "overridden": %s,
"bezier": "%s",
"enabled": %s,
"speed": %.2f,
"style": "%s"
},)#",
- ac.first.c_str(), ac.second.overriden ? "true" : "false", ac.second.internalBezier.c_str(), ac.second.internalEnabled ? "true" : "false",
+ ac.first.c_str(), ac.second.overridden ? "true" : "false", ac.second.internalBezier.c_str(), ac.second.internalEnabled ? "true" : "false",
ac.second.internalSpeed, ac.second.internalStyle.c_str());
}
@@ -956,7 +959,7 @@ std::string dispatchSetProp(std::string request) {
} else if (PROP == "forceopaque") {
PWINDOW->m_sAdditionalConfigData.forceOpaque.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forceopaqueoverriden") {
- PWINDOW->m_sAdditionalConfigData.forceOpaqueOverriden.forceSetIgnoreLocked(configStringToInt(VAL), lock);
+ PWINDOW->m_sAdditionalConfigData.forceOpaqueOverridden.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forceallowsinput") {
PWINDOW->m_sAdditionalConfigData.forceAllowsInput.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "forcenoanims") {
@@ -1178,7 +1181,7 @@ std::string dispatchNotify(std::string request) {
icon = std::stoi(ICON);
} catch (std::exception& e) { return "invalid arg 1"; }
- if (icon == -1 || icon > ICON_NONE) {
+ if (icon > ICON_NONE || icon < 0) {
icon = ICON_NONE;
}
@@ -1312,7 +1315,7 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
close(ACCEPTEDCONNECTION);
if (g_pConfigManager->m_bWantsMonitorReload) {
- g_pConfigManager->ensureDPMS();
+ g_pConfigManager->ensureMonitorStatus();
}
return 0;
diff --git a/src/events/Events.hpp b/src/events/Events.hpp
index ae441fbb..d0a1df39 100644
--- a/src/events/Events.hpp
+++ b/src/events/Events.hpp
@@ -98,6 +98,8 @@ namespace Events {
DYNLISTENFUNC(monitorFrame);
DYNLISTENFUNC(monitorDestroy);
DYNLISTENFUNC(monitorStateRequest);
+ DYNLISTENFUNC(monitorDamage);
+ DYNLISTENFUNC(monitorNeedsFrame);
// XWayland
LISTENER(readyXWayland);
diff --git a/src/events/Layers.cpp b/src/events/Layers.cpp
index a7135953..ff31355e 100644
--- a/src/events/Layers.cpp
+++ b/src/events/Layers.cpp
@@ -218,6 +218,8 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
// refocus if needed
if (WASLASTFOCUS) {
+ g_pInputManager->releaseAllMouseButtons();
+
Vector2D surfaceCoords;
SLayerSurface* pFoundLayerSurface = nullptr;
wlr_surface* foundSurface = nullptr;
diff --git a/src/events/Misc.cpp b/src/events/Misc.cpp
index 8d1b9c00..22587599 100644
--- a/src/events/Misc.cpp
+++ b/src/events/Misc.cpp
@@ -116,20 +116,11 @@ void Events::listener_startDrag(wl_listener* listener, void* data) {
g_pInputManager->m_sDrag.hyprListener_commitIcon.initCallback(&wlrDrag->icon->surface->events.commit, &Events::listener_commitDragIcon, &g_pInputManager->m_sDrag,
"DragIcon");
}
-
- static auto* const PFOLLOWONDND = &g_pConfigManager->getConfigValuePtr("misc:always_follow_on_dnd")->intValue;
-
- if (*PFOLLOWONDND)
- g_pInputManager->m_pFollowOnDnDBegin = g_pCompositor->m_pLastWindow;
- else
- g_pInputManager->m_pFollowOnDnDBegin = nullptr;
}
void Events::listener_destroyDrag(void* owner, void* data) {
Debug::log(LOG, "Drag destroyed.");
- static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
-
if (g_pInputManager->m_sDrag.drag && g_pInputManager->m_sDrag.dragIcon && g_pInputManager->m_sDrag.dragIcon->surface)
g_pHyprRenderer->damageBox(g_pInputManager->m_sDrag.pos.x - 2, g_pInputManager->m_sDrag.pos.y - 2, g_pInputManager->m_sDrag.dragIcon->surface->current.width + 4,
g_pInputManager->m_sDrag.dragIcon->surface->current.height + 4);
@@ -137,13 +128,6 @@ void Events::listener_destroyDrag(void* owner, void* data) {
g_pInputManager->m_sDrag.drag = nullptr;
g_pInputManager->m_sDrag.dragIcon = nullptr;
g_pInputManager->m_sDrag.hyprListener_destroy.removeCallback();
-
- g_pInputManager->refocus();
-
- if (g_pInputManager->m_pFollowOnDnDBegin && *PFOLLOWMOUSE != 1)
- g_pCompositor->focusWindow(g_pInputManager->m_pFollowOnDnDBegin);
-
- g_pInputManager->m_pFollowOnDnDBegin = nullptr;
}
void Events::listener_mapDragIcon(void* owner, void* data) {
diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp
index ad0e416b..c9bb6dd7 100644
--- a/src/events/Monitors.cpp
+++ b/src/events/Monitors.cpp
@@ -44,7 +44,7 @@ void Events::listener_change(wl_listener* listener, void* data) {
}
void Events::listener_newOutput(wl_listener* listener, void* data) {
- // new monitor added, let's accomodate for that.
+ // new monitor added, let's accommodate for that.
const auto OUTPUT = (wlr_output*)data;
// for warping the cursor on launch
@@ -196,3 +196,16 @@ void Events::listener_monitorStateRequest(void* owner, void* data) {
wlr_output_commit_state(PMONITOR->output, E->state);
}
+
+void Events::listener_monitorDamage(void* owner, void* data) {
+ const auto PMONITOR = (CMonitor*)owner;
+ const auto E = (wlr_output_event_damage*)data;
+
+ PMONITOR->addDamage(E->damage);
+}
+
+void Events::listener_monitorNeedsFrame(void* owner, void* data) {
+ const auto PMONITOR = (CMonitor*)owner;
+
+ g_pCompositor->scheduleFrameForMonitor(PMONITOR);
+}
diff --git a/src/events/Popups.cpp b/src/events/Popups.cpp
index b56d0792..2649abce 100644
--- a/src/events/Popups.cpp
+++ b/src/events/Popups.cpp
@@ -173,6 +173,9 @@ void Events::listener_unmapPopupXDG(void* owner, void* data) {
ASSERT(PPOPUP);
+ if (PPOPUP->popup->base->surface == g_pCompositor->m_pLastFocus)
+ g_pInputManager->releaseAllMouseButtons();
+
SubsurfaceTree::destroySurfaceTree(PPOPUP->pSurfaceTree);
int lx = 0, ly = 0;
diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp
index adbd2118..ca5d88c6 100644
--- a/src/events/Windows.cpp
+++ b/src/events/Windows.cpp
@@ -67,7 +67,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
// Foreign Toplevel
PWINDOW->createToplevelHandle();
- // checks if the window wants borders and sets the appriopriate flag
+ // checks if the window wants borders and sets the appropriate flag
g_pXWaylandManager->checkBorders(PWINDOW);
// registers the animated vars and stuff
@@ -117,6 +117,9 @@ void Events::listener_mapWindow(void* owner, void* data) {
bool shouldFocus = true;
bool workspaceSpecial = false;
+ PWINDOW->m_szInitialTitle = g_pXWaylandManager->getTitle(PWINDOW);
+ PWINDOW->m_szInitialClass = g_pXWaylandManager->getAppIDClass(PWINDOW);
+
for (auto& r : WINDOWRULES) {
if (r.szRule.find("monitor") == 0) {
try {
@@ -583,6 +586,12 @@ void Events::listener_unmapWindow(void* owner, void* data) {
Debug::log(LOG, "Window %x unmapped (class %s)", PWINDOW, g_pXWaylandManager->getAppIDClass(PWINDOW).c_str());
+ if (!PWINDOW->m_pWLSurface.exists() || !PWINDOW->m_bIsMapped) {
+ Debug::log(WARN, "Window %x unmapped without being mapped??", PWINDOW);
+ PWINDOW->m_bFadingOut = false;
+ return;
+ }
+
g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", getFormat("%x", PWINDOW)});
EMIT_HOOK_EVENT("closeWindow", PWINDOW);
@@ -628,6 +637,8 @@ void Events::listener_unmapWindow(void* owner, void* data) {
wasLastWindow = true;
g_pCompositor->m_pLastWindow = nullptr;
g_pCompositor->m_pLastFocus = nullptr;
+
+ g_pInputManager->releaseAllMouseButtons();
}
PWINDOW->m_bMappedX11 = false;
@@ -802,7 +813,7 @@ void Events::listener_fullscreenWindow(void* owner, void* data) {
}
}
- // Disable the maximize flag when we recieve a de-fullscreen request
+ // Disable the maximize flag when we receive a de-fullscreen request
PWINDOW->m_bWasMaximized &= REQUESTED->fullscreen;
requestedFullState = REQUESTED->fullscreen;
@@ -1007,7 +1018,6 @@ void Events::listener_surfaceXWayland(wl_listener* listener, void* data) {
PNEWWINDOW->m_pX11Parent = g_pCompositor->getX11Parent(PNEWWINDOW);
PNEWWINDOW->hyprListener_mapWindow.initCallback(&XWSURFACE->events.map, &Events::listener_mapWindow, PNEWWINDOW, "XWayland Window");
- PNEWWINDOW->hyprListener_unmapWindow.initCallback(&XWSURFACE->events.unmap, &Events::listener_unmapWindow, PNEWWINDOW, "XWayland Window");
PNEWWINDOW->hyprListener_destroyWindow.initCallback(&XWSURFACE->events.destroy, &Events::listener_destroyWindow, PNEWWINDOW, "XWayland Window");
PNEWWINDOW->hyprListener_setOverrideRedirect.initCallback(&XWSURFACE->events.set_override_redirect, &Events::listener_setOverrideRedirect, PNEWWINDOW, "XWayland Window");
PNEWWINDOW->hyprListener_configureX11.initCallback(&XWSURFACE->events.request_configure, &Events::listener_configureX11, PNEWWINDOW, "XWayland Window");
@@ -1026,7 +1036,6 @@ void Events::listener_newXDGSurface(wl_listener* listener, void* data) {
PNEWWINDOW->m_uSurface.xdg = XDGSURFACE;
PNEWWINDOW->hyprListener_mapWindow.initCallback(&XDGSURFACE->events.map, &Events::listener_mapWindow, PNEWWINDOW, "XDG Window");
- PNEWWINDOW->hyprListener_unmapWindow.initCallback(&XDGSURFACE->events.unmap, &Events::listener_unmapWindow, PNEWWINDOW, "XDG Window");
PNEWWINDOW->hyprListener_destroyWindow.initCallback(&XDGSURFACE->events.destroy, &Events::listener_destroyWindow, PNEWWINDOW, "XDG Window");
}
diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp
index de385e9b..ecbfa308 100644
--- a/src/helpers/MiscFunctions.cpp
+++ b/src/helpers/MiscFunctions.cpp
@@ -6,11 +6,11 @@
#include <iomanip>
#include <sstream>
-#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
+#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/sysctl.h>
#if defined(__DragonFly__)
#include <sys/kinfo.h> // struct kinfo_proc
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#elif defined(__FreeBSD__)
#include <sys/user.h> // struct kinfo_proc
#endif
@@ -23,7 +23,7 @@
#endif
#if defined(__DragonFly__)
#define KP_PPID(kp) kp.kp_ppid
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#elif defined(__FreeBSD__)
#define KP_PPID(kp) kp.ki_ppid
#else
#define KP_PPID(kp) kp.p_ppid
diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp
index d8bae3a8..e1cf54cd 100644
--- a/src/helpers/Monitor.cpp
+++ b/src/helpers/Monitor.cpp
@@ -8,13 +8,25 @@ int ratHandler(void* data) {
return 1;
}
+CMonitor::CMonitor() {
+ wlr_damage_ring_init(&damage);
+}
+
+CMonitor::~CMonitor() {
+ wlr_damage_ring_finish(&damage);
+}
+
void CMonitor::onConnect(bool noRule) {
hyprListener_monitorDestroy.removeCallback();
hyprListener_monitorFrame.removeCallback();
hyprListener_monitorStateRequest.removeCallback();
+ hyprListener_monitorDamage.removeCallback();
+ hyprListener_monitorNeedsFrame.removeCallback();
hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this);
hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this);
hyprListener_monitorStateRequest.initCallback(&output->events.request_state, &Events::listener_monitorStateRequest, this);
+ hyprListener_monitorDamage.initCallback(&output->events.damage, &Events::listener_monitorDamage, this);
+ hyprListener_monitorNeedsFrame.initCallback(&output->events.needs_frame, &Events::listener_monitorNeedsFrame, this);
if (m_bEnabled) {
wlr_output_enable(output, 1);
@@ -114,13 +126,13 @@ void CMonitor::onConnect(bool noRule) {
if (!noRule)
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
+ wlr_damage_ring_set_bounds(&damage, vecTransformedSize.x, vecTransformedSize.y);
+
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, scale);
Debug::log(LOG, "Added new monitor with name %s at %i,%i with size %ix%i, pointer %x", output->name, (int)vecPosition.x, (int)vecPosition.y, (int)vecPixelSize.x,
(int)vecPixelSize.y, output);
- damage = wlr_output_damage_create(output);
-
// add a WLR workspace group
if (!pWLRWorkspaceGroupHandle) {
pWLRWorkspaceGroupHandle = wlr_ext_workspace_group_handle_v1_create(g_pCompositor->m_sWLREXTWorkspaceMgr);
@@ -131,6 +143,8 @@ void CMonitor::onConnect(bool noRule) {
setupDefaultWS(monitorRule);
scale = monitorRule.scale;
+ if (scale < 0.1)
+ scale = getDefaultScale();
m_pThisWrap = nullptr;
@@ -205,6 +219,8 @@ void CMonitor::onDisconnect() {
m_bRenderingInitPassed = false;
hyprListener_monitorFrame.removeCallback();
+ hyprListener_monitorDamage.removeCallback();
+ hyprListener_monitorNeedsFrame.removeCallback();
for (size_t i = 0; i < 4; ++i) {
for (auto& ls : m_aLayerSurfaceLayers[i]) {
@@ -251,8 +267,6 @@ void CMonitor::onDisconnect() {
activeWorkspace = -1;
- wlr_output_damage_destroy(damage);
-
wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output);
wlr_output_enable(output, false);
@@ -281,12 +295,14 @@ void CMonitor::onDisconnect() {
std::erase_if(g_pCompositor->m_vMonitors, [&](std::shared_ptr<CMonitor>& el) { return el.get() == this; });
}
-void CMonitor::addDamage(pixman_region32_t* rg) {
- wlr_output_damage_add(damage, rg);
+void CMonitor::addDamage(const pixman_region32_t* rg) {
+ if (wlr_damage_ring_add(&damage, rg))
+ g_pCompositor->scheduleFrameForMonitor(this);
}
-void CMonitor::addDamage(wlr_box* box) {
- wlr_output_damage_add_box(damage, box);
+void CMonitor::addDamage(const wlr_box* box) {
+ if (wlr_damage_ring_add_box(&damage, box))
+ g_pCompositor->scheduleFrameForMonitor(this);
}
bool CMonitor::isMirror() {
diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp
index 0707d79f..bb475189 100644
--- a/src/helpers/Monitor.hpp
+++ b/src/helpers/Monitor.hpp
@@ -12,6 +12,9 @@ struct SMonitorRule;
class CMonitor {
public:
+ CMonitor();
+ ~CMonitor();
+
Vector2D vecPosition = Vector2D(-1, -1); // means unset
Vector2D vecSize = Vector2D(0, 0);
Vector2D vecPixelSize = Vector2D(0, 0);
@@ -29,9 +32,9 @@ class CMonitor {
Vector2D vecReservedBottomRight = Vector2D(0, 0);
// WLR stuff
+ wlr_damage_ring damage;
wlr_output* output = nullptr;
float refreshRate = 60;
- wlr_output_damage* damage = nullptr;
int framesToSkip = 0;
int forceFullFrames = 0;
bool noFrameSchedule = false;
@@ -62,6 +65,8 @@ class CMonitor {
DYNLISTENER(monitorFrame);
DYNLISTENER(monitorDestroy);
DYNLISTENER(monitorStateRequest);
+ DYNLISTENER(monitorDamage);
+ DYNLISTENER(monitorNeedsFrame);
// hack: a group = workspaces on a monitor.
// I don't really care lol :P
@@ -70,8 +75,8 @@ class CMonitor {
// methods
void onConnect(bool noRule);
void onDisconnect();
- void addDamage(pixman_region32_t* rg);
- void addDamage(wlr_box* box);
+ void addDamage(const pixman_region32_t* rg);
+ void addDamage(const wlr_box* box);
void setMirror(const std::string&);
bool isMirror();
float getDefaultScale();
diff --git a/src/helpers/SubsurfaceTree.cpp b/src/helpers/SubsurfaceTree.cpp
index 43ff3be7..e6915525 100644
--- a/src/helpers/SubsurfaceTree.cpp
+++ b/src/helpers/SubsurfaceTree.cpp
@@ -3,6 +3,9 @@
#include "../Compositor.hpp"
void addSurfaceGlobalOffset(SSurfaceTreeNode* node, int* lx, int* ly) {
+ if (!node->pSurface || !node->pSurface->exists())
+ return;
+
*lx += node->pSurface->wlr()->current.dx;
*ly += node->pSurface->wlr()->current.dy;
@@ -181,6 +184,9 @@ void Events::listener_unmapSubsurface(void* owner, void* data) {
Debug::log(LOG, "Subsurface %x unmapped", subsurface);
+ if (subsurface->pSubsurface->surface == g_pCompositor->m_pLastFocus)
+ g_pInputManager->releaseAllMouseButtons();
+
if (subsurface->pChild) {
const auto PNODE = subsurface->pChild;
diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp
index c9260f19..53340e55 100644
--- a/src/layout/IHyprLayout.cpp
+++ b/src/layout/IHyprLayout.cpp
@@ -404,6 +404,11 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
g_pCompositor->moveWindowToTop(pWindow);
+ if (DELTALESSTHAN(pWindow->m_vRealSize.vec().x, pWindow->m_vLastFloatingSize.x, 10) && DELTALESSTHAN(pWindow->m_vRealSize.vec().y, pWindow->m_vLastFloatingSize.y, 10)) {
+ pWindow->m_vRealPosition = pWindow->m_vRealPosition.goalv() + (pWindow->m_vRealSize.goalv() - pWindow->m_vLastFloatingSize) / 2.f + Vector2D{10, 10};
+ pWindow->m_vRealSize = pWindow->m_vLastFloatingSize - Vector2D{20, 20};
+ }
+
pWindow->m_vRealPosition = pWindow->m_vRealPosition.goalv() + (pWindow->m_vRealSize.goalv() - pWindow->m_vLastFloatingSize) / 2.f;
pWindow->m_vRealSize = pWindow->m_vLastFloatingSize;
diff --git a/src/main.cpp b/src/main.cpp
index 669ece50..99066429 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -3,11 +3,26 @@
#include "Compositor.hpp"
#include "config/ConfigManager.hpp"
#include "init/initHelpers.hpp"
+
#include <iostream>
+#include <iterator>
+#include <vector>
+#include <stdexcept>
+#include <string>
+#include <filesystem>
+
#ifdef USES_SYSTEMD
#include <systemd/sd-daemon.h> // for sd_notify
#endif
+void help() {
+ std::cout << "usage: Hyprland [arg [...]].\n";
+ std::cout << "\nArguments:\n";
+ std::cout << " --help -h - Show this message again\n";
+ std::cout << " --config FILE -c FILE - Specify config file to use\n";
+ std::cout << " --i-am-really-stupid - Omits root user privileges check (why would you do that?)\n";
+}
+
int main(int argc, char** argv) {
if (!getenv("XDG_RUNTIME_DIR"))
@@ -17,6 +32,7 @@ int main(int argc, char** argv) {
std::string cmd = "";
for (auto i = 0; i < argc; ++i)
cmd += std::string(i == 0 ? "" : " ") + argv[i];
+
setenv("HYPRLAND_CMD", cmd.c_str(), 1);
setenv("XDG_BACKEND", "wayland", 1);
setenv("_JAVA_AWT_WM_NONREPARENTING", "1", 1);
@@ -24,30 +40,45 @@ int main(int argc, char** argv) {
setenv("XDG_CURRENT_DESKTOP", "Hyprland", 1);
// parse some args
- std::string configPath;
- bool ignoreSudo = false;
- for (int i = 1; i < argc; ++i) {
- if (!strcmp(argv[i], "--i-am-really-stupid"))
+ std::string configPath;
+ bool ignoreSudo = false;
+
+ std::vector<std::string> args{argv + 1, argv + argc};
+
+ for (auto it = args.begin(); it != args.end(); it++) {
+ if (it->compare("--i-am-really-stupid") == 0 && !ignoreSudo) {
+ std::cout << "[ WARNING ] Running Hyprland with superuser privileges might damage your system\n";
+
ignoreSudo = true;
- else if ((!strcmp(argv[i], "-c") || !strcmp(argv[i], "--config")) && argc >= i + 2) {
- configPath = std::string(argv[++i]);
- Debug::log(LOG, "Using config location %s.", configPath.c_str());
- } else {
- std::cout << "Hyprland usage: Hyprland [arg [...]].\n\nArguments:\n"
- << "--help -h | Show this help message\n"
- << "--config -c | Specify config file to use\n";
- return 1;
}
- }
- if (!ignoreSudo) {
- if (Init::isSudo()) {
- 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;
+ else if (it->compare("-c") == 0 || it->compare("--config") == 0) {
+ if (std::next(it)->c_str() == nullptr) {
+ help();
+ return 1;
+ }
+ std::string next_arg = std::next(it)->c_str();
+
+ if (!std::filesystem::exists(next_arg)) {
+ std::cerr << "[ ERROR ] Config path '" << next_arg << "' doesn't exist!\n";
+ help();
+
+ return 1;
+ }
+
+ configPath = next_arg;
+ Debug::log(LOG, "User-specified config location: '%s'", configPath.c_str());
+ continue;
}
- } else {
- std::cout << "Running with ignored root checks, I surely hope you know what you're doing.\n";
- sleep(1);
+ }
+
+ if (!ignoreSudo && Init::isSudo()) {
+ std::cerr << "[ ERROR ] Hyprland was launched with superuser priveleges, but the privileges check is not omitted.\n";
+ std::cerr << " Hint: Use the --i-am-really-stupid flag to omit that check.\n";
+
+ return 1;
+ } else if (ignoreSudo && Init::isSudo()) {
+ std::cout << "Superuser privileges check is omitted. I hope you know what you're doing.\n";
}
std::cout << "Welcome to Hyprland!\n";
diff --git a/src/managers/EventManager.cpp b/src/managers/EventManager.cpp
index 81acd379..3fd63fcb 100644
--- a/src/managers/EventManager.cpp
+++ b/src/managers/EventManager.cpp
@@ -12,14 +12,15 @@
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
+#include <sys/ioctl.h>
#include <string>
CEventManager::CEventManager() {}
int fdHandleWrite(int fd, uint32_t mask, void* data) {
- if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP) {
- // remove, hanged up
+
+ auto removeFD = [&](int fd) -> void {
const auto ACCEPTEDFDS = (std::deque<std::pair<int, wl_event_source*>>*)data;
for (auto it = ACCEPTEDFDS->begin(); it != ACCEPTEDFDS->end();) {
if (it->first == fd) {
@@ -29,6 +30,27 @@ int fdHandleWrite(int fd, uint32_t mask, void* data) {
it++;
}
}
+ };
+
+ if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP) {
+ // remove, hanged up
+ removeFD(fd);
+ return 0;
+ }
+
+ int availableBytes;
+ if (ioctl(fd, FIONREAD, &availableBytes) == -1) {
+ Debug::log(ERR, "fd %d sent invalid data (1)", fd);
+ removeFD(fd);
+ return 0;
+ }
+
+ char buf[availableBytes];
+ const auto RECEIVED = recv(fd, buf, availableBytes, 0);
+ if (RECEIVED == -1) {
+ Debug::log(ERR, "fd %d sent invalid data (2)", fd);
+ removeFD(fd);
+ return 0;
}
return 0;
diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp
index 53a76cfc..0f99f2e4 100644
--- a/src/managers/KeybindManager.cpp
+++ b/src/managers/KeybindManager.cpp
@@ -104,7 +104,7 @@ uint32_t CKeybindManager::stringToModMask(std::string mods) {
modMask |= WLR_MODIFIER_CAPS;
if (mods.contains("CTRL") || mods.contains("CONTROL"))
modMask |= WLR_MODIFIER_CTRL;
- if (mods.contains("ALT"))
+ if (mods.contains("ALT") || mods.contains("MOD1"))
modMask |= WLR_MODIFIER_ALT;
if (mods.contains("MOD2"))
modMask |= WLR_MODIFIER_MOD2;
@@ -386,7 +386,7 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string&
// Should never happen, as we check in the ConfigManager, but oh well
if (DISPATCHER == m_mDispatchers.end()) {
- Debug::log(ERR, "Inavlid handler in a keybind! (handler %s does not exist)", k.handler.c_str());
+ Debug::log(ERR, "Invalid handler in a keybind! (handler %s does not exist)", k.handler.c_str());
} else {
// call the dispatcher
Debug::log(LOG, "Keybind triggered, calling dispatcher (%d, %s, %d)", modmask, key.c_str(), keysym);
@@ -473,11 +473,11 @@ bool CKeybindManager::handleVT(xkb_keysym_t keysym) {
// vtnr is bugged for some reason.
unsigned int ttynum = 0;
-#if defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__)
+#if defined(VT_GETSTATE)
struct vt_stat st;
if (!ioctl(0, VT_GETSTATE, &st))
ttynum = st.v_active;
-#elif defined(__DragonFly__) || defined(__FreeBSD__)
+#elif defined(VT_GETACTIVE)
int vt;
if (!ioctl(0, VT_GETACTIVE, &vt))
ttynum = vt;
@@ -1154,7 +1154,8 @@ void CKeybindManager::moveFocusTo(std::string args) {
}
};
- const auto PWINDOWTOCHANGETO = g_pCompositor->getWindowInDirection(PLASTWINDOW, arg);
+ const auto PWINDOWTOCHANGETO = PLASTWINDOW->m_bIsFullscreen ? g_pCompositor->getNextWindowOnWorkspace(PLASTWINDOW, arg == 'u' || arg == 't' || arg == 'r') :
+ g_pCompositor->getWindowInDirection(PLASTWINDOW, arg);
if (PWINDOWTOCHANGETO) {
switchToWindow(PWINDOWTOCHANGETO);
@@ -1927,7 +1928,7 @@ void CKeybindManager::toggleOpaque(std::string unused) {
return;
PWINDOW->m_sAdditionalConfigData.forceOpaque = !PWINDOW->m_sAdditionalConfigData.forceOpaque;
- PWINDOW->m_sAdditionalConfigData.forceOpaqueOverriden = true;
+ PWINDOW->m_sAdditionalConfigData.forceOpaqueOverridden = true;
g_pHyprRenderer->damageWindow(PWINDOW);
}
diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp
index 647f007f..205f3d02 100644
--- a/src/managers/ProtocolManager.cpp
+++ b/src/managers/ProtocolManager.cpp
@@ -5,4 +5,5 @@ CProtocolManager::CProtocolManager() {
m_pFractionalScaleProtocolManager = std::make_unique<CFractionalScaleProtocolManager>();
m_pTextInputV1ProtocolManager = std::make_unique<CTextInputV1ProtocolManager>();
m_pGlobalShortcutsProtocolManager = std::make_unique<CGlobalShortcutsProtocolManager>();
+ m_pScreencopyProtocolManager = std::make_unique<CScreencopyProtocolManager>();
} \ No newline at end of file
diff --git a/src/managers/ProtocolManager.hpp b/src/managers/ProtocolManager.hpp
index b4770930..bc6b776e 100644
--- a/src/managers/ProtocolManager.hpp
+++ b/src/managers/ProtocolManager.hpp
@@ -5,6 +5,7 @@
#include "../protocols/FractionalScale.hpp"
#include "../protocols/TextInputV1.hpp"
#include "../protocols/GlobalShortcuts.hpp"
+#include "../protocols/Screencopy.hpp"
class CProtocolManager {
public:
@@ -14,6 +15,7 @@ class CProtocolManager {
std::unique_ptr<CFractionalScaleProtocolManager> m_pFractionalScaleProtocolManager;
std::unique_ptr<CTextInputV1ProtocolManager> m_pTextInputV1ProtocolManager;
std::unique_ptr<CGlobalShortcutsProtocolManager> m_pGlobalShortcutsProtocolManager;
+ std::unique_ptr<CScreencopyProtocolManager> m_pScreencopyProtocolManager;
};
inline std::unique_ptr<CProtocolManager> g_pProtocolManager;
diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp
index 5929e7ff..44e3aa7f 100644
--- a/src/managers/input/InputManager.cpp
+++ b/src/managers/input/InputManager.cpp
@@ -58,6 +58,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
static auto* const PRESIZECURSORICON = &g_pConfigManager->getConfigValuePtr("general:hover_icon_on_border")->intValue;
const auto BORDER_GRAB_AREA = *PRESIZEONBORDER ? *PBORDERSIZE + *PBORDERGRABEXTEND : 0;
+ const auto FOLLOWMOUSE = *PFOLLOWONDND && m_sDrag.drag ? 1 : *PFOLLOWMOUSE;
+
m_pFoundSurfaceToFocus = nullptr;
m_pFoundLSToFocus = nullptr;
m_pFoundWindowToFocus = nullptr;
@@ -143,6 +145,33 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
// update stuff
updateDragIcon();
+ if (!m_sDrag.drag && !m_lCurrentlyHeldButtons.empty() && g_pCompositor->m_pLastFocus) {
+ if (m_bLastFocusOnLS) {
+ foundSurface = g_pCompositor->m_pLastFocus;
+ pFoundLayerSurface = g_pCompositor->getLayerSurfaceFromSurface(foundSurface);
+ if (pFoundLayerSurface) {
+ surfacePos = g_pCompositor->getLayerSurfaceFromSurface(foundSurface)->position;
+ m_bFocusHeldByButtons = true;
+ m_bRefocusHeldByButtons = refocus;
+ } else {
+ // ?
+ foundSurface = nullptr;
+ pFoundLayerSurface = nullptr;
+ }
+ } else if (g_pCompositor->m_pLastWindow) {
+ foundSurface = g_pCompositor->m_pLastFocus;
+ pFoundWindow = g_pCompositor->m_pLastWindow;
+
+ if (!g_pCompositor->m_pLastWindow->m_bIsX11)
+ foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, g_pCompositor->m_pLastWindow, surfaceCoords);
+ else
+ surfacePos = g_pCompositor->m_pLastWindow->m_vRealPosition.vec();
+
+ m_bFocusHeldByButtons = true;
+ m_bRefocusHeldByButtons = refocus;
+ }
+ }
+
g_pLayoutManager->getCurrentLayout()->onMouseMove(getMouseCoordsInternal());
if (PMONITOR && PMONITOR != g_pCompositor->m_pLastMonitor && (*PMOUSEFOCUSMON || refocus)) {
@@ -309,8 +338,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
setCursorIconOnBorder(pFoundWindow);
}
- // if we're on an input deco, reset cursor. Don't on overriden
- // if (!m_bCursorImageOverriden) {
+ // if we're on an input deco, reset cursor. Don't on overridden
+ // if (!m_bCursorImageOverridden) {
// if (!VECINRECT(m_vLastCursorPosFloored, pFoundWindow->m_vRealPosition.vec().x, pFoundWindow->m_vRealPosition.vec().y,
// pFoundWindow->m_vRealPosition.vec().x + pFoundWindow->m_vRealSize.vec().x, pFoundWindow->m_vRealPosition.vec().y + pFoundWindow->m_vRealSize.vec().y)) {
// wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", g_pCompositor->m_sWLRCursor);
@@ -321,14 +350,14 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
// }
// }
- if (*PFOLLOWMOUSE != 1 && !refocus) {
+ if (FOLLOWMOUSE != 1 && !refocus) {
if (pFoundWindow != g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow &&
((pFoundWindow->m_bIsFloating && *PFLOATBEHAVIOR == 2) || (g_pCompositor->m_pLastWindow->m_bIsFloating != pFoundWindow->m_bIsFloating && *PFLOATBEHAVIOR != 0))) {
// enter if change floating style
- if (*PFOLLOWMOUSE != 3 && allowKeyboardRefocus)
+ if (FOLLOWMOUSE != 3 && allowKeyboardRefocus)
g_pCompositor->focusWindow(pFoundWindow, foundSurface);
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
- } else if (*PFOLLOWMOUSE == 2 || *PFOLLOWMOUSE == 3) {
+ } else if (FOLLOWMOUSE == 2 || FOLLOWMOUSE == 3) {
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
}
@@ -339,17 +368,13 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
}
}
- if (*PFOLLOWONDND && m_sDrag.dragIcon) {
- wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
- }
-
- if (*PFOLLOWMOUSE != 0 || pFoundWindow == g_pCompositor->m_pLastWindow)
+ if (FOLLOWMOUSE != 0 || pFoundWindow == g_pCompositor->m_pLastWindow)
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y);
m_bLastFocusOnLS = false;
return; // don't enter any new surfaces
} else {
- if ((*PFOLLOWMOUSE != 3 && allowKeyboardRefocus) || refocus)
+ if ((FOLLOWMOUSE != 3 && allowKeyboardRefocus) || refocus)
g_pCompositor->focusWindow(pFoundWindow, foundSurface);
}
@@ -360,7 +385,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
unsetCursorImage();
}
- if (pFoundLayerSurface && pFoundLayerSurface->layerSurface->current.keyboard_interactive && *PFOLLOWMOUSE != 3 && allowKeyboardRefocus) {
+ if (pFoundLayerSurface && (pFoundLayerSurface->layerSurface->current.keyboard_interactive || pFoundLayerSurface->layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) &&
+ FOLLOWMOUSE != 3 && allowKeyboardRefocus) {
g_pCompositor->focusSurface(foundSurface);
}
@@ -392,6 +418,16 @@ void CInputManager::onMouseButton(wlr_pointer_button_event* e) {
case CLICKMODE_KILL: processMouseDownKill(e); break;
default: break;
}
+
+ if (m_bFocusHeldByButtons && m_lCurrentlyHeldButtons.empty() && e->state == WLR_BUTTON_RELEASED) {
+ if (m_bRefocusHeldByButtons)
+ refocus();
+ else
+ simulateMouseMovement();
+
+ m_bFocusHeldByButtons = false;
+ m_bRefocusHeldByButtons = false;
+ }
}
void CInputManager::processMouseRequest(wlr_seat_pointer_request_set_cursor_event* e) {
@@ -404,7 +440,7 @@ void CInputManager::processMouseRequest(wlr_seat_pointer_request_set_cursor_even
g_pHyprRenderer->m_bWindowRequestedCursorHide = false;
}
- if (m_bCursorImageOverriden) {
+ if (m_bCursorImageOverridden) {
return;
}
@@ -483,8 +519,17 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
if (*PFOLLOWMOUSE == 3) // don't refocus on full loose
break;
- if (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint)
- refocus();
+ if (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint) {
+ // a bit hacky
+ // if we only pressed one button, allow us to refocus. m_lCurrentlyHeldButtons.size() > 0 will stick the focus
+ if (m_lCurrentlyHeldButtons.size() == 1) {
+ const auto COPY = m_lCurrentlyHeldButtons;
+ m_lCurrentlyHeldButtons.clear();
+ refocus();
+ m_lCurrentlyHeldButtons = COPY;
+ } else
+ refocus();
+ }
// if clicked on a floating window make it top
if (g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->m_bIsFloating)
@@ -1338,14 +1383,14 @@ void CInputManager::destroySwitch(SSwitchDevice* pDevice) {
void CInputManager::setCursorImageUntilUnset(std::string name) {
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, name.c_str(), g_pCompositor->m_sWLRCursor);
- m_bCursorImageOverriden = true;
+ m_bCursorImageOverridden = true;
}
void CInputManager::unsetCursorImage() {
- if (!m_bCursorImageOverriden)
+ if (!m_bCursorImageOverridden)
return;
- m_bCursorImageOverriden = false;
+ m_bCursorImageOverridden = false;
if (!g_pHyprRenderer->m_bWindowRequestedCursorHide)
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", g_pCompositor->m_sWLRCursor);
}
@@ -1417,14 +1462,19 @@ void CInputManager::setCursorIconOnBorder(CWindow* w) {
return;
}
- static auto* const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
- static const auto* PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
+ static auto* const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue;
+ static const auto* PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
+ static const auto* PEXTENDBORDERGRAB = &g_pConfigManager->getConfigValuePtr("general:extend_border_grab_area")->intValue;
// give a small leeway (10 px) for corner icon
- const auto CORNER = *PROUNDING + *PBORDERSIZE + 10;
- const auto mouseCoords = getMouseCoordsInternal();
- wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
- eBorderIconDirection direction = BORDERICON_NONE;
- if (wlr_box_contains_point(&box, mouseCoords.x, mouseCoords.y)) {
+ const auto CORNER = *PROUNDING + *PBORDERSIZE + 10;
+ const auto mouseCoords = getMouseCoordsInternal();
+ wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
+ eBorderIconDirection direction = BORDERICON_NONE;
+ wlr_box boxFullGrabInput = {box.x - *PEXTENDBORDERGRAB, box.y - *PEXTENDBORDERGRAB, box.width + 2 * *PEXTENDBORDERGRAB, box.height + 2 * *PEXTENDBORDERGRAB};
+
+ if (!wlr_box_contains_point(&boxFullGrabInput, mouseCoords.x, mouseCoords.y) || (!m_lCurrentlyHeldButtons.empty() && !currentlyDraggedWindow)) {
+ direction = BORDERICON_NONE;
+ } else if (wlr_box_contains_point(&box, mouseCoords.x, mouseCoords.y)) {
if (!w->isInCurvedCorner(mouseCoords.x, mouseCoords.y)) {
direction = BORDERICON_NONE;
} else {
diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp
index fd5edf12..a98ad497 100644
--- a/src/managers/input/InputManager.hpp
+++ b/src/managers/input/InputManager.hpp
@@ -7,18 +7,21 @@
#include "../../helpers/Timer.hpp"
#include "InputMethodRelay.hpp"
-enum eClickBehaviorMode {
+enum eClickBehaviorMode
+{
CLICKMODE_DEFAULT = 0,
CLICKMODE_KILL
};
-enum eMouseBindMode {
+enum eMouseBindMode
+{
MBIND_INVALID = -1,
MBIND_MOVE = 0,
MBIND_RESIZE
};
-enum eBorderIconDirection {
+enum eBorderIconDirection
+{
BORDERICON_NONE,
BORDERICON_UP,
BORDERICON_DOWN,
@@ -154,8 +157,6 @@ class CInputManager {
// for shared mods
uint32_t accumulateModsFromAllKBs();
- CWindow* m_pFollowOnDnDBegin = nullptr;
-
// for virtual keyboards: whether we should respect them as normal ones
bool shouldIgnoreVirtualKeyboard(SKeyboard*);
@@ -175,8 +176,8 @@ class CInputManager {
bool m_bLastInputTouch = false;
private:
- bool m_bCursorImageOverriden = false;
- eBorderIconDirection m_eBorderIconDirection = BORDERICON_NONE;
+ bool m_bCursorImageOverridden = false;
+ eBorderIconDirection m_eBorderIconDirection = BORDERICON_NONE;
// for click behavior override
eClickBehaviorMode m_ecbClickBehavior = CLICKMODE_DEFAULT;
@@ -201,6 +202,10 @@ class CInputManager {
SLayerSurface* m_pFoundLSToFocus = nullptr;
CWindow* m_pFoundWindowToFocus = nullptr;
+ // for holding focus on buttons held
+ bool m_bFocusHeldByButtons = false;
+ bool m_bRefocusHeldByButtons = false;
+
// for releasing mouse buttons
std::list<uint32_t> m_lCurrentlyHeldButtons;
diff --git a/src/managers/input/Swipe.cpp b/src/managers/input/Swipe.cpp
index 596ec8f0..a3c429f9 100644
--- a/src/managers/input/Swipe.cpp
+++ b/src/managers/input/Swipe.cpp
@@ -6,7 +6,7 @@ void CInputManager::onSwipeBegin(wlr_pointer_swipe_begin_event* e) {
static auto* const PSWIPEFINGERS = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_fingers")->intValue;
static auto* const PSWIPENEW = &g_pConfigManager->getConfigValuePtr("gestures:workspace_swipe_create_new")->intValue;
- if (e->fingers != *PSWIPEFINGERS || *PSWIPE == 0)
+ if (e->fingers != *PSWIPEFINGERS || *PSWIPE == 0 || g_pSessionLockManager->isSessionLocked())
return;
int onMonitor = 0;
@@ -56,9 +56,21 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
auto workspaceIDLeft = getWorkspaceIDFromString(*PSWIPENUMBER ? "-1" : "m-1", wsname);
auto workspaceIDRight = getWorkspaceIDFromString(*PSWIPENUMBER ? "+1" : "m+1", wsname);
- if ((workspaceIDRight <= m_sActiveSwipe.pWorkspaceBegin->m_iID || (workspaceIDRight == workspaceIDLeft && workspaceIDLeft == m_sActiveSwipe.pWorkspaceBegin->m_iID)) &&
- *PSWIPENEW) {
- workspaceIDRight = m_sActiveSwipe.pWorkspaceBegin->m_iID > 0 ? m_sActiveSwipe.pWorkspaceBegin->m_iID + 1 : 1;
+ // If we've been swiping off the right end with PSWIPENEW enabled, there is
+ // no workspace there yet, and we need to choose an ID for a new one now.
+ // With multiple monitors, it might not be appropriate to choose one more
+ // than the ID of the workspace we're swiping from, because that ID might
+ // just be on another monitor. It's also not just the smallest unused ID,
+ // because that could be a gap in the existing workspace numbers, and it'd
+ // be counterintuitive to swipe rightwards onto a new workspace and end up
+ // left of where we started. Instead, it's one more than the greatest
+ // workspace ID that currently exists.
+ if (workspaceIDRight <= m_sActiveSwipe.pWorkspaceBegin->m_iID && *PSWIPENEW) {
+ int maxWorkspace = 0;
+ for (const auto& ws : g_pCompositor->m_vWorkspaces) {
+ maxWorkspace = std::max(maxWorkspace, ws->m_iID);
+ }
+ workspaceIDRight = maxWorkspace + 1;
}
auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); // not guaranteed if PSWIPENEW || PSWIPENUMBER
@@ -305,4 +317,4 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
beginWorkspaceSwipe();
}
}
-} \ No newline at end of file
+}
diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp
index 70bae3b2..9f8f0e04 100644
--- a/src/managers/input/Touch.cpp
+++ b/src/managers/input/Touch.cpp
@@ -62,7 +62,7 @@ void CInputManager::onTouchMove(wlr_touch_motion_event* e) {
if (m_sTouchData.touchFocusWindow && g_pCompositor->windowValidMapped(m_sTouchData.touchFocusWindow)) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusWindow->m_iMonitorID);
- wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x,
+ wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x,
PMONITOR->vecPosition.y + e->y * PMONITOR->vecSize.y);
const auto local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchSurfaceOrigin;
@@ -72,7 +72,7 @@ void CInputManager::onTouchMove(wlr_touch_motion_event* e) {
} else if (m_sTouchData.touchFocusLS) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusLS->monitorID);
- wlr_cursor_warp(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x,
+ wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x,
PMONITOR->vecPosition.y + e->y * PMONITOR->vecSize.y);
const auto local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchSurfaceOrigin;
diff --git a/src/plugins/PluginAPI.cpp b/src/plugins/PluginAPI.cpp
index c878516b..f26c7b9d 100644
--- a/src/plugins/PluginAPI.cpp
+++ b/src/plugins/PluginAPI.cpp
@@ -3,6 +3,12 @@
#include "../debug/HyprCtl.hpp"
#include <dlfcn.h>
+#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__)
+#include <sys/sysctl.h>
+#endif
+
+#include <sstream>
+
APICALL bool HyprlandAPI::registerCallbackStatic(HANDLE handle, const std::string& event, HOOK_CALLBACK_FN* fn) {
auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle);
@@ -240,4 +246,77 @@ APICALL bool addNotificationV2(HANDLE handle, const std::unordered_map<std::stri
}
return true;
+}
+
+APICALL std::vector<SFunctionMatch> HyprlandAPI::findFunctionsByName(HANDLE handle, const std::string& name) {
+ auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle);
+
+ if (!PLUGIN)
+ return std::vector<SFunctionMatch>{};
+
+#if defined(KERN_PROC_PATHNAME)
+ int mib[] = {
+ CTL_KERN,
+#if defined(__NetBSD__)
+ KERN_PROC_ARGS,
+ -1,
+ KERN_PROC_PATHNAME,
+#else
+ KERN_PROC,
+ KERN_PROC_PATHNAME,
+ -1,
+#endif
+ };
+ u_int miblen = sizeof(mib) / sizeof(mib[0]);
+ char exe[PATH_MAX] = "";
+ size_t sz = sizeof(exe);
+ sysctl(mib, miblen, &exe, &sz, NULL, 0);
+ const auto FPATH = std::filesystem::canonical(exe);
+#elif defined(__OpenBSD__)
+ // Neither KERN_PROC_PATHNAME nor /proc are supported
+ const auto FPATH = std::filesystem::canonical("/usr/local/bin/Hyprland");
+#else
+ const auto FPATH = std::filesystem::canonical("/proc/self/exe");
+#endif
+
+#ifdef __clang__
+ const auto SYMBOLS = execAndGet(("llvm-nm -D -j " + FPATH.string()).c_str());
+ const auto SYMBOLSDEMANGLED = execAndGet(("llvm-nm -D -j --demangle " + FPATH.string()).c_str());
+#else
+ const auto SYMBOLS = execAndGet(("nm -D -j " + FPATH.string()).c_str());
+ const auto SYMBOLSDEMANGLED = execAndGet(("nm -D -j --demangle=auto " + FPATH.string()).c_str());
+#endif
+
+ auto demangledFromID = [&](size_t id) -> std::string {
+ size_t pos = 0;
+ size_t count = 0;
+ while (count < id) {
+ pos++;
+ pos = SYMBOLSDEMANGLED.find('\n', pos);
+ if (pos == std::string::npos)
+ return "";
+ count++;
+ }
+
+ return SYMBOLSDEMANGLED.substr(pos, SYMBOLSDEMANGLED.find('\n', pos + 1) - pos);
+ };
+
+ std::vector<SFunctionMatch> matches;
+
+ std::istringstream inStream(SYMBOLS);
+ std::string line;
+ int lineNo = 0;
+ while (std::getline(inStream, line)) {
+ if (line.contains(name)) {
+ void* address = dlsym(nullptr, line.c_str());
+
+ if (!address)
+ continue;
+
+ matches.push_back({address, line, demangledFromID(lineNo)});
+ }
+ lineNo++;
+ }
+
+ return matches;
} \ No newline at end of file
diff --git a/src/plugins/PluginAPI.hpp b/src/plugins/PluginAPI.hpp
index 813d7462..ca8b662f 100644
--- a/src/plugins/PluginAPI.hpp
+++ b/src/plugins/PluginAPI.hpp
@@ -33,6 +33,12 @@ typedef struct {
std::string version;
} PLUGIN_DESCRIPTION_INFO;
+struct SFunctionMatch {
+ void* address = nullptr;
+ std::string signature;
+ std::string demangled;
+};
+
#define APICALL extern "C"
#define EXPORT __attribute__((visibility("default")))
#define REQUIRED
@@ -185,8 +191,10 @@ namespace HyprlandAPI {
This is useful for hooking private functions.
returns: function address, or nullptr on fail.
+
+ Deprecated because of findFunctionsByName.
*/
- APICALL void* getFunctionAddressFromSignature(HANDLE handle, const std::string& sig);
+ APICALL [[deprecated]] void* getFunctionAddressFromSignature(HANDLE handle, const std::string& sig);
/*
Adds a window decoration to a window
@@ -230,4 +238,13 @@ namespace HyprlandAPI {
returns: true on success. False otherwise.
*/
APICALL bool addNotificationV2(HANDLE handle, const std::unordered_map<std::string, std::any>& data);
+
+ /*
+ Returns a vector of found functions matching the provided name.
+
+ These addresses will not change, and should be made static. Lookups are slow.
+
+ Empty means either none found or handle was invalid
+ */
+ APICALL std::vector<SFunctionMatch> findFunctionsByName(HANDLE handle, const std::string& name);
}; \ No newline at end of file
diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp
new file mode 100644
index 00000000..a697abc9
--- /dev/null
+++ b/src/protocols/Screencopy.cpp
@@ -0,0 +1,414 @@
+#include "Screencopy.hpp"
+#include "../Compositor.hpp"
+#include <drm_fourcc.h>
+
+#include <algorithm>
+
+#include "ToplevelExportWlrFuncs.hpp"
+
+#define SCREENCOPY_VERSION 3
+
+static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint32_t id) {
+ g_pProtocolManager->m_pScreencopyProtocolManager->bindManager(client, data, version, id);
+}
+
+static void handleDisplayDestroy(struct wl_listener* listener, void* data) {
+ g_pProtocolManager->m_pScreencopyProtocolManager->displayDestroy();
+}
+
+void CScreencopyProtocolManager::displayDestroy() {
+ wl_global_destroy(m_pGlobal);
+}
+
+static SScreencopyFrame* frameFromResource(wl_resource*);
+
+CScreencopyProtocolManager::CScreencopyProtocolManager() {
+
+ m_pGlobal = wl_global_create(g_pCompositor->m_sWLDisplay, &zwlr_screencopy_manager_v1_interface, SCREENCOPY_VERSION, this, bindManagerInt);
+
+ if (!m_pGlobal) {
+ Debug::log(ERR, "ScreencopyProtocolManager could not start! Screensharing will not work!");
+ return;
+ }
+
+ m_liDisplayDestroy.notify = handleDisplayDestroy;
+ wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy);
+
+ Debug::log(LOG, "ScreencopyProtocolManager started successfully!");
+}
+
+static void handleCaptureOutput(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* output) {
+ g_pProtocolManager->m_pScreencopyProtocolManager->captureOutput(client, resource, frame, overlay_cursor, output);
+}
+
+static void handleCaptureRegion(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* output, int32_t x, int32_t y, int32_t width,
+ int32_t height) {
+ g_pProtocolManager->m_pScreencopyProtocolManager->captureOutput(client, resource, frame, overlay_cursor, output, {x, y, width, height});
+}
+
+static void handleDestroy(wl_client* client, wl_resource* resource) {
+ wl_resource_destroy(resource);
+}
+
+static void handleCopyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer) {
+ g_pProtocolManager->m_pScreencopyProtocolManager->copyFrame(client, resource, buffer);
+}
+
+static void handleCopyWithDamage(wl_client* client, wl_resource* resource, wl_resource* buffer) {
+ const auto PFRAME = frameFromResource(resource);
+ PFRAME->withDamage = true;
+ handleCopyFrame(client, resource, buffer);
+}
+
+static void handleDestroyFrame(wl_client* client, wl_resource* resource) {
+ wl_resource_destroy(resource);
+}
+
+static const struct zwlr_screencopy_manager_v1_interface screencopyMgrImpl = {
+ .capture_output = handleCaptureOutput,
+ .capture_output_region = handleCaptureRegion,
+ .destroy = handleDestroy,
+};
+
+static const struct zwlr_screencopy_frame_v1_interface screencopyFrameImpl = {
+ .copy = handleCopyFrame,
+ .destroy = handleDestroyFrame,
+ .copy_with_damage = handleCopyWithDamage,
+};
+
+static SScreencopyClient* clientFromResource(wl_resource* resource) {
+ ASSERT(wl_resource_instance_of(resource, &zwlr_screencopy_manager_v1_interface, &screencopyMgrImpl));
+ return (SScreencopyClient*)wl_resource_get_user_data(resource);
+}
+
+static SScreencopyFrame* frameFromResource(wl_resource* resource) {
+ ASSERT(wl_resource_instance_of(resource, &zwlr_screencopy_frame_v1_interface, &screencopyFrameImpl));
+ return (SScreencopyFrame*)wl_resource_get_user_data(resource);
+}
+
+void CScreencopyProtocolManager::removeClient(SScreencopyClient* client, bool force) {
+ if (!force) {
+ if (!client || client->ref <= 0)
+ return;
+
+ if (--client->ref != 0)
+ return;
+ }
+
+ m_lClients.remove(*client); // TODO: this doesn't get cleaned up after sharing app exits???
+}
+
+static void handleManagerResourceDestroy(wl_resource* resource) {
+ const auto PCLIENT = clientFromResource(resource);
+
+ g_pProtocolManager->m_pScreencopyProtocolManager->removeClient(PCLIENT, true);
+}
+
+void CScreencopyProtocolManager::bindManager(wl_client* client, void* data, uint32_t version, uint32_t id) {
+ const auto PCLIENT = &m_lClients.emplace_back();
+
+ PCLIENT->resource = wl_resource_create(client, &zwlr_screencopy_manager_v1_interface, version, id);
+
+ if (!PCLIENT->resource) {
+ Debug::log(ERR, "ScreencopyProtocolManager could not bind! (out of memory?)");
+ m_lClients.remove(*PCLIENT);
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ PCLIENT->ref = 1;
+
+ wl_resource_set_implementation(PCLIENT->resource, &screencopyMgrImpl, PCLIENT, handleManagerResourceDestroy);
+
+ Debug::log(LOG, "ScreencopyProtocolManager bound successfully!");
+}
+
+static void handleFrameResourceDestroy(wl_resource* resource) {
+ const auto PFRAME = frameFromResource(resource);
+
+ g_pProtocolManager->m_pScreencopyProtocolManager->removeFrame(PFRAME);
+}
+
+void CScreencopyProtocolManager::removeFrame(SScreencopyFrame* frame, bool force) {
+ if (!frame)
+ return;
+
+ std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other == frame; });
+
+ wl_resource_set_user_data(frame->resource, nullptr);
+ if (frame->buffer && frame->buffer->n_locks > 0)
+ wlr_buffer_unlock(frame->buffer);
+ removeClient(frame->client, force);
+ m_lFrames.remove(*frame);
+}
+
+void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* output, wlr_box box) {
+ const auto PCLIENT = clientFromResource(resource);
+
+ const auto PFRAME = &m_lFrames.emplace_back();
+ PFRAME->overlayCursor = !!overlay_cursor;
+ PFRAME->resource = wl_resource_create(client, &zwlr_screencopy_frame_v1_interface, wl_resource_get_version(resource), frame);
+ PFRAME->pMonitor = g_pCompositor->getMonitorFromOutput(wlr_output_from_resource(output));
+
+ if (!PFRAME->pMonitor) {
+ Debug::log(ERR, "client requested sharing of a monitor that doesnt exist");
+ zwlr_screencopy_frame_v1_send_failed(PFRAME->resource);
+ removeFrame(PFRAME);
+ return;
+ }
+
+ if (!PFRAME->resource) {
+ Debug::log(ERR, "Couldn't alloc frame for sharing! (no memory)");
+ removeFrame(PFRAME);
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ wl_resource_set_implementation(PFRAME->resource, &screencopyFrameImpl, PFRAME, handleFrameResourceDestroy);
+
+ PFRAME->client = PCLIENT;
+ PCLIENT->ref++;
+
+ PFRAME->shmFormat = wlr_output_preferred_read_format(PFRAME->pMonitor->output);
+ if (PFRAME->shmFormat == DRM_FORMAT_INVALID) {
+ Debug::log(ERR, "No format supported by renderer in capture output");
+ zwlr_screencopy_frame_v1_send_failed(PFRAME->resource);
+ removeFrame(PFRAME);
+ return;
+ }
+
+ const auto PSHMINFO = drm_get_pixel_format_info(PFRAME->shmFormat);
+ if (!PSHMINFO) {
+ Debug::log(ERR, "No pixel format supported by renderer in capture output");
+ zwlr_screencopy_frame_v1_send_failed(PFRAME->resource);
+ removeFrame(PFRAME);
+ return;
+ }
+
+ if (PFRAME->pMonitor->output->allocator && (PFRAME->pMonitor->output->allocator->buffer_caps & WLR_BUFFER_CAP_DMABUF)) {
+ PFRAME->dmabufFormat = PFRAME->pMonitor->output->render_format;
+ } else {
+ PFRAME->dmabufFormat = DRM_FORMAT_INVALID;
+ }
+
+ if (box.width == 0 && box.height == 0)
+ PFRAME->box = {0, 0, (int)(PFRAME->pMonitor->vecSize.x * PFRAME->pMonitor->scale), (int)(PFRAME->pMonitor->vecSize.y * PFRAME->pMonitor->scale)};
+ else {
+ PFRAME->box = box;
+ scaleBox(&PFRAME->box, PFRAME->pMonitor->scale);
+ }
+ int ow, oh;
+ wlr_output_effective_resolution(PFRAME->pMonitor->output, &ow, &oh);
+ wlr_box_transform(&PFRAME->box, &PFRAME->box, PFRAME->pMonitor->transform, ow, oh);
+
+ PFRAME->shmStride = (PSHMINFO->bpp / 8) * PFRAME->box.width;
+
+ zwlr_screencopy_frame_v1_send_buffer(PFRAME->resource, convert_drm_format_to_wl_shm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride);
+
+ if (wl_resource_get_version(resource) >= 3) {
+ // todo
+ // if (PFRAME->dmabufFormat != DRM_FORMAT_INVALID) {
+ // zwlr_screencopy_frame_v1_send_linux_dmabuf(PFRAME->resource, PFRAME->dmabufFormat, PFRAME->box.width, PFRAME->box.height);
+ // }
+
+ zwlr_screencopy_frame_v1_send_buffer_done(PFRAME->resource);
+ }
+}
+
+void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer) {
+ const auto PFRAME = frameFromResource(resource);
+
+ if (!PFRAME) {
+ Debug::log(ERR, "No frame in copyFrame??");
+ return;
+ }
+
+ const auto PBUFFER = wlr_buffer_from_resource(buffer);
+ if (!PBUFFER) {
+ wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer");
+ removeFrame(PFRAME);
+ return;
+ }
+
+ if (PBUFFER->width != PFRAME->box.width || PBUFFER->height != PFRAME->box.height) {
+ wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions");
+ removeFrame(PFRAME);
+ return;
+ }
+
+ if (PFRAME->buffer) {
+ wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_ALREADY_USED, "frame already used");
+ removeFrame(PFRAME);
+ return;
+ }
+
+ wlr_dmabuf_attributes dmabufAttrs;
+ void* wlrBufferAccessData;
+ uint32_t wlrBufferAccessFormat;
+ size_t wlrBufferAccessStride;
+ if (wlr_buffer_get_dmabuf(PBUFFER, &dmabufAttrs)) {
+ PFRAME->bufferCap = WLR_BUFFER_CAP_DMABUF;
+
+ if (dmabufAttrs.format != PFRAME->dmabufFormat) {
+ wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format");
+ removeFrame(PFRAME);
+ return;
+ }
+ } else if (wlr_buffer_begin_data_ptr_access(PBUFFER, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &wlrBufferAccessData, &wlrBufferAccessFormat, &wlrBufferAccessStride)) {
+ wlr_buffer_end_data_ptr_access(PBUFFER);
+
+ if (wlrBufferAccessFormat != PFRAME->shmFormat) {
+ wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format");
+ removeFrame(PFRAME);
+ return;
+ } else if ((int)wlrBufferAccessStride != PFRAME->shmStride) {
+ wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer stride");
+ removeFrame(PFRAME);
+ return;
+ }
+ } else {
+ wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer type");
+ removeFrame(PFRAME);
+ return;
+ }
+
+ PFRAME->buffer = PBUFFER;
+
+ m_vFramesAwaitingWrite.emplace_back(PFRAME);
+
+ g_pHyprRenderer->m_bDirectScanoutBlocked = true;
+ if (PFRAME->overlayCursor)
+ g_pHyprRenderer->m_bSoftwareCursorsLocked = true;
+
+ if (!PFRAME->withDamage)
+ g_pCompositor->scheduleFrameForMonitor(PFRAME->pMonitor);
+}
+
+void CScreencopyProtocolManager::onRenderEnd(CMonitor* pMonitor) {
+ if (m_vFramesAwaitingWrite.empty())
+ return; // nothing to share
+
+ std::vector<SScreencopyFrame*> framesToRemove;
+
+ // share frame if correct output
+ for (auto& f : m_vFramesAwaitingWrite) {
+ if (!f->pMonitor) {
+ framesToRemove.push_back(f);
+ continue;
+ }
+
+ if (f->pMonitor != pMonitor)
+ continue;
+
+ shareFrame(f);
+
+ framesToRemove.push_back(f);
+ }
+
+ for (auto& f : framesToRemove) {
+ removeFrame(f);
+ }
+
+ g_pHyprRenderer->m_bSoftwareCursorsLocked = false;
+
+ if (m_vFramesAwaitingWrite.empty()) {
+ g_pHyprRenderer->m_bDirectScanoutBlocked = false;
+ } else {
+ for (auto& f : m_vFramesAwaitingWrite) {
+ if (f->overlayCursor) {
+ g_pHyprRenderer->m_bSoftwareCursorsLocked = true;
+ break;
+ }
+ }
+ }
+}
+
+void CScreencopyProtocolManager::shareFrame(SScreencopyFrame* frame) {
+ if (!frame->buffer)
+ return;
+
+ timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ uint32_t flags = 0;
+ if (frame->bufferCap == WLR_BUFFER_CAP_DMABUF) {
+ if (!copyFrameDmabuf(frame)) {
+ zwlr_screencopy_frame_v1_send_failed(frame->resource);
+ return;
+ }
+ } else {
+ if (!copyFrameShm(frame, &now)) {
+ zwlr_screencopy_frame_v1_send_failed(frame->resource);
+ return;
+ }
+ }
+
+ zwlr_screencopy_frame_v1_send_flags(frame->resource, flags);
+ sendFrameDamage(frame);
+ uint32_t tvSecHi = (sizeof(now.tv_sec) > 4) ? now.tv_sec >> 32 : 0;
+ uint32_t tvSecLo = now.tv_sec & 0xFFFFFFFF;
+ zwlr_screencopy_frame_v1_send_ready(frame->resource, tvSecHi, tvSecLo, now.tv_nsec);
+}
+void CScreencopyProtocolManager::sendFrameDamage(SScreencopyFrame* frame) {
+ if (!frame->withDamage)
+ return;
+
+ const auto RECT = pixman_region32_extents(g_pHyprOpenGL->m_RenderData.pDamage);
+ zwlr_screencopy_frame_v1_send_damage(frame->resource, RECT->x1, RECT->y1, RECT->x2 - RECT->x1, RECT->y2 - RECT->y1);
+}
+
+bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* now) {
+ void* data;
+ uint32_t format;
+ size_t stride;
+ if (!wlr_buffer_begin_data_ptr_access(frame->buffer, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &data, &format, &stride))
+ return false;
+
+ // render the client
+ const auto PMONITOR = frame->pMonitor;
+ pixman_region32_t fakeDamage;
+ pixman_region32_init_rect(&fakeDamage, 0, 0, PMONITOR->vecPixelSize.x * 10, PMONITOR->vecPixelSize.y * 10);
+
+ if (!wlr_output_attach_render(PMONITOR->output, nullptr)) {
+ Debug::log(ERR, "[screencopy] Couldn't attach render");
+ pixman_region32_fini(&fakeDamage);
+ wlr_buffer_end_data_ptr_access(frame->buffer);
+ return false;
+ }
+
+ const auto PFORMAT = get_gles2_format_from_drm(format);
+ if (!PFORMAT) {
+ Debug::log(ERR, "[screencopy] Cannot read pixels, unsupported format %x", PFORMAT);
+ wlr_output_rollback(PMONITOR->output);
+ pixman_region32_fini(&fakeDamage);
+ wlr_buffer_end_data_ptr_access(frame->buffer);
+ return false;
+ }
+
+ g_pHyprOpenGL->begin(PMONITOR, &fakeDamage, true);
+
+ // we should still have the last frame by this point in the original fb
+ glBindFramebuffer(GL_FRAMEBUFFER, g_pHyprOpenGL->m_RenderData.pCurrentMonData->primaryFB.m_iFb);
+
+ glFinish(); // flush
+
+ glReadPixels(frame->box.x, frame->box.y, frame->box.width, frame->box.height, PFORMAT->gl_format, PFORMAT->gl_type, data);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, g_pHyprOpenGL->m_iWLROutputFb);
+
+ g_pHyprOpenGL->end();
+
+ wlr_output_rollback(PMONITOR->output);
+
+ pixman_region32_fini(&fakeDamage);
+
+ wlr_buffer_end_data_ptr_access(frame->buffer);
+
+ return true;
+}
+
+bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) {
+ // todo
+ Debug::log(ERR, "DMABUF copying not impl'd!");
+ return false;
+}
diff --git a/src/protocols/Screencopy.hpp b/src/protocols/Screencopy.hpp
new file mode 100644
index 00000000..d854c3bd
--- /dev/null
+++ b/src/protocols/Screencopy.hpp
@@ -0,0 +1,71 @@
+#pragma once
+
+#include "../defines.hpp"
+#include "wlr-screencopy-unstable-v1-protocol.h"
+
+#include <list>
+#include <vector>
+
+class CMonitor;
+
+struct SScreencopyClient {
+ int ref = 0;
+ wl_resource* resource = nullptr;
+
+ bool operator==(const SScreencopyClient& other) const {
+ return resource == other.resource;
+ }
+};
+
+struct SScreencopyFrame {
+ wl_resource* resource = nullptr;
+ SScreencopyClient* client = nullptr;
+
+ uint32_t shmFormat = 0;
+ uint32_t dmabufFormat = 0;
+ wlr_box box = {0};
+ int shmStride = 0;
+
+ bool overlayCursor = false;
+ bool withDamage = false;
+
+ wlr_buffer_cap bufferCap = WLR_BUFFER_CAP_SHM;
+
+ wlr_buffer* buffer = nullptr;
+
+ CMonitor* pMonitor = nullptr;
+
+ bool operator==(const SScreencopyFrame& other) const {
+ return resource == other.resource && client == other.client;
+ }
+};
+
+class CScreencopyProtocolManager {
+ public:
+ CScreencopyProtocolManager();
+
+ void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id);
+ void removeClient(SScreencopyClient* client, bool force = false);
+ void removeFrame(SScreencopyFrame* frame, bool force = false);
+ void displayDestroy();
+
+ void captureOutput(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* output, wlr_box box = {0, 0, 0, 0});
+
+ void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer);
+
+ void onRenderEnd(CMonitor* pMonitor);
+
+ private:
+ wl_global* m_pGlobal = nullptr;
+ std::list<SScreencopyFrame> m_lFrames;
+ std::list<SScreencopyClient> m_lClients;
+
+ wl_listener m_liDisplayDestroy;
+
+ std::vector<SScreencopyFrame*> m_vFramesAwaitingWrite;
+
+ void shareFrame(SScreencopyFrame* frame);
+ void sendFrameDamage(SScreencopyFrame* frame);
+ bool copyFrameDmabuf(SScreencopyFrame* frame);
+ bool copyFrameShm(SScreencopyFrame* frame, timespec* now);
+}; \ No newline at end of file
diff --git a/src/protocols/TextInputV1.cpp b/src/protocols/TextInputV1.cpp
index 71e11ea7..64c423f7 100644
--- a/src/protocols/TextInputV1.cpp
+++ b/src/protocols/TextInputV1.cpp
@@ -135,7 +135,6 @@ static void destroyTI(wl_resource* resource) {
TI->pTextInput->hyprListener_textInputDestroy.emit(nullptr);
- g_pInputManager->m_sIMERelay.removeTextInput(TI->pTextInput);
g_pProtocolManager->m_pTextInputV1ProtocolManager->removeTI(TI);
}
diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp
index bee1deb6..a51f2632 100644
--- a/src/protocols/ToplevelExport.cpp
+++ b/src/protocols/ToplevelExport.cpp
@@ -47,11 +47,11 @@ wlr_foreign_toplevel_handle_v1* zwlrHandleFromResource(wl_resource* resource) {
return (wlr_foreign_toplevel_handle_v1*)wl_resource_get_user_data(resource);
}
-void handleCaptureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, uint32_t handle) {
+static void handleCaptureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, uint32_t handle) {
g_pProtocolManager->m_pToplevelExportProtocolManager->captureToplevel(client, resource, frame, overlay_cursor, g_pCompositor->getWindowFromHandle(handle));
}
-void handleCaptureToplevelWithWlr(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* handle) {
+static void handleCaptureToplevelWithWlr(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* handle) {
g_pProtocolManager->m_pToplevelExportProtocolManager->captureToplevel(client, resource, frame, overlay_cursor, g_pCompositor->getWindowFromZWLRHandle(handle));
}
@@ -59,11 +59,11 @@ static void handleDestroy(wl_client* client, wl_resource* resource) {
wl_resource_destroy(resource);
}
-void handleCopyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage) {
+static void handleCopyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage) {
g_pProtocolManager->m_pToplevelExportProtocolManager->copyFrame(client, resource, buffer, ignore_damage);
}
-void handleDestroyFrame(wl_client* client, wl_resource* resource) {
+static void handleDestroyFrame(wl_client* client, wl_resource* resource) {
wl_resource_destroy(resource);
}
@@ -75,12 +75,12 @@ static const struct hyprland_toplevel_export_manager_v1_interface toplevelExport
static const struct hyprland_toplevel_export_frame_v1_interface toplevelFrameImpl = {.copy = handleCopyFrame, .destroy = handleDestroyFrame};
-SToplevelClient* clientFromResource(wl_resource* resource) {
+static SToplevelClient* clientFromResource(wl_resource* resource) {
ASSERT(wl_resource_instance_of(resource, &hyprland_toplevel_export_manager_v1_interface, &toplevelExportManagerImpl));
return (SToplevelClient*)wl_resource_get_user_data(resource);
}
-SToplevelFrame* frameFromResource(wl_resource* resource) {
+static SToplevelFrame* frameFromResource(wl_resource* resource) {
ASSERT(wl_resource_instance_of(resource, &hyprland_toplevel_export_frame_v1_interface, &toplevelFrameImpl));
return (SToplevelFrame*)wl_resource_get_user_data(resource);
}
@@ -122,7 +122,7 @@ void CToplevelExportProtocolManager::bindManager(wl_client* client, void* data,
Debug::log(LOG, "ToplevelExportManager bound successfully!");
}
-void handleFrameResourceDestroy(wl_resource* resource) {
+static void handleFrameResourceDestroy(wl_resource* resource) {
const auto PFRAME = frameFromResource(resource);
g_pProtocolManager->m_pToplevelExportProtocolManager->removeFrame(PFRAME);
@@ -349,10 +349,15 @@ bool CToplevelExportProtocolManager::copyFrameShm(SToplevelFrame* frame, timespe
pixman_region32_t fakeDamage;
pixman_region32_init_rect(&fakeDamage, 0, 0, PMONITOR->vecPixelSize.x * 10, PMONITOR->vecPixelSize.y * 10);
+ if (frame->overlayCursor)
+ wlr_output_lock_software_cursors(PMONITOR->output, true);
+
if (!wlr_output_attach_render(PMONITOR->output, nullptr)) {
Debug::log(ERR, "[toplevel_export] Couldn't attach render");
pixman_region32_fini(&fakeDamage);
wlr_buffer_end_data_ptr_access(frame->buffer);
+ if (frame->overlayCursor)
+ wlr_output_lock_software_cursors(PMONITOR->output, false);
return false;
}
@@ -364,6 +369,28 @@ bool CToplevelExportProtocolManager::copyFrameShm(SToplevelFrame* frame, timespe
g_pHyprRenderer->renderWindow(frame->pWindow, PMONITOR, now, false, RENDER_PASS_ALL, true, true);
g_pHyprRenderer->m_bBlockSurfaceFeedback = false;
+ if (frame->overlayCursor && wlr_renderer_begin(g_pCompositor->m_sWLRRenderer, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y)) {
+ // hack le massive
+ wlr_output_cursor* cursor;
+ const auto OFFSET = frame->pWindow->m_vRealPosition.vec() - PMONITOR->vecPosition;
+ wl_list_for_each(cursor, &PMONITOR->output->cursors, link) {
+ if (!cursor->enabled || !cursor->visible || PMONITOR->output->hardware_cursor == cursor) {
+ continue;
+ }
+ cursor->x -= OFFSET.x;
+ cursor->y -= OFFSET.y;
+ }
+ wlr_output_render_software_cursors(PMONITOR->output, NULL);
+ wl_list_for_each(cursor, &PMONITOR->output->cursors, link) {
+ if (!cursor->enabled || !cursor->visible || PMONITOR->output->hardware_cursor == cursor) {
+ continue;
+ }
+ cursor->x += OFFSET.x;
+ cursor->y += OFFSET.y;
+ }
+ wlr_renderer_end(g_pCompositor->m_sWLRRenderer);
+ }
+
// copy pixels
const auto PFORMAT = get_gles2_format_from_drm(format);
if (!PFORMAT) {
@@ -371,6 +398,8 @@ bool CToplevelExportProtocolManager::copyFrameShm(SToplevelFrame* frame, timespe
g_pHyprOpenGL->end();
pixman_region32_fini(&fakeDamage);
wlr_buffer_end_data_ptr_access(frame->buffer);
+ if (frame->overlayCursor)
+ wlr_output_lock_software_cursors(PMONITOR->output, false);
return false;
}
@@ -388,6 +417,9 @@ bool CToplevelExportProtocolManager::copyFrameShm(SToplevelFrame* frame, timespe
wlr_buffer_end_data_ptr_access(frame->buffer);
+ if (frame->overlayCursor)
+ wlr_output_lock_software_cursors(PMONITOR->output, false);
+
return true;
}
diff --git a/src/protocols/ToplevelExportWlrFuncs.hpp b/src/protocols/ToplevelExportWlrFuncs.hpp
index 39e2961b..97bf96f8 100644
--- a/src/protocols/ToplevelExportWlrFuncs.hpp
+++ b/src/protocols/ToplevelExportWlrFuncs.hpp
@@ -1,5 +1,8 @@
#include <GLES2/gl2ext.h>
+#ifndef DRM_WLR_FUNCS
+#define DRM_WLR_FUNCS
+
struct wlr_pixel_format_info {
uint32_t drm_format;
@@ -156,9 +159,9 @@ static const struct wlr_pixel_format_info pixel_format_info[] = {
},
};
-static const size_t pixel_format_info_size = sizeof(pixel_format_info) / sizeof(pixel_format_info[0]);
+static const size_t pixel_format_info_size = sizeof(pixel_format_info) / sizeof(pixel_format_info[0]);
-const struct wlr_pixel_format_info* drm_get_pixel_format_info(uint32_t fmt) {
+static const struct wlr_pixel_format_info* drm_get_pixel_format_info(uint32_t fmt) {
for (size_t i = 0; i < pixel_format_info_size; ++i) {
if (pixel_format_info[i].drm_format == fmt) {
return &pixel_format_info[i];
@@ -168,15 +171,15 @@ const struct wlr_pixel_format_info* drm_get_pixel_format_info(uint32_t fmt) {
return NULL;
}
-uint32_t convert_wl_shm_format_to_drm(enum wl_shm_format fmt) {
+/*static uint32_t convert_wl_shm_format_to_drm(enum wl_shm_format fmt) {
switch (fmt) {
case WL_SHM_FORMAT_XRGB8888: return DRM_FORMAT_XRGB8888;
case WL_SHM_FORMAT_ARGB8888: return DRM_FORMAT_ARGB8888;
default: return (uint32_t)fmt;
}
-}
+}*/
-enum wl_shm_format convert_drm_format_to_wl_shm(uint32_t fmt) {
+static enum wl_shm_format convert_drm_format_to_wl_shm(uint32_t fmt) {
switch (fmt) {
case DRM_FORMAT_XRGB8888: return WL_SHM_FORMAT_XRGB8888;
case DRM_FORMAT_ARGB8888: return WL_SHM_FORMAT_ARGB8888;
@@ -295,7 +298,7 @@ static const struct wlr_gles2_pixel_format formats[] = {
#endif
};
-const struct wlr_gles2_pixel_format* get_gles2_format_from_drm(uint32_t fmt) {
+static const struct wlr_gles2_pixel_format* get_gles2_format_from_drm(uint32_t fmt) {
for (size_t i = 0; i < sizeof(formats) / sizeof(*formats); ++i) {
if (formats[i].drm_format == fmt) {
return &formats[i];
@@ -303,3 +306,5 @@ const struct wlr_gles2_pixel_format* get_gles2_format_from_drm(uint32_t fmt) {
}
return NULL;
}
+
+#endif \ No newline at end of file
diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp
index 10ab3687..2b3dce49 100644
--- a/src/render/OpenGL.cpp
+++ b/src/render/OpenGL.cpp
@@ -205,6 +205,16 @@ void CHyprOpenGLImpl::initShaders() {
m_RenderData.pCurrentMonData->m_shPASSTHRURGBA.texAttrib = glGetAttribLocation(prog, "texcoord");
m_RenderData.pCurrentMonData->m_shPASSTHRURGBA.posAttrib = glGetAttribLocation(prog, "pos");
+ prog = createProgram(TEXVERTSRC, FRAGGLITCH);
+ m_RenderData.pCurrentMonData->m_shGLITCH.program = prog;
+ m_RenderData.pCurrentMonData->m_shGLITCH.proj = glGetUniformLocation(prog, "proj");
+ m_RenderData.pCurrentMonData->m_shGLITCH.tex = glGetUniformLocation(prog, "tex");
+ m_RenderData.pCurrentMonData->m_shGLITCH.texAttrib = glGetAttribLocation(prog, "texcoord");
+ m_RenderData.pCurrentMonData->m_shGLITCH.posAttrib = glGetAttribLocation(prog, "pos");
+ m_RenderData.pCurrentMonData->m_shGLITCH.distort = glGetUniformLocation(prog, "distort");
+ m_RenderData.pCurrentMonData->m_shGLITCH.time = glGetUniformLocation(prog, "time");
+ m_RenderData.pCurrentMonData->m_shGLITCH.fullSize = glGetUniformLocation(prog, "screenSize");
+
prog = createProgram(TEXVERTSRC, TEXFRAGSRCRGBX);
m_RenderData.pCurrentMonData->m_shRGBX.program = prog;
m_RenderData.pCurrentMonData->m_shRGBX.tex = glGetUniformLocation(prog, "tex");
@@ -318,7 +328,7 @@ void CHyprOpenGLImpl::applyScreenShader(const std::string& path) {
m_sFinalScreenShader.proj = glGetUniformLocation(m_sFinalScreenShader.program, "proj");
m_sFinalScreenShader.tex = glGetUniformLocation(m_sFinalScreenShader.program, "tex");
m_sFinalScreenShader.time = glGetUniformLocation(m_sFinalScreenShader.program, "time");
- if (m_sFinalScreenShader.time != -1 && g_pConfigManager->getInt("debug:damage_tracking") != 0) {
+ if (m_sFinalScreenShader.time != -1 && g_pConfigManager->getInt("debug:damage_tracking") != 0 && !g_pHyprRenderer->m_bCrashingInProgress) {
// The screen shader uses the "time" uniform
// Since the screen shader could change every frame, damage tracking *needs* to be disabled
g_pConfigManager->addParseError("Screen shader: Screen shader uses uniform 'time', which requires debug:damage_tracking to be switched off.\n"
@@ -502,9 +512,14 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- bool usingFinalShader = false;
+ bool usingFinalShader = false;
+
+ const bool CRASHING = m_bApplyFinalShader && g_pHyprRenderer->m_bCrashingInProgress;
- if (m_bApplyFinalShader && m_sFinalScreenShader.program) {
+ if (CRASHING) {
+ shader = &m_RenderData.pCurrentMonData->m_shGLITCH;
+ usingFinalShader = true;
+ } else if (m_bApplyFinalShader && m_sFinalScreenShader.program) {
shader = &m_sFinalScreenShader;
usingFinalShader = true;
} else {
@@ -539,13 +554,18 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
#endif
glUniform1i(shader->tex, 0);
- if (usingFinalShader && g_pConfigManager->getInt("debug:damage_tracking") == 0) {
+ if ((usingFinalShader && g_pConfigManager->getInt("debug:damage_tracking") == 0) || CRASHING) {
glUniform1f(shader->time, m_tGlobalTimer.getSeconds());
} else if (usingFinalShader && shader->time > 0) {
// Don't let time be unitialised
glUniform1f(shader->time, 0.f);
}
+ if (CRASHING) {
+ glUniform1f(shader->distort, g_pHyprRenderer->m_fCrashingDistort);
+ glUniform2f(shader->fullSize, m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y);
+ }
+
if (!usingFinalShader) {
glUniform1f(shader->alpha, alpha);
@@ -573,7 +593,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
glUniform1f(shader->radius, round);
glUniform1i(shader->primitiveMultisample, (int)(*PMULTISAMPLEEDGES == 1 && round != 0 && !noAA));
- if (allowDim && m_pCurrentWindow && *PDIMINACTIVE && m_pCurrentWindow != g_pCompositor->m_pLastWindow) {
+ if (allowDim && m_pCurrentWindow && *PDIMINACTIVE) {
glUniform1i(shader->applyTint, 1);
const auto DIM = m_pCurrentWindow->m_fDimPercent.fl();
glUniform3f(shader->tint, 1.f - DIM, 1.f - DIM, 1.f - DIM);
@@ -935,7 +955,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox,
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
- if (USENEWOPTIMIZE)
+ if (USENEWOPTIMIZE && !(m_RenderData.discardMode & DISCARD_ALPHAZERO))
renderRect(pBox, CColor(0, 0, 0, 0), round);
else
renderTexture(tex, pBox, a, round, true, true); // discard opaque
diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp
index 028be4df..3c563946 100644
--- a/src/render/OpenGL.hpp
+++ b/src/render/OpenGL.hpp
@@ -23,8 +23,7 @@ inline const float fullVerts[] = {
};
inline const float fanVertsFull[] = {-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f};
-enum eDiscardMode
-{
+enum eDiscardMode {
DISCARD_OPAQUE = 1,
DISCARD_ALPHAZERO = 1 << 1
};
@@ -55,6 +54,7 @@ struct SMonitorRenderData {
CShader m_shBLUR2;
CShader m_shSHADOW;
CShader m_shBORDER1;
+ CShader m_shGLITCH;
//
};
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index a5a576d3..75546d6b 100644
--- a/src/render/Renderer.cpp
+++ b/src/render/Renderer.cpp
@@ -570,9 +570,8 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) {
renderIMEPopup(&imep, PMONITOR, time);
}
- for (auto ls = PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY].rbegin(); ls != PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY].rend();
- ls++) {
- renderLayer(ls->get(), PMONITOR, time);
+ for (auto& ls : PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) {
+ renderLayer(ls.get(), PMONITOR, time);
}
renderDragIcon(PMONITOR, time);
@@ -663,9 +662,12 @@ void countSubsurfacesIter(wlr_surface* pSurface, int x, int y, void* data) {
}
bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) {
- if (!pMonitor->mirrors.empty() || pMonitor->isMirror())
+ if (!pMonitor->mirrors.empty() || pMonitor->isMirror() || m_bDirectScanoutBlocked)
return false; // do not DS if this monitor is being mirrored. Will break the functionality.
+ if (!wlr_output_is_direct_scanout_allowed(pMonitor->output))
+ return false;
+
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pMonitor->activeWorkspace);
if (!PWORKSPACE || !PWORKSPACE->m_bHasFullscreenWindow || g_pInputManager->m_sDrag.drag || g_pCompositor->m_sSeat.exclusiveClient || pMonitor->specialWorkspaceID)
@@ -813,19 +815,30 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
// check the damage
pixman_region32_t damage;
- bool hasChanged;
- pixman_region32_init(&damage);
+ bool hasChanged = pMonitor->output->needs_frame || !pixman_region32_not_empty(&pMonitor->damage.current);
+ int bufferAge;
if (*PDAMAGETRACKINGMODE == -1) {
Debug::log(CRIT, "Damage tracking mode -1 ????");
return;
}
- if (!wlr_output_damage_attach_render(pMonitor->damage, &hasChanged, &damage)) {
+ const bool UNLOCK_SC = g_pHyprRenderer->m_bSoftwareCursorsLocked;
+ if (UNLOCK_SC)
+ wlr_output_lock_software_cursors(pMonitor->output, true);
+
+ if (!wlr_output_attach_render(pMonitor->output, &bufferAge)) {
Debug::log(ERR, "Couldn't attach render to display %s ???", pMonitor->szName.c_str());
+
+ if (UNLOCK_SC)
+ wlr_output_lock_software_cursors(pMonitor->output, false);
+
return;
}
+ pixman_region32_init(&damage);
+ wlr_damage_ring_get_buffer_damage(&pMonitor->damage, bufferAge, &damage);
+
pMonitor->renderingActive = true;
// we need to cleanup fading out when rendering the appropriate context
@@ -840,6 +853,9 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
pMonitor->renderingActive = false;
+ if (UNLOCK_SC)
+ wlr_output_lock_software_cursors(pMonitor->output, false);
+
return;
}
@@ -939,12 +955,25 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
g_pHyprRenderer->damageMirrorsWith(pMonitor, &frameDamage);
pixman_region32_fini(&frameDamage);
- pixman_region32_fini(&damage);
pMonitor->renderingActive = false;
- if (!wlr_output_commit(pMonitor->output))
+ wlr_damage_ring_rotate(&pMonitor->damage);
+
+ if (!wlr_output_commit(pMonitor->output)) {
+ pixman_region32_fini(&damage);
+
+ if (UNLOCK_SC)
+ wlr_output_lock_software_cursors(pMonitor->output, false);
+
return;
+ }
+
+ g_pProtocolManager->m_pScreencopyProtocolManager->onRenderEnd(pMonitor);
+ pixman_region32_fini(&damage);
+
+ if (UNLOCK_SC)
+ wlr_output_lock_software_cursors(pMonitor->output, false);
if (*PDAMAGEBLINK || *PVFR == 0 || pMonitor->pendingFrame)
g_pCompositor->scheduleFrameForMonitor(pMonitor);
@@ -1225,8 +1254,7 @@ void CHyprRenderer::arrangeLayersForMonitor(const int& monitor) {
}
// damage the monitor if can
- if (PMONITOR->damage)
- damageMonitor(PMONITOR);
+ damageMonitor(PMONITOR);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitor);
@@ -1699,6 +1727,8 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
if (!pMonitor->isMirror())
wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, pMonitor->output, (int)pMonitor->vecPosition.x, (int)pMonitor->vecPosition.y);
+ wlr_damage_ring_set_bounds(&pMonitor->damage, pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y);
+
// updato us
arrangeLayersForMonitor(pMonitor->ID);
@@ -1770,3 +1800,32 @@ std::tuple<float, float, float> CHyprRenderer::getRenderTimes(CMonitor* pMonitor
return std::make_tuple<>(avgRenderTime, maxRenderTime, minRenderTime);
}
+
+static int handleCrashLoop(void* data) {
+
+ g_pHyprNotificationOverlay->addNotification("Hyprland will crash in " + std::to_string(10 - (int)(g_pHyprRenderer->m_fCrashingDistort * 2.f)) + "s.", CColor(0), 5000,
+ ICON_INFO);
+
+ g_pHyprRenderer->m_fCrashingDistort += 0.5f;
+
+ if (g_pHyprRenderer->m_fCrashingDistort >= 5.5f)
+ *((int*)nullptr) = 1337;
+
+ wl_event_source_timer_update(g_pHyprRenderer->m_pCrashingLoop, 1000);
+
+ return 1;
+}
+
+void CHyprRenderer::initiateManualCrash() {
+ g_pHyprNotificationOverlay->addNotification("Manual crash initiated. Farewell...", CColor(0), 5000, ICON_INFO);
+
+ m_pCrashingLoop = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, handleCrashLoop, nullptr);
+ wl_event_source_timer_update(m_pCrashingLoop, 1000);
+
+ m_bCrashingInProgress = true;
+ m_fCrashingDistort = 0.5;
+
+ g_pHyprOpenGL->m_tGlobalTimer.reset();
+
+ g_pConfigManager->setInt("debug:damage_tracking", 0);
+} \ No newline at end of file
diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp
index 4ce0f6dc..7b0f47fd 100644
--- a/src/render/Renderer.hpp
+++ b/src/render/Renderer.hpp
@@ -10,16 +10,14 @@
struct SMonitorRule;
// TODO: add fuller damage tracking for updating only parts of a window
-enum DAMAGETRACKINGMODES
-{
+enum DAMAGETRACKINGMODES {
DAMAGE_TRACKING_INVALID = -1,
DAMAGE_TRACKING_NONE = 0,
DAMAGE_TRACKING_MONITOR,
DAMAGE_TRACKING_FULL
};
-enum eRenderPassMode
-{
+enum eRenderPassMode {
RENDER_PASS_ALL = 0,
RENDER_PASS_MAIN,
RENDER_PASS_POPUP
@@ -55,11 +53,18 @@ class CHyprRenderer {
bool m_bRenderingSnapshot = false;
CWindow* m_pLastScanout = nullptr;
CMonitor* m_pMostHzMonitor = nullptr;
+ bool m_bDirectScanoutBlocked = false;
+ bool m_bSoftwareCursorsLocked = false;
DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&);
bool attemptDirectScanout(CMonitor*);
void setWindowScanoutMode(CWindow*);
+ void initiateManualCrash();
+
+ bool m_bCrashingInProgress = false;
+ float m_fCrashingDistort = 0.5f;
+ wl_event_source* m_pCrashingLoop = nullptr;
private:
void arrangeLayerArray(CMonitor*, const std::vector<std::unique_ptr<SLayerSurface>>&, bool, wlr_box*);
diff --git a/src/render/Shader.hpp b/src/render/Shader.hpp
index 33bcdca3..04bf9259 100644
--- a/src/render/Shader.hpp
+++ b/src/render/Shader.hpp
@@ -39,6 +39,7 @@ class CShader {
GLint angle;
GLint time;
+ GLint distort;
GLint getUniformLocation(const std::string&);
diff --git a/src/render/shaders/Textures.hpp b/src/render/shaders/Textures.hpp
index 52e77fae..45068839 100644
--- a/src/render/shaders/Textures.hpp
+++ b/src/render/shaders/Textures.hpp
@@ -258,3 +258,70 @@ void main() {
gl_FragColor = pixColor * alpha;
}
)#";
+
+static const std::string FRAGGLITCH = R"#(
+precision mediump float;
+varying vec2 v_texcoord;
+uniform sampler2D tex;
+uniform float time; // quirk: time is set to 0 at the beginning, should be around 10 when crash.
+uniform float distort;
+uniform vec2 screenSize;
+
+float rand(float co) {
+ return fract(sin(dot(vec2(co, co), vec2(12.9898, 78.233))) * 43758.5453);
+}
+
+float rand(vec2 co) {
+ return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453);
+}
+
+float noise(vec2 point) {
+ vec2 floored = floor(point);
+ vec2 fractal = fract(point);
+ fractal = fractal * fractal * (3.0 - 2.0 * fractal);
+
+ float mixed = mix(
+ mix(rand(floored), rand(floored + vec2(1.0, 0.0)), fractal.x),
+ mix(rand(floored + vec2(0.0,1.0)), rand(floored + vec2(1.0,1.0)), fractal.x), fractal.y);
+ return mixed * mixed;
+}
+
+void main() {
+ float ABERR_OFFSET = 4.0 * (distort / 5.5) * time;
+ float TEAR_AMOUNT = 9000.0 * (1.0 - (distort / 5.5));
+ float TEAR_BANDS = 108.0 / 2.0 * (distort / 5.5) * 2.0;
+ float MELT_AMOUNT = (distort * 8.0) / screenSize.y;
+
+ float NOISE = abs(mod(noise(v_texcoord) * distort * time * 2.771, 1.0)) * time / 10.0;
+ if (time < 2.0)
+ NOISE = 0.0;
+
+ float offset = (mod(rand(floor(v_texcoord.y * TEAR_BANDS)) * 318.772 * time, 20.0) - 10.0) / TEAR_AMOUNT;
+
+ vec2 blockOffset = vec2(((abs(mod(rand(floor(v_texcoord.x * 37.162)) * 721.43, 100.0))) - 50.0) / 200000.0 * pow(time, 3.0),
+ ((abs(mod(rand(floor(v_texcoord.y * 45.882)) * 733.923, 100.0))) - 50.0) / 200000.0 * pow(time, 3.0));
+ if (time < 3.0)
+ blockOffset = vec2(0,0);
+
+ float meltSeed = abs(mod(rand(floor(v_texcoord.x * screenSize.x * 17.719)) * 281.882, 1.0));
+ if (meltSeed < 0.8) {
+ meltSeed = 0.0;
+ } else {
+ meltSeed *= 25.0 * NOISE;
+ }
+ float meltAmount = MELT_AMOUNT * meltSeed;
+
+ vec2 pixCoord = vec2(v_texcoord.x + offset + NOISE * 3.0 / screenSize.x + blockOffset.x, v_texcoord.y - meltAmount + 0.02 * NOISE / screenSize.x + NOISE * 3.0 / screenSize.y + blockOffset.y);
+
+ vec4 pixColor = texture2D(tex, pixCoord);
+ vec4 pixColorLeft = texture2D(tex, pixCoord + vec2(ABERR_OFFSET / screenSize.x, 0));
+ vec4 pixColorRight = texture2D(tex, pixCoord + vec2(-ABERR_OFFSET / screenSize.x, 0));
+
+ pixColor[0] = pixColorLeft[0];
+ pixColor[2] = pixColorRight[2];
+
+ pixColor[0] += distort / 90.0;
+
+ gl_FragColor = pixColor;
+}
+)#"; \ No newline at end of file
diff --git a/subprojects/wlroots b/subprojects/wlroots
-Subproject 1d64e12391a638201c679e71d4e22bb45e5faa8
+Subproject 7abda952d0000b72d240fe1d41457b9288f0b6e