1 /*
2  * SPDX-FileCopyrightText: 2017-2017 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  */
7 #ifndef _FCITX_WAYLAND_CORE_DISPLAY_H_
8 #define _FCITX_WAYLAND_CORE_DISPLAY_H_
9 
10 #include <algorithm>
11 #include <list>
12 #include <memory>
13 #include <set>
14 #include <string>
15 #include <tuple>
16 #include <unordered_map>
17 #include <wayland-client.h>
18 #include "fcitx-utils/signals.h"
19 #include "outputinformation.h"
20 #include "wl_registry.h"
21 
22 namespace fcitx {
23 namespace wayland {
24 
25 class WlOutput;
26 class WlCallback;
27 
28 class GlobalsFactoryBase {
29 public:
~GlobalsFactoryBase()30     virtual ~GlobalsFactoryBase() {}
31     virtual std::shared_ptr<void> create(WlRegistry &, uint32_t name,
32                                          uint32_t version) = 0;
erase(uint32_t name)33     void erase(uint32_t name) { globals_.erase(name); }
34 
globals()35     const std::set<uint32_t> &globals() { return globals_; }
36 
37 protected:
38     std::set<uint32_t> globals_;
39 };
40 
41 template <typename T>
42 class GlobalsFactory : public GlobalsFactoryBase {
43 public:
create(WlRegistry & registry,uint32_t name,uint32_t version)44     virtual std::shared_ptr<void> create(WlRegistry &registry, uint32_t name,
45                                          uint32_t version) {
46         std::shared_ptr<T> p;
47         p.reset(registry.bind<T>(name, std::min(version, T::version)));
48         globals_.insert(name);
49         return p;
50     }
51 };
52 
53 class Display {
54 public:
55     Display(wl_display *display);
56     ~Display();
57 
fd()58     int fd() const { return wl_display_get_fd(display_.get()); }
59 
60     operator wl_display *() { return display_.get(); }
61 
62     void roundtrip();
63     void sync();
64     void flush();
65     void run();
66 
67     WlRegistry *registry();
68 
69     const OutputInfomation *outputInformation(WlOutput *output) const;
70 
71     template <typename T>
getGlobals()72     std::vector<std::shared_ptr<T>> getGlobals() {
73         auto iter = requestedGlobals_.find(T::interface);
74         if (iter == requestedGlobals_.end()) {
75             return {};
76         }
77         auto &items = iter->second->globals();
78         std::vector<std::shared_ptr<T>> results;
79         for (uint32_t item : items) {
80             auto iter = globals_.find(item);
81             results.push_back(std::static_pointer_cast<T>(
82                 std::get<std::shared_ptr<void>>(iter->second)));
83         }
84 
85         return results;
86     }
87 
88     template <typename T>
getGlobal()89     std::shared_ptr<T> getGlobal() {
90         auto globals = getGlobals<T>();
91         if (!globals.empty()) {
92             return globals[0];
93         }
94         return {};
95     }
96 
97     template <typename T>
getGlobal(uint32_t name)98     std::shared_ptr<T> getGlobal(uint32_t name) {
99         auto iter = globals_.find(name);
100         if (iter != globals_.end() &&
101             std::get<std::string>(iter->second) == T::interface) {
102             return std::static_pointer_cast<T>(
103                 std::get<std::shared_ptr<void>>(iter->second));
104         }
105         return {};
106     }
107 
108     template <typename T>
requestGlobals()109     void requestGlobals() {
110         auto result = requestedGlobals_.emplace(std::make_pair(
111             T::interface, std::make_unique<GlobalsFactory<T>>()));
112         if (result.second) {
113             auto iter = result.first;
114             for (auto &p : globals_) {
115                 if (std::get<std::string>(p.second) == T::interface) {
116                     createGlobalHelper(iter->second.get(), p);
117                 }
118             }
119         }
120     }
121 
globalCreated()122     auto &globalCreated() { return globalCreatedSignal_; }
globalRemoved()123     auto &globalRemoved() { return globalRemovedSignal_; }
124 
125 private:
126     void createGlobalHelper(
127         GlobalsFactoryBase *factory,
128         std::pair<const uint32_t, std::tuple<std::string, uint32_t, uint32_t,
129                                              std::shared_ptr<void>>>
130             &globalsPair);
131 
132     void addOutput(wayland::WlOutput *output);
133     void removeOutput(wayland::WlOutput *output);
134 
135     fcitx::Signal<void(const std::string &, std::shared_ptr<void>)>
136         globalCreatedSignal_;
137     fcitx::Signal<void(const std::string &, std::shared_ptr<void>)>
138         globalRemovedSignal_;
139     std::unordered_map<std::string, std::unique_ptr<GlobalsFactoryBase>>
140         requestedGlobals_;
141     UniqueCPtr<wl_display, wl_display_disconnect> display_;
142     std::unique_ptr<WlRegistry> registry_;
143     std::unordered_map<uint32_t, std::tuple<std::string, uint32_t, uint32_t,
144                                             std::shared_ptr<void>>>
145         globals_;
146     std::list<fcitx::Connection> conns_;
147     std::list<std::unique_ptr<WlCallback>> callbacks_;
148     std::unordered_map<WlOutput *, OutputInfomation> outputInfo_;
149 };
150 } // namespace wayland
151 } // namespace fcitx
152 
153 #endif // _FCITX_WAYLAND_CORE_DISPLAY_H_
154