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