e58bcac3e67e1785e33414e91c2d53733cc285b3
[profile/ivi/ico-uxf-weston-plugin.git] / src / ico_input-panel.c
1 /*
2  * Copyright © 2010-2012 Intel Corporation
3  * Copyright © 2011-2012 Collabora, Ltd.
4  * Copyright © 2013 Raspberry Pi Foundation
5  * Copyright © 2013-2014 TOYOTA MOTOR CORPORATION.
6  *
7  * Permission to use, copy, modify, distribute, and sell this software and
8  * its documentation for any purpose is hereby granted without fee, provided
9  * that the above copyright notice appear in all copies and that both that
10  * copyright notice and this permission notice appear in supporting
11  * documentation, and that the name of the copyright holders not be used in
12  * advertising or publicity pertaining to distribution of the software
13  * without specific, written prior permission.  The copyright holders make
14  * no representations about the suitability of this software for any
15  * purpose.  It is provided "as is" without express or implied warranty.
16  *
17  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
18  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
19  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
20  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
21  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
22  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
23  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24  */
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 #include "ico_ivi_shell.h"
31 #include "ico_ivi_shell_private.h"
32 #include "desktop-shell-server-protocol.h"
33 #include "input-method-server-protocol.h"
34
35 struct input_panel_surface {
36     struct wl_resource *resource;
37     struct wl_signal destroy_signal;
38
39     struct desktop_shell *shell;
40
41     struct wl_list link;
42     struct weston_surface *surface;
43     struct weston_view *view;
44     struct wl_listener surface_destroy_listener;
45
46     struct weston_output *output;
47     uint32_t panel;
48 };
49
50 extern int  ico_debug_level;
51
52 /* debug log macros         */
53 #define uifw_debug(fmt,...)  \
54     { if (ico_debug_level >= 5) {weston_log("DBG>"fmt" (%s:%d)\n",##__VA_ARGS__,__FILE__,__LINE__);} }
55 #define uifw_trace(fmt,...)  \
56     { if (ico_debug_level >= 4) {weston_log("TRC>"fmt" (%s:%d)\n",##__VA_ARGS__,__FILE__,__LINE__);} }
57 #define uifw_info(fmt,...)  \
58     { if (ico_debug_level >= 3) {weston_log("INF>"fmt" (%s:%d)\n",##__VA_ARGS__,__FILE__,__LINE__);} }
59 #define uifw_warn(fmt,...)  \
60     { if (ico_debug_level >= 2) {weston_log("WRN>"fmt" (%s:%d)\n",##__VA_ARGS__,__FILE__,__LINE__);} }
61 #define uifw_error(fmt,...)  \
62     { if (ico_debug_level >= 1) {weston_log("ERR>"fmt" (%s:%d)\n",##__VA_ARGS__,__FILE__,__LINE__);} }
63
64 static void
65 show_input_panels(struct wl_listener *listener, void *data)
66 {
67     struct desktop_shell *shell =
68         container_of(listener, struct desktop_shell,
69                  show_input_panel_listener);
70     struct input_panel_surface *ipsurf, *next;
71
72     shell->text_input.surface = (struct weston_surface*)data;
73
74     uifw_trace("show_input_panels: Enter(surface=%08x[%d])",
75                (int)data, shell->showing_input_panels);
76
77     if (shell->showing_input_panels)    {
78         uifw_trace("show_input_panels: Leave(already)");
79         return;
80     }
81     shell->showing_input_panels = true;
82
83     /* if ico_window_mgr hook, call hook routine    */
84     if (shell_hook_show_layer)  {
85         (*shell_hook_show_layer)(LAYER_TYPE_INPUTPANEL, 1, data);
86         return;
87     }
88
89     if (!shell->locked)
90         wl_list_insert(&shell->panel_layer.link,
91                    &shell->input_panel_layer.link);
92     wl_list_for_each_safe(ipsurf, next,
93                   &shell->input_panel.surfaces, link) {
94         if (ipsurf->surface->width == 0)
95             continue;
96         uifw_debug("show_input_panels: insert view=%08x surf=%08x",
97                    (int)ipsurf->view, (int)ipsurf->surface);
98         wl_list_remove(&ipsurf->view->layer_link);
99         wl_list_init(&ipsurf->view->layer_link);
100         wl_list_insert(&shell->input_panel_layer.view_list,
101                    &ipsurf->view->layer_link);
102         weston_view_geometry_dirty(ipsurf->view);
103         weston_view_update_transform(ipsurf->view);
104         weston_surface_damage(ipsurf->surface);
105         weston_slide_run(ipsurf->view, ipsurf->surface->height * 0.9,
106                  0, NULL, NULL);
107     }
108     uifw_trace("show_input_panels: Leave");
109 }
110
111 static void
112 hide_input_panels(struct wl_listener *listener, void *data)
113 {
114     struct desktop_shell *shell =
115         container_of(listener, struct desktop_shell,
116                  hide_input_panel_listener);
117     struct weston_view *view, *next;
118
119     uifw_trace("hide_input_panels: Enter(surface=%08x[%d])",
120                (int)data, shell->showing_input_panels);
121
122     if (!shell->showing_input_panels)   {
123         uifw_trace("hide_input_panels: Leave(not show)");
124         return;
125     }
126     shell->showing_input_panels = false;
127
128     /* if ico_window_mgr hook, call hook routine    */
129     if (shell_hook_show_layer)  {
130         (*shell_hook_show_layer)(LAYER_TYPE_INPUTPANEL, 0, NULL);
131         return;
132     }
133
134     if (!shell->locked)
135         wl_list_remove(&shell->input_panel_layer.link);
136
137     wl_list_for_each_safe(view, next,
138                   &shell->input_panel_layer.view_list, layer_link)
139         weston_view_unmap(view);
140     uifw_trace("hide_input_panels: Leave");
141 }
142
143 static void
144 update_input_panels(struct wl_listener *listener, void *data)
145 {
146     struct desktop_shell *shell =
147         container_of(listener, struct desktop_shell,
148                  update_input_panel_listener);
149
150     memcpy(&shell->text_input.cursor_rectangle, data, sizeof(pixman_box32_t));
151 }
152
153 static void
154 input_panel_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
155 {
156     struct input_panel_surface *ip_surface = surface->configure_private;
157     struct desktop_shell *shell = ip_surface->shell;
158     struct weston_view *view;
159     float x, y;
160
161     uifw_trace("input_panel_configure: Enter(surface=%08x x/y=%d/%d w/h=%d/%d)",
162                (int)surface, sx, sy, surface->width, surface->height);
163
164     if (surface->width == 0)    {
165         uifw_trace("input_panel_configure: Leave(width==0)");
166         return;
167     }
168     if (ip_surface->panel) {
169         view = get_default_view(shell->text_input.surface);
170         if (view == NULL)   {
171             uifw_trace("input_panel_configure: Leave(no view)");
172             return;
173         }
174         x = view->geometry.x + shell->text_input.cursor_rectangle.x2;
175         y = view->geometry.y + shell->text_input.cursor_rectangle.y2;
176     } else {
177         x = ip_surface->output->x + (ip_surface->output->width - surface->width) / 2;
178         y = ip_surface->output->y + ip_surface->output->height - surface->height;
179         if (! shell_hook_map)  {
180             y -= 132.0f;
181         }
182     }
183
184     weston_view_set_position(ip_surface->view, x, y);
185
186     if (!weston_surface_is_mapped(surface) && shell->showing_input_panels) {
187         wl_list_insert(&shell->input_panel_layer.view_list,
188                    &ip_surface->view->layer_link);
189         weston_view_update_transform(ip_surface->view);
190         weston_surface_damage(surface);
191         weston_slide_run(ip_surface->view, ip_surface->view->surface->height * 0.9, 0, NULL, NULL);
192     }
193
194     if (shell_hook_map)  {
195         int     wx, wy;
196         int     ww, wh;
197         wx = (int)x;
198         wy = (int)y;
199         ww = ip_surface->output->width;
200         wh = ip_surface->output->height;
201         (*shell_hook_map)(surface, &ww, &wh, &wx, &wy);
202     }
203     if (shell_hook_configure)  {
204         (*shell_hook_configure)(surface);
205     }
206     uifw_trace("input_panel_configure: Leave");
207 }
208
209 static void
210 destroy_input_panel_surface(struct input_panel_surface *input_panel_surface)
211 {
212     wl_signal_emit(&input_panel_surface->destroy_signal, input_panel_surface);
213
214     wl_list_remove(&input_panel_surface->surface_destroy_listener.link);
215     wl_list_remove(&input_panel_surface->link);
216
217     uifw_trace("destroy_input_panel_surface: Enter(surface=%08x)",
218                (int)input_panel_surface->surface);
219
220     input_panel_surface->surface->configure = NULL;
221     weston_view_destroy(input_panel_surface->view);
222
223     free(input_panel_surface);
224     uifw_trace("destroy_input_panel_surface: Leave");
225 }
226
227 static struct input_panel_surface *
228 get_input_panel_surface(struct weston_surface *surface)
229 {
230     if (surface->configure == input_panel_configure) {
231         return surface->configure_private;
232     } else {
233         return NULL;
234     }
235 }
236
237 static void
238 input_panel_handle_surface_destroy(struct wl_listener *listener, void *data)
239 {
240     struct input_panel_surface *ipsurface = container_of(listener,
241                                  struct input_panel_surface,
242                                  surface_destroy_listener);
243
244     if (ipsurface->resource) {
245         wl_resource_destroy(ipsurface->resource);
246     } else {
247         destroy_input_panel_surface(ipsurface);
248     }
249 }
250
251 static struct input_panel_surface *
252 create_input_panel_surface(struct desktop_shell *shell,
253                struct weston_surface *surface)
254 {
255     struct input_panel_surface *input_panel_surface;
256
257     input_panel_surface = calloc(1, sizeof *input_panel_surface);
258     if (!input_panel_surface)
259         return NULL;
260
261     uifw_trace("create_input_panel_surface: Enter(surface=%08x)", (int)surface);
262
263     surface->configure = input_panel_configure;
264     surface->configure_private = input_panel_surface;
265
266     input_panel_surface->shell = shell;
267
268     input_panel_surface->surface = surface;
269     input_panel_surface->view = weston_view_create(surface);
270
271     wl_signal_init(&input_panel_surface->destroy_signal);
272     input_panel_surface->surface_destroy_listener.notify = input_panel_handle_surface_destroy;
273     wl_signal_add(&surface->destroy_signal,
274               &input_panel_surface->surface_destroy_listener);
275
276     wl_list_init(&input_panel_surface->link);
277
278     uifw_trace("create_input_panel_surface: Leave(ipsurf=%08x)", (int)input_panel_surface);
279
280     return input_panel_surface;
281 }
282
283 static void
284 input_panel_surface_set_toplevel(struct wl_client *client,
285                  struct wl_resource *resource,
286                  struct wl_resource *output_resource,
287                  uint32_t position)
288 {
289     struct input_panel_surface *input_panel_surface =
290         wl_resource_get_user_data(resource);
291     struct desktop_shell *shell = input_panel_surface->shell;
292
293     wl_list_insert(&shell->input_panel.surfaces,
294                &input_panel_surface->link);
295
296     input_panel_surface->output = wl_resource_get_user_data(output_resource);
297     input_panel_surface->panel = 0;
298 }
299
300 static void
301 input_panel_surface_set_overlay_panel(struct wl_client *client,
302                       struct wl_resource *resource)
303 {
304     struct input_panel_surface *input_panel_surface =
305         wl_resource_get_user_data(resource);
306     struct desktop_shell *shell = input_panel_surface->shell;
307
308     wl_list_insert(&shell->input_panel.surfaces,
309                &input_panel_surface->link);
310
311     input_panel_surface->panel = 1;
312 }
313
314 static const struct wl_input_panel_surface_interface input_panel_surface_implementation = {
315     input_panel_surface_set_toplevel,
316     input_panel_surface_set_overlay_panel
317 };
318
319 static void
320 destroy_input_panel_surface_resource(struct wl_resource *resource)
321 {
322     struct input_panel_surface *ipsurf =
323         wl_resource_get_user_data(resource);
324
325     destroy_input_panel_surface(ipsurf);
326 }
327
328 static void
329 input_panel_get_input_panel_surface(struct wl_client *client,
330                     struct wl_resource *resource,
331                     uint32_t id,
332                     struct wl_resource *surface_resource)
333 {
334     struct weston_surface *surface =
335         wl_resource_get_user_data(surface_resource);
336     struct desktop_shell *shell = wl_resource_get_user_data(resource);
337     struct input_panel_surface *ipsurf;
338
339     uifw_trace("input_panel_get_input_panel_surface: Enter");
340
341     if (get_input_panel_surface(surface)) {
342         wl_resource_post_error(surface_resource,
343                        WL_DISPLAY_ERROR_INVALID_OBJECT,
344                        "wl_input_panel::get_input_panel_surface already requested");
345         return;
346     }
347
348     ipsurf = create_input_panel_surface(shell, surface);
349     if (!ipsurf) {
350         wl_resource_post_error(surface_resource,
351                        WL_DISPLAY_ERROR_INVALID_OBJECT,
352                        "surface->configure already set");
353         return;
354     }
355
356     ipsurf->resource =
357         wl_resource_create(client,
358                    &wl_input_panel_surface_interface, 1, id);
359     wl_resource_set_implementation(ipsurf->resource,
360                        &input_panel_surface_implementation,
361                        ipsurf,
362                        destroy_input_panel_surface_resource);
363
364     /* if ico_window_mgr hook, call hook routine    */
365     if (shell_hook_create)  {
366         (*shell_hook_create)(LAYER_TYPE_INPUTPANEL,
367                              surface, client, (struct shell_surface *)ipsurf);
368     }
369     uifw_trace("input_panel_get_input_panel_surface: Leave");
370 }
371
372 static const struct wl_input_panel_interface input_panel_implementation = {
373     input_panel_get_input_panel_surface
374 };
375
376 static void
377 unbind_input_panel(struct wl_resource *resource)
378 {
379     struct desktop_shell *shell = wl_resource_get_user_data(resource);
380
381     shell->input_panel.binding = NULL;
382 }
383
384 static void
385 bind_input_panel(struct wl_client *client,
386           void *data, uint32_t version, uint32_t id)
387 {
388     struct desktop_shell *shell = data;
389     struct wl_resource *resource;
390
391     resource = wl_resource_create(client,
392                       &wl_input_panel_interface, 1, id);
393
394     if (shell->input_panel.binding == NULL) {
395         wl_resource_set_implementation(resource,
396                            &input_panel_implementation,
397                            shell, unbind_input_panel);
398         shell->input_panel.binding = resource;
399         return;
400     }
401
402     wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
403                    "interface object already bound");
404     wl_resource_destroy(resource);
405 }
406
407 void
408 input_panel_destroy(struct desktop_shell *shell)
409 {
410     wl_list_remove(&shell->show_input_panel_listener.link);
411     wl_list_remove(&shell->hide_input_panel_listener.link);
412 }
413
414 int
415 input_panel_setup(struct desktop_shell *shell)
416 {
417     struct weston_compositor *ec = shell->compositor;
418
419     shell->show_input_panel_listener.notify = show_input_panels;
420     wl_signal_add(&ec->show_input_panel_signal,
421               &shell->show_input_panel_listener);
422     shell->hide_input_panel_listener.notify = hide_input_panels;
423     wl_signal_add(&ec->hide_input_panel_signal,
424               &shell->hide_input_panel_listener);
425     shell->update_input_panel_listener.notify = update_input_panels;
426     wl_signal_add(&ec->update_input_panel_signal,
427               &shell->update_input_panel_listener);
428
429     wl_list_init(&shell->input_panel.surfaces);
430
431     if (wl_global_create(shell->compositor->wl_display,
432                  &wl_input_panel_interface, 1,
433                  shell, bind_input_panel) == NULL)
434         return -1;
435
436     return 0;
437 }
438
439 WL_EXPORT   struct weston_view  *
440 ico_input_panel_get_view(void *ipsurf)
441 {
442     return ((struct input_panel_surface *)ipsurf)->view;
443 }