apply FSL license
[pkgs/u/ui-gadget.git] / src / manager.c
1 /*
2  * Copyright 2012  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.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.tizenopensource.org/license
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
19
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <glib.h>
26 #include <utilX.h>
27
28 #include "ug.h"
29 #include "ug-manager.h"
30 #include "ug-engine.h"
31 #include "ug-dbg.h"
32
33 struct ug_manager {
34         struct ui_gadget *root;
35         struct ui_gadget *fv_top;
36         GSList *fv_list;
37
38         void *win;
39         Window win_id;
40         Display *disp;
41
42         enum ug_option base_opt;
43         enum ug_event last_rotate_evt;
44
45         int walking;
46
47         int is_initted:1;
48         int is_landscape:1;
49         int destroy_all:1;
50
51         struct ug_engine *engine;
52 };
53
54 static struct ug_manager ug_man;
55
56 static inline void job_start(void);
57 static inline void job_end(void);
58
59 static int ug_relation_add(struct ui_gadget *p, struct ui_gadget *c)
60 {
61         c->parent = p;
62         /* prepend element to avoid the inefficiency,
63                 which is to traverse the entire list to find the end*/
64         p->children = g_slist_prepend(p->children, c);
65
66         return 0;
67 }
68
69 static int ug_relation_del(struct ui_gadget *ug)
70 {
71         struct ui_gadget *p;
72
73         p = ug->parent;
74         if (!p) {
75                 _ERR("ug_relation_del failed: no parent\n");
76                 return -1;
77         }
78         p->children = g_slist_remove(p->children, ug);
79         if (ug->children)
80                 g_slist_free(ug->children);
81         ug->parent = NULL;
82
83         return 0;
84 }
85
86 static int ug_fvlist_add(struct ui_gadget *c)
87 {
88         ug_man.fv_list = g_slist_prepend(ug_man.fv_list, c);
89         ug_man.fv_top = c;
90
91         return 0;
92 }
93
94 static int ug_fvlist_del(struct ui_gadget *c)
95 {
96         struct ui_gadget *t;
97
98         ug_man.fv_list = g_slist_remove(ug_man.fv_list, c);
99
100         /* update fullview top ug*/
101         t = g_slist_nth_data(ug_man.fv_list, 0);
102         ug_man.fv_top = t;
103
104         return 0;
105 }
106
107 static void ugman_tree_dump(struct ui_gadget *ug)
108 {
109         static int i;
110         int lv;
111         const char *name;
112         GSList *child;
113         struct ui_gadget *c;
114
115         if (!ug)
116                 return;
117
118         name = ug->name;
119         if (ug == ug_man.root) {
120                 i = 0;
121                 _DBG("\n============== TREE_DUMP =============\n");
122                 _DBG("ROOT: Manager\n");
123                 name = "Manager";
124         }
125
126         child = ug->children;
127         if (!child)
128                 return;
129
130         i++;
131         lv = i;
132
133         while (child) {
134                 c = child->data;
135                 _DBG("[%d] %s [%c] (%p) (PARENT:  %s)\n",
136                      lv,
137                      c && c->name ? c->name : "NO CHILD INFO FIXIT!!!",
138                      c && c->mode == UG_MODE_FULLVIEW ? 'F' : 'f', c, name);
139                 ugman_tree_dump(c);
140                 child = g_slist_next(child);
141         }
142 }
143
144 static int ugman_ug_find(struct ui_gadget *p, struct ui_gadget *ug)
145 {
146         GSList *child = NULL;
147
148         if (!p || !ug)
149                 return 0;
150         child = p->children;
151
152         while (child) {
153                 if (child->data == ug)
154                         return 1;
155                 if (ugman_ug_find(child->data, ug))
156                         return 1;
157                 child = g_slist_next(child);
158         }
159
160         return 0;
161 }
162
163 static int ugman_ug_start(void *data)
164 {
165         struct ui_gadget *ug = data;
166         struct ug_module_ops *ops = NULL;
167
168         if (!ug || ug->state != UG_STATE_CREATED
169             || ug->state == UG_STATE_RUNNING)
170                 return 0;
171
172         ug->state = UG_STATE_RUNNING;
173
174         if (ug->module)
175                 ops = &ug->module->ops;
176
177         if (ops && ops->start)
178                 ops->start(ug, ug->data, ops->priv);
179
180         return 0;
181 }
182
183 static int ugman_ug_pause(void *data)
184 {
185         struct ui_gadget *ug = data;
186         struct ug_module_ops *ops = NULL;
187         GSList *child = NULL;
188
189         job_start();
190
191         if (!ug || ug->state != UG_STATE_RUNNING)
192                 goto end;
193
194         ug->state = UG_STATE_STOPPED;
195
196         if (ug->children) {
197                 child = ug->children;
198                 while (child) {
199                         ugman_ug_pause(child->data);
200                         child = g_slist_next(child);
201                 }
202         }
203
204         if (ug->module)
205                 ops = &ug->module->ops;
206
207         if (ops && ops->pause)
208                 ops->pause(ug, ug->data, ops->priv);
209
210  end:
211         job_end();
212         return 0;
213 }
214
215 static int ugman_ug_resume(void *data)
216 {
217         struct ui_gadget *ug = data;
218         struct ug_module_ops *ops = NULL;
219         GSList *child = NULL;
220
221         job_start();
222
223         if (!ug)
224                 goto end;
225
226         switch (ug->state) {
227         case UG_STATE_CREATED:
228                 ugman_ug_start(ug);
229                 goto end;
230         case UG_STATE_STOPPED:
231                 break;
232         default:
233                 goto end;
234         }
235
236         ug->state = UG_STATE_RUNNING;
237
238         if (ug->children) {
239                 child = ug->children;
240                 while (child) {
241                         ugman_ug_resume(child->data);
242                         child = g_slist_next(child);
243                 }
244         }
245
246         if (ug->module)
247                 ops = &ug->module->ops;
248
249         if (ops && ops->resume)
250                 ops->resume(ug, ug->data, ops->priv);
251
252  end:
253         job_end();
254         return 0;
255 }
256
257 static int ugman_indicator_update(enum ug_option opt, enum ug_event event)
258 {
259         int enable;
260         int cur_state;
261
262         if (!ug_man.win) {
263                 _ERR("ugman_indicator_update failed: no window\n");
264                 return -1;
265         }
266
267         switch (UG_OPT_INDICATOR(opt)) {
268         case UG_OPT_INDICATOR_ENABLE:
269                 if (event == UG_EVENT_NONE)
270                         enable = 1;
271                 else {
272                         cur_state = utilx_get_indicator_state(ug_man.disp, ug_man.win_id);
273                         enable = cur_state ? 1 : 0;
274                 }
275                 break;
276         case UG_OPT_INDICATOR_PORTRAIT_ONLY:
277                 enable = ug_man.is_landscape ? 0 : 1;
278                 break;
279         case UG_OPT_INDICATOR_LANDSCAPE_ONLY:
280                 enable = ug_man.is_landscape ? 1 : 0;
281                 break;
282         case UG_OPT_INDICATOR_DISABLE:
283                 enable = 0;
284                 break;
285         default:
286                 _ERR("ugman_indicator_update failed: Invalid opt\n");
287                 return -1;
288         }
289
290         utilx_enable_indicator(ug_man.disp, ug_man.win_id, enable);
291
292         return 0;
293 }
294
295 static int ugman_ug_getopt(struct ui_gadget *ug)
296 {
297         if (!ug)
298                 return -1;
299         /* Indicator Option */
300         if (ug->mode == UG_MODE_FULLVIEW)
301                 ugman_indicator_update(UG_OPT_INDICATOR(ug->opt), UG_EVENT_NONE);
302
303         return 0;
304 }
305
306 static int ugman_ug_event(struct ui_gadget *ug, enum ug_event event)
307 {
308         struct ug_module_ops *ops = NULL;
309         GSList *child = NULL;
310
311         if (!ug)
312                 return 0;
313
314         if (ug->children) {
315                 child = ug->children;
316                 while (child) {
317                         ugman_ug_event(child->data, event);
318                         child = g_slist_next(child);
319                 }
320         }
321
322         if (ug->module)
323                 ops = &ug->module->ops;
324
325         if (ops && ops->event)
326                 ops->event(ug, event, ug->data, ops->priv);
327
328         return 0;
329 }
330
331 static int ugman_ug_destroy(void *data)
332 {
333         struct ui_gadget *ug = data;
334         struct ug_module_ops *ops = NULL;
335         GSList *child, *trail;
336
337         job_start();
338
339         if (!ug)
340                 goto end;
341
342         switch (ug->state) {
343         case UG_STATE_CREATED:
344         case UG_STATE_RUNNING:
345         case UG_STATE_STOPPED:
346         case UG_STATE_DESTROYING:
347                 break;
348         default:
349                 goto end;
350         }
351
352         ug->state = UG_STATE_DESTROYED;
353
354         if (ug->module)
355                 ops = &ug->module->ops;
356
357         if (ug->children) {
358                 child = ug->children;
359                 while (child) {
360                         trail = g_slist_next(child);
361                         ugman_ug_destroy(child->data);
362                         child = trail;
363                 }
364         }
365
366         if (ops && ops->destroy)
367                 ops->destroy(ug, ug->data, ops->priv);
368
369         ug_relation_del(ug);
370
371         if (ug->mode == UG_MODE_FULLVIEW) {
372                 if (ug_man.fv_top == ug) {
373                         ug_fvlist_del(ug);
374                         ugman_ug_getopt(ug_man.fv_top);
375                 } else {
376                         ug_fvlist_del(ug);
377                 }
378         }
379
380         ug_free(ug);
381
382         if (ug_man.root == ug)
383                 ug_man.root = NULL;
384
385         ugman_tree_dump(ug_man.root);
386  end:
387         job_end();
388
389         return 0;
390 }
391
392 static void ug_hide_end_cb(struct ui_gadget *ug)
393 {
394         g_idle_add(ugman_ug_destroy, ug);
395 }
396
397 static int ugman_ug_create(void *data)
398 {
399         struct ui_gadget *ug = data;
400         struct ug_module_ops *ops = NULL;
401         struct ug_cbs *cbs;
402         struct ug_engine_ops *eng_ops = NULL;
403
404         if (!ug || ug->state != UG_STATE_READY)
405                 return -1;
406
407         ug->state = UG_STATE_CREATED;
408
409         if (ug->module)
410                 ops = &ug->module->ops;
411
412         if (ug_man.engine)
413                 eng_ops = &ug_man.engine->ops;
414
415         if (ops && ops->create) {
416                 ug->layout = ops->create(ug, ug->mode, ug->data, ops->priv);
417                 if (!ug->layout) {
418                         ug_relation_del(ug);
419                         return -1;
420                 }
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(struct ui_gadget *parent, struct ui_gadget *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 struct ui_gadget *ugman_ug_load(struct ui_gadget *parent,
479                                 const char *name,
480                                 enum ug_mode mode,
481                                 bundle *data, struct ug_cbs *cbs)
482 {
483         int r;
484         struct ui_gadget *ug;
485
486         ug = calloc(1, sizeof(struct ui_gadget));
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         ug->data = bundle_dup(data);
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(struct ui_gadget *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->data, ops->priv);
544
545         return 0;
546 }
547
548 int ugman_ug_del(struct ui_gadget *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->mode == UG_MODE_FULLVIEW) {
576                 if (ug_man.engine)
577                         eng_ops = &ug_man.engine->ops;
578
579                 if (eng_ops && eng_ops->destroy) {
580                         eng_ops->destroy(ug, ug_man.fv_top);
581                 }
582                 else {
583                         g_idle_add(ugman_ug_destroy, ug);
584                 }
585         }
586         else {
587                 g_idle_add(ugman_ug_destroy, ug);
588         }
589
590         return 0;
591 }
592
593 int ugman_ug_del_all(void)
594 {
595         /*  Terminate */
596         if (!ug_man.is_initted) {
597                 _ERR("ugman_ug_del_all failed: manager is not initted\n");
598                 return -1;
599         }
600
601         if (!ug_man.root) {
602                 _ERR("ugman_ug_del_all failed: no root\n");
603                 return -1;
604         }
605
606         if (ug_man.walking > 0)
607                 ug_man.destroy_all = 1;
608         else
609                 ugman_ug_destroy(ug_man.root);
610
611         return 0;
612 }
613
614 int ugman_init(Display *disp, Window xid, void *win, enum ug_option opt)
615 {
616         ug_man.is_initted = 1;
617         ug_man.win = win;
618         ug_man.disp = disp;
619         ug_man.win_id = xid;
620         ug_man.base_opt = opt;
621         ug_man.last_rotate_evt = UG_EVENT_ROTATE_PORTRAIT;
622         ug_man.engine = ug_engine_load();
623
624         return 0;
625 }
626
627 int ugman_resume(void)
628 {
629         /* RESUME */
630         if (!ug_man.is_initted) {
631                 _ERR("ugman_resume failed: manager is not initted\n");
632                 return -1;
633         }
634
635         if (!ug_man.root) {
636                 _ERR("ugman_resume failed: no root\n");
637                 return -1;
638         }
639
640         g_idle_add(ugman_ug_resume, ug_man.root);
641
642         return 0;
643 }
644
645 int ugman_pause(void)
646 {
647         /* PAUSE (Background) */
648         if (!ug_man.is_initted) {
649                 _ERR("ugman_pause failed: manager is not initted\n");
650                 return -1;
651         }
652
653         if (!ug_man.root) {
654                 _ERR("ugman_pause failed: no root\n");
655                 return -1;
656         }
657
658         g_idle_add(ugman_ug_pause, ug_man.root);
659
660         return 0;
661 }
662
663 static int ugman_send_event_pre(void *data)
664 {
665         job_start();
666
667         ugman_ug_event(ug_man.root, (enum ug_event)data);
668
669         job_end();
670
671         return 0;
672 }
673
674 int ugman_send_event(enum ug_event event)
675 {
676         int is_rotation = 1;
677
678         /* Propagate event */
679         if (!ug_man.is_initted) {
680                 _ERR("ugman_send_event failed: manager is not initted\n");
681                 return -1;
682         }
683
684         /* In case of rotation, indicator state has to be updated */
685         switch (event) {
686         case UG_EVENT_ROTATE_PORTRAIT:
687         case UG_EVENT_ROTATE_PORTRAIT_UPSIDEDOWN:
688                 ug_man.last_rotate_evt = event;
689                 ug_man.is_landscape = 0;
690                 break;
691         case UG_EVENT_ROTATE_LANDSCAPE:
692         case UG_EVENT_ROTATE_LANDSCAPE_UPSIDEDOWN:
693                 ug_man.last_rotate_evt = event;
694                 ug_man.is_landscape = 1;
695                 break;
696         default:
697                 is_rotation = 0;
698         }
699
700         if (!ug_man.root) {
701                 _ERR("ugman_send_event failed: no root\n");
702                 return -1;
703         }
704
705         g_idle_add(ugman_send_event_pre, (void *)event);
706
707         if (is_rotation && ug_man.fv_top)
708                 ugman_indicator_update(UG_OPT_INDICATOR(ug_man.fv_top->opt), event);
709
710         return 0;
711 }
712
713 static int ugman_send_key_event_to_ug(struct ui_gadget *ug,
714                                       enum ug_key_event event)
715 {
716         struct ug_module_ops *ops = NULL;
717
718         if (!ug)
719                 return -1;
720
721         if (ug->module) {
722                 ops = &ug->module->ops;
723         } else {
724                 return -1;
725         }
726
727         if (ops && ops->key_event) {
728                 ops->key_event(ug, event, ug->data, ops->priv);
729         } else {
730                 return -1;
731         }
732
733         return 0;
734 }
735
736 int ugman_send_key_event(enum ug_key_event event)
737 {
738         if (!ug_man.is_initted) {
739                 _ERR("ugman_send_key_event failed: manager is not initted\n");
740                 return -1;
741         }
742
743         if (!ug_man.fv_top || !ugman_ug_exist(ug_man.fv_top)
744             || ug_man.fv_top->state == UG_STATE_DESTROYED) {
745                 _ERR("ugman_send_key_event failed: full view top UG is invalid\n");
746                 return -1;
747         }
748
749         return ugman_send_key_event_to_ug(ug_man.fv_top, event);
750 }
751
752 int ugman_send_message(struct ui_gadget *ug, bundle *msg)
753 {
754         struct ug_module_ops *ops = NULL;
755         if (!ug || !ugman_ug_exist(ug) || ug->state == UG_STATE_DESTROYED) {
756                 _ERR("ugman_send_message failed: Invalid ug\n");
757                 errno = EINVAL;
758                 return -1;
759         }
760
761         if (!msg) {
762                 _ERR("ugman_send_message failed: Invalid msg\n");
763                 errno = EINVAL;
764                 return -1;
765         }
766
767         if (ug->module)
768                 ops = &ug->module->ops;
769
770         if (ops && ops->message)
771                 ops->message(ug, msg, ug->data, ops->priv);
772
773         return 0;
774 }
775
776 void *ugman_get_window(void)
777 {
778         return ug_man.win;
779 }
780
781 static inline void job_start(void)
782 {
783         ug_man.walking++;
784 }
785
786 static inline void job_end(void)
787 {
788         ug_man.walking--;
789
790         if (!ug_man.walking && ug_man.destroy_all) {
791                 ug_man.destroy_all = 0;
792                 if (ug_man.root)
793                         ugman_ug_destroy(ug_man.root);
794         }
795
796         if (ug_man.walking < 0)
797                 ug_man.walking = 0;
798 }
799
800 int ugman_ug_exist(struct ui_gadget *ug)
801 {
802         return ugman_ug_find(ug_man.root, ug);
803 }