5cfc7e36b89acf7a6d2ad543c0c89bc0f19d5e31
[pkgs/u/ui-gadget.git] / src / manager.c
1 /*
2  * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * This file is part of the UI Gadget
5  * Written by Jayoun Lee <airjany@samsung.com>, Jinwoo Nam <jwoo.nam@samsung.com>
6  *
7  * PROPRIETARY/CONFIDENTIAL
8  *
9  * This software is the confidential and proprietary information of
10  * SAMSUNG ELECTRONICS (Confidential Information).
11  * You shall not disclose such Confidential Information and shall
12  * use it only in accordance with the terms of the license agreement
13  * you entered into with SAMSUNG ELECTRONICS.  SAMSUNG make no
14  * representations or warranties about the suitability
15  * of the software, either express or implied, including but not
16  * limited to the implied warranties of merchantability, fitness for a particular purpose, or non-
17  * infringement. SAMSUNG shall not be liable for any damages suffered by licensee as
18  * a result of using, modifying or distributing this software or its derivatives.
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         struct ui_gadget *root;
36         struct ui_gadget *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(struct ui_gadget *p, struct ui_gadget *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(struct ui_gadget *ug)
71 {
72         struct ui_gadget *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(struct ui_gadget *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(struct ui_gadget *c)
96 {
97         struct ui_gadget *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(struct ui_gadget *ug)
109 {
110         static int i;
111         int lv;
112         const char *name;
113         GSList *child;
114         struct ui_gadget *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(struct ui_gadget *p, struct ui_gadget *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         struct ui_gadget *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->data, ops->priv);
180
181         return 0;
182 }
183
184 static int ugman_ug_pause(void *data)
185 {
186         struct ui_gadget *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->data, ops->priv);
210
211  end:
212         job_end();
213         return 0;
214 }
215
216 static int ugman_ug_resume(void *data)
217 {
218         struct ui_gadget *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->data, 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(struct ui_gadget *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(struct ui_gadget *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->data, ops->priv);
328
329         return 0;
330 }
331
332 static int ugman_ug_destroy(void *data)
333 {
334         struct ui_gadget *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->data, 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(struct ui_gadget *ug)
394 {
395         g_idle_add(ugman_ug_destroy, ug);
396 }
397
398 static int ugman_ug_create(void *data)
399 {
400         struct ui_gadget *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->data, ops->priv);
418                 if (!ug->layout) {
419                         ug_relation_del(ug);
420                         return -1;
421                 }
422
423                 if (ug->mode == (UG_MODE_FULLVIEW)) {
424                         if (eng_ops && eng_ops->create)
425                                 ug->effect_layout = eng_ops->create(ug_man.win, ug, ug_hide_end_cb);
426                 }
427                 cbs = &ug->cbs;
428
429                 if (cbs && cbs->layout_cb)
430                         cbs->layout_cb(ug, ug->mode, cbs->priv);
431
432                 ugman_ug_getopt(ug);
433         }
434
435         ugman_ug_event(ug, ug_man.last_rotate_evt);
436         ugman_ug_start(ug);
437         ugman_tree_dump(ug_man.root);
438
439         return 0;
440 }
441
442 int ugman_ug_add(struct ui_gadget *parent, struct ui_gadget *ug)
443 {
444         if (!ug_man.is_initted) {
445                 _ERR("ugman_ug_add failed: manager is not initted\n");
446                 return -1;
447         }
448
449         if (!ug_man.root) {
450                 if (parent) {
451                         _ERR("ugman_ug_add failed: parent has to be NULL w/o root\n");
452                         errno = EINVAL;
453                         return -1;
454                 }
455
456                 ug_man.root = ug_root_create();
457                 if (!ug_man.root)
458                         return -1;
459                 ug_man.root->opt = ug_man.base_opt;
460                 ug_man.root->layout = ug_man.win;
461                 ug_fvlist_add(ug_man.root);
462         }
463
464         if (!parent)
465                 parent = ug_man.root;
466
467         if (ug_relation_add(parent, ug))
468                 return -1;
469
470         if (ugman_ug_create(ug) == -1)
471                 return -1;
472
473         if (ug->mode == UG_MODE_FULLVIEW)
474                 ug_fvlist_add(ug);
475
476         return 0;
477 }
478
479 struct ui_gadget *ugman_ug_load(struct ui_gadget *parent,
480                                 const char *name,
481                                 enum ug_mode mode,
482                                 bundle *data, struct ug_cbs *cbs)
483 {
484         int r;
485         struct ui_gadget *ug;
486
487         ug = calloc(1, sizeof(struct ui_gadget));
488         if (!ug) {
489                 _ERR("ug_create() failed: Memory allocation failed\n");
490                 return NULL;
491         }
492
493         ug->module = ug_module_load(name);
494         if (!ug->module) {
495                 _ERR("ug_create() failed: Module loading failed\n");
496                 goto load_fail;
497         }
498
499         ug->name = strdup(name);
500
501         ug->mode = mode;
502         ug->data = bundle_dup(data);
503         ug->opt = ug->module->ops.opt;
504         ug->state = UG_STATE_READY;
505         ug->children = NULL;
506
507         if (cbs)
508                 memcpy(&ug->cbs, cbs, sizeof(struct ug_cbs));
509
510         r = ugman_ug_add(parent, ug);
511         if (r) {
512                 _ERR("ug_create() failed: Tree update failed\n");
513                 goto load_fail;
514         }
515
516         return ug;
517
518  load_fail:
519         ug_free(ug);
520         return NULL;
521 }
522
523 int ugman_ug_destroying(struct ui_gadget *ug)
524 {
525         struct ug_module_ops *ops = NULL;
526         GSList *child, *trail;
527
528         ug->destroy_me = 1;
529         ug->state = UG_STATE_DESTROYING;
530
531         if (ug->module)
532                 ops = &ug->module->ops;
533
534         if (ug->children) {
535                 child = ug->children;
536                 while (child) {
537                         trail = g_slist_next(child);
538                         ugman_ug_destroying(child->data);
539                         child = trail;
540                 }
541         }
542
543         if (ops && ops->destroying)
544                 ops->destroying(ug, ug->data, ops->priv);
545
546         return 0;
547 }
548
549 int ugman_ug_del(struct ui_gadget *ug)
550 {
551         struct ug_engine_ops *eng_ops = NULL;
552
553         if (!ug || !ugman_ug_exist(ug) || ug->state == UG_STATE_DESTROYED) {
554                 _ERR("ugman_ug_del failed: Invalid ug\n");
555                 errno = EINVAL;
556                 return -1;
557         }
558
559         if (ug->destroy_me) {
560                 _ERR("ugman_ug_del failed: ug is alreay on destroying\n");
561                 return -1;
562         }
563
564         if (!ug_man.is_initted) {
565                 _ERR("ugman_ug_del failed: manager is not initted\n");
566                 return -1;
567         }
568
569         if (!ug_man.root) {
570                 _ERR("ugman_ug_del failed: no root\n");
571                 return -1;
572         }
573
574         ugman_ug_destroying(ug);
575
576         if (ug->mode == UG_MODE_FULLVIEW) {
577                 if (ug_man.engine)
578                         eng_ops = &ug_man.engine->ops;
579
580                 if (eng_ops && eng_ops->destroy) {
581                         eng_ops->destroy(ug, ug_man.fv_top);
582                 }
583                 else {
584                         g_idle_add(ugman_ug_destroy, ug);
585                 }
586         }
587         else {
588                 g_idle_add(ugman_ug_destroy, ug);
589         }
590
591         return 0;
592 }
593
594 int ugman_ug_del_all(void)
595 {
596         /*  Terminate */
597         if (!ug_man.is_initted) {
598                 _ERR("ugman_ug_del_all failed: manager is not initted\n");
599                 return -1;
600         }
601
602         if (!ug_man.root) {
603                 _ERR("ugman_ug_del_all failed: no root\n");
604                 return -1;
605         }
606
607         if (ug_man.walking > 0)
608                 ug_man.destroy_all = 1;
609         else
610                 ugman_ug_destroy(ug_man.root);
611
612         return 0;
613 }
614
615 int ugman_init(Display *disp, Window xid, void *win, enum ug_option opt)
616 {
617         ug_man.is_initted = 1;
618         ug_man.win = win;
619         ug_man.disp = disp;
620         ug_man.win_id = xid;
621         ug_man.base_opt = opt;
622         ug_man.last_rotate_evt = UG_EVENT_ROTATE_PORTRAIT;
623         ug_man.engine = ug_engine_load();
624
625         return 0;
626 }
627
628 int ugman_resume(void)
629 {
630         /* RESUME */
631         if (!ug_man.is_initted) {
632                 _ERR("ugman_resume failed: manager is not initted\n");
633                 return -1;
634         }
635
636         if (!ug_man.root) {
637                 _ERR("ugman_resume failed: no root\n");
638                 return -1;
639         }
640
641         g_idle_add(ugman_ug_resume, ug_man.root);
642
643         return 0;
644 }
645
646 int ugman_pause(void)
647 {
648         /* PAUSE (Background) */
649         if (!ug_man.is_initted) {
650                 _ERR("ugman_pause failed: manager is not initted\n");
651                 return -1;
652         }
653
654         if (!ug_man.root) {
655                 _ERR("ugman_pause failed: no root\n");
656                 return -1;
657         }
658
659         g_idle_add(ugman_ug_pause, ug_man.root);
660
661         return 0;
662 }
663
664 static int ugman_send_event_pre(void *data)
665 {
666         job_start();
667
668         ugman_ug_event(ug_man.root, (enum ug_event)data);
669
670         job_end();
671
672         return 0;
673 }
674
675 int ugman_send_event(enum ug_event event)
676 {
677         int is_rotation = 1;
678
679         /* Propagate event */
680         if (!ug_man.is_initted) {
681                 _ERR("ugman_send_event failed: manager is not initted\n");
682                 return -1;
683         }
684
685         /* In case of rotation, indicator state has to be updated */
686         switch (event) {
687         case UG_EVENT_ROTATE_PORTRAIT:
688         case UG_EVENT_ROTATE_PORTRAIT_UPSIDEDOWN:
689                 ug_man.last_rotate_evt = event;
690                 ug_man.is_landscape = 0;
691                 break;
692         case UG_EVENT_ROTATE_LANDSCAPE:
693         case UG_EVENT_ROTATE_LANDSCAPE_UPSIDEDOWN:
694                 ug_man.last_rotate_evt = event;
695                 ug_man.is_landscape = 1;
696                 break;
697         default:
698                 is_rotation = 0;
699         }
700
701         if (!ug_man.root) {
702                 _ERR("ugman_send_event failed: no root\n");
703                 return -1;
704         }
705
706         g_idle_add(ugman_send_event_pre, (void *)event);
707
708         if (is_rotation && ug_man.fv_top)
709                 ugman_indicator_update(UG_OPT_INDICATOR(ug_man.fv_top->opt), event);
710
711         return 0;
712 }
713
714 static int ugman_send_key_event_to_ug(struct ui_gadget *ug,
715                                       enum ug_key_event event)
716 {
717         struct ug_module_ops *ops = NULL;
718
719         if (!ug)
720                 return -1;
721
722         if (ug->module) {
723                 ops = &ug->module->ops;
724         } else {
725                 return -1;
726         }
727
728         if (ops && ops->key_event) {
729                 ops->key_event(ug, event, ug->data, ops->priv);
730         } else {
731                 return -1;
732         }
733
734         return 0;
735 }
736
737 int ugman_send_key_event(enum ug_key_event event)
738 {
739         if (!ug_man.is_initted) {
740                 _ERR("ugman_send_key_event failed: manager is not initted\n");
741                 return -1;
742         }
743
744         if (!ug_man.fv_top || !ugman_ug_exist(ug_man.fv_top)
745             || ug_man.fv_top->state == UG_STATE_DESTROYED) {
746                 _ERR("ugman_send_key_event failed: full view top UG is invalid\n");
747                 return -1;
748         }
749
750         return ugman_send_key_event_to_ug(ug_man.fv_top, event);
751 }
752
753 int ugman_send_message(struct ui_gadget *ug, bundle *msg)
754 {
755         struct ug_module_ops *ops = NULL;
756         if (!ug || !ugman_ug_exist(ug) || ug->state == UG_STATE_DESTROYED) {
757                 _ERR("ugman_send_message failed: Invalid ug\n");
758                 errno = EINVAL;
759                 return -1;
760         }
761
762         if (!msg) {
763                 _ERR("ugman_send_message failed: Invalid msg\n");
764                 errno = EINVAL;
765                 return -1;
766         }
767
768         if (ug->module)
769                 ops = &ug->module->ops;
770
771         if (ops && ops->message)
772                 ops->message(ug, msg, ug->data, ops->priv);
773
774         return 0;
775 }
776
777 void *ugman_get_window(void)
778 {
779         return ug_man.win;
780 }
781
782 static inline void job_start(void)
783 {
784         ug_man.walking++;
785 }
786
787 static inline void job_end(void)
788 {
789         ug_man.walking--;
790
791         if (!ug_man.walking && ug_man.destroy_all) {
792                 ug_man.destroy_all = 0;
793                 if (ug_man.root)
794                         ugman_ug_destroy(ug_man.root);
795         }
796
797         if (ug_man.walking < 0)
798                 ug_man.walking = 0;
799 }
800
801 int ugman_ug_exist(struct ui_gadget *ug)
802 {
803         return ugman_ug_find(ug_man.root, ug);
804 }