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