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