Tizen 2.1 release
[platform/core/uifw/e17.git] / src / bin / e_container.c
1 #include "e.h"
2
3 /* TODO List:
4  *
5  * * fix shape callbacks to be able to be safely deleted
6  * * remove duplicate bd->layer -> layers code
7  *
8  */
9
10 /* local subsystem functions */
11 static void         _e_container_free(E_Container *con);
12
13 static E_Container *_e_container_find_by_event_window(Ecore_X_Window win);
14
15 static Eina_Bool    _e_container_cb_mouse_in(void *data, int type, void *event);
16 static Eina_Bool    _e_container_cb_mouse_out(void *data, int type, void *event);
17 static Eina_Bool    _e_container_cb_mouse_down(void *data, int type, void *event);
18 static Eina_Bool    _e_container_cb_mouse_up(void *data, int type, void *event);
19 static Eina_Bool    _e_container_cb_mouse_move(void *data, int type, void *event);
20 static Eina_Bool    _e_container_cb_mouse_wheel(void *data, int type, void *event);
21
22 static void         _e_container_shape_del(E_Container_Shape *es);
23 static void         _e_container_shape_free(E_Container_Shape *es);
24 static void         _e_container_shape_change_call(E_Container_Shape *es, E_Container_Shape_Change ch);
25 static void         _e_container_resize_handle(E_Container *con);
26 static void         _e_container_event_container_resize_free(void *data, void *ev);
27
28 EAPI int E_EVENT_CONTAINER_RESIZE = 0;
29 static Eina_List *handlers = NULL;
30
31 /* externally accessible functions */
32 EINTERN int
33 e_container_init(void)
34 {
35    E_EVENT_CONTAINER_RESIZE = ecore_event_type_new();
36
37    handlers = eina_list_append(handlers, ecore_event_handler_add(ECORE_X_EVENT_MOUSE_IN, _e_container_cb_mouse_in, NULL));
38    handlers = eina_list_append(handlers, ecore_event_handler_add(ECORE_X_EVENT_MOUSE_OUT, _e_container_cb_mouse_out, NULL));
39    handlers = eina_list_append(handlers, ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, _e_container_cb_mouse_down, NULL));
40    handlers = eina_list_append(handlers, ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, _e_container_cb_mouse_up, NULL));
41    handlers = eina_list_append(handlers, ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE, _e_container_cb_mouse_move, NULL));
42    handlers = eina_list_append(handlers, ecore_event_handler_add(ECORE_EVENT_MOUSE_WHEEL, _e_container_cb_mouse_wheel, NULL));
43    return 1;
44 }
45
46 EINTERN int
47 e_container_shutdown(void)
48 {
49    E_FREE_LIST(handlers, ecore_event_handler_del);
50    return 1;
51 }
52
53 EAPI E_Container *
54 e_container_new(E_Manager *man)
55 {
56    E_Container *con;
57    Evas_Object *o;
58    char name[40];
59    Eina_List *l, *screens;
60    int i;
61    Ecore_X_Window mwin;
62    static int container_num = 0;
63
64    con = E_OBJECT_ALLOC(E_Container, E_CONTAINER_TYPE, _e_container_free);
65    if (!con) return NULL;
66    con->manager = man;
67    con->manager->containers = eina_list_append(con->manager->containers, con);
68    con->w = con->manager->w;
69    con->h = con->manager->h;
70    con->win = con->manager->win;
71
72    if (!e_config->null_container_win)
73      con->bg_ecore_evas = e_canvas_new(con->win,
74                                        0, 0, con->w, con->h, 1, 1,
75                                        &(con->bg_win));
76    else
77      con->bg_ecore_evas = e_canvas_new(con->win,
78                                        0, 0, 1, 1, 1, 1,
79                                        &(con->bg_win));
80    e_canvas_add(con->bg_ecore_evas);
81    con->event_win = ecore_x_window_input_new(con->win, 0, 0, con->w, con->h);
82    ecore_x_window_show(con->event_win);
83    con->bg_evas = ecore_evas_get(con->bg_ecore_evas);
84    ecore_evas_name_class_set(con->bg_ecore_evas, "E", "Background_Window");
85    ecore_evas_title_set(con->bg_ecore_evas, "Enlightenment Background");
86    if (!getenv("EVAS_RENDER_MODE"))
87      {
88         int have_comp = 0;
89         Eina_List *ll;
90         E_Config_Module *em;
91
92         // FIXME: major hack. checking in advance for comp. eventully comp
93         // will be rolled into e17 core and this won't be needed
94         EINA_LIST_FOREACH(e_config->modules, ll, em)
95           {
96 #if _F_ADD_EXTRA_COMPOSITE_NAME
97              if (!strcmp(em->name, "comp-tizen") ||
98                  !strcmp(em->name, "comp"))
99                {
100                   have_comp = 1;
101                   break;
102                }
103 #else
104              if (!strcmp(em->name, "comp"))
105                {
106                   have_comp = 1;
107                   break;
108                }
109 #endif
110           }
111         if (!have_comp)
112           {
113              if (getenv("REDRAW_DEBUG"))
114                ecore_evas_avoid_damage_set(con->bg_ecore_evas, !atoi(getenv("REDRAW_DEBUG")));
115              else
116                ecore_evas_avoid_damage_set(con->bg_ecore_evas, ECORE_EVAS_AVOID_DAMAGE_BUILT_IN);
117           }
118      }
119    ecore_x_window_lower(con->bg_win);
120
121    o = evas_object_rectangle_add(con->bg_evas);
122    con->bg_blank_object = o;
123    evas_object_layer_set(o, -100);
124    evas_object_move(o, 0, 0);
125    evas_object_resize(o, con->w, con->h);
126    evas_object_color_set(o, 255, 255, 255, 255);
127    evas_object_name_set(o, "e/desktop/background");
128    evas_object_data_set(o, "e_container", con);
129    evas_object_show(o);
130
131    con->num = container_num;
132    container_num++;
133    snprintf(name, sizeof(name), _("Container %d"), con->num);
134    con->name = eina_stringshare_add(name);
135
136    /* create a scratch window for putting stuff into */
137    con->scratch_win = ecore_x_window_override_new(con->win, 0, 0, 7, 7);
138
139    /* init layers */
140    for (i = 0; i < 11; i++)
141      {
142         con->layers[i].win = ecore_x_window_input_new(con->win, 0, 0, 1, 1);
143         ecore_x_window_lower(con->layers[i].win);
144
145         if (i > 0)
146           ecore_x_window_configure(con->layers[i].win,
147                                    ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
148                                    ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
149                                    0, 0, 0, 0, 0,
150                                    con->layers[i - 1].win, ECORE_X_WINDOW_STACK_ABOVE);
151      }
152
153    /* Put init win on top */
154    if (man->initwin)
155      ecore_x_window_configure(man->initwin,
156                               ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
157                               ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
158                               0, 0, 0, 0, 0,
159                               con->layers[10].win, ECORE_X_WINDOW_STACK_ABOVE);
160
161    /* Put menu win on top */
162    mwin = e_menu_grab_window_get();
163    if (mwin)
164      ecore_x_window_configure(mwin,
165                               ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
166                               ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
167                               0, 0, 0, 0, 0,
168                               con->layers[10].win, ECORE_X_WINDOW_STACK_ABOVE);
169
170    /* Put background win at the bottom */
171    ecore_x_window_configure(con->bg_win,
172                             ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
173                             ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
174                             0, 0, 0, 0, 0,
175                             con->layers[0].win, ECORE_X_WINDOW_STACK_BELOW);
176
177    screens = (Eina_List *)e_xinerama_screens_get();
178    if (screens)
179      {
180         E_Screen *scr;
181         EINA_LIST_FOREACH(screens, l, scr)
182           {
183              e_zone_new(con, scr->screen, scr->escreen, scr->x, scr->y, scr->w, scr->h);
184           }
185      }
186    else
187      e_zone_new(con, 0, 0, 0, 0, con->w, con->h);
188    return con;
189 }
190
191 EAPI void
192 e_container_show(E_Container *con)
193 {
194    E_OBJECT_CHECK(con);
195    E_OBJECT_TYPE_CHECK(con, E_CONTAINER_TYPE);
196
197    if (con->visible) return;
198    if (!e_config->null_container_win)
199      ecore_evas_show(con->bg_ecore_evas);
200    ecore_x_window_configure(con->bg_win,
201                             ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
202                             ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
203                             0, 0, 0, 0, 0,
204                             con->layers[0].win, ECORE_X_WINDOW_STACK_BELOW);
205    ecore_x_window_configure(con->event_win,
206                             ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
207                             ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
208                             0, 0, 0, 0, 0,
209                             con->layers[0].win, ECORE_X_WINDOW_STACK_BELOW);
210    if (con->win != con->manager->win)
211      ecore_x_window_show(con->win);
212    ecore_x_icccm_state_set(con->bg_win, ECORE_X_WINDOW_STATE_HINT_NORMAL);
213    con->visible = 1;
214 }
215
216 EAPI void
217 e_container_hide(E_Container *con)
218 {
219    E_OBJECT_CHECK(con);
220    E_OBJECT_TYPE_CHECK(con, E_CONTAINER_TYPE);
221
222    if (!con->visible) return;
223    ecore_evas_hide(con->bg_ecore_evas);
224    if (con->win != con->manager->win)
225      ecore_x_window_hide(con->win);
226    con->visible = 0;
227 }
228
229 EAPI E_Container *
230 e_container_current_get(E_Manager *man)
231 {
232    Eina_List *l;
233    E_Container *con;
234    E_OBJECT_CHECK_RETURN(man, NULL);
235    E_OBJECT_TYPE_CHECK_RETURN(man, E_MANAGER_TYPE, NULL);
236
237    EINA_LIST_FOREACH(man->containers, l, con)
238      {
239         if (!con) continue;
240         if (con->visible) return con;
241      }
242
243    /* If no one is available, return the first */
244    if (!man->containers) return NULL;
245    l = man->containers;
246    return (E_Container *)eina_list_data_get(l);
247 }
248
249 EAPI E_Container *
250 e_container_number_get(E_Manager *man, int num)
251 {
252    Eina_List *l;
253    E_Container *con;
254
255    E_OBJECT_CHECK_RETURN(man, NULL);
256    E_OBJECT_TYPE_CHECK_RETURN(man, E_MANAGER_TYPE, NULL);
257    EINA_LIST_FOREACH(man->containers, l, con)
258      {
259         if ((int)con->num == num) return con;
260      }
261    return NULL;
262 }
263
264 EAPI void
265 e_container_move(E_Container *con, int x, int y)
266 {
267    E_OBJECT_CHECK(con);
268    E_OBJECT_TYPE_CHECK(con, E_CONTAINER_TYPE);
269    if ((x == con->x) && (y == con->y)) return;
270    con->x = x;
271    con->y = y;
272    if (con->win != con->manager->win)
273      ecore_x_window_move(con->win, con->x, con->y);
274    evas_object_move(con->bg_blank_object, con->x, con->y);
275 }
276
277 EAPI void
278 e_container_resize(E_Container *con, int w, int h)
279 {
280    E_OBJECT_CHECK(con);
281    E_OBJECT_TYPE_CHECK(con, E_CONTAINER_TYPE);
282    con->w = w;
283    con->h = h;
284    if (con->win != con->manager->win)
285      ecore_x_window_resize(con->win, con->w, con->h);
286    ecore_x_window_resize(con->event_win, con->w, con->h);
287    if (!e_config->null_container_win)
288      ecore_evas_resize(con->bg_ecore_evas, con->w, con->h);
289    evas_object_resize(con->bg_blank_object, con->w, con->h);
290    _e_container_resize_handle(con);
291 }
292
293 EAPI void
294 e_container_move_resize(E_Container *con, int x, int y, int w, int h)
295 {
296    E_OBJECT_CHECK(con);
297    E_OBJECT_TYPE_CHECK(con, E_CONTAINER_TYPE);
298    con->x = x;
299    con->y = y;
300    con->w = w;
301    con->h = h;
302    if (con->win != con->manager->win)
303      ecore_x_window_move_resize(con->win, con->x, con->y, con->w, con->h);
304    ecore_x_window_move_resize(con->event_win, con->x, con->y, con->w, con->h);
305    if (!e_config->null_container_win)
306      ecore_evas_resize(con->bg_ecore_evas, con->w, con->h);
307    evas_object_move(con->bg_blank_object, con->x, con->y);
308    evas_object_resize(con->bg_blank_object, con->w, con->h);
309    _e_container_resize_handle(con);
310 }
311
312 EAPI void
313 e_container_raise(E_Container *con __UNUSED__)
314 {
315 //   E_OBJECT_CHECK(con);
316 //   E_OBJECT_TYPE_CHECK(con, E_CONTAINER_TYPE);
317 }
318
319 EAPI void
320 e_container_lower(E_Container *con __UNUSED__)
321 {
322 //   E_OBJECT_CHECK(con);
323 //   E_OBJECT_TYPE_CHECK(con, E_CONTAINER_TYPE);
324 }
325
326 EAPI E_Zone *
327 e_container_zone_at_point_get(E_Container *con, int x, int y)
328 {
329    Eina_List *l = NULL;
330    E_Zone *zone = NULL;
331
332    E_OBJECT_CHECK_RETURN(con, NULL);
333    E_OBJECT_TYPE_CHECK_RETURN(con, E_CONTAINER_TYPE, NULL);
334    EINA_LIST_FOREACH(con->zones, l, zone)
335      {
336         if (E_INSIDE(x, y, zone->x, zone->y, zone->w, zone->h))
337           return zone;
338      }
339    return NULL;
340 }
341
342 EAPI E_Zone *
343 e_container_zone_number_get(E_Container *con, int num)
344 {
345    Eina_List *l = NULL;
346    E_Zone *zone = NULL;
347
348    E_OBJECT_CHECK_RETURN(con, NULL);
349    E_OBJECT_TYPE_CHECK_RETURN(con, E_CONTAINER_TYPE, NULL);
350    EINA_LIST_FOREACH(con->zones, l, zone)
351      {
352         if ((int)zone->num == num) return zone;
353      }
354    return NULL;
355 }
356
357 EAPI E_Zone *
358 e_container_zone_id_get(E_Container *con, int id)
359 {
360    Eina_List *l = NULL;
361    E_Zone *zone = NULL;
362
363    E_OBJECT_CHECK_RETURN(con, NULL);
364    E_OBJECT_TYPE_CHECK_RETURN(con, E_CONTAINER_TYPE, NULL);
365    EINA_LIST_FOREACH(con->zones, l, zone)
366      {
367         if (zone->id == id) return zone;
368      }
369    return NULL;
370 }
371
372 #ifdef _F_USE_DESK_WINDOW_PROFILE_
373 EAPI E_Desk *
374 e_container_desk_window_profile_get(E_Container *con,
375                                     const char  *profile)
376 {
377    Eina_List *l = NULL;
378    E_Zone *zone = NULL;
379    int x, y;
380
381    E_OBJECT_CHECK_RETURN(con, NULL);
382    E_OBJECT_TYPE_CHECK_RETURN(con, E_CONTAINER_TYPE, NULL);
383
384    EINA_LIST_FOREACH(con->zones, l, zone)
385      {
386         for (x = 0; x < zone->desk_x_count; x++)
387           {
388              for (y = 0; y < zone->desk_y_count; y++)
389                {
390                   E_Desk *desk = e_desk_at_xy_get(zone, x, y);
391                   if ((desk->window_profile) &&
392                       strcmp(desk->window_profile, profile) == 0)
393                     {
394                        return desk;
395                     }
396                }
397           }
398      }
399
400    return NULL;
401 }
402 #endif
403
404 EAPI E_Container_Shape *
405 e_container_shape_add(E_Container *con)
406 {
407    E_Container_Shape *es;
408
409    E_OBJECT_CHECK_RETURN(con, NULL);
410    E_OBJECT_TYPE_CHECK_RETURN(con, E_CONTAINER_TYPE, 0);
411
412    es = E_OBJECT_ALLOC(E_Container_Shape, E_CONTAINER_SHAPE_TYPE, _e_container_shape_free);
413    E_OBJECT_DEL_SET(es, _e_container_shape_del);
414    es->con = con;
415    con->shapes = eina_list_append(con->shapes, es);
416    _e_container_shape_change_call(es, E_CONTAINER_SHAPE_ADD);
417    return es;
418 }
419
420 EAPI void
421 e_container_shape_show(E_Container_Shape *es)
422 {
423    E_OBJECT_CHECK(es);
424    E_OBJECT_TYPE_CHECK(es, E_CONTAINER_SHAPE_TYPE);
425    if (es->visible) return;
426    es->visible = 1;
427    _e_container_shape_change_call(es, E_CONTAINER_SHAPE_SHOW);
428 }
429
430 EAPI void
431 e_container_shape_hide(E_Container_Shape *es)
432 {
433    E_OBJECT_CHECK(es);
434    E_OBJECT_TYPE_CHECK(es, E_CONTAINER_SHAPE_TYPE);
435    if (!es->visible) return;
436    es->visible = 0;
437    _e_container_shape_change_call(es, E_CONTAINER_SHAPE_HIDE);
438 }
439
440 EAPI void
441 e_container_shape_move(E_Container_Shape *es, int x, int y)
442 {
443    E_OBJECT_CHECK(es);
444    E_OBJECT_TYPE_CHECK(es, E_CONTAINER_SHAPE_TYPE);
445    if ((es->x == x) && (es->y == y)) return;
446    es->x = x;
447    es->y = y;
448    _e_container_shape_change_call(es, E_CONTAINER_SHAPE_MOVE);
449 }
450
451 EAPI void
452 e_container_shape_resize(E_Container_Shape *es, int w, int h)
453 {
454    E_OBJECT_CHECK(es);
455    E_OBJECT_TYPE_CHECK(es, E_CONTAINER_SHAPE_TYPE);
456    if (w < 1) w = 1;
457    if (h < 1) h = 1;
458    if ((es->w == w) && (es->h == h)) return;
459    es->w = w;
460    es->h = h;
461    _e_container_shape_change_call(es, E_CONTAINER_SHAPE_RESIZE);
462 }
463
464 EAPI Eina_List *
465 e_container_shape_list_get(E_Container *con)
466 {
467    E_OBJECT_CHECK_RETURN(con, NULL);
468    E_OBJECT_TYPE_CHECK_RETURN(con, E_CONTAINER_TYPE, NULL);
469    return con->shapes;
470 }
471
472 EAPI void
473 e_container_shape_geometry_get(E_Container_Shape *es, int *x, int *y, int *w, int *h)
474 {
475    E_OBJECT_CHECK(es);
476    E_OBJECT_TYPE_CHECK(es, E_CONTAINER_SHAPE_TYPE);
477    if (x) *x = es->x;
478    if (y) *y = es->y;
479    if (w) *w = es->w;
480    if (h) *h = es->h;
481 }
482
483 EAPI E_Container *
484 e_container_shape_container_get(E_Container_Shape *es)
485 {
486    E_OBJECT_CHECK_RETURN(es, NULL);
487    E_OBJECT_TYPE_CHECK_RETURN(es, E_CONTAINER_SHAPE_TYPE, NULL);
488    return es->con;
489 }
490
491 EAPI void
492 e_container_shape_change_callback_add(E_Container *con, void (*func)(void *data, E_Container_Shape *es, E_Container_Shape_Change ch), void *data)
493 {
494    E_Container_Shape_Callback *cb;
495
496    E_OBJECT_CHECK(con);
497    E_OBJECT_TYPE_CHECK(con, E_CONTAINER_TYPE);
498    cb = calloc(1, sizeof(E_Container_Shape_Callback));
499    if (!cb) return;
500    cb->func = func;
501    cb->data = data;
502    con->shape_change_cb = eina_list_append(con->shape_change_cb, cb);
503 }
504
505 EAPI void
506 e_container_shape_change_callback_del(E_Container *con, void (*func)(void *data, E_Container_Shape *es, E_Container_Shape_Change ch), void *data)
507 {
508    Eina_List *l = NULL;
509    E_Container_Shape_Callback *cb = NULL;
510
511    /* FIXME: if we call this from within a callback we are in trouble */
512    E_OBJECT_CHECK(con);
513    E_OBJECT_TYPE_CHECK(con, E_CONTAINER_TYPE);
514    EINA_LIST_FOREACH(con->shape_change_cb, l, cb)
515      {
516         if ((cb->func == func) && (cb->data == data))
517           {
518              con->shape_change_cb = eina_list_remove_list(con->shape_change_cb, l);
519              free(cb);
520              return;
521           }
522      }
523 }
524
525 EAPI Eina_List *
526 e_container_shape_rects_get(E_Container_Shape *es)
527 {
528    E_OBJECT_CHECK_RETURN(es, NULL);
529    E_OBJECT_TYPE_CHECK_RETURN(es, E_CONTAINER_SHAPE_TYPE, NULL);
530    return es->shape;
531 }
532
533 EAPI void
534 e_container_shape_rects_set(E_Container_Shape *es, Ecore_X_Rectangle *rects, int num)
535 {
536    int i;
537    E_Rect *r;
538
539    E_OBJECT_CHECK(es);
540    E_OBJECT_TYPE_CHECK(es, E_CONTAINER_SHAPE_TYPE);
541    if (es->shape)
542      {
543         E_FREE_LIST(es->shape, free);
544         es->shape = NULL;
545      }
546    if ((rects) && (num == 1) &&
547        (rects[0].x == 0) &&
548        (rects[0].y == 0) &&
549        ((int)rects[0].width == es->w) &&
550        ((int)rects[0].height == es->h))
551      {
552         /* do nothing */
553      }
554    else if (rects)
555      {
556         for (i = 0; i < num; i++)
557           {
558              r = malloc(sizeof(E_Rect));
559              if (r)
560                {
561                   r->x = rects[i].x;
562                   r->y = rects[i].y;
563                   r->w = rects[i].width;
564                   r->h = rects[i].height;
565                   es->shape = eina_list_append(es->shape, r);
566                }
567           }
568      }
569    _e_container_shape_change_call(es, E_CONTAINER_SHAPE_RECTS);
570 }
571
572 EAPI void
573 e_container_shape_solid_rect_set(E_Container_Shape *es, int x, int y, int w, int h)
574 {
575    es->solid_rect.x = x;
576    es->solid_rect.y = y;
577    es->solid_rect.w = w;
578    es->solid_rect.h = h;
579 }
580
581 EAPI void
582 e_container_shape_solid_rect_get(E_Container_Shape *es, int *x, int *y, int *w, int *h)
583 {
584    if (x) *x = es->solid_rect.x;
585    if (y) *y = es->solid_rect.y;
586    if (w) *w = es->solid_rect.w;
587    if (h) *h = es->solid_rect.h;
588 }
589
590 /* layers
591  * 0 = desktop
592  * 50 = below
593  * 100 = normal
594  * 150 = above
595  * 200 = fullscreen
596  * 250 = fullscreen
597  * 300 = fullscreen
598  * 350 = stuff over fullscreen
599  * 400 = stuff over stuff
600  * 450 = yet more stuff on top
601  */
602 EAPI int
603 e_container_borders_count(E_Container *con)
604 {
605    return con->clients;
606 }
607
608 static int
609 _e_container_layer_map(int layer)
610 {
611    int pos = 0;
612
613    if (layer < 0) layer = 0;
614    pos = 1 + (layer / 50);
615    if (pos > 10) pos = 10;
616    return pos;
617 }
618
619 EAPI void
620 e_container_border_add(E_Border *bd)
621 {
622    int pos = _e_container_layer_map(bd->layer);
623    bd->zone->container->clients++;
624    bd->zone->container->layers[pos].clients =
625      eina_list_append(bd->zone->container->layers[pos].clients, bd);
626    e_hints_client_list_set();
627 }
628
629 EAPI void
630 e_container_border_remove(E_Border *bd)
631 {
632    int i;
633
634    if (!bd->zone) return;
635    /* FIXME: Could revert to old behaviour, ->layer is consistent
636     * with pos now. */
637    for (i = 0; i < 11; i++)
638      {
639         bd->zone->container->layers[i].clients =
640           eina_list_remove(bd->zone->container->layers[i].clients, bd);
641      }
642    bd->zone->container->clients--;
643    bd->zone = NULL;
644    e_hints_client_list_set();
645 }
646
647 EAPI void
648 e_container_window_raise(E_Container *con, Ecore_X_Window win, int layer)
649 {
650    int pos = _e_container_layer_map(layer);
651    ecore_x_window_configure(win,
652                             ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
653                             ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
654                             0, 0, 0, 0, 0,
655                             con->layers[pos + 1].win, ECORE_X_WINDOW_STACK_BELOW);
656 }
657
658 EAPI void
659 e_container_window_lower(E_Container *con, Ecore_X_Window win, int layer)
660 {
661    int pos = _e_container_layer_map(layer);
662    ecore_x_window_configure(win,
663                             ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
664                             ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
665                             0, 0, 0, 0, 0,
666                             con->layers[pos].win, ECORE_X_WINDOW_STACK_ABOVE);
667 }
668
669 EAPI E_Border *
670 e_container_border_raise(E_Border *bd)
671 {
672    E_Border *above = NULL;
673    Eina_List *l;
674    int pos = 0, i;
675
676    if (!bd->zone) return NULL;
677    /* Remove from old layer */
678    for (i = 0; i < 11; i++)
679      {
680         bd->zone->container->layers[i].clients =
681           eina_list_remove(bd->zone->container->layers[i].clients, bd);
682      }
683
684    /* Add to new layer */
685    pos = _e_container_layer_map(bd->layer);
686
687    ecore_x_window_configure(bd->win,
688                             ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
689                             ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
690                             0, 0, 0, 0, 0,
691                             bd->zone->container->layers[pos + 1].win, ECORE_X_WINDOW_STACK_BELOW);
692
693    bd->zone->container->layers[pos].clients =
694      eina_list_append(bd->zone->container->layers[pos].clients, bd);
695
696    /* Find the window below this one */
697    l = eina_list_data_find_list(bd->zone->container->layers[pos].clients, bd);
698    if (eina_list_prev(l))
699      above = eina_list_data_get(eina_list_prev(l));
700    else
701      {
702         /* Need to check the layers below */
703         for (i = pos - 1; i >= 0; i--)
704           {
705              if ((bd->zone->container->layers[i].clients) &&
706                  (l = eina_list_last(bd->zone->container->layers[i].clients)))
707                {
708                   above = eina_list_data_get(l);
709                   break;
710                }
711           }
712      }
713
714    e_hints_client_stacking_set();
715    return above;
716 }
717
718 EAPI E_Border *
719 e_container_border_lower(E_Border *bd)
720 {
721    E_Border *below = NULL;
722    Eina_List *l;
723    int pos = 0, i;
724
725    if (!bd->zone) return NULL;
726    /* Remove from old layer */
727    for (i = 0; i < 11; i++)
728      {
729         bd->zone->container->layers[i].clients =
730           eina_list_remove(bd->zone->container->layers[i].clients, bd);
731      }
732
733    /* Add to new layer */
734    pos = _e_container_layer_map(bd->layer);
735
736    ecore_x_window_configure(bd->win,
737                             ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
738                             ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
739                             0, 0, 0, 0, 0,
740                             bd->zone->container->layers[pos].win, ECORE_X_WINDOW_STACK_ABOVE);
741
742    bd->zone->container->layers[pos].clients =
743      eina_list_prepend(bd->zone->container->layers[pos].clients, bd);
744
745    /* Find the window above this one */
746    l = eina_list_data_find_list(bd->zone->container->layers[pos].clients, bd);
747    if (eina_list_next(l))
748      below = eina_list_data_get(eina_list_next(l));
749    else
750      {
751         /* Need to check the layers above */
752         for (i = pos + 1; i < 11; i++)
753           {
754              if (bd->zone->container->layers[i].clients)
755                {
756                   below = eina_list_data_get(bd->zone->container->layers[i].clients);
757                   break;
758                }
759           }
760      }
761
762    e_hints_client_stacking_set();
763    return below;
764 }
765
766 EAPI void
767 e_container_border_stack_above(E_Border *bd, E_Border *above)
768 {
769    int pos = 0, i;
770
771    if (!bd->zone) return;
772    /* Remove from old layer */
773    for (i = 0; i < 11; i++)
774      {
775         bd->zone->container->layers[i].clients =
776           eina_list_remove(bd->zone->container->layers[i].clients, bd);
777      }
778
779    /* Add to new layer */
780    bd->layer = above->layer;
781    pos = _e_container_layer_map(bd->layer);
782    
783    ecore_x_window_configure(bd->win,
784                             ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
785                             ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
786                             0, 0, 0, 0, 0,
787                             above->win, ECORE_X_WINDOW_STACK_ABOVE);
788
789    bd->zone->container->layers[pos].clients =
790      eina_list_append_relative(bd->zone->container->layers[pos].clients, bd, above);
791 }
792
793 EAPI void
794 e_container_border_stack_below(E_Border *bd, E_Border *below)
795 {
796    int pos = 0, i;
797
798    if (!bd->zone) return;
799    /* Remove from old layer */
800    for (i = 0; i < 11; i++)
801      {
802         bd->zone->container->layers[i].clients =
803           eina_list_remove(bd->zone->container->layers[i].clients, bd);
804      }
805
806    /* Add to new layer */
807    bd->layer = below->layer;
808    pos = _e_container_layer_map(bd->layer);
809
810    ecore_x_window_configure(bd->win,
811                             ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
812                             ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
813                             0, 0, 0, 0, 0,
814                             below->win, ECORE_X_WINDOW_STACK_BELOW);
815
816    bd->zone->container->layers[pos].clients =
817      eina_list_prepend_relative(bd->zone->container->layers[pos].clients, bd, below);
818 }
819
820 static E_Border_List *
821 _e_container_border_list_new(E_Container *con)
822 {
823    E_Border_List *list = NULL;
824    E_Border *bd;
825    int i;
826    Eina_List *l;
827
828    if (!(list = E_NEW(E_Border_List, 1))) return NULL;
829    list->container = con;
830    e_object_ref(E_OBJECT(list->container));
831    eina_array_step_set(&(list->client_array), sizeof(list->client_array), 256);
832    for (i = 0; i < 11; i++)
833      {
834         EINA_LIST_FOREACH(con->layers[i].clients, l, bd)
835           eina_array_push(&(list->client_array), bd);
836      }
837    return list;
838 }
839
840 static E_Border *
841 _e_container_border_list_jump(E_Border_List *list, int dir)
842 {
843    E_Border *bd;
844
845    if ((list->pos < 0) ||
846        (list->pos >= (int)eina_array_count(&(list->client_array))))
847      return NULL;
848    bd = eina_array_data_get(&(list->client_array), list->pos);
849    list->pos += dir;
850    return bd;
851 }
852
853 EAPI E_Border_List *
854 e_container_border_list_first(E_Container *con)
855 {
856    E_Border_List *list = NULL;
857
858    list = _e_container_border_list_new(con);
859    list->pos = 0;
860    return list;
861 }
862
863 EAPI E_Border_List *
864 e_container_border_list_last(E_Container *con)
865 {
866    E_Border_List *list = NULL;
867
868    list = _e_container_border_list_new(con);
869    list->pos = eina_array_count(&(list->client_array)) - 1;
870    return list;
871 }
872
873 EAPI E_Border *
874 e_container_border_list_next(E_Border_List *list)
875 {
876    return _e_container_border_list_jump(list, 1);
877 }
878
879 EAPI E_Border *
880 e_container_border_list_prev(E_Border_List *list)
881 {
882    return _e_container_border_list_jump(list, -1);
883 }
884
885 EAPI void
886 e_container_border_list_free(E_Border_List *list)
887 {
888    e_object_unref(E_OBJECT(list->container));
889    eina_array_flush(&(list->client_array));
890    free(list);
891 }
892
893 EAPI void
894 e_container_all_freeze(void)
895 {
896    Eina_List *l, *ll;
897    E_Manager *man;
898    E_Container *con;
899
900    EINA_LIST_FOREACH(e_manager_list(), l, man)
901      {
902         EINA_LIST_FOREACH(man->containers, ll, con)
903           {
904              evas_event_freeze(con->bg_evas);
905           }
906      }
907 }
908
909 EAPI void
910 e_container_all_thaw(void)
911 {
912    Eina_List *l, *ll;
913    E_Manager *man;
914    E_Container *con;
915
916    EINA_LIST_FOREACH(e_manager_list(), l, man)
917      {
918         EINA_LIST_FOREACH(man->containers, ll, con)
919           {
920              evas_event_thaw(con->bg_evas);
921           }
922      }
923 }
924
925 /* local subsystem functions */
926 static void
927 _e_container_free(E_Container *con)
928 {
929    Eina_List *l;
930    int i;
931
932    ecore_x_window_free(con->scratch_win);
933    ecore_x_window_free(con->event_win);
934    /* We can't use e_object_del here, because border adds a ref to itself
935     * when it is removed, and the ref is never unref'ed */
936    for (i = 0; i < 11; i++)
937      {
938         ecore_x_window_free(con->layers[i].win);
939 /* FIXME: had to disable this as it was freeing already freed items during
940  * looping (particularly remember/lock config dialogs). this is just
941  * disabled until we put in some special handling for this
942  *
943         EINA_LiST_FOREACH(con->layers[i].clients, l, tmp)
944           {
945              e_object_free(E_OBJECT(tmp));
946           }
947  */
948      }
949    l = con->zones;
950    con->zones = NULL;
951    E_FREE_LIST(l, e_object_del);
952    con->manager->containers = eina_list_remove(con->manager->containers, con);
953    e_canvas_del(con->bg_ecore_evas);
954    ecore_evas_free(con->bg_ecore_evas);
955    if (con->manager->win != con->win)
956      {
957         ecore_x_window_free(con->win);
958      }
959    if (con->name) eina_stringshare_del(con->name);
960    free(con);
961 }
962
963 static E_Container *
964 _e_container_find_by_event_window(Ecore_X_Window win)
965 {
966    Eina_List *l, *ll;
967    E_Manager *man;
968    E_Container *con;
969
970    EINA_LIST_FOREACH(e_manager_list(), l, man)
971      {
972         EINA_LIST_FOREACH(man->containers, ll, con)
973           {
974              if (con->event_win == win) return con;
975           }
976      }
977    return NULL;
978 }
979
980 static Eina_Bool
981 _e_container_cb_mouse_in(void *data __UNUSED__, int type __UNUSED__, void *event)
982 {
983    Ecore_X_Event_Mouse_In *ev;
984    E_Border *bd;
985    E_Container *con;
986
987    ev = event;
988    con = _e_container_find_by_event_window(ev->event_win);
989    if (con)
990      {
991         bd = e_border_focused_get();
992         if (bd) e_focus_event_mouse_out(bd);
993         ecore_event_evas_modifier_lock_update(con->bg_evas, ev->modifiers);
994         evas_event_feed_mouse_in(con->bg_evas, ev->time, NULL);
995      }
996    return ECORE_CALLBACK_PASS_ON;
997 }
998
999 static Eina_Bool
1000 _e_container_cb_mouse_out(void *data __UNUSED__, int type __UNUSED__, void *event)
1001 {
1002    Ecore_X_Event_Mouse_Out *ev;
1003    E_Container *con;
1004
1005    ev = event;
1006    con = _e_container_find_by_event_window(ev->event_win);
1007    if (con)
1008      {
1009         ecore_event_evas_modifier_lock_update(con->bg_evas, ev->modifiers);
1010         if (ev->mode == ECORE_X_EVENT_MODE_GRAB)
1011           evas_event_feed_mouse_cancel(con->bg_evas, ev->time, NULL);
1012         evas_event_feed_mouse_out(con->bg_evas, ev->time, NULL);
1013      }
1014    return ECORE_CALLBACK_PASS_ON;
1015 }
1016
1017 static Eina_Bool
1018 _e_container_cb_mouse_down(void *data __UNUSED__, int type __UNUSED__, void *event)
1019 {
1020    Ecore_Event_Mouse_Button *ev;
1021    E_Container *con;
1022
1023    ev = event;
1024    con = _e_container_find_by_event_window(ev->event_window);
1025    if (con)
1026      {
1027         Evas_Button_Flags flags = EVAS_BUTTON_NONE;
1028
1029         e_bindings_mouse_down_event_handle(E_BINDING_CONTEXT_CONTAINER,
1030                                            E_OBJECT(con), ev);
1031         if (ev->double_click) flags |= EVAS_BUTTON_DOUBLE_CLICK;
1032         if (ev->triple_click) flags |= EVAS_BUTTON_TRIPLE_CLICK;
1033         ecore_event_evas_modifier_lock_update(con->bg_evas, ev->modifiers);
1034         evas_event_feed_mouse_down(con->bg_evas, ev->buttons, flags, ev->timestamp, NULL);
1035      }
1036    return ECORE_CALLBACK_PASS_ON;
1037 }
1038
1039 static Eina_Bool
1040 _e_container_cb_mouse_up(void *data __UNUSED__, int type __UNUSED__, void *event)
1041 {
1042    Ecore_Event_Mouse_Button *ev;
1043    E_Container *con;
1044
1045    ev = event;
1046    con = _e_container_find_by_event_window(ev->event_window);
1047    if (con)
1048      {
1049         evas_event_feed_mouse_up(con->bg_evas, ev->buttons, EVAS_BUTTON_NONE, ev->timestamp, NULL);
1050         ecore_event_evas_modifier_lock_update(con->bg_evas, ev->modifiers);
1051         e_bindings_mouse_up_event_handle(E_BINDING_CONTEXT_CONTAINER,
1052                                          E_OBJECT(con), ev);
1053      }
1054    return ECORE_CALLBACK_PASS_ON;
1055 }
1056
1057 static Eina_Bool
1058 _e_container_cb_mouse_move(void *data __UNUSED__, int type __UNUSED__, void *event)
1059 {
1060    Ecore_Event_Mouse_Move *ev;
1061    E_Container *con;
1062
1063    ev = event;
1064    con = _e_container_find_by_event_window(ev->event_window);
1065    if (con)
1066      {
1067         ecore_event_evas_modifier_lock_update(con->bg_evas, ev->modifiers);
1068         evas_event_feed_mouse_move(con->bg_evas, ev->x, ev->y, ev->timestamp, NULL);
1069      }
1070    return 1;
1071 }
1072
1073 static Eina_Bool
1074 _e_container_cb_mouse_wheel(void *data __UNUSED__, int type __UNUSED__, void *event)
1075 {
1076    Ecore_Event_Mouse_Wheel *ev;
1077    E_Container *con;
1078
1079    ev = event;
1080    con = _e_container_find_by_event_window(ev->event_window);
1081    if (con)
1082      {
1083         if (!e_bindings_wheel_event_handle(E_BINDING_CONTEXT_CONTAINER,
1084                                            E_OBJECT(con), ev))
1085           {
1086              ecore_event_evas_modifier_lock_update(con->bg_evas, ev->modifiers);
1087              evas_event_feed_mouse_wheel(con->bg_evas, ev->direction, ev->z, ev->timestamp, NULL);
1088           }
1089      }
1090    return ECORE_CALLBACK_PASS_ON;
1091 }
1092
1093 static void
1094 _e_container_shape_del(E_Container_Shape *es)
1095 {
1096    _e_container_shape_change_call(es, E_CONTAINER_SHAPE_DEL);
1097 }
1098
1099 static void
1100 _e_container_shape_free(E_Container_Shape *es)
1101 {
1102    es->con->shapes = eina_list_remove(es->con->shapes, es);
1103    E_FREE_LIST(es->shape, free);
1104    free(es);
1105 }
1106
1107 static void
1108 _e_container_shape_change_call(E_Container_Shape *es, E_Container_Shape_Change ch)
1109 {
1110    Eina_List *l = NULL;
1111    E_Container_Shape_Callback *cb = NULL;
1112
1113    if ((!es) || (!es->con) || (!es->con->shape_change_cb)) return;
1114    EINA_LIST_FOREACH(es->con->shape_change_cb, l, cb)
1115      {
1116         if (!cb) continue;
1117         cb->func(cb->data, es, ch);
1118      }
1119 }
1120
1121 static int
1122 _e_container_cb_zone_sort(const void *data1, const void *data2)
1123 {
1124    const E_Zone *z1, *z2;
1125
1126    z1 = data1;
1127    z2 = data2;
1128
1129    return z2->num - z1->num;
1130 }
1131
1132 static void
1133 _e_container_resize_handle(E_Container *con)
1134 {
1135    E_Event_Container_Resize *ev;
1136    Eina_List *l, *screens, *zones = NULL, *ll;
1137    E_Zone *zone;
1138    E_Screen *scr;
1139    int i;
1140
1141    ev = calloc(1, sizeof(E_Event_Container_Resize));
1142    ev->container = con;
1143    e_object_ref(E_OBJECT(con));
1144
1145    e_xinerama_update();
1146    screens = (Eina_List *)e_xinerama_screens_get();
1147
1148    if (screens)
1149      {
1150         EINA_LIST_FOREACH(con->zones, l, zone)
1151           zones = eina_list_append(zones, zone);
1152         con->zones = NULL;
1153         EINA_LIST_FOREACH(screens, l, scr)
1154           {
1155              zone = NULL;
1156
1157              printf("@@@ SCREENS: %i %i | %i %i %ix%i\n",
1158                     scr->screen, scr->escreen, scr->x, scr->y, scr->w, scr->h);
1159              EINA_LIST_FOREACH(zones, ll, zone)
1160                {
1161                   if (zone->id == scr->escreen) break;
1162                   zone = NULL;
1163                }
1164              if (zone)
1165                {
1166                   printf("@@@ FOUND ZONE %i %i [%p]\n", zone->num, zone->id, zone);
1167                   e_zone_move_resize(zone, scr->x, scr->y, scr->w, scr->h);
1168                   zones = eina_list_remove(zones, zone);
1169                   con->zones = eina_list_append(con->zones, zone);
1170                   zone->num = scr->screen;
1171                   e_shelf_zone_move_resize_handle(zone);
1172                }
1173              else
1174                {
1175                   zone = e_zone_new(con, scr->screen, scr->escreen,
1176                                     scr->x, scr->y, scr->w, scr->h);
1177                   printf("@@@ NEW ZONE = %p\n", zone);
1178                }
1179           }
1180         con->zones = eina_list_sort(con->zones, eina_list_count(con->zones),
1181                                     _e_container_cb_zone_sort);
1182         if (zones)
1183           {
1184              E_Zone *spare_zone = NULL;
1185
1186              if (con->zones) spare_zone = con->zones->data;
1187
1188              EINA_LIST_FREE(zones, zone)
1189                {
1190                   Eina_List *shelves, *ll2, *del_shelves;
1191                   E_Shelf *es;
1192                   E_Border_List *bl;
1193                   E_Border *bd;
1194
1195                   /* delete any shelves on this zone */
1196                   shelves = e_shelf_list();
1197                   del_shelves = NULL;
1198                   EINA_LIST_FOREACH(shelves, ll2, es)
1199                     {
1200                        if (es->zone == zone)
1201                          del_shelves = eina_list_append(del_shelves, es);
1202                     }
1203                   E_FREE_LIST(del_shelves, e_object_del);
1204                   bl = e_container_border_list_first(zone->container);
1205                   while ((bd = e_container_border_list_next(bl)))
1206                     {
1207                        if (bd->zone == zone)
1208                          {
1209                             if (spare_zone) e_border_zone_set(bd, spare_zone);
1210                             else
1211                               printf("EEEK! should not be here - but no\n"
1212                                      "spare zones exist to move this\n"
1213                                      "window to!!! help!\n");
1214                          }
1215                     }
1216                   e_container_border_list_free(bl);
1217                   e_object_del(E_OBJECT(zone));
1218                }
1219           }
1220         e_shelf_config_update();
1221      }
1222    else
1223      {
1224         E_Zone *z;
1225
1226         z = e_container_zone_number_get(con, 0);
1227         if (z)
1228           {
1229              e_zone_move_resize(z, 0, 0, con->w, con->h);
1230              e_shelf_zone_move_resize_handle(z);
1231           }
1232      }
1233
1234    ecore_event_add(E_EVENT_CONTAINER_RESIZE, ev, _e_container_event_container_resize_free, NULL);
1235
1236    for (i = 0; i < 11; i++)
1237      {
1238         Eina_List *tmp = NULL;
1239         E_Border *bd;
1240
1241         /* Make temporary list as e_border_res_change_geometry_restore
1242          * rearranges the order. */
1243         EINA_LIST_FOREACH(con->layers[i].clients, l, bd)
1244           tmp = eina_list_append(tmp, bd);
1245
1246         EINA_LIST_FOREACH(tmp, l, bd)
1247           {
1248              e_border_res_change_geometry_save(bd);
1249              e_border_res_change_geometry_restore(bd);
1250           }
1251
1252         eina_list_free(tmp);
1253      }
1254 }
1255
1256 static void
1257 _e_container_event_container_resize_free(void *data __UNUSED__, void *ev)
1258 {
1259    E_Event_Container_Resize *e;
1260
1261    e = ev;
1262    e_object_unref(E_OBJECT(e->container));
1263    free(e);
1264 }
1265