Merge "[Wayland] Add touch event & xdg-shell functions in wayland backend" into tizen
[platform/upstream/SDL.git] / src / video / tizen / SDL_tizenwindow.c
1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
4   Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
5
6   This software is provided 'as-is', without any express or implied
7   warranty.  In no event will the authors be held liable for any damages
8   arising from the use of this software.
9
10   Permission is granted to anyone to use this software for any purpose,
11   including commercial applications, and to alter it and redistribute it
12   freely, subject to the following restrictions:
13
14   1. The origin of this software must not be misrepresented; you must not
15      claim that you wrote the original software. If you use this software
16      in a product, an acknowledgment in the product documentation would be
17      appreciated but is not required.
18   2. Altered source versions must be plainly marked as such, and must not be
19      misrepresented as being the original software.
20   3. This notice may not be removed or altered from any source distribution.
21 */
22
23 #include "../../SDL_internal.h"
24
25 #if SDL_VIDEO_DRIVER_TIZEN
26
27 #include "SDL_log.h"
28 #include "SDL_hints.h"
29 #include "SDL_loadso.h"
30
31 #include "SDL_tizenvideo.h"
32 #include "SDL_tizentouch.h"
33 #include "SDL_tizenkeyboard.h"
34 #include "SDL_tizenmouse.h"
35 #include "SDL_tizenevents_c.h"
36
37 #include "SDL_tizenwindow.h"
38
39 #include "../../events/SDL_mouse_c.h"
40 #include "../../joystick/tizen/SDL_sysjoystick_c.h"
41
42 #include "../SDL_egl_c.h"
43 #include "../SDL_vulkan_c.h"
44 #include "../SDL_sysvideo.h"
45 #include "../../events/SDL_windowevents_c.h"
46
47 enum {
48     ROTATION_TYPE_NORMAL_ROTATION = 0,
49     ROTATION_TYPE_PRE_ROTATION,      /* use pre-rotation */
50 };
51
52 #define LOAD_FUNC(NAME) \
53 _this->tizen_pre_rotation_data->NAME = SDL_LoadFunction(_this->tizen_pre_rotation_data->prerotation_dll_handle, #NAME); \
54 if (!_this->tizen_pre_rotation_data->NAME) \
55 { \
56     SDL_LogError(SDL_LOG_CATEGORY_ASSERT, "Could not retrieve pre-rotation function " #NAME); \
57     return SDL_FALSE; \
58 }
59
60 static int
61 _tizen_rotation_type_get()
62 {
63     static int type = ROTATION_TYPE_PRE_ROTATION;
64     static int checked = 0;
65     char *engine = NULL;
66
67     if (checked) return type;
68
69     engine = getenv("SDL_ROTATION");
70
71     if (engine)
72       {
73          if ((!strcasecmp(engine, "normal")))
74             type = ROTATION_TYPE_NORMAL_ROTATION;
75          else if ((!strcasecmp(engine, "pre_rotation")))
76             type = ROTATION_TYPE_PRE_ROTATION;
77          else
78             type = ROTATION_TYPE_PRE_ROTATION;
79       }
80     checked = 1;
81     return type;
82 }
83
84 int
85 _tizen_PreRotatotion_LoadLibrary(SDL_WindowData *_this, const char *lib_path)
86 {
87     void *lib_dll_handle = NULL;
88     char *path = NULL;
89
90     if (_this->isLoaded_pre_rotation)
91         return SDL_TRUE;
92
93     _this->tizen_pre_rotation_data = (Tizen_Prerotation_Data *) SDL_calloc(1, sizeof(Tizen_Prerotation_Data));
94     if (!_this->tizen_pre_rotation_data) {
95         return SDL_OutOfMemory();
96     }
97
98     if (!lib_path)
99         lib_dll_handle = SDL_LoadObject(lib_path);
100
101     if (!lib_dll_handle) {
102         path = "libwayland-egl.so";
103         lib_dll_handle = SDL_LoadObject(path);
104     }
105
106     _this->tizen_pre_rotation_data->prerotation_dll_handle = lib_dll_handle;
107
108     if (lib_dll_handle == NULL)
109         return SDL_FALSE;
110
111     LOAD_FUNC(wl_egl_window_set_rotation);
112     LOAD_FUNC(wl_egl_window_get_capabilities);
113     _this->isLoaded_pre_rotation = 1;
114
115     return SDL_TRUE;
116 }
117
118 SDL_bool
119 Tizen_GetWindowWMInfo(_THIS, SDL_Window *window, SDL_SysWMinfo *info)
120 {
121     SDL_WindowData *wmdata = (SDL_WindowData *)window->driverdata;
122     info->info.tizen.egl_display = NULL;
123     info->info.tizen.egl_surface = NULL;
124 #if SDL_VIDEO_OPENGL_EGL
125     if (_this->egl_data)
126     {
127        info->info.tizen.egl_display = (void*)_this->egl_data->egl_display;
128     }
129     info->info.tizen.egl_surface = (void*)wmdata->egl_surface;
130 #endif
131     info->subsystem = SDL_SYSWM_TIZEN;
132     return SDL_TRUE;
133 }
134
135 int
136 Tizen_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
137 {
138     return 0;  /* just succeed, the real work is done elsewhere. */
139 }
140
141 void
142 Tizen_ShowWindow(_THIS, SDL_Window *window)
143 {
144     SDL_WindowData *wind = window->driverdata;
145
146     if((window->flags & SDL_WINDOW_FULLSCREEN) || (window->flags & SDL_WINDOW_BORDERLESS))
147     {
148         ecore_wl_window_indicator_state_set(wind->window, ECORE_WL_INDICATOR_STATE_OFF);
149         ecore_wl_window_indicator_opacity_set(wind->window, ECORE_WL_INDICATOR_TRANSPARENT);
150         ecore_wl_indicator_visible_type_set(wind->window, ECORE_WL_INDICATOR_VISIBLE_TYPE_HIDDEN);
151     }
152     else
153     {
154         ecore_wl_window_indicator_state_set(wind->window, ECORE_WL_INDICATOR_STATE_ON);
155         ecore_wl_window_indicator_opacity_set(wind->window, ECORE_WL_INDICATOR_OPAQUE);
156         ecore_wl_indicator_visible_type_set(wind->window, ECORE_WL_INDICATOR_VISIBLE_TYPE_SHOWN);
157     }
158     ecore_wl_window_show(wind->window);
159 }
160
161 void
162 Tizen_SetWindowFullscreen(_THIS, SDL_Window *window,
163                           SDL_VideoDisplay *_display, SDL_bool fullscreen)
164 {
165     /*DO NOTHING*/
166 }
167
168 void
169 Tizen_pre_rotation_set(SDL_WindowData *_this)
170 {
171     tizen_wl_egl_window_rotation rot;
172     if (!_this->egl_window) return;
173
174     switch (_this->rotation) {
175          case 90:
176             rot = TIZEN_ROTATION_270;
177             break;
178          case 180:
179             rot = TIZEN_ROTATION_180;
180             break;
181          case 270:
182             rot = TIZEN_ROTATION_90;
183             break;
184          case 0:
185             rot = TIZEN_ROTATION_0;
186             break;
187          default:
188             rot = TIZEN_ROTATION_0;
189             break;
190       }
191
192       _this->tizen_pre_rotation_data->wl_egl_window_set_rotation(_this->egl_window, rot);
193 }
194
195 void
196 _tizen_window_orientaiton_hint_callback(void *userdata, const char *name, const char *oldValue, const char *newValue)
197 {
198     char *p_str = NULL;
199     char orientation_type[4][20] = {"Portrait","LandscapeLeft","PortraitUpsideDown","LandscapeRight"};
200     int checked[4] = {0,};
201     int i;
202     unsigned int j = 0;
203     SDL_WindowData *wind = (SDL_WindowData*)userdata;
204     Ecore_Wl_Window *window = wind->window;
205
206     if (wind->rotation_supported == 0) {
207         return;
208     }
209
210     SDL_assert(SDL_strncmp(name, SDL_HINT_ORIENTATIONS, SDL_strlen(SDL_HINT_ORIENTATIONS)) == 0);
211
212     if ((oldValue == NULL) && (newValue == NULL)) {
213         return;
214     }
215
216     for (i=0;i<4;i++) {
217         p_str = SDL_strstr(newValue, orientation_type[i]);
218         if (p_str) {
219             if (p_str == newValue) {
220                 int rot = 0;
221                 if (i == 0) rot = 0;
222                 else if (i == 1) rot = 90;
223                 else if (i == 2) rot = 180;
224                 else if (i == 3) rot = 270;
225                 wind->rotation = rot;
226             }
227
228             if (i == 0) {
229                 checked[j] = 0;
230             }
231             else if (i == 1) {
232                 checked[j] = 90;
233             }
234             else if (i == 2) {
235                 checked[j] = 180;
236             }
237             else if (i == 3) {
238                 checked[j] = 270;
239             }
240             j++;
241         }
242     }
243
244     if (j > 0) {
245         if (j == 1) {
246             ecore_wl_window_rotation_preferred_rotation_set(window,wind->rotation);
247             if (wind->support_pre_rotation)
248                 Tizen_pre_rotation_set(wind);
249         }else {
250             ecore_wl_window_rotation_available_rotations_set(window, (const int*)checked, j);
251         }
252     }
253 }
254
255 void
256 _tizen_window_orientation_add_hint(void *data)
257 {
258     SDL_WindowData *wind = (SDL_WindowData*)data;
259     if (wind->rotation_supported == 0) {
260         return;
261     }
262
263     SDL_AddHintCallback(SDL_HINT_ORIENTATIONS, _tizen_window_orientaiton_hint_callback, data);
264 }
265
266 int
267 Tizen_CreateWindow(_THIS, SDL_Window *window)
268 {
269     SDL_VideoData *data = _this->driverdata;
270     SDL_WindowData *wind;
271     Ecore_Wl_Global *global;
272     Eina_Inlist *globals;
273
274     wind = calloc(1, sizeof * wind);
275     if (!wind) {
276         return SDL_OutOfMemory();
277     }
278
279     window->driverdata = wind;
280     window->flags |= SDL_WINDOW_INPUT_FOCUS;    /* always has input focus */
281
282 #if SDL_VIDEO_OPENGL_EGL
283     if (window->flags & SDL_WINDOW_OPENGL) {
284         SDL_GL_LoadLibrary(NULL);
285     }
286 #endif
287
288 #if SDL_VIDEO_VULKAN
289     if (window->flags & SDL_WINDOW_VULKAN) {
290         if (!_this->vulkan_GetInstanceExtensions) {
291             SDL_SetError("No Vulkan support in video driver");
292         }
293
294         if (_this->vulkan_LoadLibrary(_this, NULL) < 0) {
295             SDL_SetError("Fail to load Vulkan Library");
296         }
297     }
298 #endif
299
300     if (window->x == SDL_WINDOWPOS_UNDEFINED) {
301         window->x = 0;
302     }
303     if (window->y == SDL_WINDOWPOS_UNDEFINED) {
304         window->y = 0;
305     }
306
307     if (!(globals = ecore_wl_globals_get()))
308       {
309          SDL_LogError(SDL_LOG_CATEGORY_ASSERT, "Failed to get wayland globals");
310          return -1;
311       }
312
313     wind->window = ecore_wl_window_new(NULL,
314                                        window->x, window->y, window->w, window->h,
315                                        ECORE_WL_WINDOW_BUFFER_TYPE_SHM);
316     wind->surface = ecore_wl_window_surface_create(wind->window);
317     ecore_wl_window_type_set(wind->window, ECORE_WL_WINDOW_TYPE_UTILITY);
318
319     wind->rotation = 0;
320     wind->rotation_supported = 0;
321     wind->received_rotation = 0;
322     ecore_wl_window_opaque_region_set(wind->window, window->x, window->y, window->w, window->h);
323
324 #if SDL_VIDEO_OPENGL_EGL
325     if (window->flags & SDL_WINDOW_OPENGL) {
326         wind->egl_window = wl_egl_window_create(ecore_wl_window_surface_get(wind->window), window->w, window->h);
327
328         /* Create the GLES window surface */
329         wind->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) wind->egl_window);
330         if (wind->egl_surface == EGL_NO_SURFACE) {
331             SDL_LogError(SDL_LOG_CATEGORY_ASSERT, "failed to create a window surface");
332             return -1;
333         }
334
335         //Support PreRotation
336         wind->support_pre_rotation = 0;
337         if (_tizen_rotation_type_get() && _tizen_PreRotatotion_LoadLibrary(wind, "libwayland-egl.so")) {
338             if (wind->tizen_pre_rotation_data->wl_egl_window_get_capabilities(wind->egl_window) == TIZEN_WL_EGL_WINDOW_CAPABILITY_ROTATION_SUPPORTED ) {
339                 wind->support_pre_rotation = 1;
340             }
341         }
342     }
343 #endif
344
345     wind->id = ecore_wl_window_id_get(wind->window);
346     eina_hash_add(data->windows, &wind->id, window);
347
348     Tizen_InitKeyboard(_this);
349     SDL_SetMouseFocus(window);
350
351     if (window->flags & 0x00008000) {
352         ecore_wl_window_input_region_set(wind->window, -1, -1, 1, 1);
353         ecore_wl_window_focus_skip_set(wind->window, EINA_TRUE);
354     }
355
356     EINA_INLIST_FOREACH(globals, global) {
357          if (!strcmp(global->interface, "tizen_policy_ext")) {
358               wind->rotation_supported = 1;
359               break;
360            }
361       }
362     // Add orientaiton hint cb
363     _tizen_window_orientation_add_hint((void*)wind);
364
365
366     return 0;
367 }
368
369 void
370 Tizen_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
371 {
372 //Add setting window bordered.
373 }
374
375 void
376 _tizen_window_resize(SDL_Window *window)
377 {
378     SDL_WindowData *wind = window->driverdata;
379     if (!wind->egl_window) {
380         return;
381     }
382
383     if(wind->support_pre_rotation && (wind->rotation==90 || wind->rotation==270))
384         ecore_wl_window_update_size(wind->window, window->h, window->w);
385     else
386         ecore_wl_window_update_size(wind->window, window->w, window->h);
387
388     // TODO : consider to rotation status.
389 #if SDL_VIDEO_OPENGL_EGL
390     if (window->flags & SDL_WINDOW_OPENGL) {
391       if(wind->support_pre_rotation && (wind->rotation==90 || wind->rotation==270))
392           wl_egl_window_resize(wind->egl_window, window->h, window->w, 0, 0);
393       else
394           wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
395     }
396 #endif
397 }
398
399 void
400 _tizen_setwindowsize(SDL_Window *window)
401 {
402     SDL_WindowData *wind = window->driverdata;
403     if (!wind->window) {
404         return;
405     }
406 }
407
408 void
409 Tizen_SetWindowSize(_THIS, SDL_Window *window)
410 {
411     _tizen_window_resize(window);
412 }
413
414 void
415 Tizen_GetWindowSize(_THIS, SDL_Window *window, int *w, int *h)
416 {
417     SDL_WindowData *wind = window->driverdata;
418     if (!wind->window) {
419         return;
420     }
421
422     if (w) *w = window->w;
423     if (h) *h = window->h;
424 }
425
426 void
427 Tizen_SetWindowPosition(_THIS, SDL_Window * window)
428 {
429     SDL_WindowData *wind = window->driverdata;
430     if (!wind->window) {
431         return;
432     }
433
434     // TODO : consider to rotation status.
435    ecore_wl_window_position_set(wind->window, window->x, window->y);
436 }
437
438 void
439 Tizen_DestroyWindow(_THIS, SDL_Window *window)
440 {
441     SDL_VideoData *data = _this->driverdata;
442     SDL_WindowData *wind = window->driverdata;
443
444     if (data) {
445         eina_hash_del(data->windows, &wind->id, window);
446 #if SDL_VIDEO_OPENGL_EGL
447     if (window->flags & SDL_WINDOW_OPENGL) {
448         SDL_EGL_DestroySurface(_this, wind->egl_surface);
449         wl_egl_window_destroy(wind->egl_window);
450     }
451 #endif
452         ecore_wl_window_free(wind->window);
453         SDL_free(wind);
454     }
455
456     window->driverdata = NULL;
457 }
458
459 SDL_Window*
460 Tizen_FindWindow(_THIS, Ecore_Wl_Window *ewin)
461 {
462     SDL_VideoData *data = _this->driverdata;
463     int id;
464
465     id = ecore_wl_window_id_get(ewin);
466     return (SDL_Window*)eina_hash_find(data->windows, &id);
467 }
468
469 Eina_Bool
470 _tizen_cb_event_window_visibility_change(void *data, int type, void *event)
471 {
472     _THIS = data;
473     Ecore_Wl_Event_Window_Visibility_Change *ev;
474     Ecore_Wl_Window *ew;
475     SDL_Window *window;
476
477     ev = event;
478     ew = ecore_wl_window_find(ev->win);
479     window = Tizen_FindWindow(_this, ew);
480
481     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
482     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESTORED, 0, 0);
483     return ECORE_CALLBACK_PASS_ON;
484 }
485
486 Eina_Bool
487 _tizen_cb_window_configure(void *data, int type EINA_UNUSED, void *event)
488 {
489    _THIS = data;
490    Ecore_Wl_Window *ew;
491    SDL_Window *window;
492    SDL_WindowData *wind;
493    Ecore_Wl_Event_Window_Configure *ev;
494    ev = event;
495    ew = ecore_wl_window_find(ev->win);
496    window = Tizen_FindWindow(_this, ew);
497    wind = window->driverdata;
498
499    if (wind->rotation_supported == 0){
500       return ECORE_CALLBACK_PASS_ON;
501    }
502 /*
503    int nx = 0, ny = 0, nw = 0, nh = 0;
504   SDL_Log( "configure notify window: %p, ecore_wl_window: %p\n", window, ew);
505
506    ecore_wl_window_geometry_get(ew, &nx, &ny, &nw, &nh);
507    if (nw < 1) nw = 1;
508    if (nh < 1) nh = 1;
509    
510    SDL_Log("[SDL_Size] * _tizen_cb_window_configure :: w->w:%d, w->h:%d, nw:%d, nh:%d", window->w, window->h, nw, nh);
511    if ((window->x != nx) || (window->y != ny))
512      ecore_wl_window_position_set(ew, nx, ny);
513
514    if ((window->w != nw) || (window->h != nh)) {
515      _tizen_setwindowsize(window);
516    }
517    */
518    return ECORE_CALLBACK_PASS_ON;
519 }
520
521
522 void
523 _tizen_send_rotation_event(SDL_Window *window, unsigned int angle)
524 {
525     SDL_Event event;
526     SDL_WindowData *wind;
527     wind = window->driverdata;
528
529     SDL_memset(&event, 0, sizeof(event));
530     event.type = SDL_ROTATEEVENT;
531     event.user.code = 0;
532     if (wind->support_pre_rotation)
533         event.user.data1 = (void*)0;
534     else
535         event.user.data1 = (void*)angle;
536     event.user.data2 = (void*)-1;
537
538     SDL_PushEvent(&event);
539     return;
540 }
541
542 void
543 _tizen_set_window_size(SDL_Window * window, int w, int h)
544 {
545     if(!window)
546     {
547         SDL_SetError("Invalid window");
548         return;
549     }
550
551     SDL_VideoDevice *_this = SDL_GetVideoDevice();
552     if (!_this) {
553         SDL_SetError("Video subsystem has not been initialized");
554         return;
555     }
556
557     if (window->magic != &_this->window_magic) {
558         return;
559     }
560
561     if (w <= 0) {
562         SDL_InvalidParamError("w");
563         return;
564     }
565     if (h <= 0) {
566         SDL_InvalidParamError("h");
567         return;
568     }
569
570     /* Make sure we don't exceed any window size limits */
571     if (window->min_w && w < window->min_w)
572     {
573         w = window->min_w;
574     }
575     if (window->max_w && w > window->max_w)
576     {
577         w = window->max_w;
578     }
579     if (window->min_h && h < window->min_h)
580     {
581         h = window->min_h;
582     }
583     if (window->max_h && h > window->max_h)
584     {
585         h = window->max_h;
586     }
587
588     window->windowed.w = w;
589     window->windowed.h = h;
590
591     window->w = w;
592     window->h = h;
593 }
594
595 Eina_Bool
596 _tizen_cb_event_window_rotate(void *data, int type EINA_UNUSED, void *event)
597 {
598     _THIS = data;
599     Ecore_Wl_Event_Window_Rotate *ev;
600     Ecore_Wl_Window *ew;
601     SDL_Window *window;
602     SDL_WindowData *wind;
603
604     ev = event;
605     if (!ev) {
606         return ECORE_CALLBACK_PASS_ON;
607     }
608
609     ew = ecore_wl_window_find(ev->win);
610     window = Tizen_FindWindow(_this, ew);
611     wind = window->driverdata;
612
613     if (wind->rotation != ev->angle) {
614         /* set ecore_wayland window rotation */
615         wind->rotation = ev->angle;
616         ecore_wl_window_rotation_set(ew, ev->angle);
617         if(wind->support_pre_rotation) {
618             int window_w, window_h;
619             if(wind->rotation==90 || wind->rotation==270)
620                 ecore_wl_window_geometry_get(wind->window, 0, 0, &window_h, &window_w);
621             else
622                 ecore_wl_window_geometry_get(wind->window, 0, 0, &window_w, &window_h);
623
624             _tizen_set_window_size(window, window_w, window_h);
625             Tizen_pre_rotation_set(wind);
626         }
627         _tizen_send_rotation_event(window, ev->angle);
628         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SIZE_CHANGED, window->w, window->h);
629         wind->received_rotation = 1;
630     }
631
632     return ECORE_CALLBACK_PASS_ON;
633 }
634
635 int
636 Tizen_InitWindow(_THIS)
637 {
638     SDL_VideoData *data = _this->driverdata;
639
640     data->windows = eina_hash_int32_new(NULL);
641
642     ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_VISIBILITY_CHANGE,
643                         _tizen_cb_event_window_visibility_change,_this);
644     ecore_event_handler_add(ECORE_EVENT_KEY_UP,
645                         _tizen_cb_event_keyup_change,_this);
646     ecore_event_handler_add(ECORE_EVENT_KEY_DOWN,
647                         _tizen_cb_event_keydown_change,_this);
648     ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN,
649                         _tizen_cb_event_mousedown_change,_this);
650     ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP,
651                         _tizen_cb_event_mouseup_change,_this);
652     ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE,
653                         _tizen_cb_event_mousemove_change,_this);
654     ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_ROTATE,
655                         _tizen_cb_event_window_rotate,_this);
656     ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_CONFIGURE,
657                         _tizen_cb_window_configure,_this);
658     ecore_event_handler_add(ECORE_EVENT_JOYSTICK,
659                         _tizen_cb_event_joystick_change,_this);
660     ecore_event_handler_add(ECORE_WL_EVENT_FOCUS_IN,
661                         _tizen_cb_event_focus_in,_this);
662     ecore_event_handler_add(ECORE_WL_EVENT_FOCUS_OUT,
663                         _tizen_cb_event_focus_out,_this);
664     ecore_event_handler_add(ECORE_WL_EVENT_MOUSE_IN,
665                         _tizen_cb_event_mouse_in,_this);
666     ecore_event_handler_add(ECORE_WL_EVENT_MOUSE_OUT,
667                         _tizen_cb_event_mouse_out,_this);
668
669     data->current_thread = SDL_GetThreadID(0);
670
671     return 0;
672 }
673
674 void
675 Tizen_DeinitWindow(_THIS)
676 {
677     SDL_VideoData *data = _this->driverdata;
678
679     eina_hash_free(data->windows);
680 }
681 #endif /* SDL_VIDEO_DRIVER_TIZEN */
682
683 /* vi: set ts=4 sw=4 expandtab: */