Merged with devel
[platform/core/uifw/e17-extra-modules.git] / illume2-tizen / src / e_mod_floating_window.c
1 #include "e_illume_private.h"
2 #include "e_mod_floating_window.h"
3
4 /* global event callback function */
5 static Eina_Bool _e_mod_floating_cb_idle_enterer(void *data __UNUSED__);
6 static Eina_Bool _e_mod_floating_cb_border_add(void *data __UNUSED__,
7                                               int type __UNUSED__,
8                                               void *event);
9 static Eina_Bool _e_mod_floating_cb_border_del(void *data __UNUSED__,
10                                               int type __UNUSED__,
11                                               void *event);
12
13 static Eina_Bool _e_mod_floating_cb_client_message(void   *data,
14                                                      int    type,
15                                                      void   *event);
16 static Eina_Bool _e_mod_floating_cb_window_property(void  *data,
17                                                       int   type,
18                                                       void  *event);
19
20 /* general function */
21 static int _e_mod_floating_atom_init(void);
22 static void _e_mod_floating_border_list_add(E_Border *bd);
23 static void _e_mod_floating_border_list_del(E_Border *bd);
24 static void _e_mod_hints_floating_list_set(void);
25 static E_Illume_Floating_Border* _e_mod_floating_get_floating_border(Ecore_X_Window win);
26 static void _e_mod_floating_window_state_change(Ecore_X_Event_Window_Property *ev);
27
28 /* for close the floating windows */
29 static void _e_mod_floating_close_all(void);
30
31 /* for iconify the floating windows */
32 static void _e_mod_floating_iconify(E_Illume_Floating_Border *ft_bd,
33                                      Eina_Bool iconify);
34 static void _e_mod_floating_iconify_all(Eina_Bool iconify);
35
36 /* for automatically align the floating windows */
37 static void _e_mod_floating_smart_cleanup(Ecore_X_Event_Client_Message *event);
38
39 /* for controlling app-in-app window */
40 static Ecore_X_Atom E_ILLUME_ATOM_FLOATING_WINDOW_ALIGN;
41 static Ecore_X_Atom E_ILLUME_ATOM_FLOATING_WINDOW_CHANGE_VISIBLE;
42 static Ecore_X_Atom E_ILLUME_ATOM_FLOATING_WINDOW_CLOSE_ALL;
43 static Ecore_X_Atom E_ILLUME_ATOM_FLOATING_WINDOW_LIST;
44
45 static Eina_List *_fw_hdls;
46 static Eina_List *_fw_hooks;
47 static Ecore_Idle_Enterer *_idle_enterer;
48
49 static Eina_Hash *floating_wins_hash;
50 static Eina_List *floating_wins;
51
52 int
53 e_mod_floating_init(void)
54 {
55    Eina_Bool ret = EINA_FALSE;
56
57    _fw_hdls =
58       eina_list_append(_fw_hdls,
59                        ecore_event_handler_add(E_EVENT_BORDER_ADD,
60                                                _e_mod_floating_cb_border_add,
61                                                NULL));
62    _fw_hdls =
63       eina_list_append(_fw_hdls,
64                        ecore_event_handler_add(E_EVENT_BORDER_REMOVE,
65                                                _e_mod_floating_cb_border_del,
66                                                NULL));
67    _fw_hdls =
68       eina_list_append(_fw_hdls,
69                        ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE,
70                                                _e_mod_floating_cb_client_message,
71                                                NULL));
72    _fw_hdls =
73       eina_list_append(_fw_hdls,
74                        ecore_event_handler_add(ECORE_X_EVENT_WINDOW_PROPERTY,
75                                                _e_mod_floating_cb_window_property,
76                                                NULL));
77
78    _idle_enterer = ecore_idle_enterer_add(_e_mod_floating_cb_idle_enterer, NULL);
79
80    ret = _e_mod_floating_atom_init();
81    if (!ret)
82      L(LT_FLOATING, "%s(%d) Failed initializing atoms\n", __func__, __LINE__);
83
84    if (!floating_wins_hash)
85      floating_wins_hash = eina_hash_string_superfast_new(NULL);
86
87    return ret;
88 }
89
90 int
91 e_mod_floating_shutdown(void)
92 {
93    E_FREE_LIST(_fw_hdls, ecore_event_handler_del);
94    E_FREE_LIST(_fw_hooks, e_border_hook_del);
95
96    if (_idle_enterer) ecore_idle_enterer_del(_idle_enterer);
97    _idle_enterer = NULL;
98
99    if (floating_wins_hash) eina_hash_free(floating_wins_hash);
100    floating_wins_hash = NULL;
101
102    if (floating_wins) eina_list_free(floating_wins);
103    floating_wins = NULL;
104
105    return 1;
106 }
107
108 EINTERN Eina_Bool
109 e_mod_floating_border_is_floating(E_Border *bd)
110 {
111    unsigned int state = bd->client.illume.win_state.state;
112    Eina_Bool ret = EINA_FALSE;
113
114    if (state == ECORE_X_ILLUME_WINDOW_STATE_FLOATING)
115      ret = EINA_TRUE;
116
117    return ret;
118 }
119
120 EINTERN Eina_List*
121 e_mod_floating_get_window_list(void)
122 {
123    return floating_wins;
124 }
125
126 static int
127 _e_mod_floating_atom_init(void)
128 {
129    E_ILLUME_ATOM_FLOATING_WINDOW_ALIGN =
130       ecore_x_atom_get("_E_ILLUME_ATOM_FLOATING_WINDOW_ALIGN");
131    if (!E_ILLUME_ATOM_FLOATING_WINDOW_ALIGN)
132      {
133         fprintf (stderr, "[ILLUME2] Critical Error!!!"
134                  "Cannot create _E_ILLUME_ATOM_FLOATING_WINDOW_ALIGN Atom...\n");
135         return 0;
136      }
137
138    E_ILLUME_ATOM_FLOATING_WINDOW_CHANGE_VISIBLE =
139       ecore_x_atom_get("_E_ILLUME_ATOM_FLOATING_WINDOW_CHANGE_VISIBLE");
140    if (!E_ILLUME_ATOM_FLOATING_WINDOW_CHANGE_VISIBLE)
141      {
142         fprintf (stderr, "[ILLUME2] Critical Error!!!"
143                  "Cannot create _E_ILLUME_ATOM_FLOATING_WINDOW_CHANGE_VISIBLE Atom...\n");
144         return 0;
145      }
146
147    E_ILLUME_ATOM_FLOATING_WINDOW_CLOSE_ALL =
148       ecore_x_atom_get("_E_ILLUME_ATOM_FLOATING_WINDOW_CLOSE_ALL");
149    if (!E_ILLUME_ATOM_FLOATING_WINDOW_CLOSE_ALL)
150      {
151         fprintf (stderr, "[ILLUME2] Critical Error!!!"
152                  "Cannot create _E_ILLUME_ATOM_FLOATING_WINDOW_CLOSE_ALL Atom...\n");
153         return 0;
154      }
155
156    E_ILLUME_ATOM_FLOATING_WINDOW_LIST =
157       ecore_x_atom_get("_E_ILLUME_ATOM_FLOATING_WINDOW_LIST");
158    if (!E_ILLUME_ATOM_FLOATING_WINDOW_LIST)
159      {
160         fprintf (stderr, "[ILLUME2] Critical Error!!!"
161                  "Cannot create _E_ILLUME_ATOM_FLOATING_WINDOW_LIST Atom...\n");
162         return 0;
163      }
164
165    return 1;
166 }
167
168 static void
169 _e_mod_floating_window_state_change(Ecore_X_Event_Window_Property *ev)
170 {
171    E_Border *bd = NULL;
172    unsigned int state = 0;
173
174    if (!(bd = e_border_find_by_client_window(ev->win))) return;
175
176    state = ecore_x_e_illume_window_state_get(ev->win);
177    switch(state)
178      {
179       case ECORE_X_ILLUME_WINDOW_STATE_FLOATING:
180          L(LT_FLOATING, "%s(%d) State of window is changed to floating, win: 0x%08x\n",
181            __func__, __LINE__, ev->win);
182          _e_mod_floating_border_list_add(bd);
183          break;
184       case ECORE_X_ILLUME_WINDOW_STATE_NORMAL:
185          L(LT_FLOATING, "%s(%d) State of window is changed to normal, win: 0x%08x\n",
186            __func__, __LINE__, ev->win);
187          _e_mod_floating_border_list_del(bd);
188          break;
189      }
190 }
191
192 static E_Illume_Floating_Border*
193 _e_mod_floating_get_floating_border(Ecore_X_Window win)
194 {
195    return eina_hash_find(floating_wins_hash, e_util_winid_str_get(win));
196 }
197
198 static void
199 _e_mod_floating_border_list_add(E_Border *bd)
200 {
201    E_Illume_Floating_Border *ft_bd = NULL, *tmp_ft_bd = NULL;
202
203    EINA_SAFETY_ON_NULL_RETURN(bd);
204    if (!e_mod_floating_border_is_floating(bd)) return;
205
206    L(LT_FLOATING, "%s(%d) Foating window is added in list, win: 0x%08x\n",
207      __func__, __LINE__, bd->client.win);
208
209    ft_bd = E_NEW(E_Illume_Floating_Border, 1);
210    EINA_SAFETY_ON_NULL_RETURN(ft_bd);
211
212    memset(ft_bd, 0, sizeof(E_Illume_Floating_Border));
213    ft_bd->bd = bd;
214
215    floating_wins = eina_list_append(floating_wins, ft_bd);
216    tmp_ft_bd = eina_hash_find(floating_wins_hash, e_util_winid_str_get(bd->client.win));
217    if (tmp_ft_bd)
218      {
219         E_Border *bd2 = tmp_ft_bd->bd;
220
221         L(LT_FLOATING, "%s(%d) Something worng!!\n", __func__, __LINE__);
222         eina_hash_del(floating_wins_hash,
223                       e_util_winid_str_get(bd2->client.win), tmp_ft_bd);
224         eina_hash_del(floating_wins_hash,
225                       e_util_winid_str_get(bd2->bg_win), tmp_ft_bd);
226         eina_hash_del(floating_wins_hash,
227                       e_util_winid_str_get(bd2->win), tmp_ft_bd);
228      }
229    eina_hash_add(floating_wins_hash, e_util_winid_str_get(bd->client.win), ft_bd);
230    eina_hash_add(floating_wins_hash, e_util_winid_str_get(bd->bg_win), ft_bd);
231    eina_hash_add(floating_wins_hash, e_util_winid_str_get(bd->win), ft_bd);
232
233    _e_mod_hints_floating_list_set();
234 }
235
236 static void
237 _e_mod_floating_border_list_del(E_Border *bd)
238 {
239    E_Illume_Floating_Border *ft_bd = NULL;
240
241    ft_bd = _e_mod_floating_get_floating_border(bd->win);
242    if (!ft_bd)
243      {
244         L(LT_FLOATING, "%s(%d) There is no border in list", __func__, __LINE__);
245         return;
246      }
247
248    L(LT_FLOATING, "%s(%d) Floating window is removed in list, win:0x%08x\n",
249      __func__, __LINE__, bd->win);
250
251    floating_wins = eina_list_remove(floating_wins, ft_bd);
252    eina_hash_del(floating_wins_hash, e_util_winid_str_get(bd->client.win), ft_bd);
253    eina_hash_del(floating_wins_hash, e_util_winid_str_get(bd->bg_win), ft_bd);
254    eina_hash_del(floating_wins_hash, e_util_winid_str_get(bd->win), ft_bd);
255
256    memset(ft_bd, 0, sizeof(E_Illume_Floating_Border));
257    E_FREE(ft_bd);
258
259    _e_mod_hints_floating_list_set();
260 }
261
262 static void
263 _e_mod_hints_floating_list_set(void)
264 {
265    Eina_List *ml = NULL, *cl = NULL;
266    E_Manager *m;
267    E_Container *c;
268    E_Border_List *bl;
269    E_Border *b;
270    E_Illume_Floating_Border *ft_bd = NULL;
271    Ecore_X_Window *clients = NULL;
272    int num = 0, i = 0;
273
274    num = floating_wins ? floating_wins->accounting->count : 0;
275
276    L(LT_FLOATING, "%s(%d) Floating window list has being updated\n",
277      __func__, __LINE__);
278
279    if (num > 0)
280      {
281         clients = calloc(num, sizeof(Ecore_X_Window));
282         EINA_SAFETY_ON_NULL_RETURN(clients);
283
284         EINA_LIST_FOREACH(e_manager_list(), ml, m)
285           {
286              EINA_LIST_FOREACH(m->containers, cl, c)
287                {
288                   bl = e_container_border_list_first(c);
289                   while ((b = e_container_border_list_next(bl)))
290                     {
291                        ft_bd = _e_mod_floating_get_floating_border(b->client.win);
292                        if (!ft_bd) continue;
293
294                        clients[i++] = b->client.win;
295                     }
296                   e_container_border_list_free(bl);
297                }
298              if (i > 0)
299                ecore_x_window_prop_window_set(m->root,
300                                               E_ILLUME_ATOM_FLOATING_WINDOW_LIST,
301                                               clients, i);
302              else
303                ecore_x_window_prop_window_set(m->root,
304                                               E_ILLUME_ATOM_FLOATING_WINDOW_LIST,
305                                               NULL, 0);
306           }
307         E_FREE(clients);
308      }
309    else
310      {
311         EINA_LIST_FOREACH(e_manager_list(), ml, m)
312           {
313              L(LT_FLOATING, "%s(%d) There is no floating window\n",
314                __func__, __LINE__);
315              ecore_x_window_prop_window_set(m->root,
316                                             E_ILLUME_ATOM_FLOATING_WINDOW_LIST,
317                                             NULL, 0);
318           }
319      }
320 }
321
322 static Eina_Bool
323 _e_mod_floating_cb_border_add(void *data __UNUSED__,
324                             int type __UNUSED__,
325                             void *event)
326 {
327    E_Event_Border_Add *ev = event;
328    E_Border *bd = NULL;
329
330    bd = ev->border;
331    EINA_SAFETY_ON_NULL_GOTO(bd, end);
332    if (!e_mod_floating_border_is_floating(bd)) goto end;
333
334    _e_mod_floating_border_list_add(bd);
335
336 end:
337    return ECORE_CALLBACK_PASS_ON;
338 }
339
340 static Eina_Bool
341 _e_mod_floating_cb_border_del(void *data __UNUSED__,
342                             int type __UNUSED__,
343                             void *event)
344 {
345    E_Event_Border_Remove *ev = event;
346    E_Border *bd = NULL;
347
348    bd = ev->border;
349    EINA_SAFETY_ON_NULL_GOTO(bd, end);
350
351    _e_mod_floating_border_list_del(bd);
352
353 end:
354    return ECORE_CALLBACK_PASS_ON;
355 }
356
357 static Eina_Bool
358 _e_mod_floating_cb_client_message(void   *data __UNUSED__,
359                                    int    type __UNUSED__,
360                                    void   *event)
361 {
362    Ecore_X_Event_Client_Message *ev = event;
363    Eina_Bool iconify = EINA_FALSE;
364
365    if (ev->message_type == E_ILLUME_ATOM_FLOATING_WINDOW_CLOSE_ALL)
366      {
367         L(LT_FLOATING,
368           "%s(%d) Received message, E_ILLUME_ATOM_FLOATING_WINDOW_CLOSE_ALL\n",
369           __func__, __LINE__);
370
371         _e_mod_floating_close_all();
372      }
373    else if (ev->message_type == E_ILLUME_ATOM_FLOATING_WINDOW_CHANGE_VISIBLE)
374      {
375         L(LT_FLOATING,
376           "%s(%d) Received message, E_ILLUME_ATOM_FLOATING_WINDOW_CHANGE_VISIBLE\n",
377           __func__, __LINE__);
378
379         iconify = ev->data.b[0];
380         _e_mod_floating_iconify_all(iconify);
381      }
382    else if (ev->message_type == E_ILLUME_ATOM_FLOATING_WINDOW_ALIGN)
383      {
384         L(LT_FLOATING,
385           "%s(%d) Received message, E_ILLUME_ATOM_FLOATING_WINDOW_ALIGN\n",
386           __func__, __LINE__);
387
388         _e_mod_floating_smart_cleanup(ev);
389      }
390
391    return ECORE_CALLBACK_PASS_ON;
392 }
393
394 static Eina_Bool
395 _e_mod_floating_cb_window_property(void *data __UNUSED__,
396                                     int type __UNUSED__,
397                                     void *event)
398 {
399    Ecore_X_Event_Window_Property *ev = event;
400
401    if (ev->atom == ECORE_X_ATOM_E_ILLUME_WINDOW_STATE)
402      {
403         _e_mod_floating_window_state_change(ev);
404      }
405
406    return ECORE_CALLBACK_PASS_ON;
407 }
408
409 static Eina_Bool
410 _e_mod_floating_cb_idle_enterer(void *data __UNUSED__)
411 {
412    E_Illume_Floating_Border *ft_bd = NULL;
413    E_Border *bd = NULL;
414    Eina_List *l;
415
416    if (!floating_wins) return ECORE_CALLBACK_RENEW;
417
418    EINA_LIST_FOREACH(floating_wins, l, ft_bd)
419      {
420         if (!ft_bd) continue;
421         if (!ft_bd->changed) continue;
422         ft_bd->changed = 0;
423
424         bd = ft_bd->bd;
425         if (!bd) continue;
426
427          L(LT_FLOATING, "%s(%d) idle state, win: 0x%08x\n",
428            __func__, __LINE__, bd->client.win);
429
430         if (ft_bd->defer.close)
431           {
432              e_border_act_close_begin(ft_bd->bd);
433              ft_bd->defer.close = 0;
434           }
435      }
436
437    return ECORE_CALLBACK_RENEW;
438 }
439
440 static void
441 _e_mod_floating_close_all(void)
442 {
443    E_Illume_Floating_Border *ft_bd = NULL;
444    Eina_List *l;
445
446    EINA_LIST_FOREACH(floating_wins, l, ft_bd)
447      {
448         _e_mod_floating_iconify(ft_bd, 1);
449
450         ft_bd->defer.close = 1;
451         ft_bd->changed = 1;
452      }
453 }
454
455 static void
456 _e_mod_floating_iconify(E_Illume_Floating_Border *ft_bd,
457                         Eina_Bool iconify)
458 {
459    E_Border *bd = NULL;
460
461    EINA_SAFETY_ON_NULL_RETURN(ft_bd);
462    bd = ft_bd->bd;
463    EINA_SAFETY_ON_NULL_RETURN(bd);
464
465    if (iconify)
466      {
467         if (!bd->iconic)
468           e_border_iconify(bd);
469      }
470    else
471      {
472         if (bd->iconic)
473           e_border_uniconify(bd);
474      }
475 }
476
477 static void
478 _e_mod_floating_iconify_all(Eina_Bool iconify)
479 {
480    Eina_List *l;
481    E_Illume_Floating_Border *ft_bd = NULL;
482
483    EINA_LIST_FOREACH(floating_wins, l, ft_bd)
484      {
485         _e_mod_floating_iconify(ft_bd, iconify);
486      }
487 }
488
489 static void
490 _e_mod_floating_smart_cleanup(Ecore_X_Event_Client_Message *event __UNUSED__)
491 {
492    Eina_List *borders = NULL, *l;
493    E_Illume_Floating_Border *ft_bd = NULL;
494    E_Border *border = NULL;
495
496    EINA_LIST_FOREACH(floating_wins, l, ft_bd)
497      {
498         border = ft_bd->bd;
499         if (!border) continue;
500         if (e_object_is_del(E_OBJECT(border))) continue;
501         /* Build a list of windows not iconified. */
502         if ((!border->iconic) && (!border->lock_user_location))
503           {
504              int area;
505              Eina_List *ll;
506              E_Border *bd;
507
508              /* Ordering windows largest to smallest gives better results */
509              area = border->w * border->h;
510              EINA_LIST_FOREACH(borders, ll, bd)
511                {
512                   int testarea;
513
514                   testarea = bd->w * bd->h;
515                   /* Insert the border if larger than the current border */
516                   if (area >= testarea)
517                     {
518                        borders = eina_list_prepend_relative(borders, border, bd);
519                        break;
520                     }
521                }
522              /* Looped over all borders without placing, so place at end */
523              if (!ll) borders = eina_list_append(borders, border);
524           }
525      }
526
527    /* Loop over the borders moving each one using the smart placement */
528    EINA_LIST_FREE(borders, border)
529      {
530         int new_x, new_y;
531         if (e_object_is_del(E_OBJECT(border))) continue;
532         e_place_zone_region_smart(border->zone, borders, border->x, border->y,
533                                   border->w, border->h, &new_x, &new_y);
534         e_border_move(border, new_x, new_y);
535      }
536
537    return;
538 }