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