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