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
1314class wayfire_foreign_toplevel ;
1415using 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+
1634class 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