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