diff options
author | Vaxry <[email protected]> | 2022-12-12 14:56:42 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2022-12-12 14:56:42 +0000 |
commit | 111d209bff5448c3a55e07f344cf89715536bba4 (patch) | |
tree | 4b21cff5e0e3a52eac48b9b8fb39b50b0c4c9417 | |
parent | b45a2134135d6d6269ba374372c93361c799d6b8 (diff) | |
download | Hyprland-111d209bff5448c3a55e07f344cf89715536bba4.tar.gz Hyprland-111d209bff5448c3a55e07f344cf89715536bba4.zip |
Added toplevel handle sharing Rev2 (#1203)v0.19.2beta
* Added toplevel handle sharing
* nix: fix build
* update hyprland-protocols
Co-authored-by: Mihai Fufezan <[email protected]>
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | Makefile | 12 | ||||
-rw-r--r-- | flake.lock | 12 | ||||
-rw-r--r-- | protocols/meson.build | 1 | ||||
-rw-r--r-- | protocols/wlr-foreign-toplevel-management-unstable-v1.xml | 270 | ||||
-rw-r--r-- | src/Compositor.cpp | 17 | ||||
-rw-r--r-- | src/Compositor.hpp | 1 | ||||
-rw-r--r-- | src/protocols/ToplevelExport.cpp | 34 | ||||
-rw-r--r-- | src/protocols/ToplevelExport.hpp | 3 | ||||
m--------- | subprojects/hyprland-protocols | 0 |
10 files changed, 330 insertions, 21 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 91d2647b..a0eb2f10 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,5 +107,6 @@ target_link_libraries(Hyprland pthread ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_SOURCE_DIR}/ext-workspace-unstable-v1-protocol.o + ${CMAKE_SOURCE_DIR}/wlr-foreign-toplevel-management-unstable-v1-protocol.o ${CMAKE_SOURCE_DIR}/hyprland-toplevel-export-v1-protocol.o ) @@ -111,6 +111,16 @@ linux-dmabuf-unstable-v1-protocol.c: linux-dmabuf-unstable-v1-protocol.o: linux-dmabuf-unstable-v1-protocol.h +wlr-foreign-toplevel-management-unstable-v1-protocol.h: + $(WAYLAND_SCANNER) server-header \ + protocols/wlr-foreign-toplevel-management-unstable-v1.xml $@ + +wlr-foreign-toplevel-management-unstable-v1-protocol.c: + $(WAYLAND_SCANNER) private-code \ + protocols/wlr-foreign-toplevel-management-unstable-v1.xml $@ + +wlr-foreign-toplevel-management-unstable-v1-protocol.o: wlr-foreign-toplevel-management-unstable-v1-protocol.h + legacyrenderer: mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DLEGACY_RENDERER:STRING=true -H./ -B./build -G Ninja cmake --build ./build --config Release --target all -j$(shell nproc) @@ -189,7 +199,7 @@ uninstall: rm -f ${PREFIX}/share/man/man1/Hyprland.1 rm -f ${PREFIX}/share/man/man1/hyprctl.1 -protocols: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o wlr-screencopy-unstable-v1-protocol.o idle-protocol.o ext-workspace-unstable-v1-protocol.o pointer-constraints-unstable-v1-protocol.o tablet-unstable-v2-protocol.o wlr-output-power-management-unstable-v1-protocol.o linux-dmabuf-unstable-v1-protocol.o hyprland-toplevel-export-v1-protocol.o +protocols: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o wlr-screencopy-unstable-v1-protocol.o idle-protocol.o ext-workspace-unstable-v1-protocol.o pointer-constraints-unstable-v1-protocol.o tablet-unstable-v2-protocol.o wlr-output-power-management-unstable-v1-protocol.o linux-dmabuf-unstable-v1-protocol.o hyprland-toplevel-export-v1-protocol.o wlr-foreign-toplevel-management-unstable-v1-protocol.o fixwlr: sed -i -E 's/(soversion = 12)([^032]|$$)/soversion = 12032/g' subprojects/wlroots/meson.build @@ -3,11 +3,11 @@ "hyprland-protocols": { "flake": false, "locked": { - "lastModified": 1670258048, - "narHash": "sha256-Lm2sXnDVZNE+taHqsqVibvPmSdu65VHvXI507KVX4lg=", + "lastModified": 1670703428, + "narHash": "sha256-4KUW5SKR0Y9uaYGcYwy53YJ3B/sgiprCL4fRGO+mpOA=", "owner": "hyprwm", "repo": "hyprland-protocols", - "rev": "0dcff94fc10df2bbb66d3e1b5a1d6cfd3ada5515", + "rev": "d0d6db8cb5bef6d93ca3ad8fb2124964173396da", "type": "github" }, "original": { @@ -82,11 +82,11 @@ ] }, "locked": { - "lastModified": 1670593043, - "narHash": "sha256-tsDs6FB+7PlBOt46dMQFBMH5yPY/fduf4cYbQYhauhA=", + "lastModified": 1670797151, + "narHash": "sha256-ZFzJHqSXhGCjSeMgqTyJG1KJ2Nlwa+NEN9K4oGhWcjg=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "5f7eecff553d82f21e049d79d8fb3f1f46568da0", + "rev": "36ffb6892e14b9c5be6e321b3c47fe286ac256e6", "type": "github" }, "original": { diff --git a/protocols/meson.build b/protocols/meson.build index d75acb3a..394ca1b8 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -21,6 +21,7 @@ wayland_scanner = find_program( protocols = [ [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], [wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'], + ['wlr-foreign-toplevel-management-unstable-v1.xml'], ['wlr-layer-shell-unstable-v1.xml'], ['wlr-output-power-management-unstable-v1.xml'], ['ext-workspace-unstable-v1.xml'], diff --git a/protocols/wlr-foreign-toplevel-management-unstable-v1.xml b/protocols/wlr-foreign-toplevel-management-unstable-v1.xml new file mode 100644 index 00000000..44505bbb --- /dev/null +++ b/protocols/wlr-foreign-toplevel-management-unstable-v1.xml @@ -0,0 +1,270 @@ +<?xml version="1.0" encoding="UTF-8"?> +<protocol name="wlr_foreign_toplevel_management_unstable_v1"> + <copyright> + Copyright © 2018 Ilia Bozhinov + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + </copyright> + + <interface name="zwlr_foreign_toplevel_manager_v1" version="3"> + <description summary="list and control opened apps"> + The purpose of this protocol is to enable the creation of taskbars + and docks by providing them with a list of opened applications and + letting them request certain actions on them, like maximizing, etc. + + After a client binds the zwlr_foreign_toplevel_manager_v1, each opened + toplevel window will be sent via the toplevel event + </description> + + <event name="toplevel"> + <description summary="a toplevel has been created"> + This event is emitted whenever a new toplevel window is created. It + is emitted for all toplevels, regardless of the app that has created + them. + + All initial details of the toplevel(title, app_id, states, etc.) will + be sent immediately after this event via the corresponding events in + zwlr_foreign_toplevel_handle_v1. + </description> + <arg name="toplevel" type="new_id" interface="zwlr_foreign_toplevel_handle_v1"/> + </event> + + <request name="stop"> + <description summary="stop sending events"> + Indicates the client no longer wishes to receive events for new toplevels. + However the compositor may emit further toplevel_created events, until + the finished event is emitted. + + The client must not send any more requests after this one. + </description> + </request> + + <event name="finished" type="destructor"> + <description summary="the compositor has finished with the toplevel manager"> + This event indicates that the compositor is done sending events to the + zwlr_foreign_toplevel_manager_v1. The server will destroy the object + immediately after sending this request, so it will become invalid and + the client should free any resources associated with it. + </description> + </event> + </interface> + + <interface name="zwlr_foreign_toplevel_handle_v1" version="3"> + <description summary="an opened toplevel"> + A zwlr_foreign_toplevel_handle_v1 object represents an opened toplevel + window. Each app may have multiple opened toplevels. + + Each toplevel has a list of outputs it is visible on, conveyed to the + client with the output_enter and output_leave events. + </description> + + <event name="title"> + <description summary="title change"> + This event is emitted whenever the title of the toplevel changes. + </description> + <arg name="title" type="string"/> + </event> + + <event name="app_id"> + <description summary="app-id change"> + This event is emitted whenever the app-id of the toplevel changes. + </description> + <arg name="app_id" type="string"/> + </event> + + <event name="output_enter"> + <description summary="toplevel entered an output"> + This event is emitted whenever the toplevel becomes visible on + the given output. A toplevel may be visible on multiple outputs. + </description> + <arg name="output" type="object" interface="wl_output"/> + </event> + + <event name="output_leave"> + <description summary="toplevel left an output"> + This event is emitted whenever the toplevel stops being visible on + the given output. It is guaranteed that an entered-output event + with the same output has been emitted before this event. + </description> + <arg name="output" type="object" interface="wl_output"/> + </event> + + <request name="set_maximized"> + <description summary="requests that the toplevel be maximized"> + Requests that the toplevel be maximized. If the maximized state actually + changes, this will be indicated by the state event. + </description> + </request> + + <request name="unset_maximized"> + <description summary="requests that the toplevel be unmaximized"> + Requests that the toplevel be unmaximized. If the maximized state actually + changes, this will be indicated by the state event. + </description> + </request> + + <request name="set_minimized"> + <description summary="requests that the toplevel be minimized"> + Requests that the toplevel be minimized. If the minimized state actually + changes, this will be indicated by the state event. + </description> + </request> + + <request name="unset_minimized"> + <description summary="requests that the toplevel be unminimized"> + Requests that the toplevel be unminimized. If the minimized state actually + changes, this will be indicated by the state event. + </description> + </request> + + <request name="activate"> + <description summary="activate the toplevel"> + Request that this toplevel be activated on the given seat. + There is no guarantee the toplevel will be actually activated. + </description> + <arg name="seat" type="object" interface="wl_seat"/> + </request> + + <enum name="state"> + <description summary="types of states on the toplevel"> + The different states that a toplevel can have. These have the same meaning + as the states with the same names defined in xdg-toplevel + </description> + + <entry name="maximized" value="0" summary="the toplevel is maximized"/> + <entry name="minimized" value="1" summary="the toplevel is minimized"/> + <entry name="activated" value="2" summary="the toplevel is active"/> + <entry name="fullscreen" value="3" summary="the toplevel is fullscreen" since="2"/> + </enum> + + <event name="state"> + <description summary="the toplevel state changed"> + This event is emitted immediately after the zlw_foreign_toplevel_handle_v1 + is created and each time the toplevel state changes, either because of a + compositor action or because of a request in this protocol. + </description> + + <arg name="state" type="array"/> + </event> + + <event name="done"> + <description summary="all information about the toplevel has been sent"> + This event is sent after all changes in the toplevel state have been + sent. + + This allows changes to the zwlr_foreign_toplevel_handle_v1 properties + to be seen as atomic, even if they happen via multiple events. + </description> + </event> + + <request name="close"> + <description summary="request that the toplevel be closed"> + Send a request to the toplevel to close itself. The compositor would + typically use a shell-specific method to carry out this request, for + example by sending the xdg_toplevel.close event. However, this gives + no guarantees the toplevel will actually be destroyed. If and when + this happens, the zwlr_foreign_toplevel_handle_v1.closed event will + be emitted. + </description> + </request> + + <request name="set_rectangle"> + <description summary="the rectangle which represents the toplevel"> + The rectangle of the surface specified in this request corresponds to + the place where the app using this protocol represents the given toplevel. + It can be used by the compositor as a hint for some operations, e.g + minimizing. The client is however not required to set this, in which + case the compositor is free to decide some default value. + + If the client specifies more than one rectangle, only the last one is + considered. + + The dimensions are given in surface-local coordinates. + Setting width=height=0 removes the already-set rectangle. + </description> + + <arg name="surface" type="object" interface="wl_surface"/> + <arg name="x" type="int"/> + <arg name="y" type="int"/> + <arg name="width" type="int"/> + <arg name="height" type="int"/> + </request> + + <enum name="error"> + <entry name="invalid_rectangle" value="0" + summary="the provided rectangle is invalid"/> + </enum> + + <event name="closed"> + <description summary="this toplevel has been destroyed"> + This event means the toplevel has been destroyed. It is guaranteed there + won't be any more events for this zwlr_foreign_toplevel_handle_v1. The + toplevel itself becomes inert so any requests will be ignored except the + destroy request. + </description> + </event> + + <request name="destroy" type="destructor"> + <description summary="destroy the zwlr_foreign_toplevel_handle_v1 object"> + Destroys the zwlr_foreign_toplevel_handle_v1 object. + + This request should be called either when the client does not want to + use the toplevel anymore or after the closed event to finalize the + destruction of the object. + </description> + </request> + + <!-- Version 2 additions --> + + <request name="set_fullscreen" since="2"> + <description summary="request that the toplevel be fullscreened"> + Requests that the toplevel be fullscreened on the given output. If the + fullscreen state and/or the outputs the toplevel is visible on actually + change, this will be indicated by the state and output_enter/leave + events. + + The output parameter is only a hint to the compositor. Also, if output + is NULL, the compositor should decide which output the toplevel will be + fullscreened on, if at all. + </description> + <arg name="output" type="object" interface="wl_output" allow-null="true"/> + </request> + + <request name="unset_fullscreen" since="2"> + <description summary="request that the toplevel be unfullscreened"> + Requests that the toplevel be unfullscreened. If the fullscreen state + actually changes, this will be indicated by the state event. + </description> + </request> + + <!-- Version 3 additions --> + + <event name="parent" since="3"> + <description summary="parent change"> + This event is emitted whenever the parent of the toplevel changes. + + No event is emitted when the parent handle is destroyed by the client. + </description> + <arg name="parent" type="object" interface="zwlr_foreign_toplevel_handle_v1" allow-null="true"/> + </event> + </interface> +</protocol> diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 942da2ee..8b415bd2 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -931,6 +931,23 @@ CWindow* CCompositor::getWindowFromHandle(uint32_t handle) { return nullptr; } +CWindow* CCompositor::getWindowFromZWLRHandle(wl_resource* handle) { + for (auto& w : m_vWindows) { + if (!w->m_bIsMapped || w->isHidden() || !w->m_phForeignToplevel) + continue; + + wl_resource* current; + + wl_list_for_each(current, &w->m_phForeignToplevel->resources, link) { + if (current == handle) { + return w.get(); + } + } + } + + return nullptr; +} + CWindow* CCompositor::getFullscreenWindowOnWorkspace(const int& ID) { for (auto& w : m_vWindows) { if (w->m_iWorkspaceID == ID && w->m_bIsFullscreen) diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 125a61eb..c4c96fae 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -128,6 +128,7 @@ public: CWindow* getWindowForPopup(wlr_xdg_popup*); CWindow* getWindowFromSurface(wlr_surface*); CWindow* getWindowFromHandle(uint32_t); + CWindow* getWindowFromZWLRHandle(wl_resource*); bool isWorkspaceVisible(const int&); CWorkspace* getWorkspaceByID(const int&); CWorkspace* getWorkspaceByName(const std::string&); diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index d7e49ab0..e579e1a7 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -6,7 +6,7 @@ #include "ToplevelExportWlrFuncs.hpp" -#define TOPLEVEL_EXPORT_VERSION 1 +#define TOPLEVEL_EXPORT_VERSION 2 static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint32_t id) { g_pProtocolManager->m_pToplevelExportProtocolManager->bindManager(client, data, version, id); @@ -41,8 +41,17 @@ CToplevelExportProtocolManager::CToplevelExportProtocolManager() { Debug::log(LOG, "ToplevelExportManager started successfully!"); } +wlr_foreign_toplevel_handle_v1* zwlrHandleFromResource(wl_resource* resource) { + // we can't assert here, but it doesnt matter. + 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) { - g_pProtocolManager->m_pToplevelExportProtocolManager->captureToplevel(client, resource, frame, overlay_cursor, 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) { + g_pProtocolManager->m_pToplevelExportProtocolManager->captureToplevel(client, resource, frame, overlay_cursor, g_pCompositor->getWindowFromZWLRHandle(handle)); } void handleDestroy(wl_client* client, wl_resource* resource) { @@ -59,7 +68,8 @@ void handleDestroyFrame(wl_client* client, wl_resource* resource) { static const struct hyprland_toplevel_export_manager_v1_interface toplevelExportManagerImpl = { .capture_toplevel = handleCaptureToplevel, - .destroy = handleDestroy + .destroy = handleDestroy, + .capture_toplevel_with_wlr_toplevel_handle = handleCaptureToplevelWithWlr, }; static const struct hyprland_toplevel_export_frame_v1_interface toplevelFrameImpl = { @@ -133,26 +143,24 @@ void CToplevelExportProtocolManager::removeFrame(SToplevelFrame* frame, bool for m_lFrames.remove(*frame); } -void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, uint32_t handle) { +void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, CWindow* pWindow) { const auto PCLIENT = clientFromResource(resource); - const auto PWINDOW = g_pCompositor->getWindowFromHandle(handle); - // create a frame const auto PFRAME = &m_lFrames.emplace_back(); PFRAME->overlayCursor = !!overlay_cursor; PFRAME->resource = wl_resource_create(client, &hyprland_toplevel_export_frame_v1_interface, wl_resource_get_version(resource), frame); - PFRAME->pWindow = PWINDOW; + PFRAME->pWindow = pWindow; - if (!PWINDOW) { - Debug::log(ERR, "Client requested sharing of window handle %x which does not exist!", handle); + if (!PFRAME->pWindow) { + Debug::log(ERR, "Client requested sharing of window handle %x which does not exist!", PFRAME->pWindow); hyprland_toplevel_export_frame_v1_send_failed(PFRAME->resource); removeFrame(PFRAME); return; } - if (!PWINDOW->m_bIsMapped || PWINDOW->isHidden()) { - Debug::log(ERR, "Client requested sharing of window handle %x which is not shareable!", handle); + if (!PFRAME->pWindow->m_bIsMapped || PFRAME->pWindow->isHidden()) { + Debug::log(ERR, "Client requested sharing of window handle %x which is not shareable!", PFRAME->pWindow); hyprland_toplevel_export_frame_v1_send_failed(PFRAME->resource); removeFrame(PFRAME); return; @@ -170,7 +178,7 @@ void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resou PFRAME->client = PCLIENT; PCLIENT->ref++; - const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); + const auto PMONITOR = g_pCompositor->getMonitorFromID(PFRAME->pWindow->m_iMonitorID); PFRAME->shmFormat = wlr_output_preferred_read_format(PMONITOR->output); if (PFRAME->shmFormat == DRM_FORMAT_INVALID) { @@ -194,7 +202,7 @@ void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resou PFRAME->dmabufFormat = DRM_FORMAT_INVALID; } - PFRAME->box = { 0, 0, (int)(PWINDOW->m_vRealSize.vec().x * PMONITOR->scale), (int)(PWINDOW->m_vRealSize.vec().y * PMONITOR->scale) }; + PFRAME->box = { 0, 0, (int)(PFRAME->pWindow->m_vRealSize.vec().x * PMONITOR->scale), (int)(PFRAME->pWindow->m_vRealSize.vec().y * PMONITOR->scale) }; int ow, oh; wlr_output_effective_resolution(PMONITOR->output, &ow, &oh); wlr_box_transform(&PFRAME->box, &PFRAME->box, PMONITOR->transform, ow, oh); diff --git a/src/protocols/ToplevelExport.hpp b/src/protocols/ToplevelExport.hpp index bdf5cfd6..eee0e97d 100644 --- a/src/protocols/ToplevelExport.hpp +++ b/src/protocols/ToplevelExport.hpp @@ -1,6 +1,7 @@ #pragma once #include "../defines.hpp" +#include "wlr-foreign-toplevel-management-unstable-v1-protocol.h" #include "hyprland-toplevel-export-v1-protocol.h" #include <list> @@ -45,7 +46,7 @@ public: CToplevelExportProtocolManager(); void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id); - void captureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, uint32_t handle); + void captureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, CWindow* handle); void removeClient(SToplevelClient* client, bool force = false); void removeFrame(SToplevelFrame* frame, bool force = false); void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage); diff --git a/subprojects/hyprland-protocols b/subprojects/hyprland-protocols -Subproject 0dcff94fc10df2bbb66d3e1b5a1d6cfd3ada551 +Subproject 301733ae466b229066ba15a53e6d8b91c5dcef5 |