Tizen 2.1 release
[platform/core/uifw/e17.git] / src / modules / illume2 / e_mod_policy.c
1 #include "e_illume_private.h"
2 #include "e_mod_policy.h"
3
4 /* local function prototypes */
5 static char *_e_mod_policy_find(void);
6 static int _e_mod_policy_load(char *file);
7 static void _e_mod_policy_handlers_add(void);
8 static void _e_mod_policy_hooks_add(void);
9 static void _e_mod_policy_cb_free(E_Illume_Policy *p);
10 static Eina_Bool _e_mod_policy_cb_border_add(void *data __UNUSED__, int type __UNUSED__, void *event);
11 static Eina_Bool _e_mod_policy_cb_border_del(void *data __UNUSED__, int type __UNUSED__, void *event);
12 static Eina_Bool _e_mod_policy_cb_border_focus_in(void *data __UNUSED__, int type __UNUSED__, void *event);
13 static Eina_Bool _e_mod_policy_cb_border_focus_out(void *data __UNUSED__, int type __UNUSED__, void *event);
14 static Eina_Bool _e_mod_policy_cb_border_show(void *data __UNUSED__, int type __UNUSED__, void *event);
15 static Eina_Bool _e_mod_policy_cb_zone_move_resize(void *data __UNUSED__, int type __UNUSED__, void *event);
16 static Eina_Bool _e_mod_policy_cb_client_message(void *data __UNUSED__, int type __UNUSED__, void *event);
17 static Eina_Bool _e_mod_policy_cb_window_property(void *data __UNUSED__, int type __UNUSED__, void *event);
18 static Eina_Bool _e_mod_policy_cb_policy_change(void *data __UNUSED__, int type, void *event __UNUSED__);
19 static void _e_mod_policy_cb_hook_post_fetch(void *data __UNUSED__, void *data2);
20 static void _e_mod_policy_cb_hook_post_assign(void *data __UNUSED__, void *data2);
21 static void _e_mod_policy_cb_hook_layout(void *data __UNUSED__, void *data2 __UNUSED__);
22
23 /* local variables */
24 static E_Illume_Policy *_policy = NULL;
25 static Eina_List *_policy_hdls = NULL, *_policy_hooks = NULL;
26
27 /* external variables */
28 int E_ILLUME_POLICY_EVENT_CHANGE = 0;
29
30 int 
31 e_mod_policy_init(void) 
32 {
33    Eina_List *ml;
34    E_Manager *man;
35    char *file;
36
37    /* try to find the policy specified in config */
38    if (!(file = _e_mod_policy_find())) 
39      {
40         printf("Cannot find policy\n");
41         return 0;
42      }
43
44    /* attempt to load policy */
45    if (!_e_mod_policy_load(file)) 
46      {
47         /* loading policy failed, bail out */
48         printf("Cannot load policy: %s\n", file);
49         if (file) free(file);
50         return 0;
51      }
52
53    /* create new event for policy changes */
54    E_ILLUME_POLICY_EVENT_CHANGE = ecore_event_type_new();
55
56    /* add our event handlers */
57    _e_mod_policy_handlers_add();
58
59    /* add our border hooks */
60    _e_mod_policy_hooks_add();
61
62    /* loop the root windows */
63    EINA_LIST_FOREACH(e_manager_list(), ml, man) 
64      {
65         Eina_List *cl;
66         E_Container *con;
67
68         /* loop the containers */
69         EINA_LIST_FOREACH(man->containers, cl, con) 
70           {
71              Eina_List *zl;
72              E_Zone *zone;
73
74              /* loop the zones */
75              EINA_LIST_FOREACH(con->zones, zl, zone) 
76                {
77                   E_Illume_Config_Zone *cz;
78                   Ecore_X_Illume_Mode mode = ECORE_X_ILLUME_MODE_SINGLE;
79
80                   /* check for zone config */
81                   if (!(cz = e_illume_zone_config_get(zone->num))) 
82                     continue;
83
84                   /* set mode on this zone */
85                   if (cz->mode.dual == 0)
86                     mode = ECORE_X_ILLUME_MODE_SINGLE;
87                   else 
88                     {
89                        if ((cz->mode.dual == 1) && (cz->mode.side == 0)) 
90                          mode = ECORE_X_ILLUME_MODE_DUAL_TOP;
91                        else if ((cz->mode.dual == 1) && (cz->mode.side == 1))
92                          mode = ECORE_X_ILLUME_MODE_DUAL_LEFT;
93                     }
94                   ecore_x_e_illume_mode_set(zone->black_win, mode);
95                }
96           }
97      }
98
99    return 1;
100 }
101
102 int 
103 e_mod_policy_shutdown(void) 
104 {
105    Ecore_Event_Handler *hdl;
106    E_Border_Hook *hook;
107
108    /* remove the ecore event handlers */
109    EINA_LIST_FREE(_policy_hdls, hdl)
110      ecore_event_handler_del(hdl);
111
112    /* remove the border hooks */
113    EINA_LIST_FREE(_policy_hooks, hook)
114      e_border_hook_del(hook);
115
116    /* destroy the policy if it exists */
117    if (_policy) e_object_del(E_OBJECT(_policy));
118
119    /* reset event type */
120    E_ILLUME_POLICY_EVENT_CHANGE = 0;
121
122    return 1;
123 }
124
125 /* local functions */
126 static char *
127 _e_mod_policy_find(void) 
128 {
129    Eina_List *files;
130    char buff[PATH_MAX], dir[PATH_MAX], *file;
131
132    snprintf(buff, sizeof(buff), "%s.so", _e_illume_cfg->policy.name);
133    snprintf(dir, sizeof(dir), "%s/policies", _e_illume_mod_dir);
134
135    /* try to list all files in this directory */
136    if (!(files = ecore_file_ls(dir))) return NULL;
137
138    /* loop the returned files */
139    EINA_LIST_FREE(files, file) 
140      {
141         /* compare file with needed .so */
142         if (!strcmp(file, buff)) 
143           {
144              snprintf(dir, sizeof(dir), "%s/policies/%s", 
145                       _e_illume_mod_dir, file);
146              break;
147           }
148         free(file);
149      }
150    if (file) free(file);
151    else 
152      {
153         /* if we did not find the requested policy, use a fallback */
154         snprintf(dir, sizeof(dir), "%s/policies/illume.so", _e_illume_mod_dir);
155      }
156
157    return strdup(dir);
158 }
159
160 static int 
161 _e_mod_policy_load(char *file) 
162 {
163    /* safety check */
164    if (!file) return 0;
165
166    /* delete existing policy first */
167    if (_policy) e_object_del(E_OBJECT(_policy));
168
169    /* try to create our new policy object */
170    _policy = 
171      E_OBJECT_ALLOC(E_Illume_Policy, E_ILLUME_POLICY_TYPE, 
172                     _e_mod_policy_cb_free);
173    if (!_policy) 
174      {
175         printf("Failed to allocate new policy object\n");
176         return 0;
177      }
178
179    /* attempt to open the .so */
180    if (!(_policy->handle = dlopen(file, (RTLD_NOW | RTLD_GLOBAL)))) 
181      {
182         /* cannot open the .so file, bail out */
183         printf("Cannot open policy: %s\n", ecore_file_file_get(file));
184         printf("\tError: %s\n", dlerror());
185         e_object_del(E_OBJECT(_policy));
186         return 0;
187      }
188
189    /* clear any existing errors in dynamic loader */
190    dlerror();
191
192    /* try to link to the needed policy api functions */
193    _policy->api = dlsym(_policy->handle, "e_illume_policy_api");
194    _policy->funcs.init = dlsym(_policy->handle, "e_illume_policy_init");
195    _policy->funcs.shutdown = dlsym(_policy->handle, "e_illume_policy_shutdown");
196
197    /* check that policy supports needed functions */
198    if ((!_policy->api) || (!_policy->funcs.init) || (!_policy->funcs.shutdown)) 
199      {
200         /* policy doesn't support needed functions, bail out */
201         printf("Policy does not support needed functions: %s\n", 
202                ecore_file_file_get(file));
203         printf("\tError: %s\n", dlerror());
204         e_object_del(E_OBJECT(_policy));
205         return 0;
206      }
207
208    /* check policy api version */
209    if (_policy->api->version < E_ILLUME_POLICY_API_VERSION) 
210      {
211         /* policy is too old, bail out */
212         printf("Policy is too old: %s\n", ecore_file_file_get(file));
213         e_object_del(E_OBJECT(_policy));
214         return 0;
215      }
216
217    /* try to initialize the policy */
218    if (!_policy->funcs.init(_policy)) 
219      {
220         /* init failed, bail out */
221         printf("Policy failed to initialize: %s\n", ecore_file_file_get(file));
222         e_object_del(E_OBJECT(_policy));
223         return 0;
224      }
225
226    return 1;
227 }
228
229 static void 
230 _e_mod_policy_handlers_add(void) 
231 {
232    _policy_hdls = 
233      eina_list_append(_policy_hdls, 
234                       ecore_event_handler_add(E_EVENT_BORDER_ADD, 
235                                               _e_mod_policy_cb_border_add, NULL));
236    _policy_hdls = 
237      eina_list_append(_policy_hdls, 
238                       ecore_event_handler_add(E_EVENT_BORDER_REMOVE, 
239                                               _e_mod_policy_cb_border_del, NULL));
240    _policy_hdls = 
241      eina_list_append(_policy_hdls, 
242                       ecore_event_handler_add(E_EVENT_BORDER_FOCUS_IN, 
243                                               _e_mod_policy_cb_border_focus_in, 
244                                               NULL));
245    _policy_hdls = 
246      eina_list_append(_policy_hdls, 
247                       ecore_event_handler_add(E_EVENT_BORDER_FOCUS_OUT, 
248                                               _e_mod_policy_cb_border_focus_out, 
249                                               NULL));
250    _policy_hdls = 
251      eina_list_append(_policy_hdls, 
252                       ecore_event_handler_add(E_EVENT_BORDER_SHOW, 
253                                               _e_mod_policy_cb_border_show, 
254                                               NULL));
255    _policy_hdls = 
256      eina_list_append(_policy_hdls, 
257                       ecore_event_handler_add(E_EVENT_ZONE_MOVE_RESIZE, 
258                                               _e_mod_policy_cb_zone_move_resize, 
259                                               NULL));
260    _policy_hdls = 
261      eina_list_append(_policy_hdls, 
262                       ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE, 
263                                               _e_mod_policy_cb_client_message, 
264                                               NULL));
265    _policy_hdls = 
266      eina_list_append(_policy_hdls, 
267                       ecore_event_handler_add(ECORE_X_EVENT_WINDOW_PROPERTY, 
268                                               _e_mod_policy_cb_window_property, 
269                                               NULL));
270    _policy_hdls = 
271      eina_list_append(_policy_hdls, 
272                       ecore_event_handler_add(E_ILLUME_POLICY_EVENT_CHANGE, 
273                                               _e_mod_policy_cb_policy_change, 
274                                               NULL));
275 }
276
277 static void 
278 _e_mod_policy_hooks_add(void) 
279 {
280    _policy_hooks = 
281      eina_list_append(_policy_hooks, 
282                       e_border_hook_add(E_BORDER_HOOK_EVAL_POST_FETCH, 
283                                         _e_mod_policy_cb_hook_post_fetch, NULL));
284    _policy_hooks = 
285      eina_list_append(_policy_hooks, 
286                       e_border_hook_add(E_BORDER_HOOK_EVAL_POST_BORDER_ASSIGN, 
287                                         _e_mod_policy_cb_hook_post_assign, NULL));
288    _policy_hooks = 
289      eina_list_append(_policy_hooks, 
290                       e_border_hook_add(E_BORDER_HOOK_CONTAINER_LAYOUT, 
291                                         _e_mod_policy_cb_hook_layout, NULL));
292 }
293
294 static void 
295 _e_mod_policy_cb_free(E_Illume_Policy *p) 
296 {
297    /* tell the policy to shutdown */
298    if (p->funcs.shutdown) p->funcs.shutdown(p);
299    p->funcs.shutdown = NULL;
300
301    p->funcs.init = NULL;
302    p->api = NULL;
303
304    /* close the linked .so */
305    if (p->handle) dlclose(p->handle);
306    p->handle = NULL;
307
308    E_FREE(p);
309 }
310
311 static Eina_Bool
312 _e_mod_policy_cb_border_add(void *data __UNUSED__, int type __UNUSED__, void *event) 
313 {
314    E_Event_Border_Add *ev;
315
316    ev = event;
317    if ((_policy) && (_policy->funcs.border_add))
318      _policy->funcs.border_add(ev->border);
319
320    return ECORE_CALLBACK_PASS_ON;
321 }
322
323 static Eina_Bool
324 _e_mod_policy_cb_border_del(void *data __UNUSED__, int type __UNUSED__, void *event) 
325 {
326    E_Event_Border_Remove *ev;
327
328    ev = event;
329    if ((_policy) && (_policy->funcs.border_del))
330      _policy->funcs.border_del(ev->border);
331
332    return ECORE_CALLBACK_PASS_ON;
333 }
334
335 static Eina_Bool
336 _e_mod_policy_cb_border_focus_in(void *data __UNUSED__, int type __UNUSED__, void *event) 
337 {
338    E_Event_Border_Focus_In *ev;
339
340    ev = event;
341    if ((_policy) && (_policy->funcs.border_focus_in))
342      _policy->funcs.border_focus_in(ev->border);
343
344    return ECORE_CALLBACK_PASS_ON;
345 }
346
347 static Eina_Bool
348 _e_mod_policy_cb_border_focus_out(void *data __UNUSED__, int type __UNUSED__, void *event) 
349 {
350    E_Event_Border_Focus_Out *ev;
351
352    ev = event;
353    if ((_policy) && (_policy->funcs.border_focus_out))
354      _policy->funcs.border_focus_out(ev->border);
355
356    return ECORE_CALLBACK_PASS_ON;
357 }
358
359 static Eina_Bool
360 _e_mod_policy_cb_border_show(void *data __UNUSED__, int type __UNUSED__, void *event) 
361 {
362    E_Event_Border_Show *ev;
363
364    ev = event;
365    if ((_policy) && (_policy->funcs.border_show))
366      _policy->funcs.border_show(ev->border);
367
368    return ECORE_CALLBACK_PASS_ON;
369 }
370
371 static Eina_Bool
372 _e_mod_policy_cb_zone_move_resize(void *data __UNUSED__, int type __UNUSED__, void *event) 
373 {
374    E_Event_Zone_Move_Resize *ev;
375
376    ev = event;
377    if ((_policy) && (_policy->funcs.zone_move_resize))
378      _policy->funcs.zone_move_resize(ev->zone);
379
380    return ECORE_CALLBACK_PASS_ON;
381 }
382
383 static E_Zone *
384 _e_mod_zone_win_get(Ecore_X_Window win)
385 {
386    E_Zone *zone = NULL;
387    E_Border *bd;
388
389    if (!(bd = e_border_find_by_client_window(win)))
390      {
391         if (!(zone = e_util_zone_window_find(win))) return NULL;
392      }
393    else if (bd->zone) zone = bd->zone;
394    return zone;
395 }
396
397 static Eina_Bool
398 _e_mod_policy_cb_client_message(void *data __UNUSED__, int type __UNUSED__, void *event) 
399 {
400    Ecore_X_Event_Client_Message *ev;
401
402    ev = event;
403    if (ev->message_type == ECORE_X_ATOM_NET_ACTIVE_WINDOW) 
404      {
405         E_Border *bd;
406
407         if (!(bd = e_border_find_by_client_window(ev->win))) return ECORE_CALLBACK_PASS_ON;
408         if ((_policy) && (_policy->funcs.border_activate))
409           _policy->funcs.border_activate(bd);
410      }
411    else if (ev->message_type == ECORE_X_ATOM_E_ILLUME_MODE) 
412      {
413         E_Zone *zone;
414         
415         if (!(zone = _e_mod_zone_win_get(ev->win))) return ECORE_CALLBACK_PASS_ON;
416         if ((_policy) && (_policy->funcs.zone_mode_change))
417           _policy->funcs.zone_mode_change(zone, ev->data.l[0]);
418      }
419    else if (ev->message_type == ECORE_X_ATOM_E_ILLUME_CLOSE) 
420      {
421         E_Zone *zone;
422
423         if (!(zone = _e_mod_zone_win_get(ev->win))) return ECORE_CALLBACK_PASS_ON;
424         if ((_policy) && (_policy->funcs.zone_close))
425           _policy->funcs.zone_close(zone);
426      }
427    else if (ev->message_type == ECORE_X_ATOM_E_ILLUME_FOCUS_BACK) 
428      {
429         E_Zone *zone;
430
431         if (!(zone = _e_mod_zone_win_get(ev->win))) return ECORE_CALLBACK_PASS_ON;
432         if ((_policy) && (_policy->funcs.focus_back))
433           _policy->funcs.focus_back(zone);
434      }
435    else if (ev->message_type == ECORE_X_ATOM_E_ILLUME_FOCUS_FORWARD) 
436      {
437         E_Zone *zone;
438
439         if (!(zone = _e_mod_zone_win_get(ev->win))) return ECORE_CALLBACK_PASS_ON;
440         if ((_policy) && (_policy->funcs.focus_forward))
441           _policy->funcs.focus_forward(zone);
442      }
443    else if (ev->message_type == ECORE_X_ATOM_E_ILLUME_FOCUS_HOME) 
444      {
445         E_Zone *zone;
446
447         if (!(zone = _e_mod_zone_win_get(ev->win))) return ECORE_CALLBACK_PASS_ON;
448         if ((_policy) && (_policy->funcs.focus_home))
449           _policy->funcs.focus_home(zone);
450      }
451    else if (ev->message_type == ECORE_X_ATOM_E_ILLUME_DRAG_START) 
452      {
453         E_Border *bd;
454
455         if (!(bd = e_border_find_by_client_window(ev->win))) return ECORE_CALLBACK_PASS_ON;
456         if ((_policy) && (_policy->funcs.drag_start))
457           _policy->funcs.drag_start(bd);
458      }
459    else if (ev->message_type == ECORE_X_ATOM_E_ILLUME_DRAG_END) 
460      {
461         E_Border *bd;
462
463         if (!(bd = e_border_find_by_client_window(ev->win))) return ECORE_CALLBACK_PASS_ON;
464         if ((_policy) && (_policy->funcs.drag_end))
465           _policy->funcs.drag_end(bd);
466      }
467
468    return ECORE_CALLBACK_PASS_ON;
469 }
470
471 static Eina_Bool
472 _e_mod_policy_cb_window_property(void *data __UNUSED__, int type __UNUSED__, void *event) 
473 {
474    Ecore_X_Event_Window_Property *ev;
475
476    ev = event;
477    if ((_policy) && (_policy->funcs.property_change))
478      _policy->funcs.property_change(ev);
479
480    return ECORE_CALLBACK_PASS_ON;
481 }
482
483 static Eina_Bool
484 _e_mod_policy_cb_policy_change(void *data __UNUSED__, int type, void *event __UNUSED__) 
485 {
486    char *file;
487
488    if (type != E_ILLUME_POLICY_EVENT_CHANGE) return ECORE_CALLBACK_PASS_ON;
489
490    /* find policy specified in config */
491    if (!(file = _e_mod_policy_find())) return ECORE_CALLBACK_PASS_ON;
492
493    /* try to load the policy */
494    _e_mod_policy_load(file);
495
496    if (file) free(file);
497
498    return ECORE_CALLBACK_PASS_ON;
499 }
500
501 static void 
502 _e_mod_policy_cb_hook_post_fetch(void *data __UNUSED__, void *data2) 
503 {
504    E_Border *bd;
505
506    if (!(bd = data2)) return;
507    if ((_policy) && (_policy->funcs.border_post_fetch))
508      _policy->funcs.border_post_fetch(bd);
509 }
510
511 static void 
512 _e_mod_policy_cb_hook_post_assign(void *data __UNUSED__, void *data2) 
513 {
514    E_Border *bd;
515
516    if (!(bd = data2)) return;
517    if ((_policy) && (_policy->funcs.border_post_assign))
518      _policy->funcs.border_post_assign(bd);
519 }
520
521 static void 
522 _e_mod_policy_cb_hook_layout(void *data __UNUSED__, void *data2 __UNUSED__) 
523 {
524    E_Zone *zone;
525    E_Border *bd;
526    Eina_List *zl = NULL, *l;
527
528    /* loop through border list and find what changed */
529    EINA_LIST_FOREACH(e_border_client_list(), l, bd) 
530      {
531         if ((bd->new_client) || (bd->pending_move_resize) || 
532             (bd->changes.pos) || (bd->changes.size) || (bd->changes.visible) || 
533             (bd->need_shape_export) || (bd->need_shape_merge)) 
534           {
535              /* NB: this border changed. add it's zone to list of what needs 
536               * updating. This is done so we do not waste cpu cycles 
537               * updating zones where nothing changed */
538              if (!eina_list_data_find(zl, bd->zone))
539                zl = eina_list_append(zl, bd->zone);
540           }
541      }
542
543    /* loop the zones that need updating and call the policy update function */
544    EINA_LIST_FREE(zl, zone) 
545      {
546         if ((_policy) && (_policy->funcs.zone_layout))
547           _policy->funcs.zone_layout(zone);
548      }
549 }