diff options
author | Vaxry <[email protected]> | 2023-04-09 00:46:13 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2023-04-09 00:46:13 +0100 |
commit | dfc729c045a94b446fa467a511726258dcbb9040 (patch) | |
tree | c5c633d27b20e8fc31f779df3ef7c73fe92356f4 | |
parent | b9f8552b11db5babe80b9c62c31766a847f7b95d (diff) | |
parent | e4e653ada6fc729efad3f6a0d49cf72b94c43b6c (diff) | |
download | Hyprland-dfc729c045a94b446fa467a511726258dcbb9040.tar.gz Hyprland-dfc729c045a94b446fa467a511726258dcbb9040.zip |
Merge branch 'main' into global-shortcuts
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}}); @@ -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 - @@ -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 |