1 /*
2  * Copyright (c) 1998 Michal Vitecek <M.Vitecek@sh.cvut.cz>
3  * Copyright (c) 1998,2002 Sasha Vasko <sasha at aftercode.net>
4  * Copyright (C) 1998 Ethan Fischer
5  * Copyright (C) 1998 Guylhem Aznar
6  * Copyright (C) 1996 Alfredo K. Kojima
7  * Copyright (C) 1996 Beat Christen
8  * Copyright (C) 1996 Kaj Groner
9  * Copyright (C) 1996 Frank Fejes
10  * Copyright (C) 1996 mj@dfv.rwth-aachen.de
11  * Copyright (C) 1995 Bo Yang
12  * Copyright (C) 1993 Robert Nation
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27  *
28  */
29 
30 #undef DO_CLOCKING
31 #define LOCAL_DEBUG
32 #define EVENT_TRACE
33 
34 #include "../../configure.h"
35 #include "../../libAfterStep/asapp.h"
36 #include <signal.h>
37 #include <unistd.h>
38 #include <fcntl.h>
39 #ifdef HAVE_SYS_WAIT_H
40 #include <sys/wait.h>
41 #endif
42 #if TIME_WITH_SYS_TIME
43 # include <sys/time.h>
44 # include <time.h>
45 #else
46 # if HAVE_SYS_TIME_H
47 #  include <sys/time.h>
48 # else
49 #  include <time.h>
50 # endif
51 #endif
52 
53 #include "../../libAfterStep/afterstep.h"
54 #include "../../libAfterStep/screen.h"
55 #include "../../libAfterStep/session.h"
56 #include "../../libAfterStep/module.h"
57 #include "../../libAfterStep/parser.h"
58 #include "../../libAfterStep/mystyle.h"
59 #include "../../libAfterStep/mystyle_property.h"
60 #include "../../libAfterStep/balloon.h"
61 #include "../../libAfterStep/aswindata.h"
62 #include "../../libAfterStep/decor.h"
63 #include "../../libAfterStep/event.h"
64 #include "../../libAfterStep/wmprops.h"
65 #include "../../libAfterStep/functions.h"
66 #include "../../libAfterStep/shape.h"
67 #include "../../libAfterStep/desktop_category.h"
68 
69 #include "../../libAfterConf/afterconf.h"
70 
71 #define UNFOCUSED_TILE_STYLE 		0
72 #define FOCUSED_TILE_STYLE 			1
73 #define UNFOCUSED_ODD_TILE_STYLE 	2
74 #define FOCUSED_ODD_TILE_STYLE 		3
75 #define WHARF_TILE_STYLES			4
76 
77 #if (WHARF_TILE_STYLES>BACK_STYLES)
78 # warning "WHARF_TILE_STYLES exceed the size of MSWindow pointers array"
79 #endif
80 
81 
82 
83 #ifdef ENABLE_SOUND
84 #define WHEV_PUSH		0
85 #define WHEV_CLOSE_FOLDER	1
86 #define WHEV_OPEN_FOLDER	2
87 #define WHEV_CLOSE_MAIN		3
88 #define WHEV_OPEN_MAIN		4
89 #define WHEV_DROP		5
90 #define MAX_EVENTS		6
91 #endif
92 
93 #define MAGIC_WHARF_BUTTON    0xA38AB110
94 #define MAGIC_WHARF_FOLDER    0xA38AF01D
95 
96 struct ASWharfFolder;
97 
98 typedef struct ASSwallowed {
99 	ASCanvas *normal, *iconic;
100 	ASCanvas *current;						/* one of the above */
101 	int pid;
102 } ASSwallowed;
103 
104 typedef struct ASWharfButton {
105 	unsigned long magic;
106 #define ASW_SwallowTarget   (0x01<<0)
107 #define ASW_MaxSwallow      (0x01<<1)
108 #define ASW_FixedWidth		(0x01<<2)
109 #define ASW_FixedHeight		(0x01<<3)
110 #define ASW_Transient		(0x01<<4)
111 #define ASW_Focusable		(0x01<<5)
112 #define ASW_NameIsUTF8		(0x01<<6)
113 #define ASW_CommentIsUTF8	(0x01<<7)
114 	ASFlagType flags;
115 	char *name;
116 	char *comment;
117 	ASCanvas *canvas;
118 	ASSwallowed *swallowed;
119 	ASTBarData *bar;
120 
121 	unsigned int desired_width, desired_height;
122 	/* this is where it it will actually be placed and what size it should have at the end : */
123 	int folder_x, folder_y;
124 	unsigned int folder_width, folder_height;
125 
126 	FunctionData *fdata[Button5];
127 
128 	struct ASWharfFolder *folder;
129 	struct ASWharfFolder *parent;
130 } ASWharfButton;
131 
132 typedef struct ASWharfFolder {
133 	unsigned long magic;
134 #define ASW_Mapped          (0x01<<0)
135 #define ASW_Vertical        (0x01<<1)
136 #define ASW_Withdrawn       (0x01<<2)
137 #define ASW_NeedsShaping    (0x01<<3)
138 #define ASW_Shaped          (0x01<<4)
139 #define ASW_ReverseOrder    (0x01<<5)
140 #define ASW_UseBoundary     (0x01<<6)
141 #define ASW_AnimationPending  (0x01<<7)
142 #define ASW_ReverseAnimation  (0x01<<8)
143 	ASFlagType flags;
144 
145 	ASCanvas *canvas;
146 	ASWharfButton *buttons;
147 	int buttons_num;
148 	ASWharfButton *parent;
149 
150 	int gravity;
151 	unsigned int total_width, total_height;	/* size calculated based on size of participating buttons */
152 
153 	int animation_steps;					/* how many steps left */
154 	int animation_dir;						/* +1 or -1 */
155 	/* this will cache RootImage so we don't have to pull it every time we
156 	 * have to be animated */
157 	ASImage *root_image;
158 	XRectangle root_clip_area;
159 
160 	XRectangle boundary;
161 	unsigned int animate_from_w, animate_from_h;
162 	unsigned int animate_to_w, animate_to_h;
163 
164 	ASWharfButton *withdrawn_button;
165 
166 } ASWharfFolder;
167 
168 typedef struct ASWharfState {
169 	ASHashTable *win2obj_xref;		/* xref of window IDs to wharf buttons and folders */
170 	ASWharfFolder *root_folder;
171 
172 	ASHashTable *swallow_targets;	/* hash of buttons that needs to swallow  */
173 
174 	ASWharfButton *pressed_button;
175 	int pressed_state;
176 
177 	Bool shaped_style;
178 
179 	ASImage *withdrawn_root_image;
180 	XRectangle withdrawn_root_clip_area;
181 
182 	ASWharfFolder *root_image_folder;	/* points to a folder that owns current Scr.RootImage */
183 
184 	int buttons_render_pending;
185 
186 	ASWharfButton *focused_button;
187 
188 	FunctionData *default_action[Button5];
189 
190 } ASWharfState;
191 
192 ASWharfState WharfState;
193 WharfConfig *Config = NULL;
194 int Rows_override = -1;
195 int Columns_override = -1;
196 
197 Atom _AS_WHARF_CLOSE = None;
198 
199 #define WHARF_BUTTON_EVENT_MASK   (ButtonReleaseMask |\
200                                    ButtonPressMask | LeaveWindowMask | EnterWindowMask |\
201                                    StructureNotifyMask | SubstructureRedirectMask )
202 #define WHARF_FOLDER_EVENT_MASK   (StructureNotifyMask)
203 
204 
205 void HandleEvents ();
206 void process_message (send_data_type type, send_data_type * body);
207 void DispatchEvent (ASEvent * Event);
208 Window make_wharf_window ();
209 void RemapFunctions();
210 void GetOptions (const char *filename);
211 void GetBaseOptions (const char *filename);
212 void CheckConfigSanity ();
213 void SetWharfLook ();
214 
215 ASWharfFolder *build_wharf_folder (WharfButton * list,
216 																	 ASWharfButton * parent, Bool vertical);
217 Bool display_wharf_folder (ASWharfFolder * aswf, int left, int top,
218 													 int right, int bottom);
219 Bool display_main_folder ();
220 void withdraw_wharf_folder (ASWharfFolder * aswf);
221 static inline void withdraw_wharf_subfolders (ASWharfFolder * aswf);
222 void on_wharf_moveresize (ASEvent * event);
223 void destroy_wharf_folder (ASWharfFolder ** paswf);
224 void on_wharf_pressed (ASEvent * event);
225 void release_pressure (int button);
226 Bool check_pending_swallow (ASWharfFolder * aswf);
227 void exec_pending_swallow (ASWharfFolder * aswf);
228 void check_swallow_window (ASWindowData * wd);
229 void update_wharf_folder_transprency (ASWharfFolder * aswf, Bool force);
230 Bool update_wharf_button_styles (ASWharfButton * aswb, Bool odd);
231 void update_wharf_folder_styles (ASWharfFolder * aswf, Bool force);
232 void on_wharf_button_confreq (ASWharfButton * aswb, ASEvent * event);
233 void do_wharf_animate_iter (void *vdata);
234 void clear_root_image_cache (ASWharfFolder * aswf);
235 Bool render_wharf_button (ASWharfButton * aswb);
236 void set_wharf_clip_area (ASWharfFolder * aswf, int x, int y);
237 void set_withdrawn_clip_area (ASWharfFolder * aswf, int x, int y,
238 															unsigned int w, unsigned int h);
239 void change_button_focus (ASWharfButton * aswb, Bool focused);
240 static Bool check_app_click (ASWharfButton * aswb, XButtonEvent * xbtn);
241 void DeadPipe (int);
242 
243 /***********************************************************************
244  *   main - start of module
245  ***********************************************************************/
main(int argc,char ** argv)246 int main (int argc, char **argv)
247 {
248 	int i;
249 	/* Save our program name - for error messages */
250 	set_DeadPipe_handler (DeadPipe);
251 	InitMyApp (CLASS_WHARF, argc, argv, NULL, NULL, 0);
252 	LinkAfterStepConfig ();
253 	for (i = 1; i < argc; ++i) {
254 		LOCAL_DEBUG_OUT ("argv[%d] = \"%s\", original argv[%d] = \"%s\"", i,
255 										 argv[i], i, MyArgs.saved_argv[i]);
256 		if (argv[i] != NULL) {
257 			if (strcmp (argv[i], "--rows") == 0 && i + 1 < argc
258 					&& argv[i + 1] != NULL)
259 				Rows_override = atoi (argv[++i]);
260 			else if (strcmp (argv[i], "--cols") == 0 && i + 1 < argc
261 							 && argv[i + 1] != NULL)
262 				Columns_override = atoi (argv[++i]);
263 		}
264 	}
265 
266 	memset (&WharfState, 0x00, sizeof (WharfState));
267 
268 	ConnectX (ASDefaultScr, EnterWindowMask);
269 	_AS_WHARF_CLOSE = XInternAtom (dpy, "_AS_WHARF_CLOSE", False);
270 	ConnectAfterStep (M_TOGGLE_PAGING |
271 										M_NEW_DESKVIEWPORT |
272 										M_END_WINDOWLIST |
273 										WINDOW_CONFIG_MASK | WINDOW_NAME_MASK, 0);
274 
275 	RemapFunctions();
276 
277 	Config = CreateWharfConfig ();
278 
279 	LOCAL_DEBUG_OUT ("parsing Options ...%s", "");
280 	LoadBaseConfig (GetBaseOptions);
281 	LoadColorScheme ();
282 	LoadConfig ("wharf", GetOptions);
283 
284 	CheckConfigSanity ();
285 	SetWharfLook ();
286 	ReloadCategories (True);
287 
288 	WharfState.root_folder =
289 			build_wharf_folder (Config->root_folder, NULL,
290 													(Config->columns > 0));
291 	/* no longer need that stuff : */
292 	DestroyCategories ();
293 	while (Config->root_folder)
294 		DestroyWharfButton (&(Config->root_folder));
295 
296 	/* let's proceed now : */
297 	if (!display_main_folder ()) {
298 		show_error
299 				("main folder does not have any entries or has zero size. Aborting!");
300 		return 1;
301 	}
302 
303 	/* Create a list of all windows */
304 	/* Request a list of all windows,
305 	 * wait for ConfigureWindow packets */
306 	if (check_pending_swallow (WharfState.root_folder))
307 		SendInfo ("Send_WindowList", 0);
308 
309 	/* create main folder here : */
310 
311 	LOCAL_DEBUG_OUT ("starting The Loop ...%s", "");
312 	HandleEvents ();
313 
314 	return 0;
315 }
316 
HandleEvents()317 void HandleEvents ()
318 {
319 	ASEvent event;
320 	Bool has_x_events = False;
321 	while (True) {
322 		while ((has_x_events = XPending (dpy))) {
323 			if (ASNextEvent (&(event.x), True)) {
324 				event.client = NULL;
325 				setup_asevent_from_xevent (&event);
326 				DispatchEvent (&event);
327 				timer_handle ();
328 			}
329 		}
330 		module_wait_pipes_input (process_message);
331 	}
332 }
333 
MapConfigureNotifyLoop()334 void MapConfigureNotifyLoop ()
335 {
336 	ASEvent event;
337 
338 	do {
339 		if (!ASCheckTypedEvent (MapNotify, &(event.x)))
340 			if (!ASCheckTypedEvent (ConfigureNotify, &(event.x)))
341 				return;
342 
343 		event.client = NULL;
344 		setup_asevent_from_xevent (&event);
345 		DispatchEvent (&event);
346 		ASSync (False);
347 	} while (1);
348 }
349 
350 
351 
DeadPipe(int nonsense)352 void DeadPipe (int nonsense)
353 {
354 	static int already_dead = False;
355 	if (already_dead)
356 		return;											/* non-reentrant function ! */
357 	already_dead = True;
358 
359 	destroy_wharf_folder (&(WharfState.root_folder));
360 	DestroyWharfConfig (Config);
361 	destroy_ashash (&(WharfState.win2obj_xref));
362 	destroy_ashash (&(WharfState.swallow_targets));
363 	window_data_cleanup ();
364 	FreeMyAppResources ();
365 #ifdef DEBUG_ALLOCS
366 /* normally, we let the system clean up, but when auditing time comes
367  * around, it's best to have the books in order... */
368 	print_unfreed_mem ();
369 #endif													/* DEBUG_ALLOCS */
370 	XFlush (dpy);									/* need this for SetErootPixmap to take effect */
371 	XCloseDisplay (dpy);					/* need this for SetErootPixmap to take effect */
372 	exit (0);
373 }
374 
375 
376 /*****************************************************************************
377  *
378  * This routine is responsible for reading and parsing the config file
379  *
380  ****************************************************************************/
check_style_shaped(MyStyle * style)381 Bool check_style_shaped (MyStyle * style)
382 {
383 	if (style == NULL)
384 		return False;
385 	if (style->texture_type >= TEXTURE_TEXTURED_START &&
386 			style->texture_type <= TEXTURE_SHAPED_PIXMAP) {
387 		LOCAL_DEBUG_OUT ("shaped pixmap detected%s", "");
388 		return True;
389 	} else if (style->texture_type >= TEXTURE_SCALED_PIXMAP &&
390 						 style->texture_type <= TEXTURE_PIXMAP) {
391 		if (style->back_icon.image
392 				&& check_asimage_alpha (Scr.asv, style->back_icon.image)) {
393 			LOCAL_DEBUG_OUT ("transparent pixmap detected%s", "");
394 			return True;
395 		}
396 	}
397 	return False;
398 }
399 
CheckConfigSanity()400 void CheckConfigSanity ()
401 {
402 	if (Config == NULL)
403 		Config = CreateWharfConfig ();
404 
405 	if (MyArgs.geometry.flags != 0)
406 		Config->geometry = MyArgs.geometry;
407 
408 	if (Rows_override >= 0)
409 		Config->rows = Rows_override;
410 	if (Columns_override >= 0)
411 		Config->columns = Columns_override;
412 
413 	if (Config->rows <= 0 && Config->columns <= 0)
414 		Config->rows = 1;
415 
416 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)
417 	show_progress ("printing wharf config : ");
418 	PrintWharfConfig (Config);
419 #endif
420 
421 }
422 
SetWharfLook()423 void SetWharfLook ()
424 {
425 	char *buf;
426 	int i;
427 	MyStyle *menu_folder_pixmap = NULL;
428 
429 	mystyle_get_property (Scr.wmprops);
430 
431 	buf = safemalloc (strlen (get_application_name ()) + 256);
432 	sprintf (buf, "*%sTile", get_application_name ());
433 	Scr.Look.MSWindow[UNFOCUSED_TILE_STYLE] = mystyle_find_or_default (buf);
434 	LOCAL_DEBUG_OUT ("Will use style \"%s\"",
435 									 Scr.Look.MSWindow[UNFOCUSED_TILE_STYLE]->name);
436 
437 	sprintf (buf, "*%sFocusedTile", get_application_name ());
438 	Scr.Look.MSWindow[FOCUSED_TILE_STYLE] = mystyle_find (buf);
439 
440 	/* its actually a hack to use MSMenu, but should be fine */
441 	sprintf (buf, "*%sOddTile", get_application_name ());
442 	Scr.Look.MSWindow[UNFOCUSED_ODD_TILE_STYLE] = mystyle_find (buf);
443 
444 	sprintf (buf, "*%sFocusedOddTile", get_application_name ());
445 	Scr.Look.MSWindow[FOCUSED_ODD_TILE_STYLE] = mystyle_find (buf);
446 	free (buf);
447 
448 	menu_folder_pixmap = mystyle_find ("menu_folder_pixmap");
449 	if (menu_folder_pixmap && menu_folder_pixmap->back_icon.image != NULL) {
450 		if (menu_folder_pixmap->back_icon.image->name == NULL) {
451 			release_asimage_by_name (Scr.image_manager,
452 															 ASXMLVAR_MenuFolderPixmap);
453 			store_asimage (Scr.image_manager,
454 										 menu_folder_pixmap->back_icon.image,
455 										 ASXMLVAR_MenuFolderPixmap);
456 			/* and increment refcount : */
457 			menu_folder_pixmap->back_icon.image =
458 					dup_asimage (menu_folder_pixmap->back_icon.image);
459 		}
460 	}
461 
462 	if (get_flags (Config->set_flags, WHARF_FORCE_SIZE)) {
463 		if (Config->force_size.width == 0)
464 			Config->force_size.width = 64;
465 		if (Config->force_size.height == 0)
466 			Config->force_size.height = 64;
467 	} else if (!get_flags (Config->flags, WHARF_FitContents)) {
468 		if (Scr.Look.MSWindow[UNFOCUSED_TILE_STYLE]->back_icon.image != NULL) {
469 			Config->force_size.width =
470 					Scr.Look.MSWindow[UNFOCUSED_TILE_STYLE]->back_icon.width;
471 			Config->force_size.height =
472 					Scr.Look.MSWindow[UNFOCUSED_TILE_STYLE]->back_icon.height;
473 		} else {
474 			Config->force_size.width = 64;
475 			Config->force_size.height = 64;
476 		}
477 	} else {
478 		Config->force_size.width = 0;
479 		Config->force_size.height = 0;
480 	}
481 
482 	if (Config->CompositionMethod == 0)
483 		Config->CompositionMethod = WHARF_DEFAULT_CompositionMethod;
484 
485 	WharfState.shaped_style = False;
486 	for (i = 0; i < WHARF_TILE_STYLES; ++i)
487 		if (check_style_shaped (Scr.Look.MSWindow[i])) {
488 			WharfState.shaped_style = True;
489 			break;
490 		}
491 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)
492 	show_progress ("printing wharf look: ");
493 	Print_balloonConfig (Config->balloon_conf);
494 #endif
495 
496 	balloon_config2look (&(Scr.Look), NULL, Config->balloon_conf,
497 											 "*WharfBalloon");
498 	set_balloon_look (Scr.Look.balloon_look);
499 
500 
501 }
502 
merge_wharf_folders(WharfButton ** pf1,WharfButton ** pf2)503 void merge_wharf_folders (WharfButton ** pf1, WharfButton ** pf2)
504 {
505 	while (*pf1)
506 		pf1 = &((*pf1)->next);
507 	*pf1 = *pf2;
508 	*pf2 = NULL;
509 }
510 
RemapFunctions()511 void RemapFunctions()
512 {
513 	char *fname = make_session_data_file (Session, False, 0, AFTER_FUNC_REMAP, NULL);
514 	FeelConfig *feel_config = ParseFeelOptions (fname, MyName);
515 
516 	free (fname);
517 
518 	if (feel_config != NULL) {
519 		ComplexFunction *remap_func = find_complex_func (feel_config->feel->ComplexFunctions, "RemapFunctions");
520 		if (remap_func){
521 			int i;
522 			for (i = 0 ; i < remap_func->items_num ; ++i)
523 				if (remap_func->items[i].func == F_Remap
524 				    && remap_func->items[i].name != NULL
525 				    && remap_func->items[i].text != NULL)
526 					change_func_code (remap_func->items[i].name, txt2func_code (remap_func->items[i].text));
527 		}
528 		DestroyFeelConfig (feel_config);
529 	}
530 }
531 
GetOptions(const char * filename)532 void GetOptions (const char *filename)
533 {
534 	WharfConfig *config;
535 	WharfConfig *to = Config, *from;
536 	START_TIME (option_time);
537 	SHOW_CHECKPOINT;
538 	LOCAL_DEBUG_OUT ("loading wharf config from \"%s\": ", filename);
539 	from = config = ParseWharfOptions (filename, MyName);
540 	SHOW_TIME ("Config parsing", option_time);
541 
542 	/* Need to merge new config with what we have already : */
543 	/* now lets check the config sanity : */
544 	/* mixing set and default flags : */
545 	Config->flags =
546 			(config->flags & config->set_flags) | (Config->
547 																						 flags & (~config->set_flags));
548 	Config->set_flags |= config->set_flags;
549 
550 	if (get_flags (config->set_flags, WHARF_ROWS))
551 		Config->rows = config->rows;
552 
553 	if (get_flags (config->set_flags, WHARF_COLUMNS))
554 		Config->columns = config->columns;
555 
556 	if (get_flags (config->set_flags, WHARF_GEOMETRY))
557 		merge_geometry (&(config->geometry), &(Config->geometry));
558 
559 	if (get_flags (config->set_flags, WHARF_WITHDRAW_STYLE))
560 		Config->withdraw_style = config->withdraw_style;
561 
562 	if (get_flags (config->set_flags, WHARF_FORCE_SIZE))
563 		merge_geometry (&(config->force_size), &(Config->force_size));
564 
565 	if (get_flags (config->set_flags, WHARF_ANIMATE_STEPS))
566 		Config->animate_steps = config->animate_steps;
567 	if (get_flags (config->set_flags, WHARF_ANIMATE_STEPS_MAIN))
568 		Config->animate_steps_main = config->animate_steps_main;
569 	if (get_flags (config->set_flags, WHARF_ANIMATE_DELAY))
570 		Config->animate_delay = config->animate_delay;
571 	ASCF_MERGE_SCALAR_KEYWORD (WHARF, to, from, LabelLocation);
572 	ASCF_MERGE_SCALAR_KEYWORD (WHARF, to, from, AlignContents);
573 	ASCF_MERGE_SCALAR_KEYWORD (WHARF, to, from, Bevel);
574 	ASCF_MERGE_SCALAR_KEYWORD (WHARF, to, from, ShowHints);
575 	ASCF_MERGE_SCALAR_KEYWORD (WHARF, to, from, CompositionMethod);
576 	ASCF_MERGE_SCALAR_KEYWORD (WHARF, to, from, FolderOffset);
577 	ASCF_MERGE_SCALAR_KEYWORD (WHARF, to, from, OrthogonalFolderOffset);
578 
579 /*LOCAL_DEBUG_OUT( "align_contents = %d", Config->align_contents ); */
580 	if (get_flags (config->set_flags, WHARF_SOUND)) {
581 		int i;
582 		for (i = 0; i < WHEV_MAX_EVENTS; ++i) {
583 			set_string (&(Config->sounds[i]), mystrdup (config->sounds[i]));
584 			config->sounds[i] = NULL;
585 		}
586 	}
587 	/* merging folders : */
588 
589 	if (config->root_folder)
590 		merge_wharf_folders (&(Config->root_folder), &(config->root_folder));
591 
592 	if (Config->balloon_conf)
593 		Destroy_balloonConfig (Config->balloon_conf);
594 	Config->balloon_conf = config->balloon_conf;
595 	config->balloon_conf = NULL;
596 
597 	if (config->style_defs)
598 		ProcessMyStyleDefinitions (&(config->style_defs));
599 
600 	DestroyWharfConfig (config);
601 	FreeSyntaxHash (&WharfFolderSyntax);
602 	SHOW_TIME ("Config parsing", option_time);
603 }
604 
605 /*****************************************************************************
606  *
607  * This routine is responsible for reading and parsing the base file
608  *
609  ****************************************************************************/
GetBaseOptions(const char * filename)610 void GetBaseOptions (const char *filename)
611 {
612 	START_TIME (started);
613 
614 	ReloadASEnvironment (NULL, NULL, NULL, False, True);
615 
616 	SHOW_TIME ("BaseConfigParsingTime", started);
617 }
618 
619 /****************************************************************************/
620 /* Window ID xref :                                                         */
621 /****************************************************************************/
register_object(Window w,ASMagic * obj)622 Bool register_object (Window w, ASMagic * obj)
623 {
624 	if (WharfState.win2obj_xref == NULL)
625 		WharfState.win2obj_xref = create_ashash (0, NULL, NULL, NULL);
626 
627 	return (add_hash_item (WharfState.win2obj_xref, AS_HASHABLE (w), obj) ==
628 					ASH_Success);
629 }
630 
fetch_object(Window w)631 ASMagic *fetch_object (Window w)
632 {
633 	ASHashData hdata = { 0 };
634 	if (WharfState.win2obj_xref)
635 		if (get_hash_item
636 				(WharfState.win2obj_xref, AS_HASHABLE (w),
637 				 &hdata.vptr) != ASH_Success)
638 			hdata.vptr = NULL;
639 	return hdata.vptr;
640 }
641 
unregister_object(Window w)642 void unregister_object (Window w)
643 {
644 	if (WharfState.win2obj_xref)
645 		remove_hash_item (WharfState.win2obj_xref, AS_HASHABLE (w), NULL,
646 											False);
647 }
648 
register_swallow_target(char * name,ASWharfButton * aswb)649 Bool register_swallow_target (char *name, ASWharfButton * aswb)
650 {
651 	if (name && aswb) {
652 		if (WharfState.swallow_targets == NULL)
653 			WharfState.swallow_targets =
654 					create_ashash (0, casestring_hash_value, casestring_compare,
655 												 NULL);
656 
657 		return (add_hash_item
658 						(WharfState.swallow_targets, AS_HASHABLE (name),
659 						 aswb) == ASH_Success);
660 	}
661 	return False;
662 }
663 
fetch_swallow_target(char * name)664 ASWharfButton *fetch_swallow_target (char *name)
665 {
666 	ASHashData hdata = { 0 };
667 	if (WharfState.swallow_targets && name)
668 		if (get_hash_item
669 				(WharfState.swallow_targets, AS_HASHABLE (name),
670 				 &hdata.vptr) != ASH_Success)
671 			hdata.vptr = NULL;
672 	return hdata.vptr;
673 }
674 
unregister_swallow_target(char * name)675 void unregister_swallow_target (char *name)
676 {
677 	if (WharfState.swallow_targets && name)
678 		remove_hash_item (WharfState.swallow_targets, AS_HASHABLE (name), NULL,
679 											False);
680 }
681 
682 
683 /****************************************************************************/
684 /* PROCESSING OF AFTERSTEP MESSAGES :                                       */
685 /****************************************************************************/
process_message(send_data_type type,send_data_type * body)686 void process_message (send_data_type type, send_data_type * body)
687 {
688 	LOCAL_DEBUG_OUT ("received message %lX", type);
689 	if ((type & WINDOW_PACKET_MASK) != 0) {
690 		struct ASWindowData *wd = fetch_window_by_id (body[0]);
691 		WindowPacketResult res;
692 		/* saving relevant client info since handle_window_packet could destroy the actuall structure */
693 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)
694 		Window saved_w = (wd && wd->canvas) ? wd->canvas->w : None;
695 		int saved_desk = wd ? wd->desk : INVALID_DESK;
696 		struct ASWindowData *saved_wd = wd;
697 #endif
698 		LOCAL_DEBUG_OUT ("message %lX window %lX data %p", type, body[0], wd);
699 		res = handle_window_packet (type, body, &wd);
700 		LOCAL_DEBUG_OUT ("\t res = %d, data %p", res, wd);
701 		if (res == WP_DataCreated || res == WP_DataChanged) {
702 			check_swallow_window (wd);
703 		} else if (res == WP_DataDeleted) {
704 			LOCAL_DEBUG_OUT ("client deleted (%p)->window(%lX)->desk(%d)",
705 											 saved_wd, saved_w, saved_desk);
706 		}
707 	} else if (type == M_END_WINDOWLIST)
708 		exec_pending_swallow (WharfState.root_folder);
709 }
710 
711 /*************************************************************************
712  * Event handling :
713  *************************************************************************/
DispatchEvent(ASEvent * event)714 void DispatchEvent (ASEvent * event)
715 {
716 	static Bool root_pointer_moved = True;
717 
718 	SHOW_EVENT_TRACE (event);
719 
720 	if ((event->eclass & ASE_POINTER_EVENTS) != 0
721 			&& is_balloon_click (&(event->x))) {
722 		withdraw_balloon (NULL);
723 		return;
724 	}
725 
726 	event->client = NULL;
727 	switch (event->x.type) {
728 	case ConfigureNotify:
729 		on_wharf_moveresize (event);
730 		break;
731 	case KeyPress:
732 	case KeyRelease:
733 		{
734 			ASMagic *obj = fetch_object (event->w);
735 			if (obj && obj->magic == MAGIC_WHARF_BUTTON) {
736 				ASWharfButton *aswb = (ASWharfButton *) obj;
737 				if (aswb->swallowed) {
738 					event->x.xkey.window = aswb->swallowed->current->w;
739 					XSendEvent (dpy, aswb->swallowed->current->w, False,
740 											KeyPressMask | KeyReleaseMask, &(event->x));
741 				}
742 			}
743 		}
744 		break;
745 	case ButtonPress:
746 		on_wharf_pressed (event);
747 		break;
748 	case ButtonRelease:
749 		release_pressure (event->x.xbutton.button);
750 		{
751 			ASMagic *obj = fetch_object (event->w);
752 			if (obj && obj->magic == MAGIC_WHARF_BUTTON) {
753 				ASWharfButton *aswb = (ASWharfButton *) obj;
754 				if (check_app_click (aswb, &(event->x.xbutton))) {
755 					event->x.xbutton.window = aswb->swallowed->current->w;
756 					XSendEvent (dpy, aswb->swallowed->current->w, False,
757 											ButtonReleaseMask, &(event->x));
758 					return;
759 				}
760 			}
761 		}
762 		break;
763 	case MotionNotify:
764 		root_pointer_moved = True;
765 		break;
766 	case EnterNotify:
767 		if (event->x.xcrossing.window == Scr.Root) {
768 			if (WharfState.focused_button)
769 				change_button_focus (WharfState.focused_button, False);
770 			withdraw_active_balloon ();
771 			break;
772 		}
773 	case LeaveNotify:
774 		{
775 			ASMagic *obj = fetch_object (event->w);
776 			if (WharfState.focused_button)
777 				change_button_focus (WharfState.focused_button, False);
778 			if (obj != NULL && obj->magic == MAGIC_WHARF_BUTTON) {
779 				ASWharfButton *aswb = (ASWharfButton *) obj;
780 				on_astbar_pointer_action (aswb->bar, 0,
781 																	(event->x.type == LeaveNotify),
782 																	root_pointer_moved);
783 				root_pointer_moved = False;
784 				if (event->x.type == EnterNotify)
785 					change_button_focus (aswb, True);
786 			}
787 		}
788 		break;
789 	case ConfigureRequest:
790 		{
791 			ASMagic *obj = fetch_object (event->w);
792 			if (obj != NULL && obj->magic == MAGIC_WHARF_BUTTON) {
793 				ASWharfButton *aswb = (ASWharfButton *) obj;
794 				on_wharf_button_confreq (aswb, event);
795 			}
796 		}
797 		break;
798 
799 	case ClientMessage:
800 		{
801 #ifdef LOCAL_DEBUG
802 			char *name = XGetAtomName (dpy, event->x.xclient.message_type);
803 			LOCAL_DEBUG_OUT ("ClientMessage(\"%s\",data=(%lX,%lX,%lX,%lX,%lX)",
804 											 name, event->x.xclient.data.l[0],
805 											 event->x.xclient.data.l[1],
806 											 event->x.xclient.data.l[2],
807 											 event->x.xclient.data.l[3],
808 											 event->x.xclient.data.l[4]);
809 			XFree (name);
810 #endif
811 			if (event->x.xclient.format == 32) {
812 				if (event->x.xclient.data.l[0] == _XA_WM_DELETE_WINDOW) {
813 					DeadPipe (0);
814 				} else if (event->x.xclient.data.l[0] == _AS_WHARF_CLOSE) {
815 					withdraw_wharf_subfolders (WharfState.root_folder);
816 				}
817 			}
818 		}
819 		break;
820 	case ReparentNotify:
821 		if (event->x.xreparent.parent == Scr.Root) {
822 			//sleep_a_millisec( 100 );
823 			//XMoveResizeWindow( dpy, event->x.xreparent.window, -10000, -10000, 1, 1 );
824 		}
825 		break;
826 	case PropertyNotify:
827 		handle_wmprop_event (Scr.wmprops, &(event->x));
828 		if (event->x.xproperty.atom == _AS_BACKGROUND) {
829 			LOCAL_DEBUG_OUT ("root background updated!%s", "");
830 			clear_root_image_cache (WharfState.root_folder);
831 			if (Scr.RootImage) {
832 				safe_asimage_destroy (Scr.RootImage);
833 				Scr.RootImage = NULL;
834 			}
835 			update_wharf_folder_transprency (WharfState.root_folder, True);
836 		} else if (event->x.xproperty.atom == _AS_STYLE) {
837 			LOCAL_DEBUG_OUT ("AS Styles updated!%s", "");
838 			mystyle_list_destroy_all (&(Scr.Look.styles_list));
839 			LoadColorScheme ();
840 			SetWharfLook ();
841 			reload_asimage_manager (Scr.image_manager);
842 			/* now we need to update everything */
843 			update_wharf_folder_styles (WharfState.root_folder, True);
844 		}
845 		break;
846 	default:
847 #ifdef XSHMIMAGE
848 		LOCAL_DEBUG_OUT
849 				("XSHMIMAGE> EVENT : completion_type = %d, event->type = %d ",
850 				 Scr.ShmCompletionEventType, event->x.type);
851 		if (event->x.type == Scr.ShmCompletionEventType)
852 			handle_ShmCompletion (event);
853 #endif													/* SHAPE */
854 		break;
855 	}
856 }
857 
858 /*************************************************************************/
859 /* Wharf buttons :                                                       */
860 
create_wharf_folder_canvas(ASWharfFolder * aswf)861 ASCanvas *create_wharf_folder_canvas (ASWharfFolder * aswf)
862 {
863 	static XSetWindowAttributes attr;
864 	Window w;
865 	ASCanvas *pc = NULL;
866 	unsigned long mask = CWEventMask | CWBackPixel;	/*map ; */
867 
868 	attr.event_mask = WHARF_FOLDER_EVENT_MASK;
869 	attr.background_pixel = Scr.asv->black_pixel;
870 	attr.background_pixmap = ParentRelative;
871 	if (Scr.asv->visual_info.visual !=
872 			DefaultVisual (dpy, DefaultScreen (dpy)))
873 		mask |= CWBackPixel;
874 	w = create_visual_window (Scr.asv, Scr.Root, 0, 0, 2, 2, 0, InputOutput,
875 														mask, &attr);
876 
877 #ifdef SHAPE
878 	if (get_flags (Config->flags, WHARF_ANIMATE)) {
879 		XRectangle rect;
880 		rect.x = rect.y = 0;
881 		rect.width = rect.height = 1;
882 		XShapeCombineRectangles (dpy, w, ShapeBounding, 0, 0, &rect, 1,
883 														 ShapeSet, Unsorted);
884 		aswf->animate_from_w = 1;
885 		aswf->animate_from_h = 1;
886 		set_flags (aswf->flags, ASW_AnimationPending);
887 	}
888 #endif
889 
890 	register_object (w, (ASMagic *) aswf);
891 	pc = create_ascanvas_container (w);
892 	LOCAL_DEBUG_OUT ("folder canvas %p created for window %lX", pc, w);
893 	return pc;
894 }
895 
896 
create_wharf_button_canvas(ASWharfButton * aswb,ASCanvas * parent)897 ASCanvas *create_wharf_button_canvas (ASWharfButton * aswb,
898 																			ASCanvas * parent)
899 {
900 	static XSetWindowAttributes attr;
901 	Window w;
902 	ASCanvas *canvas;
903 
904 	attr.event_mask = WHARF_BUTTON_EVENT_MASK;
905 	attr.background_pixel = Scr.asv->black_pixel;
906 	w = create_visual_window (Scr.asv, parent->w, -1, -1, 1, 1, 0,
907 														InputOutput, CWEventMask | CWBackPixel, &attr);
908 	register_object (w, (ASMagic *) aswb);
909 	canvas = create_ascanvas (w);
910 
911 	if (WharfState.shaped_style)
912 		set_flags (canvas->state, CANVAS_FORCE_MASK);
913 	return canvas;
914 }
915 
916 
917 void
build_wharf_button_comment(ASWharfButton * aswb,WharfButton * wb,ASTBarData * bar)918 build_wharf_button_comment (ASWharfButton * aswb, WharfButton * wb,
919 														ASTBarData * bar)
920 {
921 	/* if both comment and title are present - it came from Desktop Entries and thus are
922 	   encoded in UTF-8. So we should not worry.
923 	 */
924 	char *hint = NULL;
925 	int hint_length = 0, exec_length = 0;
926 	char encoding = AS_Text_UTF8;
927 	int i, pos;
928 
929 	/* first we figure out what text encoding we should use : */
930 	if (!get_flags (wb->set_flags, WHARF_BUTTON_TITLE_IS_UTF8) &&
931 			get_flags (Config->ShowHints, WHARF_SHOW_HINT_Name)) {
932 		encoding = AS_Text_ASCII;
933 	}
934 	/* done with encoding - now to build actuall text */
935 	/* at first we determine its length : */
936 	if (get_flags (Config->ShowHints, WHARF_SHOW_HINT_Name) && wb->title)
937 		hint_length += strlen (wb->title) + 3;
938 
939 	if (get_flags (Config->ShowHints, WHARF_SHOW_HINT_Comment)
940 			&& wb->comment)
941 		hint_length += strlen (wb->comment) + 1;
942 
943 	if (get_flags (Config->ShowHints, WHARF_SHOW_HINT_Exec)) {
944 		for (i = 0; i < Button5; ++i)
945 			if (aswb->fdata[i]) {
946 				exec_length += 128;
947 				if (aswb->fdata[i]->name)
948 					exec_length += 1 + 1 + strlen (aswb->fdata[i]->name) + 1;
949 				if (aswb->fdata[i]->text)
950 					exec_length += 1 + strlen (aswb->fdata[i]->text) + 1;
951 			}
952 		hint_length += exec_length;
953 	}
954 	if (hint_length <= 1)
955 		return;
956 	/* now lets compile actuall text : */
957 	hint = safemalloc (hint_length);
958 	pos = 0;
959 
960 	if (get_flags (Config->ShowHints, WHARF_SHOW_HINT_Name) && wb->title) {
961 		strcpy (&(hint[pos]), wb->title);
962 		while (hint[pos])
963 			++pos;
964 	}
965 
966 	if (get_flags (Config->ShowHints, WHARF_SHOW_HINT_Comment)
967 			&& wb->comment) {
968 		if (pos > 0)
969 			sprintf (&(hint[pos]), " - %s", wb->comment);
970 		else
971 			strcpy (&(hint[pos]), wb->comment);
972 		while (hint[pos])
973 			++pos;
974 	}
975 
976 	if (get_flags (Config->ShowHints, WHARF_SHOW_HINT_Exec)
977 			&& exec_length > 0) {
978 		for (i = 0; i < Button5; ++i)
979 			if (aswb->fdata[i]) {
980 				TermDef *fterm;
981 
982 				fterm = func2fterm (aswb->fdata[i]->func, True);
983 				sprintf (&(hint[pos]), (pos > 0) ? "\n%s " : "%s ",
984 								 fterm->keyword);
985 				while (hint[pos])
986 					++pos;
987 				if (aswb->fdata[i]->name) {
988 					sprintf (&(hint[pos]), "\"%s\" ", aswb->fdata[i]->name);
989 					while (hint[pos])
990 						++pos;
991 				}
992 				if (aswb->fdata[i]->text) {
993 					strcpy (&(hint[pos]), aswb->fdata[i]->text);
994 					while (hint[pos])
995 						++pos;
996 				}
997 			}
998 	}
999 
1000 	set_astbar_balloon (bar, 0, hint, encoding);
1001 	free (hint);
1002 }
1003 
build_wharf_button_tbar(ASWharfButton * aswb,WharfButton * wb)1004 ASTBarData *build_wharf_button_tbar (ASWharfButton * aswb,
1005 																		 WharfButton * wb)
1006 {
1007 	ASTBarData *bar = create_astbar ();
1008 	int icon_row = 0, icon_col = 0;
1009 	int label_row = 0, label_col = 0;
1010 	int label_flip =
1011 			get_flags (Config->flags, WHARF_FlipLabel) ? FLIP_UPSIDEDOWN : 0;
1012 	int label_align = NO_ALIGN;
1013 #define WLL_Vertical    (0x01<<0)
1014 #define WLL_Opposite    (0x01<<1)
1015 #define WLL_AlignCenter (0x01<<2)
1016 #define WLL_AlignRight  (0x01<<3)
1017 #define WLL_OverIcon    (0x01<<4)
1018 
1019 	if (get_flags (Config->flags, WHARF_SHOW_LABEL) && wb->title) {
1020 		if (get_flags (Config->LabelLocation, WLL_Vertical))
1021 			label_flip |= FLIP_VERTICAL;
1022 		if (!get_flags (Config->LabelLocation, WLL_OverIcon)) {
1023 			if (get_flags (Config->LabelLocation, WLL_Vertical)) {
1024 				if (get_flags (Config->LabelLocation, WLL_Opposite))
1025 					label_col = 1;
1026 				else
1027 					icon_col = 1;
1028 			} else if (get_flags (Config->LabelLocation, WLL_Opposite))
1029 				label_row = 1;
1030 			else
1031 				icon_row = 1;
1032 		}
1033 		if (get_flags (Config->LabelLocation, WLL_AlignCenter))
1034 			label_align = ALIGN_CENTER;
1035 		else if (get_flags (Config->LabelLocation, WLL_AlignRight))
1036 			label_align = ALIGN_RIGHT | ALIGN_TOP;
1037 		else
1038 			label_align = ALIGN_LEFT | ALIGN_BOTTOM;
1039 	}
1040 	LOCAL_DEBUG_OUT ("Building contents...");
1041 	if (wb->contents) {
1042 		char **icon = NULL;
1043 		Bool no_icon = False;
1044 		if (wb->selected_content >= 0
1045 				&& wb->selected_content < wb->contents_num) {
1046 			icon = wb->contents[wb->selected_content].icon;
1047 			if (icon == NULL
1048 					&& IsSwallowFunc (wb->contents[wb->selected_content].function->
1049 														func))
1050 				no_icon = True;
1051 		}
1052 		if (icon == NULL && !no_icon) {
1053 			register int i;
1054 			for (i = 0; i < wb->contents_num; ++i)
1055 				if (wb->contents[i].icon != NULL) {
1056 					icon = wb->contents[i].icon;
1057 					break;
1058 				}
1059 		}
1060 
1061 		if (icon) {
1062 			register int i = -1;
1063 			int desired_size = max (aswb->desired_width, Config->force_size.width);
1064 			if (desired_size == 0)
1065 				desired_size = max (aswb->desired_height, Config->force_size.height);
1066 			if (desired_size == 0)
1067 				desired_size = 64;
1068 			while (icon[++i]) {				/* load image here */
1069 				ASImage *im = load_environment_icon_any (icon[i], desired_size);
1070 				LOCAL_DEBUG_OUT ("icon[%d] = \"%s\", loaded im = %p", i, icon[i], im);
1071 				if (im) {
1072 					int scale_to_width = aswb->desired_width > 0 ? aswb->desired_width : Config->force_size.width;
1073 					int scale_to_height = aswb->desired_height > 0 ? aswb->desired_height : Config->force_size.height;
1074 					if (scale_to_width == 0) scale_to_width = im->width;
1075 					if (scale_to_height == 0) scale_to_height = im->height;
1076 					LOCAL_DEBUG_OUT
1077 							("icon = \"%s\", im_size = %dx%d, desired = %dx%d, to_scale = %dx%d",
1078 							 icon[i], im->width, im->height, aswb->desired_width,
1079 							 aswb->desired_height, scale_to_width, scale_to_height);
1080 					if ( scale_to_width < im->width || scale_to_height < im->height) {
1081 						ASImage *tmp =
1082 								scale_asimage (Scr.asv, im, min(scale_to_width,im->width),
1083 															 min(scale_to_height,im->height), ASA_ASImage, 100,
1084 															 ASIMAGE_QUALITY_DEFAULT);
1085 						if (tmp != NULL && tmp != im) {
1086 							safe_asimage_destroy (im);
1087 							im = tmp;
1088 						}
1089 					}
1090 					add_astbar_icon (bar, icon_col, icon_row, 0,
1091 													 Config->AlignContents, im);
1092 				}
1093 			}
1094 		}
1095 	}
1096 
1097 	set_astbar_composition_method (bar, BAR_STATE_UNFOCUSED,
1098 																 Config->CompositionMethod);
1099 
1100 	if (!get_flags (wb->set_flags, WHARF_BUTTON_TRANSIENT)) {
1101 		if (get_flags (Config->flags, WHARF_SHOW_LABEL) && wb->title) {
1102 			add_astbar_label (bar, label_col, label_row, label_flip, label_align,
1103 												2, 2, wb->title, get_flags (wb->set_flags,
1104 																										WHARF_BUTTON_TITLE_IS_UTF8)
1105 												? AS_Text_UTF8 : AS_Text_ASCII);
1106 
1107 		}
1108 		build_wharf_button_comment (aswb, wb, bar);
1109 	}
1110 
1111 	LOCAL_DEBUG_OUT ("wharf bevel is %s, value 0x%lX, wharf_no_border is %s",
1112 									 get_flags (Config->set_flags,
1113 															WHARF_Bevel) ? "set" : "unset",
1114 									 Config->Bevel, get_flags (Config->flags,
1115 																						 WHARF_NO_BORDER) ? "set" :
1116 									 "unset");
1117 	if (get_flags (Config->flags, WHARF_NO_BORDER)) {
1118 		set_astbar_hilite (bar, BAR_STATE_UNFOCUSED, 0);
1119 		set_astbar_hilite (bar, BAR_STATE_FOCUSED, 0);
1120 	} else if (get_flags (Config->set_flags, WHARF_Bevel)) {
1121 		set_astbar_hilite (bar, BAR_STATE_UNFOCUSED, Config->Bevel);
1122 		set_astbar_hilite (bar, BAR_STATE_FOCUSED, Config->Bevel);
1123 	} else {
1124 		set_astbar_hilite (bar, BAR_STATE_UNFOCUSED,
1125 											 RIGHT_HILITE | BOTTOM_HILITE);
1126 		set_astbar_hilite (bar, BAR_STATE_FOCUSED,
1127 											 RIGHT_HILITE | BOTTOM_HILITE);
1128 	}
1129 	return bar;
1130 }
1131 
1132 
1133 /*************************************************************************/
1134 /* Wharf folders :                                                       */
1135 
create_wharf_folder(int button_count,ASWharfButton * parent)1136 ASWharfFolder *create_wharf_folder (int button_count,
1137 																		ASWharfButton * parent)
1138 {
1139 	ASWharfFolder *aswf = NULL;
1140 	if (button_count > 0) {
1141 		register int i = button_count;
1142 		aswf = safecalloc (1, sizeof (ASWharfFolder));
1143 		aswf->magic = MAGIC_WHARF_FOLDER;
1144 		aswf->buttons = safecalloc (i, sizeof (ASWharfButton));
1145 		aswf->buttons_num = i;
1146 		while (--i >= 0) {
1147 			aswf->buttons[i].magic = MAGIC_WHARF_BUTTON;
1148 			aswf->buttons[i].parent = aswf;
1149 		}
1150 		aswf->parent = parent;
1151 	}
1152 	return aswf;
1153 }
1154 
update_wharf_button_content_from_de(WharfButtonContent * content,ASDesktopEntry * de)1155 void update_wharf_button_content_from_de (WharfButtonContent * content,
1156 																					ASDesktopEntry * de)
1157 {
1158 	if (de->Icon) {
1159 		content->icon = safecalloc (2, sizeof (char *));
1160 		content->icon[0] = mystrdup (de->Icon);
1161 		/* curr->contents[0].icon[1] is NULL - terminator */
1162 	}
1163 	if (content->function == NULL)
1164 		content->function = desktop_entry2function (de, NULL);
1165 
1166 	if (de->type == ASDE_TypeDirectory && content->function)
1167 		content->function->func = F_Folder;
1168 }
1169 
desktop_category2wharf_folder(WharfButton * owner,WharfButtonContent * content,const char * category_name,int max_depth)1170 WharfButton *desktop_category2wharf_folder (WharfButton * owner,
1171 																						WharfButtonContent * content,
1172 																						const char *category_name,
1173 																						int max_depth)
1174 {
1175 	ASCategoryTree *ct = NULL;
1176 	ASDesktopCategory *dc = NULL;
1177 	WharfButton *list = NULL;
1178 	WharfButton **tail = &list;
1179 	WharfButton *curr = NULL;
1180 
1181 	ASDesktopEntryInfo *entries;
1182 	int i, entries_num;
1183 
1184 	if (--max_depth < 0)
1185 		return NULL;
1186 
1187 	if ((dc = name2desktop_category (category_name, &ct)) != NULL) {
1188 		ASDesktopEntry *cat_de = fetch_desktop_entry (ct, dc->name);
1189 		if (owner != NULL && cat_de != NULL) {
1190 			char *utf8_title = NULL;
1191 			if (content != NULL && content->icon == NULL)
1192 				update_wharf_button_content_from_de (content, cat_de);
1193 			if (dup_desktop_entry_Name (cat_de, &utf8_title)) {
1194 				if (owner->title)
1195 					free (owner->title);
1196 				owner->title = utf8_title;
1197 				set_flags (owner->set_flags, WHARF_BUTTON_TITLE_IS_UTF8);
1198 			} else
1199 				destroy_string (&utf8_title);
1200 			if (owner->comment)
1201 				free (owner->comment);
1202 			if (dup_desktop_entry_Comment (cat_de, &(owner->comment)))
1203 				set_flags (owner->set_flags, WHARF_BUTTON_COMMENT_IS_UTF8);
1204 		}
1205 
1206 		entries =
1207 				desktop_category_get_entries (ct, dc, max_depth, NULL,
1208 																			&entries_num);
1209 		if (entries) {
1210 			for (i = 0; i < entries_num; ++i) {
1211 				ASDesktopEntry *de = entries[i].de;
1212 				if (de->type != ASDE_TypeApplication &&
1213 						(de->type != ASDE_TypeDirectory || max_depth <= 0))
1214 					continue;
1215 
1216 				if (get_flags (de->flags, ASDE_Unavailable))
1217 					continue;
1218 
1219 				if (de->type == ASDE_TypeApplication) {
1220 					if (max_depth > 0)
1221 						if (desktop_entry_in_subcategory
1222 								(ct, de, entries, entries_num))
1223 							continue;
1224 				} else if (de->type == ASDE_TypeDirectory && max_depth <= 0)
1225 					continue;
1226 
1227 				curr = CreateWharfButton ();
1228 				*tail = curr;
1229 				tail = &(curr->next);
1230 
1231 				if (dup_desktop_entry_Name (de, &(curr->title)))
1232 					set_flags (curr->set_flags, WHARF_BUTTON_TITLE_IS_UTF8);
1233 				if (dup_desktop_entry_Comment (de, &(curr->comment)))
1234 					set_flags (curr->set_flags, WHARF_BUTTON_COMMENT_IS_UTF8);
1235 
1236 				curr->contents = safecalloc (1, sizeof (WharfButtonContent));
1237 				curr->contents_num = 1;
1238 				update_wharf_button_content_from_de (&(curr->contents[0]), de);
1239 				if (de->type == ASDE_TypeDirectory) {
1240 					curr->folder =
1241 							desktop_category2wharf_folder (NULL, NULL, de->Name,
1242 																						 max_depth);
1243 				}
1244 			}
1245 			free (entries);
1246 		}
1247 	}
1248 	if (owner != NULL) {
1249 		*tail = owner->folder;
1250 		owner->folder = list;
1251 	}
1252 	return list;
1253 }
1254 
1255 
build_wharf_folder(WharfButton * list,ASWharfButton * parent,Bool vertical)1256 ASWharfFolder *build_wharf_folder (WharfButton * list,
1257 																	 ASWharfButton * parent, Bool vertical)
1258 {
1259 	ASWharfFolder *aswf = NULL;
1260 	int count = 0;
1261 	WharfButton *wb = list;
1262 	while (wb) {
1263 		Bool disabled = True;
1264 		int i = 0;
1265 		if (get_flags (wb->set_flags, WHARF_BUTTON_TRANSIENT))
1266 			disabled = False;
1267 		else {
1268 			for (i = 0; i < wb->contents_num; ++i) {
1269 				FunctionData *function = wb->contents[i].function;
1270 				LOCAL_DEBUG_OUT ("contents %d has function %p with func = %ld", i,
1271 												 function, function ? function->func : -1);
1272 				if (function) {
1273 					int func = function->func;
1274 					if (func == F_DesktopEntry) {
1275 						char *de_name =
1276 								function->text ? function->text : function->name;
1277 						ASDesktopEntry *de = name2desktop_entry (de_name, NULL);
1278 						if (de == NULL) {
1279 							disabled = True;
1280 							function->func = F_NOP;
1281 						} else {
1282 							if (dup_desktop_entry_Name (de, &(wb->title)))
1283 								set_flags (wb->set_flags, WHARF_BUTTON_TITLE_IS_UTF8);
1284 							if (dup_desktop_entry_Comment (de, &(wb->comment)))
1285 								set_flags (wb->set_flags, WHARF_BUTTON_COMMENT_IS_UTF8);
1286 
1287 							destroy_func_data (&(wb->contents[i].function));
1288 							update_wharf_button_content_from_de (&(wb->contents[i]), de);
1289 
1290 							function = wb->contents[i].function;
1291 						}
1292 					} else if (func == F_CATEGORY || func == F_CATEGORY_TREE) {
1293 						char *cat_name =
1294 								function->text ? function->text : function->name;
1295 						desktop_category2wharf_folder (wb, &(wb->contents[i]),
1296 																					 cat_name,
1297 																					 (func == F_CATEGORY) ? 1 : 5);
1298 						function->func = F_Folder;
1299 
1300 					} else {
1301 						char *target = NULL;
1302 						if ((func < F_ExecToolStart || func > F_ExecToolEnd) &&
1303 								(IsSwallowFunc (func) || IsExecFunc (func))) {
1304 							target = function->text;
1305 						} else if (func == F_ExecInTerm) {
1306 							target = strstr (function->text, "-e ");
1307 							target = target ? target + 3 : function->text;
1308 						}
1309 
1310 						if (target) {
1311 							disabled = !is_executable_in_path (target);
1312 							if (disabled) {
1313 								wb->contents[i].unavailable = True;
1314 								show_warning("Application \"%s\" cannot be found in the PATH.", target);
1315 							}
1316 						} else
1317 							disabled = (func == F_NOP);
1318 					}
1319 				}
1320 				if (!disabled) {
1321 					wb->selected_content = i;
1322 					break;
1323 				}
1324 			}
1325 			if (wb->folder != NULL)
1326 				disabled = False;
1327 		}
1328 
1329 		if (wb->contents_num == 0 && disabled) {
1330 			set_flags (wb->set_flags, WHARF_BUTTON_DISABLED);
1331 			show_warning
1332 					("Button \"%s\" has no functions nor folder assigned to it. Button will be disabled",
1333 					 wb->title ? wb->title : "-");
1334 		} else if (disabled) {
1335 			set_flags (wb->set_flags, WHARF_BUTTON_DISABLED);
1336 			show_warning
1337 					("None of Applications assigned to the button \"%s\" can be found in the PATH. Button will be disabled",
1338 					 wb->title ? wb->title : "-");
1339 		}
1340 		if (!disabled)
1341 			++count;
1342 		wb = wb->next;
1343 	}
1344 
1345 	if ((aswf = create_wharf_folder (count, parent)) != NULL) {
1346 		int button_no = 0;
1347 		aswf->canvas = create_wharf_folder_canvas (aswf);
1348 		if (vertical)
1349 			set_flags (aswf->flags, ASW_Vertical);
1350 		else
1351 			clear_flags (aswf->flags, ASW_Vertical);
1352 
1353 		wb = list;
1354 		while (wb) {
1355 			ASWharfButton *aswb = &(aswf->buttons[button_no]);
1356 			if (get_flags (wb->set_flags, WHARF_BUTTON_DISABLED)) {
1357 				wb = wb->next;
1358 				continue;
1359 			}
1360 
1361 			aswb->name = mystrdup (wb->title);
1362 			if (wb->contents) {
1363 				int i;
1364 				for (i = 0; i < wb->contents_num; ++i)
1365 					if (!wb->contents[i].unavailable) {
1366 						FunctionData *function = wb->contents[i].function;
1367 						if (function) {
1368 							int btn = Button1;
1369 							if (function->name != NULL && strlen (function->name) == 1) {
1370 								switch (function->name[0]) {
1371 								case 'l':
1372 									btn = Button1;
1373 									break;
1374 								case 'm':
1375 									btn = Button2;
1376 									break;
1377 								case 'r':
1378 									btn = Button3;
1379 									break;
1380 								case '4':
1381 									btn = Button4;
1382 									break;
1383 								case '5':
1384 									btn = Button5;
1385 									break;
1386 								}
1387 							}
1388 							btn -= Button1;
1389 							if (aswb->fdata[btn] == NULL) {
1390 								aswb->fdata[btn] = safecalloc (1, sizeof (FunctionData));
1391 								dup_func_data (aswb->fdata[btn], function);
1392 								if (IsSwallowFunc (aswb->fdata[btn]->func)) {
1393 									set_flags (aswb->flags, ASW_SwallowTarget);
1394 									register_swallow_target (aswb->fdata[btn]->name, aswb);
1395 									if (aswb->fdata[btn]->func == F_MaxSwallow ||
1396 											aswb->fdata[btn]->func == F_MaxSwallowModule)
1397 										set_flags (aswb->flags, ASW_MaxSwallow);
1398 								}
1399 							}
1400 						}
1401 					}
1402 			}
1403 			/* TODO:  Transient buttons are just spacers - they should not
1404 			 *      have any balloons displayed on them , nor they should
1405 			 *      interpret any clicks
1406 			 */
1407 			if (get_flags (wb->set_flags, WHARF_BUTTON_TRANSIENT)) {
1408 				LOCAL_DEBUG_OUT ("Markip button %p as transient", aswb);
1409 				set_flags (aswb->flags, ASW_Transient);
1410 			}
1411 
1412 			if (get_flags (wb->set_flags, WHARF_BUTTON_SIZE)) {
1413 				if (wb->width > 0)
1414 					set_flags (aswb->flags, ASW_FixedWidth);
1415 				if (wb->height > 0)
1416 					set_flags (aswb->flags, ASW_FixedHeight);
1417 				aswb->desired_width = wb->width;
1418 				aswb->desired_height = wb->height;
1419 			}
1420 
1421 			aswb->canvas = create_wharf_button_canvas (aswb, aswf->canvas);
1422 			aswb->bar = build_wharf_button_tbar (aswb, wb);
1423 
1424 			update_wharf_button_styles (aswb, ((button_no & 0x01) == 0));
1425 
1426 			if (!get_flags (aswb->flags, ASW_SwallowTarget)) {
1427 				if (aswb->desired_width == 0)
1428 					aswb->desired_width =
1429 							(Config->force_size.width ==
1430 							 0) ? calculate_astbar_width (aswb->bar) : Config->
1431 							force_size.width;
1432 				if (aswb->desired_height == 0)
1433 					aswb->desired_height =
1434 							(Config->force_size.height ==
1435 							 0) ? calculate_astbar_height (aswb->bar) : Config->
1436 							force_size.height;
1437 			} else {
1438 				if (aswb->desired_width == 0)
1439 					aswb->desired_width = Config->force_size.width;
1440 				if (aswb->desired_height == 0)
1441 					aswb->desired_height = Config->force_size.height;
1442 			}
1443 
1444 			if (aswb->desired_width == 0)
1445 				aswb->desired_width = 64;
1446 
1447 			if (aswb->desired_height == 0)
1448 				aswb->desired_height = 64;
1449 
1450 			if (wb->folder)
1451 				aswb->folder =
1452 						build_wharf_folder (wb->folder, aswb, vertical ? False : True);
1453 
1454 			++button_no;
1455 			wb = wb->next;
1456 		}
1457 		XMapSubwindows (dpy, aswf->canvas->w);
1458 	}
1459 	return aswf;
1460 }
1461 
destroy_wharf_folder(ASWharfFolder ** paswf)1462 void destroy_wharf_folder (ASWharfFolder ** paswf)
1463 {
1464 	ASWharfFolder *aswf;
1465 	if (paswf == NULL)
1466 		return;
1467 
1468 	if ((aswf = *paswf) == NULL)
1469 		return;
1470 	if (aswf->magic != MAGIC_WHARF_FOLDER)
1471 		return;
1472 
1473 	if (aswf->canvas)
1474 		unmap_canvas_window (aswf->canvas);
1475 
1476 	if (aswf->buttons) {
1477 		int i = aswf->buttons_num;
1478 		while (--i >= 0) {
1479 			ASWharfButton *aswb = &(aswf->buttons[i]);
1480 			int i;
1481 			if (aswb->swallowed) {
1482 				send_wm_protocol_request (aswb->swallowed->current->w,
1483 																	_XA_WM_DELETE_WINDOW, CurrentTime);
1484 				ASSync (False);
1485 				sleep_a_millisec (200);
1486 				XKillClient (dpy, aswb->swallowed->current->w);
1487 				ASSync (False);
1488 				sleep_a_millisec (100);
1489 				if (aswb->swallowed->pid > 0)
1490 					kill (aswb->swallowed->pid, SIGKILL);
1491 			}
1492 			if (aswb->name)
1493 				free (aswb->name);
1494 			destroy_astbar (&(aswb->bar));
1495 			if (aswb->canvas)
1496 				unregister_object (aswb->canvas->w);
1497 			destroy_ascanvas (&(aswb->canvas));
1498 			for (i = 0; i < 5; ++i)
1499 				if (aswb->fdata[i])
1500 					destroy_func_data (&(aswb->fdata[i]));
1501 			destroy_wharf_folder (&(aswb->folder));
1502 		}
1503 		free (aswf->buttons);
1504 	}
1505 	if (aswf->canvas)
1506 		unregister_object (aswf->canvas->w);
1507 	destroy_ascanvas (&(aswf->canvas));
1508 
1509 	memset (aswf, 0x00, sizeof (ASWharfFolder));
1510 	free (aswf);
1511 	*paswf = NULL;
1512 }
1513 
set_folder_name(ASWharfFolder * aswf,Bool withdrawn)1514 void set_folder_name (ASWharfFolder * aswf, Bool withdrawn)
1515 {
1516 	if (withdrawn) {
1517 		char *withdrawn_name = safemalloc (strlen (MyName) + 16);
1518 		sprintf (withdrawn_name, "%s%s", MyName, "Withdrawn");
1519 		set_client_names (aswf->canvas->w, withdrawn_name, withdrawn_name,
1520 											AS_MODULE_CLASS, CLASS_WHARF_WITHDRAWN);
1521 		free (withdrawn_name);
1522 	} else if (aswf == WharfState.root_folder) {
1523 		set_client_names (aswf->canvas->w, MyName, MyName, AS_MODULE_CLASS,
1524 											CLASS_WHARF);
1525 	} else {
1526 
1527 		char *folder_name;
1528 
1529 		if (aswf->parent->name) {
1530 #define WHARF_SUBFOLDER_TEXT	"Subfolder"
1531 			folder_name =
1532 					safemalloc (strlen (MyName) +
1533 											sizeof (WHARF_SUBFOLDER_TEXT " - ") +
1534 											strlen (aswf->parent->name) + 1);
1535 			sprintf (folder_name, "%s" WHARF_SUBFOLDER_TEXT " - %s", MyName,
1536 							 aswf->parent->name);
1537 		} else {
1538 			folder_name =
1539 					safemalloc (strlen (MyName) + sizeof (WHARF_SUBFOLDER_TEXT) + 1);
1540 			sprintf (folder_name, "%s" WHARF_SUBFOLDER_TEXT, MyName);
1541 		}
1542 		set_client_names (aswf->canvas->w, folder_name, folder_name,
1543 											AS_MODULE_CLASS, CLASS_WHARF);
1544 		free (folder_name);
1545 	}
1546 }
1547 
update_wharf_folder_shape(ASWharfFolder * aswf)1548 Bool update_wharf_folder_shape (ASWharfFolder * aswf)
1549 {
1550 #ifdef SHAPE
1551 	int i = aswf->buttons_num;
1552 	int set = 0;
1553 
1554 	clear_flags (aswf->flags, ASW_Shaped);
1555 
1556 	if ((get_flags (Config->flags, WHARF_ShapeToContents)
1557 			 && get_flags (aswf->flags, ASW_NeedsShaping))
1558 			|| WharfState.shaped_style
1559 			|| get_flags (aswf->flags, ASW_UseBoundary)) {
1560 		if (aswf->canvas->shape)
1561 			flush_vector (aswf->canvas->shape);
1562 		else
1563 			aswf->canvas->shape = create_shape ();
1564 
1565 		while (--i >= 0) {
1566 			register ASWharfButton *aswb = &(aswf->buttons[i]);
1567 			Bool do_combine = False;
1568 			LOCAL_DEBUG_OUT
1569 					("Adding shape of the button %d (%p) with geometry %dx%d%+d%+d, and geometry inside folder %dx%d%+d%+d",
1570 					 i, aswb, aswb->canvas->width, aswb->canvas->height,
1571 					 aswb->canvas->root_x, aswb->canvas->root_y, aswb->folder_width,
1572 					 aswb->folder_height, aswb->folder_x, aswb->folder_y);
1573 			if (aswb->canvas->width == aswb->folder_width
1574 					&& aswb->canvas->height == aswb->folder_height)
1575 				do_combine = True;
1576 			if (aswb->swallowed) {
1577 				refresh_container_shape (aswb->swallowed->current);
1578 				LOCAL_DEBUG_OUT
1579 						("$$$$$$ name = \"%s\" current pos = %+d%+d, button = %+d%+d",
1580 						 aswb->name, aswb->swallowed->current->root_x,
1581 						 aswb->swallowed->current->root_y, aswb->canvas->root_x,
1582 						 aswb->canvas->root_y);
1583 				combine_canvas_shape_at (aswb->canvas, aswb->swallowed->current,
1584 																 aswb->swallowed->current->root_x -
1585 																 aswb->canvas->root_x,
1586 																 aswb->swallowed->current->root_y -
1587 																 aswb->canvas->root_y);
1588 				update_canvas_display_mask (aswb->canvas, True);
1589 /*
1590  * We already combined swallowed shape with button's shape - now we need to combine
1591  * this was causing wierd artifacts :  if( combine_canvas_shape_at (aswf->canvas, aswb->swallowed->current, aswb->folder_x, aswb->folder_y ) )
1592  */
1593 				do_combine = True;
1594 			}
1595 			if (do_combine)
1596 				if (combine_canvas_shape_at
1597 						(aswf->canvas, aswb->canvas, aswb->folder_x, aswb->folder_y))
1598 					++set;
1599 
1600 		}
1601 		if (get_flags (aswf->flags, ASW_UseBoundary)) {
1602 			XRectangle sr;
1603 			int do_subtract = 0;
1604 			sr = aswf->boundary;
1605 			LOCAL_DEBUG_OUT ("boundary = %dx%d%+d%+d, canvas = %dx%d\n",
1606 											 sr.width, sr.height, sr.x, sr.y,
1607 											 aswf->canvas->width, aswf->canvas->height);
1608 
1609 			if (sr.width < aswf->canvas->width) {
1610 				if (sr.x > 0) {
1611 					sr.width = sr.x;
1612 					sr.x = 0;
1613 				} else {
1614 					sr.x = sr.width;
1615 					sr.width = aswf->canvas->width - sr.width;
1616 				}
1617 				++do_subtract;
1618 			}
1619 
1620 			if (sr.height < aswf->canvas->height) {
1621 				if (sr.y > 0) {
1622 					sr.height = sr.y;
1623 					sr.y = 0;
1624 				} else {
1625 					sr.y = sr.height;
1626 					sr.height = aswf->canvas->height - sr.height;
1627 				}
1628 				++do_subtract;
1629 			}
1630 #if 0
1631 			fprintf (stderr,
1632 							 "%s: substr_boundary = %dx%d%+d%+d canvas = %dx%d%+d%+d\n",
1633 							 __FUNCTION__, sr.width, sr.height, sr.x, sr.y,
1634 							 aswf->canvas->width, aswf->canvas->height,
1635 							 aswf->canvas->root_x, aswf->canvas->root_y);
1636 			fprintf (stderr, "shape = %p, used = %d\n", aswf->canvas->shape,
1637 							 PVECTOR_USED (aswf->canvas->shape));
1638 #endif
1639 			if (sr.width > 0 && sr.height > 0 && do_subtract > 0) {
1640 				subtract_shape_rectangle (aswf->canvas->shape, &sr, 1, 0, 0,
1641 																	aswf->canvas->width,
1642 																	aswf->canvas->height);
1643 			}
1644 		}
1645 
1646 		update_canvas_display_mask (aswf->canvas, True);
1647 
1648 		if (set > 0)
1649 			set_flags (aswf->flags, ASW_Shaped);
1650 		return True;
1651 	}
1652 #endif
1653 	return False;
1654 }
1655 
update_wharf_folder_transprency(ASWharfFolder * aswf,Bool force)1656 void update_wharf_folder_transprency (ASWharfFolder * aswf, Bool force)
1657 {
1658 	if (aswf) {
1659 		int i = aswf->buttons_num;
1660 		while (--i >= 0) {
1661 			ASWharfButton *aswb = &(aswf->buttons[i]);
1662 			if (update_astbar_transparency (aswb->bar, aswb->canvas, force)) {
1663 				invalidate_canvas_save (aswb->canvas);
1664 				render_wharf_button (aswb);
1665 				update_canvas_display (aswb->canvas);
1666 			}
1667 			if (aswb->folder && get_flags (aswb->folder->flags, ASW_Mapped))
1668 				update_wharf_folder_transprency (aswb->folder, force);
1669 		}
1670 		/*update_wharf_folder_shape( aswf ); */
1671 	}
1672 }
1673 
change_button_focus(ASWharfButton * aswb,Bool focused)1674 void change_button_focus (ASWharfButton * aswb, Bool focused)
1675 {
1676 
1677 	if (aswb == NULL)
1678 		return;
1679 	if (focused && !get_flags (aswb->flags, ASW_Focusable))
1680 		return;
1681 
1682 	if (set_astbar_focused (aswb->bar, NULL, focused)) {
1683 		if (!swap_save_canvas (aswb->canvas)) {
1684 			render_wharf_button (aswb);
1685 		}
1686 		update_canvas_display (aswb->canvas);
1687 		update_wharf_folder_shape (aswb->parent);
1688 	}
1689 	if (focused)
1690 		WharfState.focused_button = aswb;
1691 	else if (WharfState.focused_button == aswb)
1692 		WharfState.focused_button = NULL;
1693 }
1694 
update_wharf_button_styles(ASWharfButton * aswb,Bool odd)1695 Bool update_wharf_button_styles (ASWharfButton * aswb, Bool odd)
1696 {
1697 	MyStyle *focused_style =
1698 			Scr.Look.MSWindow[odd ? FOCUSED_ODD_TILE_STYLE : FOCUSED_TILE_STYLE];
1699 	MyStyle *unfocused_style =
1700 			Scr.Look.
1701 			MSWindow[odd ? UNFOCUSED_ODD_TILE_STYLE : UNFOCUSED_TILE_STYLE];
1702 	if (unfocused_style == NULL)
1703 		unfocused_style = Scr.Look.MSWindow[UNFOCUSED_TILE_STYLE];
1704 	set_flags (aswb->flags, ASW_Focusable);
1705 
1706 	if (get_flags (Config->flags, WHARF_StretchBackground))
1707 		set_flags (aswb->bar->state, BAR_FLAGS_CROP_BACK);
1708 	else
1709 		clear_flags (aswb->bar->state, BAR_FLAGS_CROP_BACK);
1710 
1711 	if (focused_style == NULL) {
1712 		if (odd && unfocused_style == Scr.Look.MSWindow[UNFOCUSED_TILE_STYLE])
1713 			focused_style = Scr.Look.MSWindow[FOCUSED_TILE_STYLE];
1714 		if (focused_style == NULL) {
1715 			focused_style = unfocused_style;
1716 			clear_flags (aswb->flags, ASW_Focusable);
1717 		}
1718 	}
1719 
1720 	set_astbar_style_ptr (aswb->bar, -1, focused_style);
1721 	return set_astbar_style_ptr (aswb->bar, BAR_STATE_UNFOCUSED,
1722 															 unfocused_style);
1723 }
1724 
update_wharf_folder_styles(ASWharfFolder * aswf,Bool force)1725 void update_wharf_folder_styles (ASWharfFolder * aswf, Bool force)
1726 {
1727 	if (aswf) {
1728 		int i = aswf->buttons_num;
1729 		while (--i >= 0) {
1730 			ASWharfButton *aswb = &(aswf->buttons[i]);
1731 
1732 			if (update_wharf_button_styles (aswb, ((i & 0x01) == 0))) {
1733 				invalidate_canvas_save (aswb->canvas);
1734 				render_wharf_button (aswb);
1735 				update_canvas_display (aswb->canvas);
1736 			}
1737 			if (aswb->
1738 					folder /*&& get_flags( aswb->folder->flags, ASW_Mapped ) */ )
1739 				update_wharf_folder_styles (aswb->folder, force);
1740 		}
1741 		update_wharf_folder_shape (aswf);
1742 	}
1743 }
1744 
map_wharf_folder(ASWharfFolder * aswf,int gravity)1745 void map_wharf_folder (ASWharfFolder * aswf, int gravity)
1746 {
1747 	XSizeHints shints;
1748 	ExtendedWMHints extwm_hints;
1749 	ASFlagType protocols = 0;
1750 
1751 	set_folder_name (aswf, False);
1752 
1753 	shints.flags = USSize | PWinGravity;
1754 	if (get_flags (Config->set_flags, WHARF_GEOMETRY)
1755 			|| get_flags (MyArgs.geometry.flags, XValue | YValue))
1756 		shints.flags |= USPosition;
1757 	else
1758 		shints.flags |= PPosition;
1759 
1760 	shints.win_gravity = gravity;
1761 	aswf->gravity = gravity;
1762 
1763 	extwm_hints.pid = getpid ();
1764 	extwm_hints.flags = EXTWM_PID | EXTWM_TypeSet | EXTWM_StateSet;
1765 	extwm_hints.type_flags = EXTWM_TypeDock | EXTWM_TypeASModule;
1766 	extwm_hints.state_flags = EXTWM_StateSkipTaskbar;
1767 	if (aswf != WharfState.root_folder) {
1768 		XSetTransientForHint (dpy, aswf->canvas->w,
1769 													WharfState.root_folder->canvas->w);
1770 		set_flags (extwm_hints.type_flags, EXTWM_TypeDialog);
1771 	} else {
1772 		protocols = AS_DoesWmDeleteWindow;
1773 		set_client_cmd (aswf->canvas->w);
1774 	}
1775 
1776 	set_client_hints (aswf->canvas->w, NULL, &shints, AS_DoesWmDeleteWindow,
1777 										&extwm_hints);
1778 
1779 //  ASSync(False);
1780 //  sleep_a_millisec (10);
1781 	/* showing window to let user see that we are doing something */
1782 	map_canvas_window (aswf->canvas, True);
1783 #ifdef SHAPE
1784 	if (get_flags (Config->flags, WHARF_ANIMATE)) {
1785 		XShapeCombineRectangles (dpy, aswf->canvas->w, ShapeBounding, 0, 0,
1786 														 &(aswf->boundary), 1, ShapeSet, Unsorted);
1787 		aswf->animate_from_w = 1;
1788 		aswf->animate_from_h = 1;
1789 		set_flags (aswf->flags, ASW_AnimationPending);
1790 	}
1791 #endif
1792 	LOCAL_DEBUG_OUT ("mapping folder window for folder %p", aswf);
1793 	/* final cleanup */
1794 //    ASSync( False );
1795 //    sleep_a_millisec (10);                                 /* we have to give AS a chance to spot us */
1796 }
1797 
1798 void
place_wharf_buttons(ASWharfFolder * aswf,int * total_width_return,int * total_height_return)1799 place_wharf_buttons (ASWharfFolder * aswf, int *total_width_return,
1800 										 int *total_height_return)
1801 {
1802 	int max_width = 0, max_height = 0;
1803 	int x = 0, y = 0;
1804 	int i;
1805 	Bool fit_contents = get_flags (Config->flags, WHARF_FitContents);
1806 	Bool needs_shaping = False;
1807 	Bool reverse_order =
1808 			get_flags (aswf->flags,
1809 								 ASW_ReverseOrder) ? aswf->buttons_num - 1 : -1;
1810 	int button_offset_x = 0;
1811 	int button_offset_y = 0;
1812 
1813 	*total_width_return = 0;
1814 	*total_height_return = 0;
1815 
1816 	LOCAL_DEBUG_OUT ("flags 0x%lX, reverse_order = %d", aswf->flags,
1817 									 reverse_order);
1818 	if (get_flags (aswf->flags, ASW_Vertical)) {
1819 		int columns = (aswf == WharfState.root_folder) ? Config->columns : 1;
1820 		int buttons_per_column = (aswf->buttons_num + columns - 1) / columns;
1821 		int bc = 0;
1822 
1823 		if (buttons_per_column > Scr.MyDisplayHeight / 64) {	/* too many buttons - let's add some columns, shall we */
1824 			int avg_height = 0;
1825 			for (i = 0; i < aswf->buttons_num; ++i)
1826 				avg_height +=
1827 						(!get_flags (aswf->buttons[0].flags, ASW_MaxSwallow)) ? aswf->
1828 						buttons[0].desired_height : 64;
1829 			avg_height = avg_height / aswf->buttons_num;
1830 
1831 			if (buttons_per_column > Scr.MyDisplayHeight / avg_height) {
1832 				buttons_per_column = Scr.MyDisplayHeight / avg_height - 1;
1833 				if (buttons_per_column <= 4)
1834 					buttons_per_column = min (4, aswf->buttons_num);
1835 				columns =
1836 						(aswf->buttons_num + buttons_per_column -
1837 						 1) / buttons_per_column;
1838 			}
1839 		}
1840 		for (i = 0; i < aswf->buttons_num; ++i) {
1841 			ASWharfButton *aswb =
1842 					&(aswf->buttons[reverse_order >= 0 ? reverse_order - i : i]);
1843 			int height;
1844 
1845 			if (bc == 0) {
1846 				register int k = i + buttons_per_column;
1847 				if (k > aswf->buttons_num)
1848 					k = aswf->buttons_num;
1849 				max_width = 0;
1850 				max_height = 0;
1851 				while (--k >= i) {
1852 					register ASWharfButton *aswb =
1853 							&(aswf->buttons[reverse_order >= 0 ? reverse_order - k : k]);
1854 					if (max_width < aswb->desired_width)
1855 						max_width = aswb->desired_width;
1856 					if (max_height < aswb->desired_height
1857 							&& !get_flags (aswb->flags, ASW_MaxSwallow))
1858 						max_height = aswb->desired_height;
1859 				}
1860 				LOCAL_DEBUG_OUT ("max_size(%dx%d)", max_width, max_height);
1861 				if (max_width + button_offset_x < 0)
1862 					button_offset_x = 0;
1863 			}
1864 			height = (get_flags (aswb->flags, ASW_MaxSwallow)
1865 								|| fit_contents) ? aswb->desired_height : max_height;
1866 			if (get_flags (Config->flags, WHARF_ShapeToContents)) {
1867 				int dx = max_width - aswb->desired_width;
1868 				int dy = height - aswb->desired_height;
1869 				if (get_flags (Config->AlignContents, ALIGN_RIGHT) == 0)
1870 					dx = 0;
1871 				else if (get_flags (Config->AlignContents, ALIGN_LEFT))
1872 					dx = dx >> 1;
1873 				if (get_flags (Config->AlignContents, ALIGN_BOTTOM) == 0)
1874 					dy = 0;
1875 				else if (get_flags (Config->AlignContents, ALIGN_TOP))
1876 					dy = dy >> 1;
1877 				aswb->folder_x = x + dx + button_offset_x;
1878 				aswb->folder_y = y + dy + button_offset_y;
1879 				aswb->folder_width = aswb->desired_width;
1880 				aswb->folder_height = aswb->desired_height;
1881 				if (aswb->desired_width != max_width)
1882 					needs_shaping = True;
1883 			} else {
1884 				aswb->folder_x = x + button_offset_x;
1885 				aswb->folder_y = y + button_offset_y;
1886 				aswb->folder_width = max_width;
1887 				aswb->folder_height = height;
1888 			}
1889 			moveresize_canvas (aswb->canvas, aswb->folder_x, aswb->folder_y,
1890 												 aswb->folder_width, aswb->folder_height);
1891 			y += height + button_offset_y;
1892 			if (++bc >= buttons_per_column) {
1893 				*total_width_return += max_width + button_offset_x;
1894 				if (*total_height_return < y)
1895 					*total_height_return = y;
1896 				x += max_width;
1897 				y = 0;
1898 				bc = 0;
1899 			}
1900 		}
1901 		if (columns * buttons_per_column > aswf->buttons_num) {
1902 			*total_width_return += max_width + button_offset_x;
1903 			if (*total_height_return < y)
1904 				*total_height_return = y;
1905 		}
1906 
1907 	} else {
1908 		int rows = (aswf == WharfState.root_folder) ? Config->rows : 1;
1909 		int buttons_per_row = (aswf->buttons_num + rows - 1) / rows, br = 0;
1910 
1911 		if (buttons_per_row > Scr.MyDisplayWidth / 64) {	/* too many buttons - let's add some columns, shall we */
1912 			int avg_width = 0;
1913 			for (i = 0; i < aswf->buttons_num; ++i)
1914 				avg_width += aswf->buttons[0].desired_width;
1915 			avg_width = avg_width / aswf->buttons_num;
1916 
1917 			if (buttons_per_row > Scr.MyDisplayWidth / avg_width) {
1918 				buttons_per_row = Scr.MyDisplayWidth / avg_width - 1;
1919 				if (buttons_per_row <= 4)
1920 					buttons_per_row = min (4, aswf->buttons_num);
1921 				rows = (aswf->buttons_num + buttons_per_row - 1) / buttons_per_row;
1922 			}
1923 		}
1924 
1925 		for (i = 0; i < aswf->buttons_num; ++i) {
1926 			ASWharfButton *aswb =
1927 					&(aswf->buttons[reverse_order >= 0 ? reverse_order - i : i]);
1928 			int width;
1929 
1930 			if (br == 0) {
1931 				register int k = i + buttons_per_row;
1932 				if (k > aswf->buttons_num)
1933 					k = aswf->buttons_num;
1934 				max_width = 0;
1935 				max_height = 0;
1936 				while (--k >= i) {
1937 					register ASWharfButton *aswb =
1938 							&(aswf->buttons[reverse_order >= 0 ? reverse_order - k : k]);
1939 					if (max_width < aswb->desired_width
1940 							&& !get_flags (aswb->flags, ASW_MaxSwallow))
1941 						max_width = aswb->desired_width;
1942 					if (max_height < aswb->desired_height)
1943 						max_height = aswb->desired_height;
1944 				}
1945 				LOCAL_DEBUG_OUT ("max_size(%dx%d)", max_width, max_height);
1946 			}
1947 
1948 			width = (get_flags (aswb->flags, ASW_MaxSwallow)
1949 							 || fit_contents) ? aswb->desired_width : max_width;
1950 			if (get_flags (Config->flags, WHARF_ShapeToContents)) {
1951 				int dx = width - aswb->desired_width;
1952 				int dy = max_height - aswb->desired_height;
1953 				if (get_flags (Config->AlignContents, ALIGN_RIGHT) == 0)
1954 					dx = 0;
1955 				else if (get_flags (Config->AlignContents, ALIGN_LEFT))
1956 					dx = dx >> 1;
1957 				if (get_flags (Config->AlignContents, ALIGN_BOTTOM) == 0)
1958 					dy = 0;
1959 				else if (get_flags (Config->AlignContents, ALIGN_TOP))
1960 					dy = dy >> 1;
1961 				aswb->folder_x = x + dx;
1962 				aswb->folder_y = y + dy;
1963 				aswb->folder_width = aswb->desired_width;
1964 				aswb->folder_height = aswb->desired_height;
1965 				if (aswb->desired_height != max_height)
1966 					needs_shaping = True;
1967 			} else {
1968 				aswb->folder_x = x;
1969 				aswb->folder_y = y;
1970 				aswb->folder_width = width;
1971 				aswb->folder_height = max_height;
1972 			}
1973 			moveresize_canvas (aswb->canvas, aswb->folder_x, aswb->folder_y,
1974 												 aswb->folder_width, aswb->folder_height);
1975 			x += width;
1976 			if (++br >= buttons_per_row) {
1977 				if (*total_width_return < x)
1978 					*total_width_return = x;
1979 				*total_height_return += max_height;
1980 				x = 0;
1981 				y += max_height;
1982 				br = 0;
1983 			}
1984 		}
1985 		if (rows * buttons_per_row > aswf->buttons_num) {
1986 			if (*total_width_return < x)
1987 				*total_width_return = x;
1988 			*total_height_return += max_height;
1989 		}
1990 	}
1991 	LOCAL_DEBUG_OUT ("total_size_return(%dx%d)", *total_width_return,
1992 									 *total_height_return);
1993 
1994 	ASSync (False);
1995 	WharfState.buttons_render_pending = aswf->buttons_num;
1996 	if (needs_shaping)
1997 		set_flags (aswf->flags, ASW_NeedsShaping);
1998 	else
1999 		clear_flags (aswf->flags, ASW_NeedsShaping);
2000 }
2001 
2002 
2003 void
clamp_animation_rect(ASWharfFolder * aswf,int from_width,int from_height,int to_width,int to_height,XRectangle * rect,Bool reverse)2004 clamp_animation_rect (ASWharfFolder * aswf, int from_width,
2005 											int from_height, int to_width, int to_height,
2006 											XRectangle * rect, Bool reverse)
2007 {
2008 	if (get_flags (aswf->flags, ASW_Vertical)) {
2009 		Bool down = (aswf->gravity == SouthWestGravity
2010 								 || aswf->gravity == SouthEastGravity);
2011 
2012 		if (reverse)
2013 			down = !down;
2014 
2015 		if (down)
2016 			rect->y = max (to_height, from_height) - (short)rect->height;
2017 		if (rect->y < 0) {
2018 			rect->y = 0;
2019 			rect->height = to_height;
2020 		}
2021 	} else {
2022 		Bool right = (aswf->gravity == NorthEastGravity
2023 									|| aswf->gravity == SouthEastGravity);
2024 		if (reverse)
2025 			right = !right;
2026 		if (right)
2027 			rect->x = max (to_width, from_width) - (short)rect->width;
2028 		if (rect->x < 0) {
2029 			rect->x = 0;
2030 			rect->width = to_width;
2031 		}
2032 	}
2033 }
2034 
2035 void
animate_wharf_loop(ASWharfFolder * aswf,int from_width,int from_height,int to_width,int to_height,Bool reverse)2036 animate_wharf_loop (ASWharfFolder * aswf, int from_width, int from_height,
2037 										int to_width, int to_height, Bool reverse)
2038 {
2039 	int i, steps;
2040 	XRectangle rect;
2041 
2042 	steps =
2043 			get_flags (Config->set_flags,
2044 								 WHARF_ANIMATE_STEPS) ? Config->animate_steps : 12;
2045 	LOCAL_DEBUG_OUT ("steps = %d", steps);
2046 	for (i = 0; i < steps; ++i) {
2047 		rect.x = rect.y = 0;
2048 		rect.width =
2049 				get_flags (aswf->flags,
2050 									 ASW_Vertical) ? to_width : from_width + ((to_width -
2051 																														 from_width) /
2052 																														steps) * (i +
2053 																																			1);
2054 		rect.height =
2055 				get_flags (aswf->flags,
2056 									 ASW_Vertical) ? from_height + ((to_height -
2057 																									 from_height) / steps) *
2058 				(i + 1) : to_height;
2059 
2060 		clamp_animation_rect (aswf, from_width, from_height, to_width,
2061 													to_height, &rect, reverse);
2062 
2063 		LOCAL_DEBUG_OUT ("boundary = %dx%d%+d%+d, canvas = %dx%d\n",
2064 										 rect.width, rect.height, rect.x, rect.y,
2065 										 aswf->canvas->width, aswf->canvas->height);
2066 		if (rect.x + rect.width > aswf->canvas->width ||
2067 				rect.y + rect.height > aswf->canvas->height) {
2068 			return;
2069 		}
2070 
2071 
2072 		aswf->boundary = rect;
2073 		update_wharf_folder_shape (aswf);
2074 		ASSync (False);
2075 
2076 		if (get_flags (Config->set_flags, WHARF_ANIMATE_DELAY)
2077 				&& Config->animate_delay > 0)
2078 			sleep_a_millisec (Config->animate_delay + 1);
2079 		else
2080 			sleep_a_millisec (50);
2081 	}
2082 
2083 	rect.x = rect.y = 0;
2084 	rect.width = to_width;
2085 	rect.height = to_height;
2086 	clamp_animation_rect (aswf, from_width, from_height, to_width, to_height,
2087 												&rect, reverse);
2088 
2089 	LOCAL_DEBUG_OUT ("boundary = %dx%d%+d%+d, canvas = %dx%d\n",
2090 									 rect.width, rect.height, rect.x, rect.y,
2091 									 aswf->canvas->width, aswf->canvas->height);
2092 
2093 	aswf->boundary = rect;
2094 	update_wharf_folder_shape (aswf);
2095 }
2096 
2097 void
animate_wharf(ASWharfFolder * aswf,int * new_width_return,int * new_height_return)2098 animate_wharf (ASWharfFolder * aswf, int *new_width_return,
2099 							 int *new_height_return)
2100 {
2101 	int new_width = aswf->canvas->width;
2102 	int new_height = aswf->canvas->height;
2103 
2104 	if (aswf->animation_dir < 0) {
2105 		if (get_flags (aswf->flags, ASW_Vertical)) {
2106 			if (aswf->animation_steps <= 1)
2107 				new_height = 0;
2108 			else {
2109 				new_height =
2110 						(new_height * (aswf->animation_steps - 1)) /
2111 						aswf->animation_steps;
2112 				if (new_height == aswf->canvas->height)
2113 					--new_height;
2114 			}
2115 		} else {
2116 			if (aswf->animation_steps <= 1)
2117 				new_width = 0;
2118 			else {
2119 				new_width =
2120 						(new_width * (aswf->animation_steps - 1)) /
2121 						aswf->animation_steps;
2122 				if (new_width == aswf->canvas->width)
2123 					--new_width;
2124 			}
2125 		}
2126 	} else {
2127 		new_width = aswf->total_width;
2128 		new_height = aswf->total_height;
2129 		if (get_flags (aswf->flags, ASW_Vertical)) {
2130 			if (aswf->animation_steps <= 1)
2131 				new_height = aswf->total_height;
2132 			else {
2133 				new_height =
2134 						aswf->canvas->height +
2135 						((aswf->total_height -
2136 							aswf->canvas->height) / aswf->animation_steps);
2137 				if (new_height == aswf->canvas->height
2138 						&& new_height < aswf->total_height)
2139 					++new_height;
2140 			}
2141 		} else {
2142 			if (aswf->animation_steps <= 1)
2143 				new_width = aswf->total_width;
2144 			else {
2145 				new_width =
2146 						aswf->canvas->width +
2147 						((aswf->total_width -
2148 							aswf->canvas->width) / aswf->animation_steps);
2149 				if (new_width == aswf->canvas->width
2150 						&& new_width < aswf->total_width)
2151 					++new_width;
2152 			}
2153 		}
2154 	}
2155 	--(aswf->animation_steps);
2156 
2157 	*new_width_return = new_width;
2158 	*new_height_return = new_height;
2159 }
2160 
2161 Bool
display_wharf_folder(ASWharfFolder * aswf,int left,int top,int right,int bottom)2162 display_wharf_folder (ASWharfFolder * aswf, int left, int top, int right,
2163 											int bottom)
2164 {
2165 	Bool east = get_flags (Config->geometry.flags, XNegative);
2166 	Bool south = get_flags (Config->geometry.flags, YNegative);
2167 	int x, y, width = 0, height = 0;
2168 	int total_width = 0, total_height = 0;
2169 	int old_x, old_y;
2170 	Bool reverse = False;
2171 	if (AS_ASSERT (aswf) ||
2172 			(get_flags (aswf->flags, ASW_Mapped)
2173 			 && !get_flags (aswf->flags, ASW_Withdrawn)))
2174 		return False;
2175 
2176 	if (MyArgs.gravity == SouthWestGravity
2177 			|| MyArgs.gravity == SouthEastGravity)
2178 		south = True;
2179 	if (MyArgs.gravity == NorthEastGravity
2180 			|| MyArgs.gravity == SouthEastGravity)
2181 		east = True;
2182 
2183 	if (aswf != WharfState.root_folder) {
2184 		if (get_flags (aswf->flags, ASW_Vertical)) {
2185 			if (south)
2186 				set_flags (aswf->flags, ASW_ReverseOrder);
2187 		} else {
2188 			if (east)
2189 				set_flags (aswf->flags, ASW_ReverseOrder);
2190 		}
2191 	}
2192 	place_wharf_buttons (aswf, &total_width, &total_height);
2193 
2194 	if (total_width == 0 || total_height == 0)
2195 		return False;;
2196 	if (total_width > Scr.MyDisplayWidth)
2197 		total_width = Scr.MyDisplayWidth;
2198 	if (total_height > Scr.MyDisplayHeight)
2199 		total_height = Scr.MyDisplayHeight;
2200 
2201 	aswf->total_width = total_width;
2202 	aswf->total_height = total_height;
2203 
2204 	if (left < 0)
2205 		east = False;
2206 	else if (left < total_width)
2207 		east = !(Scr.MyDisplayWidth > right
2208 						 && (Scr.MyDisplayWidth - right > total_width
2209 								 || left < Scr.MyDisplayWidth - right));
2210 
2211 	if (east) {
2212 		if (left < total_width)
2213 			left = total_width;
2214 	} else if (Scr.MyDisplayWidth - right < total_width)
2215 		right = Scr.MyDisplayWidth - total_width;
2216 
2217 	if (south) {
2218 		if (top < total_height)
2219 			top = total_height;
2220 	} else if (Scr.MyDisplayHeight - bottom < total_height)
2221 		bottom = Scr.MyDisplayHeight - total_width;
2222 
2223 	if (south && top < total_height)
2224 		south = !(Scr.MyDisplayHeight > bottom
2225 							&& (Scr.MyDisplayHeight - bottom > total_height
2226 									|| top < Scr.MyDisplayHeight - bottom));
2227 
2228 #if 0
2229 	if (aswf->animation_steps > 0) {
2230 		aswf->animation_dir = 1;
2231 		aswf->canvas->width = aswf->canvas->height = 1;
2232 		animate_wharf (aswf, &width, &height);
2233 	}
2234 #endif
2235 	if (width == 0)
2236 		width = total_width;
2237 	if (height == 0)
2238 		height = total_height;
2239 	LOCAL_DEBUG_OUT ("animation_steps(%d)->size(%dx%d)->total_size(%dx%d)",
2240 									 aswf->animation_steps, width, height, total_width,
2241 									 total_height);
2242 
2243 	if (get_flags (aswf->flags, ASW_Vertical)) {
2244 		x = east ? right - width : left;
2245 		y = south ? top - height : bottom;
2246 		if (top != bottom)
2247 			y += south ? -Config->FolderOffset : Config->FolderOffset;
2248 		if (left != right)
2249 			x += east ? -Config->OrthogonalFolderOffset : Config->
2250 					OrthogonalFolderOffset;
2251 	} else {
2252 		x = east ? left - width : right;
2253 		y = south ? bottom - height : top;
2254 		if (left != right)
2255 			x += east ? -Config->FolderOffset : Config->FolderOffset;
2256 		if (top != bottom)
2257 			y += south ? -Config->OrthogonalFolderOffset : Config->
2258 					OrthogonalFolderOffset;
2259 	}
2260 	LOCAL_DEBUG_OUT
2261 			("calculated pos(%+d%+d), east(%d), south(%d), total_size(%dx%d)", x,
2262 			 y, east, south, total_width, total_height);
2263 	if (east) {
2264 		if (x + width > Scr.MyDisplayWidth)
2265 			x = Scr.MyDisplayWidth - width;
2266 	} else {
2267 		if (x + total_width > Scr.MyDisplayWidth)
2268 			x = Scr.MyDisplayWidth - total_width;
2269 	}
2270 	if (south) {
2271 		if (y + height > Scr.MyDisplayHeight)
2272 			y = Scr.MyDisplayHeight - height;
2273 	} else {
2274 		if (y + total_height > Scr.MyDisplayHeight)
2275 			y = Scr.MyDisplayHeight - total_height;
2276 	}
2277 	/* if user has configured us so that we'll have to overlap ourselves -
2278 	   then its theirs fault - we cannot account for all situations */
2279 
2280 	LOCAL_DEBUG_OUT ("corrected  pos(%+d%+d)", x, y);
2281 	LOCAL_DEBUG_OUT ("flags 0x%lX, reverse_order = %d", aswf->flags,
2282 									 get_flags (aswf->flags,
2283 															ASW_ReverseOrder) ? aswf->buttons_num -
2284 									 1 : -1);
2285 
2286 	old_x = aswf->canvas->root_x;
2287 	old_y = aswf->canvas->root_y;
2288 	moveresize_canvas (aswf->canvas, x, y, width, height);
2289 	set_wharf_clip_area (aswf, left, top);
2290 
2291 	aswf->animate_to_w = width;
2292 	aswf->animate_to_h = height;
2293 	if (get_flags (aswf->flags, ASW_Vertical))
2294 		reverse = ((old_y > y && !south) || (old_y < y && south));
2295 	else
2296 		reverse = ((old_x > x && !east) || (old_x < x && east));
2297 
2298 	if (get_flags (Config->flags, WHARF_ANIMATE)) {
2299 		set_flags (aswf->flags, ASW_UseBoundary | ASW_AnimationPending);
2300 		if (reverse)
2301 			set_flags (aswf->flags, ASW_ReverseAnimation);
2302 		aswf->animate_from_w =
2303 				get_flags (aswf->flags, ASW_Vertical) ? aswf->canvas->width : 0;
2304 		aswf->animate_from_h =
2305 				get_flags (aswf->flags, ASW_Vertical) ? 0 : aswf->canvas->height;
2306 		aswf->boundary.x = aswf->boundary.y = 0;
2307 		if (get_flags (aswf->flags, ASW_Vertical)) {
2308 			if (south)
2309 				aswf->boundary.y = height - 1;
2310 			aswf->boundary.height = 1;
2311 			aswf->boundary.width = 1;
2312 		} else {
2313 			if (east)
2314 				aswf->boundary.x = width - 1;
2315 			aswf->boundary.height = 1;
2316 			aswf->boundary.width = 1;
2317 
2318 /* 			aswf->boundary.width = (aswf->gravity == NorthWestGravity || aswf->gravity == SouthWestGravity )?aswf->canvas->width:1 ;
2319 			aswf->boundary.height = (aswf->boundary.width == 1)?aswf->canvas->height:1 ;
2320  */
2321 		}
2322 #ifdef SHAPE
2323 		LOCAL_DEBUG_OUT ("boundary pos(%dx%d%+d%+d) shaping window %lX",
2324 										 aswf->boundary.width, aswf->boundary.height,
2325 										 aswf->boundary.x, aswf->boundary.y, aswf->canvas->w);
2326 		/* fprintf( stderr, "setting boundary to 1x1\n" );  */
2327 		XShapeCombineRectangles (dpy, aswf->canvas->w, ShapeBounding, 0, 0,
2328 														 &(aswf->boundary), 1, ShapeSet, Unsorted);
2329 #endif
2330 	}
2331 
2332 	map_wharf_folder (aswf,
2333 										east ? (south ? SouthEastGravity : NorthEastGravity)
2334 										: (south ? SouthWestGravity : NorthWestGravity));
2335 
2336 	set_flags (aswf->flags, ASW_Mapped);
2337 	clear_flags (aswf->flags, ASW_Withdrawn);
2338 	ASSync (False);
2339 
2340 	if (aswf->canvas->width == width && aswf->canvas->height == height
2341 			&& get_flags (Config->flags, WHARF_ANIMATE)) {
2342 		animate_wharf_loop (aswf, aswf->animate_from_w, aswf->animate_from_h,
2343 												aswf->animate_to_w, aswf->animate_to_h, reverse);
2344 		clear_flags (aswf->flags, ASW_UseBoundary | ASW_AnimationPending);
2345 	}
2346 
2347 	return True;
2348 }
2349 
2350 static inline void unmap_wharf_folder (ASWharfFolder * aswf);
2351 
unmap_wharf_subfolders(ASWharfFolder * aswf)2352 static inline void unmap_wharf_subfolders (ASWharfFolder * aswf)
2353 {
2354 	int i = aswf->buttons_num;
2355 	while (--i >= 0) {
2356 		if (aswf->buttons[i].folder &&
2357 				get_flags (aswf->buttons[i].folder->flags, ASW_Mapped))
2358 			unmap_wharf_folder (aswf->buttons[i].folder);
2359 	}
2360 }
2361 
unmap_wharf_folder(ASWharfFolder * aswf)2362 static inline void unmap_wharf_folder (ASWharfFolder * aswf)
2363 {
2364 	LOCAL_DEBUG_OUT ("unmapping canvas %p at %dx%d%+d%+d", aswf->canvas,
2365 									 aswf->canvas->width, aswf->canvas->height,
2366 									 aswf->canvas->root_x, aswf->canvas->root_y);
2367 	unmap_canvas_window (aswf->canvas);
2368 	/*moveresize_canvas( aswf->canvas, -1000, -1000, 1, 1 ); to make sure we get ConfigureNotify next time we map the folder again */
2369 	clear_flags (aswf->flags, ASW_Mapped);
2370 
2371 	unmap_wharf_subfolders (aswf);
2372 }
2373 
withdraw_wharf_folder(ASWharfFolder * aswf)2374 void withdraw_wharf_folder (ASWharfFolder * aswf)
2375 {
2376 	LOCAL_DEBUG_OUT ("withdrawing folder %p", aswf);
2377 	if (AS_ASSERT (aswf))
2378 		return;
2379 	LOCAL_DEBUG_OUT ("folder->flags(%lX)", aswf->flags);
2380 	if (!get_flags (aswf->flags, ASW_Mapped))
2381 		return;
2382 
2383 	withdraw_wharf_subfolders (aswf);
2384 	ASSync (False);
2385 
2386 	if (get_flags (Config->flags, WHARF_ANIMATE)) {
2387 		set_flags (aswf->flags, ASW_UseBoundary);
2388 		aswf->boundary.x = aswf->boundary.y = 0;
2389 		aswf->boundary.width = aswf->canvas->width;
2390 		aswf->boundary.height = aswf->canvas->height;
2391 
2392 		if (get_flags (aswf->flags, ASW_Vertical))
2393 			animate_wharf_loop (aswf, aswf->canvas->width, aswf->canvas->height,
2394 													aswf->canvas->width, 1, False);
2395 		else
2396 			animate_wharf_loop (aswf, aswf->canvas->width, aswf->canvas->height,
2397 													1, aswf->canvas->height, False);
2398 	}
2399 	LOCAL_DEBUG_OUT ("unmapping folder %p", aswf);
2400 	unmap_wharf_folder (aswf);
2401 	ASSync (False);
2402 	sleep_a_millisec (10);
2403 }
2404 
withdraw_wharf_subfolders(ASWharfFolder * aswf)2405 static inline void withdraw_wharf_subfolders (ASWharfFolder * aswf)
2406 {
2407 	int i = aswf->buttons_num;
2408 	while (--i >= 0) {
2409 		if (aswf->buttons[i].swallowed) {
2410 			ASCanvas *sc = aswf->buttons[i].swallowed->current;
2411 			if (sc) {
2412 				XClientMessageEvent ev;
2413 				ev.type = ClientMessage;
2414 				ev.window = sc->w;
2415 				ev.message_type = _AS_WHARF_CLOSE;
2416 				ev.format = 32;
2417 				ev.data.l[0] = _AS_WHARF_CLOSE;
2418 				ev.data.l[1] = CurrentTime;
2419 				XSendEvent (dpy, sc->w, False, 0, (XEvent *) & ev);
2420 			}
2421 		}
2422 		if (aswf->buttons[i].folder &&
2423 				get_flags (aswf->buttons[i].folder->flags, ASW_Mapped))
2424 			withdraw_wharf_folder (aswf->buttons[i].folder);
2425 	}
2426 }
2427 
2428 
2429 
display_main_folder()2430 Bool display_main_folder ()
2431 {
2432 	int left = Config->geometry.x;
2433 	int top = Config->geometry.y;
2434 
2435 	if (get_flags (Config->geometry.flags, XNegative))
2436 		left += Scr.MyDisplayWidth;
2437 
2438 	if (get_flags (Config->geometry.flags, YNegative))
2439 		top += Scr.MyDisplayHeight;
2440 	return display_wharf_folder (WharfState.root_folder, left, top, left,
2441 															 top);
2442 }
2443 
check_pending_swallow(ASWharfFolder * aswf)2444 Bool check_pending_swallow (ASWharfFolder * aswf)
2445 {
2446 	if (aswf) {
2447 		int i = aswf->buttons_num;
2448 		/* checking buttons : */
2449 		while (--i >= 0)
2450 			if (get_flags (aswf->buttons[i].flags, ASW_SwallowTarget))
2451 				return True;
2452 		/* checking subfolders : */
2453 		i = aswf->buttons_num;
2454 		while (--i >= 0)
2455 			if (aswf->buttons[i].folder)
2456 				if (check_pending_swallow (aswf->buttons[i].folder))
2457 					return True;
2458 	}
2459 	return False;
2460 }
2461 
exec_pending_swallow(ASWharfFolder * aswf)2462 void exec_pending_swallow (ASWharfFolder * aswf)
2463 {
2464 	if (aswf) {
2465 		int i = aswf->buttons_num;
2466 		int sent = 0;
2467 		while (--i >= 0) {
2468 			if (get_flags (aswf->buttons[i].flags, ASW_SwallowTarget) &&
2469 					aswf->buttons[i].swallowed == NULL) {
2470 				int k;
2471 				for (k = 0; k < 5; ++k)
2472 					if (aswf->buttons[i].fdata[k]
2473 							&& IsSwallowFunc (aswf->buttons[i].fdata[k]->func)) {
2474 						SendCommand (aswf->buttons[i].fdata[k], 0);
2475 						++sent;
2476 						break;
2477 					}
2478 			}
2479 			if (aswf->buttons[i].folder)
2480 				exec_pending_swallow (aswf->buttons[i].folder);
2481 		}
2482 		if (sent)
2483 			sleep_a_millisec (200);		/* give AS a chance to handle requests */
2484 	}
2485 }
2486 
2487 void
grab_swallowed_canvas_btn(ASCanvas * canvas,int button,int non_lock_mods)2488 grab_swallowed_canvas_btn (ASCanvas * canvas, int button,
2489 													 int non_lock_mods)
2490 {
2491 	register int i = 0;
2492 	register unsigned int *mods = lock_mods;
2493 
2494 	LOCAL_DEBUG_OUT ("%p,%d,0x%x", canvas, button, non_lock_mods);
2495 
2496 	if (AS_ASSERT (canvas))
2497 		return;
2498 	do {
2499 		/* grab button 1 if this button performs an action */
2500 		XGrabButton (dpy, button, mods[i] | non_lock_mods,
2501 								 canvas->w,
2502 								 False, ButtonPressMask | ButtonReleaseMask,
2503 								 GrabModeAsync, GrabModeAsync, None, None);
2504 #if !defined(NO_DEBUG_OUTPUT)
2505 		ASSync (False);
2506 		fprintf (stderr, "line = %d, mods = 0x%X\n", __LINE__, mods[i]);
2507 #endif
2508 		if (mods[i] == 0)
2509 			return;
2510 	} while (++i < MAX_LOCK_MODS);
2511 
2512 	XGrabButton (dpy, button, non_lock_mods,
2513 							 canvas->w,
2514 							 False, ButtonPressMask | ButtonReleaseMask,
2515 							 GrabModeAsync, GrabModeAsync, None, None);
2516 #if !defined(NO_DEBUG_OUTPUT)
2517 	ASSync (False);
2518 	fprintf (stderr, "line = %d, mods = 0\n", __LINE__);
2519 #endif
2520 }
2521 
2522 
2523 void
grab_swallowed_canvas_btns(ASCanvas * canvas,ASWharfButton * aswb,Bool withdraw_btn)2524 grab_swallowed_canvas_btns (ASCanvas * canvas, ASWharfButton * aswb,
2525 														Bool withdraw_btn)
2526 {
2527 	if (aswb->folder != NULL)
2528 		grab_swallowed_canvas_btn (canvas, Button1, 0);
2529 
2530 	if (withdraw_btn && aswb->parent == WharfState.root_folder) {
2531 		grab_swallowed_canvas_btn (canvas, Button3, ControlMask);
2532 		grab_swallowed_canvas_btn (canvas, Button3, 0);
2533 	} else if (aswb->fdata[Button3 - Button1])
2534 		grab_swallowed_canvas_btn (canvas, Button3, 0);
2535 
2536 	if (aswb->fdata[Button2 - Button1])
2537 		grab_swallowed_canvas_btn (canvas, Button2, 0);
2538 	if (aswb->fdata[Button4 - Button1])
2539 		grab_swallowed_canvas_btn (canvas, Button4, 0);
2540 	if (aswb->fdata[Button5 - Button1])
2541 		grab_swallowed_canvas_btn (canvas, Button5, 0);
2542 }
2543 
update_wharf_folder_size(ASWharfFolder * aswf)2544 void update_wharf_folder_size (ASWharfFolder * aswf)
2545 {
2546 	int total_width = 1, total_height = 1;
2547 	if (!get_flags (aswf->flags, ASW_Mapped))
2548 		return;
2549 	place_wharf_buttons (aswf, &total_width, &total_height);
2550 
2551 	if (total_width != 0 && total_height != 0) {
2552 		if (total_width > Scr.MyDisplayWidth)
2553 			total_width = Scr.MyDisplayWidth;
2554 		if (total_height > Scr.MyDisplayHeight)
2555 			total_height = Scr.MyDisplayHeight;
2556 
2557 		aswf->total_width = total_width;
2558 		aswf->total_height = total_height;
2559 	}
2560 	resize_canvas (aswf->canvas, total_width, total_height);
2561 }
2562 
send_swallowed_configure_notify(ASWharfButton * aswb)2563 void send_swallowed_configure_notify (ASWharfButton * aswb)
2564 {
2565 	LOCAL_DEBUG_CALLER_OUT ("%p,%p", aswb, aswb->swallowed);
2566 	if (aswb->swallowed) {
2567 		send_canvas_configure_notify (aswb->canvas, aswb->swallowed->current);
2568 	}
2569 }
2570 
2571 
make_swallow_pad(Bool pad_before,Bool pad_after,int cell_size,int tile_size)2572 int make_swallow_pad (Bool pad_before, Bool pad_after, int cell_size,
2573 											int tile_size)
2574 {
2575 	if (!pad_before)
2576 		return 0;
2577 	if (!pad_after)
2578 		return cell_size - tile_size;
2579 	return (cell_size - tile_size) / 2;
2580 }
2581 
2582 
check_swallow_window(ASWindowData * wd)2583 void check_swallow_window (ASWindowData * wd)
2584 {
2585 	ASWharfFolder *aswf = NULL;
2586 	ASWharfButton *aswb = NULL;
2587 	Window w;
2588 	int try_num = 0;
2589 	Bool withdraw_btn;
2590 	ASCanvas *nc;
2591 	int swidth, sheight;
2592 	Window icon_w = None;
2593 	int user_set_height = 0, user_set_width = 0;
2594 	XWMHints *wm_hints;
2595 	XSizeHints *wm_normal_hints;
2596 
2597 	if (wd == NULL || !get_flags (wd->state_flags, AS_Mapped))
2598 		return;
2599 	LOCAL_DEBUG_OUT
2600 			("name(\"%s\")->icon_name(\"%s\")->res_class(\"%s\")->res_name(\"%s\")",
2601 			 wd->window_name, wd->icon_name, wd->res_class, wd->res_name);
2602 	if ((aswb = fetch_swallow_target (wd->window_name)) == NULL)
2603 		if ((aswb = fetch_swallow_target (wd->icon_name)) == NULL)
2604 			if ((aswb = fetch_swallow_target (wd->res_class)) == NULL)
2605 				if ((aswb = fetch_swallow_target (wd->res_name)) == NULL)
2606 					return;
2607 	LOCAL_DEBUG_OUT ("swallow target is %p, swallowed = %p", aswb,
2608 									 aswb->swallowed);
2609 	aswf = aswb->parent;
2610 	if (aswb->swallowed != NULL)
2611 		return;
2612 	/* do the actuall swallowing here : */
2613 	grab_server ();
2614 	/* first lets check if window is still not swallowed : it should have no more then 2 parents before root */
2615 	w = get_parent_window (wd->client);
2616 	LOCAL_DEBUG_OUT ("first parent %lX, root %lX", w, Scr.Root);
2617 	while (w == Scr.Root && ++try_num < 10) {	/* we should wait for AfterSTep to complete AddWindow protocol */
2618 		/* do the actuall swallowing here : */
2619 		ungrab_server ();
2620 		sleep_a_millisec (200 * try_num);
2621 		grab_server ();
2622 		w = get_parent_window (wd->client);
2623 		LOCAL_DEBUG_OUT ("attempt %d:first parent %lX, root %lX", try_num, w,
2624 										 Scr.Root);
2625 	}
2626 	if (w == Scr.Root) {
2627 		ungrab_server ();
2628 		return;
2629 	}
2630 	if (w != None)
2631 		w = get_parent_window (w);
2632 	LOCAL_DEBUG_OUT ("second parent %lX, root %lX, service_win = %lX", w,
2633 									 Scr.Root, Scr.ServiceWin);
2634 	if (w != Scr.Root && w != Scr.ServiceWin) {
2635 		ungrab_server ();
2636 		return;
2637 	}
2638 	withdraw_btn = (WITHDRAW_ON_EDGE (Config) &&
2639 									(&(aswf->buttons[0]) == aswb
2640 									 || &(aswf->buttons[aswf->buttons_num - 1]) == aswb))
2641 			|| WITHDRAW_ON_ANY (Config);
2642 	/* its ok - we can swallow it now : */
2643 	/* create swallow object : */
2644 	aswb->swallowed = safecalloc (1, sizeof (ASSwallowed));
2645 	aswb->swallowed->pid = wd->pid;
2646 	/* first thing - we reparent window and its icon if there is any */
2647 	nc = aswb->swallowed->normal = create_ascanvas_container (wd->client);
2648 	XReparentWindow (dpy, wd->client, aswb->canvas->w,
2649 									 (aswb->canvas->width - nc->width) / 2,
2650 									 (aswb->canvas->height - nc->height) / 2);
2651 	register_object (wd->client, (ASMagic *) aswb);
2652 	XSelectInput (dpy, wd->client,
2653 								StructureNotifyMask | LeaveWindowMask | EnterWindowMask);
2654 	ASSync (False);
2655 	ungrab_server ();
2656 	ASSync (False);
2657 	sleep_a_millisec (100);
2658 	grab_swallowed_canvas_btns (nc, aswb, withdraw_btn);
2659 
2660 	wm_hints = XGetWMHints (dpy, wd->client);
2661 	if ((wm_normal_hints = XAllocSizeHints ()) != NULL) {
2662 		long supplied;
2663 		if (XGetWMNormalHints (dpy, wd->client, wm_normal_hints, &supplied) ==
2664 				0) {
2665 			XFree (wm_normal_hints);
2666 			wm_normal_hints = NULL;
2667 		}
2668 	}
2669 
2670 	if (get_flags (wd->client_icon_flags, AS_ClientIcon)
2671 			&& !get_flags (wd->client_icon_flags, AS_ClientIconPixmap))
2672 		icon_w = wd->icon;
2673 	else if (get_flags (wd->flags, AS_WMDockApp)) {
2674 		if (wm_hints != NULL) {
2675 			if (get_flags (wm_hints->flags, IconWindowHint))
2676 				icon_w = wm_hints->icon_window;
2677 		}
2678 	}
2679 
2680 	if (icon_w != None) {
2681 		ASCanvas *ic = create_ascanvas_container (icon_w);
2682 		aswb->swallowed->iconic = ic;
2683 		XReparentWindow (dpy, icon_w, aswb->canvas->w,
2684 										 (aswb->canvas->width - ic->width) / 2,
2685 										 (aswb->canvas->height - ic->height) / 2);
2686 		register_object (icon_w, (ASMagic *) aswb);
2687 		XSelectInput (dpy, icon_w, StructureNotifyMask);
2688 		ASSync (False);
2689 		grab_swallowed_canvas_btns (ic, aswb, withdraw_btn);
2690 	}
2691 	aswb->swallowed->current = aswb->swallowed->normal;
2692 	if (aswb->swallowed->iconic != NULL) {
2693 		if (get_flags (wd->flags, AS_WMDockApp) ||
2694 #if 0
2695 				(wd->res_class && strcasecmp (wd->res_class, "DockApp") == 0) ||
2696 #endif
2697 				get_flags (wd->state_flags, AS_Iconic)) {
2698 			aswb->swallowed->current = aswb->swallowed->iconic;
2699 		}
2700 	}
2701 	handle_canvas_config (aswb->swallowed->current);
2702 	LOCAL_DEBUG_OUT ("client(%lX)->icon(%lX)->current(%lX)", wd->client,
2703 									 icon_w, aswb->swallowed->current->w);
2704 
2705 	if (get_flags (aswb->flags, ASW_MaxSwallow) ||
2706 			(Config->force_size.width == 0
2707 			 && !get_flags (aswb->flags, ASW_FixedWidth)))
2708 		aswb->desired_width = aswb->swallowed->current->width;
2709 	if (get_flags (aswb->flags, ASW_MaxSwallow) ||
2710 			(Config->force_size.height == 0
2711 			 && !get_flags (aswb->flags, ASW_FixedHeight)))
2712 		aswb->desired_height = aswb->swallowed->current->height;
2713 
2714 	if (wm_normal_hints) {
2715 		LOCAL_DEBUG_OUT ("wm_normal_hints->flags = 0x%lX",
2716 										 wm_normal_hints->flags);
2717 		if (get_flags (wm_normal_hints->flags, USSize)) {
2718 			user_set_width = wm_normal_hints->width;
2719 			user_set_height = wm_normal_hints->height;
2720 			if (user_set_width == 0)
2721 				user_set_width = aswb->swallowed->current->width;
2722 			if (user_set_height == 0)
2723 				user_set_height = aswb->swallowed->current->height;
2724 		}
2725 	}
2726 	swidth = aswb->swallowed->current->width;
2727 	if (get_flags (wd->flags, AS_MinSize) && swidth < wd->hints.min_width)
2728 		swidth = wd->hints.min_width;
2729 	else if (user_set_width > 0)
2730 		swidth = user_set_width;
2731 	else if (get_flags (wd->flags, AS_WMDockApp))
2732 		swidth = 64;
2733 	else
2734 		swidth = aswb->desired_width;
2735 	if (swidth <= 2)
2736 		swidth = aswb->desired_width;
2737 
2738 	sheight = aswb->swallowed->current->height;
2739 	if (get_flags (wd->flags, AS_MinSize) && sheight < wd->hints.min_height)
2740 		sheight = wd->hints.min_height;
2741 	else if (user_set_height > 0)
2742 		sheight = user_set_height;
2743 	else if (get_flags (wd->flags, AS_WMDockApp))
2744 		sheight = 64;
2745 	else
2746 		sheight = aswb->desired_height;
2747 	if (sheight <= 2)
2748 		sheight = aswb->desired_height;
2749 
2750 	LOCAL_DEBUG_OUT
2751 			("original %dx%d, user %dx%d, final %dx%d, desired %dx%d",
2752 			 aswb->swallowed->current->width, aswb->swallowed->current->height,
2753 			 user_set_width, user_set_height, swidth, sheight,
2754 			 aswb->desired_width, aswb->desired_height);
2755 
2756 	moveresize_canvas (aswb->swallowed->current,
2757 										 make_swallow_pad (get_flags
2758 																			 (Config->AlignContents, PAD_LEFT),
2759 																			 get_flags (Config->AlignContents,
2760 																									PAD_RIGHT),
2761 																			 aswb->canvas->width, swidth),
2762 										 make_swallow_pad (get_flags
2763 																			 (Config->AlignContents, PAD_TOP),
2764 																			 get_flags (Config->AlignContents,
2765 																									PAD_BOTTOM),
2766 																			 aswb->canvas->height, sheight),
2767 										 swidth, sheight);
2768 	if (!get_flags (wd->client_icon_flags, AS_ClientIcon)) {	/* workaround for broken wmdock apps that draw into icon, that is a child of a client,
2769 																														 * and at the same time not properly sized ( Just don't ask - some ppl are wierd ) */
2770 		LOCAL_DEBUG_OUT ("wmfire workaround step1: wm_hints = %p", wm_hints);
2771 		if (wm_hints) {
2772 			LOCAL_DEBUG_OUT
2773 					("wmfire workaround step2: icon_window_hint = %ld, icon_window = %lX",
2774 					 get_flags (wm_hints->flags, IconWindowHint),
2775 					 wm_hints->icon_window);
2776 			if (get_flags (wm_hints->flags, IconWindowHint)
2777 					&& wm_hints->icon_window != None) {
2778 				LOCAL_DEBUG_OUT ("wmfire workaround step3: resizing to %dx%d",
2779 												 swidth, sheight);
2780 				XResizeWindow (dpy, wm_hints->icon_window, swidth, sheight);
2781 			}
2782 		}
2783 	}
2784 
2785 	if (wm_normal_hints != NULL)
2786 		XFree (wm_normal_hints);
2787 	if (wm_hints != NULL)
2788 		XFree (wm_hints);
2789 
2790 	map_canvas_window (aswb->swallowed->current, True);
2791 	send_swallowed_configure_notify (aswb);
2792 	update_wharf_folder_size (aswf);
2793 }
2794 
2795 
2796 /*************************************************************************/
2797 /* Event handling                                                        */
2798 /*************************************************************************/
on_wharf_button_confreq(ASWharfButton * aswb,ASEvent * event)2799 void on_wharf_button_confreq (ASWharfButton * aswb, ASEvent * event)
2800 {
2801 	if (aswb && aswb->swallowed) {
2802 		XConfigureRequestEvent *cre = &(event->x.xconfigurerequest);
2803 		XWindowChanges xwc;
2804 		unsigned long xwcm;
2805 		int re_width = aswb->desired_width;
2806 		int re_height = aswb->desired_height;
2807 
2808 		xwcm =
2809 				CWX | CWY | CWWidth | CWHeight | (cre->value_mask & CWBorderWidth);
2810 
2811 		if (get_flags (cre->value_mask, CWWidth)) {
2812 			if (get_flags (aswb->flags, ASW_MaxSwallow) ||
2813 					(Config->force_size.width == 0
2814 					 && !get_flags (aswb->flags, ASW_FixedWidth))) {
2815 				aswb->desired_width = cre->width;
2816 			}
2817 			re_width = cre->width;
2818 		}
2819 		if (get_flags (cre->value_mask, CWHeight)) {
2820 			if (get_flags (aswb->flags, ASW_MaxSwallow) ||
2821 					(Config->force_size.height == 0
2822 					 && !get_flags (aswb->flags, ASW_FixedHeight))) {
2823 				aswb->desired_height = cre->height;
2824 			}
2825 			re_height = cre->height;
2826 		}
2827 
2828 		xwc.width = min (aswb->desired_width, re_width);
2829 		xwc.height = min (aswb->desired_height, re_height);
2830 
2831 		xwc.x = make_tile_pad (get_flags (Config->AlignContents, PAD_LEFT),
2832 													 get_flags (Config->AlignContents, PAD_RIGHT),
2833 													 aswb->canvas->width, xwc.width);
2834 		xwc.y = make_tile_pad (get_flags (Config->AlignContents, PAD_TOP),
2835 													 get_flags (Config->AlignContents, PAD_BOTTOM),
2836 													 aswb->canvas->height, xwc.height);
2837 
2838 		xwc.border_width = cre->border_width;
2839 
2840 		LOCAL_DEBUG_OUT
2841 				("Configuring swallowed window %lX to req(%dx%d%+d%+d bw = %d)- actual(%dx%d%+d%+d), (flags=%lX)",
2842 				 (unsigned long)aswb->swallowed->current->w, cre->width,
2843 				 cre->height, cre->x, cre->y, cre->border_width, xwc.width,
2844 				 xwc.height, xwc.x, xwc.y, xwcm);
2845 		XConfigureWindow (dpy, aswb->swallowed->current->w, xwcm, &xwc);
2846 		return;
2847 	}
2848 }
2849 
on_wharf_button_moveresize(ASWharfButton * aswb,ASEvent * event)2850 Bool on_wharf_button_moveresize (ASWharfButton * aswb, ASEvent * event)
2851 {
2852 	ASFlagType changes = handle_canvas_config (aswb->canvas);
2853 	ASFlagType swallowed_changes = 0;
2854 
2855 	if (aswb->swallowed) {
2856 		ASCanvas *sc = aswb->swallowed->current;
2857 		swallowed_changes = handle_canvas_config (sc);
2858 		if (get_flags (swallowed_changes, CANVAS_RESIZED)) {
2859 			update_wharf_folder_size (aswb->parent);
2860 		}
2861 		if (get_flags (changes, CANVAS_RESIZED)) {
2862 			int swidth =
2863 					min (aswb->desired_width, aswb->swallowed->current->width);
2864 			int sheight =
2865 					min (aswb->desired_height, aswb->swallowed->current->height);
2866 
2867 			moveresize_canvas (aswb->swallowed->current,
2868 												 make_tile_pad (get_flags
2869 																				(Config->AlignContents, PAD_LEFT),
2870 																				get_flags (Config->AlignContents,
2871 																									 PAD_RIGHT),
2872 																				aswb->canvas->width, swidth),
2873 												 make_tile_pad (get_flags
2874 																				(Config->AlignContents, PAD_TOP),
2875 																				get_flags (Config->AlignContents,
2876 																									 PAD_BOTTOM),
2877 																				aswb->canvas->height, sheight),
2878 												 swidth, sheight);
2879 		}
2880 		if (!get_flags (swallowed_changes, CANVAS_RESIZED) && changes != 0)
2881 			send_swallowed_configure_notify (aswb);
2882 	}
2883 
2884 	if (aswb->folder_width != aswb->canvas->width ||
2885 			aswb->folder_height != aswb->canvas->height)
2886 		return False;
2887 
2888 	if (get_flags (changes, CANVAS_RESIZED))
2889 		set_astbar_size (aswb->bar, aswb->canvas->width, aswb->canvas->height);
2890 
2891 	if (changes != 0)							/* have to always do that whenever canvas is changed */
2892 		update_astbar_transparency (aswb->bar, aswb->canvas, False);
2893 
2894 	if (changes != 0
2895 			&& (DoesBarNeedsRendering (aswb->bar)
2896 					|| is_canvas_needs_redraw (aswb->canvas))) {
2897 		invalidate_canvas_save (aswb->canvas);
2898 		render_wharf_button (aswb);
2899 	}
2900 #ifndef SHAPE
2901 	swallowed_changes = 0;				/* if no shaped extentions - ignore the changes */
2902 #endif
2903 	if (is_canvas_dirty (aswb->canvas) || swallowed_changes != 0) {
2904 		update_canvas_display (aswb->canvas);
2905 #ifdef SHAPE
2906 		if (get_flags (aswb->canvas->state, CANVAS_SHAPE_SET)
2907 				&& aswb->swallowed) {
2908 			update_wharf_folder_shape (aswb->parent);
2909 		}
2910 #endif
2911 	}
2912 	return True;
2913 }
2914 
set_wharf_clip_area(ASWharfFolder * aswf,int x,int y)2915 void set_wharf_clip_area (ASWharfFolder * aswf, int x, int y)
2916 {
2917 	if (aswf != NULL) {
2918 		int w = aswf->total_width;
2919 		int h = aswf->total_height;
2920 		XRectangle *target_area;
2921 		ASImage **target_root_image;
2922 
2923 		x += (int)aswf->canvas->bw;
2924 		y += (int)aswf->canvas->bw;
2925 
2926 		LOCAL_DEBUG_OUT ("folder: %dx%d%+d%+d", w, h, x, y);
2927 
2928 		target_area = &(aswf->root_clip_area);
2929 		target_root_image = &(aswf->root_image);
2930 		LOCAL_DEBUG_OUT ("target is normal (%dx%d%+d%+d)", target_area->width,
2931 										 target_area->height, target_area->x, target_area->y);
2932 
2933 		if (target_area->x != x || target_area->width != w ||
2934 				target_area->y != y || target_area->height != h) {
2935 			target_area->x = x;
2936 			target_area->y = y;
2937 			target_area->width = w;
2938 			target_area->height = h;
2939 			if (*target_root_image) {
2940 				safe_asimage_destroy (*target_root_image);
2941 				if (Scr.RootImage == *target_root_image)
2942 					Scr.RootImage = NULL;
2943 				*target_root_image = NULL;
2944 			}
2945 		}
2946 	}
2947 }
2948 
2949 void
set_withdrawn_clip_area(ASWharfFolder * aswf,int x,int y,unsigned int w,unsigned int h)2950 set_withdrawn_clip_area (ASWharfFolder * aswf, int x, int y,
2951 												 unsigned int w, unsigned int h)
2952 {
2953 	if (aswf != NULL) {
2954 		XRectangle *target_area;
2955 		ASImage **target_root_image;
2956 
2957 		x += (int)aswf->canvas->bw;
2958 		y += (int)aswf->canvas->bw;
2959 
2960 		LOCAL_DEBUG_OUT ("folder: %dx%d%+d%+d", w, h, x, y);
2961 
2962 		target_area = &(WharfState.withdrawn_root_clip_area);
2963 		target_root_image = &(WharfState.withdrawn_root_image);
2964 		LOCAL_DEBUG_OUT ("target is withdrawn (%dx%d%+d%+d)",
2965 										 target_area->width, target_area->height,
2966 										 target_area->x, target_area->y);
2967 
2968 		if (target_area->x != x || target_area->width != w ||
2969 				target_area->y != y || target_area->height != h) {
2970 			target_area->x = x;
2971 			target_area->y = y;
2972 			target_area->width = w;
2973 			target_area->height = h;
2974 			if (*target_root_image) {
2975 				safe_asimage_destroy (*target_root_image);
2976 				if (Scr.RootImage == *target_root_image)
2977 					Scr.RootImage = NULL;
2978 				*target_root_image = NULL;
2979 			}
2980 		}
2981 	}
2982 }
2983 
2984 
clear_root_image_cache(ASWharfFolder * aswf)2985 void clear_root_image_cache (ASWharfFolder * aswf)
2986 {
2987 	if (aswf) {
2988 		int i = aswf->buttons_num;
2989 		if (aswf->root_image) {
2990 			safe_asimage_destroy (aswf->root_image);
2991 			if (Scr.RootImage == aswf->root_image)
2992 				Scr.RootImage = NULL;
2993 			aswf->root_image = NULL;
2994 		}
2995 		while (--i >= 0)
2996 			if (aswf->buttons[i].folder != NULL)
2997 				clear_root_image_cache (aswf->buttons[i].folder);
2998 	}
2999 }
3000 
render_wharf_button(ASWharfButton * aswb)3001 Bool render_wharf_button (ASWharfButton * aswb)
3002 {
3003 	Bool result;
3004 	ASWharfFolder *aswf = aswb->parent;
3005 	Bool withdrawn_root = (aswf == WharfState.root_folder
3006 												 && get_flags (aswf->flags, ASW_Withdrawn));
3007 	if (withdrawn_root) {
3008 		Scr.RootImage = WharfState.withdrawn_root_image;
3009 		Scr.RootClipArea = WharfState.withdrawn_root_clip_area;
3010 	} else {
3011 		Scr.RootImage = aswf->root_image;
3012 		Scr.RootClipArea = aswf->root_clip_area;
3013 	}
3014 	LOCAL_DEBUG_OUT ("rendering button %p for folder %p. Root Image = %p",
3015 									 aswb, aswf, Scr.RootImage);
3016 	if (get_flags (aswb->bar->state, BAR_FLAGS_CROP_BACK))
3017 		result =
3018 				render_astbar_cached_back (aswb->bar, aswb->canvas, NULL,
3019 																	 aswf->canvas);
3020 	else
3021 		result = render_astbar (aswb->bar, aswb->canvas);
3022 	ASSync (False);
3023 	--WharfState.buttons_render_pending;
3024 
3025 	if (withdrawn_root)
3026 		WharfState.withdrawn_root_image = Scr.RootImage;
3027 	else
3028 		aswf->root_image = Scr.RootImage;
3029 
3030 	return result;
3031 }
3032 
3033 
3034 #if 0														/* keep here just in case */
3035 void
3036 add_wharf_folder_to_area (ASWharfFolder * aswf, int *from_x, int *from_y,
3037 													int *to_x, int *to_y)
3038 {
3039 	if (aswf != NULL && get_flags (aswf->flags, ASW_Mapped)) {
3040 		int x1 = aswf->canvas->root_x + (int)aswf->canvas->bw;
3041 		int y1 = aswf->canvas->root_y + (int)aswf->canvas->bw;
3042 		int x2 = aswf->total_width;
3043 		int y2 = aswf->total_height;
3044 		int i = aswf->buttons_num;
3045 
3046 		if (aswf->gravity == NorthEastGravity
3047 				|| aswf->gravity == SouthEastGravity)
3048 			x1 = x1 + aswf->canvas->width - x2;
3049 		if (aswf->gravity == SouthWestGravity
3050 				|| aswf->gravity == SouthEastGravity)
3051 			y1 = y1 + aswf->canvas->height - y2;
3052 		x2 += x1;
3053 		y2 += y1;
3054 		LOCAL_DEBUG_OUT
3055 				("folder: from %+d%+d to %+d%+d, all: from %+d%+d to %+d%+d", x1,
3056 				 y1, x2, y2, *from_x, *from_y, *to_x, *to_y);
3057 		if (x2 > 0 && x1 < (int)Scr.MyDisplayWidth && y2 > 0
3058 				&& y1 < (int)Scr.MyDisplayHeight) {
3059 			x1 = AS_CLAMP (0, x1, Scr.MyDisplayWidth);
3060 			x2 = AS_CLAMP (0, x2, Scr.MyDisplayWidth);
3061 			y1 = AS_CLAMP (0, y1, Scr.MyDisplayHeight);
3062 			y2 = AS_CLAMP (0, y2, Scr.MyDisplayHeight);
3063 			if (x1 < *from_x)
3064 				*from_x = x1;
3065 			if (x2 > *to_x)
3066 				*to_x = x2;
3067 			if (y1 < *from_y)
3068 				*from_y = y1;
3069 			if (y2 > *to_y)
3070 				*to_y = y2;
3071 
3072 			LOCAL_DEBUG_OUT
3073 					("CLAMPED: folder: from %+d%+d to %+d%+d, all: from %+d%+d to %+d%+d",
3074 					 x1, y1, x2, y2, *from_x, *from_y, *to_x, *to_y);
3075 		}
3076 		while (--i >= 0)
3077 			if (aswf->buttons[i].folder != NULL)
3078 				add_wharf_folder_to_area (aswf->buttons[i].folder,
3079 																	from_x, from_y, to_x, to_y);
3080 	}
3081 }
3082 
3083 void update_root_clip_area ()
3084 {
3085 	/* TODO: update root clip area to the max area occupied by all mapped folders */
3086 	int from_x = Scr.MyDisplayWidth, from_y = Scr.MyDisplayHeight;
3087 	int to_x = 0, to_y = 0;
3088 	ASWharfFolder *aswf = WharfState.root_folder;
3089 	add_wharf_folder_to_area (aswf, &from_x, &from_y, &to_x, &to_y);
3090 	Scr.RootClipArea.x = from_x;
3091 	Scr.RootClipArea.y = from_y;
3092 	Scr.RootClipArea.width = (to_x > from_x) ? to_x - from_x : 1;
3093 	Scr.RootClipArea.height = (to_y > from_y) ? to_y - from_y : 1;
3094 	if (Scr.RootImage) {
3095 		safe_asimage_destroy (Scr.RootImage);
3096 		Scr.RootImage = NULL;
3097 	}
3098 }
3099 #endif
3100 
do_wharf_animate_iter(void * vdata)3101 void do_wharf_animate_iter (void *vdata)
3102 {
3103 	ASWharfFolder *aswf = (ASWharfFolder *) vdata;
3104 
3105 	if (aswf != NULL && aswf->animation_steps > 0) {
3106 		int new_width = 1, new_height = 1;
3107 		animate_wharf (aswf, &new_width, &new_height);
3108 		if (new_width == 0 || new_height == 0	/*||
3109 																					   (new_width == aswf->canvas->width && new_height == aswf->canvas->height ) */
3110 				)
3111 			unmap_wharf_folder (aswf);
3112 		else {
3113 			LOCAL_DEBUG_OUT ("resizing folder from %dx%d to %dx%d",
3114 											 aswf->canvas->width, aswf->canvas->height,
3115 											 new_width, new_height);
3116 			resize_canvas (aswf->canvas, new_width, new_height);
3117 			ASSync (False);
3118 			if (get_flags (Config->set_flags, WHARF_ANIMATE_DELAY)
3119 					&& Config->animate_delay > 0) {
3120 				timer_new (Config->animate_delay + 1, do_wharf_animate_iter,
3121 									 vdata);
3122 			} else
3123 				timer_new (60, do_wharf_animate_iter, vdata);
3124 		}
3125 	}
3126 }
3127 
3128 
on_wharf_moveresize(ASEvent * event)3129 void on_wharf_moveresize (ASEvent * event)
3130 {
3131 	ASMagic *obj = NULL;
3132 
3133 	obj = fetch_object (event->w);
3134 	if (obj == NULL)
3135 		return;
3136 	if (obj->magic == MAGIC_WHARF_BUTTON) {
3137 		ASWharfButton *aswb = (ASWharfButton *) obj;
3138 
3139 		/* need to check if there were any ConfigureNotify 's for our folder
3140 		 * and if so - go process them first */
3141 		ASEvent parent_event;
3142 		while (ASCheckTypedWindowEvent
3143 					 (aswb->parent->canvas->w, ConfigureNotify, &(parent_event.x))) {
3144 			parent_event.client = NULL;
3145 			setup_asevent_from_xevent (&parent_event);
3146 			DispatchEvent (&parent_event);
3147 			timer_handle ();
3148 			ASSync (False);
3149 		}
3150 
3151 		LOCAL_DEBUG_OUT ("Handling button resizefor button %p", aswb);
3152 		on_wharf_button_moveresize (aswb, event);
3153 	} else if (obj->magic == MAGIC_WHARF_FOLDER) {
3154 		ASWharfFolder *aswf = (ASWharfFolder *) obj;
3155 		ASFlagType changes = handle_canvas_config (aswf->canvas);
3156 		LOCAL_DEBUG_OUT ("Handling folder resize for folder %p, mapped = %lX",
3157 										 aswf, get_flags (aswf->flags, ASW_Mapped));
3158 		if (aswf->animation_steps == 0 && get_flags (aswf->flags, ASW_Mapped)
3159 				&& aswf->animation_dir < 0) {
3160 			unmap_wharf_folder (aswf);
3161 		} else if (changes != 0) {
3162 			int i = aswf->buttons_num;
3163 			Bool withdrawn = False;
3164 			LOCAL_DEBUG_OUT ("animation_steps = %d", aswf->animation_steps);
3165 
3166 			withdrawn = (aswf->canvas->width == 1 || aswf->canvas->height == 1 ||
3167 									 (aswf->canvas->root_x == -10000
3168 										&& aswf->canvas->root_y == -10000));
3169 
3170 #ifdef SHAPE
3171 			if (get_flags (changes, CANVAS_RESIZED)
3172 					&& get_flags (aswf->flags, ASW_AnimationPending))
3173 				XShapeCombineRectangles (dpy, aswf->canvas->w, ShapeBounding, 0, 0,
3174 																 &(aswf->boundary), 1, ShapeSet, Unsorted);
3175 #endif
3176 
3177 			if (!withdrawn) {
3178 				if (!get_flags (aswf->flags, ASW_Withdrawn)) {
3179 					set_wharf_clip_area (aswf, aswf->canvas->root_x,
3180 															 aswf->canvas->root_y);
3181 					while (--i >= 0)
3182 						on_wharf_button_moveresize (&(aswf->buttons[i]), event);
3183 				} else if (aswf->withdrawn_button != NULL)
3184 					on_wharf_button_moveresize (aswf->withdrawn_button, event);
3185 			}
3186 #if 1
3187 			if (get_flags (changes, CANVAS_RESIZED)) {
3188 				LOCAL_DEBUG_OUT ("AnimationPending ? = %lX",
3189 												 get_flags (aswf->flags, ASW_AnimationPending));
3190 				if (get_flags (aswf->flags, ASW_AnimationPending)) {
3191 					LOCAL_DEBUG_OUT ("animate from = %dx%d, to = %dx%d",
3192 													 aswf->animate_from_w, aswf->animate_from_h,
3193 													 aswf->animate_to_w, aswf->animate_to_h);
3194 					animate_wharf_loop (aswf, aswf->animate_from_w,
3195 															aswf->animate_from_h, aswf->animate_to_w,
3196 															aswf->animate_to_h, get_flags (aswf->flags,
3197 																														 ASW_ReverseAnimation));
3198 					clear_flags (aswf->flags,
3199 											 ASW_UseBoundary | ASW_AnimationPending |
3200 											 ASW_ReverseAnimation);
3201 				} else if (!withdrawn) {
3202 					/* fprintf(stderr, "clearing or applying boundary\n");    */
3203 					if (!update_wharf_folder_shape (aswf)) {
3204 						/* fprintf(stderr, "forcing boundary\n");   */
3205 						update_canvas_display_mask (aswf->canvas, True);
3206 					}
3207 				}
3208 			}
3209 #endif
3210 
3211 		}
3212 	}
3213 }
3214 
press_wharf_button(ASWharfButton * aswb,int state)3215 void press_wharf_button (ASWharfButton * aswb, int state)
3216 {
3217 	if (WharfState.pressed_button && WharfState.pressed_button != aswb) {
3218 		set_astbar_pressed (WharfState.pressed_button->bar,
3219 												WharfState.pressed_button->canvas, False);
3220 		WharfState.pressed_button = NULL;
3221 	}
3222 	if (aswb && WharfState.pressed_button != aswb) {
3223 		set_astbar_pressed (aswb->bar, aswb->canvas, True);
3224 		WharfState.pressed_state = state;
3225 		WharfState.pressed_button = aswb;
3226 	}
3227 }
3228 
release_pressure(int button)3229 void release_pressure (int button)
3230 {
3231 	ASWharfButton *pressed = WharfState.pressed_button;
3232 	LOCAL_DEBUG_OUT ("pressed button is %p", pressed);
3233 	button -= Button1;
3234 	if (pressed) {
3235 		if (pressed->folder && !(button > 0 && pressed->fdata[button])) {
3236 			LOCAL_DEBUG_OUT ("pressed button has folder %p (%s)",
3237 											 pressed->folder, get_flags (pressed->folder->flags,
3238 																									 ASW_Mapped) ? "Mapped" :
3239 											 "Unmapped");
3240 			if (get_flags (pressed->folder->flags, ASW_Mapped))
3241 				withdraw_wharf_folder (pressed->folder);
3242 			else
3243 				display_wharf_folder (pressed->folder, pressed->canvas->root_x,
3244 															pressed->canvas->root_y,
3245 															pressed->canvas->root_x +
3246 															pressed->canvas->width,
3247 															pressed->canvas->root_y +
3248 															pressed->canvas->height);
3249 		} else if (pressed->fdata[button]) {
3250 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)
3251 			print_func_data (__FILE__, __FUNCTION__, __LINE__,
3252 											 pressed->fdata[button]);
3253 #endif
3254 			if (button > 0 || !get_flags (pressed->flags, ASW_SwallowTarget) || pressed->swallowed == NULL) {	/* send command to the AS-proper : */
3255 				ASWharfFolder *parentf = pressed->parent;
3256 				ASWharfButton *parentb = NULL;
3257 				SendCommand (pressed->fdata[button], 0);
3258 				sleep_a_millisec (200);	/* give AS a chance to handle requests */
3259 				while (parentf != WharfState.root_folder) {
3260 					parentb = parentf->parent;
3261 					withdraw_wharf_folder (parentf);
3262 					if (parentb == NULL)
3263 						break;
3264 					parentf = parentb->parent;
3265 				}
3266 			}
3267 		}
3268 		set_astbar_pressed (pressed->bar, pressed->canvas, False);
3269 		WharfState.pressed_button = NULL;
3270 	}
3271 }
3272 
3273 
check_app_click(ASWharfButton * aswb,XButtonEvent * xbtn)3274 static Bool check_app_click (ASWharfButton * aswb, XButtonEvent * xbtn)
3275 {
3276 	if (aswb->swallowed) {
3277 		int sx = aswb->swallowed->current->root_x;
3278 		int sy = aswb->swallowed->current->root_y;
3279 		return (sx <= xbtn->x_root && sy <= xbtn->y_root &&
3280 						aswb->swallowed->current->width + sx > xbtn->x_root &&
3281 						aswb->swallowed->current->height + sy > xbtn->y_root);
3282 	}
3283 	return False;
3284 }
3285 
on_wharf_pressed(ASEvent * event)3286 void on_wharf_pressed (ASEvent * event)
3287 {
3288 	ASMagic *obj = fetch_object (event->w);
3289 	if (obj == NULL)
3290 		return;
3291 	if (obj->magic == MAGIC_WHARF_BUTTON) {
3292 		ASWharfButton *aswb = (ASWharfButton *) obj;
3293 		ASWharfFolder *aswf = aswb->parent;
3294 
3295 		if (get_flags (aswb->flags, ASW_Transient))
3296 			return;
3297 
3298 		if (event->x.xbutton.button == Button3
3299 				&& aswf == WharfState.root_folder) {
3300 			if ((WITHDRAW_ON_EDGE (Config)
3301 					 && (&(aswf->buttons[0]) == aswb
3302 							 || &(aswf->buttons[aswf->buttons_num - 1]) == aswb))
3303 					|| WITHDRAW_ON_ANY (Config)) {
3304 				if (aswb->fdata[Button3 - Button1] == NULL
3305 						|| (event->x.xbutton.state & AllModifierMask) == ControlMask) {
3306 					if (get_flags (WharfState.root_folder->flags, ASW_Withdrawn)) {
3307 						/* update our name to normal */
3308 						set_folder_name (WharfState.root_folder, False);
3309 						LOCAL_DEBUG_OUT ("un - withdrawing folder%s", "");
3310 						display_main_folder ();
3311 					} else {
3312 						int wx = 0, wy = 0, wwidth, wheight;
3313 						int i = aswf->buttons_num;
3314 						Bool reverse = False;
3315 
3316 						if (Config->withdraw_style < WITHDRAW_ON_ANY_BUTTON_AND_SHOW)
3317 							aswb = &(aswf->buttons[0]);
3318 
3319 						withdraw_wharf_subfolders (aswf);
3320 						/* update our name to withdrawn */
3321 						set_folder_name (aswf, True);
3322 
3323 						wwidth = aswb->desired_width;
3324 						wheight = aswb->desired_height;
3325 						if (get_flags (aswf->flags, ASW_Vertical)) {
3326 							int dy = event->x.xbutton.y_root - aswf->canvas->root_y;
3327 							if (get_flags (Config->geometry.flags, XNegative))
3328 								wx = Scr.MyDisplayWidth - wwidth;
3329 							if (dy > aswf->canvas->height / 2) {
3330 								wy = Scr.MyDisplayHeight - wheight;
3331 								reverse = (!get_flags (Config->geometry.flags, YNegative));
3332 							} else
3333 								reverse = (get_flags (Config->geometry.flags, YNegative));
3334 						} else {
3335 							int dx = event->x.xbutton.x_root - aswf->canvas->root_x;
3336 							if (get_flags (Config->geometry.flags, YNegative))
3337 								wy = Scr.MyDisplayHeight - wheight;
3338 							if (dx > aswf->canvas->width / 2) {
3339 								wx = Scr.MyDisplayWidth - wwidth;
3340 								reverse = (!get_flags (Config->geometry.flags, XNegative));
3341 							} else
3342 								reverse = (get_flags (Config->geometry.flags, XNegative));
3343 						}
3344 						if (get_flags (Config->flags, WHARF_ANIMATE)) {
3345 							set_flags (aswf->flags, ASW_UseBoundary);
3346 							animate_wharf_loop (aswf, aswf->canvas->width,
3347 																	aswf->canvas->height, wwidth, wheight,
3348 																	reverse);
3349 							clear_flags (aswf->flags, ASW_UseBoundary);
3350 						}
3351 
3352 						LOCAL_DEBUG_OUT ("withdrawing folder to %dx%d%+d%+d", wwidth,
3353 														 wheight, wx, wy);
3354 						XRaiseWindow (dpy, aswb->canvas->w);
3355 						while (--i >= 0) {
3356 							if (&(aswf->buttons[i]) != aswb &&
3357 									aswf->buttons[i].canvas->root_x == aswf->canvas->root_x
3358 									&& aswf->buttons[i].canvas->root_y ==
3359 									aswf->canvas->root_y) {
3360 								aswf->buttons[i].folder_x = wwidth;
3361 								aswf->buttons[i].folder_y = wheight;
3362 								move_canvas (aswf->buttons[i].canvas, wwidth, wheight);
3363 							}
3364 						}
3365 						set_flags (aswf->flags, ASW_Withdrawn);
3366 						set_withdrawn_clip_area (aswf, wx, wy, wwidth, wheight);
3367 						moveresize_canvas (aswf->canvas, wx, wy, wwidth, wheight);
3368 						//          ASSync(False);
3369 						//          MapConfigureNotifyLoop();
3370 
3371 						aswb->folder_x = 0;
3372 						aswb->folder_y = 0;
3373 						aswb->folder_width = wwidth;
3374 						aswb->folder_height = wheight;
3375 						moveresize_canvas (aswb->canvas, 0, 0, wwidth, wheight);
3376 
3377 						aswf->withdrawn_button = aswb;
3378 					}
3379 					return;
3380 				}
3381 			}
3382 			if (event->x.xbutton.button == Button1
3383 					|| aswb->fdata[event->x.xbutton.button - Button1] == NULL) {
3384 				if (check_app_click (aswb, &(event->x.xbutton))) {
3385 					event->x.xbutton.window = aswb->swallowed->current->w;
3386 					XSendEvent (dpy, aswb->swallowed->current->w, False,
3387 											ButtonPressMask, &(event->x));
3388 					return;
3389 				}
3390 			}
3391 		}
3392 		press_wharf_button (aswb, event->x.xbutton.state);
3393 	}
3394 }
3395