1 #include <wayfire/singleton-plugin.hpp>
2 #include <wayfire/plugin.hpp>
3 #include <wayfire/core.hpp>
4 #include <glibmm/main.h>
5 #include <giomm/init.h>
6 #include <glibmm/init.h>
7 #include <wayfire/util/log.hpp>
8 #include <wayfire/config.h>
9 #include <filesystem>
10 #include <dlfcn.h>
11
12 #include <glib-2.0/glib-unix.h>
13
14 static gboolean on_wayland_fd_event(gint fd, GIOCondition condition,
15 gpointer user_data);
16
17 namespace wf
18 {
19 class glib_main_loop_t
20 {
21 Glib::RefPtr<Glib::MainLoop> g_loop;
22
23 public:
glib_main_loop_t()24 glib_main_loop_t()
25 {
26 // IMPORTANT!
27 // Ensure that the .so file for this plugin is never closed, by opening it
28 // with dlopen() once more.
29 auto path = find_plugin_in_path();
30 if (path.empty())
31 {
32 LOGE("Failed to find libglib-main-loop.so! ",
33 "Add it to the WAYFIRE_PLUGIN_PATH.");
34 return;
35 }
36
37 auto handle = dlopen(path.c_str(), RTLD_NOW | RTLD_GLOBAL);
38 if (handle == NULL)
39 {
40 LOGE("Failed to open ", path, ", glib-main-loop cannot work!");
41 return;
42 }
43
44 LOGI("creating main loop");
45
46 Glib::init();
47 Gio::init();
48
49 g_loop = Glib::MainLoop::create();
50 wf::get_core().connect_signal("startup-finished", &glib_loop_run);
51 wf::get_core().connect_signal("shutdown", &glib_loop_quit);
52 }
53
handle_wayland_fd_in(GIOCondition flag)54 void handle_wayland_fd_in(GIOCondition flag)
55 {
56 if (flag != G_IO_IN)
57 {
58 LOGE("A problem in the Wayland event loop has been detected!");
59 g_loop->quit();
60 return;
61 }
62
63 wl_display_flush_clients(wf::get_core().display);
64 wl_event_loop_dispatch(wf::get_core().ev_loop, 0);
65 wl_display_flush_clients(wf::get_core().display);
66 }
67
68 wf::signal_connection_t glib_loop_run = [=] (auto)
__anon9a10aaaf0102(auto) 69 {
70 auto fd = wl_event_loop_get_fd(wf::get_core().ev_loop);
71 g_unix_fd_add(fd, G_IO_IN, on_wayland_fd_event, this);
72 g_unix_fd_add(fd, G_IO_ERR, on_wayland_fd_event, this);
73 g_unix_fd_add(fd, G_IO_HUP, on_wayland_fd_event, this);
74
75 g_loop->run();
76 };
77
78 wf::signal_connection_t glib_loop_quit = [=] (auto)
__anon9a10aaaf0202(auto) 79 {
80 auto display = wf::get_core().display;
81 wl_display_destroy_clients(display);
82 wl_display_destroy(display);
83 std::exit(0);
84 };
85
86 /**
87 * Find the path to this plugin, by searching in Wayfire's search path.
88 *
89 * Code adapted from plugin-loader.cpp
90 */
find_plugin_in_path()91 std::string find_plugin_in_path()
92 {
93 std::vector<std::string> plugin_prefixes;
94 if (char *plugin_path = getenv("WAYFIRE_PLUGIN_PATH"))
95 {
96 std::stringstream ss(plugin_path);
97 std::string entry;
98 while (std::getline(ss, entry, ':'))
99 {
100 plugin_prefixes.push_back(entry);
101 }
102 }
103
104 plugin_prefixes.push_back(PLUGIN_PATH);
105
106 std::string plugin_name = "glib-main-loop";
107 for (std::filesystem::path plugin_prefix : plugin_prefixes)
108 {
109 auto plugin_path = plugin_prefix / ("lib" + plugin_name + ".so");
110 if (std::filesystem::exists(plugin_path))
111 {
112 return plugin_path;
113 }
114 }
115
116 return "";
117 }
118 };
119 }
120
on_wayland_fd_event(gint,GIOCondition condition,gpointer user_data)121 static gboolean on_wayland_fd_event(gint, GIOCondition condition,
122 gpointer user_data)
123 {
124 auto loop = (wf::glib_main_loop_t*)user_data;
125 loop->handle_wayland_fd_in(condition);
126 return true;
127 }
128
129 DECLARE_WAYFIRE_PLUGIN((wf::singleton_plugin_t<wf::glib_main_loop_t, true>));
130