mirror of
https://github.com/hyprwm/xdg-desktop-portal-hyprland.git
synced 2024-11-21 22:25:58 +01:00
Toplevel sharing Rev2 impl (#3)
* toplevel sharing rev2 * nix: fix build * updated protocols Co-authored-by: Mihai Fufezan <fufexan@protonmail.com>
This commit is contained in:
parent
1fa106cfdf
commit
3c4c9969cc
8 changed files with 532 additions and 31 deletions
|
@ -3,11 +3,11 @@
|
|||
"hyprland-protocols": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1670185345,
|
||||
"narHash": "sha256-hxWGqlPecqEsE6nOHDV29KFBKePbY2Ipeac6lrChMKY=",
|
||||
"lastModified": 1670703428,
|
||||
"narHash": "sha256-4KUW5SKR0Y9uaYGcYwy53YJ3B/sgiprCL4fRGO+mpOA=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-protocols",
|
||||
"rev": "4623a404c091e64743ba310199bb380ec52f1936",
|
||||
"rev": "d0d6db8cb5bef6d93ca3ad8fb2124964173396da",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
std::string execAndGet(const char* cmd) {
|
||||
std::array<char, 128> buffer;
|
||||
|
@ -31,12 +32,58 @@ std::string execAndGet(const char* cmd) {
|
|||
}
|
||||
|
||||
QApplication* pickerPtr = nullptr;
|
||||
MainPicker* mainPickerPtr = nullptr;
|
||||
|
||||
struct SWindowEntry {
|
||||
std::string name;
|
||||
std::string clazz;
|
||||
int id = 0;
|
||||
};
|
||||
|
||||
std::vector<SWindowEntry> getWindows(const char* env) {
|
||||
std::vector<SWindowEntry> result;
|
||||
|
||||
if (!env)
|
||||
return result;
|
||||
|
||||
std::string rolling = env;
|
||||
|
||||
while (!rolling.empty()) {
|
||||
// ID
|
||||
const auto IDSEPPOS = rolling.find("[HC\011]");
|
||||
const auto IDSTR = rolling.substr(0, IDSEPPOS);
|
||||
|
||||
// class
|
||||
const auto CLASSSEPPOS = rolling.find("[HT\011]");
|
||||
const auto CLASSSTR = rolling.substr(IDSEPPOS + 5, CLASSSEPPOS - IDSEPPOS - 5);
|
||||
|
||||
// title
|
||||
const auto TITLESEPPOS = rolling.find("[HE\011]");
|
||||
const auto TITLESTR = rolling.substr(CLASSSEPPOS + 5, TITLESEPPOS - 5 - CLASSSEPPOS);
|
||||
|
||||
try {
|
||||
result.push_back({TITLESTR, CLASSSTR, std::stoi(IDSTR)});
|
||||
} catch (...) {
|
||||
std::cout << "err\n"; // silent err
|
||||
}
|
||||
|
||||
rolling = rolling.substr(TITLESEPPOS + 5);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
qputenv("QT_LOGGING_RULES", "qml=false");
|
||||
|
||||
const char* WINDOWLISTSTR = getenv("XDPH_WINDOW_SHARING_LIST");
|
||||
|
||||
const auto WINDOWLIST = getWindows(WINDOWLISTSTR);
|
||||
|
||||
QApplication picker(argc, argv);
|
||||
pickerPtr = &picker;
|
||||
MainPicker w;
|
||||
mainPickerPtr = &w;
|
||||
|
||||
// get the tabwidget
|
||||
const auto TABWIDGET = (QTabWidget*)w.children()[1]->children()[0];
|
||||
|
@ -82,29 +129,18 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
// loop over them
|
||||
int windowIterator = 0;
|
||||
while (windowsList.find("Window ") != std::string::npos) {
|
||||
auto windowPropLen = windowsList.find("Window ", windowsList.find("\n\n") + 2);
|
||||
if (windowPropLen == std::string::npos)
|
||||
windowPropLen = windowsList.length();
|
||||
const std::string windowProp = windowsList.substr(0, windowPropLen);
|
||||
windowsList = windowsList.substr(windowPropLen);
|
||||
for (auto& window : WINDOWLIST) {
|
||||
|
||||
// get window name
|
||||
auto windowName = windowProp.substr(windowProp.find(" -> ") + 4);
|
||||
windowName = windowName.substr(0, windowName.find_first_of('\n') - 1);
|
||||
|
||||
auto windowHandle = windowProp.substr(7, windowProp.find(" -> ") - 7);
|
||||
|
||||
QString text = QString::fromStdString("Window " + windowHandle + ": " + windowName);
|
||||
QString text = QString::fromStdString(window.clazz + ": " + window.name);
|
||||
|
||||
QPushButton* button = new QPushButton(text, (QWidget*)WINDOWS_SCROLL_AREA_CONTENTS);
|
||||
button->move(9, 5 + (BUTTON_HEIGHT + BUTTON_PAD) * windowIterator);
|
||||
button->resize(BUTTON_WIDTH, BUTTON_HEIGHT);
|
||||
QObject::connect(button, &QPushButton::clicked, [=] () {
|
||||
std::string HANDLE = button->text().toStdString();
|
||||
HANDLE = HANDLE.substr(7, HANDLE.find_first_of(':') - 7);
|
||||
|
||||
std::cout << "window:" << HANDLE << "\n";
|
||||
mainPickerPtr->windowIDs[button] = window.id;
|
||||
|
||||
QObject::connect(button, &QPushButton::clicked, [=] () {
|
||||
std::cout << "window:" << mainPickerPtr->windowIDs[button] << "\n";
|
||||
pickerPtr->quit();
|
||||
return 0;
|
||||
});
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <QMainWindow>
|
||||
#include <QObject>
|
||||
#include <QEvent>
|
||||
#include <unordered_map>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class MainPicker; }
|
||||
|
@ -19,6 +20,8 @@ public:
|
|||
|
||||
void onMonitorButtonClicked(QObject* target, QEvent* event);
|
||||
|
||||
std::unordered_map<void*, int> windowIDs; // button -> id
|
||||
|
||||
private:
|
||||
Ui::MainPicker *ui;
|
||||
};
|
||||
|
|
|
@ -126,6 +126,8 @@ struct xdpw_screencast_context {
|
|||
|
||||
// hyprland
|
||||
struct hyprland_toplevel_export_manager_v1 *hyprland_toplevel_manager;
|
||||
struct zwlr_foreign_toplevel_manager_v1 *wlroots_toplevel_manager;
|
||||
struct wl_list toplevel_resource_list;
|
||||
|
||||
// gbm
|
||||
struct gbm_device *gbm;
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 4623a404c091e64743ba310199bb380ec52f1936
|
||||
Subproject commit 301733ae466b229066ba15a53e6d8b91c5dcef5b
|
|
@ -14,6 +14,7 @@ client_protocols = [
|
|||
wl_protocol_dir / 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml',
|
||||
wl_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml',
|
||||
'wlr-screencopy-unstable-v1.xml',
|
||||
'wlr-foreign-toplevel-management-unstable-v1.xml',
|
||||
'hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml'
|
||||
]
|
||||
|
||||
|
|
270
protocols/wlr-foreign-toplevel-management-unstable-v1.xml
Normal file
270
protocols/wlr-foreign-toplevel-management-unstable-v1.xml
Normal file
|
@ -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>
|
|
@ -3,6 +3,7 @@
|
|||
#include "linux-dmabuf-unstable-v1-client-protocol.h"
|
||||
#include "wlr-screencopy-unstable-v1-client-protocol.h"
|
||||
#include "xdg-output-unstable-v1-client-protocol.h"
|
||||
#include "wlr-foreign-toplevel-management-unstable-v1-client-protocol.h"
|
||||
#include "hyprland-toplevel-export-v1-client-protocol.h"
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
|
@ -24,6 +25,117 @@
|
|||
#include "xdpw.h"
|
||||
#include "logger.h"
|
||||
#include "fps_limit.h"
|
||||
//
|
||||
|
||||
struct SToplevelEntry {
|
||||
struct zwlr_foreign_toplevel_handle_v1 *handle;
|
||||
char name[256];
|
||||
char clazz[256];
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
void handleTitle(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, const char *title) {
|
||||
struct xdpw_screencast_context *ctx = data;
|
||||
|
||||
struct SToplevelEntry *current;
|
||||
wl_list_for_each(current, &ctx->toplevel_resource_list, link) {
|
||||
if (current->handle == handle) {
|
||||
strncpy(current->name, title, 255);
|
||||
current->name[255] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleAppID(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, const char *app_id) {
|
||||
struct xdpw_screencast_context *ctx = data;
|
||||
|
||||
struct SToplevelEntry *current;
|
||||
wl_list_for_each(current, &ctx->toplevel_resource_list, link) {
|
||||
if (current->handle == handle) {
|
||||
strncpy(current->clazz, app_id, 255);
|
||||
current->name[255] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleOutputEnter(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, struct wl_output *output) {
|
||||
; // noop
|
||||
}
|
||||
|
||||
void handleOutputLeave(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, struct wl_output *output) {
|
||||
; // noop
|
||||
}
|
||||
|
||||
void handleState(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, struct wl_array *state) {
|
||||
; // noop
|
||||
}
|
||||
|
||||
void handleDone(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle) {
|
||||
; // noop
|
||||
}
|
||||
|
||||
void handleClosed(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle) {
|
||||
struct xdpw_screencast_context *ctx = data;
|
||||
|
||||
struct SToplevelEntry *current;
|
||||
wl_list_for_each(current, &ctx->toplevel_resource_list, link) {
|
||||
if (current->handle == handle) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
wl_list_remove(¤t->link);
|
||||
}
|
||||
|
||||
void handleParent(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, struct zwlr_foreign_toplevel_handle_v1 *parent) {
|
||||
; // noop
|
||||
}
|
||||
|
||||
struct zwlr_foreign_toplevel_handle_v1_listener toplevelHandleListener = {
|
||||
.title = handleTitle,
|
||||
.app_id = handleAppID,
|
||||
.output_enter = handleOutputEnter,
|
||||
.output_leave = handleOutputLeave,
|
||||
.state = handleState,
|
||||
.done = handleDone,
|
||||
.closed = handleClosed,
|
||||
.parent = handleParent,
|
||||
};
|
||||
|
||||
void handleToplevel(void *data, struct zwlr_foreign_toplevel_manager_v1 *manager, struct zwlr_foreign_toplevel_handle_v1 *toplevel) {
|
||||
struct xdpw_screencast_context *ctx = data;
|
||||
|
||||
struct SToplevelEntry* entry = malloc(sizeof(struct SToplevelEntry));
|
||||
|
||||
entry->handle = toplevel;
|
||||
|
||||
wl_list_insert(&ctx->toplevel_resource_list, &entry->link);
|
||||
|
||||
zwlr_foreign_toplevel_handle_v1_add_listener(toplevel, &toplevelHandleListener, ctx);
|
||||
}
|
||||
|
||||
void handleFinished(void *data, struct zwlr_foreign_toplevel_manager_v1 *zwlr_foreign_toplevel_manager_v1) {
|
||||
; // noop
|
||||
}
|
||||
|
||||
struct zwlr_foreign_toplevel_manager_v1_listener toplevelListener = {
|
||||
.toplevel = handleToplevel,
|
||||
.finished = handleFinished,
|
||||
};
|
||||
|
||||
struct SToplevelEntry* toplevelEntryFromID(struct xdpw_screencast_context *ctx, uint32_t id) {
|
||||
struct SToplevelEntry *current;
|
||||
wl_list_for_each(current, &ctx->toplevel_resource_list, link) {
|
||||
if (((uint64_t)current->handle & 0xFFFFFFFF) == id) {
|
||||
return current;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
void wlr_frame_free(struct xdpw_screencast_instance *cast) {
|
||||
if (!cast->wlr_frame) {
|
||||
|
@ -423,8 +535,15 @@ void xdpw_wlr_register_cb(struct xdpw_screencast_instance *cast) {
|
|||
cast->ctx->screencopy_manager, cast->with_cursor, cast->target.output->output);
|
||||
} else {
|
||||
// share window
|
||||
cast->frame_callback_hyprland = hyprland_toplevel_export_manager_v1_capture_toplevel(
|
||||
cast->ctx->hyprland_toplevel_manager, cast->with_cursor, cast->target.window_handle);
|
||||
struct SToplevelEntry* entry = toplevelEntryFromID(cast->ctx, cast->target.window_handle);
|
||||
|
||||
if (!entry) {
|
||||
logprint(DEBUG, "hyprland: error in getting entry");
|
||||
return;
|
||||
}
|
||||
|
||||
cast->frame_callback_hyprland = hyprland_toplevel_export_manager_v1_capture_toplevel_with_wlr_toplevel_handle(
|
||||
cast->ctx->hyprland_toplevel_manager, cast->with_cursor, entry->handle);
|
||||
|
||||
hyprland_toplevel_export_frame_v1_add_listener(cast->frame_callback_hyprland,
|
||||
&hyprland_frame_listener, cast);
|
||||
|
@ -514,6 +633,65 @@ static void wlr_init_xdg_outputs(struct xdpw_screencast_context *ctx) {
|
|||
}
|
||||
}
|
||||
|
||||
// stolen from LLVM cuz it wouldnt include lol
|
||||
static inline int vasprintf(char **strp, const char *fmt, va_list ap) {
|
||||
const size_t buff_size = 256;
|
||||
if ((*strp = (char *)malloc(buff_size)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
va_list ap_copy;
|
||||
// va_copy may not be provided by the C library in C++ 03 mode.
|
||||
#if defined(_LIBCPP_CXX03_LANG) && __has_builtin(__builtin_va_copy)
|
||||
__builtin_va_copy(ap_copy, ap);
|
||||
#else
|
||||
va_copy(ap_copy, ap);
|
||||
#endif
|
||||
int str_size = vsnprintf(*strp, buff_size, fmt, ap_copy);
|
||||
va_end(ap_copy);
|
||||
|
||||
if ((size_t)str_size >= buff_size) {
|
||||
if ((*strp = (char *)realloc(*strp, str_size + 1)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
str_size = vsnprintf(*strp, str_size + 1, fmt, ap);
|
||||
}
|
||||
return str_size;
|
||||
}
|
||||
|
||||
char *getFormat(const char *fmt, ...) {
|
||||
char *outputStr = NULL;
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vasprintf(&outputStr, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return outputStr;
|
||||
}
|
||||
|
||||
char* buildWindowList(struct xdpw_screencast_context *ctx) {
|
||||
|
||||
char* rolling = calloc(1, 1);
|
||||
|
||||
struct SToplevelEntry* current;
|
||||
wl_list_for_each(current, &ctx->toplevel_resource_list, link) {
|
||||
|
||||
char* oldRolling = rolling;
|
||||
|
||||
rolling = getFormat("%s%u[HC\011]%s[HT\011]%s[HE\011]", rolling, (uint32_t)(((uint64_t)current->handle) & 0xFFFFFFFF), current->clazz, current->name);
|
||||
|
||||
free(oldRolling);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < strlen(rolling); ++i) {
|
||||
if (rolling[i] == '\"')
|
||||
rolling[i] = ' ';
|
||||
}
|
||||
|
||||
return rolling;
|
||||
}
|
||||
|
||||
struct xdpw_share xdpw_wlr_chooser(struct xdpw_screencast_context *ctx) {
|
||||
char result[1024] = {0};
|
||||
FILE *fp;
|
||||
|
@ -523,13 +701,11 @@ struct xdpw_share xdpw_wlr_chooser(struct xdpw_screencast_context *ctx) {
|
|||
const char *XCURSOR_SIZE = getenv("XCURSOR_SIZE");
|
||||
const char *HYPRLAND_INSTANCE_SIGNATURE = getenv("HYPRLAND_INSTANCE_SIGNATURE");
|
||||
|
||||
char cmd[256] = "WAYLAND_DISPLAY=";
|
||||
strcat(cmd, WAYLAND_DISPLAY);
|
||||
strcat(cmd, " XCURSOR_SIZE=");
|
||||
strcat(cmd, XCURSOR_SIZE ? XCURSOR_SIZE : "24");
|
||||
strcat(cmd, " HYPRLAND_INSTANCE_SIGNATURE=");
|
||||
strcat(cmd, HYPRLAND_INSTANCE_SIGNATURE ? HYPRLAND_INSTANCE_SIGNATURE : "0");
|
||||
strcat(cmd, " QT_QPA_PLATFORM=wayland hyprland-share-picker");
|
||||
char* windowList = buildWindowList(ctx);
|
||||
|
||||
char *cmd = getFormat("WAYLAND_DISPLAY=%s XCURSOR_SIZE=%s HYPRLAND_INSTANCE_SIGNATURE=%s XDPH_WINDOW_SHARING_LIST=\"%s\" hyprland-share-picker", WAYLAND_DISPLAY, XCURSOR_SIZE ? XCURSOR_SIZE : "24", HYPRLAND_INSTANCE_SIGNATURE ? HYPRLAND_INSTANCE_SIGNATURE : "0", windowList);
|
||||
|
||||
free(windowList);
|
||||
|
||||
logprint(DEBUG, "Screencast: Picker: Running command \"%s\"", cmd);
|
||||
|
||||
|
@ -545,6 +721,8 @@ struct xdpw_share xdpw_wlr_chooser(struct xdpw_screencast_context *ctx) {
|
|||
|
||||
pclose(fp);
|
||||
|
||||
free(cmd);
|
||||
|
||||
// great, let's parse it.
|
||||
|
||||
struct xdpw_share res = {NULL, -1, -1, -1, -1, -1};
|
||||
|
@ -630,7 +808,7 @@ struct xdpw_share xdpw_wlr_chooser(struct xdpw_screencast_context *ctx) {
|
|||
strncpy(display_name, result + 7, strlen(result) - 8);
|
||||
display_name[strlen(result) - 8] = 0;
|
||||
|
||||
res.window_handle = strtol(display_name, NULL, 16);
|
||||
res.window_handle = strtol(display_name, NULL, 10);
|
||||
|
||||
free(display_name);
|
||||
return res;
|
||||
|
@ -882,6 +1060,17 @@ static void wlr_registry_handle_add(void *data, struct wl_registry *reg,
|
|||
ctx->hyprland_toplevel_manager = wl_registry_bind(reg, id, &hyprland_toplevel_export_manager_v1_interface, version);
|
||||
}
|
||||
|
||||
if (!strcmp(interface, zwlr_foreign_toplevel_manager_v1_interface.name)) {
|
||||
uint32_t version = ver;
|
||||
|
||||
logprint(DEBUG, "hyprland: |-- registered to interface %s (Version %u)", interface, version);
|
||||
|
||||
ctx->wlroots_toplevel_manager = wl_registry_bind(reg, id, &zwlr_foreign_toplevel_manager_v1_interface, version);
|
||||
wl_list_init(&ctx->toplevel_resource_list);
|
||||
|
||||
zwlr_foreign_toplevel_manager_v1_add_listener(ctx->wlroots_toplevel_manager, &toplevelListener, ctx);
|
||||
}
|
||||
|
||||
if (strcmp(interface, wl_shm_interface.name) == 0) {
|
||||
logprint(DEBUG, "wlroots: |-- registered to interface %s (Version %u)", interface, WL_SHM_VERSION);
|
||||
ctx->shm = wl_registry_bind(reg, id, &wl_shm_interface, WL_SHM_VERSION);
|
||||
|
|
Loading…
Reference in a new issue