1 #include "hotspot-manager.hpp"
2 
process_input_motion(wf::point_t gc)3 void wf::hotspot_instance_t::process_input_motion(wf::point_t gc)
4 {
5     if (!(hotspot_geometry[0] & gc) && !(hotspot_geometry[1] & gc))
6     {
7         timer.disconnect();
8         return;
9     }
10 
11     if (!timer.is_connected())
12     {
13         timer.set_timeout(timeout_ms, [=] ()
14         {
15             callback(this->edges);
16             return false;
17         });
18     }
19 }
20 
pin(wf::dimensions_t dim)21 wf::geometry_t wf::hotspot_instance_t::pin(wf::dimensions_t dim) noexcept
22 {
23     auto og = output->get_layout_geometry();
24 
25     wf::geometry_t result;
26     result.width  = dim.width;
27     result.height = dim.height;
28 
29     if (this->edges & OUTPUT_EDGE_LEFT)
30     {
31         result.x = og.x;
32     } else if (this->edges & OUTPUT_EDGE_RIGHT)
33     {
34         result.x = og.x + og.width - dim.width;
35     } else
36     {
37         result.x = og.x + og.width / 2 - dim.width / 2;
38     }
39 
40     if (this->edges & OUTPUT_EDGE_TOP)
41     {
42         result.y = og.y;
43     } else if (this->edges & OUTPUT_EDGE_BOTTOM)
44     {
45         result.y = og.y + og.height - dim.height;
46     } else
47     {
48         result.y = og.y + og.height / 2 - dim.height / 2;
49     }
50 
51     // Need to clamp if the region is very wide
52     return wf::clamp(result, og);
53 }
54 
recalc_geometry()55 void wf::hotspot_instance_t::recalc_geometry() noexcept
56 {
57     uint32_t cnt_edges = __builtin_popcount(edges);
58 
59     if (cnt_edges == 2)
60     {
61         hotspot_geometry[0] = pin({away, along});
62         hotspot_geometry[1] = pin({along, away});
63     } else
64     {
65         wf::dimensions_t dim;
66         if (edges & (OUTPUT_EDGE_LEFT | OUTPUT_EDGE_RIGHT))
67         {
68             dim = {away, along};
69         } else
70         {
71             dim = {along, away};
72         }
73 
74         hotspot_geometry[0] = pin(dim);
75         hotspot_geometry[1] = hotspot_geometry[0];
76     }
77 }
78 
hotspot_instance_t(wf::output_t * output,uint32_t edges,uint32_t along,uint32_t away,int32_t timeout,std::function<void (uint32_t)> callback)79 wf::hotspot_instance_t::hotspot_instance_t(wf::output_t *output, uint32_t edges,
80     uint32_t along, uint32_t away, int32_t timeout,
81     std::function<void(uint32_t)> callback)
82 {
83     output->connect_signal("configuration-changed", &on_output_config_changed);
84     wf::get_core().connect_signal("pointer_motion", &on_motion_event);
85     wf::get_core().connect_signal("tablet_axis", &on_motion_event);
86     wf::get_core().connect_signal("touch_motion", &on_touch_motion_event);
87 
88     this->edges = edges;
89     this->along = along;
90     this->away  = away;
91     this->timeout_ms = timeout;
92     this->output     = output;
93     this->callback   = callback;
94 
95     recalc_geometry();
96 
97     // callbacks
98     on_motion_event.set_callback([=] (wf::signal_data_t *data)
99     {
100         auto gcf = wf::get_core().get_cursor_position();
101         wf::point_t gc{(int)gcf.x, (int)gcf.y};
102         process_input_motion(gc);
103     });
104 
105     on_touch_motion_event.set_callback([=] (wf::signal_data_t *data)
106     {
107         auto gcf = wf::get_core().get_touch_position(0);
108         wf::point_t gc{(int)gcf.x, (int)gcf.y};
109         process_input_motion(gc);
110     });
111 
112     on_output_config_changed.set_callback([=] (wf::signal_data_t*)
113     {
114         recalc_geometry();
115     });
116 }
117 
update_hotspots(const container_t & activators)118 void wf::hotspot_manager_t::update_hotspots(const container_t& activators)
119 {
120     hotspots.clear();
121     for (const auto& opt : activators)
122     {
123         auto opt_hotspots = opt->activated_by->get_value().get_hotspots();
124         for (const auto& hs : opt_hotspots)
125         {
126             auto activator_cb = opt->callback;
127             auto callback = [activator_cb] (uint32_t edges)
128             {
129                 wf::activator_data_t data = {
130                     .source = activator_source_t::HOTSPOT,
131                     .activation_data = edges,
132                 };
133                 (*activator_cb)(data);
134             };
135 
136             auto instance = std::make_unique<hotspot_instance_t>(output,
137                 hs.get_edges(), hs.get_size_along_edge(),
138                 hs.get_size_away_from_edge(), hs.get_timeout(), callback);
139             hotspots.push_back(std::move(instance));
140         }
141     }
142 }
143