2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * This module is all original code
20 * Copyright 1993, Robert Nation
21 * You may use this code for any purpose, as long as the original
22 * copyright remains in the source code and all documentation
25 /* ---------------------------- included header files ---------------------- */
31 #include <sys/types.h>
35 #include <X11/keysym.h>
37 #include "libs/fvwmlib.h"
38 #include "libs/fvwmsignal.h"
39 #include "libs/setpgrp.h"
40 #include "libs/Grab.h"
41 #include "libs/Parse.h"
42 #include "libs/ColorUtils.h"
43 #include "libs/Graphics.h"
44 #include "libs/wild.h"
45 #include "libs/envvar.h"
46 #include "libs/ClientMsg.h"
47 #include "libs/Picture.h"
48 #include "libs/PictureUtils.h"
49 #include "libs/FGettext.h"
50 #include "libs/charmap.h"
51 #include "libs/wcontext.h"
58 #include "functions.h"
62 #include "module_interface.h"
68 #include "decorations.h"
69 #include "add_window.h"
72 #include "move_resize.h"
76 #endif /* HAVE_STROKE */
78 /* ---------------------------- local definitions -------------------------- */
80 /* ---------------------------- local macros ------------------------------- */
82 /* ---------------------------- imports ------------------------------------ */
84 extern float rgpctMovementDefault
[32];
85 extern int cpctMovementDefault
;
86 extern int cmsDelayDefault
;
88 /* ---------------------------- included code files ------------------------ */
90 /* ---------------------------- local types -------------------------------- */
91 typedef enum {FakeMouseEvent
, FakeKeyEvent
} FakeEventType
;
92 /* ---------------------------- forward declarations ----------------------- */
94 /* ---------------------------- local variables ---------------------------- */
96 static char *exec_shell_name
="/bin/sh";
98 /* button state strings must match the enumerated states */
99 static char *button_states
[BS_MaxButtonStateName
+ 1] =
108 "ToggledInactiveDown",
126 /* ---------------------------- exported variables (globals) --------------- */
128 char *ModulePath
= FVWM_MODULEDIR
;
129 int moduleTimeout
= DEFAULT_MODULE_TIMEOUT
;
131 /* ---------------------------- local functions ---------------------------- */
133 /** Prepend rather than replace the image path.
134 Used for obsolete PixmapPath and IconPath **/
135 static void obsolete_imagepaths( const char* pre_path
)
137 char* tmp
= stripcpy( pre_path
);
138 char* path
= alloca(strlen( tmp
) + strlen(PictureGetImagePath()) + 2 );
144 strcat( path
, PictureGetImagePath() );
146 PictureSetImagePath( path
);
153 * Reads a title button description (veliaa@rpi.edu)
156 static char *ReadTitleButton(
157 char *s
, TitleButton
*tb
, Boolean append
, int button
)
164 int bs_start
, bs_end
;
172 s
= SkipSpaces(s
, NULL
, 0);
173 t
= GetNextTokenIndex(s
, button_states
, 0, &bs
);
176 s
= SkipSpaces(t
, NULL
, 0);
184 else if (bs
== BS_Active
)
186 use_mask
= BS_MASK_INACTIVE
| BS_MASK_TOGGLED
;
189 else if (bs
== BS_Inactive
)
191 use_mask
= BS_MASK_INACTIVE
| BS_MASK_TOGGLED
;
192 set_mask
= BS_MASK_INACTIVE
;
194 else if (bs
== BS_ToggledActive
)
196 use_mask
= BS_MASK_INACTIVE
| BS_MASK_TOGGLED
;
197 set_mask
= BS_MASK_TOGGLED
;
199 else if (bs
== BS_ToggledInactive
)
201 use_mask
= BS_MASK_INACTIVE
| BS_MASK_TOGGLED
;
202 set_mask
= BS_MASK_INACTIVE
| BS_MASK_TOGGLED
;
204 else if (bs
== BS_AllNormal
)
206 use_mask
= BS_MASK_TOGGLED
;
209 else if (bs
== BS_AllToggled
)
211 use_mask
= BS_MASK_TOGGLED
;
212 set_mask
= BS_MASK_TOGGLED
;
214 else if (bs
== BS_AllActive
)
216 use_mask
= BS_MASK_INACTIVE
;
219 else if (bs
== BS_AllInactive
)
221 use_mask
= BS_MASK_INACTIVE
;
222 set_mask
= BS_MASK_INACTIVE
;
224 else if (bs
== BS_AllUp
)
226 use_mask
= BS_MASK_DOWN
;
229 else if (bs
== BS_AllDown
)
231 use_mask
= BS_MASK_DOWN
;
232 set_mask
= BS_MASK_DOWN
;
234 else if (bs
== BS_AllActiveUp
)
236 use_mask
= BS_MASK_INACTIVE
| BS_MASK_DOWN
;
239 else if (bs
== BS_AllActiveDown
)
241 use_mask
= BS_MASK_INACTIVE
| BS_MASK_DOWN
;
242 set_mask
= BS_MASK_DOWN
;
244 else if (bs
== BS_AllInactiveUp
)
246 use_mask
= BS_MASK_INACTIVE
| BS_MASK_DOWN
;
247 set_mask
= BS_MASK_INACTIVE
;
249 else if (bs
== BS_AllInactiveDown
)
251 use_mask
= BS_MASK_INACTIVE
| BS_MASK_DOWN
;
252 set_mask
= BS_MASK_INACTIVE
| BS_MASK_DOWN
;
255 if ((bs
& BS_MaxButtonStateMask
) == bs
)
265 bs_end
= BS_MaxButtonState
- 1;
266 for (i
= bs_start
; (i
& use_mask
) != set_mask
&& i
<= bs_end
;
277 if (!(end
= strchr(++s
, ')')))
280 ERR
, "ReadTitleButton",
281 "missing parenthesis: %s", s
);
284 s
= SkipSpaces(s
, NULL
, 0);
286 spec
= safemalloc(len
);
287 strncpy(spec
, s
, len
- 1);
295 spec
= SkipSpaces(spec
, NULL
, 0);
296 /* setup temporary in case button read fails */
297 memset(&tmpdf
, 0, sizeof(DecorFace
));
298 DFS_FACE_TYPE(tmpdf
.style
) = SimpleButton
;
300 if (strncmp(spec
, "--", 2) == 0)
302 /* only change flags */
304 for (i
= bs_start
; i
<= bs_end
; ++i
)
306 if (multiple
&& (i
& use_mask
) != set_mask
)
310 ReadDecorFace(spec
, &TB_STATE(*tb
)[i
], button
, verbose
);
314 else if (ReadDecorFace(spec
, &tmpdf
, button
, True
))
318 DecorFace
*head
= &TB_STATE(*tb
)[bs_start
];
319 DecorFace
*tail
= head
;
326 tail
->next
= (DecorFace
*)safemalloc(sizeof(DecorFace
));
327 memcpy(tail
->next
, &tmpdf
, sizeof(DecorFace
));
328 if (DFS_FACE_TYPE(tail
->next
->style
) == VectorButton
&&
329 DFS_FACE_TYPE((&TB_STATE(*tb
)[bs_start
])->style
) ==
332 /* override the default vector style */
334 &tail
->next
->style
, &head
->style
,
335 sizeof(DecorFaceStyle
));
336 DFS_FACE_TYPE(tail
->next
->style
) = VectorButton
;
339 FreeDecorFace(dpy
, head
);
340 memcpy(head
, next
, sizeof(DecorFace
));
343 for (i
= bs_start
+ 1; i
<= bs_end
; ++i
)
345 if (multiple
&& (i
& use_mask
) != set_mask
)
349 head
= &TB_STATE(*tb
)[i
];
355 tail
->next
= (DecorFace
*)safemalloc(
358 &DFS_FLAGS(tail
->next
->style
), 0,
359 sizeof(DFS_FLAGS(tail
->next
->style
)));
360 DFS_FACE_TYPE(tail
->next
->style
) =
362 tail
->next
->next
= NULL
;
363 ReadDecorFace(spec
, tail
->next
, button
, False
);
364 if (DFS_FACE_TYPE(tail
->next
->style
) ==
366 DFS_FACE_TYPE((&TB_STATE(*tb
)[i
])->style
) ==
369 /* override the default vector style */
373 sizeof(DecorFaceStyle
));
374 DFS_FACE_TYPE(tail
->next
->style
) =
378 FreeDecorFace(dpy
, head
);
379 memcpy(head
, next
, sizeof(DecorFace
));
386 FreeDecorFace(dpy
, &TB_STATE(*tb
)[bs_start
]);
388 &(TB_STATE(*tb
)[bs_start
]), &tmpdf
,
390 for (i
= bs_start
+ 1; i
<= bs_end
; ++i
)
392 if (multiple
&& (i
& use_mask
) != set_mask
)
397 spec
, &TB_STATE(*tb
)[i
], button
, False
);
405 end
= SkipSpaces(end
, NULL
, 0);
411 /* Remove the given decor from all windows */
412 static void __remove_window_decors(F_CMD_ARGS
, FvwmDecor
*d
)
414 const exec_context_t
*exc2
;
415 exec_context_changes_t ecc
;
418 for (t
= Scr
.FvwmRoot
.next
; t
; t
= t
->next
)
422 /* remove the extra title height now because we delete
423 * the current decor before calling ChangeDecor(). */
424 t
->g
.frame
.height
-= t
->decor
->title_height
;
427 ecc
.w
.wcontext
= C_WINDOW
;
428 exc2
= exc_clone_context(
429 exc
, &ecc
, ECC_FW
| ECC_WCONTEXT
);
431 cond_rc
, exc2
, "ChangeDecor Default", 0);
432 exc_destroy_context(exc2
);
439 static void do_title_style(F_CMD_ARGS
, Bool do_add
)
444 FvwmDecor
*decor
= Scr
.cur_decor
? Scr
.cur_decor
: &Scr
.DefaultDecor
;
446 FvwmDecor
*decor
= &Scr
.DefaultDecor
;
449 Scr
.flags
.do_need_window_update
= 1;
450 decor
->flags
.has_changed
= 1;
451 decor
->titlebar
.flags
.has_changed
= 1;
453 for (prev
= action
; (parm
= PeekToken(action
, &action
)); prev
= action
)
455 if (!do_add
&& StrEquals(parm
,"centered"))
457 TB_JUSTIFICATION(decor
->titlebar
) = JUST_CENTER
;
459 else if (!do_add
&& StrEquals(parm
,"leftjustified"))
461 TB_JUSTIFICATION(decor
->titlebar
) = JUST_LEFT
;
463 else if (!do_add
&& StrEquals(parm
,"rightjustified"))
465 TB_JUSTIFICATION(decor
->titlebar
) = JUST_RIGHT
;
467 else if (!do_add
&& StrEquals(parm
,"height"))
473 sscanf(action
, "%d%n", &height
, &next
) <= 0 ||
474 height
< MIN_FONT_HEIGHT
||
475 height
> MAX_FONT_HEIGHT
)
479 fvwm_msg(ERR
, "do_title_style",
480 "bad height argument (height"
481 " must be from 5 to 256)");
485 if (decor
->title_height
!= height
||
486 decor
->min_title_height
!= 0)
488 decor
->title_height
= height
;
489 decor
->min_title_height
= 0;
490 decor
->flags
.has_title_height_changed
= 1;
495 else if (!do_add
&& StrEquals(parm
,"MinHeight"))
501 sscanf(action
, "%d%n", &height
, &next
) <= 0 ||
502 height
< MIN_FONT_HEIGHT
||
503 height
> MAX_FONT_HEIGHT
)
505 if (height
< MIN_FONT_HEIGHT
)
506 height
= MIN_FONT_HEIGHT
;
507 else if (height
> MAX_FONT_HEIGHT
)
510 if (decor
->min_title_height
!= height
)
512 decor
->title_height
= 0;
513 decor
->min_title_height
= height
;
514 decor
->flags
.has_title_height_changed
= 1;
521 action
= ReadTitleButton(
522 prev
, &decor
->titlebar
, do_add
, -1);
531 * Reads a multi-pixmap titlebar config. (tril@igs.net)
534 static char *ReadMultiPixmapDecor(char *s
, DecorFace
*df
)
536 static char *pm_names
[TBMP_NUM_PIXMAPS
+1] =
556 Bool load_pixmap
= False
;
558 FvwmPictureAttributes fpa
;
560 df
->style
.face_type
= MultiPixmap
;
561 df
->u
.mp
.pixmaps
= pm
=
562 (FvwmPicture
**)safecalloc(
563 TBMP_NUM_PIXMAPS
, sizeof(FvwmPicture
*));
565 (FvwmAcs
*)safemalloc(TBMP_NUM_PIXMAPS
* sizeof(FvwmAcs
));
566 df
->u
.mp
.pixels
= pixels
=
567 (Pixel
*)safemalloc(TBMP_NUM_PIXMAPS
* sizeof(Pixel
));
568 for(i
=0; i
< TBMP_NUM_PIXMAPS
; i
++)
571 acs
[i
].alpha_percent
= 100;
573 s
= GetNextTokenIndex(s
, pm_names
, 0, &pm_id
);
578 s
= DoPeekToken(s
, &token
, ",()", NULL
, NULL
);
579 if (StrEquals(token
, "stretched"))
582 s
= DoPeekToken(s
, &token
, ",", NULL
, NULL
);
584 else if (StrEquals(token
, "tiled"))
586 s
= DoPeekToken(s
, &token
, ",", NULL
, NULL
);
592 if (pm
[pm_id
] || acs
[pm_id
].cs
>= 0 ||
593 (df
->u
.mp
.solid_flags
& (1 << pm_id
)))
595 fvwm_msg(WARN
, "ReadMultiPixmapDecor",
596 "Ignoring: already-specified %s",
602 df
->u
.mp
.stretch_flags
|= (1 << pm_id
);
604 if (strncasecmp (token
, "Colorset", 8) == 0)
609 tmp
= DoPeekToken(s
, &token
, ",", NULL
, NULL
);
610 if (!GetIntegerArguments(token
, NULL
, &val
, 1) ||
614 ERR
, "ReadMultiPixmapDecor",
615 "Colorset shoule take one or two "
616 "positive integers as argument");
623 tmp
= DoPeekToken(s
, &token
, ",", NULL
, NULL
);
624 if (GetIntegerArguments(token
, NULL
, &val
, 1))
626 acs
[pm_id
].alpha_percent
=
627 max(0, min(100,val
));
632 else if (strncasecmp(token
, "TiledPixmap", 11) == 0)
634 s
= DoPeekToken(s
, &token
, ",", NULL
, NULL
);
637 else if (strncasecmp(token
, "AdjustedPixmap", 14) == 0)
639 s
= DoPeekToken(s
, &token
, ",", NULL
, NULL
);
641 df
->u
.mp
.stretch_flags
|= (1 << pm_id
);
643 else if (strncasecmp(token
, "Solid", 5) == 0)
645 s
= DoPeekToken(s
, &token
, ",", NULL
, NULL
);
648 df
->u
.mp
.pixels
[pm_id
] = GetColor(token
);
649 df
->u
.mp
.solid_flags
|= (1 << pm_id
);
656 if (load_pixmap
&& token
)
658 fpa
.mask
= (Pdepth
<= 8)? FPAM_DITHER
:0; /* ? */
659 pm
[pm_id
] = PCacheFvwmPicture(
660 dpy
, Scr
.NoFocusWin
, NULL
, token
, fpa
);
663 fvwm_msg(ERR
, "ReadMultiPixmapDecor",
664 "Pixmap '%s' could not be loaded",
668 if (pm_id
== TBMP_BUTTONS
)
670 if (pm
[TBMP_LEFT_BUTTONS
])
672 PDestroyFvwmPicture(dpy
, pm
[TBMP_LEFT_BUTTONS
]);
674 if (pm
[TBMP_RIGHT_BUTTONS
])
676 PDestroyFvwmPicture(dpy
, pm
[TBMP_RIGHT_BUTTONS
]);
678 df
->u
.mp
.stretch_flags
&= ~(1 << TBMP_LEFT_BUTTONS
);
679 df
->u
.mp
.stretch_flags
&= ~(1 << TBMP_RIGHT_BUTTONS
);
680 df
->u
.mp
.solid_flags
&= ~(1 << TBMP_LEFT_BUTTONS
);
681 df
->u
.mp
.solid_flags
&= ~(1 << TBMP_RIGHT_BUTTONS
);
682 if (pm
[TBMP_BUTTONS
])
684 pm
[TBMP_LEFT_BUTTONS
] =
685 PCloneFvwmPicture(pm
[TBMP_BUTTONS
]);
686 acs
[TBMP_LEFT_BUTTONS
].cs
= -1;
687 pm
[TBMP_RIGHT_BUTTONS
] =
688 PCloneFvwmPicture(pm
[TBMP_BUTTONS
]);
689 acs
[TBMP_RIGHT_BUTTONS
].cs
= -1;
693 pm
[TBMP_RIGHT_BUTTONS
] =
694 pm
[TBMP_LEFT_BUTTONS
] = NULL
;
695 acs
[TBMP_RIGHT_BUTTONS
].cs
=
696 acs
[TBMP_LEFT_BUTTONS
].cs
=
697 acs
[TBMP_BUTTONS
].cs
;
698 acs
[TBMP_RIGHT_BUTTONS
].alpha_percent
=
699 acs
[TBMP_LEFT_BUTTONS
].alpha_percent
=
700 acs
[TBMP_BUTTONS
].alpha_percent
;
701 pixels
[TBMP_LEFT_BUTTONS
] =
702 pixels
[TBMP_RIGHT_BUTTONS
] =
703 pixels
[TBMP_BUTTONS
];
707 df
->u
.mp
.stretch_flags
|=
708 (1 << TBMP_LEFT_BUTTONS
) |
709 (1 << TBMP_RIGHT_BUTTONS
);
711 if (df
->u
.mp
.solid_flags
& (1 << TBMP_BUTTONS
))
713 df
->u
.mp
.solid_flags
|=
714 (1 << TBMP_LEFT_BUTTONS
);
715 df
->u
.mp
.solid_flags
|=
716 (1 << TBMP_RIGHT_BUTTONS
);
718 if (pm
[TBMP_BUTTONS
])
720 PDestroyFvwmPicture(dpy
, pm
[TBMP_BUTTONS
]);
721 pm
[TBMP_BUTTONS
] = NULL
;
723 acs
[TBMP_BUTTONS
].cs
= -1;
724 df
->u
.mp
.solid_flags
&= ~(1 << TBMP_BUTTONS
);
726 s
= SkipSpaces(s
, NULL
, 0);
727 s
= GetNextTokenIndex(s
, pm_names
, 0, &pm_id
);
730 if (!(pm
[TBMP_MAIN
] || acs
[TBMP_MAIN
].cs
>= 0 ||
731 (df
->u
.mp
.solid_flags
& TBMP_MAIN
))
733 !(pm
[TBMP_LEFT_MAIN
] || acs
[TBMP_LEFT_MAIN
].cs
>= 0 ||
734 (df
->u
.mp
.solid_flags
& TBMP_LEFT_MAIN
))
736 !(pm
[TBMP_RIGHT_MAIN
] || acs
[TBMP_RIGHT_MAIN
].cs
>= 0 ||
737 (df
->u
.mp
.solid_flags
& TBMP_RIGHT_MAIN
)))
739 fvwm_msg(ERR
, "ReadMultiPixmapDecor",
740 "No Main pixmap/colorset/solid found for TitleStyle "
741 "MultiPixmap (you must specify either Main, "
742 "or both LeftMain and RightMain)");
743 for (i
=0; i
< TBMP_NUM_PIXMAPS
; i
++)
747 PDestroyFvwmPicture(dpy
, pm
[i
]);
749 else if (!!(df
->u
.mp
.solid_flags
& i
))
752 dpy
, Pcmap
, &df
->u
.mp
.pixels
[i
], 1, 0,
767 * DestroyFvwmDecor -- frees all memory assocated with an FvwmDecor
768 * structure, but does not free the FvwmDecor itself
771 static void DestroyFvwmDecor(FvwmDecor
*decor
)
774 /* reset to default button set (frees allocated mem) */
775 DestroyAllButtons(decor
);
776 for (i
= 0; i
< BS_MaxButtonState
; ++i
)
778 FreeDecorFace(dpy
, &TB_STATE(decor
->titlebar
)[i
]);
780 FreeDecorFace(dpy
, &decor
->BorderStyle
.active
);
781 FreeDecorFace(dpy
, &decor
->BorderStyle
.inactive
);
793 static void SetLayerButtonFlag(
794 int layer
, int multi
, int set
, FvwmDecor
*decor
, TitleButton
*tb
)
810 for (i
= start
; i
< NUMBER_OF_TITLE_BUTTONS
; i
+= add
)
814 TB_FLAGS(decor
->buttons
[i
]).has_layer
= 1;
815 TB_LAYER(decor
->buttons
[i
]) = layer
;
819 TB_FLAGS(decor
->buttons
[i
]).has_layer
= 0;
827 TB_FLAGS(*tb
).has_layer
= 1;
828 TB_LAYER(*tb
) = layer
;
832 TB_FLAGS(*tb
).has_layer
= 0;
841 * Changes a button decoration style (changes by veliaa@rpi.edu)
844 static void SetMWMButtonFlag(
845 mwm_flags flag
, int multi
, int set
, FvwmDecor
*decor
, TitleButton
*tb
)
861 for (i
= start
; i
< NUMBER_OF_TITLE_BUTTONS
; i
+= add
)
865 TB_MWM_DECOR_FLAGS(decor
->buttons
[i
]) |= flag
;
869 TB_MWM_DECOR_FLAGS(decor
->buttons
[i
]) &= ~flag
;
877 TB_MWM_DECOR_FLAGS(*tb
) |= flag
;
881 TB_MWM_DECOR_FLAGS(*tb
) &= ~flag
;
888 static void do_button_style(F_CMD_ARGS
, Bool do_add
)
897 TitleButton
*tb
= NULL
;
899 FvwmDecor
*decor
= Scr
.cur_decor
? Scr
.cur_decor
: &Scr
.DefaultDecor
;
901 FvwmDecor
*decor
= &Scr
.DefaultDecor
;
904 parm
= PeekToken(action
, &text
);
905 if (parm
&& isdigit(*parm
))
908 button
= BUTTON_INDEX(button
);
911 if (parm
== NULL
|| button
>= NUMBER_OF_TITLE_BUTTONS
|| button
< 0)
914 ERR
, "ButtonStyle", "Bad button style (1) in line %s",
919 Scr
.flags
.do_need_window_update
= 1;
924 if (StrEquals(parm
,"left"))
926 multi
= 1; /* affect all left buttons */
928 else if (StrEquals(parm
,"right"))
930 multi
= 2; /* affect all right buttons */
932 else if (StrEquals(parm
,"all"))
934 multi
= 3; /* affect all buttons */
938 /* we're either resetting buttons or an invalid button
939 * set was specified */
940 if (StrEquals(parm
,"reset"))
942 ResetAllButtons(decor
);
948 "Bad button style (2) in line %s",
955 /* mark button style and decor as changed */
956 decor
->flags
.has_changed
= 1;
959 /* a single button was specified */
960 tb
= &decor
->buttons
[button
];
961 TB_FLAGS(*tb
).has_changed
= 1;
965 for (i
= 0; i
< NUMBER_OF_TITLE_BUTTONS
; ++i
)
967 if (((multi
& 1) && !(i
& 1)) ||
968 ((multi
& 2) && (i
& 1)))
970 TB_FLAGS(decor
->buttons
[i
]).has_changed
= 1;
978 for (prev
= text
; (parm
= PeekToken(text
, &text
)); prev
= text
)
980 if (!do_add
&& strcmp(parm
,"-") == 0)
983 text
= GetNextToken(text
, &tok
);
987 char *old_tok
= NULL
;
996 if (StrEquals(tok
,"Clear"))
1001 i
< NUMBER_OF_TITLE_BUTTONS
; ++i
)
1008 TB_JUSTIFICATION(decor
->buttons
[i
]) =
1009 (set
) ? JUST_CENTER
: JUST_RIGHT
;
1010 memset(&TB_FLAGS(decor
->buttons
[i
]), (set
) ? 0 : 0xff,
1011 sizeof(TB_FLAGS(decor
->buttons
[i
])));
1012 /* ? not very useful if set == 0 ? */
1018 TB_JUSTIFICATION(*tb
) = (set
) ?
1021 memset(&TB_FLAGS(*tb
), (set
) ?
1023 sizeof(TB_FLAGS(*tb
)));
1024 /* ? not very useful if
1028 else if (StrEquals(tok
, "MWMDecorMenu"))
1031 MWM_DECOR_MENU
, multi
, set
,
1034 else if (StrEquals(tok
, "MWMDecorMin"))
1037 MWM_DECOR_MINIMIZE
, multi
, set
,
1040 else if (StrEquals(tok
, "MWMDecorMax"))
1043 MWM_DECOR_MAXIMIZE
, multi
, set
,
1046 else if (StrEquals(tok
, "MWMDecorShade"))
1049 MWM_DECOR_SHADE
, multi
, set
,
1052 else if (StrEquals(tok
, "MWMDecorStick"))
1055 MWM_DECOR_STICK
, multi
, set
,
1058 else if (StrEquals(tok
, "MwmDecorLayer"))
1060 int layer
, got_number
;
1062 text
= GetNextToken(text
, <ok
);
1074 if (!ltok
|| !got_number
)
1076 fvwm_msg(ERR
, "ButtonStyle",
1078 " integer value for"
1079 " layer -- line: %s",
1092 fvwm_msg(ERR
, "ButtonStyle",
1093 "unknown title button flag"
1094 " %s -- line: %s", tok
, text
);
1104 text
= GetNextToken(text
, &tok
);
1112 for (i
= 0; i
< NUMBER_OF_TITLE_BUTTONS
; ++i
)
1114 if (((multi
& 1) && !(i
& 1)) ||
1115 ((multi
& 2) && (i
& 1)))
1117 text
= ReadTitleButton(
1124 else if (!(text
= ReadTitleButton(
1125 prev
, tb
, do_add
, button
)))
1136 int update_decorface_colorset(DecorFace
*df
, int cset
)
1139 int has_changed
= 0;
1141 for(tdf
= df
; tdf
!= NULL
; tdf
= tdf
->next
)
1143 if (DFS_FACE_TYPE(tdf
->style
) == ColorsetButton
&&
1144 tdf
->u
.acs
.cs
== cset
)
1146 tdf
->flags
.has_changed
= 1;
1149 else if (DFS_FACE_TYPE(tdf
->style
) == MultiPixmap
)
1153 for (i
= 0; i
< TBMP_NUM_PIXMAPS
; i
++)
1155 if (tdf
->u
.mp
.acs
[i
].cs
== cset
)
1157 tdf
->flags
.has_changed
= 1;
1168 int update_titlebutton_colorset(TitleButton
*tb
, int cset
)
1171 int has_changed
= 0;
1173 for(i
= 0; i
< BS_MaxButtonState
; i
++)
1175 tb
->state
[i
].flags
.has_changed
=
1176 update_decorface_colorset(&(tb
->state
[i
]), cset
);
1177 has_changed
|= tb
->state
[i
].flags
.has_changed
;
1183 void update_decors_colorset(int cset
)
1187 FvwmDecor
*decor
= &Scr
.DefaultDecor
;
1190 for(decor
= &Scr
.DefaultDecor
; decor
!= NULL
; decor
= decor
->next
)
1194 for(i
= 0; i
< NUMBER_OF_TITLE_BUTTONS
; i
++)
1196 decor
->flags
.has_changed
|= update_titlebutton_colorset(
1197 &(decor
->buttons
[i
]), cset
);
1199 decor
->flags
.has_changed
|= update_titlebutton_colorset(
1200 &(decor
->titlebar
), cset
);
1201 decor
->flags
.has_changed
|= update_decorface_colorset(
1202 &(decor
->BorderStyle
.active
), cset
);
1203 decor
->flags
.has_changed
|= update_decorface_colorset(
1204 &(decor
->BorderStyle
.inactive
), cset
);
1205 if (decor
->flags
.has_changed
)
1207 Scr
.flags
.do_need_window_update
= 1;
1212 static Bool
__parse_vector_line_one_coord(
1213 char **ret_action
, int *pcoord
, int *poff
, char *action
)
1218 *ret_action
= action
;
1219 n
= sscanf(action
, "%d%n", pcoord
, &offset
);
1225 /* check for offest */
1226 if (*action
== '+' || *action
== '-')
1228 n
= sscanf(action
, "%dp%n", poff
, &offset
);
1237 else if (*poff
> 127)
1247 *ret_action
= action
;
1252 static Bool
__parse_vector_line(
1253 char **ret_action
, int *px
, int *py
, int *pxoff
, int *pyoff
, int *pc
,
1256 Bool is_valid
= True
;
1260 *ret_action
= action
;
1261 if (__parse_vector_line_one_coord(&action
, px
, pxoff
, action
) == False
)
1270 if (__parse_vector_line_one_coord(&action
, py
, pyoff
, action
) == False
)
1279 /* read the line style */
1280 n
= sscanf(action
, "%d%n", pc
, &offset
);
1286 *ret_action
= action
;
1291 /* ---------------------------- interface functions ------------------------ */
1293 void refresh_window(Window w
, Bool window_update
)
1295 XSetWindowAttributes attributes
;
1296 unsigned long valuemask
;
1298 valuemask
= CWOverrideRedirect
| CWBackingStore
| CWSaveUnder
|
1300 attributes
.override_redirect
= True
;
1301 attributes
.save_under
= False
;
1302 attributes
.background_pixmap
= None
;
1303 attributes
.backing_store
= NotUseful
;
1305 dpy
, w
, 0, 0, Scr
.MyDisplayWidth
, Scr
.MyDisplayHeight
, 0,
1306 CopyFromParent
, CopyFromParent
, CopyFromParent
, valuemask
,
1309 if (Scr
.flags
.do_need_window_update
&& window_update
)
1311 flush_window_updates();
1313 XDestroyWindow(dpy
, w
);
1315 handle_all_expose();
1320 void ApplyDefaultFontAndColors(void)
1324 int cset
= Scr
.DefaultColorset
;
1327 gcm
= GCFunction
|GCLineWidth
|GCForeground
|GCBackground
;
1328 gcv
.function
= GXcopy
;
1329 if (Scr
.DefaultFont
->font
)
1332 gcv
.font
= Scr
.DefaultFont
->font
->fid
;
1337 gcv
.foreground
= Colorset
[cset
].fg
;
1338 gcv
.background
= Colorset
[cset
].bg
;
1342 gcv
.foreground
= Scr
.StdFore
;
1343 gcv
.background
= Scr
.StdBack
;
1347 XChangeGC(dpy
, Scr
.StdGC
, gcm
, &gcv
);
1351 Scr
.StdGC
= fvwmlib_XCreateGC(dpy
, Scr
.NoFocusWin
, gcm
, &gcv
);
1354 gcm
= GCFunction
|GCLineWidth
|GCForeground
;
1357 gcv
.foreground
= Colorset
[cset
].hilite
;
1361 gcv
.foreground
= Scr
.StdHilite
;
1363 if (Scr
.StdReliefGC
)
1365 XChangeGC(dpy
, Scr
.StdReliefGC
, gcm
, &gcv
);
1369 Scr
.StdReliefGC
= fvwmlib_XCreateGC(
1370 dpy
, Scr
.NoFocusWin
, gcm
, &gcv
);
1374 gcv
.foreground
= Colorset
[cset
].shadow
;
1378 gcv
.foreground
= Scr
.StdShadow
;
1380 if (Scr
.StdShadowGC
)
1382 XChangeGC(dpy
, Scr
.StdShadowGC
, gcm
, &gcv
);
1386 Scr
.StdShadowGC
= fvwmlib_XCreateGC(
1387 dpy
, Scr
.NoFocusWin
, gcm
, &gcv
);
1389 /* update the geometry window for move/resize */
1390 if (Scr
.SizeWindow
!= None
)
1392 resize_geometry_window();
1394 UpdateAllMenuStyles();
1399 void FreeDecorFace(Display
*dpy
, DecorFace
*df
)
1403 switch (DFS_FACE_TYPE(df
->style
))
1405 case GradientButton
:
1406 if (df
->u
.grad
.d_pixels
!= NULL
&& df
->u
.grad
.d_npixels
)
1409 dpy
, Pcmap
, df
->u
.grad
.d_pixels
,
1410 df
->u
.grad
.d_npixels
, 0, False
);
1411 free(df
->u
.grad
.d_pixels
);
1413 else if (Pdepth
<= 8 && df
->u
.grad
.xcs
!= NULL
&&
1414 df
->u
.grad
.npixels
> 0 && !df
->u
.grad
.do_dither
)
1419 p
= (Pixel
*)safemalloc(
1420 df
->u
.grad
.npixels
* sizeof(Pixel
));
1421 for(i
=0; i
< df
->u
.grad
.npixels
; i
++)
1423 p
[i
] = df
->u
.grad
.xcs
[i
].pixel
;
1426 dpy
, Pcmap
, p
, df
->u
.grad
.npixels
, 0, False
);
1429 if (df
->u
.grad
.xcs
!= NULL
)
1431 free(df
->u
.grad
.xcs
);
1436 case TiledPixmapButton
:
1437 case StretchedPixmapButton
:
1438 case AdjustedPixmapButton
:
1439 case ShrunkPixmapButton
:
1442 PDestroyFvwmPicture(dpy
, df
->u
.p
);
1447 if (df
->u
.mp
.pixmaps
)
1449 for (i
= 0; i
< TBMP_NUM_PIXMAPS
; i
++)
1451 if (df
->u
.mp
.pixmaps
[i
])
1453 PDestroyFvwmPicture(
1454 dpy
, df
->u
.mp
.pixmaps
[i
]);
1456 else if (!!(df
->u
.mp
.solid_flags
& i
))
1459 dpy
, Pcmap
, &df
->u
.mp
.pixels
[i
],
1463 free(df
->u
.mp
.pixmaps
);
1469 if (df
->u
.mp
.pixels
)
1471 free(df
->u
.mp
.pixels
);
1475 case DefaultVectorButton
:
1478 free (df
->u
.vector
.x
);
1482 free (df
->u
.vector
.y
);
1484 /* free offsets for coord */
1485 if (df
->u
.vector
.xoff
)
1487 free(df
->u
.vector
.xoff
);
1489 if (df
->u
.vector
.yoff
)
1491 free(df
->u
.vector
.yoff
);
1495 free (df
->u
.vector
.c
);
1502 /* delete any compound styles */
1505 FreeDecorFace(dpy
, df
->next
);
1509 memset(&df
->style
, 0, sizeof(df
->style
));
1510 memset(&df
->u
, 0, sizeof(df
->u
));
1511 DFS_FACE_TYPE(df
->style
) = SimpleButton
;
1518 * Reads a button face line into a structure (veliaa@rpi.edu)
1521 Bool
ReadDecorFace(char *s
, DecorFace
*df
, int button
, int verbose
)
1524 char style
[256], *file
;
1527 /* some variants of scanf do not increase the assign count when %n is
1528 * used, so a return value of 1 is no error. */
1529 if (sscanf(s
, "%255s%n", style
, &offset
) < 1)
1533 fvwm_msg(ERR
, "ReadDecorFace", "error in face `%s'", s
);
1539 if (strncasecmp(style
, "--", 2) != 0)
1543 FreeDecorFace(dpy
, df
);
1545 /* determine button style */
1546 if (strncasecmp(style
,"Simple",6)==0)
1548 memset(&df
->style
, 0, sizeof(df
->style
));
1549 DFS_FACE_TYPE(df
->style
) = SimpleButton
;
1551 else if (strncasecmp(style
,"Default",7)==0)
1553 int b
= -1, n
= sscanf(s
, "%d%n", &b
, &offset
);
1562 ERR
,"ReadDecorFace",
1563 "need default button"
1572 b
= BUTTON_INDEX(b
);
1575 if (b
>= 0 && b
< NUMBER_OF_TITLE_BUTTONS
)
1577 LoadDefaultButton(df
, b
);
1584 ERR
, "ReadDecorFace",
1585 "button number out of range:"
1591 else if (strncasecmp(style
,"Vector",6)==0 ||
1592 (strlen(style
)<=2 && isdigit(*style
)))
1594 /* normal coordinate list button style */
1595 int i
, num_coords
, num
;
1596 struct vector_coords
*vc
= &df
->u
.vector
;
1598 /* get number of points */
1599 if (strncasecmp(style
,"Vector",6)==0)
1601 num
= sscanf(s
,"%d%n",&num_coords
,&offset
);
1606 num
= sscanf(style
,"%d",&num_coords
);
1609 if (num
< 1 || num_coords
<2 ||
1610 num_coords
> MAX_TITLE_BUTTON_VECTOR_LINES
)
1615 ERR
, "ReadDecorFace",
1616 "Bad button style (2) in line:"
1622 vc
->num
= num_coords
;
1624 vc
->x
= (signed char*)safemalloc(sizeof(char) *
1626 vc
->y
= (signed char*)safemalloc(sizeof(char) *
1628 vc
->xoff
= (signed char*)safemalloc(sizeof(char) *
1630 vc
->yoff
= (signed char*)safemalloc(sizeof(char) *
1632 vc
->c
= (signed char*)safemalloc(sizeof(char) *
1635 /* get the points */
1636 for (i
= 0; i
< vc
->num
; ++i
)
1644 if (__parse_vector_line(
1645 &s
, &x
, &y
, &xoff
, &yoff
, &c
, s
) ==
1675 if (c
== 2 || c
== 3)
1685 ERR
, "ReadDecorFace",
1686 "Bad button style (3) in line"
1701 memset(&df
->style
, 0, sizeof(df
->style
));
1702 DFS_FACE_TYPE(df
->style
) = VectorButton
;
1704 else if (strncasecmp(style
,"Solid",5)==0)
1706 s
= GetNextToken(s
, &file
);
1709 memset(&df
->style
, 0, sizeof(df
->style
));
1710 DFS_FACE_TYPE(df
->style
) = SolidButton
;
1711 df
->u
.back
= GetColor(file
);
1719 ERR
, "ReadDecorFace",
1720 "no color given for Solid"
1721 " face type: %s", action
);
1726 else if (strncasecmp(style
+1, "Gradient", 8)==0)
1729 int npixels
, nsegs
, *perc
;
1731 Bool do_dither
= False
;
1733 if (!IsGradientTypeSupported(style
[0]))
1737 /* translate the gradient string into an array of
1739 npixels
= ParseGradient(
1740 s
, &s
, &s_colors
, &perc
, &nsegs
);
1741 while (*s
&& isspace(*s
))
1749 /* grab the colors */
1754 xcs
= AllocAllGradientColors(
1755 s_colors
, perc
, nsegs
, npixels
, do_dither
);
1758 df
->u
.grad
.xcs
= xcs
;
1759 df
->u
.grad
.npixels
= npixels
;
1760 df
->u
.grad
.do_dither
= do_dither
;
1761 df
->u
.grad
.d_pixels
= NULL
;
1762 memset(&df
->style
, 0, sizeof(df
->style
));
1763 DFS_FACE_TYPE(df
->style
) = GradientButton
;
1764 df
->u
.grad
.gradient_type
= toupper(style
[0]);
1766 else if (strncasecmp(style
,"Pixmap",6)==0
1767 || strncasecmp(style
,"TiledPixmap",11)==0
1768 || strncasecmp(style
,"StretchedPixmap",15)==0
1769 || strncasecmp(style
,"AdjustedPixmap",14)==0
1770 || strncasecmp(style
,"ShrunkPixmap",12)==0)
1772 FvwmPictureAttributes fpa
;
1774 s
= GetNextToken(s
, &file
);
1775 fpa
.mask
= (Pdepth
<= 8)? FPAM_DITHER
:0; /* ? */
1776 df
->u
.p
= PCacheFvwmPicture(
1777 dpy
, Scr
.NoFocusWin
, NULL
, file
, fpa
);
1778 if (df
->u
.p
== NULL
)
1785 ERR
, "ReadDecorFace",
1786 "couldn't load pixmap"
1799 memset(&df
->style
, 0, sizeof(df
->style
));
1800 if (strncasecmp(style
,"Tiled",5)==0)
1802 DFS_FACE_TYPE(df
->style
) = TiledPixmapButton
;
1804 else if (strncasecmp(style
,"Stretched",9)==0)
1806 DFS_FACE_TYPE(df
->style
) =
1807 StretchedPixmapButton
;
1809 else if (strncasecmp(style
,"Adjusted",8)==0)
1811 DFS_FACE_TYPE(df
->style
) =
1812 AdjustedPixmapButton
;
1814 else if (strncasecmp(style
,"Shrunk",6)==0)
1816 DFS_FACE_TYPE(df
->style
) =
1821 DFS_FACE_TYPE(df
->style
) = PixmapButton
;
1824 else if (strncasecmp(style
,"MultiPixmap",11)==0)
1831 ERR
, "ReadDecorFace",
1832 "MultiPixmap is only valid"
1837 s
= ReadMultiPixmapDecor(s
, df
);
1843 else if (FMiniIconsSupported
&&
1844 strncasecmp (style
, "MiniIcon", 8) == 0)
1846 memset(&df
->style
, 0, sizeof(df
->style
));
1847 DFS_FACE_TYPE(df
->style
) = MiniIconButton
;
1848 /* pixmap read in when the window is created */
1851 else if (strncasecmp (style
, "Colorset", 8) == 0)
1856 n
= GetIntegerArguments(s
, NULL
, val
, 2);
1860 memset(&df
->style
, 0, sizeof(df
->style
));
1861 if (n
> 0 && val
[0] >= 0)
1864 df
->u
.acs
.cs
= val
[0];
1865 alloc_colorset(val
[0]);
1866 DFS_FACE_TYPE(df
->style
) = ColorsetButton
;
1868 df
->u
.acs
.alpha_percent
= 100;
1871 df
->u
.acs
.alpha_percent
=
1872 max(0, min(100,val
[1]));
1874 s
= SkipNTokens(s
, n
);
1881 ERR
, "ReadDecorFace",
1882 "unknown style %s: %s", style
, action
);
1888 /* Process button flags ("--" signals start of flags,
1889 it is also checked for above) */
1890 s
= GetNextToken(s
, &file
);
1891 if (file
&& (strcmp(file
,"--")==0))
1894 s
= GetNextToken(s
, &tok
);
1898 char *old_tok
= NULL
;
1906 if (StrEquals(tok
,"Clear"))
1908 memset(&DFS_FLAGS(df
->style
), (set
) ? 0 : 0xff,
1909 sizeof(DFS_FLAGS(df
->style
)));
1910 /* ? what is set == 0 good for ? */
1912 else if (StrEquals(tok
,"Left"))
1916 DFS_H_JUSTIFICATION(df
->style
) =
1921 DFS_H_JUSTIFICATION(df
->style
) =
1925 else if (StrEquals(tok
,"Right"))
1929 DFS_H_JUSTIFICATION(df
->style
) =
1934 DFS_H_JUSTIFICATION(df
->style
) =
1938 else if (StrEquals(tok
,"Centered"))
1940 DFS_H_JUSTIFICATION(df
->style
) = JUST_CENTER
;
1941 DFS_V_JUSTIFICATION(df
->style
) = JUST_CENTER
;
1943 else if (StrEquals(tok
,"Top"))
1947 DFS_V_JUSTIFICATION(df
->style
) =
1952 DFS_V_JUSTIFICATION(df
->style
) =
1956 else if (StrEquals(tok
,"Bottom"))
1960 DFS_V_JUSTIFICATION(df
->style
) =
1965 DFS_V_JUSTIFICATION(df
->style
) =
1969 else if (StrEquals(tok
,"Flat"))
1973 DFS_BUTTON_RELIEF(df
->style
) =
1976 else if (DFS_BUTTON_RELIEF(df
->style
) ==
1979 DFS_BUTTON_RELIEF(df
->style
) =
1983 else if (StrEquals(tok
,"Sunk"))
1987 DFS_BUTTON_RELIEF(df
->style
) =
1990 else if (DFS_BUTTON_RELIEF(df
->style
) ==
1993 DFS_BUTTON_RELIEF(df
->style
) =
1997 else if (StrEquals(tok
,"Raised"))
2001 DFS_BUTTON_RELIEF(df
->style
) =
2006 DFS_BUTTON_RELIEF(df
->style
) =
2010 else if (StrEquals(tok
,"UseTitleStyle"))
2014 DFS_USE_TITLE_STYLE(df
->style
) = 1;
2015 DFS_USE_BORDER_STYLE(df
->style
) = 0;
2018 DFS_USE_TITLE_STYLE(df
->style
) = 0;
2020 else if (StrEquals(tok
,"HiddenHandles"))
2022 DFS_HAS_HIDDEN_HANDLES(df
->style
) = !!set
;
2024 else if (StrEquals(tok
,"NoInset"))
2026 DFS_HAS_NO_INSET(df
->style
) = !!set
;
2028 else if (StrEquals(tok
,"UseBorderStyle"))
2032 DFS_USE_BORDER_STYLE(df
->style
) = 1;
2033 DFS_USE_TITLE_STYLE(df
->style
) = 0;
2037 DFS_USE_BORDER_STYLE(df
->style
) = 0;
2043 ERR
, "ReadDecorFace",
2044 "unknown button face flag '%s'"
2045 " -- line: %s", tok
, action
);
2055 s
= GetNextToken(s
, &tok
);
2069 * Diverts a style definition to an FvwmDecor structure (veliaa@rpi.edu)
2072 void AddToDecor(F_CMD_ARGS
, FvwmDecor
*decor
)
2078 while (*action
&& isspace((unsigned char)*action
))
2086 Scr
.cur_decor
= decor
;
2087 execute_function(cond_rc
, exc
, action
, 0);
2088 Scr
.cur_decor
= NULL
;
2095 * InitFvwmDecor -- initializes an FvwmDecor structure to defaults
2098 void InitFvwmDecor(FvwmDecor
*decor
)
2103 /* zero out the structures */
2104 memset(decor
, 0, sizeof (FvwmDecor
));
2105 memset(&tmpdf
, 0, sizeof(DecorFace
));
2107 /* initialize title-bar button styles */
2108 DFS_FACE_TYPE(tmpdf
.style
) = SimpleButton
;
2109 for (i
= 0; i
< NUMBER_OF_TITLE_BUTTONS
; ++i
)
2112 for (; j
< BS_MaxButtonState
; ++j
)
2114 TB_STATE(decor
->buttons
[i
])[j
] = tmpdf
;
2117 /* reset to default button set */
2118 ResetAllButtons(decor
);
2119 /* initialize title-bar styles */
2120 for (i
= 0; i
< BS_MaxButtonState
; ++i
)
2123 TB_STATE(decor
->titlebar
)[i
].style
) = SimpleButton
;
2126 /* initialize border texture styles */
2127 DFS_FACE_TYPE(decor
->BorderStyle
.active
.style
) = SimpleButton
;
2128 DFS_FACE_TYPE(decor
->BorderStyle
.inactive
.style
) = SimpleButton
;
2133 void reset_decor_changes(void)
2136 Scr
.DefaultDecor
.flags
.has_changed
= 0;
2137 Scr
.DefaultDecor
.flags
.has_title_height_changed
= 0;
2140 for (decor
= &Scr
.DefaultDecor
; decor
; decor
= decor
->next
)
2142 decor
->flags
.has_changed
= 0;
2143 decor
->flags
.has_title_height_changed
= 0;
2145 /* todo: must reset individual change flags too */
2151 void update_fvwm_colorset(int cset
)
2153 if (cset
== Scr
.DefaultColorset
)
2155 Scr
.flags
.do_need_window_update
= 1;
2156 Scr
.flags
.has_default_color_changed
= 1;
2158 UpdateMenuColorset(cset
);
2159 update_style_colorset(cset
);
2160 update_decors_colorset(cset
);
2165 /* ---------------------------- builtin commands --------------------------- */
2167 void CMD_Beep(F_CMD_ARGS
)
2170 parse_colorset(11, "RootTransparent");
2177 void CMD_Nop(F_CMD_ARGS
)
2182 void CMD_EscapeFunc(F_CMD_ARGS
)
2187 void CMD_CursorMove(F_CMD_ARGS
)
2190 int val1
, val2
, val1_unit
, val2_unit
;
2191 int virtual_x
, virtual_y
;
2193 int x_pages
, y_pages
;
2195 if (GetTwoArguments(action
, &val1
, &val2
, &val1_unit
, &val2_unit
) != 2)
2197 fvwm_msg(ERR
, "movecursor", "CursorMove needs 2 arguments");
2200 if (FQueryPointer(dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
,
2201 &x
, &y
, &JunkX
, &JunkY
, &JunkMask
) == False
)
2203 /* pointer is on a different screen */
2206 x
= x
+ val1
* val1_unit
/ 100;
2207 y
= y
+ val2
* val2_unit
/ 100;
2212 x_pages
= x
/ Scr
.MyDisplayWidth
;
2216 x_pages
= ((x
+ 1) / Scr
.MyDisplayWidth
) - 1;
2218 virtual_x
+= x_pages
* Scr
.MyDisplayWidth
;
2219 x
-= x_pages
* Scr
.MyDisplayWidth
;
2225 else if (virtual_x
> Scr
.VxMax
)
2227 x
+= virtual_x
- Scr
.VxMax
;
2228 virtual_x
= Scr
.VxMax
;
2233 y_pages
= y
/ Scr
.MyDisplayHeight
;
2237 y_pages
= ((y
+ 1) / Scr
.MyDisplayHeight
) - 1;
2239 virtual_y
+= y_pages
* Scr
.MyDisplayHeight
;
2240 y
-= y_pages
* Scr
.MyDisplayHeight
;
2246 else if (virtual_y
> Scr
.VyMax
)
2248 y
+= virtual_y
- Scr
.VyMax
;
2249 virtual_y
= Scr
.VyMax
;
2251 if (virtual_x
!= Scr
.Vx
|| virtual_y
!= Scr
.Vy
)
2252 MoveViewport(virtual_x
, virtual_y
, True
);
2253 pan_x
= (Scr
.EdgeScrollX
!= 0) ? 2 : 0;
2254 pan_y
= (Scr
.EdgeScrollY
!= 0) ? 2 : 0;
2255 /* prevent paging if EdgeScroll is active */
2256 if (x
>= Scr
.MyDisplayWidth
- pan_x
)
2258 x
= Scr
.MyDisplayWidth
- pan_x
-1;
2264 if (y
>= Scr
.MyDisplayHeight
- pan_y
)
2266 y
= Scr
.MyDisplayHeight
- pan_y
- 1;
2272 FWarpPointerUpdateEvpos(
2273 exc
->x
.elast
, dpy
, None
, Scr
.Root
, 0, 0, Scr
.MyDisplayWidth
,
2274 Scr
.MyDisplayHeight
, x
, y
);
2279 void CMD_Delete(F_CMD_ARGS
)
2281 FvwmWindow
* const fw
= exc
->w
.fw
;
2283 if (!is_function_allowed(F_DELETE
, NULL
, fw
, RQORIG_PROGRAM_US
, True
))
2289 if (IS_TEAR_OFF_MENU(fw
))
2291 /* 'soft' delete tear off menus. Note: we can't send the
2292 * message to the menu window directly because it was created
2293 * using a different display. The client message would never
2294 * be read from there. */
2296 dpy
, FW_W_PARENT(fw
), _XA_WM_DELETE_WINDOW
,
2301 if (WM_DELETES_WINDOW(fw
))
2304 dpy
, FW_W(fw
), _XA_WM_DELETE_WINDOW
, CurrentTime
);
2317 void CMD_Destroy(F_CMD_ARGS
)
2319 FvwmWindow
* const fw
= exc
->w
.fw
;
2321 if (IS_TEAR_OFF_MENU(fw
))
2323 CMD_Delete(F_PASS_ARGS
);
2326 if (!is_function_allowed(F_DESTROY
, NULL
, fw
, True
, True
))
2333 dpy
, FW_W(fw
), &JunkRoot
, &JunkX
, &JunkY
,
2334 (unsigned int*)&JunkWidth
, (unsigned int*)&JunkHeight
,
2335 (unsigned int*)&JunkBW
, (unsigned int*)&JunkDepth
)
2338 XKillClient(dpy
, FW_W(fw
));
2346 void CMD_Close(F_CMD_ARGS
)
2348 FvwmWindow
* const fw
= exc
->w
.fw
;
2350 if (IS_TEAR_OFF_MENU(fw
))
2352 CMD_Delete(F_PASS_ARGS
);
2355 if (!is_function_allowed(F_CLOSE
, NULL
, fw
, True
, True
))
2360 if (WM_DELETES_WINDOW(fw
))
2363 dpy
, FW_W(fw
), _XA_WM_DELETE_WINDOW
, CurrentTime
);
2368 dpy
, FW_W(fw
), &JunkRoot
, &JunkX
, &JunkY
,
2369 (unsigned int*)&JunkWidth
, (unsigned int*)&JunkHeight
,
2370 (unsigned int*)&JunkBW
, (unsigned int*)&JunkDepth
)
2373 XKillClient(dpy
, FW_W(fw
));
2382 void CMD_Restart(F_CMD_ARGS
)
2389 void CMD_ExecUseShell(F_CMD_ARGS
)
2392 static char shell_set
= 0;
2396 free(exec_shell_name
);
2399 action
= GetNextToken(action
,&arg
);
2400 if (arg
) /* specific shell was specified */
2402 exec_shell_name
= arg
;
2404 else /* no arg, so use $SHELL -- not working??? */
2406 if (getenv("SHELL"))
2408 exec_shell_name
= safestrdup(getenv("SHELL"));
2412 /* if $SHELL not set, use default */
2413 exec_shell_name
= safestrdup("/bin/sh");
2418 void CMD_Exec(F_CMD_ARGS
)
2422 /* if it doesn't already have an 'exec' as the first word, add that
2423 * to keep down number of procs started */
2424 /* need to parse string better to do this right though, so not doing
2425 * this for now... */
2427 if (strncasecmp(action
,"exec",4)!=0)
2429 cmd
= (char *)safemalloc(strlen(action
)+6);
2430 strcpy(cmd
,"exec ");
2436 cmd
= safestrdup(action
);
2442 /* Use to grab the pointer here, but the fork guarantees that
2443 * we wont be held up waiting for the function to finish,
2444 * so the pointer-gram just caused needless delay and flashing
2446 /* Thought I'd try vfork and _exit() instead of regular fork().
2447 * The man page says that its better. */
2448 /* Not everyone has vfork! */
2449 /* According to the man page, vfork should never be used at all.
2452 if (!(fork())) /* child process */
2454 /* This is for fixing a problem with rox filer */
2457 fvmm_deinstall_signals();
2458 fd
= open("/dev/null", O_RDONLY
, 0);
2459 dup2(fd
,STDIN_FILENO
);
2460 if (fvwm_setpgrp() == -1)
2462 fvwm_msg(ERR
, "exec_function", "setpgrp failed (%s)",
2466 if (execl(exec_shell_name
, exec_shell_name
, "-c", cmd
, NULL
) ==
2469 fvwm_msg(ERR
, "exec_function", "execl failed (%s)",
2479 void CMD_Refresh(F_CMD_ARGS
)
2481 refresh_window(Scr
.Root
, True
);
2486 void CMD_RefreshWindow(F_CMD_ARGS
)
2488 FvwmWindow
* const fw
= exc
->w
.fw
;
2491 (exc
->w
.wcontext
== C_ICON
) ?
2492 FW_W_ICON_TITLE(fw
) : FW_W_FRAME(fw
), True
);
2497 void CMD_Wait(F_CMD_ARGS
)
2500 Bool redefine_cursor
= False
;
2503 Window nonewin
= None
;
2504 char *wait_string
, *rest
;
2507 /* try to get a single token */
2508 rest
= GetNextToken(action
, &wait_string
);
2511 while (*rest
&& isspace((unsigned char)*rest
))
2520 /* nope, multiple tokens - try old syntax */
2522 /* strip leading and trailing whitespace */
2524 while (*temp
&& isspace((unsigned char)*temp
))
2528 wait_string
= safestrdup(temp
);
2529 for (i
= strlen(wait_string
) - 1; i
>= 0 &&
2530 isspace(wait_string
[i
]); i
--)
2538 wait_string
= safestrdup("");
2541 is_ungrabbed
= UngrabEm(GRAB_NORMAL
);
2542 while (!done
&& !isTerminated
)
2545 if (BUSY_WAIT
& Scr
.BusyCursor
)
2547 XDefineCursor(dpy
, Scr
.Root
, Scr
.FvwmCursors
[CRS_WAIT
]);
2548 redefine_cursor
= True
;
2550 if (My_XNextEvent(dpy
, &e
))
2554 dpy
, e
.xmap
.window
, FvwmContext
,
2555 (caddr_t
*)&t
) == XCNOENT
)
2560 if (e
.type
== MapNotify
&& e
.xmap
.event
== Scr
.Root
)
2566 if (t
&& matchWildcards(
2567 wait_string
, t
->name
.name
) == True
)
2571 else if (t
&& t
->class.res_class
&&
2574 t
->class.res_class
) == True
)
2578 else if (t
&& t
->class.res_name
&&
2581 t
->class.res_name
) == True
)
2586 else if (e
.type
== KeyPress
)
2588 /* should I be using <t> or <exc->w.fw>?
2595 context
= GetContext(&t
, t
, &e
, &nonewin
);
2598 class = &(t
->class);
2599 name
= t
->name
.name
;
2606 escape
= CheckBinding(
2607 Scr
.AllBindings
, STROKE_ARG(0)
2608 e
.xkey
.keycode
, e
.xkey
.state
,
2609 GetUnusedModifiers(), context
,
2610 BIND_KEYPRESS
, class, name
);
2613 if (!strcasecmp(escape
,"escapefunc"))
2621 if (redefine_cursor
)
2623 XDefineCursor(dpy
, Scr
.Root
, Scr
.FvwmCursors
[CRS_ROOT
]);
2627 GrabEm(CRS_NONE
, GRAB_NORMAL
);
2634 void CMD_Quit(F_CMD_ARGS
)
2636 if (master_pid
!= getpid())
2638 kill(master_pid
, SIGTERM
);
2645 void CMD_QuitScreen(F_CMD_ARGS
)
2652 void CMD_Echo(F_CMD_ARGS
)
2660 len
= strlen(action
);
2663 if (action
[len
-1]=='\n')
2668 fvwm_msg(ECHO
,"Echo",action
);
2673 void CMD_PrintInfo(F_CMD_ARGS
)
2676 char *rest
, *subject
= NULL
;
2678 rest
= GetNextToken(action
, &subject
);
2679 if (!rest
|| GetIntegerArguments(rest
, NULL
, &verbose
, 1) != 1)
2683 if (StrEquals(subject
, "Colors"))
2685 PicturePrintColorInfo(verbose
);
2687 else if (StrEquals(subject
, "Locale"))
2689 FlocalePrintLocaleInfo(dpy
, verbose
);
2691 else if (StrEquals(subject
, "NLS"))
2693 FGettextPrintLocalePath(verbose
);
2695 else if (StrEquals(subject
, "style"))
2697 print_styles(verbose
);
2699 else if (StrEquals(subject
, "ImageCache"))
2701 PicturePrintImageCache(verbose
);
2703 else if (StrEquals(subject
, "Bindings"))
2709 fvwm_msg(ERR
, "PrintInfo",
2710 "Unknown subject '%s'", action
);
2719 void CMD_ColormapFocus(F_CMD_ARGS
)
2721 if (MatchToken(action
,"FollowsFocus"))
2723 Scr
.ColormapFocus
= COLORMAP_FOLLOWS_FOCUS
;
2725 else if (MatchToken(action
,"FollowsMouse"))
2727 Scr
.ColormapFocus
= COLORMAP_FOLLOWS_MOUSE
;
2731 fvwm_msg(ERR
, "SetColormapFocus",
2732 "ColormapFocus requires 1 arg: FollowsFocus or"
2740 void CMD_ClickTime(F_CMD_ARGS
)
2744 if (GetIntegerArguments(action
, NULL
, &val
, 1) != 1)
2746 Scr
.ClickTime
= DEFAULT_CLICKTIME
;
2750 Scr
.ClickTime
= (val
< 0)? 0 : val
;
2753 /* Use a negative value during startup and change sign afterwards. This
2754 * speeds things up quite a bit. */
2757 Scr
.ClickTime
= -Scr
.ClickTime
;
2764 void CMD_ImagePath(F_CMD_ARGS
)
2766 PictureSetImagePath( action
);
2771 void CMD_IconPath(F_CMD_ARGS
)
2773 fvwm_msg(ERR
, "iconPath_function",
2774 "IconPath is deprecated since 2.3.0; use ImagePath instead.");
2775 obsolete_imagepaths( action
);
2780 void CMD_PixmapPath(F_CMD_ARGS
)
2782 fvwm_msg(ERR
, "pixmapPath_function",
2783 "PixmapPath is deprecated since 2.3.0; use ImagePath"
2785 obsolete_imagepaths( action
);
2790 void CMD_LocalePath(F_CMD_ARGS
)
2792 FGettextSetLocalePath( action
);
2797 void CMD_ModulePath(F_CMD_ARGS
)
2799 static int need_to_free
= 0;
2801 setPath( &ModulePath
, action
, need_to_free
);
2807 void CMD_ModuleTimeout(F_CMD_ARGS
)
2811 moduleTimeout
= DEFAULT_MODULE_TIMEOUT
;
2812 if (GetIntegerArguments(action
, NULL
, &timeout
, 1) == 1 && timeout
> 0)
2814 moduleTimeout
= timeout
;
2820 void CMD_HilightColor(F_CMD_ARGS
)
2825 if (Scr
.cur_decor
&& Scr
.cur_decor
!= &Scr
.DefaultDecor
)
2829 "Decors do not support the HilightColor command"
2830 " anymore. Please use"
2831 " 'Style <stylename> HilightFore <forecolor>' and"
2832 " 'Style <stylename> HilightBack <backcolor>' instead."
2833 " Sorry for the inconvenience.");
2837 action
= GetNextToken(action
, &fore
);
2838 GetNextToken(action
, &back
);
2841 action
= safemalloc(strlen(fore
) + strlen(back
) + 29);
2842 sprintf(action
, "* HilightFore %s, HilightBack %s", fore
, back
);
2843 CMD_Style(F_PASS_ARGS
);
2857 void CMD_HilightColorset(F_CMD_ARGS
)
2862 if (Scr
.cur_decor
&& Scr
.cur_decor
!= &Scr
.DefaultDecor
)
2865 ERR
, "SetHiColorset",
2866 "Decors do not support the HilightColorset command "
2867 "anymore. Please use "
2868 "'Style <stylename> HilightColorset <colorset>'"
2869 " instead. Sorry for the inconvenience.");
2875 newaction
= safemalloc(strlen(action
) + 32);
2876 sprintf(newaction
, "* HilightColorset %s", action
);
2878 CMD_Style(F_PASS_ARGS
);
2885 void CMD_TitleStyle(F_CMD_ARGS
)
2887 do_title_style(F_PASS_ARGS
, False
);
2890 } /* SetTitleStyle */
2894 * Appends a titlestyle (veliaa@rpi.edu)
2897 void CMD_AddTitleStyle(F_CMD_ARGS
)
2899 do_title_style(F_PASS_ARGS
, True
);
2904 void CMD_PropertyChange(F_CMD_ARGS
)
2910 unsigned long argument
;
2911 unsigned long data1
;
2912 unsigned long data2
;
2915 token
= PeekToken(action
, &rest
);
2920 ret
= sscanf(token
, "%lu", &argument
);
2927 token
= PeekToken(rest
, &rest
);
2930 ret
= sscanf(token
, "%lu", &data1
);
2938 token
= PeekToken(rest
, &rest
);
2941 ret
= sscanf(token
, "%lu", &data2
);
2948 memset(string
, 0, 256);
2951 ret
= sscanf(rest
, "%255c", &(string
[0]));
2953 BroadcastPropertyChange(argument
, data1
, data2
, string
);
2958 void CMD_DefaultIcon(F_CMD_ARGS
)
2960 if (Scr
.DefaultIcon
)
2962 free(Scr
.DefaultIcon
);
2964 GetNextToken(action
, &Scr
.DefaultIcon
);
2969 void CMD_DefaultColorset(F_CMD_ARGS
)
2973 if (GetIntegerArguments(action
, NULL
, &cset
, 1) != 1)
2977 Scr
.DefaultColorset
= cset
;
2978 if (Scr
.DefaultColorset
< 0)
2980 Scr
.DefaultColorset
= -1;
2982 alloc_colorset(Scr
.DefaultColorset
);
2983 Scr
.flags
.do_need_window_update
= 1;
2984 Scr
.flags
.has_default_color_changed
= 1;
2989 void CMD_DefaultColors(F_CMD_ARGS
)
2994 action
= GetNextToken(action
, &fore
);
2997 action
= GetNextToken(action
, &back
);
3001 back
= safestrdup(DEFAULT_BACK_COLOR
);
3005 fore
= safestrdup(DEFAULT_FORE_COLOR
);
3007 if (!StrEquals(fore
, "-"))
3009 PictureFreeColors(dpy
, Pcmap
, &Scr
.StdFore
, 1, 0, True
);
3010 Scr
.StdFore
= GetColor(fore
);
3012 if (!StrEquals(back
, "-"))
3014 PictureFreeColors(dpy
, Pcmap
, &Scr
.StdBack
, 3, 0, True
);
3015 Scr
.StdBack
= GetColor(back
);
3016 Scr
.StdHilite
= GetHilite(Scr
.StdBack
);
3017 Scr
.StdShadow
= GetShadow(Scr
.StdBack
);
3022 Scr
.DefaultColorset
= -1;
3023 Scr
.flags
.do_need_window_update
= 1;
3024 Scr
.flags
.has_default_color_changed
= 1;
3029 void CMD_DefaultFont(F_CMD_ARGS
)
3032 FlocaleFont
*new_font
;
3035 font
= PeekToken(action
, &action
);
3038 /* Try 'fixed', pass NULL font name */
3040 if (!(new_font
= FlocaleLoadFont(dpy
, font
, "fvwm")))
3042 if (Scr
.DefaultFont
== NULL
)
3051 FlocaleUnloadFont(dpy
, Scr
.DefaultFont
);
3052 Scr
.DefaultFont
= new_font
;
3053 /* we should do that here because a redraw can happen before
3054 flush_window_updates is called ... */
3055 for (t
= Scr
.FvwmRoot
.next
; t
!= NULL
; t
= t
->next
)
3057 if (USING_DEFAULT_ICON_FONT(t
))
3059 t
->icon_font
= Scr
.DefaultFont
;
3061 if (USING_DEFAULT_WINDOW_FONT(t
))
3063 t
->title_font
= Scr
.DefaultFont
;
3066 /* set flags to indicate that the font has changed */
3067 Scr
.flags
.do_need_window_update
= 1;
3068 Scr
.flags
.has_default_font_changed
= 1;
3073 void CMD_IconFont(F_CMD_ARGS
)
3078 if (Scr
.cur_decor
&& Scr
.cur_decor
!= &Scr
.DefaultDecor
)
3081 ERR
, "LoadIconFont",
3082 "Decors do not support the IconFont command anymore."
3083 " Please use 'Style <stylename> IconFont <fontname>'"
3084 " instead. Sorry for the inconvenience.");
3090 newaction
= safemalloc(strlen(action
) + 16);
3091 sprintf(newaction
, "* IconFont %s", action
);
3093 CMD_Style(F_PASS_ARGS
);
3100 void CMD_WindowFont(F_CMD_ARGS
)
3105 if (Scr
.cur_decor
&& Scr
.cur_decor
!= &Scr
.DefaultDecor
)
3108 ERR
, "LoadWindowFont",
3109 "Decors do not support the WindowFont command anymore."
3110 " Please use 'Style <stylename> Font <fontname>'"
3111 " instead. Sorry for the inconvenience.");
3117 newaction
= safemalloc(strlen(action
) + 16);
3118 sprintf(newaction
, "* Font %s", action
);
3120 CMD_Style(F_PASS_ARGS
);
3129 * Changes the window's FvwmDecor pointer (veliaa@rpi.edu)
3132 void CMD_ChangeDecor(F_CMD_ARGS
)
3136 FvwmDecor
*decor
= &Scr
.DefaultDecor
;
3137 FvwmDecor
*found
= NULL
;
3138 FvwmWindow
* const fw
= exc
->w
.fw
;
3140 item
= PeekToken(action
, &action
);
3141 if (!action
|| !item
)
3145 /* search for tag */
3146 for (; decor
; decor
= decor
->next
)
3148 if (decor
->tag
&& StrEquals(item
, decor
->tag
))
3159 SET_DECOR_CHANGED(fw
, 1);
3160 old_height
= (fw
->decor
) ? fw
->decor
->title_height
: 0;
3162 apply_decor_change(fw
);
3169 * Destroys an FvwmDecor (veliaa@rpi.edu)
3172 void CMD_DestroyDecor(F_CMD_ARGS
)
3175 FvwmDecor
*decor
= Scr
.DefaultDecor
.next
;
3176 FvwmDecor
*prev
= &Scr
.DefaultDecor
, *found
= NULL
;
3177 Bool do_recreate
= False
;
3179 item
= PeekToken(action
, &action
);
3184 if (StrEquals(item
, "recreate"))
3187 item
= PeekToken(action
, NULL
);
3194 /* search for tag */
3195 for (; decor
; decor
= decor
->next
)
3197 if (decor
->tag
&& StrEquals(item
, decor
->tag
))
3205 if (found
&& (found
!= &Scr
.DefaultDecor
|| do_recreate
))
3209 __remove_window_decors(F_PASS_ARGS
, found
);
3211 DestroyFvwmDecor(found
);
3216 InitFvwmDecor(found
);
3217 found
->tag
= safestrdup(item
);
3218 Scr
.flags
.do_need_window_update
= 1;
3219 found
->flags
.has_changed
= 1;
3220 found
->flags
.has_title_height_changed
= 0;
3221 found
->titlebar
.flags
.has_changed
= 1;
3222 for (i
= 0; i
< NUMBER_OF_TITLE_BUTTONS
; ++i
)
3224 TB_FLAGS(found
->buttons
[i
]).has_changed
= 1;
3229 prev
->next
= found
->next
;
3239 * Initiates an AddToDecor (veliaa@rpi.edu)
3242 void CMD_AddToDecor(F_CMD_ARGS
)
3245 FvwmDecor
*found
= NULL
;
3248 action
= GetNextToken(action
, &item
);
3258 /* search for tag */
3259 for (decor
= &Scr
.DefaultDecor
; decor
; decor
= decor
->next
)
3261 if (decor
->tag
&& StrEquals(item
, decor
->tag
))
3269 /* then make a new one */
3270 found
= (FvwmDecor
*)safemalloc(sizeof( FvwmDecor
));
3271 InitFvwmDecor(found
);
3272 found
->tag
= item
; /* tag it */
3273 /* add it to list */
3274 for (decor
= &Scr
.DefaultDecor
; decor
->next
;
3275 decor
= decor
->next
)
3279 decor
->next
= found
;
3288 AddToDecor(F_PASS_ARGS
, found
);
3289 /* Set + state to last decor */
3290 set_last_added_item(ADDED_DECOR
, found
);
3295 #endif /* USEDECOR */
3300 * Updates window decoration styles (veliaa@rpi.edu)
3303 void CMD_UpdateDecor(F_CMD_ARGS
)
3307 FvwmDecor
*decor
, *found
= NULL
;
3308 FvwmWindow
*hilight
= Scr
.Hilite
;
3311 action
= GetNextToken(action
, &item
);
3314 /* search for tag */
3315 for (decor
= &Scr
.DefaultDecor
; decor
; decor
= decor
->next
)
3317 if (decor
->tag
&& StrEquals(item
, decor
->tag
))
3327 for (fw2
= Scr
.FvwmRoot
.next
; fw2
; fw2
= fw2
->next
)
3330 /* update specific decor, or all */
3333 if (fw2
->decor
== found
)
3335 border_draw_decorations(
3336 fw2
, PART_ALL
, True
, True
, CLEAR_ALL
,
3338 border_draw_decorations(
3339 fw2
, PART_ALL
, False
, True
, CLEAR_ALL
,
3346 border_draw_decorations(
3347 fw2
, PART_ALL
, True
, True
, CLEAR_ALL
, NULL
,
3349 border_draw_decorations(
3350 fw2
, PART_ALL
, False
, True
, CLEAR_ALL
, NULL
,
3354 border_draw_decorations(
3355 hilight
, PART_ALL
, True
, True
, CLEAR_ALL
, NULL
, NULL
);
3358 void CMD_ButtonStyle(F_CMD_ARGS
)
3360 do_button_style(F_PASS_ARGS
, False
);
3367 * Appends a button decoration style (veliaa@rpi.edu)
3370 void CMD_AddButtonStyle(F_CMD_ARGS
)
3372 do_button_style(F_PASS_ARGS
, True
);
3377 void CMD_SetEnv(F_CMD_ARGS
)
3380 char *szValue
= NULL
;
3381 char *szPutenv
= NULL
;
3383 action
= GetNextToken(action
, &szVar
);
3388 action
= GetNextToken(action
, &szValue
);
3391 szValue
= safestrdup("");
3393 szPutenv
= safemalloc(strlen(szVar
) + strlen(szValue
) + 2);
3394 sprintf(szPutenv
,"%s=%s", szVar
, szValue
);
3395 flib_putenv(szVar
, szPutenv
);
3403 void CMD_UnsetEnv(F_CMD_ARGS
)
3407 szVar
= PeekToken(action
, &action
);
3412 flib_unsetenv(szVar
);
3417 void CMD_GlobalOpts(F_CMD_ARGS
)
3425 "WindowShadeShrinks",
3426 "WindowShadeScrolls",
3427 "SmartPlacementIsReallySmart",
3428 "SmartPlacementIsNormal",
3429 "ClickToFocusDoesntPassClick",
3430 "ClickToFocusPassesClick",
3431 "ClickToFocusDoesntRaise",
3432 "ClickToFocusRaises",
3433 "MouseFocusClickDoesntRaise",
3434 "MouseFocusClickRaises",
3437 "CaptureHonorsStartsOnPage",
3438 "CaptureIgnoresStartsOnPage",
3439 "RecaptureHonorsStartsOnPage",
3440 "RecaptureIgnoresStartsOnPage",
3441 "ActivePlacementHonorsStartsOnPage",
3442 "ActivePlacementIgnoresStartsOnPage",
3443 "RaiseOverNativeWindows",
3444 "IgnoreNativeWindows",
3447 char *replacelist
[] = {
3448 /* These options are mapped to the Style * command */
3449 NULL
, /* NULL means to use "Style * <optionname>" */
3451 "* MinOverlapPlacement",
3452 "* TileCascadePlacement",
3453 "* ClickToFocusPassesClickOff",
3454 "* ClickToFocusPassesClick",
3455 "* ClickToFocusRaisesOff",
3456 "* ClickToFocusRaises",
3457 "* MouseFocusClickRaisesOff",
3458 "* MouseFocusClickRaises",
3459 "* StippledTitleOff",
3465 "* ManualPlacementHonorsStartsOnPage",
3466 "* ManualPlacementIgnoresStartsOnPage",
3467 /* These options are mapped to the BugOpts command */
3468 "RaiseOverNativeWindows on",
3469 "RaiseOverNativeWindows off"
3472 fvwm_msg(ERR
, "SetGlobalOptions",
3473 "The GlobalOpts command is obsolete.");
3474 for (action
= GetNextSimpleOption(action
, &opt
); opt
;
3475 action
= GetNextSimpleOption(action
, &opt
))
3480 i
= GetTokenIndex(opt
, optlist
, 0, NULL
);
3486 replace
= replacelist
[i
];
3487 if (replace
== NULL
)
3489 replace
= &(buf
[0]);
3490 sprintf(buf
, "* %s", opt
);
3492 else if (*replace
!= '*')
3500 CMD_Style(F_PASS_ARGS
);
3505 CMD_BugOpts(F_PASS_ARGS
);
3510 ERR
, "SetGlobalOptions",
3511 "Please replace 'GlobalOpts %s' with '%s %s'.",
3516 fvwm_msg(ERR
, "SetGlobalOptions",
3517 "Unknown Global Option '%s'", opt
);
3519 /* should never be null, but checking anyways... */
3533 void CMD_BugOpts(F_CMD_ARGS
)
3539 /* fvwm_msg(DBG,"SetGlobalOptions","init action == '%s'\n",action); */
3542 action
= DoGetNextToken(action
, &opt
, NULL
, ",", &delim
);
3545 /* no more options */
3548 if (delim
== '\n' || delim
== ',')
3550 /* missing toggle argument */
3555 toggle
= ParseToggleArgument(action
, &action
, 1, False
);
3558 if (StrEquals(opt
, "FlickeringMoveWorkaround"))
3563 Scr
.bo
.do_disable_configure_notify
^= 1;
3567 Scr
.bo
.do_disable_configure_notify
= toggle
;
3570 Scr
.bo
.do_disable_configure_notify
= 0;
3574 else if (StrEquals(opt
, "MixedVisualWorkaround"))
3579 Scr
.bo
.do_install_root_cmap
^= 1;
3583 Scr
.bo
.do_install_root_cmap
= toggle
;
3586 Scr
.bo
.do_install_root_cmap
= 0;
3590 else if (StrEquals(opt
, "ModalityIsEvil"))
3595 Scr
.bo
.is_modality_evil
^= 1;
3599 Scr
.bo
.is_modality_evil
= toggle
;
3602 Scr
.bo
.is_modality_evil
= 0;
3605 if (Scr
.bo
.is_modality_evil
)
3607 SetMWM_INFO(Scr
.NoFocusWin
);
3610 else if (StrEquals(opt
, "RaiseOverNativeWindows"))
3615 Scr
.bo
.is_raise_hack_needed
^= 1;
3619 Scr
.bo
.is_raise_hack_needed
= toggle
;
3622 Scr
.bo
.is_raise_hack_needed
= 0;
3626 else if (StrEquals(opt
, "RaiseOverUnmanaged"))
3631 Scr
.bo
.do_raise_over_unmanaged
^= 1;
3635 Scr
.bo
.do_raise_over_unmanaged
= toggle
;
3638 Scr
.bo
.do_raise_over_unmanaged
= 0;
3642 else if (StrEquals(opt
, "FlickeringQtDialogsWorkaround"))
3647 Scr
.bo
.do_enable_flickering_qt_dialogs_workaround
^= 1;
3651 Scr
.bo
.do_enable_flickering_qt_dialogs_workaround
= toggle
;
3654 Scr
.bo
.do_enable_flickering_qt_dialogs_workaround
= 0;
3658 else if (EWMH_BugOpts(opt
, toggle
))
3660 /* work is done in EWMH_BugOpts */
3662 else if (StrEquals(opt
, "DisplayNewWindowNames"))
3667 Scr
.bo
.do_display_new_window_names
^= 1;
3671 Scr
.bo
.do_display_new_window_names
= toggle
;
3674 Scr
.bo
.do_display_new_window_names
= 0;
3678 else if (StrEquals(opt
, "ExplainWindowPlacement"))
3683 Scr
.bo
.do_explain_window_placement
^= 1;
3687 Scr
.bo
.do_explain_window_placement
= toggle
;
3690 Scr
.bo
.do_explain_window_placement
= 0;
3694 else if (StrEquals(opt
, "DebugCRMotionMethod"))
3699 Scr
.bo
.do_debug_cr_motion_method
^= 1;
3703 Scr
.bo
.do_debug_cr_motion_method
= toggle
;
3706 Scr
.bo
.do_debug_cr_motion_method
= 0;
3712 fvwm_msg(ERR
, "SetBugOptions",
3713 "Unknown Bug Option '%s'", opt
);
3721 void CMD_Emulate(F_CMD_ARGS
)
3725 style
= PeekToken(action
, NULL
);
3726 if (!style
|| StrEquals(style
, "fvwm"))
3728 Scr
.gs
.do_emulate_mwm
= False
;
3729 Scr
.gs
.do_emulate_win
= False
;
3731 else if (StrEquals(style
, "mwm"))
3733 Scr
.gs
.do_emulate_mwm
= True
;
3734 Scr
.gs
.do_emulate_win
= False
;
3736 else if (StrEquals(style
, "win"))
3738 Scr
.gs
.do_emulate_mwm
= False
;
3739 Scr
.gs
.do_emulate_win
= True
;
3743 fvwm_msg(ERR
, "Emulate", "Unknown style '%s'", style
);
3746 Scr
.flags
.do_need_window_update
= 1;
3747 Scr
.flags
.has_default_font_changed
= 1;
3748 Scr
.flags
.has_default_color_changed
= 1;
3753 void CMD_ColorLimit(F_CMD_ARGS
)
3756 WARN
, "ColorLimit", "ColorLimit is obsolete,\n\tuse the "
3757 "fvwm -color-limit option");
3763 /* set animation parameters */
3764 void CMD_SetAnimation(F_CMD_ARGS
)
3771 opt
= PeekToken(action
, &action
);
3772 if (!opt
|| sscanf(opt
,"%d",&delay
) != 1)
3774 fvwm_msg(ERR
,"SetAnimation",
3775 "Improper milli-second delay as first argument");
3780 fvwm_msg(WARN
,"SetAnimation",
3781 "Using longer than .5 seconds as between frame"
3782 " animation delay");
3784 cmsDelayDefault
= delay
;
3785 for (opt
= PeekToken(action
, &action
); opt
;
3786 opt
= PeekToken(action
, &action
))
3788 if (sscanf(opt
,"%f",&pct
) != 1)
3790 fvwm_msg(ERR
,"SetAnimation",
3791 "Use fractional values ending in 1.0 as args"
3795 rgpctMovementDefault
[i
++] = pct
;
3797 /* No pct entries means don't change them at all */
3798 if (i
> 0 && rgpctMovementDefault
[i
-1] != 1.0)
3800 rgpctMovementDefault
[i
++] = 1.0;
3806 /* Determine which modifiers are required with a keycode to make <keysym>. */
3807 static Bool
FKeysymToKeycode (Display
*dpy
, KeySym keysym
,
3808 unsigned int *keycode
, unsigned int *modifiers
)
3812 *keycode
= XKeysymToKeycode(dpy
, keysym
);
3815 for (m
= 0; m
<= 8; ++m
)
3817 KeySym ks
= XKeycodeToKeysym(dpy
, *keycode
, m
);
3822 case 0: /* No modifiers */
3824 case 1: /* Shift modifier */
3825 *modifiers
|= ShiftMask
;
3828 fvwm_msg(ERR
, "FKeysymToKeycode",
3829 "Unhandled modifier %d", m
);
3838 static void __fake_event(F_CMD_ARGS
, FakeEventType type
)
3849 unsigned int mask
= 0;
3850 Window root
= Scr
.Root
;
3852 static char args
[128];
3853 strncpy(args
, action
, sizeof(args
) - 1);
3855 /* get the mask of pressed/released buttons/keys */
3857 dpy
, Scr
.Root
, &root
, &JunkRoot
, &JunkX
, &JunkY
, &JunkX
,
3860 token
= PeekToken(action
, &action
);
3861 while (token
&& action
)
3863 int index
= GetTokenIndex(token
, optlist
, 0, NULL
);
3874 KeySym keysym
= NoSymbol
;
3886 /* key/button press or release */
3887 if (type
== FakeMouseEvent
)
3889 if ((GetIntegerArguments(
3890 action
, &action
, &val
, 1) != 1) ||
3892 val
> NUMBER_OF_EXTENDED_MOUSE_BUTTONS
)
3895 ERR
, "__fake_event",
3896 "Invalid button specifier in"
3897 " \"%s\" for FakeClick.", args
);
3901 else /* type == FakeKeyEvent */
3903 char *key
= PeekToken(action
, &action
);
3907 ERR
, "__fake_event",
3908 "No keysym specifier in \"%s\""
3909 " for FakeKeypress.", args
);
3913 /* Do *NOT* use FvwmStringToKeysym() as it is
3914 * case insensitive. */
3915 keysym
= XStringToKeysym(key
);
3916 if (keysym
== NoSymbol
)
3919 ERR
, "__fake_event",
3920 "Invalid keysym specifier (%s)"
3921 " in \"%s\" for FakeKeypress.",
3930 depth
!= maxdepth
&&
3931 w
!= child_w
&& child_w
!= None
;
3936 dpy
, w
, &root
, &child_w
,
3938 &JunkMask
) == False
)
3940 /* pointer is on a different
3941 * screen - that's okay here */
3945 if (type
== FakeMouseEvent
)
3947 e
.type
= (do_unset
) ?
3948 ButtonRelease
: ButtonPress
;
3949 e
.xbutton
.display
= dpy
;
3950 e
.xbutton
.window
= w
;
3951 e
.xbutton
.subwindow
= None
;
3952 e
.xbutton
.root
= root
;
3953 e
.xbutton
.time
= fev_get_evtime();
3956 e
.xbutton
.x_root
= rx
;
3957 e
.xbutton
.y_root
= ry
;
3958 e
.xbutton
.button
= val
;
3959 e
.xbutton
.state
= mask
;
3960 e
.xbutton
.same_screen
= (Scr
.Root
== root
);
3961 /* SS: I think this mask handling code is
3963 * The value of <mask> is overridden during a
3964 * "wait" operation. Also why are we only using
3965 * Button1Mask? What if the user has requested
3966 * a FakeClick using some other button? */
3967 /* DV: Button1Mask is actually a bit. Shifting
3968 * it by (val -1) bits to the left gives
3969 * Button2Mask, Button3Mask etc. */
3972 mask
&= ~(Button1Mask
<< (val
- 1));
3976 mask
|= (Button1Mask
<< (val
- 1));
3978 add_mask
= (do_unset
) ?
3979 ButtonPressMask
: ButtonReleaseMask
;
3983 /* type == FakeKeyEvent */
3984 e
.type
= (do_unset
? KeyRelease
: KeyPress
);
3985 e
.xkey
.display
= dpy
;
3986 e
.xkey
.subwindow
= None
;
3988 e
.xkey
.time
= fev_get_evtime();
3993 e
.xkey
.same_screen
= (Scr
.Root
== root
);
3995 w
= e
.xkey
.window
= exc
->w
.w
;
3997 if (FKeysymToKeycode(
3998 dpy
, keysym
, &(e
.xkey
.keycode
),
3999 &(e
.xkey
.state
)) != True
)
4001 fvwm_msg(DBG
, "__fake_event",
4002 "FKeysymToKeycode failed");
4005 e
.xkey
.state
|= mask
;
4006 add_mask
= (do_unset
) ?
4007 KeyReleaseMask
: KeyPressMask
;
4009 FSendEvent(dpy
, w
, True
,
4010 SubstructureNotifyMask
| add_mask
, &e
);
4016 if ((GetIntegerArguments(
4017 action
, &action
, &val
, 1) != 1) ||
4018 val
<= 0 || val
> 1000000)
4020 fvwm_msg(ERR
, "__fake_event",
4021 "Invalid wait value in \"%s\"", args
);
4027 dpy
, Scr
.Root
, &root
, &JunkRoot
,
4028 &JunkX
, &JunkY
, &JunkX
, &JunkY
,
4031 /* pointer is on a different screen -
4032 * that's okay here */
4038 if (GetIntegerArguments(action
, &action
, &val
, 1) != 1)
4041 ERR
, "__fake_event",
4042 "Invalid modifier value in \"%s\"",
4064 else if (val
>=1 && val
<= 5)
4066 val
= (Mod1Mask
<< (val
- 1));
4073 /* SS: Could be buggy if a "modifier" operation
4074 * preceeds a "wait" operation. */
4087 if (GetIntegerArguments(action
, &action
, &val
, 1) != 1)
4089 fvwm_msg(ERR
, "__fake_event",
4090 "Invalid depth value in \"%s\"", args
);
4096 fvwm_msg(ERR
, "__fake_event",
4097 "Invalid command (%s) in \"%s\"", token
, args
);
4102 token
= PeekToken(action
, &action
);
4109 void CMD_FakeClick(F_CMD_ARGS
)
4111 __fake_event(F_PASS_ARGS
, FakeMouseEvent
);
4116 void CMD_FakeKeypress(F_CMD_ARGS
)
4118 __fake_event(F_PASS_ARGS
, FakeKeyEvent
);
4123 /* A function to handle stroke (olicha Nov 11, 1999) */
4125 void CMD_StrokeFunc(F_CMD_ARGS
)
4129 int modifiers
= exc
->x
.etrigger
->xbutton
.state
;
4130 int start_event_type
= exc
->x
.etrigger
->type
;
4131 char sequence
[STROKE_MAX_SEQUENCE
+ 1];
4132 char *stroke_action
, *name
;
4134 Bool finish_on_release
= True
;
4136 Bool restore_repeat
= False
;
4137 Bool echo_sequence
= False
;
4138 Bool draw_motion
= False
;
4142 const int STROKE_CHUNK_SIZE
= 0xff;
4143 int coords_size
= STROKE_CHUNK_SIZE
;
4144 Window JunkRoot
, JunkChild
;
4147 unsigned int JunkMask
;
4148 Bool feed_back
= False
;
4149 int stroke_width
= 1;
4155 if (!GrabEm(CRS_STROKE
, GRAB_NORMAL
))
4160 x
= (int*)safemalloc(coords_size
* sizeof(int));
4161 y
= (int*)safemalloc(coords_size
* sizeof(int));
4162 e
= *exc
->x
.etrigger
;
4163 /* set the default option */
4164 if (e
.type
== KeyPress
|| e
.type
== ButtonPress
)
4166 finish_on_release
= True
;
4170 finish_on_release
= False
;
4173 /* parse the option */
4174 for (action
= GetNextSimpleOption(action
, &opt
); opt
;
4175 action
= GetNextSimpleOption(action
, &opt
))
4177 if (StrEquals("NotStayPressed",opt
))
4179 finish_on_release
= False
;
4181 else if (StrEquals("EchoSequence",opt
))
4183 echo_sequence
= True
;
4185 else if (StrEquals("DrawMotion",opt
))
4189 else if (StrEquals("FeedBack",opt
))
4193 else if (StrEquals("StrokeWidth",opt
))
4195 /* stroke width takes a positive integer argument */
4200 action
= GetNextToken(action
, &opt
);
4204 WARN
, "StrokeWidth",
4205 "needs an integer argument");
4207 /* we allow stroke_width == 0 which means drawing a
4208 * `fast' line of width 1; the upper level of 100 is
4210 else if (!sscanf(opt
, "%d", &stroke_width
) ||
4211 stroke_width
< 0 || stroke_width
> 100)
4214 WARN
, "StrokeWidth",
4215 "Bad integer argument %d",
4222 fvwm_msg(WARN
,"StrokeFunc","Unknown option %s", opt
);
4234 /* Force auto repeat off and grab the Keyboard to get proper
4235 * KeyRelease events if we need it.
4236 * Some computers do not support KeyRelease events, can we
4237 * check this here ? No ? */
4238 if (start_event_type
== KeyPress
&& finish_on_release
)
4240 XKeyboardState kstate
;
4242 XGetKeyboardControl(dpy
, &kstate
);
4243 if (kstate
.global_auto_repeat
== AutoRepeatModeOn
)
4245 XAutoRepeatOff(dpy
);
4246 restore_repeat
= True
;
4248 MyXGrabKeyboard(dpy
);
4251 /* be ready to get a stroke sequence */
4258 dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
, &x
[0], &y
[0],
4259 &JunkX
, &JunkY
, &JunkMask
) == False
)
4261 /* pointer is on a different screen */
4266 dpy
,Scr
.XorGC
,stroke_width
,LineSolid
,CapButt
,JoinMiter
);
4269 while (!finished
&& !abort
)
4271 /* block until there is an event */
4273 dpy
, ButtonPressMask
| ButtonReleaseMask
|
4274 KeyPressMask
| KeyReleaseMask
| ButtonMotionMask
|
4275 PointerMotionMask
, &e
);
4279 if (e
.xmotion
.same_screen
== False
)
4283 if (e
.xany
.window
!= Scr
.Root
)
4286 dpy
, Scr
.Root
, &JunkRoot
,
4287 &JunkChild
, &tmpx
, &tmpy
, &JunkX
,
4288 &JunkY
, &JunkMask
) == False
)
4290 /* pointer is on a different screen */
4300 stroke_record(tmpx
,tmpy
);
4301 if (draw_motion
&& (x
[i
] != tmpx
|| y
[i
] != tmpy
))
4304 if (i
>= coords_size
)
4306 coords_size
+= STROKE_CHUNK_SIZE
;
4307 x
= (int*)saferealloc(
4308 (void *)x
, coords_size
*
4310 y
= (int*)saferealloc(
4311 (void *)y
, coords_size
*
4317 dpy
, Scr
.Root
, Scr
.XorGC
, x
[i
-1],
4318 y
[i
-1], x
[i
], y
[i
]);
4322 if (finish_on_release
&& start_event_type
==
4329 if (finish_on_release
&& start_event_type
== KeyPress
)
4335 keysym
= XLookupKeysym(&e
.xkey
, 0);
4336 /* abort if Escape or Delete is pressed (as in menus.c)
4338 if (keysym
== XK_Escape
|| keysym
== XK_Delete
||
4339 keysym
== XK_KP_Separator
)
4343 /* finish on enter or space (as in menus.c) */
4344 if (keysym
== XK_Return
|| keysym
== XK_KP_Enter
||
4351 if (!finish_on_release
)
4366 dpy
, Scr
.Root
, Scr
.XorGC
, x
[i
-1], y
[i
-1], x
[i
],
4370 XSetLineAttributes(dpy
,Scr
.XorGC
,0,LineSolid
,CapButt
,JoinMiter
);
4371 MyXUngrabServer(dpy
);
4378 if (start_event_type
== KeyPress
&& finish_on_release
)
4380 MyXUngrabKeyboard(dpy
);
4382 UngrabEm(GRAB_NORMAL
);
4388 /* get the stroke sequence */
4389 stroke_trans(sequence
);
4393 char num_seq
[STROKE_MAX_SEQUENCE
+ 1];
4395 for (i
= 0; sequence
[i
] != '\0';i
++)
4397 /* Telephone to numeric pad */
4398 if ('7' <= sequence
[i
] && sequence
[i
] <= '9')
4400 num_seq
[i
] = sequence
[i
]-6;
4402 else if ('1' <= sequence
[i
] && sequence
[i
] <= '3')
4404 num_seq
[i
] = sequence
[i
]+6;
4408 num_seq
[i
] = sequence
[i
];
4411 num_seq
[i
++] = '\0';
4412 fvwm_msg(INFO
, "StrokeFunc", "stroke sequence: %s (N%s)",
4419 if (exc
->w
.fw
== NULL
)
4426 class = &exc
->w
.fw
->class;
4427 name
= exc
->w
.fw
->name
.name
;
4429 /* check for a binding */
4430 stroke_action
= CheckBinding(
4431 Scr
.AllBindings
, sequence
, 0, modifiers
, GetUnusedModifiers(),
4432 exc
->w
.wcontext
, BIND_STROKE
, class, name
);
4434 /* execute the action */
4435 if (stroke_action
!= NULL
)
4437 const exec_context_t
*exc2
;
4438 exec_context_changes_t ecc
;
4440 if (feed_back
&& atoi(sequence
) != 0)
4442 GrabEm(CRS_WAIT
, GRAB_BUSY
);
4444 UngrabEm(GRAB_BUSY
);
4446 ecc
.x
.etrigger
= &e
;
4447 exc2
= exc_clone_context(exc
, &ecc
, ECC_ETRIGGER
);
4448 execute_function(cond_rc
, exc2
, stroke_action
, 0);
4449 exc_destroy_context(exc2
);
4454 #endif /* HAVE_STROKE */
4456 void CMD_State(F_CMD_ARGS
)
4461 FvwmWindow
* const fw
= exc
->w
.fw
;
4463 n
= GetIntegerArguments(action
, &action
, (int *)&state
, 1);
4468 if (state
< 0 || state
> 31)
4470 fvwm_msg(ERR
, "CMD_State", "Illegal state %d\n", state
);
4473 toggle
= ParseToggleArgument(action
, NULL
, -1, 0);
4474 state
= (1 << state
);
4478 TOGGLE_USER_STATES(fw
, state
);
4481 CLEAR_USER_STATES(fw
, state
);
4485 SET_USER_STATES(fw
, state
);