26f4ab87a4cd32a1adfcf0c190cbf64890274d3f
[platform/upstream/enlightenment.git] / src / bin / e_place.c
1 #include "e.h"
2
3 EINTERN void
4 e_place_zone_region_smart_cleanup(E_Zone *zone)
5 {
6    E_Desk *desk;
7    Eina_List *clients = NULL;
8    E_Client *ec;
9
10    E_OBJECT_CHECK(zone);
11    desk = e_desk_current_get(zone);
12    E_CLIENT_FOREACH(ec)
13      {
14         /* Build a list of windows on this desktop and not iconified. */
15         if ((ec->desk == desk) && (!ec->iconic) &&
16             (!ec->lock_user_location) && (!e_client_util_ignored_get(ec)))
17           {
18              int area;
19              Eina_List *ll;
20              E_Client *ec2;
21
22              /* Ordering windows largest to smallest gives better results */
23              area = ec->w * ec->h;
24              EINA_LIST_FOREACH(clients, ll, ec2)
25                {
26                   int testarea;
27
28                   testarea = ec2->w * ec2->h;
29                   /* Insert the ec if larger than the current ec */
30                   if (area >= testarea)
31                     {
32                        clients = eina_list_prepend_relative(clients, ec2, ec);
33                        break;
34                     }
35                }
36              /* Looped over all clients without placing, so place at end */
37              if (!ll) clients = eina_list_append(clients, ec);
38           }
39      }
40
41    /* Loop over the clients moving each one using the smart placement */
42    EINA_LIST_FREE(clients, ec)
43      {
44         int new_x, new_y;
45
46         e_place_zone_region_smart(zone, clients, ec->x, ec->y,
47                                   ec->w, ec->h, &new_x, &new_y);
48         evas_object_move(ec->frame, new_x, new_y);
49      }
50 }
51
52 static int
53 _e_place_cb_sort_cmp(const void *v1, const void *v2)
54 {
55    return (*((int *)v1)) - (*((int *)v2));
56 }
57
58 static int
59 _e_place_coverage_client_add(E_Desk *desk, Eina_List *skiplist, int ar, int x, int y, int w, int h)
60 {
61    E_Client *ec;
62    int x2, y2, w2, h2;
63    int iw, ih;
64    int x0, x00, yy0, y00;
65
66    E_CLIENT_FOREACH(ec)
67      {
68         if (eina_list_data_find(skiplist, ec)) continue;
69         if (e_client_util_ignored_get(ec)) continue;
70         x2 = (ec->x - desk->zone->x); y2 = (ec->y - desk->zone->y); w2 = ec->w; h2 = ec->h;
71         if (E_INTERSECTS(x, y, w, h, x2, y2, w2, h2) &&
72             ((ec->sticky) || (ec->desk == desk)) &&
73             (!ec->iconic) && (ec->visible))
74           {
75              x0 = x;
76              if (x < x2) x0 = x2;
77              x00 = (x + w);
78              if ((x2 + w2) < (x + w)) x00 = (x2 + w2);
79              yy0 = y;
80              if (y < y2) yy0 = y2;
81              y00 = (y + h);
82              if ((y2 + h2) < (y + h)) y00 = (y2 + h2);
83              iw = x00 - x0;
84              ih = y00 - yy0;
85              ar += (iw * ih);
86           }
87      }
88    return ar;
89 }
90
91 /* TODO: remove this function */
92 static int
93 _e_place_coverage_shelf_add(E_Desk *desk, int ar, int x, int y, int w, int h)
94 {
95    return ar;
96 }
97
98 EINTERN int
99 e_place_desk_region_smart(E_Desk *desk, Eina_List *skiplist, int x, int y, int w, int h, int *rx, int *ry)
100 {
101    int a_w = 0, a_h = 0, a_alloc_w = 0, a_alloc_h = 0;
102    int *a_x = NULL, *a_y = NULL;
103    int zw, zh;
104    char *u_x = NULL, *u_y = NULL;
105    E_Client *ec;
106
107    *rx = x;
108    *ry = y;
109 #if 0
110    /* DISABLE placement entirely for speed testing */
111    return 1;
112 #endif
113
114    if ((w <= 0) || (h <= 0))
115      {
116         printf("EEEK! trying to place 0x0 window!!!!\n");
117         return 1;
118      }
119
120    /* FIXME: this NEEDS optimizing */
121    a_w = 2;
122    a_h = 2;
123    a_x = E_NEW(int, 2);
124    a_y = E_NEW(int, 2);
125    if (!a_x || !a_y) goto error;
126
127    a_alloc_w = 2;
128    a_alloc_h = 2;
129
130    zw = desk->zone->w;
131    zh = desk->zone->h;
132
133    u_x = calloc(zw + 1, sizeof(char));
134    u_y = calloc(zh + 1, sizeof(char));
135    if (!u_x || !u_y) goto error;
136
137    a_x[0] = 0;
138    a_x[1] = zw;
139    a_y[0] = 0;
140    a_y[1] = zh;
141
142    u_x[0] = 1;
143    u_x[zw] = 1;
144    u_y[0] = 1;
145    u_y[zh] = 1;
146
147    E_CLIENT_FOREACH(ec)
148      {
149         int bx, by, bw, bh;
150
151         if (e_client_util_ignored_get(ec)) continue;
152
153         if (eina_list_data_find(skiplist, ec)) continue;
154
155         if (!((ec->sticky) || (ec->desk == desk))) continue;
156
157         bx = ec->x - desk->zone->x;
158         by = ec->y - desk->zone->y;
159         bw = ec->w;
160         bh = ec->h;
161
162         if (E_INTERSECTS(bx, by, bw, bh, 0, 0, zw, zh))
163           {
164              if (bx < 0)
165                {
166                   bw += bx;
167                   bx = 0;
168                }
169              if ((bx + bw) > zw) bw = zw - bx;
170              if (bx >= zw) continue;
171              if (by < 0)
172                {
173                   bh += by;
174                   by = 0;
175                }
176              if ((by + bh) > zh) bh = zh - by;
177              if (by >= zh) continue;
178              if (!u_x[bx])
179                {
180                   a_w++;
181                   if (a_w > a_alloc_w)
182                     {
183                        a_alloc_w += 32;
184                        E_REALLOC(a_x, int, a_alloc_w);
185                        if (!a_x) goto error;
186                     }
187                   a_x[a_w - 1] = bx;
188                   u_x[bx] = 1;
189                }
190              if (!u_x[bx + bw])
191                {
192                   a_w++;
193                   if (a_w > a_alloc_w)
194                     {
195                        a_alloc_w += 32;
196                        E_REALLOC(a_x, int, a_alloc_w);
197                        if (!a_x) goto error;
198                     }
199                   a_x[a_w - 1] = bx + bw;
200                   u_x[bx + bw] = 1;
201                }
202              if (!u_y[by])
203                {
204                   a_h++;
205                   if (a_h > a_alloc_h)
206                     {
207                        a_alloc_h += 32;
208                        E_REALLOC(a_y, int, a_alloc_h);
209                        if (!a_y) goto error;
210                     }
211                   a_y[a_h - 1] = by;
212                   u_y[by] = 1;
213                }
214              if (!u_y[by + bh])
215                {
216                   a_h++;
217                   if (a_h > a_alloc_h)
218                     {
219                        a_alloc_h += 32;
220                        E_REALLOC(a_y, int, a_alloc_h);
221                        if (!a_y) goto error;
222                     }
223                   a_y[a_h - 1] = by + bh;
224                   u_y[by + bh] = 1;
225                }
226           }
227      }
228    qsort(a_x, a_w, sizeof(int), _e_place_cb_sort_cmp);
229    qsort(a_y, a_h, sizeof(int), _e_place_cb_sort_cmp);
230    free(u_x);
231    free(u_y);
232
233    {
234       int i, j;
235       int area = 0x7fffffff;
236
237       for (j = 0; j < a_h - 1; j++)
238         {
239            for (i = 0; i < a_w - 1; i++)
240              {
241                 if ((a_x[i] <= (zw - w)) &&
242                     (a_y[j] <= (zh - h)))
243                   {
244                      int ar = 0;
245
246                      ar = _e_place_coverage_client_add(desk, skiplist, ar,
247                                                        a_x[i], a_y[j],
248                                                        w, h);
249                      if (e_config->window_placement_policy == E_WINDOW_PLACEMENT_SMART)
250                        ar = _e_place_coverage_shelf_add(desk, ar,
251                                                         a_x[i], a_y[j],
252                                                         w, h);
253                      if (ar < area)
254                        {
255                           area = ar;
256                           *rx = a_x[i];
257                           *ry = a_y[j];
258                           if (ar == 0) goto done;
259                        }
260                   }
261                 if ((a_x[i + 1] - w > 0) && (a_y[j] <= (zh - h)))
262                   {
263                      int ar = 0;
264
265                      ar = _e_place_coverage_client_add(desk, skiplist, ar,
266                                                        a_x[i + 1] - w, a_y[j],
267                                                        w, h);
268                      if (e_config->window_placement_policy == E_WINDOW_PLACEMENT_SMART)
269                        ar = _e_place_coverage_shelf_add(desk, ar,
270                                                         a_x[i + 1] - w, a_y[j],
271                                                         w, h);
272                      if (ar < area)
273                        {
274                           area = ar;
275                           *rx = a_x[i + 1] - w;
276                           *ry = a_y[j];
277                           if (ar == 0) goto done;
278                        }
279                   }
280                 if ((a_x[i + 1] - w > 0) && (a_y[j + 1] - h > 0))
281                   {
282                      int ar = 0;
283
284                      ar = _e_place_coverage_client_add(desk, skiplist, ar,
285                                                        a_x[i + 1] - w, a_y[j + 1] - h,
286                                                        w, h);
287                      if (e_config->window_placement_policy == E_WINDOW_PLACEMENT_SMART)
288                        ar = _e_place_coverage_shelf_add(desk, ar,
289                                                         a_x[i + 1] - w, a_y[j + 1] - h,
290                                                         w, h);
291                      if (ar < area)
292                        {
293                           area = ar;
294                           *rx = a_x[i + 1] - w;
295                           *ry = a_y[j + 1] - h;
296                           if (ar == 0) goto done;
297                        }
298                   }
299                 if ((a_x[i] <= (zw - w)) && (a_y[j + 1] - h > 0))
300                   {
301                      int ar = 0;
302
303                      ar = _e_place_coverage_client_add(desk, skiplist, ar,
304                                                        a_x[i], a_y[j + 1] - h,
305                                                        w, h);
306                      if (e_config->window_placement_policy == E_WINDOW_PLACEMENT_SMART)
307                        ar = _e_place_coverage_shelf_add(desk, ar,
308                                                         a_x[i], a_y[j + 1] - h,
309                                                         w, h);
310                      if (ar < area)
311                        {
312                           area = ar;
313                           *rx = a_x[i];
314                           *ry = a_y[j + 1] - h;
315                           if (ar == 0) goto done;
316                        }
317                   }
318              }
319         }
320    }
321 done:
322    E_FREE(a_x);
323    E_FREE(a_y);
324
325    if ((*rx + w) > desk->zone->w) *rx = desk->zone->w - w;
326    if (*rx < 0) *rx = 0;
327    if ((*ry + h) > desk->zone->h) *ry = desk->zone->h - h;
328    if (*ry < 0) *ry = 0;
329
330 //   printf("0 - PLACE %i %i | %ix%i\n", *rx, *ry, w, h);
331
332    *rx += desk->zone->x;
333    *ry += desk->zone->y;
334    return 1;
335
336 error:
337    E_FREE(a_x);
338    E_FREE(a_y);
339    free(u_x);
340    free(u_y);
341
342    return 0;
343 }
344
345 EINTERN int
346 e_place_zone_region_smart(E_Zone *zone, Eina_List *skiplist, int x, int y, int w, int h, int *rx, int *ry)
347 {
348    return e_place_desk_region_smart(e_desk_current_get(zone), skiplist,
349                                     x, y, w, h, rx, ry);
350 }
351
352 EINTERN int
353 e_place_zone_cursor(E_Zone *zone, int x EINA_UNUSED, int y EINA_UNUSED, int w, int h, int it, int *rx, int *ry)
354 {
355    int cursor_x = 0, cursor_y = 0;
356    int zone_right, zone_bottom;
357
358    E_OBJECT_CHECK_RETURN(zone, 0);
359
360    e_input_device_pointer_xy_get(NULL, &cursor_x, &cursor_y);
361    *rx = cursor_x - (w >> 1);
362    *ry = cursor_y - (it >> 1);
363
364    if (*rx < zone->x)
365      *rx = zone->x;
366
367    if (*ry < zone->y)
368      *ry = zone->y;
369
370    zone_right = zone->x + zone->w;
371    zone_bottom = zone->y + zone->h;
372
373    if ((*rx + w) > zone_right)
374      *rx = zone_right - w;
375
376    if ((*ry + h) > zone_bottom)
377      *ry = zone_bottom - h;
378
379    return 1;
380 }
381
382 EINTERN int
383 e_place_zone_manual(E_Zone *zone, int w, int h, int *rx, int *ry)
384 {
385    int cursor_x = 0, cursor_y = 0;
386
387    E_OBJECT_CHECK_RETURN(zone, 0);
388
389    e_input_device_pointer_xy_get(NULL, &cursor_x, &cursor_y);
390    if (rx) *rx = cursor_x - (w >> 1);
391    if (ry) *ry = cursor_y - (h >> 1);
392
393    return 1;
394 }
395