Add Notification Level apis with wayland
[platform/core/api/efl-util.git] / src / efl_util.c
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License. 
15  */
16
17
18 #define LOG_TAG "TIZEN_N_EFL_UTIL"
19
20 #include <efl_util.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <Elementary.h>
25
26 #if X11
27 #include <Ecore_X.h>
28 #include <utilX.h>
29 #endif
30
31 #if WAYLAND
32 #include <Ecore_Wayland.h>
33 #include <wayland-client.h>
34 #include "tizen_notification-client-protocol.h"
35 #endif
36
37 typedef struct _notification_error_cb_info
38 {
39    Evas_Object *window;
40    efl_util_notification_window_level_error_cb err_cb;
41    void *user_data;
42 } notification_error_cb_info;
43
44 Eina_List *_g_notification_error_cb_info_list;
45 static Ecore_Event_Handler* _noti_level_access_result_handler = NULL;
46 static int _noti_handler_count = 0;
47
48 static notification_error_cb_info *_notification_error_cb_info_find(Evas_Object *window);
49 static Eina_Bool _efl_util_notification_info_add(Evas_Object *window, efl_util_notification_window_level_error_cb callback, void *user_data);
50 static Eina_Bool _efl_util_notification_info_del(Evas_Object *window);
51
52 #if X11
53 static unsigned int _noti_level_access_result_atom = 0;
54
55 static Eina_Bool _efl_util_client_message(void *data, int type, void *event);
56 static notification_error_cb_info *_notification_error_cb_info_find_by_xwin(unsigned int xwin);
57 #endif
58
59 #if WAYLAND
60 typedef struct _Surface_Level
61 {
62    struct wl_surface *surface;
63    uint32_t level;
64 } Surface_Level;
65
66 static void _cb_handle_registry_global(void *data, struct wl_registry *registry, unsigned int name, const char *interface, unsigned int version);
67 static void _cb_handle_registry_global_remove(void *data, struct wl_registry *registry, unsigned int name);
68 static void _notification_set_level_done(void *data, struct tizen_notification *tizen_notification, struct wl_surface *surface, uint32_t level, uint32_t error_state);
69 static notification_error_cb_info *_notification_error_cb_info_find_by_wl_surface(struct wl_surface *surface);
70
71 static const struct wl_registry_listener _registry_listener =
72 {
73    _cb_handle_registry_global,
74    _cb_handle_registry_global_remove
75 };
76
77 struct tizen_notification_listener _tizen_notification_listener =
78 {
79    _notification_set_level_done,
80 };
81
82 static struct tizen_notification *_tizen_notification = NULL;
83 static Eina_Bool _efl_util_init_done = EINA_FALSE;
84 static Eina_Hash *hash_surface_levels = NULL;
85
86 static void
87 _cb_handle_registry_global(void *data, struct wl_registry *registry, unsigned int name, const char *interface, unsigned int version)
88 {
89    if (!strcmp(interface, "tizen_notification"))
90      {
91         _tizen_notification = wl_registry_bind(registry, name, &tizen_notification_interface, 1);
92         if (!_tizen_notification) return;
93         tizen_notification_add_listener(_tizen_notification, &_tizen_notification_listener, NULL);
94         _efl_util_init_done = EINA_TRUE;
95         hash_surface_levels = eina_hash_pointer_new(free);
96      }
97 }
98
99 # define _FREE_FUNC(_h, _fn) do { if (_h) { _fn((void*)_h); _h = NULL; } } while (0)
100 static void
101 _cb_handle_registry_global_remove(void *data, struct wl_registry *registry, unsigned int name)
102 {
103    _tizen_notification = NULL;
104    _efl_util_init_done = EINA_FALSE;
105    _FREE_FUNC(hash_surface_levels, eina_hash_free);
106    /* no-op */
107 }
108
109 static void
110 _notification_set_level_done(void *data,
111                              struct tizen_notification *tizen_notification,
112                              struct wl_surface *surface,
113                              uint32_t level,
114                              uint32_t error_state)
115 {
116    Surface_Level *sl;
117    notification_error_cb_info *cb_info = NULL;
118    efl_util_error_e error_cb_state = EFL_UTIL_ERROR_NONE;
119
120    if (error_state == TIZEN_NOTIFICATION_ERROR_STATE_NONE)
121      {
122         if (hash_surface_levels)
123           {
124              sl = eina_hash_find(hash_surface_levels, &surface);
125              if (!sl)
126                {
127                   sl = calloc(1, sizeof(Surface_Level));
128                   if (sl)
129                     {
130                        sl->surface = surface;
131                        sl->level = level;
132                        eina_hash_add(hash_surface_levels, &surface, sl);
133                     }
134                }
135              else
136                {
137                   sl->level = level;
138                }
139           }
140      }
141
142    cb_info = _notification_error_cb_info_find_by_wl_surface(surface);
143    if (cb_info)
144      {
145         switch (error_state)
146           {
147              case TIZEN_NOTIFICATION_ERROR_STATE_NONE:
148                 error_cb_state = EFL_UTIL_ERROR_NONE;
149                 break;
150              case TIZEN_NOTIFICATION_ERROR_STATE_INVALID_PARAMETER:
151                 error_cb_state = EFL_UTIL_ERROR_INVALID_PARAMETER;
152                 break;
153              case TIZEN_NOTIFICATION_ERROR_STATE_OUT_OF_MEMORY:
154                 error_cb_state = EFL_UTIL_ERROR_OUT_OF_MEMORY;
155                 break;
156              case TIZEN_NOTIFICATION_ERROR_STATE_PERMISSION_DENIED:
157                 error_cb_state = EFL_UTIL_ERROR_PERMISSION_DENIED;
158                 break;
159              case EFL_UTIL_ERROR_NOT_SUPPORTED_WINDOW_TYPE:
160              default:
161                 error_cb_state = TIZEN_NOTIFICATION_ERROR_STATE_NOT_SUPPORTED_WINDOW_TYPE;
162                 break;
163           }
164         if (cb_info->err_cb)
165           cb_info->err_cb(cb_info->window, error_cb_state , cb_info->user_data);
166      }
167 }
168
169 static void
170 _efl_util_wl_init(void)
171 {
172    static Eina_Bool init = EINA_FALSE;
173    if (!init)
174      {
175         wl_registry_add_listener(wl_display_get_registry(ecore_wl_display_get()),
176                                  &_registry_listener, NULL);
177         init = EINA_TRUE;
178      }
179    while (!_efl_util_init_done)
180      wl_display_dispatch(ecore_wl_display_get());
181 }
182 #endif
183
184 int
185 efl_util_set_notification_window_level(Evas_Object *window, efl_util_notification_level_e level)
186 {
187    EINA_SAFETY_ON_NULL_RETURN_VAL(window, EFL_UTIL_ERROR_INVALID_PARAMETER);
188    EINA_SAFETY_ON_FALSE_RETURN_VAL((level >= EFL_UTIL_NOTIFICATION_LEVEL_1) &&
189                                    (level <= EFL_UTIL_NOTIFICATION_LEVEL_3),
190                                    EFL_UTIL_ERROR_INVALID_PARAMETER);
191
192 #if X11
193    Ecore_X_Window xwin = elm_win_xwindow_get(window);
194    if (xwin)
195      {
196         Ecore_X_Window_Type window_type;
197         if(ecore_x_netwm_window_type_get(xwin, &window_type) == EINA_TRUE)
198           {
199              // success to get window type
200              if(window_type != ECORE_X_WINDOW_TYPE_NOTIFICATION)
201                {
202                   // given EFL window's type is not notification type.
203                   return EFL_UTIL_ERROR_NOT_SUPPORTED_WINDOW_TYPE;
204                }
205           }
206         else
207           return EFL_UTIL_ERROR_NOT_SUPPORTED_WINDOW_TYPE;
208
209         utilx_set_system_notification_level(ecore_x_display_get(), xwin,
210                                             level);
211         return EFL_UTIL_ERROR_NONE;
212      }
213 #endif
214
215 #if WAYLAND
216    Ecore_Wl_Window *wl_win = elm_win_wl_window_get(window);
217    if (wl_win)
218      {
219         _efl_util_wl_init();
220         //Add notification window type check
221         tizen_notification_set_level(_tizen_notification,
222                                      ecore_wl_window_surface_get(wl_win),
223                                      level);
224         return EFL_UTIL_ERROR_NONE;
225      }
226 #endif
227
228    return EFL_UTIL_ERROR_NOT_SUPPORTED_WINDOW_TYPE;
229 }
230
231 int
232 efl_util_get_notification_window_level(Evas_Object *window, efl_util_notification_level_e *level)
233 {
234
235    EINA_SAFETY_ON_NULL_RETURN_VAL(window, EFL_UTIL_ERROR_INVALID_PARAMETER);
236    EINA_SAFETY_ON_NULL_RETURN_VAL(level, EFL_UTIL_ERROR_INVALID_PARAMETER);
237
238 #if X11
239    Ecore_X_Window_Type window_type;
240    Utilx_Notification_Level utilx_level;
241    Ecore_X_Window xwin = elm_win_xwindow_get(window);
242    if (xwin)
243      {
244         if(ecore_x_netwm_window_type_get(xwin, &window_type) == EINA_TRUE)
245           {
246              // success to get window type
247              if(window_type != ECORE_X_WINDOW_TYPE_NOTIFICATION)
248                {
249                   // given EFL window's type is not notification type.
250                   return EFL_UTIL_ERROR_NOT_SUPPORTED_WINDOW_TYPE;
251                }
252
253              utilx_level = utilx_get_system_notification_level (ecore_x_display_get(), xwin);
254
255              if(utilx_level == UTILX_NOTIFICATION_LEVEL_LOW)
256                {
257                   *level = EFL_UTIL_NOTIFICATION_LEVEL_1;
258                }
259              else if(utilx_level == UTILX_NOTIFICATION_LEVEL_NORMAL)
260                {
261                   *level = EFL_UTIL_NOTIFICATION_LEVEL_2;
262                }
263              else if(utilx_level == UTILX_NOTIFICATION_LEVEL_HIGH)
264                {
265                   *level = EFL_UTIL_NOTIFICATION_LEVEL_3;
266                }
267              else
268                {
269                   return EFL_UTIL_ERROR_INVALID_PARAMETER;
270                }
271
272           }
273         else
274           {
275              // fail to get window type
276              return EFL_UTIL_ERROR_NOT_SUPPORTED_WINDOW_TYPE;
277           }
278
279         return EFL_UTIL_ERROR_NONE;
280      }
281 #endif
282
283 #if WAYLAND
284    Ecore_Wl_Window *wl_win = elm_win_wl_window_get(window);
285    if (wl_win)
286      {
287         Surface_Level *sl;
288         struct wl_surface *surface = ecore_wl_window_surface_get(wl_win);
289         sl = eina_hash_find(hash_surface_levels, &surface);
290         if (sl)
291           {
292             switch (sl->level)
293               {
294                  case TIZEN_NOTIFICATION_LEVEL_1:
295                    *level = EFL_UTIL_NOTIFICATION_LEVEL_1;
296                    break;
297                  case TIZEN_NOTIFICATION_LEVEL_2:
298                    *level = EFL_UTIL_NOTIFICATION_LEVEL_2;
299                    break;
300                  case TIZEN_NOTIFICATION_LEVEL_3:
301                    *level = EFL_UTIL_NOTIFICATION_LEVEL_3;
302                    break;
303                  default:
304                    return EFL_UTIL_ERROR_INVALID_PARAMETER;
305               }
306             return EFL_UTIL_ERROR_NONE;
307           }
308      }
309 #endif
310    return EFL_UTIL_ERROR_NOT_SUPPORTED_WINDOW_TYPE;
311 }
312
313 int
314 efl_util_set_notification_window_level_error_cb(Evas_Object *window, efl_util_notification_window_level_error_cb callback, void *user_data)
315 {
316    Eina_Bool ret = EINA_FALSE;
317
318    EINA_SAFETY_ON_NULL_RETURN_VAL(window, EFL_UTIL_ERROR_INVALID_PARAMETER);
319    EINA_SAFETY_ON_NULL_RETURN_VAL(callback, EFL_UTIL_ERROR_INVALID_PARAMETER);
320
321    ret = _efl_util_notification_info_add(window, callback, user_data);
322    if (ret)
323      {
324 #if X11
325         if (!_noti_level_access_result_atom)
326           _noti_level_access_result_atom = ecore_x_atom_get("_E_NOTIFICATION_LEVEL_ACCESS_RESULT");
327
328         if (!_noti_level_access_result_handler)
329           _noti_level_access_result_handler = ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE, _efl_util_client_message, NULL);
330         _noti_handler_count++;
331
332         return EFL_UTIL_ERROR_NONE;
333 #endif
334
335 #if WAYLAND
336         return EFL_UTIL_ERROR_NONE;
337 #endif
338      }
339    return EFL_UTIL_ERROR_OUT_OF_MEMORY;
340 }
341
342 int
343 efl_util_unset_notification_window_level_error_cb(Evas_Object *window)
344 {
345    Eina_Bool ret = EINA_FALSE;
346
347    EINA_SAFETY_ON_NULL_RETURN_VAL(window, EFL_UTIL_ERROR_INVALID_PARAMETER);
348
349    ret = _efl_util_notification_info_del(window);
350    if (ret)
351      {
352         _noti_handler_count--;
353         if (_noti_handler_count == 0)
354           {
355              if (_noti_level_access_result_handler)
356                {
357                   ecore_event_handler_del(_noti_level_access_result_handler);
358                   _noti_level_access_result_handler = NULL;
359                }
360           }
361         return EFL_UTIL_ERROR_NONE;
362      }
363
364    return EFL_UTIL_ERROR_INVALID_PARAMETER;
365 }
366
367 #if X11
368 static Eina_Bool
369 _efl_util_client_message(void *data, int type, void *event)
370 {
371    Ecore_X_Event_Client_Message *ev;
372
373    ev = event;
374    if (!ev) return ECORE_CALLBACK_PASS_ON;
375
376    if (ev->message_type == _noti_level_access_result_atom)
377      {
378         Ecore_X_Window xwin;
379         xwin = ev->win;
380
381         notification_error_cb_info *cb_info = NULL;
382         cb_info = _notification_error_cb_info_find_by_xwin(xwin);
383         if (cb_info)
384           {
385              int access = ev->data.l[1];
386              if (access == 0) // permission denied
387                {
388                   if (cb_info->err_cb)
389                     {
390                        cb_info->err_cb(cb_info->window, EFL_UTIL_ERROR_PERMISSION_DENIED, cb_info->user_data);
391                     }
392                }
393           }
394      }
395
396    return ECORE_CALLBACK_PASS_ON;
397 }
398
399 static notification_error_cb_info *
400 _notification_error_cb_info_find_by_xwin(unsigned int xwin)
401 {
402    Eina_List *l;
403    notification_error_cb_info* temp;
404    unsigned int temp_xwin;
405
406    EINA_LIST_FOREACH(_g_notification_error_cb_info_list, l, temp)
407      {
408         if (temp->window)
409           {
410              temp_xwin = elm_win_xwindow_get(temp->window);
411              if (xwin == temp_xwin)
412                {
413                   return temp;
414                }
415           }
416      }
417
418    return NULL;
419 }
420 #endif
421
422 #if WAYLAND
423 static notification_error_cb_info *
424 _notification_error_cb_info_find_by_wl_surface(struct wl_surface *surface)
425 {
426    Eina_List *l;
427    notification_error_cb_info* temp;
428    struct wl_surface *temp_surface;
429
430    EINA_LIST_FOREACH(_g_notification_error_cb_info_list, l, temp)
431      {
432         if (temp->window)
433           {
434              temp_surface = ecore_wl_window_surface_get(elm_win_wl_window_get(temp->window));
435              if (surface == temp_surface)
436                {
437                   return temp;
438                }
439           }
440      }
441
442    return NULL;
443 }
444 #endif
445
446 static notification_error_cb_info *
447 _notification_error_cb_info_find(Evas_Object *window)
448 {
449    Eina_List *l;
450    notification_error_cb_info* temp;
451
452    EINA_LIST_FOREACH(_g_notification_error_cb_info_list, l, temp)
453      {
454         if (temp->window == window)
455           {
456              return temp;
457           }
458      }
459
460    return NULL;
461 }
462
463 static Eina_Bool
464 _efl_util_notification_info_add(Evas_Object *window, efl_util_notification_window_level_error_cb callback, void *user_data)
465 {
466    notification_error_cb_info* _err_info = _notification_error_cb_info_find(window);
467
468    if (_err_info)
469      {
470         _g_notification_error_cb_info_list = eina_list_remove(_g_notification_error_cb_info_list, _err_info);
471         free(_err_info);
472         _err_info = NULL;
473      }
474
475    _err_info = (notification_error_cb_info*)calloc(1, sizeof(notification_error_cb_info));
476    if (!_err_info)
477      {
478         return EINA_FALSE;
479      }
480    _err_info->window = window;
481    _err_info->err_cb = callback;
482    _err_info->user_data = user_data;
483
484    _g_notification_error_cb_info_list = eina_list_append(_g_notification_error_cb_info_list, _err_info);
485
486    return EINA_TRUE;
487 }
488
489 static Eina_Bool
490 _efl_util_notification_info_del(Evas_Object *window)
491 {
492    notification_error_cb_info* _err_info = _notification_error_cb_info_find(window);
493    if (!_err_info)
494      {
495         return EINA_FALSE;
496      }
497
498    _g_notification_error_cb_info_list = eina_list_remove(_g_notification_error_cb_info_list, _err_info);
499    free(_err_info);
500
501    return EINA_TRUE;
502 }