Skip to content

Commit 1e630e6

Browse files
committed
foreign-toplevel: send DBus annotation related to global menus
Note: this requires an update to the protocol and wlroots. This forwards the information received by the KDE AppMenu and GTK Shell protocols using the proposed extension to wlr-foreign-toplevel that allows forwarding information about DBus interfaces.
1 parent 10ce4d7 commit 1e630e6

File tree

1 file changed

+189
-0
lines changed

1 file changed

+189
-0
lines changed

plugins/protocols/foreign-toplevel.cpp

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,29 @@
88
#include <wayfire/toplevel-view.hpp>
99
#include <wayfire/window-manager.hpp>
1010
#include "gtk-shell.hpp"
11+
#include "kde-appmenu.hpp"
1112
#include "config.h"
1213

1314
class wayfire_foreign_toplevel;
1415
using foreign_toplevel_map_type = std::map<wayfire_toplevel_view, std::unique_ptr<wayfire_foreign_toplevel>>;
1516

17+
class toplevel_gtk_shell1_dbus_properties_t : public wf::custom_data_t
18+
{
19+
public:
20+
std::optional<std::string> app_menu_path;
21+
std::optional<std::string> menubar_path;
22+
std::optional<std::string> window_object_path;
23+
std::optional<std::string> application_object_path;
24+
std::optional<std::string> unique_bus_name;
25+
};
26+
27+
class toplevel_kde_appmenu_path_t : public wf::custom_data_t
28+
{
29+
public:
30+
std::optional<std::string> service_name;
31+
std::optional<std::string> object_path;
32+
};
33+
1634
class wayfire_foreign_toplevel
1735
{
1836
wayfire_toplevel_view view;
@@ -62,6 +80,59 @@ class wayfire_foreign_toplevel
6280
wlr_foreign_toplevel_handle_v1_destroy(handle);
6381
}
6482

83+
void toplevel_send_gtk_shell1_dbus_properties(
84+
const char *app_menu_path,
85+
const char *menubar_path,
86+
const char *window_object_path,
87+
const char *application_object_path,
88+
const char *unique_bus_name)
89+
{
90+
// !! TODO: app_menu_path (not sure which interface it corresponds to)
91+
92+
if (menubar_path && unique_bus_name)
93+
{
94+
wlr_foreign_toplevel_handle_v1_add_surface_dbus_annotation(
95+
handle, "org.gtk.Menus", unique_bus_name, menubar_path);
96+
} else
97+
{
98+
wlr_foreign_toplevel_handle_v1_remove_surface_dbus_annotation(
99+
handle, "org.gtk.Menus");
100+
}
101+
102+
if (window_object_path && unique_bus_name)
103+
{
104+
wlr_foreign_toplevel_handle_v1_add_surface_dbus_annotation(
105+
handle, "org.gtk.Actions", unique_bus_name, window_object_path);
106+
} else
107+
{
108+
wlr_foreign_toplevel_handle_v1_remove_surface_dbus_annotation(
109+
handle, "org.gtk.Actions");
110+
}
111+
112+
if (application_object_path && unique_bus_name)
113+
{
114+
wlr_foreign_toplevel_handle_v1_add_client_dbus_annotation(
115+
handle, "org.gtk.Actions", unique_bus_name, application_object_path);
116+
} else
117+
{
118+
wlr_foreign_toplevel_handle_v1_remove_client_dbus_annotation(
119+
handle, "org.gtk.Actions");
120+
}
121+
}
122+
123+
void toplevel_send_kde_appmenu_path(const char *service_name, const char *object_path)
124+
{
125+
if (service_name && object_path)
126+
{
127+
wlr_foreign_toplevel_handle_v1_add_surface_dbus_annotation(
128+
handle, "com.canonical.dbusmenu", service_name, object_path);
129+
} else
130+
{
131+
wlr_foreign_toplevel_handle_v1_remove_surface_dbus_annotation(
132+
handle, "com.canonical.dbusmenu");
133+
}
134+
}
135+
65136
private:
66137
void toplevel_send_title()
67138
{
@@ -257,6 +328,8 @@ class wayfire_foreign_toplevel_protocol_impl : public wf::plugin_interface_t
257328
toplevel_manager = wlr_foreign_toplevel_manager_v1_create(wf::get_core().display);
258329
wf::get_core().connect(&on_view_mapped);
259330
wf::get_core().connect(&on_view_unmapped);
331+
wf::get_core().connect(&on_view_dbus_properties_changed);
332+
wf::get_core().connect(&on_view_kde_appmenu_changed);
260333
}
261334

262335
void fini() override
@@ -275,6 +348,23 @@ class wayfire_foreign_toplevel_protocol_impl : public wf::plugin_interface_t
275348
auto handle = wlr_foreign_toplevel_handle_v1_create(toplevel_manager);
276349
handle_for_view[toplevel] =
277350
std::make_unique<wayfire_foreign_toplevel>(toplevel, handle, &handle_for_view);
351+
352+
if (auto props = toplevel->get_data<toplevel_gtk_shell1_dbus_properties_t>())
353+
{
354+
handle_for_view[toplevel]->toplevel_send_gtk_shell1_dbus_properties(
355+
props->app_menu_path ? props->app_menu_path->c_str() : nullptr,
356+
props->menubar_path ? props->menubar_path->c_str() : nullptr,
357+
props->window_object_path ? props->window_object_path->c_str() : nullptr,
358+
props->application_object_path ? props->application_object_path->c_str() : nullptr,
359+
props->unique_bus_name ? props->unique_bus_name->c_str() : nullptr);
360+
}
361+
362+
if (auto props = toplevel->get_data<toplevel_kde_appmenu_path_t>())
363+
{
364+
handle_for_view[toplevel]->toplevel_send_kde_appmenu_path(
365+
props->service_name ? props->service_name->c_str() : nullptr,
366+
props->object_path ? props->object_path->c_str() : nullptr);
367+
}
278368
}
279369
};
280370

@@ -283,6 +373,105 @@ class wayfire_foreign_toplevel_protocol_impl : public wf::plugin_interface_t
283373
handle_for_view.erase(toplevel_cast(ev->view));
284374
};
285375

376+
wf::signal::connection_t<gtk_shell_dbus_properties_signal> on_view_dbus_properties_changed =
377+
[=] (gtk_shell_dbus_properties_signal *ev)
378+
{
379+
if (auto toplevel = wf::toplevel_cast(ev->view))
380+
{
381+
auto it = handle_for_view.find(toplevel);
382+
if (it != handle_for_view.end())
383+
{
384+
it->second->toplevel_send_gtk_shell1_dbus_properties(
385+
ev->app_menu_path,
386+
ev->menubar_path,
387+
ev->window_object_path,
388+
ev->application_object_path,
389+
ev->unique_bus_name);
390+
}
391+
392+
/* Store the values with the view. This is necessary to cover the cases when either:
393+
* (1) the view has not been mapped yet; or (2) the view is later unmapped and remapped
394+
*/
395+
auto props = toplevel->get_data_safe<toplevel_gtk_shell1_dbus_properties_t>();
396+
if (ev->app_menu_path)
397+
{
398+
props->app_menu_path = ev->app_menu_path;
399+
} else
400+
{
401+
props->app_menu_path.reset();
402+
}
403+
404+
if (ev->application_object_path)
405+
{
406+
props->application_object_path =
407+
ev->application_object_path;
408+
} else
409+
{
410+
props->application_object_path.reset();
411+
}
412+
413+
if (ev->menubar_path)
414+
{
415+
props->menubar_path = ev->menubar_path;
416+
} else
417+
{
418+
props->menubar_path.reset();
419+
}
420+
421+
if (ev->unique_bus_name)
422+
{
423+
props->unique_bus_name = ev->unique_bus_name;
424+
} else
425+
{
426+
props->unique_bus_name.reset();
427+
}
428+
429+
if (ev->window_object_path)
430+
{
431+
props->window_object_path =
432+
ev->window_object_path;
433+
} else
434+
{
435+
props->window_object_path.reset();
436+
}
437+
}
438+
};
439+
440+
wf::signal::connection_t<kde_appmenu_dbus_address_signal> on_view_kde_appmenu_changed =
441+
[=] (kde_appmenu_dbus_address_signal *ev)
442+
{
443+
if (auto toplevel = wf::toplevel_cast(ev->view))
444+
{
445+
auto it = handle_for_view.find(toplevel);
446+
if (it != handle_for_view.end())
447+
{
448+
it->second->toplevel_send_kde_appmenu_path(
449+
ev->service_name,
450+
ev->object_path);
451+
}
452+
453+
/* Store the values with the view. This is necessary to cover the cases when either:
454+
* (1) the view has not been mapped yet; or (2) the view is later unmapped and remapped
455+
*/
456+
auto props = toplevel->get_data_safe<toplevel_kde_appmenu_path_t>();
457+
if (ev->service_name)
458+
{
459+
props->service_name = ev->service_name;
460+
} else
461+
{
462+
props->service_name.reset();
463+
}
464+
465+
if (ev->object_path)
466+
{
467+
props->object_path = ev->object_path;
468+
} else
469+
{
470+
props->object_path.reset();
471+
}
472+
}
473+
};
474+
286475
wlr_foreign_toplevel_manager_v1 *toplevel_manager;
287476
std::map<wayfire_toplevel_view, std::unique_ptr<wayfire_foreign_toplevel>> handle_for_view;
288477
};

0 commit comments

Comments
 (0)