1
2 /*
3 * Copyright (C) 2005 Fabian Yamaguchi <fabiany at gmx.net>
4 * Copyright (C) 1998 Sasha Vasko <sasha at aftercode.net>
5 * Copyright (C) 1995 Bo Yang
6 * Copyright (C) 1993 Robert Nation
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 */
23 #define LOCAL_DEBUG
24
25 #include "../../configure.h"
26
27 #include "asinternals.h"
28
29 #include <unistd.h>
30 #include <signal.h>
31
32
33 /***********************************************************************/
34 /* new IconBox handling : */
35 /***********************************************************************/
36
destroy_asiconbox(ASIconBox ** pib)37 void destroy_asiconbox (ASIconBox ** pib)
38 {
39 if (pib && *pib) {
40 register ASIconBox *ib = *pib;
41 if (ib->areas)
42 free (ib->areas);
43 if (ib->icons)
44 destroy_asbidirlist (&(ib->icons));
45 free (ib);
46 *pib = NULL;
47 }
48 }
49
get_iconbox(int desktop)50 ASIconBox *get_iconbox (int desktop)
51 {
52 ASIconBox *ib = NULL;
53 if (IsValidDesk (desktop)) {
54 if (get_flags (Scr.Feel.flags, StickyIcons))
55 ib = Scr.default_icon_box;
56 else if (Scr.icon_boxes) {
57 ASHashData hdata;
58 if (get_hash_item
59 (Scr.icon_boxes, AS_HASHABLE (desktop),
60 &hdata.vptr) != ASH_Success)
61 ib = NULL;
62 else
63 ib = hdata.vptr;
64 }
65 if (ib == NULL) {
66 ib = safecalloc (1, sizeof (ASIconBox));
67 if (Scr.Look.configured_icon_areas_num == 0
68 || Scr.Look.configured_icon_areas == NULL) {
69 ib->areas_num = 1;
70 ib->areas = safecalloc (1, sizeof (ASGeometry));
71 ib->areas->width = Scr.MyDisplayWidth;
72 ib->areas->height = Scr.MyDisplayHeight;
73 ib->areas->flags = 0;
74 } else {
75 register int i = Scr.Look.configured_icon_areas_num;
76 ib->areas_num = i;
77 ib->areas = safecalloc (ib->areas_num, sizeof (ASGeometry));
78 while (--i >= 0)
79 ib->areas[i] = Scr.Look.configured_icon_areas[i];
80 }
81 ib->icons = create_asbidirlist (NULL);
82 if (get_flags (Scr.Feel.flags, StickyIcons))
83 Scr.default_icon_box = ib;
84 else {
85 if (Scr.icon_boxes == NULL)
86 Scr.icon_boxes = create_ashash (3, NULL, NULL, NULL);
87
88 if (add_hash_item (Scr.icon_boxes, AS_HASHABLE (desktop), ib) !=
89 ASH_Success)
90 destroy_asiconbox (&ib);
91 }
92 }
93 }
94 return ib;
95 }
96
97 typedef struct ASIconRearrangeAux {
98 int curr_area;
99 int last_x, last_y, last_width, last_height;
100 ASIconBox *ib;
101 } ASIconRearrangeAux;
102
fix_iconbox_area(ASGeometry * geom,int min_width,int min_height)103 void fix_iconbox_area (ASGeometry * geom, int min_width, int min_height)
104 {
105 if (geom->width <= min_width) {
106 if (get_flags (geom->flags, XNegative))
107 geom->x -= min_width - geom->width;
108 geom->width = min_width;
109 }
110 if (geom->height < min_height) {
111 if (get_flags (geom->flags, YNegative))
112 geom->y -= min_height - geom->height;
113 geom->height = min_height;
114 }
115 }
116
rearrange_icon_iter_func(void * data,void * aux_data)117 Bool rearrange_icon_iter_func (void *data, void *aux_data)
118 {
119 ASWindow *asw = (ASWindow *) data;
120 ASIconRearrangeAux *rd = (ASIconRearrangeAux *) aux_data;
121 int width = 0, height = 0, title_width = 0, title_height = 0;
122 int whole_width = 0, whole_height = 0;
123 int x, y, box_x = 0, box_y = 0;
124 Bool placed = False;
125 ASGeometry *geom = NULL;
126
127 int new_x = -1, new_y = -1;
128
129 /*
130 p stands for primary coordinate, the coordinate which is changed
131 first when trying to place a new icon. In the past, this
132 was the x coordinate. In that case the y coordinate is the
133 secondary coordinate (s), that means we move it only if the primary
134 coordinate is no longer valid after moving it. (Start a new
135 row if row is full)
136 */
137
138 int *new_p, *new_s;
139 unsigned int *geom_size_p, *geom_size_s;
140 unsigned int PNegative, SNegative;
141 int *last_p, *last_s;
142 int *whole_p, *whole_s;
143 int *last_p_size, *last_s_size;
144
145
146 Bool vertical = get_flags (Scr.Look.flags, IconsGrowVertically);
147
148
149 if (AS_ASSERT (asw) || AS_ASSERT (rd))
150 return False;
151
152 LOCAL_DEBUG_OUT
153 ("asw(%p)->magic(%lX)->icon_canvas(%p)->icon_title_canvas(%p)->icon_button(%p)->icon_title(%p)",
154 asw, asw->magic, asw->icon_canvas, asw->icon_title_canvas,
155 asw->icon_button, asw->icon_title);
156 if (asw->icon_canvas == NULL || rd->ib == NULL)
157 return True;
158
159 if (asw->icon_button) {
160 if (Scr.Look.ButtonWidth == 0)
161 width = calculate_astbar_width (asw->icon_button);
162 else
163 width = Scr.Look.ButtonWidth;
164 if (Scr.Look.ButtonHeight == 0)
165 height = calculate_astbar_height (asw->icon_button);
166 else
167 height = Scr.Look.ButtonHeight;
168 }
169 if (asw->icon_title) {
170 title_width = calculate_astbar_width (asw->icon_title);
171 if (title_width < width)
172 title_width = width;
173 title_height = calculate_astbar_height (asw->icon_title);
174 LOCAL_DEBUG_OUT ("title_size = %dx%d", title_width, title_height);
175 }
176
177 if (get_flags (Scr.Look.flags, SeparateButtonTitle)) {
178 if (title_width > width) {
179 if (title_width > width * 3)
180 title_width = width * 3;
181 whole_width = title_width;
182 } else
183 whole_width = width;
184 } else
185 whole_width = (width == 0) ? title_width : width;
186
187 whole_height = height + title_height;
188 /* now we could determine where exactly to place icon to : */
189 x = -whole_width;
190 y = -whole_height;
191
192 if (rd->curr_area < 0 && rd->ib->areas_num > 0) {
193 rd->curr_area = 0;
194 geom = &(rd->ib->areas[0]);
195 fix_iconbox_area (geom, whole_width, whole_height);
196 rd->last_x = get_flags (geom->flags, XNegative) ? geom->width : 0;
197 rd->last_y = get_flags (geom->flags, YNegative) ? geom->height : 0;
198 } else {
199 geom = &(rd->ib->areas[rd->curr_area]);
200 fix_iconbox_area (geom, whole_width, whole_height);
201 }
202
203
204 /* Set primary/secondary-pointers */
205 if (vertical) {
206
207 new_p = &new_y;
208 new_s = &new_x;
209 geom_size_p = &(geom->height);
210 geom_size_s = &(geom->width);
211 PNegative = YNegative;
212 SNegative = XNegative;
213 last_p = &(rd->last_y);
214 last_s = &(rd->last_x);
215 whole_p = &whole_height;
216 whole_s = &whole_width;
217 last_p_size = &(rd->last_height);
218 last_s_size = &(rd->last_width);
219
220 } else {
221
222 new_p = &new_x;
223 new_s = &new_y;
224 geom_size_p = &(geom->width);
225 geom_size_s = &(geom->height);
226 PNegative = XNegative;
227 SNegative = YNegative;
228 last_p = &(rd->last_x);
229 last_s = &(rd->last_y);
230 whole_p = &whole_width;
231 whole_s = &whole_height;
232 last_p_size = &(rd->last_width);
233 last_s_size = &(rd->last_height);
234 }
235
236
237 LOCAL_DEBUG_OUT ("entering loop : areas_num = %d", rd->ib->areas_num);
238 while (rd->curr_area < rd->ib->areas_num) {
239 new_x = new_y = -1;
240
241 LOCAL_DEBUG_OUT ("trying area #%d : %s%s, %dx%d%+d%+d", rd->curr_area,
242 get_flags (geom->flags, XNegative) ? "XNeg" : "XPos",
243 get_flags (geom->flags, YNegative) ? "YNeg" : "YPos",
244 geom->width, geom->height, geom->x, geom->y);
245 LOCAL_DEBUG_OUT ("last: %dx%d%+d%+d", rd->last_width, rd->last_height,
246 rd->last_x, rd->last_y);
247
248 /* change primary coordinate */
249 if (get_flags (geom->flags, PNegative))
250 *new_p = *last_p - *whole_p;
251 else
252 *new_p = *last_p + *last_p_size;
253
254 /* if primary-coordinate is now invalid */
255 if (*new_p < 0 || *new_p + *whole_p > (int)*geom_size_p) { /* lets try and go to the next row and see if that makes a difference */
256 /* change secondary coordinate */
257 if (get_flags (geom->flags, SNegative))
258 *last_s -= *last_s_size;
259 else
260 *last_s += *last_s_size;
261
262 /* reset primary coordinate */
263 *last_p =
264 get_flags (geom->flags, PNegative) ? (int)*geom_size_p - 1 : 0;
265
266 /* adjust primary coordinate if PNegative */
267 if (get_flags (geom->flags, PNegative))
268 *(new_p) = *last_p -= *whole_p;
269 } else
270 *last_p = *new_p;
271
272 *new_s = *last_s;
273 *new_p = *last_p;
274
275 /* Adjust secondary coordinate if SNegative */
276 if (get_flags (geom->flags, SNegative))
277 *new_s = *last_s - *whole_s;
278
279 LOCAL_DEBUG_OUT ("new : %+d%+d", new_x, new_y);
280 if (new_x >= 0 && new_x + whole_width <= geom->width &&
281 new_y >= 0 && new_y + whole_height <= geom->height) {
282 x = new_x;
283 y = new_y;
284 box_x = geom->x;
285 box_y = geom->y;
286 placed = True;
287 break;
288 }
289
290 ++(rd->curr_area);
291 if (rd->curr_area < rd->ib->areas_num) {
292 geom = &(rd->ib->areas[rd->curr_area]);
293 fix_iconbox_area (geom, whole_width, whole_height);
294 rd->last_x = get_flags (geom->flags, XNegative) ? geom->width : 0;
295 rd->last_y = get_flags (geom->flags, YNegative) ? geom->height : 0;
296 } else {
297 rd->last_x = 0;
298 rd->last_y = 0;
299 }
300
301 rd->last_width = 0;
302 rd->last_height = 0;
303 }
304 /* placing the icon : */
305 LOCAL_DEBUG_OUT
306 ("placing an icon at %+d%+d, base %+d%+d whole %dx%d button %dx%d",
307 x, y, box_x, box_y, whole_width, whole_height, width, height);
308 if (asw->icon_title_canvas && asw->icon_title_canvas != asw->icon_canvas) {
309 moveresize_canvas (asw->icon_canvas,
310 box_x + x + (title_width - width) / 2, box_y + y,
311 width, height);
312 moveresize_canvas (asw->icon_title_canvas, box_x + x,
313 box_y + y + height, title_width, title_height);
314 } else
315 moveresize_canvas (asw->icon_canvas, box_x + x, box_y + y, whole_width,
316 whole_height);
317
318 *last_p_size = *whole_p;
319 if (*whole_s > *last_s_size)
320 *last_s_size = *whole_s;
321 return True;
322 }
323
rearrange_iconbox(ASIconBox * ib)324 void rearrange_iconbox (ASIconBox * ib)
325 {
326 ASIconRearrangeAux aux_data;
327
328 if (ib == NULL)
329 return;
330 aux_data.curr_area = -1;
331 aux_data.last_x = 0;
332 aux_data.last_y = 0;
333 aux_data.last_width = 0;
334 aux_data.last_height = 0;
335 aux_data.ib = ib;
336
337 iterate_asbidirlist (ib->icons, rearrange_icon_iter_func, &aux_data,
338 NULL, False);
339 }
340
add_iconbox_icon(ASWindow * asw)341 Bool add_iconbox_icon (ASWindow * asw)
342 {
343 ASIconBox *ib = NULL;
344 if (AS_ASSERT (asw))
345 return False;
346
347 /* we need to add this window to the list of icons,
348 * and then place it in appropriate position : */
349 if ((ib = get_iconbox (ASWIN_DESK (asw))) == NULL)
350 return False;
351
352 append_bidirelem (ib->icons, asw);
353 rearrange_iconbox (ib);
354
355 return True;
356 }
357
remove_iconbox_icon(ASWindow * asw)358 Bool remove_iconbox_icon (ASWindow * asw)
359 {
360 ASIconBox *ib = NULL;
361 Bool success = False;
362
363 if (AS_ASSERT (asw))
364 return False;
365 /* we need to remove this window from the list of icons -
366 * going through all existing icon boxes just in case : */
367 if (Scr.default_icon_box) {
368 ib = Scr.default_icon_box;
369 if (ib && ib->icons)
370 if (discard_bidirelem (ib->icons, asw)) {
371 rearrange_iconbox (ib);
372 success = True;
373 }
374 }
375
376 if (Scr.icon_boxes) {
377 ASHashIterator iterator;
378 if (start_hash_iteration (Scr.icon_boxes, &iterator))
379 do {
380 ib = (ASIconBox *) curr_hash_data (&iterator);
381 if (discard_bidirelem (ib->icons, asw)) {
382 rearrange_iconbox (ib);
383 success = True;
384 }
385 } while (next_hash_item (&iterator));
386 }
387
388 return success;
389 }
390
change_iconbox_icon_desk(ASWindow * asw,int from_desk,int to_desk)391 Bool change_iconbox_icon_desk (ASWindow * asw, int from_desk, int to_desk)
392 {
393 return False;
394 }
395
on_icon_changed(ASWindow * asw)396 void on_icon_changed (ASWindow * asw)
397 {
398 if (AS_ASSERT (asw))
399 return;
400 /* we probably need to reshuffle entire iconbox when that happen : */
401 if (asw->icon_title) {
402 int width = calculate_astbar_width (asw->icon_title);
403 int height = calculate_astbar_height (asw->icon_title);
404 if (width < Scr.Look.ButtonWidth)
405 width = Scr.Look.ButtonWidth;
406 set_astbar_size (asw->icon_title, width, height);
407 if (asw->icon_title_canvas
408 && asw->icon_title_canvas != asw->icon_canvas) {
409 resize_canvas (asw->icon_title_canvas, width, height);
410 handle_canvas_config (asw->icon_title_canvas);
411 }
412 render_astbar (asw->icon_title,
413 asw->icon_title_canvas ? asw->icon_title_canvas : asw->
414 icon_canvas);
415 }
416 if (asw->icon_button) {
417 render_astbar (asw->icon_button, asw->icon_canvas);
418 }
419 update_canvas_display (asw->icon_canvas);
420 update_canvas_display (asw->icon_title_canvas);
421 }
422
rearrange_iconbox_icons(int desktop)423 void rearrange_iconbox_icons (int desktop)
424 {
425 rearrange_iconbox (get_iconbox (desktop));
426 }
427