move to appcore_get_rotation_state in the last of app_create
[framework/appfw/ui-gadget-1.git] / src / manager.c
1 /*
2  *  UI Gadget
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jayoun Lee <airjany@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <glib.h>
27 #include <utilX.h>
28
29 #include "ug.h"
30 #include "ug-manager.h"
31 #include "ug-engine.h"
32 #include "ug-dbg.h"
33
34 struct ug_manager {
35         ui_gadget_h root;
36         ui_gadget_h fv_top;
37         GSList *fv_list;
38
39         void *win;
40         Window win_id;
41         Display *disp;
42
43         enum ug_option base_opt;
44         enum ug_event last_rotate_evt;
45
46         int walking;
47
48         int is_initted:1;
49         int is_landscape:1;
50         int destroy_all:1;
51
52         struct ug_engine *engine;
53 };
54
55 static struct ug_manager ug_man;
56
57 static inline void job_start(void);
58 static inline void job_end(void);
59
60 static int ug_relation_add(ui_gadget_h p, ui_gadget_h c)
61 {
62         c->parent = p;
63         /* prepend element to avoid the inefficiency,
64                 which is to traverse the entire list to find the end*/
65         p->children = g_slist_prepend(p->children, c);
66
67         return 0;
68 }
69
70 static int ug_relation_del(ui_gadget_h ug)
71 {
72         ui_gadget_h p;
73
74         p = ug->parent;
75         if (!p) {
76                 _ERR("ug_relation_del failed: no parent\n");
77                 return -1;
78         }
79         p->children = g_slist_remove(p->children, ug);
80         if (ug->children)
81                 g_slist_free(ug->children);
82         ug->parent = NULL;
83
84         return 0;
85 }
86
87 static int ug_fvlist_add(ui_gadget_h c)
88 {
89         ug_man.fv_list = g_slist_prepend(ug_man.fv_list, c);
90         ug_man.fv_top = c;
91
92         return 0;
93 }
94
95 static int ug_fvlist_del(ui_gadget_h c)
96 {
97         ui_gadget_h t;
98
99         ug_man.fv_list = g_slist_remove(ug_man.fv_list, c);
100
101         /* update fullview top ug*/
102         t = g_slist_nth_data(ug_man.fv_list, 0);
103         ug_man.fv_top = t;
104
105         return 0;
106 }
107
108 static void ugman_tree_dump(ui_gadget_h ug)
109 {
110         static int i;
111         int lv;
112         const char *name;
113         GSList *child;
114         ui_gadget_h c;
115
116         if (!ug)
117                 return;
118
119         name = ug->name;
120         if (ug == ug_man.root) {
121                 i = 0;
122                 _DBG("\n============== TREE_DUMP =============\n");
123                 _DBG("ROOT: Manager\n");
124                 name = "Manager";
125         }
126
127         child = ug->children;
128         if (!child)
129                 return;
130
131         i++;
132         lv = i;
133
134         while (child) {
135                 c = child->data;
136                 _DBG("[%d] %s [%c] (%p) (PARENT:  %s)\n",
137                      lv,
138                      c && c->name ? c->name : "NO CHILD INFO FIXIT!!!",
139                      c && c->mode == UG_MODE_FULLVIEW ? 'F' : 'f', c, name);
140                 ugman_tree_dump(c);
141                 child = g_slist_next(child);
142         }
143 }
144
145 static int ugman_ug_find(ui_gadget_h p, ui_gadget_h ug)
146 {
147         GSList *child = NULL;
148
149         if (!p || !ug)
150                 return 0;
151         child = p->children;
152
153         while (child) {
154                 if (child->data == ug)
155                         return 1;
156                 if (ugman_ug_find(child->data, ug))
157                         return 1;
158                 child = g_slist_next(child);
159         }
160
161         return 0;
162 }
163
164 static int ugman_ug_start(void *data)
165 {
166         ui_gadget_h ug = data;
167         struct ug_module_ops *ops = NULL;
168
169         if (!ug || ug->state != UG_STATE_CREATED
170             || ug->state == UG_STATE_RUNNING)
171                 return 0;
172
173         ug->state = UG_STATE_RUNNING;
174
175         if (ug->module)
176                 ops = &ug->module->ops;
177
178         if (ops && ops->start)
179                 ops->start(ug, ug->service, ops->priv);
180
181         return 0;
182 }
183
184 static int ugman_ug_pause(void *data)
185 {
186         ui_gadget_h ug = data;
187         struct ug_module_ops *ops = NULL;
188         GSList *child = NULL;
189
190         job_start();
191
192         if (!ug || ug->state != UG_STATE_RUNNING)
193                 goto end;
194
195         ug->state = UG_STATE_STOPPED;
196
197         if (ug->children) {
198                 child = ug->children;
199                 while (child) {
200                         ugman_ug_pause(child->data);
201                         child = g_slist_next(child);
202                 }
203         }
204
205         if (ug->module)
206                 ops = &ug->module->ops;
207
208         if (ops && ops->pause)
209                 ops->pause(ug, ug->service, ops->priv);
210
211  end:
212         job_end();
213         return 0;
214 }
215
216 static int ugman_ug_resume(void *data)
217 {
218         ui_gadget_h ug = data;
219         struct ug_module_ops *ops = NULL;
220         GSList *child = NULL;
221
222         job_start();
223
224         if (!ug)
225                 goto end;
226
227         switch (ug->state) {
228         case UG_STATE_CREATED:
229                 ugman_ug_start(ug);
230                 goto end;
231         case UG_STATE_STOPPED:
232                 break;
233         default:
234                 goto end;
235         }
236
237         ug->state = UG_STATE_RUNNING;
238
239         if (ug->children) {
240                 child = ug->children;
241                 while (child) {
242                         ugman_ug_resume(child->data);
243                         child = g_slist_next(child);
244                 }
245         }
246
247         if (ug->module)
248                 ops = &ug->module->ops;
249
250         if (ops && ops->resume)
251                 ops->resume(ug, ug->service, ops->priv);
252
253  end:
254         job_end();
255         return 0;
256 }
257
258 static int ugman_indicator_update(enum ug_option opt, enum ug_event event)
259 {
260         int enable;
261         int cur_state;
262
263         if (!ug_man.win) {
264                 _ERR("ugman_indicator_update failed: no window\n");
265                 return -1;
266         }
267
268         switch (UG_OPT_INDICATOR(opt)) {
269         case UG_OPT_INDICATOR_ENABLE:
270                 if (event == UG_EVENT_NONE)
271                         enable = 1;
272                 else {
273                         cur_state = utilx_get_indicator_state(ug_man.disp, ug_man.win_id);
274                         enable = cur_state ? 1 : 0;
275                 }
276                 break;
277         case UG_OPT_INDICATOR_PORTRAIT_ONLY:
278                 enable = ug_man.is_landscape ? 0 : 1;
279                 break;
280         case UG_OPT_INDICATOR_LANDSCAPE_ONLY:
281                 enable = ug_man.is_landscape ? 1 : 0;
282                 break;
283         case UG_OPT_INDICATOR_DISABLE:
284                 enable = 0;
285                 break;
286         default:
287                 _ERR("ugman_indicator_update failed: Invalid opt\n");
288                 return -1;
289         }
290
291         utilx_enable_indicator(ug_man.disp, ug_man.win_id, enable);
292
293         return 0;
294 }
295
296 static int ugman_ug_getopt(ui_gadget_h ug)
297 {
298         if (!ug)
299                 return -1;
300         /* Indicator Option */
301         if (ug->mode == UG_MODE_FULLVIEW)
302                 ugman_indicator_update(UG_OPT_INDICATOR(ug->opt), UG_EVENT_NONE);
303
304         return 0;
305 }
306
307 static int ugman_ug_event(ui_gadget_h ug, enum ug_event event)
308 {
309         struct ug_module_ops *ops = NULL;
310         GSList *child = NULL;
311
312         if (!ug)
313                 return 0;
314
315         if (ug->children) {
316                 child = ug->children;
317                 while (child) {
318                         ugman_ug_event(child->data, event);
319                         child = g_slist_next(child);
320                 }
321         }
322
323         if (ug->module)
324                 ops = &ug->module->ops;
325
326         if (ops && ops->event)
327                 ops->event(ug, event, ug->service, ops->priv);
328
329         return 0;
330 }
331
332 static int ugman_ug_destroy(void *data)
333 {
334         ui_gadget_h ug = data;
335         struct ug_module_ops *ops = NULL;
336         GSList *child, *trail;
337
338         job_start();
339
340         if (!ug)
341                 goto end;
342
343         switch (ug->state) {
344         case UG_STATE_CREATED:
345         case UG_STATE_RUNNING:
346         case UG_STATE_STOPPED:
347         case UG_STATE_DESTROYING:
348                 break;
349         default:
350                 goto end;
351         }
352
353         ug->state = UG_STATE_DESTROYED;
354
355         if (ug->module)
356                 ops = &ug->module->ops;
357
358         if (ug->children) {
359                 child = ug->children;
360                 while (child) {
361                         trail = g_slist_next(child);
362                         ugman_ug_destroy(child->data);
363                         child = trail;
364                 }
365         }
366
367         if (ops && ops->destroy)
368                 ops->destroy(ug, ug->service, ops->priv);
369
370         ug_relation_del(ug);
371
372         if (ug->mode == UG_MODE_FULLVIEW) {
373                 if (ug_man.fv_top == ug) {
374                         ug_fvlist_del(ug);
375                         ugman_ug_getopt(ug_man.fv_top);
376                 } else {
377                         ug_fvlist_del(ug);
378                 }
379         }
380
381         ug_free(ug);
382
383         if (ug_man.root == ug)
384                 ug_man.root = NULL;
385
386         ugman_tree_dump(ug_man.root);
387  end:
388         job_end();
389
390         return 0;
391 }
392
393 static void ug_hide_end_cb(ui_gadget_h ug)
394 {
395         g_idle_add(ugman_ug_destroy, ug);
396 }
397
398 static int ugman_ug_create(void *data)
399 {
400         ui_gadget_h ug = data;
401         struct ug_module_ops *ops = NULL;
402         struct ug_cbs *cbs;
403         struct ug_engine_ops *eng_ops = NULL;
404
405         if (!ug || ug->state != UG_STATE_READY)
406                 return -1;
407
408         ug->state = UG_STATE_CREATED;
409
410         if (ug->module)
411                 ops = &ug->module->ops;
412
413         if (ug_man.engine)
414                 eng_ops = &ug_man.engine->ops;
415
416         if (ops && ops->create) {
417                 ug->layout = ops->create(ug, ug->mode, ug->service, ops->priv);
418                 if (!ug->layout) {
419                         ug_relation_del(ug);
420                         return -1;
421                 }
422                 if (ug->mode == UG_MODE_FULLVIEW) {
423                         if (eng_ops && eng_ops->create)
424                                 ug->effect_layout = eng_ops->create(ug_man.win, ug, ug_hide_end_cb);
425                 }
426                 cbs = &ug->cbs;
427
428                 if (cbs && cbs->layout_cb)
429                         cbs->layout_cb(ug, ug->mode, cbs->priv);
430
431                 ugman_ug_getopt(ug);
432         }
433
434         ugman_ug_event(ug, ug_man.last_rotate_evt);
435         ugman_ug_start(ug);
436         ugman_tree_dump(ug_man.root);
437
438         return 0;
439 }
440
441 int ugman_ug_add(ui_gadget_h parent, ui_gadget_h ug)
442 {
443         if (!ug_man.is_initted) {
444                 _ERR("ugman_ug_add failed: manager is not initted\n");
445                 return -1;
446         }
447
448         if (!ug_man.root) {
449                 if (parent) {
450                         _ERR("ugman_ug_add failed: parent has to be NULL w/o root\n");
451                         errno = EINVAL;
452                         return -1;
453                 }
454
455                 ug_man.root = ug_root_create();
456                 if (!ug_man.root)
457                         return -1;
458                 ug_man.root->opt = ug_man.base_opt;
459                 ug_man.root->layout = ug_man.win;
460                 ug_fvlist_add(ug_man.root);
461         }
462
463         if (!parent)
464                 parent = ug_man.root;
465
466         if (ug_relation_add(parent, ug))
467                 return -1;
468
469         if (ugman_ug_create(ug) == -1)
470                 return -1;
471
472         if (ug->mode == UG_MODE_FULLVIEW)
473                 ug_fvlist_add(ug);
474
475         return 0;
476 }
477
478 ui_gadget_h ugman_ug_load(ui_gadget_h parent,
479                                 const char *name,
480                                 enum ug_mode mode,
481                                 service_h service, struct ug_cbs *cbs)
482 {
483         int r;
484         ui_gadget_h ug;
485
486         ug = calloc(1, sizeof(struct ui_gadget_s));
487         if (!ug) {
488                 _ERR("ug_create() failed: Memory allocation failed\n");
489                 return NULL;
490         }
491
492         ug->module = ug_module_load(name);
493         if (!ug->module) {
494                 _ERR("ug_create() failed: Module loading failed\n");
495                 goto load_fail;
496         }
497
498         ug->name = strdup(name);
499
500         ug->mode = mode;
501         service_clone(&ug->service, service);
502         ug->opt = ug->module->ops.opt;
503         ug->state = UG_STATE_READY;
504         ug->children = NULL;
505
506         if (cbs)
507                 memcpy(&ug->cbs, cbs, sizeof(struct ug_cbs));
508
509         r = ugman_ug_add(parent, ug);
510         if (r) {
511                 _ERR("ug_create() failed: Tree update failed\n");
512                 goto load_fail;
513         }
514
515         return ug;
516
517  load_fail:
518         ug_free(ug);
519         return NULL;
520 }
521
522 int ugman_ug_destroying(ui_gadget_h ug)
523 {
524         struct ug_module_ops *ops = NULL;
525         GSList *child, *trail;
526
527         ug->destroy_me = 1;
528         ug->state = UG_STATE_DESTROYING;
529
530         if (ug->module)
531                 ops = &ug->module->ops;
532
533         if (ug->children) {
534                 child = ug->children;
535                 while (child) {
536                         trail = g_slist_next(child);
537                         ugman_ug_destroying(child->data);
538                         child = trail;
539                 }
540         }
541
542         if (ops && ops->destroying)
543                 ops->destroying(ug, ug->service, ops->priv);
544
545         return 0;
546 }
547
548 int ugman_ug_del(ui_gadget_h ug)
549 {
550         struct ug_engine_ops *eng_ops = NULL;
551
552         if (!ug || !ugman_ug_exist(ug) || ug->state == UG_STATE_DESTROYED) {
553                 _ERR("ugman_ug_del failed: Invalid ug\n");
554                 errno = EINVAL;
555                 return -1;
556         }
557
558         if (ug->destroy_me) {
559                 _ERR("ugman_ug_del failed: ug is alreay on destroying\n");
560                 return -1;
561         }
562
563         if (!ug_man.is_initted) {
564                 _ERR("ugman_ug_del failed: manager is not initted\n");
565                 return -1;
566         }
567
568         if (!ug_man.root) {
569                 _ERR("ugman_ug_del failed: no root\n");
570                 return -1;
571         }
572
573         ugman_ug_destroying(ug);
574
575         if (ug_man.engine)
576                 eng_ops = &ug_man.engine->ops;
577
578         if (eng_ops && eng_ops->destroy)
579                 if (ug->mode == UG_MODE_FULLVIEW)
580                         eng_ops->destroy(ug, ug_man.fv_top);
581                 else {
582                         eng_ops->destroy(ug, NULL);
583                         g_idle_add(ugman_ug_destroy, ug);
584                 }
585         else
586                 g_idle_add(ugman_ug_destroy, ug);
587
588         return 0;
589 }
590
591 int ugman_ug_del_all(void)
592 {
593         /*  Terminate */
594         if (!ug_man.is_initted) {
595                 _ERR("ugman_ug_del_all failed: manager is not initted\n");
596                 return -1;
597         }
598
599         if (!ug_man.root) {
600                 _ERR("ugman_ug_del_all failed: no root\n");
601                 return -1;
602         }
603
604         if (ug_man.walking > 0)
605                 ug_man.destroy_all = 1;
606         else
607                 ugman_ug_destroy(ug_man.root);
608
609         return 0;
610 }
611
612 int ugman_init(Display *disp, Window xid, void *win, enum ug_option opt)
613 {
614         ug_man.is_initted = 1;
615         ug_man.win = win;
616         ug_man.disp = disp;
617         ug_man.win_id = xid;
618         ug_man.base_opt = opt;
619         ug_man.last_rotate_evt = UG_EVENT_ROTATE_PORTRAIT;
620         ug_man.engine = ug_engine_load();
621
622         return 0;
623 }
624
625 int ugman_resume(void)
626 {
627         /* RESUME */
628         if (!ug_man.is_initted) {
629                 _ERR("ugman_resume failed: manager is not initted\n");
630                 return -1;
631         }
632
633         if (!ug_man.root) {
634                 _ERR("ugman_resume failed: no root\n");
635                 return -1;
636         }
637
638         g_idle_add(ugman_ug_resume, ug_man.root);
639
640         return 0;
641 }
642
643 int ugman_pause(void)
644 {
645         /* PAUSE (Background) */
646         if (!ug_man.is_initted) {
647                 _ERR("ugman_pause failed: manager is not initted\n");
648                 return -1;
649         }
650
651         if (!ug_man.root) {
652                 _ERR("ugman_pause failed: no root\n");
653                 return -1;
654         }
655
656         g_idle_add(ugman_ug_pause, ug_man.root);
657
658         return 0;
659 }
660
661 static int ugman_send_event_pre(void *data)
662 {
663         job_start();
664
665         ugman_ug_event(ug_man.root, (enum ug_event)data);
666
667         job_end();
668
669         return 0;
670 }
671
672 int ugman_send_event(enum ug_event event)
673 {
674         int is_rotation = 1;
675
676         /* Propagate event */
677         if (!ug_man.is_initted) {
678                 _ERR("ugman_send_event failed: manager is not initted\n");
679                 return -1;
680         }
681
682         /* In case of rotation, indicator state has to be updated */
683         switch (event) {
684         case UG_EVENT_ROTATE_PORTRAIT:
685         case UG_EVENT_ROTATE_PORTRAIT_UPSIDEDOWN:
686                 ug_man.last_rotate_evt = event;
687                 ug_man.is_landscape = 0;
688                 break;
689         case UG_EVENT_ROTATE_LANDSCAPE:
690         case UG_EVENT_ROTATE_LANDSCAPE_UPSIDEDOWN:
691                 ug_man.last_rotate_evt = event;
692                 ug_man.is_landscape = 1;
693                 break;
694         default:
695                 is_rotation = 0;
696         }
697
698         if (!ug_man.root) {
699                 _ERR("ugman_send_event failed: no root\n");
700                 return -1;
701         }
702
703         g_idle_add(ugman_send_event_pre, (void *)event);
704
705         if (is_rotation && ug_man.fv_top)
706                 ugman_indicator_update(UG_OPT_INDICATOR(ug_man.fv_top->opt), event);
707
708         return 0;
709 }
710
711 static int ugman_send_key_event_to_ug(ui_gadget_h ug,
712                                       enum ug_key_event event)
713 {
714         struct ug_module_ops *ops = NULL;
715
716         if (!ug)
717                 return -1;
718
719         if (ug->module) {
720                 ops = &ug->module->ops;
721         } else {
722                 return -1;
723         }
724
725         if (ops && ops->key_event) {
726                 ops->key_event(ug, event, ug->service, ops->priv);
727         } else {
728                 return -1;
729         }
730
731         return 0;
732 }
733
734 int ugman_send_key_event(enum ug_key_event event)
735 {
736         if (!ug_man.is_initted) {
737                 _ERR("ugman_send_key_event failed: manager is not initted\n");
738                 return -1;
739         }
740
741         if (!ug_man.fv_top || !ugman_ug_exist(ug_man.fv_top)
742             || ug_man.fv_top->state == UG_STATE_DESTROYED) {
743                 _ERR("ugman_send_key_event failed: full view top UG is invalid\n");
744                 return -1;
745         }
746
747         return ugman_send_key_event_to_ug(ug_man.fv_top, event);
748 }
749
750 int ugman_send_message(ui_gadget_h ug, service_h msg)
751 {
752         struct ug_module_ops *ops = NULL;
753         if (!ug || !ugman_ug_exist(ug) || ug->state == UG_STATE_DESTROYED) {
754                 _ERR("ugman_send_message failed: Invalid ug\n");
755                 errno = EINVAL;
756                 return -1;
757         }
758
759         if (!msg) {
760                 _ERR("ugman_send_message failed: Invalid msg\n");
761                 errno = EINVAL;
762                 return -1;
763         }
764
765         if (ug->module)
766                 ops = &ug->module->ops;
767
768         if (ops && ops->message)
769                 ops->message(ug, msg, ug->service, ops->priv);
770
771         return 0;
772 }
773
774 void *ugman_get_window(void)
775 {
776         return ug_man.win;
777 }
778
779 static inline void job_start(void)
780 {
781         ug_man.walking++;
782 }
783
784 static inline void job_end(void)
785 {
786         ug_man.walking--;
787
788         if (!ug_man.walking && ug_man.destroy_all) {
789                 ug_man.destroy_all = 0;
790                 if (ug_man.root)
791                         ugman_ug_destroy(ug_man.root);
792         }
793
794         if (ug_man.walking < 0)
795                 ug_man.walking = 0;
796 }
797
798 int ugman_ug_exist(ui_gadget_h ug)
799 {
800         return ugman_ug_find(ug_man.root, ug);
801 }