1 #define E_COMP_WL
2 #include "e.h"
3 #include "e_mod_main.h"
4 #include "input-method-unstable-v1-server-protocol.h"
5
6 typedef struct _E_Input_Panel E_Input_Panel;
7 typedef struct _E_Input_Panel_Surface E_Input_Panel_Surface;
8
9 struct _E_Input_Panel
10 {
11 struct wl_resource *resource;
12 Eina_List *surfaces;
13 };
14
15 struct _E_Input_Panel_Surface
16 {
17 E_Client *ec;
18
19 Eina_Bool panel;
20 Eina_Bool showing;
21 };
22
23 static E_Input_Panel input_panel;
24 static Eina_List *handlers = NULL;
25 static struct wl_global *input_panel_global = NULL;
26
27 static void
_e_input_panel_surface_cb_toplevel_set(struct wl_client * client EINA_UNUSED,struct wl_resource * resource,struct wl_resource * output_resource EINA_UNUSED,uint32_t position EINA_UNUSED)28 _e_input_panel_surface_cb_toplevel_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *output_resource EINA_UNUSED, uint32_t position EINA_UNUSED)
29 {
30 E_Input_Panel_Surface *ips;
31
32 ips = wl_resource_get_user_data(resource);
33 ips->panel = EINA_FALSE;
34 }
35
36 static void
_e_input_panel_surface_cb_overlay_panel_set(struct wl_client * client EINA_UNUSED,struct wl_resource * resource)37 _e_input_panel_surface_cb_overlay_panel_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
38 {
39 E_Input_Panel_Surface *ips;
40
41 ips = wl_resource_get_user_data(resource);
42 ips->panel = EINA_TRUE;
43 }
44
45 static const struct zwp_input_panel_surface_v1_interface _e_input_panel_surface_implementation = {
46 _e_input_panel_surface_cb_toplevel_set,
47 _e_input_panel_surface_cb_overlay_panel_set
48 };
49
50 static void
_e_input_panel_surface_resource_destroy(struct wl_resource * resource)51 _e_input_panel_surface_resource_destroy(struct wl_resource *resource)
52 {
53 E_Input_Panel_Surface *ips;
54 E_Client *ec;
55
56 ips = wl_resource_get_user_data(resource);
57 ec = ips->ec;
58 if (!e_object_is_del(E_OBJECT(ec)))
59 {
60 if (ec->comp_data->mapped)
61 {
62 if ((ec->comp_data->shell.surface) &&
63 (ec->comp_data->shell.unmap))
64 ec->comp_data->shell.unmap(ec->comp_data->shell.surface);
65 }
66 if (ec->parent)
67 {
68 ec->parent->transients =
69 eina_list_remove(ec->parent->transients, ec);
70 }
71 ec->comp_data->shell.surface = NULL;
72 }
73
74 input_panel.surfaces = eina_list_remove(input_panel.surfaces, ips);
75
76 free(ips);
77 }
78
79 static void
_e_input_panel_position_set(E_Client * ec,int w,int h)80 _e_input_panel_position_set(E_Client *ec, int w, int h)
81 {
82 int nx, ny;
83 int zx, zy, zw, zh;
84
85 e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh);
86
87 nx = zx + (zw - w) / 2;
88 ny = zy + zh - h;
89
90 e_client_util_move_without_frame(ec, nx, ny);
91 }
92
93 static void
_e_input_panel_surface_visible_update(E_Input_Panel_Surface * ips)94 _e_input_panel_surface_visible_update(E_Input_Panel_Surface *ips)
95 {
96 E_Client *ec;
97
98 ec = ips->ec;
99 if ((ips->showing) &&
100 (e_pixmap_usable_get(ec->pixmap)))
101 {
102 if (!ips->panel)
103 _e_input_panel_position_set(ec, ec->client.w, ec->client.h);
104
105 ec->visible = EINA_TRUE;
106 evas_object_geometry_set(ec->frame, ec->x, ec->y, ec->w, ec->h);
107 evas_object_show(ec->frame);
108 e_comp_object_damage(ec->frame, ec->x, ec->y, ec->w, ec->h);
109 }
110 else
111 {
112 ec->visible = EINA_FALSE;
113 evas_object_hide(ec->frame);
114 }
115 }
116
117 static void
_e_input_panel_surface_configure(struct wl_resource * resource,Evas_Coord x EINA_UNUSED,Evas_Coord y EINA_UNUSED,Evas_Coord w,Evas_Coord h)118 _e_input_panel_surface_configure(struct wl_resource *resource, Evas_Coord x EINA_UNUSED, Evas_Coord y EINA_UNUSED, Evas_Coord w, Evas_Coord h)
119 {
120 E_Input_Panel_Surface *ips;
121
122 ips = wl_resource_get_user_data(resource);
123
124 e_client_util_resize_without_frame(ips->ec, w, h);
125
126 if (ips->showing)
127 _e_input_panel_surface_visible_update(ips);
128 }
129
130 static void
_e_input_panel_surface_map(struct wl_resource * resource)131 _e_input_panel_surface_map(struct wl_resource *resource)
132 {
133 E_Input_Panel_Surface *ips;
134 E_Client *ec;
135
136 ips = wl_resource_get_user_data(resource);
137 ec = ips->ec;
138
139 if (e_object_is_del(E_OBJECT(ec)))
140 return;
141
142 // NOTE: we need to set mapped, so that avoid showing evas_object and continue buffer's commit process.
143 if ((!ec->comp_data->mapped) && (e_pixmap_usable_get(ec->pixmap)))
144 ec->comp_data->mapped = EINA_TRUE;
145 }
146
147 static void
_e_input_panel_surface_unmap(struct wl_resource * resource)148 _e_input_panel_surface_unmap(struct wl_resource *resource)
149 {
150 E_Input_Panel_Surface *ips;
151 E_Client *ec;
152
153 ips = wl_resource_get_user_data(resource);
154 ec = ips->ec;
155
156 if (e_object_is_del(E_OBJECT(ec)))
157 return;
158
159 if (ec->comp_data->mapped)
160 {
161 ec->visible = EINA_FALSE;
162 evas_object_hide(ec->frame);
163 ec->comp_data->mapped = EINA_FALSE;
164 }
165 }
166
167 static void
_e_input_panel_cb_surface_get(struct wl_client * client,struct wl_resource * resource EINA_UNUSED,uint32_t id,struct wl_resource * surface_resource)168 _e_input_panel_cb_surface_get(struct wl_client *client, struct wl_resource *resource EINA_UNUSED, uint32_t id, struct wl_resource *surface_resource)
169 {
170 E_Client *ec;
171 E_Input_Panel_Surface *ips;
172 E_Comp_Client_Data *cd;
173
174 ec = wl_resource_get_user_data(surface_resource);
175 if (!ec)
176 {
177 wl_resource_post_error(surface_resource,
178 WL_DISPLAY_ERROR_INVALID_OBJECT,
179 "No Client Set On Surface");
180 return;
181 }
182
183 cd = ec->comp_data;
184 if (!cd)
185 {
186 wl_resource_post_error(surface_resource,
187 WL_DISPLAY_ERROR_INVALID_OBJECT,
188 "No Comp Data For Client");
189 return;
190 }
191
192 /* check for existing shell surface */
193 if (ec->comp_data->shell.surface)
194 {
195 wl_resource_post_error(surface_resource,
196 WL_DISPLAY_ERROR_INVALID_OBJECT,
197 "Client already has shell surface");
198 return;
199 }
200
201 ips = E_NEW(E_Input_Panel_Surface, 1);
202 if (!ips)
203 {
204 wl_client_post_no_memory(client);
205 return;
206 }
207
208 cd->shell.surface = wl_resource_create(client,
209 &zwp_input_panel_surface_v1_interface,
210 1, id);
211 if (!cd->shell.surface)
212 {
213 wl_client_post_no_memory(client);
214 free(ips);
215 return;
216 }
217
218 ips->ec = ec;
219
220 EC_CHANGED(ec);
221 if (!ec->new_client)
222 {
223 ec->new_client = EINA_TRUE;
224 e_comp->new_clients++;
225 }
226 if (ec->ignored)
227 e_client_unignore(ec);
228
229 /* set input panel client properties */
230 ec->borderless = EINA_TRUE;
231 ec->argb = EINA_TRUE;
232 ec->lock_border = EINA_TRUE;
233 ec->lock_focus_in = ec->lock_focus_out = EINA_TRUE;
234 ec->netwm.state.skip_taskbar = EINA_TRUE;
235 ec->netwm.state.skip_pager = EINA_TRUE;
236 ec->no_shape_cut = EINA_TRUE;
237 ec->border_size = 0;
238 ec->netwm.type = E_WINDOW_TYPE_UTILITY;
239
240
241 cd->surface = surface_resource;
242 cd->shell.configure_send = NULL;
243 cd->shell.configure = _e_input_panel_surface_configure;
244 cd->shell.ping = NULL;
245 cd->shell.map = _e_input_panel_surface_map;
246 cd->shell.unmap = _e_input_panel_surface_unmap;
247
248
249 wl_resource_set_implementation(cd->shell.surface,
250 &_e_input_panel_surface_implementation,
251 ips, _e_input_panel_surface_resource_destroy);
252
253 input_panel.surfaces = eina_list_append(input_panel.surfaces, ips);
254 }
255
256 static const struct zwp_input_panel_v1_interface _e_input_panel_implementation = {
257 _e_input_panel_cb_surface_get
258 };
259
260 static void
_e_input_panel_unbind(struct wl_resource * resource EINA_UNUSED)261 _e_input_panel_unbind(struct wl_resource *resource EINA_UNUSED)
262 {
263 input_panel.resource = NULL;
264
265 E_FREE_FUNC(input_panel.surfaces, eina_list_free);
266 }
267
268 static void
_e_input_panel_bind(struct wl_client * client,void * data EINA_UNUSED,uint32_t version EINA_UNUSED,uint32_t id)269 _e_input_panel_bind(struct wl_client *client, void *data EINA_UNUSED, uint32_t version EINA_UNUSED, uint32_t id)
270 {
271 struct wl_resource *resource;
272
273 resource = wl_resource_create(client, &zwp_input_panel_v1_interface, 1, id);
274 if (!resource)
275 {
276 wl_client_post_no_memory(client);
277 return;
278 }
279
280 if (input_panel.resource)
281 {
282 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
283 "interface object already bound");
284 return;
285 }
286
287 input_panel.resource = resource;
288
289 wl_resource_set_implementation(resource,
290 &_e_input_panel_implementation,
291 NULL, _e_input_panel_unbind);
292 }
293
294 static Eina_Bool
_e_input_panel_cb_visible_change(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)295 _e_input_panel_cb_visible_change(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
296 {
297 E_Event_Text_Input_Panel_Visibility_Change *ev = event;
298 E_Input_Panel_Surface *ips;
299 Eina_List *l;
300
301 EINA_LIST_FOREACH(input_panel.surfaces, l, ips)
302 {
303 if (!ips->ec) continue;
304 ips->showing = ev->visible;
305 _e_input_panel_surface_visible_update(ips);
306 }
307
308 return ECORE_CALLBACK_RENEW;
309 }
310
311 EINTERN Eina_Bool
e_input_panel_init(void)312 e_input_panel_init(void)
313 {
314 E_LIST_HANDLER_APPEND(handlers, E_EVENT_TEXT_INPUT_PANEL_VISIBILITY_CHANGE,
315 _e_input_panel_cb_visible_change, NULL);
316 // TODO: add signal handler - update input panel
317
318 input_panel_global = wl_global_create(e_comp->wl_comp_data->wl.disp,
319 &zwp_input_panel_v1_interface, 1,
320 NULL, _e_input_panel_bind);
321 if (!input_panel_global)
322 {
323 ERR("failed to create wl_global for input panel");
324 return EINA_FALSE;
325 }
326
327 return EINA_TRUE;
328 }
329
330 EINTERN void
e_input_panel_shutdown(void)331 e_input_panel_shutdown(void)
332 {
333 E_FREE_FUNC(input_panel_global, wl_global_destroy);
334 E_FREE_LIST(handlers, ecore_event_handler_del);
335 }
336