[SDL_Tizen] Add pre-rotation environment variable
[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_tizenindicator.h"
32
33 #include "SDL_tizenvideo.h"
34 #include "SDL_tizentouch.h"
35 #include "SDL_tizenkeyboard.h"
36 #include "SDL_tizenmouse.h"
37 #include "SDL_tizenevents_c.h"
38
39 #include "SDL_tizenwindow.h"
40
41 #include "../../events/SDL_mouse_c.h"
42 #include "../../joystick/tizen/SDL_sysjoystick_c.h"
43
44 #include "../SDL_egl_c.h"
45 #include "../SDL_vulkan_c.h"
46 #include "../SDL_sysvideo.h"
47 #include "../../events/SDL_windowevents_c.h"
48
49 enum {
50     ROTATION_TYPE_NORMAL_ROTATION = 0,
51     ROTATION_TYPE_PRE_ROTATION,      /* use pre-rotation */
52 };
53
54 #define LOAD_FUNC(NAME) \
55 _this->tizen_pre_rotation_data->NAME = SDL_LoadFunction(_this->tizen_pre_rotation_data->prerotation_dll_handle, #NAME); \
56 if (!_this->tizen_pre_rotation_data->NAME) \
57 { \
58     SDL_LogError(SDL_LOG_CATEGORY_ASSERT, "Could not retrieve pre-rotation function " #NAME); \
59     return SDL_FALSE; \
60 }
61
62 static int
63 _tizen_rotation_type_get()
64 {
65     static int type = ROTATION_TYPE_PRE_ROTATION;
66     static int checked = 0;
67     char *engine = NULL;
68
69     if (checked) return type;
70
71     engine = getenv("SDL_ROTATION");
72
73     if (engine)
74       {
75          if ((!strcasecmp(engine, "normal")))
76             type = ROTATION_TYPE_NORMAL_ROTATION;
77          else if ((!strcasecmp(engine, "pre_rotation")))
78             type = ROTATION_TYPE_PRE_ROTATION;
79          else
80             type = ROTATION_TYPE_PRE_ROTATION;
81       }
82     checked = 1;
83     return type;
84 }
85
86 int
87 _tizen_PreRotatotion_LoadLibrary(SDL_WindowData *_this, const char *lib_path)
88 {
89     void *lib_dll_handle = NULL;
90     char *path = NULL;
91
92     if (_this->isLoaded_pre_rotation)
93         return SDL_TRUE;
94
95     _this->tizen_pre_rotation_data = (Tizen_Prerotation_Data *) SDL_calloc(1, sizeof(Tizen_Prerotation_Data));
96     if (!_this->tizen_pre_rotation_data) {
97         return SDL_OutOfMemory();
98     }
99
100     if (!lib_path)
101         lib_dll_handle = SDL_LoadObject(lib_path);
102
103     if (!lib_dll_handle) {
104         path = "libwayland-egl.so";
105         lib_dll_handle = SDL_LoadObject(path);
106     }
107
108     _this->tizen_pre_rotation_data->prerotation_dll_handle = lib_dll_handle;
109
110     if (lib_dll_handle == NULL)
111         return SDL_FALSE;
112
113     LOAD_FUNC(wl_egl_window_set_rotation);
114     LOAD_FUNC(wl_egl_window_get_capabilities);
115     _this->isLoaded_pre_rotation = 1;
116
117     return SDL_TRUE;
118 }
119
120 SDL_bool
121 Tizen_GetWindowWMInfo(_THIS, SDL_Window *window, SDL_SysWMinfo *info)
122 {
123     SDL_WindowData *wmdata = (SDL_WindowData *)window->driverdata;
124     info->info.tizen.egl_display = NULL;
125     info->info.tizen.egl_surface = NULL;
126 #if SDL_VIDEO_OPENGL_EGL
127     if (_this->egl_data)
128     {
129        info->info.tizen.egl_display = (void*)_this->egl_data->egl_display;
130     }
131     info->info.tizen.egl_surface = (void*)wmdata->egl_surface;
132 #endif
133     info->subsystem = SDL_SYSWM_TIZEN;
134     return SDL_TRUE;
135 }
136
137 int
138 Tizen_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
139 {
140     return 0;  /* just succeed, the real work is done elsewhere. */
141 }
142
143 void
144 Tizen_ShowWindow(_THIS, SDL_Window *window)
145 {
146     SDL_WindowData *wind = window->driverdata;
147     ecore_wl_window_show(wind->window);
148 }
149
150 void
151 Tizen_SetWindowFullscreen(_THIS, SDL_Window *window,
152                           SDL_VideoDisplay *_display, SDL_bool fullscreen)
153 {
154     /*DO NOTHING*/
155 }
156
157 void
158 Tizen_pre_rotation_set(SDL_WindowData *_this)
159 {
160     tizen_wl_egl_window_rotation rot;
161     if (!_this->egl_window) return;
162
163     switch (_this->rotation) {
164          case 90:
165             rot = TIZEN_ROTATION_270;
166             break;
167          case 180:
168             rot = TIZEN_ROTATION_180;
169             break;
170          case 270:
171             rot = TIZEN_ROTATION_90;
172             break;
173          case 0:
174             rot = TIZEN_ROTATION_0;
175             break;
176          default:
177             rot = TIZEN_ROTATION_0;
178             break;
179       }
180
181       _this->tizen_pre_rotation_data->wl_egl_window_set_rotation(_this->egl_window, rot);
182 }
183
184 void
185 _tizen_window_orientaiton_hint_callback(void *userdata, const char *name, const char *oldValue, const char *newValue)
186 {
187     char *p_str = NULL;
188     char orientation_type[4][20] = {"Portrait","LandscapeLeft","PortraitUpsideDown","LandscapeRight"};
189     int checked[4] = {0,};
190     int i;
191     unsigned int j = 0;
192     SDL_WindowData *wind = (SDL_WindowData*)userdata;
193     Ecore_Wl_Window *window = wind->window;
194
195     if (wind->rotation_supported == 0) {
196         return;
197     }
198
199     SDL_assert(SDL_strncmp(name, SDL_HINT_ORIENTATIONS, SDL_strlen(SDL_HINT_ORIENTATIONS)) == 0);
200
201     if ((oldValue == NULL) && (newValue == NULL)) {
202         return;
203     }
204
205     for (i=0;i<4;i++) {
206         p_str = SDL_strstr(newValue, orientation_type[i]);
207         if (p_str) {
208             if (p_str == newValue) {
209                 int rot = 0;
210                 if (i == 0) rot = 0;
211                 else if (i == 1) rot = 90;
212                 else if (i == 2) rot = 180;
213                 else if (i == 3) rot = 270;
214                 wind->rotation = rot;
215             }
216
217             if (i == 0) {
218                 checked[j] = 0;
219             }
220             else if (i == 1) {
221                 checked[j] = 90;
222             }
223             else if (i == 2) {
224                 checked[j] = 180;
225             }
226             else if (i == 3) {
227                 checked[j] = 270;
228             }
229             j++;
230         }
231     }
232
233     if (j > 0) {
234         if (j == 1) {
235             ecore_wl_window_rotation_preferred_rotation_set(window,wind->rotation);
236             if (wind->support_pre_rotation) {
237                 Tizen_pre_rotation_set(wind);
238             }
239         }
240         ecore_wl_window_rotation_available_rotations_set(window, (const int*)checked, j);
241     }
242 }
243
244 void
245 _tizen_window_orientation_add_hint(void *data)
246 {
247     SDL_WindowData *wind = (SDL_WindowData*)data;
248     if (wind->rotation_supported == 0) {
249         return;
250     }
251
252     SDL_AddHintCallback(SDL_HINT_ORIENTATIONS, _tizen_window_orientaiton_hint_callback, data);
253 }
254
255 int
256 Tizen_CreateWindow(_THIS, SDL_Window *window)
257 {
258     SDL_VideoData *data = _this->driverdata;
259     SDL_WindowData *wind;
260     Ecore_Wl_Global *global;
261     Eina_Inlist *globals;
262
263     wind = calloc(1, sizeof * wind);
264     if (!wind) {
265         return SDL_OutOfMemory();
266     }
267
268     window->driverdata = wind;
269     window->flags |= SDL_WINDOW_INPUT_FOCUS;    /* always has input focus */
270     window->flags |= SDL_WINDOW_BORDERLESS;     /* defalut - not support indicator*/
271
272 #if SDL_VIDEO_OPENGL_EGL
273     if (window->flags & SDL_WINDOW_OPENGL) {
274         SDL_GL_LoadLibrary(NULL);
275     }
276 #endif
277
278 #if SDL_VIDEO_VULKAN
279     if (window->flags & SDL_WINDOW_VULKAN) {
280         if (!_this->vulkan_GetInstanceExtensions) {
281             SDL_SetError("No Vulkan support in video driver");
282         }
283
284         if (_this->vulkan_LoadLibrary(_this, NULL) < 0) {
285             SDL_SetError("Fail to load Vulkan Library");
286         }
287     }
288 #endif
289
290     if (window->x == SDL_WINDOWPOS_UNDEFINED) {
291         window->x = 0;
292     }
293     if (window->y == SDL_WINDOWPOS_UNDEFINED) {
294         window->y = 0;
295     }
296
297     if (!(globals = ecore_wl_globals_get()))
298       {
299          SDL_LogError(SDL_LOG_CATEGORY_ASSERT, "Failed to get wayland globals");
300          return -1;
301       }
302
303     wind->window = ecore_wl_window_new(NULL,
304                                        window->x, window->y, window->w, window->h,
305                                        ECORE_WL_WINDOW_BUFFER_TYPE_SHM);
306     wind->surface = ecore_wl_window_surface_create(wind->window);
307     wind->rotation = 0;
308     wind->rotation_supported = 0;
309     wind->received_rotation = 0;
310     ecore_wl_window_opaque_region_set(wind->window, window->x, window->y, window->w, window->h);
311
312 #if SDL_VIDEO_OPENGL_EGL
313     if (window->flags & SDL_WINDOW_OPENGL) {
314         wind->egl_window = wl_egl_window_create(ecore_wl_window_surface_get(wind->window), window->w, window->h);
315
316         /* Create the GLES window surface */
317         wind->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) wind->egl_window);
318         if (wind->egl_surface == EGL_NO_SURFACE) {
319             SDL_LogError(SDL_LOG_CATEGORY_ASSERT, "failed to create a window surface");
320             return -1;
321         }
322
323         //Support PreRotation
324         wind->support_pre_rotation = 0;
325         if (_tizen_rotation_type_get() && _tizen_PreRotatotion_LoadLibrary(wind, "libwayland-egl.so")) {
326             if (wind->tizen_pre_rotation_data->wl_egl_window_get_capabilities(wind->egl_window) == TIZEN_WL_EGL_WINDOW_CAPABILITY_ROTATION_SUPPORTED ) {
327                 wind->support_pre_rotation = 1;
328             }
329         }
330     }
331 #endif
332
333     wind->id = ecore_wl_window_id_get(wind->window);
334     eina_hash_add(data->windows, &wind->id, window);
335
336     Tizen_InitKeyboard(_this);
337     SDL_SetMouseFocus(window);
338
339     if (window->flags & 0x00008000) {
340         ecore_wl_window_input_region_set(wind->window, -1, -1, 1, 1);
341         ecore_wl_window_focus_skip_set(wind->window, EINA_TRUE);
342     }
343
344     EINA_INLIST_FOREACH(globals, global) {
345          if (!strcmp(global->interface, "tizen_policy_ext")) {
346               wind->rotation_supported = 1;
347               break;
348            }
349       }
350     // Add orientaiton hint cb
351     _tizen_window_orientation_add_hint((void*)wind);
352
353     return 0;
354 }
355
356 void
357 Tizen_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
358 {
359 //Add setting window bordered.
360 }
361
362 void
363 _tizen_egl_window_resize(SDL_Window *window)
364 {
365     SDL_WindowData *wind = window->driverdata;
366     if (!wind->egl_window) {
367         return;
368     }
369
370     // TODO : consider to rotation status.
371 #if SDL_VIDEO_OPENGL_EGL
372     if (window->flags & SDL_WINDOW_OPENGL) {
373         // TODO : if window size is not FULL, we need the code about Non FullSize Window.
374         int aw, ah;
375         wl_egl_window_get_attached_size(wind->egl_window, &aw, &ah);
376         wl_egl_window_resize(wind->egl_window, aw, ah, 0, 0);
377     }
378 #endif
379
380 }
381
382 void
383 _tizen_setwindowsize(SDL_Window *window)
384 {
385     SDL_WindowData *wind = window->driverdata;
386     if (!wind->window) {
387         return;
388     }
389     ecore_wl_window_update_size(wind->window, window->w, window->h);
390 }
391
392 void
393 Tizen_SetWindowSize(_THIS, SDL_Window *window)
394 {
395 //    _tizen_setwindowsize(window);
396 //    _tizen_egl_window_resize(window);
397 }
398
399 void
400 Tizen_GetWindowSize(_THIS, SDL_Window *window, int *w, int *h)
401 {
402     SDL_WindowData *wind = window->driverdata;
403     if (!wind->window) {
404         return;
405     }
406
407     if (w) *w = window->w;
408     if (h) *h = window->h;
409 }
410
411 void
412 Tizen_SetWindowPosition(_THIS, SDL_Window * window)
413 {
414     SDL_WindowData *wind = window->driverdata;
415     if (!wind->window) {
416         return;
417     }
418
419     // TODO : consider to rotation status.
420    ecore_wl_window_position_set(wind->window, window->x, window->y);
421 }
422
423 void
424 Tizen_DestroyWindow(_THIS, SDL_Window *window)
425 {
426     SDL_VideoData *data = _this->driverdata;
427     SDL_WindowData *wind = window->driverdata;
428
429     if (data) {
430         eina_hash_del(data->windows, &wind->id, window);
431 #if SDL_VIDEO_OPENGL_EGL
432     if (window->flags & SDL_WINDOW_OPENGL) {
433         SDL_EGL_DestroySurface(_this, wind->egl_surface);
434         wl_egl_window_destroy(wind->egl_window);
435     }
436 #endif
437         ecore_wl_window_free(wind->window);
438         SDL_free(wind);
439     }
440
441     window->driverdata = NULL;
442 }
443
444 SDL_Window*
445 Tizen_FindWindow(_THIS, Ecore_Wl_Window *ewin)
446 {
447     SDL_VideoData *data = _this->driverdata;
448     int id;
449
450     id = ecore_wl_window_id_get(ewin);
451     return (SDL_Window*)eina_hash_find(data->windows, &id);
452 }
453
454 Eina_Bool
455 _tizen_cb_event_window_visibility_change(void *data, int type, void *event)
456 {
457     _THIS = data;
458     Ecore_Wl_Event_Window_Visibility_Change *ev;
459     Ecore_Wl_Window *ew;
460     SDL_Window *window;
461
462     ev = event;
463     ew = ecore_wl_window_find(ev->win);
464     window = Tizen_FindWindow(_this, ew);
465
466     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
467     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESTORED, 0, 0);
468     return ECORE_CALLBACK_PASS_ON;
469 }
470
471 Eina_Bool
472 _tizen_cb_window_configure(void *data, int type EINA_UNUSED, void *event)
473 {
474    _THIS = data;
475    Ecore_Wl_Window *ew;
476    SDL_Window *window;
477    SDL_WindowData *wind;
478    Ecore_Wl_Event_Window_Configure *ev;
479    ev = event;
480    ew = ecore_wl_window_find(ev->win);
481    window = Tizen_FindWindow(_this, ew);
482    wind = window->driverdata;
483
484    if (wind->rotation_supported == 0){
485       return ECORE_CALLBACK_PASS_ON;
486    }
487 /*
488    int nx = 0, ny = 0, nw = 0, nh = 0;
489   SDL_Log( "configure notify window: %p, ecore_wl_window: %p\n", window, ew);
490
491    ecore_wl_window_geometry_get(ew, &nx, &ny, &nw, &nh);
492    if (nw < 1) nw = 1;
493    if (nh < 1) nh = 1;
494    
495    SDL_Log("[SDL_Size] * _tizen_cb_window_configure :: w->w:%d, w->h:%d, nw:%d, nh:%d", window->w, window->h, nw, nh);
496    if ((window->x != nx) || (window->y != ny))
497      ecore_wl_window_position_set(ew, nx, ny);
498
499    if ((window->w != nw) || (window->h != nh)) {
500      _tizen_setwindowsize(window);
501    }
502    */
503    return ECORE_CALLBACK_PASS_ON;
504 }
505
506
507 void
508 _tizen_send_rotation_event(SDL_Window *window, unsigned int angle)
509 {
510     SDL_Event event;
511     SDL_WindowData *wind;
512     wind = window->driverdata;
513
514     SDL_memset(&event, 0, sizeof(event));
515     event.type = SDL_ROTATEEVENT;
516     event.user.code = 0;
517     if (wind->support_pre_rotation)
518         event.user.data1 = (void*)0;
519     else
520         event.user.data1 = (void*)angle;
521     event.user.data2 = (void*)-1;
522
523     SDL_PushEvent(&event);
524     return;
525 }
526
527 Eina_Bool
528 _tizen_cb_event_window_rotate(void *data, int type EINA_UNUSED, void *event)
529 {
530     _THIS = data;
531     Ecore_Wl_Event_Window_Rotate *ev;
532     Ecore_Wl_Window *ew;
533     SDL_Window *window;
534     SDL_WindowData *wind;
535
536     ev = event;
537     if (!ev) {
538         return ECORE_CALLBACK_PASS_ON;
539     }
540
541     ew = ecore_wl_window_find(ev->win);
542     window = Tizen_FindWindow(_this, ew);
543     wind = window->driverdata;
544
545     if (wind->rotation != ev->angle) {
546         /* set ecore_wayland window rotation */
547         wind->rotation = ev->angle;
548         ecore_wl_window_rotation_set(ew, ev->angle);
549         // Send Rotation Event
550         _tizen_send_rotation_event(window, ev->angle);
551     }
552
553     wind->received_rotation = 1;
554     return ECORE_CALLBACK_PASS_ON;
555 }
556
557 int
558 Tizen_InitWindow(_THIS)
559 {
560     SDL_VideoData *data = _this->driverdata;
561
562     data->windows = eina_hash_int32_new(NULL);
563
564     ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_VISIBILITY_CHANGE,
565                         _tizen_cb_event_window_visibility_change,_this);
566     ecore_event_handler_add(ECORE_EVENT_KEY_UP,
567                         _tizen_cb_event_keyup_change,_this);
568     ecore_event_handler_add(ECORE_EVENT_KEY_DOWN,
569                         _tizen_cb_event_keydown_change,_this);
570     ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN,
571                         _tizen_cb_event_mousedown_change,_this);
572     ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP,
573                         _tizen_cb_event_mouseup_change,_this);
574     ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE,
575                         _tizen_cb_event_mousemove_change,_this);
576     ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_ROTATE,
577                         _tizen_cb_event_window_rotate,_this);
578     ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_CONFIGURE,
579                         _tizen_cb_window_configure,_this);
580     ecore_event_handler_add(ECORE_EVENT_JOYSTICK,
581                         _tizen_cb_event_joystick_change,_this);
582     ecore_event_handler_add(ECORE_WL_EVENT_FOCUS_IN,
583                         _tizen_cb_event_focus_in,_this);
584     ecore_event_handler_add(ECORE_WL_EVENT_FOCUS_OUT,
585                         _tizen_cb_event_focus_out,_this);
586     ecore_event_handler_add(ECORE_WL_EVENT_MOUSE_IN,
587                         _tizen_cb_event_mouse_in,_this);
588     ecore_event_handler_add(ECORE_WL_EVENT_MOUSE_OUT,
589                         _tizen_cb_event_mouse_out,_this);
590
591     data->current_thread = SDL_GetThreadID(0);
592
593     return 0;
594 }
595
596 void
597 Tizen_DeinitWindow(_THIS)
598 {
599     SDL_VideoData *data = _this->driverdata;
600
601     eina_hash_free(data->windows);
602 }
603 #endif /* SDL_VIDEO_DRIVER_TIZEN */
604
605 /* vi: set ts=4 sw=4 expandtab: */