3 * FvwmButtons, copyright 1996, Jarl Totland
5 * This module, and the entire GoodStuff program, and the concept for
6 * interfacing this module to the Window Manager, are all original work
9 * Copyright 1993, Robert Nation. No guarantees or warantees or anything
10 * are provided or implied in any way whatsoever. Use this program at your
11 * own risk. Permission to use this program for any purpose is given,
12 * as long as the copyright is kept intact.
16 /* This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 /* ------------------------------- includes -------------------------------- */
33 #ifdef HAVE_SYS_BSDTYPES_H
34 #include <sys/bsdtypes.h> /* Saul */
42 #include "libs/ftime.h"
45 #include <X11/keysym.h>
47 #include <X11/Xutil.h>
48 #include <X11/Xproto.h>
49 #include <X11/Xatom.h>
50 #include <X11/Intrinsic.h>
52 #include "libs/defaults.h"
53 #include "libs/fvwmlib.h"
54 #include "libs/FScreen.h"
55 #include "libs/FShape.h"
56 #include "libs/FRenderInit.h"
57 #include "libs/Grab.h"
58 #include "libs/gravity.h"
59 #include "fvwm/fvwm.h"
60 #include "libs/Module.h"
61 #include "libs/fvwmsignal.h"
62 #include "libs/Colorset.h"
63 #include "libs/vpacket.h"
64 #include "libs/FRender.h"
66 #include "libs/ColorUtils.h"
67 #include "libs/Graphics.h"
68 #include "libs/Parse.h"
69 #include "libs/Strings.h"
70 #include "libs/System.h"
71 #include "libs/wild.h"
72 #include "libs/WinMagic.h"
73 #include "libs/XError.h"
75 #include "FvwmButtons.h"
76 #include "misc.h" /* ConstrainSize() */
77 #include "parse.h" /* ParseConfiguration(), parse_window_geometry() */
84 StructureNotifyMask | \
94 /* SW_EVENTS are for swallowed windows... */
96 PropertyChangeMask | \
97 StructureNotifyMask | \
98 ResizeRedirectMask | \
99 SubstructureNotifyMask | \
101 /* PA_EVENTS are for swallowed panels... */
102 #define PA_EVENTS ( \
103 StructureNotifyMask | \
106 extern int nColorsets
; /* in libs/Colorsets.c */
108 /* --------------------------- external functions -------------------------- */
109 extern void DumpButtons(button_info
*);
110 extern void SaveButtons(button_info
*);
112 /* ------------------------------ prototypes ------------------------------- */
114 RETSIGTYPE
DeadPipe(int nonsense
);
115 static void DeadPipeCleanup(void);
116 static RETSIGTYPE
TerminateHandler(int sig
);
117 void SetButtonSize(button_info
*, int, int);
120 void RedrawWindow(void);
121 void RecursiveLoadData(button_info
*, int *, int *);
122 void CreateUberButtonWindow(button_info
*, int, int);
123 int My_FNextEvent(Display
*dpy
, XEvent
*event
);
124 void process_message(unsigned long type
, unsigned long *body
);
125 extern void send_clientmessage(Display
*disp
, Window w
, Atom a
, Time timestamp
);
126 void parse_message_line(char *line
);
127 void CheckForHangon(unsigned long *);
128 static Window
GetRealGeometry(
129 Display
*, Window
, int *, int *, unsigned int *, unsigned int *,
130 unsigned int *, unsigned int *);
131 static void GetPanelGeometry(
132 Bool get_big
, button_info
*b
, int lb
, int tb
, int rb
, int bb
,
133 int *x
, int *y
, int *w
, int *h
);
134 void swallow(unsigned long *);
135 void AddButtonAction(button_info
*, int, char *);
136 char *GetButtonAction(button_info
*, int);
137 static void update_root_transparency(XEvent
*Event
);
138 static void change_colorset(int colorset
, XEvent
*Event
);
140 void DebugEvents(XEvent
*);
142 static void HandlePanelPress(button_info
*b
);
144 /* -------------------------------- globals ---------------------------------*/
153 static fd_set_size_t fd_width
;
155 char *config_file
= NULL
;
157 static Atom _XA_WM_DEL_WIN
;
159 char *imagePath
= NULL
;
161 static Pixel hilite_pix
, back_pix
, shadow_pix
, fore_pix
;
163 /* needed for relief drawing only */
165 /* needed for transparency */
169 static int x
= -30000, y
= -30000;
172 static int gravity
= NorthWestGravity
;
174 static int ready
= 0;
177 int button_width
= 0;
178 int button_height
= 0;
179 int button_lborder
= 0;
180 int button_rborder
= 0;
181 int button_tborder
= 0;
182 int button_bborder
= 0;
183 Bool has_button_geometry
= 0;
184 Bool is_transient
= 0;
185 Bool is_transient_panel
= 0;
187 /* $CurrentButton is set on ButtonPress, $ActiveButton is set whenever the
188 mouse is over a button that is redrawn specially. */
189 button_info
*CurrentButton
= NULL
, *ActiveButton
= NULL
;
190 Bool is_pointer_in_current_button
= False
;
193 button_info
*UberButton
= NULL
;
198 Bool do_allow_bad_access
= False
;
199 Bool was_bad_access
= False
;
200 Bool swallowed
= False
;
201 Window swallower_win
= 0;
203 /* ------------------------------ Misc functions ----------------------------*/
206 char *mymalloc(int length
)
209 char *p
= safemalloc(length
);
219 *** Some fancy routines straight out of the manual :-) Used in DeadPipe.
221 Bool
DestroyedWindow(Display
*d
, XEvent
*e
, char *a
)
223 if (e
->xany
.window
== (Window
)a
&&
224 ((e
->type
== DestroyNotify
225 && e
->xdestroywindow
.window
== (Window
)a
) ||
226 (e
->type
== UnmapNotify
&& e
->xunmap
.window
== (Window
)a
)))
233 static Window
SwallowedWindow(button_info
*b
)
235 return (b
->flags
.b_Panel
) ? b
->PanelWin
: b
->IconWin
;
238 int IsThereADestroyEvent(button_info
*b
)
241 return FCheckIfEvent(
242 Dpy
, &event
, DestroyedWindow
, (char *)SwallowedWindow(b
));
247 *** Externally callable function to quit! Note that DeadPipeCleanup
248 *** is an exit-procedure and so will be called automatically
250 RETSIGTYPE
DeadPipe(int whatever
)
257 *** TerminateHandler()
258 *** Signal handler that will make the event-loop terminate
261 TerminateHandler(int sig
)
263 fvwmSetTerminate(sig
);
268 *** DeadPipeCleanup()
269 *** Remove all the windows from the Button-Bar, and close them as necessary
271 static void DeadPipeCleanup(void)
273 button_info
*b
, *ub
= UberButton
;
277 signal(SIGPIPE
, SIG_IGN
);/* Xsync may cause SIGPIPE */
279 MyXGrabServer(Dpy
); /* We don't want interference right now */
280 while (NextButton(&ub
, &b
, &button
, 0))
282 swin
= SwallowedWindow(b
);
283 /* delete swallowed windows */
284 if ((buttonSwallowCount(b
) == 3) && swin
)
288 "%s: Button 0x%06x window 0x%x (\"%s\") is ",
289 MyName
, (ushort
)b
, (ushort
)swin
, b
->hangon
);
291 if (!IsThereADestroyEvent(b
))
292 { /* Has someone destroyed it? */
293 if (!(buttonSwallow(b
)&b_NoClose
))
295 if (buttonSwallow(b
)&b_Kill
)
297 XKillClient(Dpy
, swin
);
299 fprintf(stderr
, "now killed\n");
317 fprintf(stderr
, "now unswallowed\n");
319 if (b
->swallow
& b_FvwmModule
)
325 "PropertyChange %u %u %lu",
326 MX_PROPERTY_CHANGE_SWALLOW
,
328 SendText(fd
, cmd
, 0);
330 fsm_proxy(Dpy
, swin
, NULL
);
332 Dpy
, swin
, Root
, b
->x
, b
->y
);
333 XMoveWindow(Dpy
, swin
, b
->x
, b
->y
);
334 XResizeWindow(Dpy
, swin
, b
->w
, b
->h
);
335 XSetWindowBorderWidth(Dpy
, swin
, b
->bw
);
336 if (b
->flags
.b_Panel
)
338 XMapWindow(Dpy
, swin
);
345 fprintf(stderr
, "already handled\n");
351 MyXUngrabServer(Dpy
); /* We're through */
354 /* Hey, we have to free the pictures too! */
357 while (NextButton(&ub
, &b
, &button
, 1))
359 /* The picture pointer is NULL if the pixmap came from a
361 if (b
->flags
.b_Icon
&& b
->icon
!= NULL
)
363 PDestroyFvwmPicture(Dpy
, b
->icon
);
365 if (b
->flags
.b_IconBack
&& b
->backicon
!= NULL
)
367 PDestroyFvwmPicture(Dpy
, b
->icon
);
369 if (b
->flags
.b_Container
&& b
->c
->flags
.b_IconBack
&&
370 !(b
->c
->flags
.b_TransBack
) && b
->c
->backicon
!= NULL
)
372 PDestroyFvwmPicture(Dpy
, b
->c
->backicon
);
379 *** Propagates global geometry down through the button hierarchy.
381 void SetButtonSize(button_info
*ub
, int w
, int h
)
387 if (!ub
|| !(ub
->flags
.b_Container
))
390 "%s: BUG: Tried to set size of noncontainer\n", MyName
);
393 if (ub
->c
->num_rows
== 0 || ub
->c
->num_columns
== 0)
396 "%s: BUG: Set size when rows/cols was unset\n", MyName
);
403 ub
->c
->xpos
= buttonXPos(ub
, i
);
404 ub
->c
->ypos
= buttonYPos(ub
, i
);
406 dx
= buttonXPad(ub
) + buttonFrame(ub
);
407 dy
= buttonYPad(ub
) + buttonFrame(ub
);
416 while (i
< ub
->c
->num_buttons
)
418 if (ub
->c
->buttons
[i
] && ub
->c
->buttons
[i
]->flags
.b_Container
)
422 buttonWidth(ub
->c
->buttons
[i
]),
423 buttonHeight(ub
->c
->buttons
[i
]));
431 *** AddButtonAction()
433 void AddButtonAction(button_info
*b
, int n
, char *action
)
439 if (!b
|| n
< 0 || n
> NUMBER_OF_EXTENDED_MOUSE_BUTTONS
|| !action
)
441 fprintf(stderr
, "%s: BUG: AddButtonAction failed\n", MyName
);
444 if (b
->flags
.b_Action
)
454 b
->action
= (char**)mymalloc(
455 (NUMBER_OF_EXTENDED_MOUSE_BUTTONS
+ 1) * sizeof(char*));
456 for (i
= 0; i
<= NUMBER_OF_EXTENDED_MOUSE_BUTTONS
;
457 b
->action
[i
++] = NULL
)
460 b
->flags
.b_Action
= 1;
463 while (*action
&& isspace((unsigned char)*action
))
475 s
= SkipQuote(action
, NULL
, "", "");
476 /* Strip outer quotes */
487 t
= (char *)mymalloc(l
+ 1);
488 memmove(t
, action
, l
);
495 *** GetButtonAction()
497 char *GetButtonAction(button_info
*b
, int n
)
502 if (!b
|| !(b
->flags
.b_Action
) || !(b
->action
) || n
< 0 ||
503 n
> NUMBER_OF_EXTENDED_MOUSE_BUTTONS
)
511 get_button_root_geometry(&r
, b
);
512 act
= module_expand_action(
513 Dpy
, screen
, b
->action
[n
], &r
, UberButton
->c
->fore
,
514 UberButton
->c
->back
);
519 Pixmap shapeMask
= None
;
521 *** SetTransparentBackground()
522 *** use the Shape extension to create a transparent background.
523 *** Patrice Fortier & others.
525 void SetTransparentBackground(button_info
*ub
, int w
, int h
)
527 if (FShapesSupported
)
533 if (shapeMask
!= None
)
534 XFreePixmap(Dpy
, shapeMask
);
535 shapeMask
= XCreatePixmap(Dpy
, MyWindow
, w
, h
, 1);
538 transGC
= fvwmlib_XCreateGC(Dpy
, shapeMask
, 0, &gcv
);
540 XSetClipMask(Dpy
, transGC
, None
);
541 XSetForeground(Dpy
, transGC
, 1);
542 XFillRectangle(Dpy
, shapeMask
, transGC
, x
, y
, w
, h
);
544 while (NextButton(&ub
, &b
, &i
, 0))
546 RedrawButton(b
, DRAW_FORCE
, NULL
);
554 *** Shows X errors made by FvwmButtons.
556 XErrorHandler oldErrorHandler
= NULL
;
557 int myErrorHandler(Display
*dpy
, XErrorEvent
*event
)
559 /* some errors are acceptable, mostly they're caused by
560 * trying to update a lost window */
561 if ((event
->error_code
== BadAccess
) && do_allow_bad_access
)
566 if ((event
->error_code
== BadWindow
)
567 || (event
->error_code
== BadDrawable
)
568 || (event
->error_code
== BadMatch
)
569 || (event
->request_code
== X_GrabButton
)
570 || (event
->request_code
== X_GetGeometry
)
571 || (event
->error_code
== BadPixmap
)
572 || (event
->error_code
==
573 FRenderGetErrorCodeBase() + FRenderBadPicture
))
576 PrintXErrorAndCoredump(dpy
, event
, MyName
);
578 /* return (*oldErrorHandler)(dpy, event); */
582 /* ---------------------------------- main ----------------------------------*/
587 int main(int argc
, char **argv
)
591 int x
, y
, maxx
, maxy
, border_width
;
594 int geom_option_argc
= 0;
595 XSetWindowAttributes xswa
;
597 FlocaleInit(LC_CTYPE
, "", "", "FvwmButtons");
599 MyName
= GetFileNameFromPath(argv
[0]);
601 #ifdef HAVE_SIGACTION
603 struct sigaction sigact
;
605 sigemptyset(&sigact
.sa_mask
);
606 sigaddset(&sigact
.sa_mask
, SIGPIPE
);
607 sigaddset(&sigact
.sa_mask
, SIGINT
);
608 sigaddset(&sigact
.sa_mask
, SIGHUP
);
609 sigaddset(&sigact
.sa_mask
, SIGQUIT
);
610 sigaddset(&sigact
.sa_mask
, SIGTERM
);
612 sigact
.sa_flags
= SA_INTERRUPT
;
616 sigact
.sa_handler
= TerminateHandler
;
618 sigaction(SIGPIPE
, &sigact
, NULL
);
619 sigaction(SIGINT
, &sigact
, NULL
);
620 sigaction(SIGHUP
, &sigact
, NULL
);
621 sigaction(SIGQUIT
, &sigact
, NULL
);
622 sigaction(SIGTERM
, &sigact
, NULL
);
625 /* We don't have sigaction(), so fall back to less robust methods. */
626 #ifdef USE_BSD_SIGNALS
635 signal(SIGPIPE
, TerminateHandler
);
636 signal(SIGINT
, TerminateHandler
);
637 signal(SIGHUP
, TerminateHandler
);
638 signal(SIGQUIT
, TerminateHandler
);
639 signal(SIGTERM
, TerminateHandler
);
640 #ifdef HAVE_SIGINTERRUPT
641 siginterrupt(SIGPIPE
, 1);
642 siginterrupt(SIGINT
, 1);
643 siginterrupt(SIGHUP
, 1);
644 siginterrupt(SIGQUIT
, 1);
645 siginterrupt(SIGTERM
, 1);
649 if (argc
<6 || argc
>10)
652 "%s version %s should only be executed by fvwm!\n",
657 for (i
= 6; i
< argc
&& i
< 11; i
++)
659 static Bool has_name
= 0;
660 static Bool has_file
= 0;
661 static Bool has_geometry
= 0;
663 if (!has_geometry
&& strcmp(argv
[i
], "-g") == 0)
668 /* can't do that now because the UberButton */
669 /* has not been set up */
670 geom_option_argc
= i
;
673 else if (!is_transient
&& !is_transient_panel
&&
674 (strcmp(argv
[i
], "-transient") == 0 ||
675 strcmp(argv
[i
], "transient") == 0))
679 else if (!is_transient
&& !is_transient_panel
&&
680 (strcmp(argv
[i
], "-transientpanel") == 0 ||
681 strcmp(argv
[i
], "transientpanel") == 0))
683 is_transient_panel
= 1;
686 /* There is a naming argument here! */
689 MyName
= safestrdup(argv
[i
]);
693 /* There is a config file here! */
695 config_file
= safestrdup(argv
[i
]);
700 fd
[0] = atoi(argv
[1]);
701 fd
[1] = atoi(argv
[2]);
702 if (!(Dpy
= XOpenDisplay(NULL
)))
705 "%s: Can't open display %s", MyName
,
709 flib_init_graphics(Dpy
);
711 x_fd
= XConnectionNumber(Dpy
);
712 fd_width
= GetFdWidth();
714 screen
= DefaultScreen(Dpy
);
715 Root
= RootWindow(Dpy
, screen
);
718 fprintf(stderr
, "%s: Screen %d is not valid\n", MyName
, screen
);
722 oldErrorHandler
= XSetErrorHandler(myErrorHandler
);
724 UberButton
= (button_info
*)mymalloc(sizeof(button_info
));
725 memset(UberButton
, 0, sizeof(button_info
));
726 UberButton
->BWidth
= 1;
727 UberButton
->BHeight
= 1;
728 MakeContainer(UberButton
);
730 dpw
= DisplayWidth(Dpy
, screen
);
731 dph
= DisplayHeight(Dpy
, screen
);
734 fprintf(stderr
, "%s: Parsing...", MyName
);
737 UberButton
->title
= MyName
;
738 UberButton
->swallow
= 1; /* the panel is shown */
740 /* parse module options */
741 ParseConfiguration(UberButton
);
743 /* To avoid an infinite loop of Enter/Leave-Notify events, if the user
744 uses ActiveIcon with "Pixmap none" they MUST specify ActiveColorset.
746 if (FShapesSupported
&& (UberButton
->c
->flags
.b_TransBack
) &&
747 !(UberButton
->c
->flags
.b_ActiveColorset
))
751 while (NextButton(&ub
, &b
, &i
, 0))
753 if (b
->flags
.b_ActiveIcon
|| b
->flags
.b_ActiveTitle
)
756 "%s: Must specify ActiveColorset when "
757 "using ActiveIcon or ActiveTitle with "
758 "\"Pixmap none\".\n", MyName
);
764 /* we can't set the size if it was specified in pixels per button here;
765 * delay until after call to RecursiveLoadData. */
766 /* parse the geometry string */
767 if (geom_option_argc
!= 0)
769 parse_window_geometry(argv
[geom_option_argc
], 0);
772 /* Don't quit if only a subpanel is empty */
773 if (UberButton
->c
->num_buttons
== 0)
775 fprintf(stderr
, "%s: No buttons defined. Quitting\n", MyName
);
780 fprintf(stderr
, "OK\n%s: Shuffling...", MyName
);
783 ShuffleButtons(UberButton
);
784 NumberButtons(UberButton
);
787 fprintf(stderr
, "OK\n%s: Creating Main Window ...", MyName
);
790 xswa
.colormap
= Pcmap
;
791 xswa
.border_pixel
= 0;
792 xswa
.background_pixmap
= None
;
793 MyWindow
= XCreateWindow(
794 Dpy
, Root
, 0, 0, 1, 1, 0, Pdepth
, InputOutput
, Pvisual
,
795 CWColormap
| CWBackPixmap
| CWBorderPixel
, &xswa
);
798 fprintf(stderr
, "OK\n%s: Loading data...\n", MyName
);
801 /* Load fonts and icons, calculate max buttonsize */
804 RecursiveLoadData(UberButton
, &maxx
, &maxy
);
806 /* now we can size the main window if pixels per button were specified
808 if (has_button_geometry
&& button_width
> 0 && button_height
> 0)
810 w
= button_width
* UberButton
->c
->num_columns
;
811 h
= button_height
* UberButton
->c
->num_rows
;
815 fprintf(stderr
, "%s: Configuring main window...", MyName
);
818 CreateUberButtonWindow(UberButton
, maxx
, maxy
);
821 Dpy
, MyWindow
, &root
, &x
, &y
, (unsigned int *)&Width
,
822 (unsigned int *)&Height
, (unsigned int *)&border_width
, &depth
))
824 fprintf(stderr
, "%s: Failed to get window geometry\n", MyName
);
827 SetButtonSize(UberButton
, Width
, Height
);
831 if (FShapesSupported
)
833 if (UberButton
->c
->flags
.b_TransBack
)
835 SetTransparentBackground(UberButton
, Width
, Height
);
841 while (NextButton(&ub
, &b
, &i
, 0))
847 fprintf(stderr
, "OK\n%s: Mapping windows...", MyName
);
850 XMapSubwindows(Dpy
, MyWindow
);
851 XMapWindow(Dpy
, MyWindow
);
854 fd
, M_NEW_DESK
| M_END_WINDOWLIST
| M_MAP
| M_WINDOW_NAME
855 | M_RES_CLASS
| M_CONFIG_INFO
| M_END_CONFIG_INFO
| M_RES_NAME
856 | M_SENDCONFIG
| M_ADD_WINDOW
| M_CONFIGURE_WINDOW
| M_STRING
);
857 SetMessageMask(fd
, MX_PROPERTY_CHANGE
);
859 /* request a window list, since this triggers a response which
860 * will tell us the current desktop and paging status, needed to
861 * indent buttons correctly */
862 SendText(fd
, "Send_WindowList", 0);
865 fprintf(stderr
, "OK\n%s: Startup complete\n", MyName
);
869 ** Now that we have finished initialising everything,
870 ** it is safe(r) to install the clean-up handlers ...
872 atexit(DeadPipeCleanup
);
874 /* tell fvwm we're running */
875 SendFinishedStartupNotification(fd
);
882 static button_info
*handle_new_position(
883 button_info
*b
, int pos_x
, int pos_y
)
885 Bool f
= is_pointer_in_current_button
, redraw
= False
;
887 if (pos_x
< 0 || pos_x
>= Width
||
888 pos_y
< 0 || pos_y
>= Height
)
890 /* cursor is outside of FvwmButtons window. */
894 /* find out which button the cursor is in now. */
895 b
= select_button(UberButton
, pos_x
, pos_y
);
897 is_pointer_in_current_button
=
898 (CurrentButton
&& CurrentButton
== b
);
899 if (CurrentButton
&& is_pointer_in_current_button
!= f
)
904 if (b
!= ActiveButton
&& CurrentButton
== NULL
)
908 button_info
*tmp
= ActiveButton
;
910 RedrawButton(tmp
, DRAW_FORCE
, NULL
);
913 b
->flags
.b_ActiveIcon
||
914 b
->flags
.b_ActiveTitle
||
915 b
->flags
.b_ActiveColorset
||
916 UberButton
->c
->flags
.b_ActiveColorset
)
924 RedrawButton(b
, DRAW_FORCE
, NULL
);
930 void ButtonPressProcess (button_info
*b
, char **act
)
932 FlocaleNameString tmp
;
935 memset(&tmp
, 0, sizeof(tmp
));
936 if (b
&& !*act
&& b
->flags
.b_Panel
)
940 if (b
->newflags
.panel_mapped
== 0)
944 /* terminate if transient and panel has been
948 else if (is_transient_panel
)
950 XWithdrawWindow(Dpy
, MyWindow
, screen
);
957 *act
=GetButtonAction(b
,0);
958 if (b
&& b
== CurrentButton
&& *act
)
960 if (strncasecmp(*act
,"Exec",4) == 0 &&
964 /* Look for Exec "identifier", in which case
965 * the button stays down until window
966 * "identifier" materializes */
968 while(isspace((unsigned char)(*act
)[i
]))
973 while((*act
)[i2
]!=0 && (*act
)[i2
]!='"')
978 b
->flags
.b_Hangon
= 1;
979 b
->hangon
= mymalloc(i2
-i
);
981 b
->hangon
, &(*act
)[i
+1],
983 b
->hangon
[i2
-i
-1] = 0;
990 tmp
.name
= mymalloc(strlen(*act
)+1);
991 strcpy(tmp
.name
, "Exec ");
994 isspace((unsigned char)(*act
)[i2
]))
998 strcat(tmp
.name
,&(*act
)[i2
]);
1001 /* delete the window before continuing
1003 XDestroyWindow(Dpy
, MyWindow
);
1006 SendText(fd
,tmp
.name
,0);
1012 if (is_transient_panel
)
1014 XWithdrawWindow(Dpy
, MyWindow
, screen
);
1018 else if(strncasecmp(*act
,"DumpButtons",11)==0)
1019 DumpButtons(UberButton
);
1020 else if(strncasecmp(*act
,"SaveButtons",11)==0)
1021 SaveButtons(UberButton
);
1026 /* delete the window before continuing
1028 XDestroyWindow(Dpy
, MyWindow
);
1031 SendText(fd
,*act
,0);
1037 if (is_transient_panel
)
1039 XWithdrawWindow(Dpy
, MyWindow
, screen
);
1046 /* -------------------------------- Main Loop -------------------------------*/
1055 char buffer
[10], *act
;
1059 button_info
*ub
, *b
;
1061 FlocaleNameString tmp
;
1064 tmp
.name_list
= NULL
;
1065 while ( !isTerminated
)
1067 if (My_FNextEvent(Dpy
, &Event
))
1069 if (FShapesSupported
&& Event
.type
== FShapeEventBase
+ FShapeNotify
)
1071 FShapeEvent
*sev
= (FShapeEvent
*) &Event
;
1073 if (sev
->kind
!= FShapeBounding
)
1077 if (UberButton
->c
->flags
.b_TransBack
)
1079 SetTransparentBackground(
1080 UberButton
, Width
, Height
);
1088 int ex
, ey
, ex2
, ey2
;
1090 if (Event
.xexpose
.window
!= MyWindow
)
1094 ex
= Event
.xexpose
.x
;
1095 ey
= Event
.xexpose
.y
;
1096 ex2
= Event
.xexpose
.x
+
1097 Event
.xexpose
.width
;
1098 ey2
= Event
.xexpose
.y
+
1099 Event
.xexpose
.height
;
1101 FCheckTypedWindowEvent(
1102 Dpy
, MyWindow
, Expose
,
1105 /* maybe we should not purge here,
1106 * this may interfere
1107 * with configure notify */
1108 ex
= min(ex
, Event
.xexpose
.x
);
1109 ey
= min(ey
, Event
.xexpose
.y
);
1110 ex2
= max(ex2
, Event
.xexpose
.x
1111 + Event
.xexpose
.width
);
1112 ey2
= max(ey2
, Event
.xexpose
.y
1113 + Event
.xexpose
.height
);
1115 Event
.xexpose
.x
= ex
;
1116 Event
.xexpose
.y
= ey
;
1117 Event
.xexpose
.width
= ex2
-ex
;
1118 Event
.xexpose
.height
= ey2
-ey
;
1121 while (NextButton(&ub
, &b
, &button
, 1))
1126 while (tmpb
->parent
!= NULL
)
1128 if (tmpb
->flags
.b_Container
)
1149 buttonWidth(tmpb
) ||
1152 buttonHeight(tmpb
) ||
1157 tmpb
= tmpb
->parent
;
1162 !(b
->flags
.b_Container
))
1167 b
, DRAW_ALL
, &Event
);
1177 /* Start of TO-BE-REFORMATTED-BLOCK */
1179 case ConfigureNotify
:
1182 unsigned int depth
, tw
, th
, border_width
;
1185 while (FCheckTypedWindowEvent(Dpy
, MyWindow
, ConfigureNotify
, &event
))
1187 if (!event
.xconfigure
.send_event
&&
1188 Event
.xconfigure
.window
!= MyWindow
)
1190 Event
.xconfigure
.x
= event
.xconfigure
.x
;
1191 Event
.xconfigure
.y
= event
.xconfigure
.y
;
1192 Event
.xconfigure
.send_event
= True
;
1194 if (!XGetGeometry(Dpy
, MyWindow
, &root
, &x
, &y
, &tw
, &th
,
1195 &border_width
, &depth
))
1199 if (tw
!= Width
|| th
!= Height
)
1203 SetButtonSize(UberButton
, Width
, Height
);
1206 /* what follow can be optimized */
1207 while (NextButton(&ub
, &b
, &button
, 0))
1209 if (FShapesSupported
&& UberButton
->c
->flags
.b_TransBack
)
1211 SetTransparentBackground(UberButton
, Width
, Height
);
1213 for (i
= 0; i
< nColorsets
; i
++)
1214 change_colorset(i
, &Event
);
1215 if (!UberButton
->c
->flags
.b_Colorset
)
1217 XClearWindow(Dpy
, MyWindow
);
1221 else if (Event
.xconfigure
.window
== MyWindow
&&
1222 Event
.xconfigure
.send_event
)
1224 update_root_transparency(&Event
);
1230 b
= handle_new_position(
1231 b
, Event
.xcrossing
.x
, Event
.xcrossing
.y
);
1235 b
= handle_new_position(b
, Event
.xmotion
.x
, Event
.xmotion
.y
);
1240 Event
.xcrossing
.x
< 0 || Event
.xcrossing
.x
>= Width
||
1241 Event
.xcrossing
.y
< 0 || Event
.xcrossing
.y
>= Height
||
1243 /* We get LeaveNotify events when the mouse enters
1244 * a swallowed window of FvwmButtons, but we're not
1245 * interested in these situations. */
1246 !select_button(UberButton
, x
, y
)->flags
.b_Swallow
||
1248 /* But we're interested in those situations when
1249 * the mouse enters a window which overlaps with
1250 * the swallowed window. */
1251 Event
.xcrossing
.subwindow
!= None
)
1256 ActiveButton
= NULL
;
1257 RedrawButton(b
, DRAW_FORCE
, NULL
);
1261 RedrawButton(b
, DRAW_FORCE
, NULL
);
1267 XLookupString(&Event
.xkey
, buffer
, 10, &keysym
, 0);
1269 keysym
!= XK_Return
&& keysym
!= XK_KP_Enter
&&
1270 keysym
!= XK_Linefeed
)
1271 break; /* fall through to ButtonPress */
1274 if (Event
.xbutton
.window
== MyWindow
)
1276 x
= Event
.xbutton
.x
;
1277 y
= Event
.xbutton
.y
;
1283 XTranslateCoordinates(
1284 Dpy
, Event
.xbutton
.window
, MyWindow
, Event
.xbutton
.x
,
1285 Event
.xbutton
.y
, &x
, &y
, &dummy
);
1290 CurrentButton
= NULL
;
1291 ActiveButton
= select_button(UberButton
, x
, y
);
1292 RedrawButton(b
, DRAW_FORCE
, NULL
);
1293 if (ActiveButton
!= b
)
1295 RedrawButton(ActiveButton
, DRAW_FORCE
, NULL
);
1300 if (Event
.xbutton
.state
& DEFAULT_ALL_BUTTONS_MASK
)
1305 CurrentButton
= b
= select_button(UberButton
, x
, y
);
1306 is_pointer_in_current_button
= True
;
1309 if (!b
->flags
.b_Panel
&&
1310 (!b
|| !b
->flags
.b_Action
||
1311 ((act
= GetButtonAction(b
, Event
.xbutton
.button
)) == NULL
&&
1312 (act
= GetButtonAction(b
, 0)) == NULL
)))
1314 CurrentButton
= NULL
;
1318 /* Undraw ActiveButton (if there is one). */
1321 /* $b & $ActiveButton are always the same button. */
1322 button_info
*tmp
= ActiveButton
;
1323 ActiveButton
= NULL
;
1324 RedrawButton(tmp
, DRAW_FORCE
, NULL
);
1327 RedrawButton(b
, DRAW_FORCE
, NULL
);
1332 if (act
&& !b
->flags
.b_ActionOnPress
&&
1333 strncasecmp(act
, "popup", 5) != 0)
1339 else /* i.e. action is Popup */
1341 XUngrabPointer(Dpy
, CurrentTime
); /* And fall through */
1352 if (CurrentButton
== NULL
|| !is_pointer_in_current_button
)
1356 button_info
*tmp
= CurrentButton
;
1357 CurrentButton
= NULL
;
1358 RedrawButton(tmp
, DRAW_FORCE
, NULL
);
1361 CurrentButton
= NULL
;
1364 RedrawButton(ActiveButton
, DRAW_FORCE
, NULL
);
1367 if (Event
.xbutton
.window
== MyWindow
)
1369 x
= Event
.xbutton
.x
;
1370 y
= Event
.xbutton
.y
;
1376 XTranslateCoordinates(
1377 Dpy
, Event
.xbutton
.window
, MyWindow
, Event
.xbutton
.x
,
1378 Event
.xbutton
.y
, &x
, &y
, &dummy
);
1380 b
= select_button(UberButton
, x
, y
);
1381 act
= GetButtonAction(b
,Event
.xbutton
.button
);
1383 ButtonPressProcess(b
, &act
);
1391 CurrentButton
= NULL
;
1393 if (b
&& !b
->flags
.b_Hangon
)
1394 RedrawButton(b
, DRAW_FORCE
, NULL
);
1398 if (Event
.xclient
.format
== 32 &&
1399 Event
.xclient
.data
.l
[0]==_XA_WM_DEL_WIN
)
1405 case PropertyNotify
:
1406 if (Event
.xany
.window
== None
)
1408 ub
= UberButton
;button
= -1;
1409 while (NextButton(&ub
, &b
, &button
, 0))
1411 Window swin
= SwallowedWindow(b
);
1413 if ((buttonSwallowCount(b
) == 3) && Event
.xany
.window
== swin
)
1415 if (Event
.xproperty
.atom
== XA_WM_NAME
&&
1416 buttonSwallow(b
)&b_UseTitle
)
1418 if (b
->flags
.b_Title
)
1420 b
->flags
.b_Title
= 1;
1421 FlocaleGetNameProperty(XGetWMName
, Dpy
, swin
, &tmp
);
1422 if (tmp
.name
!= NULL
)
1424 CopyString(&b
->title
, tmp
.name
);
1425 FlocaleFreeNameProperty(&tmp
);
1429 CopyString(&b
->title
, "");
1433 else if ((Event
.xproperty
.atom
== XA_WM_NORMAL_HINTS
) &&
1434 (!(buttonSwallow(b
)&b_NoHints
)))
1437 if (!XGetWMNormalHints(Dpy
, swin
, b
->hints
, &supp
))
1438 b
->hints
->flags
= 0;
1440 if (FShapesSupported
)
1442 if (UberButton
->c
->flags
.b_TransBack
)
1444 SetTransparentBackground(UberButton
, Width
, Height
);
1448 RedrawButton(b
, DRAW_FORCE
, NULL
);
1458 while (NextButton(&ub
, &b
, &button
, 0))
1460 if (b
->flags
.b_Panel
&& Event
.xany
.window
== b
->PanelWin
)
1462 /* A panel has been unmapped, update the button */
1463 b
->newflags
.panel_mapped
= (Event
.type
== MapNotify
);
1464 RedrawButton(b
, DRAW_FORCE
, NULL
);
1471 ub
= UberButton
;button
= -1;
1472 while (NextButton(&ub
, &b
, &button
, 0))
1474 Window swin
= SwallowedWindow(b
);
1476 if ((buttonSwallowCount(b
) == 3) && Event
.xany
.window
== swin
)
1480 "%s: Button 0x%06x lost its window 0x%x (\"%s\")",
1481 MyName
, (ushort
)b
, (ushort
)swin
, b
->hangon
);
1483 b
->swallow
&= ~b_Count
;
1484 if (b
->flags
.b_Panel
)
1488 if (buttonSwallow(b
)&b_Respawn
&& b
->hangon
&& b
->spawn
)
1493 fprintf(stderr
, ", respawning\n");
1495 if (b
->newflags
.is_panel
&& is_transient
)
1497 /* terminate if transient and a panel has been killed */
1501 if (!b
->newflags
.is_panel
)
1503 b
->flags
.b_Swallow
= 1;
1504 b
->flags
.b_Hangon
= 1;
1508 b
->flags
.b_Panel
= 1;
1509 b
->flags
.b_Hangon
= 1;
1510 b
->newflags
.panel_mapped
= 0;
1512 p
= module_expand_action(
1513 Dpy
, screen
, b
->spawn
, NULL
, UberButton
->c
->fore
,
1514 UberButton
->c
->back
);
1520 RedrawButton(b
, DRAW_CLEAN
, NULL
); /* ? */
1521 if (is_transient_panel
)
1523 XWithdrawWindow(Dpy
, MyWindow
, screen
);
1526 else if (b
->newflags
.do_swallow_new
&& b
->hangon
&& b
->spawn
&&
1527 !b
->newflags
.is_panel
)
1530 fprintf(stderr
, ", waiting for respawned window\n");
1533 b
->flags
.b_Swallow
= 1;
1534 b
->flags
.b_Hangon
= 1;
1535 RedrawButton(b
, DRAW_CLEAN
, NULL
);
1536 if (is_transient_panel
)
1538 XWithdrawWindow(Dpy
, MyWindow
, screen
);
1543 b
->flags
.b_Swallow
= 0;
1544 b
->flags
.b_Panel
= 0;
1545 RedrawButton(b
, DRAW_FORCE
, NULL
);
1547 fprintf(stderr
, "\n");
1555 /* End of TO-BE-REFORMATTED-BLOCK */
1560 "%s: Event fell through unhandled\n",
1565 } /* event handling */
1572 *** Draws the window by traversing the button tree
1574 void RedrawWindow(void)
1578 button_info
*ub
, *b
;
1579 static Bool initial_redraw
= True
;
1587 /* Flush expose events */
1588 while (FCheckTypedWindowEvent(Dpy
, MyWindow
, Expose
, &dummy
))
1592 /* Clean out the entire window first */
1593 if (initial_redraw
== False
)
1595 XClearWindow(Dpy
, MyWindow
);
1596 clear_buttons
= False
;
1600 initial_redraw
= False
;
1601 clear_buttons
= True
;
1606 while (NextButton(&ub
, &b
, &button
, 1))
1608 RedrawButton(b
, DRAW_ALL
, NULL
);
1615 int LoadIconFile(const char *s
, FvwmPicture
**p
, int cset
)
1617 FvwmPictureAttributes fpa
;
1620 if (cset
>= 0 && Colorset
[cset
].do_dither_icon
)
1622 fpa
.mask
|= FPAM_DITHER
;
1624 if (UberButton
->c
->flags
.b_TransBack
)
1626 fpa
.mask
|= FPAM_NO_ALPHA
;
1628 *p
= PCacheFvwmPicture(Dpy
, MyWindow
, imagePath
, s
, fpa
);
1637 *** RecursiveLoadData()
1638 *** Loads colors, fonts and icons, and calculates buttonsizes
1640 void RecursiveLoadData(button_info
*b
, int *maxx
, int *maxy
)
1642 int i
, x
= 0, y
= 0, ix
, iy
, tx
, ty
, hix
, hiy
, htx
, hty
, pix
, piy
, ptx
, pty
;
1648 #ifdef DEBUG_LOADDATA
1649 fprintf(stderr
, "%s: Loading: Button 0x%06x: colors", MyName
, (ushort
)b
);
1653 /* initialise button colours and background */
1654 if (b
->flags
.b_Colorset
)
1656 int cset
= b
->colorset
;
1658 /* override normal icon options */
1659 if (b
->flags
.b_IconBack
&& !b
->flags
.b_TransBack
)
1663 b
->flags
.b_IconBack
= 0;
1664 b
->flags
.b_TransBack
= 0;
1666 /* fetch the colours from the colorset */
1667 b
->fc
= Colorset
[cset
].fg
;
1668 b
->bc
= Colorset
[cset
].bg
;
1669 b
->hc
= Colorset
[cset
].hilite
;
1670 b
->sc
= Colorset
[cset
].shadow
;
1671 if (Colorset
[cset
].pixmap
!= None
)
1673 /* we have a pixmap */
1675 b
->flags
.b_IconBack
= 1;
1678 else /* no colorset */
1681 if (b
->flags
.b_Fore
)
1682 b
->fc
= GetColor(b
->fore
);
1683 if (b
->flags
.b_Back
)
1685 b
->bc
= GetColor(b
->back
);
1686 b
->hc
= GetHilite(b
->bc
);
1687 b
->sc
= GetShadow(b
->bc
);
1688 if (b
->flags
.b_IconBack
)
1690 if (!LoadIconFile(b
->back
, &b
->backicon
, b
->colorset
))
1691 b
->flags
.b_Back
= 0;
1696 /* initialise container colours and background */
1697 if (b
->flags
.b_Container
)
1699 if (b
->c
->flags
.b_Colorset
)
1701 int cset
= b
->c
->colorset
;
1703 /* override normal icon options */
1704 if (b
->c
->flags
.b_IconBack
&& !b
->c
->flags
.b_TransBack
)
1706 free(b
->c
->back_file
);
1708 b
->c
->flags
.b_IconBack
= 0;
1709 b
->c
->flags
.b_TransBack
= 0;
1711 /* fetch the colours from the colorset */
1712 b
->c
->fc
= Colorset
[cset
].fg
;
1713 b
->c
->bc
= Colorset
[cset
].bg
;
1714 b
->c
->hc
= Colorset
[cset
].hilite
;
1715 b
->c
->sc
= Colorset
[cset
].shadow
;
1716 if (Colorset
[cset
].pixmap
!= None
)
1718 /* we have a pixmap */
1719 b
->c
->backicon
= NULL
;
1720 b
->c
->flags
.b_IconBack
= 1;
1723 else /* no colorset */
1725 b
->c
->colorset
= -1;
1726 #ifdef DEBUG_LOADDATA
1727 fprintf(stderr
, ", colors2");
1729 if (b
->c
->flags
.b_Fore
)
1730 b
->c
->fc
= GetColor(b
->c
->fore
);
1731 if (b
->c
->flags
.b_Back
)
1733 b
->c
->bc
= GetColor(b
->c
->back
);
1734 b
->c
->hc
= GetHilite(b
->c
->bc
);
1735 b
->c
->sc
= GetShadow(b
->c
->bc
);
1736 if (b
->c
->flags
.b_IconBack
&& !b
->c
->flags
.b_TransBack
)
1738 if (!LoadIconFile(b
->c
->back_file
, &b
->c
->backicon
, -1))
1739 b
->c
->flags
.b_IconBack
= 0;
1748 if (b
->flags
.b_Font
)
1750 #ifdef DEBUG_LOADDATA
1751 fprintf(stderr
, ", font \"%s\"", b
->font_string
);
1754 if (strncasecmp(b
->font_string
, "none", 4) == 0)
1758 else if (!(b
->Ffont
= FlocaleLoadFont(Dpy
, b
->font_string
, MyName
)))
1760 b
->flags
.b_Font
= 0;
1764 if (b
->flags
.b_Container
&& b
->c
->flags
.b_Font
)
1766 #ifdef DEBUG_LOADDATA
1767 fprintf(stderr
, ", font2 \"%s\"", b
->c
->font_string
);
1769 if (strncasecmp(b
->c
->font_string
, "none", 4) == 0)
1773 else if (!(b
->c
->Ffont
= FlocaleLoadFont(Dpy
, b
->c
->font_string
, MyName
)))
1775 b
->c
->flags
.b_Font
= 0;
1779 /* Calculate subbutton sizes */
1780 if (b
->flags
.b_Container
&& b
->c
->num_buttons
)
1782 #ifdef DEBUG_LOADDATA
1783 fprintf(stderr
, ", entering container\n");
1785 for (i
= 0; i
< b
->c
->num_buttons
; i
++)
1786 if (b
->c
->buttons
[i
])
1787 RecursiveLoadData(b
->c
->buttons
[i
], &x
, &y
);
1789 if (b
->c
->flags
.b_Size
)
1794 #ifdef DEBUG_LOADDATA
1795 fprintf(stderr
, "%s: Loading: Back to container 0x%06x", MyName
, (ushort
)b
);
1798 x
*= b
->c
->num_columns
;
1799 y
*= b
->c
->num_rows
;
1804 /* $ix & $iy are dimensions of Icon
1805 $tx & $ty are dimensions of Title
1806 $hix & $hiy are dimensions of ActiveIcon
1807 $htx & $hty are dimensions of ActiveTitle
1808 $pix & $piy are dimensions of PressIcon
1809 $ptx & $pty are dimensions of PressTitle
1811 Note that if No ActiveIcon is specified, Icon is displayed during hover.
1812 Similarly for ActiveTitle, PressIcon & PressTitle. */
1813 ix
= iy
= tx
= ty
= hix
= hiy
= htx
= hty
= pix
= piy
= ptx
= pty
= 0;
1818 LoadIconFile(b
->icon_file
, &b
->icon
, buttonColorset(b
)))
1820 #ifdef DEBUG_LOADDATA
1821 fprintf(stderr
, ", icon \"%s\"", b
->icon_file
);
1823 ix
= b
->icon
->width
;
1824 iy
= b
->icon
->height
;
1827 b
->flags
.b_Icon
= 0;
1829 /* load the active icon. */
1830 if (b
->flags
.b_ActiveIcon
&&
1831 LoadIconFile(b
->active_icon_file
, &b
->activeicon
, buttonColorset(b
)))
1833 #ifdef DEBUG_LOADDATA
1834 fprintf(stderr
, ", active icon \"%s\"", b
->active_icon_file
);
1837 hix
= b
->activeicon
->width
;
1838 hiy
= b
->activeicon
->height
;
1844 b
->flags
.b_ActiveIcon
= 0;
1847 /* load the press icon. */
1848 if (b
->flags
.b_PressIcon
&&
1849 LoadIconFile(b
->press_icon_file
, &b
->pressicon
, buttonColorset(b
)))
1851 #ifdef DEBUG_LOADDATA
1852 fprintf(stderr
, ", press icon \"%s\"", b
->press_icon_file
);
1855 pix
= b
->pressicon
->width
;
1856 piy
= b
->pressicon
->height
;
1862 b
->flags
.b_PressIcon
= 0;
1865 /* calculate Title dimensions. */
1866 if (b
->flags
.b_Title
&& (Ffont
= buttonFont(b
)))
1868 #ifdef DEBUG_LOADDATA
1869 fprintf(stderr
, ", title \"%s\"", b
->title
);
1871 if (buttonJustify(b
)&b_Horizontal
)
1873 tx
= buttonXPad(b
) + FlocaleTextWidth(Ffont
, b
->title
, strlen(b
->title
));
1878 tx
= FlocaleTextWidth(Ffont
, b
->title
, strlen(b
->title
));
1883 /* calculate ActiveTitle dimensions. */
1884 if (b
->flags
.b_ActiveTitle
&& (Ffont
= buttonFont(b
)))
1886 #ifdef DEBUG_LOADDATA
1887 fprintf(stderr
, ", title \"%s\"", b
->title
);
1889 if (buttonJustify(b
) & b_Horizontal
)
1891 htx
= buttonXPad(b
) + FlocaleTextWidth(Ffont
, b
->activeTitle
,
1892 strlen(b
->activeTitle
));
1893 hty
= Ffont
->height
;
1897 htx
= FlocaleTextWidth(Ffont
, b
->activeTitle
, strlen(b
->activeTitle
));
1898 hty
= Ffont
->height
;
1907 /* calculate PressTitle dimensions. */
1908 if (b
->flags
.b_PressTitle
&& (Ffont
= buttonFont(b
)))
1910 #ifdef DEBUG_LOADDATA
1911 fprintf(stderr
, ", title \"%s\"", b
->title
);
1913 if (buttonJustify(b
) & b_Horizontal
)
1915 ptx
= buttonXPad(b
) + FlocaleTextWidth(Ffont
, b
->pressTitle
,
1916 strlen(b
->pressTitle
));
1917 pty
= Ffont
->height
;
1921 ptx
= FlocaleTextWidth(Ffont
, b
->pressTitle
, strlen(b
->pressTitle
));
1922 pty
= Ffont
->height
;
1931 x
+= max(max(ix
, tx
), max(hix
, htx
));
1932 y
+= max(iy
+ ty
, hiy
+ hty
);
1934 if (b
->flags
.b_Size
)
1940 x
+= 2 * (buttonFrame(b
) + buttonXPad(b
));
1941 y
+= 2 * (buttonFrame(b
) + buttonYPad(b
));
1946 *maxx
= max(x
, *maxx
);
1947 *maxy
= max(y
, *maxy
);
1948 #ifdef DEBUG_LOADDATA
1949 fprintf(stderr
, ", size %ux%u, done\n", x
, y
);
1954 static void HandlePanelPress(button_info
*b
)
1958 int px
, py
, pw
, ph
, pbw
;
1959 int ax
, ay
, aw
, ah
, abw
;
1961 int steps
= b
->slide_steps
;
1966 XSizeHints mysizehints
;
1969 XWindowAttributes xwa
;
1973 if (XGetWindowAttributes(Dpy
, b
->PanelWin
, &xwa
))
1974 is_mapped
= (xwa
.map_state
== IsViewable
);
1978 /* force StaticGravity on window */
1979 mysizehints
.flags
= 0;
1980 XGetWMNormalHints(Dpy
, b
->PanelWin
, &mysizehints
, &supplied
);
1981 mysizehints
.flags
|= PWinGravity
;
1982 mysizehints
.win_gravity
= StaticGravity
;
1983 XSetWMNormalHints(Dpy
, b
->PanelWin
, &mysizehints
);
1985 XGetGeometry(Dpy
, b
->PanelWin
, &JunkW
, &b
->x
, &b
->y
, &b
->w
, &b
->h
,
1988 /* get the current geometry */
1989 XTranslateCoordinates(
1990 Dpy
, b
->PanelWin
, Root
, b
->x
, b
->y
, &b
->x
, &b
->y
, &JunkW
);
1996 /* Make sure the icon is unmapped first. Needed to work properly with
1997 * shaded and iconified windows. */
1998 XWithdrawWindow(Dpy
, b
->PanelWin
, screen
);
2000 /* now request mapping in the void and wait until it gets mapped */
2001 mysizehints
.flags
= 0;
2002 XGetWMNormalHints(Dpy
, b
->PanelWin
, &mysizehints
, &supplied
);
2003 mysizehints
.flags
|= USPosition
;
2004 /* hack to prevent mapping panels on wrong screen with StartsOnScreen */
2005 FScreenMangleScreenIntoUSPosHints(FSCREEN_XYPOS
, &mysizehints
);
2006 XSetWMNormalHints(Dpy
, b
->PanelWin
, &mysizehints
);
2007 /* make sure its not mapped as an icon */
2008 wmhints
.flags
= StateHint
;
2009 wmhints
.initial_state
= NormalState
;
2010 XSetWMHints(Dpy
, b
->PanelWin
, &wmhints
);
2012 /* map the window in the void */
2013 XMoveWindow(Dpy
, b
->PanelWin
, 32767, 32767);
2014 XMapWindow(Dpy
, b
->PanelWin
);
2017 /* give the X server the CPU to do something */
2020 /* wait until it appears or one second has passed */
2021 for (i
= 0; i
< 10; i
++)
2023 if (!XGetWindowAttributes(Dpy
, b
->PanelWin
, &xwa
))
2025 /* the window has been destroyed */
2026 XUnmapWindow(Dpy
, b
->PanelWin
);
2028 RedrawButton(b
, DRAW_CLEAN
, NULL
);
2031 if (xwa
.map_state
== IsViewable
)
2033 /* okay, it's mapped */
2036 /* still unmapped wait 0.1 seconds and try again */
2040 if (xwa
.map_state
!= IsViewable
)
2042 /* give up after one second */
2043 XUnmapWindow(Dpy
, b
->PanelWin
);
2045 RedrawButton(b
, DRAW_FORCE
, NULL
);
2050 /* We're sure that the window is mapped and decorated now. Find the top level
2057 if (!b
->panel_flags
.ignore_lrborder
|| !b
->panel_flags
.ignore_tbborder
)
2059 ancestor
= GetTopAncestorWindow(Dpy
, b
->PanelWin
);
2063 XGetGeometry(Dpy
, ancestor
, &JunkW
, &ax
, &ay
, (unsigned int *)&aw
,
2064 (unsigned int *)&ah
, (unsigned int *)&abw
, &d
) &&
2065 XGetGeometry(Dpy
, b
->PanelWin
, &JunkW
, &px
, &py
, (unsigned int *)&pw
,
2066 (unsigned int *)&ph
, (unsigned int *)&pbw
, &d
) &&
2067 XTranslateCoordinates(
2068 Dpy
, b
->PanelWin
, ancestor
, 0, 0, &px
, &py
, &JunkW
))
2070 /* calculate the 'border' width in all four directions */
2071 if (!b
->panel_flags
.ignore_lrborder
)
2073 lb
= max(px
, 0) + abw
;
2074 rb
= max((aw
+ abw
) - (px
+ pw
), 0) + abw
;
2076 if (!b
->panel_flags
.ignore_tbborder
)
2078 tb
= max(py
, 0) + abw
;
2079 bb
= max((ah
+ abw
) - (py
+ ph
), 0) + abw
;
2084 /* now find the source and destination positions for the slide operation */
2085 GetPanelGeometry(is_mapped
, b
, lb
, tb
, rb
, bb
, &x1
, &y1
, &w1
, &h1
);
2086 GetPanelGeometry(!is_mapped
, b
, lb
, tb
, rb
, bb
, &x2
, &y2
, &w2
, &h2
);
2087 MyXUngrabServer(Dpy
);
2089 /* to force fvwm to map the window where we want */
2092 /* don't slide the window if it has been moved or resized */
2093 if (b
->x
!= x1
|| b
->y
!= y1
|| b
->w
!= w1
|| b
->h
!= h1
)
2099 /* redraw our button */
2100 b
->newflags
.panel_mapped
= !is_mapped
;
2102 /* make sure the window maps on the current desk */
2103 sprintf(cmd
, "Silent WindowId 0x%08x (!Sticky) MoveToDesk 0",
2105 SendInfo(fd
, cmd
, b
->PanelWin
);
2106 SlideWindow(Dpy
, b
->PanelWin
,
2109 steps
, b
->slide_delay_ms
, NULL
, b
->panel_flags
.smooth
,
2110 (b
->swallow
&b_NoHints
) ? 0 : 1);
2113 XUnmapWindow(Dpy
, b
->PanelWin
);
2115 tmp
= CurrentButton
;
2116 CurrentButton
= NULL
;
2117 RedrawButton(b
, DRAW_FORCE
, NULL
);
2118 CurrentButton
= tmp
;
2120 /* Give fvwm a chance to update the window. Otherwise the window may end up
2121 * too small. This doesn't prevent this completely, but makes it much less
2130 *** CreateUberButtonWindow()
2131 *** Sizes and creates the window
2133 void CreateUberButtonWindow(button_info
*ub
, int maxx
, int maxy
)
2135 XSizeHints mysizehints
;
2138 XClassHint myclasshints
;
2142 x
= UberButton
->x
; /* Geometry x where to put the panel */
2143 y
= UberButton
->y
; /* Geometry y where to put the panel */
2144 xneg
= UberButton
->w
;
2145 yneg
= UberButton
->h
;
2157 fprintf(stderr
, "making atoms...");
2160 _XA_WM_DEL_WIN
= XInternAtom(Dpy
, "WM_DELETE_WINDOW", 0);
2163 fprintf(stderr
, "sizing...");
2166 mysizehints
.flags
= PWinGravity
| PBaseSize
;
2167 mysizehints
.base_width
= 0;
2168 mysizehints
.base_height
= 0;
2169 mysizehints
.width
= mysizehints
.base_width
+ maxx
;
2170 mysizehints
.height
= mysizehints
.base_height
+ maxy
;
2172 if (w
>-1) /* from geometry */
2175 fprintf(stderr
, "constraining (w=%i)...", w
);
2177 ConstrainSize(&mysizehints
, &w
, &h
);
2178 mysizehints
.width
= w
;
2179 mysizehints
.height
= h
;
2180 mysizehints
.flags
|= USSize
;
2184 fprintf(stderr
, "gravity...");
2192 wx
= DisplayWidth(Dpy
, screen
) + x
- mysizehints
.width
;
2193 gravity
= NorthEastGravity
;
2201 wy
= DisplayHeight(Dpy
, screen
) + y
- mysizehints
.height
;
2202 gravity
= SouthWestGravity
;
2210 gravity
= SouthEastGravity
;
2212 mysizehints
.flags
|= USPosition
;
2214 /* hack to prevent mapping panels on wrong screen with
2216 FScreenMangleScreenIntoUSPosHints(FSCREEN_XYPOS
, &mysizehints
);
2218 mysizehints
.win_gravity
= gravity
;
2221 if (mysizehints
.flags
&USPosition
)
2224 "create(%i,%i,%u,%u,1,%u,%u)...",
2225 wx
, wy
, mysizehints
.width
, mysizehints
.height
,
2226 (ushort
)fore_pix
, (ushort
)back_pix
);
2231 "create(-,-,%u,%u,1,%u,%u)...",
2232 mysizehints
.width
, mysizehints
.height
,
2233 (ushort
)fore_pix
, (ushort
)back_pix
);
2238 Dpy
, MyWindow
, wx
, wy
, mysizehints
.width
, mysizehints
.height
);
2240 XSetWMNormalHints(Dpy
, MyWindow
, &mysizehints
);
2244 XSetTransientForHint(Dpy
, MyWindow
, Root
);
2248 fprintf(stderr
, "colors...");
2252 back_pix
= GetColor("white");
2253 fore_pix
= GetColor("black");
2254 hilite_pix
= back_pix
;
2255 shadow_pix
= fore_pix
;
2259 fore_pix
= ub
->c
->fc
;
2260 back_pix
= ub
->c
->bc
;
2261 hilite_pix
= ub
->c
->hc
;
2262 shadow_pix
= ub
->c
->sc
;
2267 fprintf(stderr
, "properties...");
2269 XSetWMProtocols(Dpy
, MyWindow
, &_XA_WM_DEL_WIN
, 1);
2271 myclasshints
.res_name
= safestrdup(MyName
);
2272 myclasshints
.res_class
= safestrdup("FvwmButtons");
2275 XTextProperty mynametext
;
2276 char *list
[] = { NULL
, NULL
};
2278 if (!XStringListToTextProperty(list
, 1, &mynametext
))
2281 "%s: Failed to convert name to XText\n",
2286 Dpy
, MyWindow
, &mynametext
, &mynametext
, NULL
, 0,
2287 &mysizehints
, NULL
, &myclasshints
);
2288 XFree(mynametext
.value
);
2291 XSelectInput(Dpy
, MyWindow
, MW_EVENTS
);
2294 fprintf(stderr
, "GC...");
2296 gcm
= GCForeground
|GCBackground
;
2297 gcv
.foreground
= fore_pix
;
2298 gcv
.background
= back_pix
;
2299 if (ub
&& ub
->c
&& ub
->c
->Ffont
&& ub
->c
->Ffont
->font
&& ub
->Ffont
)
2301 gcv
.font
= ub
->c
->Ffont
->font
->fid
;
2304 NormalGC
= fvwmlib_XCreateGC(Dpy
, MyWindow
, gcm
, &gcv
);
2305 gcv
.foreground
= shadow_pix
;
2306 gcv
.background
= fore_pix
;
2307 ShadowGC
= fvwmlib_XCreateGC(Dpy
, MyWindow
, gcm
, &gcv
);
2309 if (ub
->c
->flags
.b_Colorset
)
2311 SetWindowBackground(
2312 Dpy
, MyWindow
, mysizehints
.width
, mysizehints
.height
,
2313 &Colorset
[ub
->c
->colorset
], Pdepth
, NormalGC
, True
);
2315 else if (ub
->c
->flags
.b_IconBack
&& !ub
->c
->flags
.b_TransBack
)
2317 XSetWindowBackgroundPixmap(
2318 Dpy
, MyWindow
, ub
->c
->backicon
->picture
);
2322 XSetWindowBackground(Dpy
, MyWindow
, back_pix
);
2325 free(myclasshints
.res_class
);
2326 free(myclasshints
.res_name
);
2329 /* --------------------------------------------------------------------------*/
2332 void DebugEvents(XEvent
*event
)
2334 char *event_names
[] =
2372 fprintf(stderr
, "%s: Received %s event from window 0x%x\n",
2373 MyName
, event_names
[event
->type
], (ushort
)event
->xany
.window
);
2379 *** Waits for next X event, or for an auto-raise timeout.
2381 int My_FNextEvent(Display
*Dpy
, XEvent
*event
)
2384 static int miss_counter
= 0;
2385 static Bool fsm_pending
= False
;
2390 FNextEvent(Dpy
, event
);
2398 FD_SET(x_fd
, &in_fdset
);
2399 FD_SET(fd
[1], &in_fdset
);
2400 fsm_fdset(&in_fdset
);
2405 tv
.tv_usec
= 10000; /* 10 ms */
2409 fd_width
, SELECT_FD_SET_CAST
&in_fdset
, 0, 0,
2410 (fsm_pending
)? &tv
:NULL
) > 0)
2412 if (FD_ISSET(x_fd
, &in_fdset
))
2416 FNextEvent(Dpy
, event
);
2427 if (miss_counter
> 100)
2433 if (FD_ISSET(fd
[1], &in_fdset
))
2435 FvwmPacket
* packet
= ReadFvwmPacket(fd
[1]);
2436 if ( packet
== NULL
)
2442 process_message( packet
->type
, packet
->body
);
2446 fsm_pending
= fsm_process(&in_fdset
);
2453 fsm_pending
= fsm_process(&in_fdset
);
2461 *** Is run after the windowlist is checked. If any button hangs on UseOld,
2462 *** it has failed, so we try to spawn a window for them.
2464 void SpawnSome(void)
2466 static char first
= 1;
2467 button_info
*b
, *ub
= UberButton
;
2476 while (NextButton(&ub
, &b
, &button
, 0))
2478 if ((buttonSwallowCount(b
) == 1) && b
->flags
.b_Hangon
&&
2479 (buttonSwallow(b
)&b_UseOld
))
2485 "%s: Button 0x%06x did not find a "
2486 "\"%s\" window, %s",
2487 MyName
, (ushort
)b
, b
->hangon
,
2490 p
= module_expand_action(
2491 Dpy
, screen
, b
->spawn
, NULL
,
2492 UberButton
->c
->fore
,
2493 UberButton
->c
->back
);
2504 /* This function is a real hack. It forces our nice background upon the
2505 * windows of the swallowed application! */
2506 void change_swallowed_window_colorset(button_info
*b
, Bool do_clear
)
2508 Window w
= SwallowedWindow(b
);
2509 Window
*children
= None
;
2512 nchildren
= GetEqualSizeChildren(
2513 Dpy
, w
, Pdepth
, XVisualIDFromVisual(Pvisual
), Pcmap
, &children
);
2514 SetWindowBackground(
2515 Dpy
, w
, buttonWidth(b
), buttonHeight(b
),
2516 &Colorset
[b
->colorset
], Pdepth
, NormalGC
, do_clear
);
2517 while (nchildren
-- > 0)
2519 SetWindowBackground(
2520 Dpy
, children
[nchildren
], buttonWidth(b
),
2521 buttonHeight(b
), &Colorset
[b
->colorset
], Pdepth
,
2522 NormalGC
, do_clear
);
2532 static void send_bg_change_to_module(button_info
*b
, XEvent
*Event
)
2534 int bx
, by
, bpx
, bpy
, bf
;
2538 buttonInfo(b
, &bx
, &by
, &bpx
, &bpy
, &bf
);
2539 Event
->xconfigure
.x
= UberButton
->x
+ bx
;
2540 Event
->xconfigure
.y
= UberButton
->y
+ by
;
2541 Event
->xconfigure
.width
= b
->icon_w
;
2542 Event
->xconfigure
.height
= b
->icon_h
;
2543 Event
->xconfigure
.window
= SwallowedWindow(b
);
2544 FSendEvent(Dpy
, SwallowedWindow(b
), False
, NoEventMask
, Event
);
2549 sprintf(cmd
, "PropertyChange %u %u %lu",
2550 MX_PROPERTY_CHANGE_BACKGROUND
, 0, SwallowedWindow(b
));
2551 SendText(fd
, cmd
, 0);
2555 static void update_root_transparency(XEvent
*Event
)
2557 button_info
*ub
, *b
;
2559 Bool bg_is_transparent
= CSET_IS_TRANSPARENT(UberButton
->c
->colorset
);
2561 if (bg_is_transparent
)
2563 SetWindowBackground(
2564 Dpy
, MyWindow
, UberButton
->c
->width
,
2565 UberButton
->c
->height
,
2566 &Colorset
[UberButton
->c
->colorset
],
2567 Pdepth
, NormalGC
, True
);
2568 /* the window is redraw by exposure. It is very difficult
2569 * the clear only the needed part and then redraw the
2570 * cleared buttons (pbs with containers which contain containers
2574 if (!bg_is_transparent
)
2576 /* update root transparent button (and its childs) */
2579 while (NextButton(&ub
, &b
, &button
, 1))
2582 Bool redraw
= False
;
2585 /* see if _a_ parent (!= UberButton) is root trans */
2586 while (tmpb
->parent
!= NULL
&& !redraw
)
2588 if (CSET_IS_TRANSPARENT_ROOT(
2589 buttonColorset(tmpb
)))
2593 tmpb
= tmpb
->parent
;
2597 RedrawButton(b
, DRAW_ALL
, NULL
);
2603 /* Handle the swallowed window */
2606 while (NextButton(&ub
, &b
, &button
, 0))
2608 if (buttonSwallowCount(b
) == 3 && b
->flags
.b_Swallow
)
2610 /* should handle 2 cases: module or not */
2611 if (b
->swallow
& b_FvwmModule
)
2613 if (bg_is_transparent
)
2616 send_bg_change_to_module(b
, Event
);
2619 else if (b
->flags
.b_Colorset
&&
2620 CSET_IS_TRANSPARENT(b
->colorset
))
2622 change_swallowed_window_colorset(b
, True
);
2629 static void recursive_change_colorset(
2630 container_info
*c
, int colorset
, XEvent
*Event
)
2633 button_info
*ub
, *b
;
2638 while (NextButton(&ub
, &b
, &button
, 1))
2640 Bool redraw
= False
;
2643 /* see if _a_ parent (!= UberButton) has colorset as cset */
2644 while (tmpb
->parent
!= NULL
&& !redraw
)
2646 if (buttonColorset(tmpb
) == colorset
)
2650 tmpb
= tmpb
->parent
;
2656 if (b
->flags
.b_Swallow
)
2658 /* swallowed window */
2659 if (buttonSwallowCount(b
) == 3 && b
->IconWin
!= None
)
2661 RedrawButton(b
, DRAW_ALL
, NULL
);
2662 if (b
->flags
.b_Colorset
&&
2663 !(b
->swallow
&b_FvwmModule
))
2665 change_swallowed_window_colorset(
2672 RedrawButton(b
, DRAW_ALL
, NULL
);
2679 static void change_colorset(int colorset
, XEvent
*Event
)
2681 if (UberButton
->c
->flags
.b_Colorset
&&
2682 colorset
== UberButton
->c
->colorset
)
2684 button_info
*ub
, *b
;
2687 SetWindowBackground(
2688 Dpy
, MyWindow
, UberButton
->c
->width
,
2689 UberButton
->c
->height
,
2690 &Colorset
[colorset
], Pdepth
, NormalGC
, True
);
2692 /* some change are done by exposing. Do the other one */
2695 while (NextButton(&ub
, &b
, &button
, 0))
2697 if (b
->flags
.b_Swallow
&& buttonSwallowCount(b
) == 3)
2699 if (b
->swallow
&b_FvwmModule
)
2701 /* the bg has changed send the info to
2704 send_bg_change_to_module(b
, Event
);
2706 else if (CSET_IS_TRANSPARENT_PR(b
->colorset
) &&
2707 !buttonBackgroundButton(b
->parent
, NULL
))
2709 /* the swallowed app has a ParentRel bg
2710 * and the bg of the button is the bg */
2711 change_swallowed_window_colorset(
2719 recursive_change_colorset(
2720 UberButton
->c
, colorset
, Event
);
2723 static void handle_config_info_packet(unsigned long *body
)
2725 char *tline
, *token
;
2728 tline
= (char*)&(body
[3]);
2729 token
= PeekToken(tline
, &tline
);
2730 if (StrEquals(token
, "Colorset"))
2732 colorset
= LoadColorset(tline
);
2733 change_colorset(colorset
, NULL
);
2735 else if (StrEquals(token
, XINERAMA_CONFIG_STRING
))
2737 FScreenConfigureModule(tline
);
2744 *** process_message()
2745 *** Process window list messages
2747 void process_message(unsigned long type
, unsigned long *body
)
2749 struct ConfigWinPacket
*cfgpacket
;
2757 button_info
*b
, *ub
;
2760 while (NextButton(&ub
, &b
, &button
, 1))
2762 RedrawButton(b
, DRAW_FORCE
, NULL
);
2766 case M_END_WINDOWLIST
:
2775 CheckForHangon(body
);
2778 handle_config_info_packet((unsigned long*)body
);
2781 case M_CONFIGURE_WINDOW
:
2782 cfgpacket
= (void *) body
;
2783 if (cfgpacket
->w
== MyWindow
)
2785 button_lborder
= button_rborder
= button_tborder
2786 = button_bborder
= cfgpacket
->border_width
;
2787 switch (GET_TITLE_DIR(cfgpacket
))
2790 button_tborder
+= cfgpacket
->title_height
;
2793 button_bborder
+= cfgpacket
->title_height
;
2796 button_lborder
+= cfgpacket
->title_height
;
2799 button_rborder
+= cfgpacket
->title_height
;
2804 case MX_PROPERTY_CHANGE
:
2805 if (body
[0] == MX_PROPERTY_CHANGE_BACKGROUND
&&
2806 ((!swallowed
&& body
[2] == 0)
2807 || (swallowed
&& body
[2] == MyWindow
)))
2809 if (CSET_IS_TRANSPARENT_PR(UberButton
->c
->colorset
))
2811 update_root_transparency(NULL
);
2814 else if (body
[0] == MX_PROPERTY_CHANGE_SWALLOW
2815 && body
[2] == MyWindow
)
2821 button_info
*b
, *ub
= UberButton
;
2824 str
= (char *)&body
[3];
2825 swallowed
= body
[1];
2826 if (swallowed
&& str
&& sscanf(str
, "%lu", &u
) == 1)
2828 swallower_win
= (Window
)u
;
2834 /* update the swallower */
2835 s
= ((swallower_win
&& swallowed
) ? swallower_win
:
2837 while (NextButton(&ub
, &b
, &button
, 0))
2839 swin
= SwallowedWindow(b
);
2840 if ((buttonSwallowCount(b
) == 3) && swin
)
2843 "PropertyChange %u %u %lu %lu",
2844 MX_PROPERTY_CHANGE_SWALLOW
, 1,
2846 SendText(fd
, cmd
, 0);
2852 parse_message_line((char *)&body
[3]);
2860 /* --------------------------------- swallow code -------------------------- */
2863 *** CheckForHangon()
2864 *** Is the window here now?
2866 void CheckForHangon(unsigned long *body
)
2868 button_info
*b
, *ub
= UberButton
;
2872 cbody
= (char *)&body
[3];
2874 while (NextButton(&ub
, &b
, &button
, 0))
2876 if (b
->flags
.b_Hangon
&& matchWildcards(b
->hangon
, cbody
))
2878 /* Is this a swallowing button in state 1? */
2879 if (buttonSwallowCount(b
) == 1)
2881 b
->swallow
&= ~b_Count
;
2884 /* must grab the server here to make sure
2885 * the window is not swallowed by some
2886 * other application. */
2887 if (b
->flags
.b_Panel
)
2889 b
->PanelWin
= (Window
)body
[0];
2893 b
->IconWin
= (Window
)body
[0];
2895 b
->flags
.b_Hangon
= 0;
2897 /* We get the parent of the window to compare
2902 Dpy
, SwallowedWindow(b
),
2903 &b
->x
, &b
->y
, &b
->w
, &b
->h
,
2908 "%s: Button 0x%06x %s 0x%lx \"%s\", "
2909 "parent 0x%lx\n", MyName
, (ushort
)b
,
2910 "will swallow window", body
[0], cbody
,
2914 if (buttonSwallow(b
)&b_UseOld
)
2921 /* Else it is an executing button with a
2926 "%s: Button 0x%06x %s 0x%lx "\"%s
\", "
2927 "released
\n", MyName, (int)b,
2928 "hung on window
", body[0], cbody);
2930 b->flags.b_Hangon = 0;
2933 RedrawButton(b, DRAW_FORCE, NULL);
2937 else if (buttonSwallowCount(b) >= 2
2938 && (Window)body[0] == SwallowedWindow(b))
2940 /* This window has already been swallowed by
2948 *** GetRealGeometry()
2949 *** Traverses window tree to find the real x,y of a window. Any simpler?
2950 *** Returns parent window, or None if failed.
2952 Window GetRealGeometry(
2953 Display *dpy, Window win, int *x, int *y, unsigned int *w,
2954 unsigned int *h, unsigned int *bw, unsigned int *d)
2958 Window *children = None;
2961 if (!XGetGeometry(dpy, win, &root, x, y, w, h, bw, d))
2966 /* Now, x and y are not correct. They are parent relative, not root...
2967 * Hmm, ever heard of XTranslateCoordinates!? */
2968 XTranslateCoordinates(dpy, win, root, *x, *y, x, y, &rp);
2969 if (!XQueryTree(dpy, win, &root, &rp, &children, &n))
2981 static void GetPanelGeometry(
2982 Bool get_big, button_info *b, int lb, int tb, int rb, int bb,
2983 int *x, int *y, int *w, int *h)
2986 int ftb = 0, fbb = 0, frb = 0, flb = 0;
2989 /* take in acount or not the FvwmButtons borders width */
2990 if (b->panel_flags.buttons_tbborder)
2992 ftb = button_tborder;
2993 fbb = button_bborder;
2995 if (b->panel_flags.buttons_lrborder)
2997 frb = button_rborder;
2998 flb = button_lborder;
3001 switch (b->slide_context)
3003 case SLIDE_CONTEXT_PB: /* slide relatively to the panel button */
3004 bx = buttonXPos(b, b->n);
3005 by = buttonYPos(b, b->n);
3006 bw = buttonWidth(b);
3007 bh = buttonHeight(b);
3008 XTranslateCoordinates(
3009 Dpy, MyWindow, Root, bx, by, &bx, &by, &JunkWin);
3011 case SLIDE_CONTEXT_MODULE: /* slide relatively to FvwmButtons */
3013 unsigned int dum, dum2;
3016 Dpy, MyWindow, &JunkWin, &bx, &by,
3017 (unsigned int *)&bw, (unsigned int *)&bh,
3018 (unsigned int *)&dum, &dum2))
3020 XTranslateCoordinates(
3021 Dpy, MyWindow, Root, bx, by, &bx, &by,
3027 /* fall thorugh to SLIDE_CONTEXT_ROOT */
3030 case SLIDE_CONTEXT_ROOT: /* slide relatively to the root windows */
3031 switch (b->slide_direction)
3055 /* relative corrections in % or pixel */
3058 if (b->relative_x != 0)
3060 if (b->panel_flags.relative_x_pixel)
3066 *x = (int)(b->relative_x * bw) / 100;
3069 if (b->relative_y != 0)
3071 if (b->panel_flags.relative_y_pixel)
3077 *y = (int)(b->relative_y * bh) / 100;
3081 switch (b->slide_direction)
3084 switch (b->slide_position)
3086 case SLIDE_POSITION_CENTER:
3087 *x += bx + (int)(bw - (b->w + (rb - lb))
3090 case SLIDE_POSITION_LEFT_TOP:
3091 *x += bx + lb - flb;
3093 case SLIDE_POSITION_RIGHT_BOTTOM:
3094 *x += bx + bw - b->w - rb + frb;
3100 *y += by - (int)b->h - bb - ftb;
3105 *y += by - bb - ftb;
3110 switch (b->slide_position)
3112 case SLIDE_POSITION_CENTER:
3113 *x += bx + (int)(bw - (b->w + (rb - lb))
3116 case SLIDE_POSITION_LEFT_TOP:
3117 *x += bx + lb - flb;
3119 case SLIDE_POSITION_RIGHT_BOTTOM:
3120 *x += bx + bw - b->w - rb + frb;
3123 *y += by + (int)bh + tb + fbb;
3135 switch (b->slide_position)
3137 case SLIDE_POSITION_CENTER:
3138 *y += by + (int)(bh - b->h + (tb - bb)
3141 case SLIDE_POSITION_LEFT_TOP:
3142 *y += by + tb - ftb;
3144 case SLIDE_POSITION_RIGHT_BOTTOM:
3145 *y += by + bh - b->h - bb + fbb;
3151 *x += bx - (int)b->w - rb - flb;
3156 *x += bx - rb - flb;
3161 switch (b->slide_position)
3163 case SLIDE_POSITION_CENTER:
3164 *y += by + (int)(bh - b->h + (tb - bb)
3167 case SLIDE_POSITION_LEFT_TOP:
3168 *y += by + tb - ftb;
3170 case SLIDE_POSITION_RIGHT_BOTTOM:
3171 *y += by + bh - b->h - bb + fbb;
3174 *x += bx + (int)bw + lb + frb;
3193 *** Executed when swallowed windows get mapped
3195 void swallow(unsigned long *body)
3197 button_info *ub = UberButton, *b;
3202 FlocaleNameString temp;
3204 temp.name_list = NULL;
3206 while (NextButton(&ub, &b, &button, 0))
3208 Window swin = SwallowedWindow(b);
3210 if ((swin == (Window)body[0]) && (buttonSwallowCount(b) == 2))
3212 /* Store the geometry in case we need to unswallow.
3215 p = GetRealGeometry(
3216 Dpy, swin, &b->x, &b->y, &b->w, &b->h, &b->bw,
3220 "%s
: Button
0x
%06x
%s
0x
%lx
, parent
0x
%lx
\n",
3221 MyName, (ushort)b, "trying to swallow window
",
3226 /* This means the window is no more */ /* NO! wrong */
3229 "%s
: Window
0x
%lx (\"%s
\") disappeared
"
3230 " before swallow complete
\n",
3231 MyName, swin, b->hangon);
3232 /* Now what? For now: give up that button */
3233 b->flags.b_Hangon = 0;
3234 b->flags.b_Swallow = 0;
3235 b->flags.b_Panel = 0;
3239 if (p != b->IconWinParent)
3241 /* The window has been reparented */
3243 "%s
: Window
0x
%lx (\"%s
\") was grabbed
"
3244 " by someone
else (window
0x
%lx
)\n",
3245 MyName, swin, b->hangon, p);
3247 /* Request a new windowlist, we might have
3248 ignored another matching window.. */
3249 SendText(fd, "Send_WindowList
", 0);
3251 /* Back one square and lose one turn */
3252 b->swallow &= ~b_Count;
3254 b->flags.b_Hangon = 1;
3260 "%s
: Button
0x
%06x swallowed window
0x
%lx
\n",
3261 MyName, (ushort)b, body[0]);
3264 if (b->flags.b_Swallow)
3266 /* "Swallow
" the window! Place it in the void
3267 * so we don't see it until it's MoveResize'd */
3270 do_allow_bad_access = True;
3271 XSelectInput(Dpy, swin, SW_EVENTS);
3273 do_allow_bad_access = False;
3276 /* BadAccess means that the window is
3277 * already swallowed by someone else.
3278 * Wait for another window. */
3279 was_bad_access = False;
3280 /* Back one square and lose one turn */
3281 b->swallow &= ~b_Count;
3283 b->flags.b_Hangon = 1;
3284 MyXUngrabServer(Dpy);
3289 !b->flags.b_ActionIgnoresClientWindow
3291 i <= NUMBER_OF_EXTENDED_MOUSE_BUTTONS;
3294 if (b->action != NULL && b->action[i] != NULL)
3297 Dpy, i, 0, b->IconWin,
3298 False, ButtonPressMask
3299 | ButtonReleaseMask,
3309 XUnmapWindow(Dpy, swin);
3311 Dpy, swin, MyWindow, -32768, -32768);
3312 fsm_proxy(Dpy, swin, getenv("SESSION_MANAGER
"));
3314 MyXUngrabServer(Dpy);
3317 b->swallow &= ~b_Count;
3319 if (buttonSwallow(b) & b_UseTitle)
3321 if (b->flags.b_Title)
3325 b->flags.b_Title = 1;
3326 FlocaleGetNameProperty(
3327 XGetWMName, Dpy, swin, &temp);
3328 if (temp.name != NULL)
3331 &b->title, temp.name);
3332 FlocaleFreeNameProperty(&temp);
3336 CopyString(&b->title, "");
3341 XMapWindow(Dpy, swin);
3343 if (b->swallow & b_FvwmModule)
3345 /* if we swallow a module we send an avertisment */
3349 "PropertyChange
%u
%u
%lu
%lu
",
3350 MX_PROPERTY_CHANGE_SWALLOW, 1,
3352 swallower_win ? swallower_win
3354 SendText(fd, cmd, 0);
3356 if (b->flags.b_Colorset && !(b->swallow & b_FvwmModule))
3358 /* A short delay to give the application
3359 * the chance to set the background
3360 * itself, so we can override it.
3361 * If we don't do this, the application
3362 * may override our background. On the
3363 * other hand it may still override our
3364 * background, but our chances are a bit
3369 change_swallowed_window_colorset(b, True);
3371 if (FShapesSupported)
3373 if (UberButton->c->flags.b_TransBack)
3375 SetTransparentBackground(
3383 /* Redraw and force cleaning the background to erase the old button
3385 RedrawButton(b, DRAW_FORCE, NULL);
3387 else /* (b->flags & b_Panel) */
3389 b->swallow &= ~b_Count;
3391 XSelectInput(Dpy, swin, PA_EVENTS);
3392 if (!XWithdrawWindow(Dpy, swin, screen))
3394 /* oops. what can we do now?
3395 * let's pretend the unmap worked. */
3397 b->newflags.panel_mapped = 0;
3405 void exec_swallow(char *action, button_info *b)
3407 static char *my_sm_env = NULL;
3408 static char *orig_sm_env = NULL;
3410 static Bool sm_initialized = False;
3411 static Bool session_manager = False;
3419 if (!sm_initialized)
3421 /* use sm only when needed */
3422 sm_initialized = True;
3423 orig_sm_env = getenv("SESSION_MANAGER
");
3424 if (orig_sm_env && !StrEquals("", orig_sm_env))
3426 /* this set the new SESSION_MANAGER env */
3427 session_manager = fsm_init(MyName);
3431 if (!session_manager /*|| (buttonSwallow(b)&b_NoClose)*/)
3433 SendText(fd, action, 0);
3437 if (my_sm_env == NULL)
3439 my_sm_env = getenv("SESSION_MANAGER
");
3440 len = 45 + strlen(my_sm_env) + strlen(orig_sm_env);
3443 cmd = safemalloc(len + strlen(action));
3446 "FSMExecFuncWithSessionManagment
\"%s
\" \"%s
\" \"%s
\"",
3447 my_sm_env, action, orig_sm_env);
3448 SendText(fd, cmd, 0);