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