Initialize Tizen 2.3
[framework/uifw/ecore.git] / mobile / src / lib / ecore_x / xcb / ecore_xcb_window_shadow.c
1 #include "ecore_xcb_private.h"
2
3 typedef struct _Shadow Shadow;
4 struct _Shadow
5 {
6    Shadow        *parent, **children;
7    Ecore_X_Window win;
8    int            children_num;
9    short          x, y;
10    unsigned short w, h;
11 };
12
13 static Eina_Bool _inside_rects(Shadow            *s,
14                                int                x,
15                                int                y,
16                                int                bx,
17                                int                by,
18                                Ecore_X_Rectangle *rects,
19                                int                num);
20
21 //static int shadow_count = 0;
22 static Shadow **shadow_base = NULL;
23 static int shadow_num = 0;
24
25 /* FIXME: round trips */
26 static Shadow *
27 _ecore_x_window_tree_walk(Ecore_X_Window window)
28 {
29    Shadow *s, **sl;
30    xcb_get_window_attributes_reply_t *reply_attr;
31    xcb_get_geometry_reply_t *reply_geom;
32    xcb_query_tree_reply_t *reply_tree;
33    xcb_get_window_attributes_cookie_t cookie_attr;
34    xcb_get_geometry_cookie_t cookie_geom;
35    xcb_query_tree_cookie_t cookie_tree;
36    int i, j;
37
38    CHECK_XCB_CONN;
39
40    cookie_attr = xcb_get_window_attributes_unchecked(_ecore_xcb_conn, window);
41    reply_attr = xcb_get_window_attributes_reply(_ecore_xcb_conn, cookie_attr, NULL);
42    if (!reply_attr) return NULL;
43    if (reply_attr->map_state != XCB_MAP_STATE_VIEWABLE)
44      {
45         free(reply_attr);
46         return NULL;
47      }
48
49    free(reply_attr);
50
51    cookie_geom = xcb_get_geometry_unchecked(_ecore_xcb_conn, window);
52    reply_geom = xcb_get_geometry_reply(_ecore_xcb_conn, cookie_geom, NULL);
53    if (!reply_geom) return NULL;
54
55    if (!(s = calloc(1, sizeof(Shadow))))
56      {
57         free(reply_geom);
58         return NULL;
59      }
60
61    s->win = window;
62    s->x = reply_geom->x;
63    s->y = reply_geom->y;
64    s->w = reply_geom->width;
65    s->h = reply_geom->height;
66
67    free(reply_geom);
68
69    cookie_tree = xcb_query_tree_unchecked(_ecore_xcb_conn, window);
70    reply_tree = xcb_query_tree_reply(_ecore_xcb_conn, cookie_tree, NULL);
71    if (reply_tree)
72      {
73         xcb_window_t *list;
74         int num;
75
76         num = xcb_query_tree_children_length(reply_tree);
77         list = xcb_query_tree_children(reply_tree);
78
79         s->children = calloc(1, sizeof(Shadow *) * num);
80         if (s->children)
81           {
82              s->children_num = num;
83              for (i = 0; i < num; i++)
84                {
85                   s->children[i] = _ecore_x_window_tree_walk(list[i]);
86                   if (s->children[i])
87                     s->children[i]->parent = s;
88                }
89              /* compress list down */
90              j = 0;
91              for (i = 0; i < num; i++)
92                {
93                   if (s->children[i])
94                     {
95                        s->children[j] = s->children[i];
96                        j++;
97                     }
98                }
99              if (j == 0)
100                {
101                   free(s->children);
102                   s->children = NULL;
103                   s->children_num = 0;
104                }
105              else
106                {
107                   s->children_num = j;
108                   sl = realloc(s->children, sizeof(Shadow *) * j);
109                   if (sl) s->children = sl;
110                }
111           }
112
113         free(reply_tree);
114      }
115
116    return s;
117 }
118
119 static void
120 _ecore_x_window_tree_shadow_free1(Shadow *s)
121 {
122    int i = 0;
123
124    if (!s) return;
125    if (s->children)
126      {
127         for (i = 0; i < s->children_num; i++)
128           {
129              if (s->children[i])
130                _ecore_x_window_tree_shadow_free1(s->children[i]);
131           }
132         free(s->children);
133      }
134
135    free(s);
136 }
137
138 static void
139 _ecore_x_window_tree_shadow_free(void)
140 {
141    int i = 0;
142
143    if (!shadow_base) return;
144
145    for (i = 0; i < shadow_num; i++)
146      {
147         if (!shadow_base[i]) continue;
148         _ecore_x_window_tree_shadow_free1(shadow_base[i]);
149      }
150    free(shadow_base);
151    shadow_base = NULL;
152    shadow_num = 0;
153 }
154
155 static void
156 _ecore_x_window_tree_shadow_populate(void)
157 {
158    Ecore_X_Window *roots = NULL;
159    int i = 0, num = 0;
160
161    if ((roots = ecore_x_window_root_list(&num)))
162      {
163         shadow_base = calloc(1, sizeof(Shadow *) * num);
164         if (shadow_base)
165           {
166              shadow_num = num;
167              for (i = 0; i < num; i++)
168                shadow_base[i] = _ecore_x_window_tree_walk(roots[i]);
169           }
170
171         free(roots);
172      }
173 }
174
175 /*
176    static void
177    _ecore_x_window_tree_shadow_start(void)
178    {
179    shadow_count++;
180    if (shadow_count > 1) return;
181    _ecore_x_window_tree_shadow_populate();
182    }
183
184    static void
185    _ecore_x_window_tree_shadow_stop(void)
186    {
187    shadow_count--;
188    if (shadow_count != 0) return;
189    _ecore_x_window_tree_shadow_free();
190    }
191  */
192
193 Shadow *
194 _ecore_x_window_shadow_tree_find_shadow(Shadow        *s,
195                                         Ecore_X_Window win)
196 {
197    Shadow *ss;
198    int i = 0;
199
200    if (s->win == win) return s;
201
202    if (s->children)
203      {
204         for (i = 0; i < s->children_num; i++)
205           {
206              if (!s->children[i]) continue;
207
208              if ((ss =
209                     _ecore_x_window_shadow_tree_find_shadow(s->children[i], win)))
210                return ss;
211           }
212      }
213
214    return NULL;
215 }
216
217 Shadow *
218 _ecore_x_window_shadow_tree_find(Ecore_X_Window base)
219 {
220    Shadow *s;
221    int i = 0;
222
223    for (i = 0; i < shadow_num; i++)
224      {
225         if (!shadow_base[i]) continue;
226
227         if ((s =
228                _ecore_x_window_shadow_tree_find_shadow(shadow_base[i], base)))
229           return s;
230      }
231    return NULL;
232 }
233
234 static Ecore_X_Window
235 _ecore_x_window_shadow_tree_at_xy_get_shadow(Shadow         *s,
236                                              int             bx,
237                                              int             by,
238                                              int             x,
239                                              int             y,
240                                              Ecore_X_Window *skip,
241                                              int             skip_num)
242 {
243    Ecore_X_Window child;
244    Ecore_X_Rectangle *rects;
245    int i = 0, j = 0, wx = 0, wy = 0, num = 0;
246
247    wx = s->x + bx;
248    wy = s->y + by;
249    if (!((x >= wx) && (y >= wy) && (x < (wx + s->w)) && (y < (wy + s->h))))
250      return 0;
251
252    rects = ecore_x_window_shape_rectangles_get(s->win, &num);
253    if (!_inside_rects(s, x, y, bx, by, rects, num)) return 0;
254    num = 0;
255    rects = ecore_x_window_shape_input_rectangles_get(s->win, &num);
256    if (!_inside_rects(s, x, y, bx, by, rects, num)) return 0;
257
258    if (s->children)
259      {
260         int skipit = 0;
261
262         for (i = s->children_num - 1; i >= 0; --i)
263           {
264              if (!s->children[i]) continue;
265
266              skipit = 0;
267              if (skip)
268                {
269                   for (j = 0; j < skip_num; j++)
270                     {
271                        if (s->children[i]->win == skip[j])
272                          {
273                             skipit = 1;
274                             goto onward;
275                          }
276                     }
277                }
278 onward:
279              if (!skipit)
280                {
281                   if ((child =
282                          _ecore_x_window_shadow_tree_at_xy_get_shadow(s->children[i], wx, wy, x, y, skip, skip_num)))
283                     return child;
284                }
285           }
286      }
287
288    return s->win;
289 }
290
291 static Ecore_X_Window
292 _ecore_x_window_shadow_tree_at_xy_get(Ecore_X_Window  base,
293                                       int             bx,
294                                       int             by,
295                                       int             x,
296                                       int             y,
297                                       Ecore_X_Window *skip,
298                                       int             skip_num)
299 {
300    Shadow *s;
301
302    if (!shadow_base)
303      {
304         _ecore_x_window_tree_shadow_populate();
305         if (!shadow_base) return 0;
306      }
307
308    s = _ecore_x_window_shadow_tree_find(base);
309    if (!s) return 0;
310
311    return _ecore_x_window_shadow_tree_at_xy_get_shadow(s, bx, by, x, y, skip, skip_num);
312 }
313
314 static Eina_Bool
315 _inside_rects(Shadow            *s,
316               int                x,
317               int                y,
318               int                bx,
319               int                by,
320               Ecore_X_Rectangle *rects,
321               int                num)
322 {
323    Eina_Bool inside = EINA_FALSE;
324    int i = 0;
325
326    if (!rects) return EINA_FALSE;
327    for (i = 0; i < num; i++)
328      {
329         if ((x >= s->x + bx + rects[i].x) &&
330             (y >= s->y + by + rects[i].y) &&
331             (x < (int)(s->x + bx + rects[i].x + rects[i].width)) &&
332             (y < (int)(s->y + by + rects[i].y + rects[i].height)))
333           {
334              inside = EINA_TRUE;
335              break;
336           }
337      }
338    free(rects);
339    return inside;
340 }
341
342 /**
343  * Retrieves the top, visible window at the given location,
344  * but skips the windows in the list. This uses a shadow tree built from the
345  * window tree that is only updated the first time
346  * ecore_x_window_shadow_tree_at_xy_with_skip_get() is called, or the next time
347  * it is called after a  ecore_x_window_shadow_tree_flush()
348  * @param   base The base window to start searching from (normally root).
349  * @param   x The given X position.
350  * @param   y The given Y position.
351  * @param   skip The list of windows to be skipped.
352  * @param   skip_num The number of windows to be skipped.
353  * @return  The window at the desired position.
354  * @ingroup Ecore_X_Window_Geometry_Group
355  */
356 EAPI Ecore_X_Window
357 ecore_x_window_shadow_tree_at_xy_with_skip_get(Ecore_X_Window  base,
358                                                int             x,
359                                                int             y,
360                                                Ecore_X_Window *skip,
361                                                int             skip_num)
362 {
363    return _ecore_x_window_shadow_tree_at_xy_get(base, 0, 0, x, y, skip, skip_num);
364 }
365
366 /**
367  * Retrieves the parent window a given window has. This uses the shadow window
368  * tree.
369  * @param   root The root window of @p win - if 0, this will be automatically determined with extra processing overhead
370  * @param   win The window to get the parent window of
371  * @return  The parent window of @p win
372  * @ingroup Ecore_X_Window_Geometry_Group
373  */
374 EAPI Ecore_X_Window
375 ecore_x_window_shadow_parent_get(Ecore_X_Window root __UNUSED__,
376                                  Ecore_X_Window win)
377 {
378    Shadow *s;
379    int i = 0;
380
381    if (!shadow_base)
382      {
383         _ecore_x_window_tree_shadow_populate();
384         if (!shadow_base) return 0;
385      }
386
387    for (i = 0; i < shadow_num; i++)
388      {
389         if (!shadow_base[i]) continue;
390
391         s = _ecore_x_window_shadow_tree_find_shadow(shadow_base[i], win);
392         if (s)
393           {
394              if (!s->parent) return 0;
395              return s->parent->win;
396           }
397      }
398    return 0;
399 }
400
401 /**
402  * Flushes the window shadow tree so nothing is stored.
403  * @ingroup Ecore_X_Window_Geometry_Group
404  */
405 EAPI void
406 ecore_x_window_shadow_tree_flush(void)
407 {
408    _ecore_x_window_tree_shadow_free();
409 }
410