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