Tizen 2.1 base
[framework/uifw/ecore.git] / src / lib / ecore_wayland / ecore_wl_window.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include "ecore_wl_private.h"
6
7 /* local function prototypes */
8 static void _ecore_wl_window_cb_ping(void *data __UNUSED__, struct wl_shell_surface *shell_surface, unsigned int serial);
9 static void _ecore_wl_window_cb_configure(void *data, struct wl_shell_surface *shell_surface __UNUSED__, unsigned int edges, int w, int h);
10 static void _ecore_wl_window_cb_popup_done(void *data, struct wl_shell_surface *shell_surface __UNUSED__);
11 static void _ecore_wl_window_cb_surface_enter(void *data, struct wl_surface *surface, struct wl_output *output __UNUSED__);
12 static void _ecore_wl_window_cb_surface_leave(void *data, struct wl_surface *surface, struct wl_output *output __UNUSED__);
13 static void _ecore_wl_window_configure_send(Ecore_Wl_Window *win, int w, int h);
14 static char *_ecore_wl_window_id_str_get(unsigned int win_id);
15
16 /* local variables */
17 static Eina_Hash *_windows = NULL;
18
19 /* wayland listeners */
20 static const struct wl_surface_listener _ecore_wl_surface_listener = 
21 {
22    _ecore_wl_window_cb_surface_enter,
23    _ecore_wl_window_cb_surface_leave
24 };
25
26 static const struct wl_shell_surface_listener _ecore_wl_shell_surface_listener = 
27 {
28    _ecore_wl_window_cb_ping,
29    _ecore_wl_window_cb_configure,
30    _ecore_wl_window_cb_popup_done
31 };
32
33 /* internal functions */
34 void 
35 _ecore_wl_window_init(void)
36 {
37    if (!_windows) 
38      _windows = eina_hash_string_superfast_new(NULL);
39 }
40
41 void 
42 _ecore_wl_window_shutdown(void)
43 {
44    eina_hash_free(_windows);
45    _windows = NULL;
46 }
47
48 /**
49  * @defgroup Ecore_Wl_Window_Group Wayland Library Init and Shutdown Functions
50  * 
51  * Functions that can be used to create a Wayland window.
52  */
53
54 /**
55  * Creates a new window
56  * 
57  * @param parent The parent window to use. If @p parent is @c 0, the root window 
58  *               of the default display is used.
59  * @param x      X Position
60  * @param y      Y position
61  * @param w      Width
62  * @param h      Height
63  * @param buffer_type The type of the buffer to be used to create a new Ecore_Wl_Window.
64  * 
65  * @return The new window
66  * 
67  * @ingroup Ecore_Wl_Window_Group
68  * @since 1.2
69  */
70 EAPI Ecore_Wl_Window *
71 ecore_wl_window_new(Ecore_Wl_Window *parent, int x, int y, int w, int h, int buffer_type)
72 {
73    Ecore_Wl_Window *win;
74    static int _win_id = 1;
75
76    LOGFN(__FILE__, __LINE__, __FUNCTION__);
77
78    if (!(win = malloc(sizeof(Ecore_Wl_Window))))
79      {
80         ERR("Failed to allocate an Ecore Wayland Window");
81         return NULL;
82      }
83
84    memset(win, 0, sizeof(Ecore_Wl_Window));
85
86    win->display = _ecore_wl_disp;
87    win->parent = parent;
88    win->allocation.x = x;
89    win->allocation.y = y;
90    win->allocation.w = w;
91    win->allocation.h = h;
92    win->saved_allocation = win->allocation;
93    win->transparent = EINA_FALSE;
94    /* win->type = ECORE_WL_WINDOW_TYPE_TOPLEVEL; */
95    win->type = ECORE_WL_WINDOW_TYPE_NONE;
96    win->buffer_type = buffer_type;
97    win->id = _win_id++;
98
99    eina_hash_add(_windows, _ecore_wl_window_id_str_get(win->id), win);
100    return win;
101 }
102
103 /**
104  * Deletes the given window
105  * 
106  * @param win The given window
107  * 
108  * @ingroup Ecore_Wl_Window_Group
109  * @since 1.2
110  */
111 EAPI void 
112 ecore_wl_window_free(Ecore_Wl_Window *win)
113 {
114    Ecore_Wl_Input *input;
115
116    LOGFN(__FILE__, __LINE__, __FUNCTION__);
117
118    if (!win) return;
119
120    eina_hash_del(_windows, _ecore_wl_window_id_str_get(win->id), win);
121
122    wl_list_for_each(input, &_ecore_wl_disp->inputs, link)
123      {
124         if ((input->pointer_focus) && (input->pointer_focus == win))
125           input->pointer_focus = NULL;
126         if ((input->keyboard_focus) && (input->keyboard_focus == win))
127           input->keyboard_focus = NULL;
128      }
129
130    if (win->region.input) wl_region_destroy(win->region.input);
131    win->region.input = NULL;
132    if (win->region.opaque) wl_region_destroy(win->region.opaque);
133    win->region.opaque = NULL;
134    if (win->shell_surface) wl_shell_surface_destroy(win->shell_surface);
135    win->shell_surface = NULL;
136
137    if (win->surface) wl_surface_destroy(win->surface);
138    win->surface = NULL;
139
140    /* HMMM, why was this disabled ? */
141    free(win);
142 }
143
144 /**
145  * Signals for Wayland to initiate a window move.
146  * 
147  * The position requested (@p x, @p y) is not honored by Wayland because 
148  * Wayland does not allow specific window placement to be set.
149  * 
150  * @param win The window to move.
151  * @param x   X Position
152  * @param y   Y Position
153  * 
154  * @ingroup Ecore_Wl_Window_Group
155  * @since 1.2
156  */
157 EAPI void 
158 ecore_wl_window_move(Ecore_Wl_Window *win, int x, int y)
159 {
160    LOGFN(__FILE__, __LINE__, __FUNCTION__);
161
162    if (!win) return;
163
164    win->allocation.x = x;
165    win->allocation.y = y;
166
167    if (win->shell_surface)
168      {
169         Ecore_Wl_Input *input;
170
171         if (!(input = win->keyboard_device))
172           {
173              if (win->parent)
174                {
175                   if (!(input = win->parent->keyboard_device))
176                     input = win->parent->pointer_device;
177                }
178           }
179
180         if ((!input) || (!input->seat)) return;
181
182         wl_shell_surface_move(win->shell_surface, input->seat,
183                               input->display->serial);
184      }
185 }
186
187 /**
188  * Signals for Wayland to initiate a window resize.
189  * 
190  * The size requested (@p w, @p h) is not honored by Wayland because 
191  * Wayland does not allow specific window sizes to be set.
192  * 
193  * @param win      The window to resize.
194  * @param w        Width
195  * @param h        Height
196  * @param location The edge of the window from where the resize should start.
197  * 
198  * @ingroup Ecore_Wl_Window_Group
199  * @since 1.2
200  */
201 EAPI void 
202 ecore_wl_window_resize(Ecore_Wl_Window *win, int w, int h, int location)
203 {
204    LOGFN(__FILE__, __LINE__, __FUNCTION__);
205
206    if (!win) return;
207
208    if (win->type != ECORE_WL_WINDOW_TYPE_FULLSCREEN)
209      {
210         win->allocation.w = w;
211         win->allocation.h = h;
212
213         win->region.input = 
214           wl_compositor_create_region(_ecore_wl_disp->wl.compositor);
215         wl_region_add(win->region.input, win->allocation.x, win->allocation.y, 
216                       win->allocation.w, win->allocation.h);
217      }
218
219    if (!win->transparent)
220      {
221         win->region.opaque = 
222           wl_compositor_create_region(_ecore_wl_disp->wl.compositor);
223         wl_region_add(win->region.opaque, win->allocation.x, win->allocation.y, 
224                       win->allocation.w, win->allocation.h);
225      }
226
227    if (win->shell_surface)
228      {
229         Ecore_Wl_Input *input;
230
231         if (!(input = win->keyboard_device))
232           {
233              if (win->parent)
234                {
235                   if (!(input = win->parent->keyboard_device))
236                     input = win->parent->pointer_device;
237                }
238           }
239
240         if ((!input) || (!input->seat)) return;
241
242         wl_shell_surface_resize(win->shell_surface, input->seat, 
243                                 input->display->serial, location);
244      }
245 }
246
247 EAPI void 
248 ecore_wl_window_damage(Ecore_Wl_Window *win, int x, int y, int w, int h)
249 {
250    LOGFN(__FILE__, __LINE__, __FUNCTION__);
251
252    if (!win) return;
253    if (win->surface) 
254      wl_surface_damage(win->surface, x, y, w, h);
255 }
256
257 EAPI void 
258 ecore_wl_window_buffer_attach(Ecore_Wl_Window *win, struct wl_buffer *buffer, int x, int y)
259 {
260    LOGFN(__FILE__, __LINE__, __FUNCTION__);
261
262    if (!win) return;
263
264    switch (win->buffer_type)
265      {
266       case ECORE_WL_WINDOW_BUFFER_TYPE_EGL_WINDOW:
267         win->server_allocation = win->allocation;
268         break;
269       case ECORE_WL_WINDOW_BUFFER_TYPE_EGL_IMAGE:
270       case ECORE_WL_WINDOW_BUFFER_TYPE_SHM:
271         if (win->surface)
272           {
273              if (win->edges & 4) //  resizing from the left
274                x = win->server_allocation.w - win->allocation.w;
275              else
276                x = 0;
277
278              if (win->edges & 1) // resizing from the top
279                y = win->server_allocation.h - win->allocation.h;
280              else
281                y = 0;
282
283              win->edges = 0;
284
285              /* if (buffer) */
286              wl_surface_attach(win->surface, buffer, x, y);
287              wl_surface_damage(win->surface, 0, 0, 
288                                win->allocation.w, win->allocation.h);
289
290              win->server_allocation = win->allocation;
291           }
292         break;
293       default:
294         return;
295      }
296
297    if (win->region.input)
298      {
299         wl_surface_set_input_region(win->surface, win->region.input);
300         wl_region_destroy(win->region.input);
301         win->region.input = NULL;
302      }
303
304    if (win->region.opaque)
305      {
306         wl_surface_set_opaque_region(win->surface, win->region.opaque);
307         wl_region_destroy(win->region.opaque);
308         win->region.opaque = NULL;
309      }
310 }
311
312 /**
313  * Shows a window
314  * 
315  * Synonymous to "mapping" a window in Wayland System terminology.
316  * 
317  * @param win The window to show.
318  * 
319  * @ingroup Ecore_Wl_Window_Group
320  * @since 1.2
321  */
322 EAPI void 
323 ecore_wl_window_show(Ecore_Wl_Window *win)
324 {
325    LOGFN(__FILE__, __LINE__, __FUNCTION__);
326
327    if (!win) return;
328    if (win->surface) return;
329
330    win->surface = wl_compositor_create_surface(_ecore_wl_disp->wl.compositor);
331    wl_surface_set_user_data(win->surface, win);
332    /* wl_surface_add_listener(win->surface, &_ecore_wl_surface_listener, win); */
333
334    win->shell_surface = 
335      wl_shell_get_shell_surface(_ecore_wl_disp->wl.shell, win->surface);
336    wl_shell_surface_add_listener(win->shell_surface, 
337                                  &_ecore_wl_shell_surface_listener, win);
338
339    switch (win->type)
340      {
341       case ECORE_WL_WINDOW_TYPE_FULLSCREEN:
342         wl_shell_surface_set_fullscreen(win->shell_surface, 
343                                         WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
344                                         0, NULL);
345         break;
346       case ECORE_WL_WINDOW_TYPE_MAXIMIZED:
347         wl_shell_surface_set_maximized(win->shell_surface, NULL);
348         break;
349       case ECORE_WL_WINDOW_TYPE_TRANSIENT:
350         wl_shell_surface_set_transient(win->shell_surface, 
351                                        win->parent->surface, 
352                                        win->allocation.x, win->allocation.y, 0);
353         break;
354       case ECORE_WL_WINDOW_TYPE_MENU:
355         wl_shell_surface_set_popup(win->shell_surface, 
356                                    _ecore_wl_disp->input->seat,
357                                    _ecore_wl_disp->serial,
358                                    win->parent->surface, 
359                                    win->allocation.x, win->allocation.y, 0);
360         break;
361       case ECORE_WL_WINDOW_TYPE_NONE:
362         win->type = ECORE_WL_WINDOW_TYPE_TOPLEVEL;
363         /* fallthrough */
364       case ECORE_WL_WINDOW_TYPE_TOPLEVEL:
365         wl_shell_surface_set_toplevel(win->shell_surface);
366         break;
367       default:
368         break;
369      }
370
371    /* if (win->type != ECORE_WL_WINDOW_TYPE_FULLSCREEN) */
372    /*   { */
373    /*      win->region.input =  */
374    /*        wl_compositor_create_region(_ecore_wl_disp->wl.compositor); */
375    /*      wl_region_add(win->region.input, win->allocation.x, win->allocation.y,  */
376    /*                    win->allocation.w, win->allocation.h); */
377    /*   } */
378
379    /* if (!win->transparent) */
380    /*   { */
381    /*      win->region.opaque =  */
382    /*        wl_compositor_create_region(_ecore_wl_disp->wl.compositor); */
383    /*      wl_region_add(win->region.opaque, win->allocation.x, win->allocation.y,  */
384    /*                    win->allocation.w, win->allocation.h); */
385    /*   } */
386 }
387
388 /**
389  * Hides a window
390  * 
391  * Synonymous to "unmapping" a window in Wayland System terminology.
392  * 
393  * @param win The window to hide.
394  * 
395  * @ingroup Ecore_Wl_Window_Group
396  * @since 1.2
397  */
398 EAPI void 
399 ecore_wl_window_hide(Ecore_Wl_Window *win)
400 {
401    LOGFN(__FILE__, __LINE__, __FUNCTION__);
402
403    if (!win) return;
404    if (win->shell_surface) wl_shell_surface_destroy(win->shell_surface);
405    win->shell_surface = NULL;
406    if (win->surface) wl_surface_destroy(win->surface);
407    win->surface = NULL;
408 }
409
410 /**
411  * Raises a window
412  * 
413  * @param win The window to raise.
414  * 
415  * @ingroup Ecore_Wl_Window_Group
416  * @since 1.2
417  */
418 EAPI void 
419 ecore_wl_window_raise(Ecore_Wl_Window *win)
420 {
421    LOGFN(__FILE__, __LINE__, __FUNCTION__);
422
423    if (!win) return;
424    if (win->shell_surface) 
425      wl_shell_surface_set_toplevel(win->shell_surface);
426 }
427
428 EAPI void 
429 ecore_wl_window_maximized_set(Ecore_Wl_Window *win, Eina_Bool maximized)
430 {
431    LOGFN(__FILE__, __LINE__, __FUNCTION__);
432
433    if (!win) return;
434
435    if ((win->type == ECORE_WL_WINDOW_TYPE_MAXIMIZED) == maximized) return;
436    if (win->type == ECORE_WL_WINDOW_TYPE_TOPLEVEL)
437      {
438         win->saved_allocation = win->allocation;
439         if (win->shell_surface) 
440           wl_shell_surface_set_maximized(win->shell_surface, NULL);
441         win->type = ECORE_WL_WINDOW_TYPE_MAXIMIZED;
442      }
443    else if (win->type == ECORE_WL_WINDOW_TYPE_MAXIMIZED)
444      {
445         if (win->shell_surface) 
446           wl_shell_surface_set_toplevel(win->shell_surface);
447         win->type = ECORE_WL_WINDOW_TYPE_TOPLEVEL;
448         _ecore_wl_window_configure_send(win, win->saved_allocation.w, 
449                                         win->saved_allocation.h);
450      }
451 }
452
453 EAPI void 
454 ecore_wl_window_fullscreen_set(Ecore_Wl_Window *win, Eina_Bool fullscreen)
455 {
456    LOGFN(__FILE__, __LINE__, __FUNCTION__);
457
458    if (!win) return;
459    if ((win->type == ECORE_WL_WINDOW_TYPE_FULLSCREEN) == fullscreen) return;
460    if (fullscreen)
461      {
462         win->type = ECORE_WL_WINDOW_TYPE_FULLSCREEN;
463         win->saved_allocation = win->allocation;
464         if (win->shell_surface)
465           wl_shell_surface_set_fullscreen(win->shell_surface, 
466                                           WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
467                                           0, NULL);
468      }
469    else 
470      {
471         if (win->shell_surface)
472           wl_shell_surface_set_toplevel(win->shell_surface);
473         win->type = ECORE_WL_WINDOW_TYPE_TOPLEVEL;
474         _ecore_wl_window_configure_send(win, win->saved_allocation.w, 
475                                         win->saved_allocation.h);
476      }
477 }
478
479 EAPI void 
480 ecore_wl_window_transparent_set(Ecore_Wl_Window *win, Eina_Bool transparent)
481 {
482    LOGFN(__FILE__, __LINE__, __FUNCTION__);
483
484    if (!win) return;
485    win->transparent = transparent;
486    if (win->region.opaque) wl_region_destroy(win->region.opaque);
487    win->region.opaque = NULL;
488    if (!win->transparent)
489      {
490         win->region.opaque = 
491           wl_compositor_create_region(_ecore_wl_disp->wl.compositor);
492         wl_region_add(win->region.opaque, win->allocation.x, win->allocation.y, 
493                       win->allocation.w, win->allocation.h);
494      }
495 }
496
497 EAPI void 
498 ecore_wl_window_update_size(Ecore_Wl_Window *win, int w, int h)
499 {
500    LOGFN(__FILE__, __LINE__, __FUNCTION__);
501
502    if (!win) return;
503    win->allocation.w = w;
504    win->allocation.h = h;
505 }
506
507 EAPI void 
508 ecore_wl_window_update_location(Ecore_Wl_Window *win, int x, int y)
509 {
510    LOGFN(__FILE__, __LINE__, __FUNCTION__);
511
512    if (!win) return;
513    win->allocation.x = x;
514    win->allocation.y = y;
515 }
516
517 EAPI struct wl_surface *
518 ecore_wl_window_surface_get(Ecore_Wl_Window *win)
519 {
520    LOGFN(__FILE__, __LINE__, __FUNCTION__);
521
522    if (!win) return NULL;
523    return win->surface;
524 }
525
526 /* @since 1.2 */
527 EAPI struct wl_shell_surface *
528 ecore_wl_window_shell_surface_get(Ecore_Wl_Window *win)
529 {
530    LOGFN(__FILE__, __LINE__, __FUNCTION__);
531
532    if (!win) return NULL;
533    return win->shell_surface;
534 }
535
536 EAPI Ecore_Wl_Window *
537 ecore_wl_window_find(unsigned int id)
538 {
539    Ecore_Wl_Window *win = NULL;
540
541    win = eina_hash_find(_windows, _ecore_wl_window_id_str_get(id));
542    return win;
543 }
544
545 EAPI void 
546 ecore_wl_window_type_set(Ecore_Wl_Window *win, Ecore_Wl_Window_Type type)
547 {
548    LOGFN(__FILE__, __LINE__, __FUNCTION__);
549
550    if (!win) return;
551    win->type = type;
552 }
553
554 EAPI void 
555 ecore_wl_window_pointer_set(Ecore_Wl_Window *win, struct wl_surface *surface, int hot_x, int hot_y)
556 {
557    Ecore_Wl_Input *input;
558
559    LOGFN(__FILE__, __LINE__, __FUNCTION__);
560
561    if (!win) return;
562
563    if ((input = win->pointer_device))
564      ecore_wl_input_pointer_set(input, surface, hot_x, hot_y);
565 }
566
567 EAPI void
568 ecore_wl_window_cursor_from_name_set(Ecore_Wl_Window *win, const char *cursor_name)
569 {
570    Ecore_Wl_Input *input;
571
572    LOGFN(__FILE__, __LINE__, __FUNCTION__);
573
574    if (!win) return;
575
576    if ((input = win->pointer_device))
577      ecore_wl_input_cursor_from_name_set(input, cursor_name);
578 }
579
580 EAPI void
581 ecore_wl_window_cursor_default_restore(Ecore_Wl_Window *win)
582 {
583    Ecore_Wl_Input *input;
584
585    LOGFN(__FILE__, __LINE__, __FUNCTION__);
586
587    if (!win) return;
588
589    if ((input = win->pointer_device))
590      ecore_wl_input_cursor_default_restore(input);
591 }
592
593 /* @since 1.2 */
594 EAPI void 
595 ecore_wl_window_parent_set(Ecore_Wl_Window *win, Ecore_Wl_Window *parent)
596 {
597    LOGFN(__FILE__, __LINE__, __FUNCTION__);
598
599    win->parent = parent;
600 }
601
602 /* local functions */
603 static void 
604 _ecore_wl_window_cb_ping(void *data __UNUSED__, struct wl_shell_surface *shell_surface, unsigned int serial)
605 {
606    if (!shell_surface) return;
607    wl_shell_surface_pong(shell_surface, serial);
608 }
609
610 static void 
611 _ecore_wl_window_cb_configure(void *data, struct wl_shell_surface *shell_surface __UNUSED__, unsigned int edges, int w, int h)
612 {
613    Ecore_Wl_Window *win;
614
615    LOGFN(__FILE__, __LINE__, __FUNCTION__);
616
617    if (!(win = data)) return;
618
619    if ((w <= 0) || (h <= 0)) return;
620
621    if ((win->allocation.w != w) || (win->allocation.h != h))
622      {
623         win->edges = edges;
624         if (win->region.input) wl_region_destroy(win->region.input);
625         win->region.input = NULL;
626         if (win->region.opaque) wl_region_destroy(win->region.opaque);
627         win->region.opaque = NULL;
628
629         _ecore_wl_window_configure_send(win, w, h);
630      }
631 }
632
633 static void 
634 _ecore_wl_window_cb_popup_done(void *data, struct wl_shell_surface *shell_surface __UNUSED__)
635 {
636    Ecore_Wl_Window *win;
637
638    LOGFN(__FILE__, __LINE__, __FUNCTION__);
639
640    if (!shell_surface) return;
641    if (!(win = data)) return;
642    ecore_wl_input_ungrab(win->pointer_device);
643 }
644
645 static void 
646 _ecore_wl_window_cb_surface_enter(void *data, struct wl_surface *surface, struct wl_output *output __UNUSED__)
647 {
648    Ecore_Wl_Window *win;
649
650    LOGFN(__FILE__, __LINE__, __FUNCTION__);
651
652    if (!surface) return;
653    if (!(win = data)) return;
654 }
655
656 static void 
657 _ecore_wl_window_cb_surface_leave(void *data, struct wl_surface *surface, struct wl_output *output __UNUSED__)
658 {
659    Ecore_Wl_Window *win;
660
661    LOGFN(__FILE__, __LINE__, __FUNCTION__);
662
663    if (!surface) return;
664    if (!(win = data)) return;
665 }
666
667 static void 
668 _ecore_wl_window_configure_send(Ecore_Wl_Window *win, int w, int h)
669 {
670    Ecore_Wl_Event_Window_Configure *ev;
671
672    LOGFN(__FILE__, __LINE__, __FUNCTION__);
673
674    if (!(ev = calloc(1, sizeof(Ecore_Wl_Event_Window_Configure)))) return;
675    ev->win = win->id;
676    ev->event_win = win->id;
677    ev->x = win->allocation.x;
678    ev->y = win->allocation.y;
679    ev->w = w;
680    ev->h = h;
681    ecore_event_add(ECORE_WL_EVENT_WINDOW_CONFIGURE, ev, NULL, NULL);
682 }
683
684 static char *
685 _ecore_wl_window_id_str_get(unsigned int win_id)
686 {
687    const char *vals = "qWeRtYuIoP5$&<~";
688    static char id[9];
689    unsigned int val;
690
691    val = win_id;
692    id[0] = vals[(val >> 28) & 0xf];
693    id[1] = vals[(val >> 24) & 0xf];
694    id[2] = vals[(val >> 20) & 0xf];
695    id[3] = vals[(val >> 16) & 0xf];
696    id[4] = vals[(val >> 12) & 0xf];
697    id[5] = vals[(val >> 8) & 0xf];
698    id[6] = vals[(val >> 4) & 0xf];
699    id[7] = vals[(val) & 0xf];
700    id[8] = 0;
701
702    return id;
703 }