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"
52 #include "libs/Flocale.h"
53 #include "libs/Ficonv.h"
60 #include "functions.h"
64 #include "module_interface.h"
70 #include "decorations.h"
71 #include "add_window.h"
74 #include "move_resize.h"
78 #endif /* HAVE_STROKE */
80 /* ---------------------------- local definitions -------------------------- */
82 /* ---------------------------- local macros ------------------------------- */
84 /* ---------------------------- imports ------------------------------------ */
86 extern float rgpctMovementDefault
[32];
87 extern int cpctMovementDefault
;
88 extern int cmsDelayDefault
;
90 /* ---------------------------- included code files ------------------------ */
92 /* ---------------------------- local types -------------------------------- */
93 typedef enum {FakeMouseEvent
, FakeKeyEvent
} FakeEventType
;
94 /* ---------------------------- forward declarations ----------------------- */
96 /* ---------------------------- local variables ---------------------------- */
98 static char *exec_shell_name
="/bin/sh";
100 /* button state strings must match the enumerated states */
101 static char *button_states
[BS_MaxButtonStateName
+ 1] =
110 "ToggledInactiveDown",
128 /* ---------------------------- exported variables (globals) --------------- */
130 char *ModulePath
= FVWM_MODULEDIR
;
131 int moduleTimeout
= DEFAULT_MODULE_TIMEOUT
;
133 /* ---------------------------- local functions ---------------------------- */
135 /** Prepend rather than replace the image path.
136 Used for obsolete PixmapPath and IconPath **/
137 static void obsolete_imagepaths( const char* pre_path
)
139 char* tmp
= stripcpy( pre_path
);
140 char* path
= alloca(strlen( tmp
) + strlen(PictureGetImagePath()) + 2 );
146 strcat( path
, PictureGetImagePath() );
148 PictureSetImagePath( path
);
155 * Reads a title button description (veliaa@rpi.edu)
158 static char *ReadTitleButton(
159 char *s
, TitleButton
*tb
, Boolean append
, int button
)
166 int bs_start
, bs_end
;
174 s
= SkipSpaces(s
, NULL
, 0);
175 t
= GetNextTokenIndex(s
, button_states
, 0, &bs
);
178 s
= SkipSpaces(t
, NULL
, 0);
186 else if (bs
== BS_Active
)
188 use_mask
= BS_MASK_INACTIVE
| BS_MASK_TOGGLED
;
191 else if (bs
== BS_Inactive
)
193 use_mask
= BS_MASK_INACTIVE
| BS_MASK_TOGGLED
;
194 set_mask
= BS_MASK_INACTIVE
;
196 else if (bs
== BS_ToggledActive
)
198 use_mask
= BS_MASK_INACTIVE
| BS_MASK_TOGGLED
;
199 set_mask
= BS_MASK_TOGGLED
;
201 else if (bs
== BS_ToggledInactive
)
203 use_mask
= BS_MASK_INACTIVE
| BS_MASK_TOGGLED
;
204 set_mask
= BS_MASK_INACTIVE
| BS_MASK_TOGGLED
;
206 else if (bs
== BS_AllNormal
)
208 use_mask
= BS_MASK_TOGGLED
;
211 else if (bs
== BS_AllToggled
)
213 use_mask
= BS_MASK_TOGGLED
;
214 set_mask
= BS_MASK_TOGGLED
;
216 else if (bs
== BS_AllActive
)
218 use_mask
= BS_MASK_INACTIVE
;
221 else if (bs
== BS_AllInactive
)
223 use_mask
= BS_MASK_INACTIVE
;
224 set_mask
= BS_MASK_INACTIVE
;
226 else if (bs
== BS_AllUp
)
228 use_mask
= BS_MASK_DOWN
;
231 else if (bs
== BS_AllDown
)
233 use_mask
= BS_MASK_DOWN
;
234 set_mask
= BS_MASK_DOWN
;
236 else if (bs
== BS_AllActiveUp
)
238 use_mask
= BS_MASK_INACTIVE
| BS_MASK_DOWN
;
241 else if (bs
== BS_AllActiveDown
)
243 use_mask
= BS_MASK_INACTIVE
| BS_MASK_DOWN
;
244 set_mask
= BS_MASK_DOWN
;
246 else if (bs
== BS_AllInactiveUp
)
248 use_mask
= BS_MASK_INACTIVE
| BS_MASK_DOWN
;
249 set_mask
= BS_MASK_INACTIVE
;
251 else if (bs
== BS_AllInactiveDown
)
253 use_mask
= BS_MASK_INACTIVE
| BS_MASK_DOWN
;
254 set_mask
= BS_MASK_INACTIVE
| BS_MASK_DOWN
;
257 if ((bs
& BS_MaxButtonStateMask
) == bs
)
267 bs_end
= BS_MaxButtonState
- 1;
268 for (i
= bs_start
; (i
& use_mask
) != set_mask
&& i
<= bs_end
;
279 if (!(end
= strchr(++s
, ')')))
282 ERR
, "ReadTitleButton",
283 "missing parenthesis: %s", s
);
286 s
= SkipSpaces(s
, NULL
, 0);
288 spec
= safemalloc(len
);
289 strncpy(spec
, s
, len
- 1);
297 spec
= SkipSpaces(spec
, NULL
, 0);
298 /* setup temporary in case button read fails */
299 memset(&tmpdf
, 0, sizeof(DecorFace
));
300 DFS_FACE_TYPE(tmpdf
.style
) = SimpleButton
;
302 if (strncmp(spec
, "--", 2) == 0)
304 /* only change flags */
306 for (i
= bs_start
; i
<= bs_end
; ++i
)
308 if (multiple
&& (i
& use_mask
) != set_mask
)
312 ReadDecorFace(spec
, &TB_STATE(*tb
)[i
], button
, verbose
);
316 else if (ReadDecorFace(spec
, &tmpdf
, button
, True
))
320 DecorFace
*head
= &TB_STATE(*tb
)[bs_start
];
321 DecorFace
*tail
= head
;
328 tail
->next
= (DecorFace
*)safemalloc(sizeof(DecorFace
));
329 memcpy(tail
->next
, &tmpdf
, sizeof(DecorFace
));
330 if (DFS_FACE_TYPE(tail
->next
->style
) == VectorButton
&&
331 DFS_FACE_TYPE((&TB_STATE(*tb
)[bs_start
])->style
) ==
334 /* override the default vector style */
336 &tail
->next
->style
, &head
->style
,
337 sizeof(DecorFaceStyle
));
338 DFS_FACE_TYPE(tail
->next
->style
) = VectorButton
;
341 FreeDecorFace(dpy
, head
);
342 memcpy(head
, next
, sizeof(DecorFace
));
345 for (i
= bs_start
+ 1; i
<= bs_end
; ++i
)
347 if (multiple
&& (i
& use_mask
) != set_mask
)
351 head
= &TB_STATE(*tb
)[i
];
357 tail
->next
= (DecorFace
*)safemalloc(
360 &DFS_FLAGS(tail
->next
->style
), 0,
361 sizeof(DFS_FLAGS(tail
->next
->style
)));
362 DFS_FACE_TYPE(tail
->next
->style
) =
364 tail
->next
->next
= NULL
;
365 ReadDecorFace(spec
, tail
->next
, button
, False
);
366 if (DFS_FACE_TYPE(tail
->next
->style
) ==
368 DFS_FACE_TYPE((&TB_STATE(*tb
)[i
])->style
) ==
371 /* override the default vector style */
375 sizeof(DecorFaceStyle
));
376 DFS_FACE_TYPE(tail
->next
->style
) =
380 FreeDecorFace(dpy
, head
);
381 memcpy(head
, next
, sizeof(DecorFace
));
388 FreeDecorFace(dpy
, &TB_STATE(*tb
)[bs_start
]);
390 &(TB_STATE(*tb
)[bs_start
]), &tmpdf
,
392 for (i
= bs_start
+ 1; i
<= bs_end
; ++i
)
394 if (multiple
&& (i
& use_mask
) != set_mask
)
399 spec
, &TB_STATE(*tb
)[i
], button
, False
);
407 end
= SkipSpaces(end
, NULL
, 0);
413 /* Remove the given decor from all windows */
414 static void __remove_window_decors(F_CMD_ARGS
, FvwmDecor
*d
)
416 const exec_context_t
*exc2
;
417 exec_context_changes_t ecc
;
420 for (t
= Scr
.FvwmRoot
.next
; t
; t
= t
->next
)
424 /* remove the extra title height now because we delete
425 * the current decor before calling ChangeDecor(). */
426 t
->g
.frame
.height
-= t
->decor
->title_height
;
429 ecc
.w
.wcontext
= C_WINDOW
;
430 exc2
= exc_clone_context(
431 exc
, &ecc
, ECC_FW
| ECC_WCONTEXT
);
433 cond_rc
, exc2
, "ChangeDecor Default", 0);
434 exc_destroy_context(exc2
);
441 static void do_title_style(F_CMD_ARGS
, Bool do_add
)
446 FvwmDecor
*decor
= Scr
.cur_decor
? Scr
.cur_decor
: &Scr
.DefaultDecor
;
448 FvwmDecor
*decor
= &Scr
.DefaultDecor
;
451 Scr
.flags
.do_need_window_update
= 1;
452 decor
->flags
.has_changed
= 1;
453 decor
->titlebar
.flags
.has_changed
= 1;
455 for (prev
= action
; (parm
= PeekToken(action
, &action
)); prev
= action
)
457 if (!do_add
&& StrEquals(parm
,"centered"))
459 TB_JUSTIFICATION(decor
->titlebar
) = JUST_CENTER
;
461 else if (!do_add
&& StrEquals(parm
,"leftjustified"))
463 TB_JUSTIFICATION(decor
->titlebar
) = JUST_LEFT
;
465 else if (!do_add
&& StrEquals(parm
,"rightjustified"))
467 TB_JUSTIFICATION(decor
->titlebar
) = JUST_RIGHT
;
469 else if (!do_add
&& StrEquals(parm
,"height"))
475 sscanf(action
, "%d%n", &height
, &next
) <= 0 ||
476 height
< MIN_FONT_HEIGHT
||
477 height
> MAX_FONT_HEIGHT
)
481 fvwm_msg(ERR
, "do_title_style",
482 "bad height argument (height"
483 " must be from 5 to 256)");
487 if (decor
->title_height
!= height
||
488 decor
->min_title_height
!= 0)
490 decor
->title_height
= height
;
491 decor
->min_title_height
= 0;
492 decor
->flags
.has_title_height_changed
= 1;
497 else if (!do_add
&& StrEquals(parm
,"MinHeight"))
503 sscanf(action
, "%d%n", &height
, &next
) <= 0 ||
504 height
< MIN_FONT_HEIGHT
||
505 height
> MAX_FONT_HEIGHT
)
507 if (height
< MIN_FONT_HEIGHT
)
508 height
= MIN_FONT_HEIGHT
;
509 else if (height
> MAX_FONT_HEIGHT
)
512 if (decor
->min_title_height
!= height
)
514 decor
->title_height
= 0;
515 decor
->min_title_height
= height
;
516 decor
->flags
.has_title_height_changed
= 1;
523 action
= ReadTitleButton(
524 prev
, &decor
->titlebar
, do_add
, -1);
533 * Reads a multi-pixmap titlebar config. (tril@igs.net)
536 static char *ReadMultiPixmapDecor(char *s
, DecorFace
*df
)
538 static char *pm_names
[TBMP_NUM_PIXMAPS
+1] =
558 Bool load_pixmap
= False
;
560 FvwmPictureAttributes fpa
;
562 df
->style
.face_type
= MultiPixmap
;
563 df
->u
.mp
.pixmaps
= pm
=
564 (FvwmPicture
**)safecalloc(
565 TBMP_NUM_PIXMAPS
, sizeof(FvwmPicture
*));
567 (FvwmAcs
*)safemalloc(TBMP_NUM_PIXMAPS
* sizeof(FvwmAcs
));
568 df
->u
.mp
.pixels
= pixels
=
569 (Pixel
*)safemalloc(TBMP_NUM_PIXMAPS
* sizeof(Pixel
));
570 for(i
=0; i
< TBMP_NUM_PIXMAPS
; i
++)
573 acs
[i
].alpha_percent
= 100;
575 s
= GetNextTokenIndex(s
, pm_names
, 0, &pm_id
);
580 s
= DoPeekToken(s
, &token
, ",()", NULL
, NULL
);
581 if (StrEquals(token
, "stretched"))
584 s
= DoPeekToken(s
, &token
, ",", NULL
, NULL
);
586 else if (StrEquals(token
, "tiled"))
588 s
= DoPeekToken(s
, &token
, ",", NULL
, NULL
);
594 if (pm
[pm_id
] || acs
[pm_id
].cs
>= 0 ||
595 (df
->u
.mp
.solid_flags
& (1 << pm_id
)))
597 fvwm_msg(WARN
, "ReadMultiPixmapDecor",
598 "Ignoring: already-specified %s",
604 df
->u
.mp
.stretch_flags
|= (1 << pm_id
);
606 if (strncasecmp (token
, "Colorset", 8) == 0)
611 tmp
= DoPeekToken(s
, &token
, ",", NULL
, NULL
);
612 if (!GetIntegerArguments(token
, NULL
, &val
, 1) ||
616 ERR
, "ReadMultiPixmapDecor",
617 "Colorset shoule take one or two "
618 "positive integers as argument");
625 tmp
= DoPeekToken(s
, &token
, ",", NULL
, NULL
);
626 if (GetIntegerArguments(token
, NULL
, &val
, 1))
628 acs
[pm_id
].alpha_percent
=
629 max(0, min(100,val
));
634 else if (strncasecmp(token
, "TiledPixmap", 11) == 0)
636 s
= DoPeekToken(s
, &token
, ",", NULL
, NULL
);
639 else if (strncasecmp(token
, "AdjustedPixmap", 14) == 0)
641 s
= DoPeekToken(s
, &token
, ",", NULL
, NULL
);
643 df
->u
.mp
.stretch_flags
|= (1 << pm_id
);
645 else if (strncasecmp(token
, "Solid", 5) == 0)
647 s
= DoPeekToken(s
, &token
, ",", NULL
, NULL
);
650 df
->u
.mp
.pixels
[pm_id
] = GetColor(token
);
651 df
->u
.mp
.solid_flags
|= (1 << pm_id
);
658 if (load_pixmap
&& token
)
660 fpa
.mask
= (Pdepth
<= 8)? FPAM_DITHER
:0; /* ? */
661 pm
[pm_id
] = PCacheFvwmPicture(
662 dpy
, Scr
.NoFocusWin
, NULL
, token
, fpa
);
665 fvwm_msg(ERR
, "ReadMultiPixmapDecor",
666 "Pixmap '%s' could not be loaded",
670 if (pm_id
== TBMP_BUTTONS
)
672 if (pm
[TBMP_LEFT_BUTTONS
])
674 PDestroyFvwmPicture(dpy
, pm
[TBMP_LEFT_BUTTONS
]);
676 if (pm
[TBMP_RIGHT_BUTTONS
])
678 PDestroyFvwmPicture(dpy
, pm
[TBMP_RIGHT_BUTTONS
]);
680 df
->u
.mp
.stretch_flags
&= ~(1 << TBMP_LEFT_BUTTONS
);
681 df
->u
.mp
.stretch_flags
&= ~(1 << TBMP_RIGHT_BUTTONS
);
682 df
->u
.mp
.solid_flags
&= ~(1 << TBMP_LEFT_BUTTONS
);
683 df
->u
.mp
.solid_flags
&= ~(1 << TBMP_RIGHT_BUTTONS
);
684 if (pm
[TBMP_BUTTONS
])
686 pm
[TBMP_LEFT_BUTTONS
] =
687 PCloneFvwmPicture(pm
[TBMP_BUTTONS
]);
688 acs
[TBMP_LEFT_BUTTONS
].cs
= -1;
689 pm
[TBMP_RIGHT_BUTTONS
] =
690 PCloneFvwmPicture(pm
[TBMP_BUTTONS
]);
691 acs
[TBMP_RIGHT_BUTTONS
].cs
= -1;
695 pm
[TBMP_RIGHT_BUTTONS
] =
696 pm
[TBMP_LEFT_BUTTONS
] = NULL
;
697 acs
[TBMP_RIGHT_BUTTONS
].cs
=
698 acs
[TBMP_LEFT_BUTTONS
].cs
=
699 acs
[TBMP_BUTTONS
].cs
;
700 acs
[TBMP_RIGHT_BUTTONS
].alpha_percent
=
701 acs
[TBMP_LEFT_BUTTONS
].alpha_percent
=
702 acs
[TBMP_BUTTONS
].alpha_percent
;
703 pixels
[TBMP_LEFT_BUTTONS
] =
704 pixels
[TBMP_RIGHT_BUTTONS
] =
705 pixels
[TBMP_BUTTONS
];
709 df
->u
.mp
.stretch_flags
|=
710 (1 << TBMP_LEFT_BUTTONS
) |
711 (1 << TBMP_RIGHT_BUTTONS
);
713 if (df
->u
.mp
.solid_flags
& (1 << TBMP_BUTTONS
))
715 df
->u
.mp
.solid_flags
|=
716 (1 << TBMP_LEFT_BUTTONS
);
717 df
->u
.mp
.solid_flags
|=
718 (1 << TBMP_RIGHT_BUTTONS
);
720 if (pm
[TBMP_BUTTONS
])
722 PDestroyFvwmPicture(dpy
, pm
[TBMP_BUTTONS
]);
723 pm
[TBMP_BUTTONS
] = NULL
;
725 acs
[TBMP_BUTTONS
].cs
= -1;
726 df
->u
.mp
.solid_flags
&= ~(1 << TBMP_BUTTONS
);
728 s
= SkipSpaces(s
, NULL
, 0);
729 s
= GetNextTokenIndex(s
, pm_names
, 0, &pm_id
);
732 if (!(pm
[TBMP_MAIN
] || acs
[TBMP_MAIN
].cs
>= 0 ||
733 (df
->u
.mp
.solid_flags
& TBMP_MAIN
))
735 !(pm
[TBMP_LEFT_MAIN
] || acs
[TBMP_LEFT_MAIN
].cs
>= 0 ||
736 (df
->u
.mp
.solid_flags
& TBMP_LEFT_MAIN
))
738 !(pm
[TBMP_RIGHT_MAIN
] || acs
[TBMP_RIGHT_MAIN
].cs
>= 0 ||
739 (df
->u
.mp
.solid_flags
& TBMP_RIGHT_MAIN
)))
741 fvwm_msg(ERR
, "ReadMultiPixmapDecor",
742 "No Main pixmap/colorset/solid found for TitleStyle "
743 "MultiPixmap (you must specify either Main, "
744 "or both LeftMain and RightMain)");
745 for (i
=0; i
< TBMP_NUM_PIXMAPS
; i
++)
749 PDestroyFvwmPicture(dpy
, pm
[i
]);
751 else if (!!(df
->u
.mp
.solid_flags
& i
))
754 dpy
, Pcmap
, &df
->u
.mp
.pixels
[i
], 1, 0,
769 * DestroyFvwmDecor -- frees all memory assocated with an FvwmDecor
770 * structure, but does not free the FvwmDecor itself
773 static void DestroyFvwmDecor(FvwmDecor
*decor
)
776 /* reset to default button set (frees allocated mem) */
777 DestroyAllButtons(decor
);
778 for (i
= 0; i
< BS_MaxButtonState
; ++i
)
780 FreeDecorFace(dpy
, &TB_STATE(decor
->titlebar
)[i
]);
782 FreeDecorFace(dpy
, &decor
->BorderStyle
.active
);
783 FreeDecorFace(dpy
, &decor
->BorderStyle
.inactive
);
795 static void SetLayerButtonFlag(
796 int layer
, int multi
, int set
, FvwmDecor
*decor
, TitleButton
*tb
)
812 for (i
= start
; i
< NUMBER_OF_TITLE_BUTTONS
; i
+= add
)
816 TB_FLAGS(decor
->buttons
[i
]).has_layer
= 1;
817 TB_LAYER(decor
->buttons
[i
]) = layer
;
821 TB_FLAGS(decor
->buttons
[i
]).has_layer
= 0;
829 TB_FLAGS(*tb
).has_layer
= 1;
830 TB_LAYER(*tb
) = layer
;
834 TB_FLAGS(*tb
).has_layer
= 0;
843 * Changes a button decoration style (changes by veliaa@rpi.edu)
846 static void SetMWMButtonFlag(
847 mwm_flags flag
, int multi
, int set
, FvwmDecor
*decor
, TitleButton
*tb
)
863 for (i
= start
; i
< NUMBER_OF_TITLE_BUTTONS
; i
+= add
)
867 TB_MWM_DECOR_FLAGS(decor
->buttons
[i
]) |= flag
;
871 TB_MWM_DECOR_FLAGS(decor
->buttons
[i
]) &= ~flag
;
879 TB_MWM_DECOR_FLAGS(*tb
) |= flag
;
883 TB_MWM_DECOR_FLAGS(*tb
) &= ~flag
;
890 static void do_button_style(F_CMD_ARGS
, Bool do_add
)
899 TitleButton
*tb
= NULL
;
901 FvwmDecor
*decor
= Scr
.cur_decor
? Scr
.cur_decor
: &Scr
.DefaultDecor
;
903 FvwmDecor
*decor
= &Scr
.DefaultDecor
;
906 parm
= PeekToken(action
, &text
);
907 if (parm
&& isdigit(*parm
))
910 button
= BUTTON_INDEX(button
);
913 if (parm
== NULL
|| button
>= NUMBER_OF_TITLE_BUTTONS
|| button
< 0)
916 ERR
, "ButtonStyle", "Bad button style (1) in line %s",
921 Scr
.flags
.do_need_window_update
= 1;
926 if (StrEquals(parm
,"left"))
928 multi
= 1; /* affect all left buttons */
930 else if (StrEquals(parm
,"right"))
932 multi
= 2; /* affect all right buttons */
934 else if (StrEquals(parm
,"all"))
936 multi
= 3; /* affect all buttons */
940 /* we're either resetting buttons or an invalid button
941 * set was specified */
942 if (StrEquals(parm
,"reset"))
944 ResetAllButtons(decor
);
950 "Bad button style (2) in line %s",
957 /* mark button style and decor as changed */
958 decor
->flags
.has_changed
= 1;
961 /* a single button was specified */
962 tb
= &decor
->buttons
[button
];
963 TB_FLAGS(*tb
).has_changed
= 1;
967 for (i
= 0; i
< NUMBER_OF_TITLE_BUTTONS
; ++i
)
969 if (((multi
& 1) && !(i
& 1)) ||
970 ((multi
& 2) && (i
& 1)))
972 TB_FLAGS(decor
->buttons
[i
]).has_changed
= 1;
980 for (prev
= text
; (parm
= PeekToken(text
, &text
)); prev
= text
)
982 if (!do_add
&& strcmp(parm
,"-") == 0)
985 text
= GetNextToken(text
, &tok
);
989 char *old_tok
= NULL
;
998 if (StrEquals(tok
,"Clear"))
1003 i
< NUMBER_OF_TITLE_BUTTONS
; ++i
)
1010 TB_JUSTIFICATION(decor
->buttons
[i
]) =
1011 (set
) ? JUST_CENTER
: JUST_RIGHT
;
1012 memset(&TB_FLAGS(decor
->buttons
[i
]), (set
) ? 0 : 0xff,
1013 sizeof(TB_FLAGS(decor
->buttons
[i
])));
1014 /* ? not very useful if set == 0 ? */
1020 TB_JUSTIFICATION(*tb
) = (set
) ?
1023 memset(&TB_FLAGS(*tb
), (set
) ?
1025 sizeof(TB_FLAGS(*tb
)));
1026 /* ? not very useful if
1030 else if (StrEquals(tok
, "MWMDecorMenu"))
1033 MWM_DECOR_MENU
, multi
, set
,
1036 else if (StrEquals(tok
, "MWMDecorMin"))
1039 MWM_DECOR_MINIMIZE
, multi
, set
,
1042 else if (StrEquals(tok
, "MWMDecorMax"))
1045 MWM_DECOR_MAXIMIZE
, multi
, set
,
1048 else if (StrEquals(tok
, "MWMDecorShade"))
1051 MWM_DECOR_SHADE
, multi
, set
,
1054 else if (StrEquals(tok
, "MWMDecorStick"))
1057 MWM_DECOR_STICK
, multi
, set
,
1060 else if (StrEquals(tok
, "MwmDecorLayer"))
1062 int layer
, got_number
;
1064 text
= GetNextToken(text
, <ok
);
1076 if (!ltok
|| !got_number
)
1078 fvwm_msg(ERR
, "ButtonStyle",
1080 " integer value for"
1081 " layer -- line: %s",
1094 fvwm_msg(ERR
, "ButtonStyle",
1095 "unknown title button flag"
1096 " %s -- line: %s", tok
, text
);
1106 text
= GetNextToken(text
, &tok
);
1114 for (i
= 0; i
< NUMBER_OF_TITLE_BUTTONS
; ++i
)
1116 if (((multi
& 1) && !(i
& 1)) ||
1117 ((multi
& 2) && (i
& 1)))
1119 text
= ReadTitleButton(
1126 else if (!(text
= ReadTitleButton(
1127 prev
, tb
, do_add
, button
)))
1138 int update_decorface_colorset(DecorFace
*df
, int cset
)
1141 int has_changed
= 0;
1143 for(tdf
= df
; tdf
!= NULL
; tdf
= tdf
->next
)
1145 if (DFS_FACE_TYPE(tdf
->style
) == ColorsetButton
&&
1146 tdf
->u
.acs
.cs
== cset
)
1148 tdf
->flags
.has_changed
= 1;
1151 else if (DFS_FACE_TYPE(tdf
->style
) == MultiPixmap
)
1155 for (i
= 0; i
< TBMP_NUM_PIXMAPS
; i
++)
1157 if (tdf
->u
.mp
.acs
[i
].cs
== cset
)
1159 tdf
->flags
.has_changed
= 1;
1170 int update_titlebutton_colorset(TitleButton
*tb
, int cset
)
1173 int has_changed
= 0;
1175 for(i
= 0; i
< BS_MaxButtonState
; i
++)
1177 tb
->state
[i
].flags
.has_changed
=
1178 update_decorface_colorset(&(tb
->state
[i
]), cset
);
1179 has_changed
|= tb
->state
[i
].flags
.has_changed
;
1185 void update_decors_colorset(int cset
)
1189 FvwmDecor
*decor
= &Scr
.DefaultDecor
;
1192 for(decor
= &Scr
.DefaultDecor
; decor
!= NULL
; decor
= decor
->next
)
1196 for(i
= 0; i
< NUMBER_OF_TITLE_BUTTONS
; i
++)
1198 decor
->flags
.has_changed
|= update_titlebutton_colorset(
1199 &(decor
->buttons
[i
]), cset
);
1201 decor
->flags
.has_changed
|= update_titlebutton_colorset(
1202 &(decor
->titlebar
), cset
);
1203 decor
->flags
.has_changed
|= update_decorface_colorset(
1204 &(decor
->BorderStyle
.active
), cset
);
1205 decor
->flags
.has_changed
|= update_decorface_colorset(
1206 &(decor
->BorderStyle
.inactive
), cset
);
1207 if (decor
->flags
.has_changed
)
1209 Scr
.flags
.do_need_window_update
= 1;
1214 static Bool
__parse_vector_line_one_coord(
1215 char **ret_action
, int *pcoord
, int *poff
, char *action
)
1220 *ret_action
= action
;
1221 n
= sscanf(action
, "%d%n", pcoord
, &offset
);
1227 /* check for offest */
1228 if (*action
== '+' || *action
== '-')
1230 n
= sscanf(action
, "%dp%n", poff
, &offset
);
1239 else if (*poff
> 127)
1249 *ret_action
= action
;
1254 static Bool
__parse_vector_line(
1255 char **ret_action
, int *px
, int *py
, int *pxoff
, int *pyoff
, int *pc
,
1258 Bool is_valid
= True
;
1262 *ret_action
= action
;
1263 if (__parse_vector_line_one_coord(&action
, px
, pxoff
, action
) == False
)
1272 if (__parse_vector_line_one_coord(&action
, py
, pyoff
, action
) == False
)
1281 /* read the line style */
1282 n
= sscanf(action
, "%d%n", pc
, &offset
);
1288 *ret_action
= action
;
1293 /* ---------------------------- interface functions ------------------------ */
1295 void refresh_window(Window w
, Bool window_update
)
1297 XSetWindowAttributes attributes
;
1298 unsigned long valuemask
;
1300 valuemask
= CWOverrideRedirect
| CWBackingStore
| CWSaveUnder
|
1302 attributes
.override_redirect
= True
;
1303 attributes
.save_under
= False
;
1304 attributes
.background_pixmap
= None
;
1305 attributes
.backing_store
= NotUseful
;
1307 dpy
, w
, 0, 0, Scr
.MyDisplayWidth
, Scr
.MyDisplayHeight
, 0,
1308 CopyFromParent
, CopyFromParent
, CopyFromParent
, valuemask
,
1311 if (Scr
.flags
.do_need_window_update
&& window_update
)
1313 flush_window_updates();
1315 XDestroyWindow(dpy
, w
);
1317 handle_all_expose();
1322 void ApplyDefaultFontAndColors(void)
1326 int cset
= Scr
.DefaultColorset
;
1329 gcm
= GCFunction
|GCLineWidth
|GCForeground
|GCBackground
;
1330 gcv
.function
= GXcopy
;
1331 if (Scr
.DefaultFont
->font
)
1334 gcv
.font
= Scr
.DefaultFont
->font
->fid
;
1339 gcv
.foreground
= Colorset
[cset
].fg
;
1340 gcv
.background
= Colorset
[cset
].bg
;
1344 gcv
.foreground
= Scr
.StdFore
;
1345 gcv
.background
= Scr
.StdBack
;
1349 XChangeGC(dpy
, Scr
.StdGC
, gcm
, &gcv
);
1353 Scr
.StdGC
= fvwmlib_XCreateGC(dpy
, Scr
.NoFocusWin
, gcm
, &gcv
);
1356 gcm
= GCFunction
|GCLineWidth
|GCForeground
;
1359 gcv
.foreground
= Colorset
[cset
].hilite
;
1363 gcv
.foreground
= Scr
.StdHilite
;
1365 if (Scr
.StdReliefGC
)
1367 XChangeGC(dpy
, Scr
.StdReliefGC
, gcm
, &gcv
);
1371 Scr
.StdReliefGC
= fvwmlib_XCreateGC(
1372 dpy
, Scr
.NoFocusWin
, gcm
, &gcv
);
1376 gcv
.foreground
= Colorset
[cset
].shadow
;
1380 gcv
.foreground
= Scr
.StdShadow
;
1382 if (Scr
.StdShadowGC
)
1384 XChangeGC(dpy
, Scr
.StdShadowGC
, gcm
, &gcv
);
1388 Scr
.StdShadowGC
= fvwmlib_XCreateGC(
1389 dpy
, Scr
.NoFocusWin
, gcm
, &gcv
);
1391 /* update the geometry window for move/resize */
1392 if (Scr
.SizeWindow
!= None
)
1394 resize_geometry_window();
1396 UpdateAllMenuStyles();
1401 void FreeDecorFace(Display
*dpy
, DecorFace
*df
)
1405 switch (DFS_FACE_TYPE(df
->style
))
1407 case GradientButton
:
1408 if (df
->u
.grad
.d_pixels
!= NULL
&& df
->u
.grad
.d_npixels
)
1411 dpy
, Pcmap
, df
->u
.grad
.d_pixels
,
1412 df
->u
.grad
.d_npixels
, 0, False
);
1413 free(df
->u
.grad
.d_pixels
);
1415 else if (Pdepth
<= 8 && df
->u
.grad
.xcs
!= NULL
&&
1416 df
->u
.grad
.npixels
> 0 && !df
->u
.grad
.do_dither
)
1421 p
= (Pixel
*)safemalloc(
1422 df
->u
.grad
.npixels
* sizeof(Pixel
));
1423 for(i
=0; i
< df
->u
.grad
.npixels
; i
++)
1425 p
[i
] = df
->u
.grad
.xcs
[i
].pixel
;
1428 dpy
, Pcmap
, p
, df
->u
.grad
.npixels
, 0, False
);
1431 if (df
->u
.grad
.xcs
!= NULL
)
1433 free(df
->u
.grad
.xcs
);
1438 case TiledPixmapButton
:
1439 case StretchedPixmapButton
:
1440 case AdjustedPixmapButton
:
1441 case ShrunkPixmapButton
:
1444 PDestroyFvwmPicture(dpy
, df
->u
.p
);
1449 if (df
->u
.mp
.pixmaps
)
1451 for (i
= 0; i
< TBMP_NUM_PIXMAPS
; i
++)
1453 if (df
->u
.mp
.pixmaps
[i
])
1455 PDestroyFvwmPicture(
1456 dpy
, df
->u
.mp
.pixmaps
[i
]);
1458 else if (!!(df
->u
.mp
.solid_flags
& i
))
1461 dpy
, Pcmap
, &df
->u
.mp
.pixels
[i
],
1465 free(df
->u
.mp
.pixmaps
);
1471 if (df
->u
.mp
.pixels
)
1473 free(df
->u
.mp
.pixels
);
1477 case DefaultVectorButton
:
1480 free (df
->u
.vector
.x
);
1484 free (df
->u
.vector
.y
);
1486 /* free offsets for coord */
1487 if (df
->u
.vector
.xoff
)
1489 free(df
->u
.vector
.xoff
);
1491 if (df
->u
.vector
.yoff
)
1493 free(df
->u
.vector
.yoff
);
1497 free (df
->u
.vector
.c
);
1504 /* delete any compound styles */
1507 FreeDecorFace(dpy
, df
->next
);
1511 memset(&df
->style
, 0, sizeof(df
->style
));
1512 memset(&df
->u
, 0, sizeof(df
->u
));
1513 DFS_FACE_TYPE(df
->style
) = SimpleButton
;
1520 * Reads a button face line into a structure (veliaa@rpi.edu)
1523 Bool
ReadDecorFace(char *s
, DecorFace
*df
, int button
, int verbose
)
1526 char style
[256], *file
;
1529 /* some variants of scanf do not increase the assign count when %n is
1530 * used, so a return value of 1 is no error. */
1531 if (sscanf(s
, "%255s%n", style
, &offset
) < 1)
1535 fvwm_msg(ERR
, "ReadDecorFace", "error in face `%s'", s
);
1541 if (strncasecmp(style
, "--", 2) != 0)
1545 FreeDecorFace(dpy
, df
);
1547 /* determine button style */
1548 if (strncasecmp(style
,"Simple",6)==0)
1550 memset(&df
->style
, 0, sizeof(df
->style
));
1551 DFS_FACE_TYPE(df
->style
) = SimpleButton
;
1553 else if (strncasecmp(style
,"Default",7)==0)
1555 int b
= -1, n
= sscanf(s
, "%d%n", &b
, &offset
);
1564 ERR
,"ReadDecorFace",
1565 "need default button"
1574 b
= BUTTON_INDEX(b
);
1577 if (b
>= 0 && b
< NUMBER_OF_TITLE_BUTTONS
)
1579 LoadDefaultButton(df
, b
);
1586 ERR
, "ReadDecorFace",
1587 "button number out of range:"
1593 else if (strncasecmp(style
,"Vector",6)==0 ||
1594 (strlen(style
)<=2 && isdigit(*style
)))
1596 /* normal coordinate list button style */
1597 int i
, num_coords
, num
;
1598 struct vector_coords
*vc
= &df
->u
.vector
;
1600 /* get number of points */
1601 if (strncasecmp(style
,"Vector",6)==0)
1603 num
= sscanf(s
,"%d%n",&num_coords
,&offset
);
1608 num
= sscanf(style
,"%d",&num_coords
);
1611 if (num
< 1 || num_coords
<2 ||
1612 num_coords
> MAX_TITLE_BUTTON_VECTOR_LINES
)
1617 ERR
, "ReadDecorFace",
1618 "Bad button style (2) in line:"
1624 vc
->num
= num_coords
;
1626 vc
->x
= (signed char*)safemalloc(sizeof(char) *
1628 vc
->y
= (signed char*)safemalloc(sizeof(char) *
1630 vc
->xoff
= (signed char*)safemalloc(sizeof(char) *
1632 vc
->yoff
= (signed char*)safemalloc(sizeof(char) *
1634 vc
->c
= (signed char*)safemalloc(sizeof(char) *
1637 /* get the points */
1638 for (i
= 0; i
< vc
->num
; ++i
)
1646 if (__parse_vector_line(
1647 &s
, &x
, &y
, &xoff
, &yoff
, &c
, s
) ==
1677 if (c
== 2 || c
== 3)
1687 ERR
, "ReadDecorFace",
1688 "Bad button style (3) in line"
1703 memset(&df
->style
, 0, sizeof(df
->style
));
1704 DFS_FACE_TYPE(df
->style
) = VectorButton
;
1706 else if (strncasecmp(style
,"Solid",5)==0)
1708 s
= GetNextToken(s
, &file
);
1711 memset(&df
->style
, 0, sizeof(df
->style
));
1712 DFS_FACE_TYPE(df
->style
) = SolidButton
;
1713 df
->u
.back
= GetColor(file
);
1721 ERR
, "ReadDecorFace",
1722 "no color given for Solid"
1723 " face type: %s", action
);
1728 else if (strncasecmp(style
+1, "Gradient", 8)==0)
1731 int npixels
, nsegs
, *perc
;
1733 Bool do_dither
= False
;
1735 if (!IsGradientTypeSupported(style
[0]))
1739 /* translate the gradient string into an array of
1741 npixels
= ParseGradient(
1742 s
, &s
, &s_colors
, &perc
, &nsegs
);
1743 while (*s
&& isspace(*s
))
1751 /* grab the colors */
1756 xcs
= AllocAllGradientColors(
1757 s_colors
, perc
, nsegs
, npixels
, do_dither
);
1760 df
->u
.grad
.xcs
= xcs
;
1761 df
->u
.grad
.npixels
= npixels
;
1762 df
->u
.grad
.do_dither
= do_dither
;
1763 df
->u
.grad
.d_pixels
= NULL
;
1764 memset(&df
->style
, 0, sizeof(df
->style
));
1765 DFS_FACE_TYPE(df
->style
) = GradientButton
;
1766 df
->u
.grad
.gradient_type
= toupper(style
[0]);
1768 else if (strncasecmp(style
,"Pixmap",6)==0
1769 || strncasecmp(style
,"TiledPixmap",11)==0
1770 || strncasecmp(style
,"StretchedPixmap",15)==0
1771 || strncasecmp(style
,"AdjustedPixmap",14)==0
1772 || strncasecmp(style
,"ShrunkPixmap",12)==0)
1774 FvwmPictureAttributes fpa
;
1776 s
= GetNextToken(s
, &file
);
1777 fpa
.mask
= (Pdepth
<= 8)? FPAM_DITHER
:0; /* ? */
1778 df
->u
.p
= PCacheFvwmPicture(
1779 dpy
, Scr
.NoFocusWin
, NULL
, file
, fpa
);
1780 if (df
->u
.p
== NULL
)
1787 ERR
, "ReadDecorFace",
1788 "couldn't load pixmap"
1801 memset(&df
->style
, 0, sizeof(df
->style
));
1802 if (strncasecmp(style
,"Tiled",5)==0)
1804 DFS_FACE_TYPE(df
->style
) = TiledPixmapButton
;
1806 else if (strncasecmp(style
,"Stretched",9)==0)
1808 DFS_FACE_TYPE(df
->style
) =
1809 StretchedPixmapButton
;
1811 else if (strncasecmp(style
,"Adjusted",8)==0)
1813 DFS_FACE_TYPE(df
->style
) =
1814 AdjustedPixmapButton
;
1816 else if (strncasecmp(style
,"Shrunk",6)==0)
1818 DFS_FACE_TYPE(df
->style
) =
1823 DFS_FACE_TYPE(df
->style
) = PixmapButton
;
1826 else if (strncasecmp(style
,"MultiPixmap",11)==0)
1833 ERR
, "ReadDecorFace",
1834 "MultiPixmap is only valid"
1839 s
= ReadMultiPixmapDecor(s
, df
);
1845 else if (FMiniIconsSupported
&&
1846 strncasecmp (style
, "MiniIcon", 8) == 0)
1848 memset(&df
->style
, 0, sizeof(df
->style
));
1849 DFS_FACE_TYPE(df
->style
) = MiniIconButton
;
1850 /* pixmap read in when the window is created */
1853 else if (strncasecmp (style
, "Colorset", 8) == 0)
1858 n
= GetIntegerArguments(s
, NULL
, val
, 2);
1862 memset(&df
->style
, 0, sizeof(df
->style
));
1863 if (n
> 0 && val
[0] >= 0)
1866 df
->u
.acs
.cs
= val
[0];
1867 alloc_colorset(val
[0]);
1868 DFS_FACE_TYPE(df
->style
) = ColorsetButton
;
1870 df
->u
.acs
.alpha_percent
= 100;
1873 df
->u
.acs
.alpha_percent
=
1874 max(0, min(100,val
[1]));
1876 s
= SkipNTokens(s
, n
);
1883 ERR
, "ReadDecorFace",
1884 "unknown style %s: %s", style
, action
);
1890 /* Process button flags ("--" signals start of flags,
1891 it is also checked for above) */
1892 s
= GetNextToken(s
, &file
);
1893 if (file
&& (strcmp(file
,"--")==0))
1896 s
= GetNextToken(s
, &tok
);
1900 char *old_tok
= NULL
;
1908 if (StrEquals(tok
,"Clear"))
1910 memset(&DFS_FLAGS(df
->style
), (set
) ? 0 : 0xff,
1911 sizeof(DFS_FLAGS(df
->style
)));
1912 /* ? what is set == 0 good for ? */
1914 else if (StrEquals(tok
,"Left"))
1918 DFS_H_JUSTIFICATION(df
->style
) =
1923 DFS_H_JUSTIFICATION(df
->style
) =
1927 else if (StrEquals(tok
,"Right"))
1931 DFS_H_JUSTIFICATION(df
->style
) =
1936 DFS_H_JUSTIFICATION(df
->style
) =
1940 else if (StrEquals(tok
,"Centered"))
1942 DFS_H_JUSTIFICATION(df
->style
) = JUST_CENTER
;
1943 DFS_V_JUSTIFICATION(df
->style
) = JUST_CENTER
;
1945 else if (StrEquals(tok
,"Top"))
1949 DFS_V_JUSTIFICATION(df
->style
) =
1954 DFS_V_JUSTIFICATION(df
->style
) =
1958 else if (StrEquals(tok
,"Bottom"))
1962 DFS_V_JUSTIFICATION(df
->style
) =
1967 DFS_V_JUSTIFICATION(df
->style
) =
1971 else if (StrEquals(tok
,"Flat"))
1975 DFS_BUTTON_RELIEF(df
->style
) =
1978 else if (DFS_BUTTON_RELIEF(df
->style
) ==
1981 DFS_BUTTON_RELIEF(df
->style
) =
1985 else if (StrEquals(tok
,"Sunk"))
1989 DFS_BUTTON_RELIEF(df
->style
) =
1992 else if (DFS_BUTTON_RELIEF(df
->style
) ==
1995 DFS_BUTTON_RELIEF(df
->style
) =
1999 else if (StrEquals(tok
,"Raised"))
2003 DFS_BUTTON_RELIEF(df
->style
) =
2008 DFS_BUTTON_RELIEF(df
->style
) =
2012 else if (StrEquals(tok
,"UseTitleStyle"))
2016 DFS_USE_TITLE_STYLE(df
->style
) = 1;
2017 DFS_USE_BORDER_STYLE(df
->style
) = 0;
2020 DFS_USE_TITLE_STYLE(df
->style
) = 0;
2022 else if (StrEquals(tok
,"HiddenHandles"))
2024 DFS_HAS_HIDDEN_HANDLES(df
->style
) = !!set
;
2026 else if (StrEquals(tok
,"NoInset"))
2028 DFS_HAS_NO_INSET(df
->style
) = !!set
;
2030 else if (StrEquals(tok
,"UseBorderStyle"))
2034 DFS_USE_BORDER_STYLE(df
->style
) = 1;
2035 DFS_USE_TITLE_STYLE(df
->style
) = 0;
2039 DFS_USE_BORDER_STYLE(df
->style
) = 0;
2045 ERR
, "ReadDecorFace",
2046 "unknown button face flag '%s'"
2047 " -- line: %s", tok
, action
);
2057 s
= GetNextToken(s
, &tok
);
2071 * Diverts a style definition to an FvwmDecor structure (veliaa@rpi.edu)
2074 void AddToDecor(F_CMD_ARGS
, FvwmDecor
*decor
)
2080 while (*action
&& isspace((unsigned char)*action
))
2088 Scr
.cur_decor
= decor
;
2089 execute_function(cond_rc
, exc
, action
, 0);
2090 Scr
.cur_decor
= NULL
;
2097 * InitFvwmDecor -- initializes an FvwmDecor structure to defaults
2100 void InitFvwmDecor(FvwmDecor
*decor
)
2105 /* zero out the structures */
2106 memset(decor
, 0, sizeof (FvwmDecor
));
2107 memset(&tmpdf
, 0, sizeof(DecorFace
));
2109 /* initialize title-bar button styles */
2110 DFS_FACE_TYPE(tmpdf
.style
) = SimpleButton
;
2111 for (i
= 0; i
< NUMBER_OF_TITLE_BUTTONS
; ++i
)
2114 for (; j
< BS_MaxButtonState
; ++j
)
2116 TB_STATE(decor
->buttons
[i
])[j
] = tmpdf
;
2119 /* reset to default button set */
2120 ResetAllButtons(decor
);
2121 /* initialize title-bar styles */
2122 for (i
= 0; i
< BS_MaxButtonState
; ++i
)
2125 TB_STATE(decor
->titlebar
)[i
].style
) = SimpleButton
;
2128 /* initialize border texture styles */
2129 DFS_FACE_TYPE(decor
->BorderStyle
.active
.style
) = SimpleButton
;
2130 DFS_FACE_TYPE(decor
->BorderStyle
.inactive
.style
) = SimpleButton
;
2135 void reset_decor_changes(void)
2138 Scr
.DefaultDecor
.flags
.has_changed
= 0;
2139 Scr
.DefaultDecor
.flags
.has_title_height_changed
= 0;
2142 for (decor
= &Scr
.DefaultDecor
; decor
; decor
= decor
->next
)
2144 decor
->flags
.has_changed
= 0;
2145 decor
->flags
.has_title_height_changed
= 0;
2147 /* todo: must reset individual change flags too */
2153 void update_fvwm_colorset(int cset
)
2155 if (cset
== Scr
.DefaultColorset
)
2157 Scr
.flags
.do_need_window_update
= 1;
2158 Scr
.flags
.has_default_color_changed
= 1;
2160 UpdateMenuColorset(cset
);
2161 update_style_colorset(cset
);
2162 update_decors_colorset(cset
);
2167 /* ---------------------------- builtin commands --------------------------- */
2169 void CMD_Beep(F_CMD_ARGS
)
2172 parse_colorset(11, "RootTransparent");
2179 void CMD_Nop(F_CMD_ARGS
)
2184 void CMD_EscapeFunc(F_CMD_ARGS
)
2189 void CMD_CursorMove(F_CMD_ARGS
)
2192 int val1
, val2
, val1_unit
, val2_unit
;
2193 int virtual_x
, virtual_y
;
2195 int x_pages
, y_pages
;
2197 if (GetTwoArguments(action
, &val1
, &val2
, &val1_unit
, &val2_unit
) != 2)
2199 fvwm_msg(ERR
, "movecursor", "CursorMove needs 2 arguments");
2202 if (FQueryPointer(dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
,
2203 &x
, &y
, &JunkX
, &JunkY
, &JunkMask
) == False
)
2205 /* pointer is on a different screen */
2208 x
= x
+ val1
* val1_unit
/ 100;
2209 y
= y
+ val2
* val2_unit
/ 100;
2214 x_pages
= x
/ Scr
.MyDisplayWidth
;
2218 x_pages
= ((x
+ 1) / Scr
.MyDisplayWidth
) - 1;
2220 virtual_x
+= x_pages
* Scr
.MyDisplayWidth
;
2221 x
-= x_pages
* Scr
.MyDisplayWidth
;
2227 else if (virtual_x
> Scr
.VxMax
)
2229 x
+= virtual_x
- Scr
.VxMax
;
2230 virtual_x
= Scr
.VxMax
;
2235 y_pages
= y
/ Scr
.MyDisplayHeight
;
2239 y_pages
= ((y
+ 1) / Scr
.MyDisplayHeight
) - 1;
2241 virtual_y
+= y_pages
* Scr
.MyDisplayHeight
;
2242 y
-= y_pages
* Scr
.MyDisplayHeight
;
2248 else if (virtual_y
> Scr
.VyMax
)
2250 y
+= virtual_y
- Scr
.VyMax
;
2251 virtual_y
= Scr
.VyMax
;
2253 if (virtual_x
!= Scr
.Vx
|| virtual_y
!= Scr
.Vy
)
2254 MoveViewport(virtual_x
, virtual_y
, True
);
2255 pan_x
= (Scr
.EdgeScrollX
!= 0) ? 2 : 0;
2256 pan_y
= (Scr
.EdgeScrollY
!= 0) ? 2 : 0;
2257 /* prevent paging if EdgeScroll is active */
2258 if (x
>= Scr
.MyDisplayWidth
- pan_x
)
2260 x
= Scr
.MyDisplayWidth
- pan_x
-1;
2266 if (y
>= Scr
.MyDisplayHeight
- pan_y
)
2268 y
= Scr
.MyDisplayHeight
- pan_y
- 1;
2274 FWarpPointerUpdateEvpos(
2275 exc
->x
.elast
, dpy
, None
, Scr
.Root
, 0, 0, Scr
.MyDisplayWidth
,
2276 Scr
.MyDisplayHeight
, x
, y
);
2281 void CMD_Delete(F_CMD_ARGS
)
2283 FvwmWindow
* const fw
= exc
->w
.fw
;
2285 if (!is_function_allowed(F_DELETE
, NULL
, fw
, RQORIG_PROGRAM_US
, True
))
2291 if (IS_TEAR_OFF_MENU(fw
))
2293 /* 'soft' delete tear off menus. Note: we can't send the
2294 * message to the menu window directly because it was created
2295 * using a different display. The client message would never
2296 * be read from there. */
2298 dpy
, FW_W_PARENT(fw
), _XA_WM_DELETE_WINDOW
,
2303 if (WM_DELETES_WINDOW(fw
))
2306 dpy
, FW_W(fw
), _XA_WM_DELETE_WINDOW
, CurrentTime
);
2319 void CMD_Destroy(F_CMD_ARGS
)
2321 FvwmWindow
* const fw
= exc
->w
.fw
;
2323 if (IS_TEAR_OFF_MENU(fw
))
2325 CMD_Delete(F_PASS_ARGS
);
2328 if (!is_function_allowed(F_DESTROY
, NULL
, fw
, True
, True
))
2335 dpy
, FW_W(fw
), &JunkRoot
, &JunkX
, &JunkY
,
2336 (unsigned int*)&JunkWidth
, (unsigned int*)&JunkHeight
,
2337 (unsigned int*)&JunkBW
, (unsigned int*)&JunkDepth
)
2340 XKillClient(dpy
, FW_W(fw
));
2348 void CMD_Close(F_CMD_ARGS
)
2350 FvwmWindow
* const fw
= exc
->w
.fw
;
2352 if (IS_TEAR_OFF_MENU(fw
))
2354 CMD_Delete(F_PASS_ARGS
);
2357 if (!is_function_allowed(F_CLOSE
, NULL
, fw
, True
, True
))
2362 if (WM_DELETES_WINDOW(fw
))
2365 dpy
, FW_W(fw
), _XA_WM_DELETE_WINDOW
, CurrentTime
);
2370 dpy
, FW_W(fw
), &JunkRoot
, &JunkX
, &JunkY
,
2371 (unsigned int*)&JunkWidth
, (unsigned int*)&JunkHeight
,
2372 (unsigned int*)&JunkBW
, (unsigned int*)&JunkDepth
)
2375 XKillClient(dpy
, FW_W(fw
));
2384 void CMD_Restart(F_CMD_ARGS
)
2391 void CMD_ExecUseShell(F_CMD_ARGS
)
2394 static char shell_set
= 0;
2398 free(exec_shell_name
);
2401 action
= GetNextToken(action
,&arg
);
2402 if (arg
) /* specific shell was specified */
2404 exec_shell_name
= arg
;
2406 else /* no arg, so use $SHELL -- not working??? */
2408 if (getenv("SHELL"))
2410 exec_shell_name
= safestrdup(getenv("SHELL"));
2414 /* if $SHELL not set, use default */
2415 exec_shell_name
= safestrdup("/bin/sh");
2420 void CMD_Exec(F_CMD_ARGS
)
2424 /* if it doesn't already have an 'exec' as the first word, add that
2425 * to keep down number of procs started */
2426 /* need to parse string better to do this right though, so not doing
2427 * this for now... */
2429 if (strncasecmp(action
,"exec",4)!=0)
2431 cmd
= (char *)safemalloc(strlen(action
)+6);
2432 strcpy(cmd
,"exec ");
2438 cmd
= safestrdup(action
);
2444 /* Use to grab the pointer here, but the fork guarantees that
2445 * we wont be held up waiting for the function to finish,
2446 * so the pointer-gram just caused needless delay and flashing
2448 /* Thought I'd try vfork and _exit() instead of regular fork().
2449 * The man page says that its better. */
2450 /* Not everyone has vfork! */
2451 /* According to the man page, vfork should never be used at all.
2454 if (!(fork())) /* child process */
2456 /* This is for fixing a problem with rox filer */
2459 fvmm_deinstall_signals();
2460 fd
= open("/dev/null", O_RDONLY
, 0);
2461 dup2(fd
,STDIN_FILENO
);
2462 if (fvwm_setpgrp() == -1)
2464 fvwm_msg(ERR
, "exec_function", "setpgrp failed (%s)",
2468 if (execl(exec_shell_name
, exec_shell_name
, "-c", cmd
, NULL
) ==
2471 fvwm_msg(ERR
, "exec_function", "execl failed (%s)",
2481 void CMD_Refresh(F_CMD_ARGS
)
2483 refresh_window(Scr
.Root
, True
);
2488 void CMD_RefreshWindow(F_CMD_ARGS
)
2490 FvwmWindow
* const fw
= exc
->w
.fw
;
2493 (exc
->w
.wcontext
== C_ICON
) ?
2494 FW_W_ICON_TITLE(fw
) : FW_W_FRAME(fw
), True
);
2499 void CMD_Wait(F_CMD_ARGS
)
2502 Bool redefine_cursor
= False
;
2505 Window nonewin
= None
;
2506 char *wait_string
, *rest
;
2509 /* try to get a single token */
2510 rest
= GetNextToken(action
, &wait_string
);
2513 while (*rest
&& isspace((unsigned char)*rest
))
2522 /* nope, multiple tokens - try old syntax */
2524 /* strip leading and trailing whitespace */
2526 while (*temp
&& isspace((unsigned char)*temp
))
2530 wait_string
= safestrdup(temp
);
2531 for (i
= strlen(wait_string
) - 1; i
>= 0 &&
2532 isspace(wait_string
[i
]); i
--)
2540 wait_string
= safestrdup("");
2543 is_ungrabbed
= UngrabEm(GRAB_NORMAL
);
2544 while (!done
&& !isTerminated
)
2547 if (BUSY_WAIT
& Scr
.BusyCursor
)
2549 XDefineCursor(dpy
, Scr
.Root
, Scr
.FvwmCursors
[CRS_WAIT
]);
2550 redefine_cursor
= True
;
2552 if (My_XNextEvent(dpy
, &e
))
2556 dpy
, e
.xmap
.window
, FvwmContext
,
2557 (caddr_t
*)&t
) == XCNOENT
)
2562 if (e
.type
== MapNotify
&& e
.xmap
.event
== Scr
.Root
)
2568 if (t
&& matchWildcards(
2569 wait_string
, t
->name
.name
) == True
)
2573 else if (t
&& t
->class.res_class
&&
2576 t
->class.res_class
) == True
)
2580 else if (t
&& t
->class.res_name
&&
2583 t
->class.res_name
) == True
)
2588 else if (e
.type
== KeyPress
)
2590 /* should I be using <t> or <exc->w.fw>?
2597 context
= GetContext(&t
, t
, &e
, &nonewin
);
2600 class = &(t
->class);
2601 name
= t
->name
.name
;
2608 escape
= CheckBinding(
2609 Scr
.AllBindings
, STROKE_ARG(0)
2610 e
.xkey
.keycode
, e
.xkey
.state
,
2611 GetUnusedModifiers(), context
,
2612 BIND_KEYPRESS
, class, name
);
2615 if (!strcasecmp(escape
,"escapefunc"))
2623 if (redefine_cursor
)
2625 XDefineCursor(dpy
, Scr
.Root
, Scr
.FvwmCursors
[CRS_ROOT
]);
2629 GrabEm(CRS_NONE
, GRAB_NORMAL
);
2636 void CMD_Quit(F_CMD_ARGS
)
2638 if (master_pid
!= getpid())
2640 kill(master_pid
, SIGTERM
);
2647 void CMD_QuitScreen(F_CMD_ARGS
)
2654 void CMD_Echo(F_CMD_ARGS
)
2662 len
= strlen(action
);
2665 if (action
[len
-1]=='\n')
2670 fvwm_msg(ECHO
,"Echo",action
);
2675 void CMD_PrintInfo(F_CMD_ARGS
)
2678 char *rest
, *subject
= NULL
;
2680 rest
= GetNextToken(action
, &subject
);
2681 if (!rest
|| GetIntegerArguments(rest
, NULL
, &verbose
, 1) != 1)
2685 if (StrEquals(subject
, "Colors"))
2687 PicturePrintColorInfo(verbose
);
2689 else if (StrEquals(subject
, "Locale"))
2691 FlocalePrintLocaleInfo(dpy
, verbose
);
2693 else if (StrEquals(subject
, "NLS"))
2695 FGettextPrintLocalePath(verbose
);
2697 else if (StrEquals(subject
, "style"))
2699 print_styles(verbose
);
2701 else if (StrEquals(subject
, "ImageCache"))
2703 PicturePrintImageCache(verbose
);
2705 else if (StrEquals(subject
, "Bindings"))
2711 fvwm_msg(ERR
, "PrintInfo",
2712 "Unknown subject '%s'", action
);
2721 void CMD_ColormapFocus(F_CMD_ARGS
)
2723 if (MatchToken(action
,"FollowsFocus"))
2725 Scr
.ColormapFocus
= COLORMAP_FOLLOWS_FOCUS
;
2727 else if (MatchToken(action
,"FollowsMouse"))
2729 Scr
.ColormapFocus
= COLORMAP_FOLLOWS_MOUSE
;
2733 fvwm_msg(ERR
, "SetColormapFocus",
2734 "ColormapFocus requires 1 arg: FollowsFocus or"
2742 void CMD_ClickTime(F_CMD_ARGS
)
2746 if (GetIntegerArguments(action
, NULL
, &val
, 1) != 1)
2748 Scr
.ClickTime
= DEFAULT_CLICKTIME
;
2752 Scr
.ClickTime
= (val
< 0)? 0 : val
;
2755 /* Use a negative value during startup and change sign afterwards. This
2756 * speeds things up quite a bit. */
2759 Scr
.ClickTime
= -Scr
.ClickTime
;
2766 void CMD_ImagePath(F_CMD_ARGS
)
2768 PictureSetImagePath( action
);
2773 void CMD_IconPath(F_CMD_ARGS
)
2775 fvwm_msg(ERR
, "iconPath_function",
2776 "IconPath is deprecated since 2.3.0; use ImagePath instead.");
2777 obsolete_imagepaths( action
);
2782 void CMD_PixmapPath(F_CMD_ARGS
)
2784 fvwm_msg(ERR
, "pixmapPath_function",
2785 "PixmapPath is deprecated since 2.3.0; use ImagePath"
2787 obsolete_imagepaths( action
);
2792 void CMD_LocalePath(F_CMD_ARGS
)
2794 FGettextSetLocalePath( action
);
2799 void CMD_ModulePath(F_CMD_ARGS
)
2801 static int need_to_free
= 0;
2803 setPath( &ModulePath
, action
, need_to_free
);
2809 void CMD_ModuleTimeout(F_CMD_ARGS
)
2813 moduleTimeout
= DEFAULT_MODULE_TIMEOUT
;
2814 if (GetIntegerArguments(action
, NULL
, &timeout
, 1) == 1 && timeout
> 0)
2816 moduleTimeout
= timeout
;
2822 void CMD_HilightColor(F_CMD_ARGS
)
2827 if (Scr
.cur_decor
&& Scr
.cur_decor
!= &Scr
.DefaultDecor
)
2831 "Decors do not support the HilightColor command"
2832 " anymore. Please use"
2833 " 'Style <stylename> HilightFore <forecolor>' and"
2834 " 'Style <stylename> HilightBack <backcolor>' instead."
2835 " Sorry for the inconvenience.");
2839 action
= GetNextToken(action
, &fore
);
2840 GetNextToken(action
, &back
);
2843 action
= safemalloc(strlen(fore
) + strlen(back
) + 29);
2844 sprintf(action
, "* HilightFore %s, HilightBack %s", fore
, back
);
2845 CMD_Style(F_PASS_ARGS
);
2859 void CMD_HilightColorset(F_CMD_ARGS
)
2864 if (Scr
.cur_decor
&& Scr
.cur_decor
!= &Scr
.DefaultDecor
)
2867 ERR
, "SetHiColorset",
2868 "Decors do not support the HilightColorset command "
2869 "anymore. Please use "
2870 "'Style <stylename> HilightColorset <colorset>'"
2871 " instead. Sorry for the inconvenience.");
2877 newaction
= safemalloc(strlen(action
) + 32);
2878 sprintf(newaction
, "* HilightColorset %s", action
);
2880 CMD_Style(F_PASS_ARGS
);
2887 void CMD_TitleStyle(F_CMD_ARGS
)
2889 do_title_style(F_PASS_ARGS
, False
);
2892 } /* SetTitleStyle */
2896 * Appends a titlestyle (veliaa@rpi.edu)
2899 void CMD_AddTitleStyle(F_CMD_ARGS
)
2901 do_title_style(F_PASS_ARGS
, True
);
2906 void CMD_PropertyChange(F_CMD_ARGS
)
2912 unsigned long argument
;
2913 unsigned long data1
;
2914 unsigned long data2
;
2917 token
= PeekToken(action
, &rest
);
2922 ret
= sscanf(token
, "%lu", &argument
);
2929 token
= PeekToken(rest
, &rest
);
2932 ret
= sscanf(token
, "%lu", &data1
);
2940 token
= PeekToken(rest
, &rest
);
2943 ret
= sscanf(token
, "%lu", &data2
);
2950 memset(string
, 0, 256);
2953 ret
= sscanf(rest
, "%255c", &(string
[0]));
2955 BroadcastPropertyChange(argument
, data1
, data2
, string
);
2960 void CMD_DefaultIcon(F_CMD_ARGS
)
2962 if (Scr
.DefaultIcon
)
2964 free(Scr
.DefaultIcon
);
2966 GetNextToken(action
, &Scr
.DefaultIcon
);
2971 void CMD_DefaultColorset(F_CMD_ARGS
)
2975 if (GetIntegerArguments(action
, NULL
, &cset
, 1) != 1)
2979 Scr
.DefaultColorset
= cset
;
2980 if (Scr
.DefaultColorset
< 0)
2982 Scr
.DefaultColorset
= -1;
2984 alloc_colorset(Scr
.DefaultColorset
);
2985 Scr
.flags
.do_need_window_update
= 1;
2986 Scr
.flags
.has_default_color_changed
= 1;
2991 void CMD_DefaultColors(F_CMD_ARGS
)
2996 action
= GetNextToken(action
, &fore
);
2999 action
= GetNextToken(action
, &back
);
3003 back
= safestrdup(DEFAULT_BACK_COLOR
);
3007 fore
= safestrdup(DEFAULT_FORE_COLOR
);
3009 if (!StrEquals(fore
, "-"))
3011 PictureFreeColors(dpy
, Pcmap
, &Scr
.StdFore
, 1, 0, True
);
3012 Scr
.StdFore
= GetColor(fore
);
3014 if (!StrEquals(back
, "-"))
3016 PictureFreeColors(dpy
, Pcmap
, &Scr
.StdBack
, 3, 0, True
);
3017 Scr
.StdBack
= GetColor(back
);
3018 Scr
.StdHilite
= GetHilite(Scr
.StdBack
);
3019 Scr
.StdShadow
= GetShadow(Scr
.StdBack
);
3024 Scr
.DefaultColorset
= -1;
3025 Scr
.flags
.do_need_window_update
= 1;
3026 Scr
.flags
.has_default_color_changed
= 1;
3031 void CMD_DefaultFont(F_CMD_ARGS
)
3034 FlocaleFont
*new_font
;
3037 font
= PeekToken(action
, &action
);
3040 /* Try 'fixed', pass NULL font name */
3042 if (!(new_font
= FlocaleLoadFont(dpy
, font
, "fvwm")))
3044 if (Scr
.DefaultFont
== NULL
)
3053 FlocaleUnloadFont(dpy
, Scr
.DefaultFont
);
3054 Scr
.DefaultFont
= new_font
;
3055 /* we should do that here because a redraw can happen before
3056 flush_window_updates is called ... */
3057 for (t
= Scr
.FvwmRoot
.next
; t
!= NULL
; t
= t
->next
)
3059 if (USING_DEFAULT_ICON_FONT(t
))
3061 t
->icon_font
= Scr
.DefaultFont
;
3063 if (USING_DEFAULT_WINDOW_FONT(t
))
3065 t
->title_font
= Scr
.DefaultFont
;
3068 /* set flags to indicate that the font has changed */
3069 Scr
.flags
.do_need_window_update
= 1;
3070 Scr
.flags
.has_default_font_changed
= 1;
3075 void CMD_IconFont(F_CMD_ARGS
)
3080 if (Scr
.cur_decor
&& Scr
.cur_decor
!= &Scr
.DefaultDecor
)
3083 ERR
, "LoadIconFont",
3084 "Decors do not support the IconFont command anymore."
3085 " Please use 'Style <stylename> IconFont <fontname>'"
3086 " instead. Sorry for the inconvenience.");
3092 newaction
= safemalloc(strlen(action
) + 16);
3093 sprintf(newaction
, "* IconFont %s", action
);
3095 CMD_Style(F_PASS_ARGS
);
3102 void CMD_WindowFont(F_CMD_ARGS
)
3107 if (Scr
.cur_decor
&& Scr
.cur_decor
!= &Scr
.DefaultDecor
)
3110 ERR
, "LoadWindowFont",
3111 "Decors do not support the WindowFont command anymore."
3112 " Please use 'Style <stylename> Font <fontname>'"
3113 " instead. Sorry for the inconvenience.");
3119 newaction
= safemalloc(strlen(action
) + 16);
3120 sprintf(newaction
, "* Font %s", action
);
3122 CMD_Style(F_PASS_ARGS
);
3131 * Changes the window's FvwmDecor pointer (veliaa@rpi.edu)
3134 void CMD_ChangeDecor(F_CMD_ARGS
)
3138 FvwmDecor
*decor
= &Scr
.DefaultDecor
;
3139 FvwmDecor
*found
= NULL
;
3140 FvwmWindow
* const fw
= exc
->w
.fw
;
3142 item
= PeekToken(action
, &action
);
3143 if (!action
|| !item
)
3147 /* search for tag */
3148 for (; decor
; decor
= decor
->next
)
3150 if (decor
->tag
&& StrEquals(item
, decor
->tag
))
3161 SET_DECOR_CHANGED(fw
, 1);
3162 old_height
= (fw
->decor
) ? fw
->decor
->title_height
: 0;
3164 apply_decor_change(fw
);
3171 * Destroys an FvwmDecor (veliaa@rpi.edu)
3174 void CMD_DestroyDecor(F_CMD_ARGS
)
3177 FvwmDecor
*decor
= Scr
.DefaultDecor
.next
;
3178 FvwmDecor
*prev
= &Scr
.DefaultDecor
, *found
= NULL
;
3179 Bool do_recreate
= False
;
3181 item
= PeekToken(action
, &action
);
3186 if (StrEquals(item
, "recreate"))
3189 item
= PeekToken(action
, NULL
);
3196 /* search for tag */
3197 for (; decor
; decor
= decor
->next
)
3199 if (decor
->tag
&& StrEquals(item
, decor
->tag
))
3207 if (found
&& (found
!= &Scr
.DefaultDecor
|| do_recreate
))
3211 __remove_window_decors(F_PASS_ARGS
, found
);
3213 DestroyFvwmDecor(found
);
3218 InitFvwmDecor(found
);
3219 found
->tag
= safestrdup(item
);
3220 Scr
.flags
.do_need_window_update
= 1;
3221 found
->flags
.has_changed
= 1;
3222 found
->flags
.has_title_height_changed
= 0;
3223 found
->titlebar
.flags
.has_changed
= 1;
3224 for (i
= 0; i
< NUMBER_OF_TITLE_BUTTONS
; ++i
)
3226 TB_FLAGS(found
->buttons
[i
]).has_changed
= 1;
3231 prev
->next
= found
->next
;
3241 * Initiates an AddToDecor (veliaa@rpi.edu)
3244 void CMD_AddToDecor(F_CMD_ARGS
)
3247 FvwmDecor
*found
= NULL
;
3250 action
= GetNextToken(action
, &item
);
3260 /* search for tag */
3261 for (decor
= &Scr
.DefaultDecor
; decor
; decor
= decor
->next
)
3263 if (decor
->tag
&& StrEquals(item
, decor
->tag
))
3271 /* then make a new one */
3272 found
= (FvwmDecor
*)safemalloc(sizeof( FvwmDecor
));
3273 InitFvwmDecor(found
);
3274 found
->tag
= item
; /* tag it */
3275 /* add it to list */
3276 for (decor
= &Scr
.DefaultDecor
; decor
->next
;
3277 decor
= decor
->next
)
3281 decor
->next
= found
;
3290 AddToDecor(F_PASS_ARGS
, found
);
3291 /* Set + state to last decor */
3292 set_last_added_item(ADDED_DECOR
, found
);
3297 #endif /* USEDECOR */
3302 * Updates window decoration styles (veliaa@rpi.edu)
3305 void CMD_UpdateDecor(F_CMD_ARGS
)
3309 FvwmDecor
*decor
, *found
= NULL
;
3310 FvwmWindow
*hilight
= Scr
.Hilite
;
3313 action
= GetNextToken(action
, &item
);
3316 /* search for tag */
3317 for (decor
= &Scr
.DefaultDecor
; decor
; decor
= decor
->next
)
3319 if (decor
->tag
&& StrEquals(item
, decor
->tag
))
3329 for (fw2
= Scr
.FvwmRoot
.next
; fw2
; fw2
= fw2
->next
)
3332 /* update specific decor, or all */
3335 if (fw2
->decor
== found
)
3337 border_draw_decorations(
3338 fw2
, PART_ALL
, True
, True
, CLEAR_ALL
,
3340 border_draw_decorations(
3341 fw2
, PART_ALL
, False
, True
, CLEAR_ALL
,
3348 border_draw_decorations(
3349 fw2
, PART_ALL
, True
, True
, CLEAR_ALL
, NULL
,
3351 border_draw_decorations(
3352 fw2
, PART_ALL
, False
, True
, CLEAR_ALL
, NULL
,
3356 border_draw_decorations(
3357 hilight
, PART_ALL
, True
, True
, CLEAR_ALL
, NULL
, NULL
);
3360 void CMD_ButtonStyle(F_CMD_ARGS
)
3362 do_button_style(F_PASS_ARGS
, False
);
3369 * Appends a button decoration style (veliaa@rpi.edu)
3372 void CMD_AddButtonStyle(F_CMD_ARGS
)
3374 do_button_style(F_PASS_ARGS
, True
);
3379 void CMD_SetEnv(F_CMD_ARGS
)
3382 char *szValue
= NULL
;
3383 char *szPutenv
= NULL
;
3385 action
= GetNextToken(action
, &szVar
);
3390 action
= GetNextToken(action
, &szValue
);
3393 szValue
= safestrdup("");
3395 szPutenv
= safemalloc(strlen(szVar
) + strlen(szValue
) + 2);
3396 sprintf(szPutenv
,"%s=%s", szVar
, szValue
);
3397 flib_putenv(szVar
, szPutenv
);
3405 void CMD_UnsetEnv(F_CMD_ARGS
)
3409 szVar
= PeekToken(action
, &action
);
3414 flib_unsetenv(szVar
);
3419 void CMD_GlobalOpts(F_CMD_ARGS
)
3427 "WindowShadeShrinks",
3428 "WindowShadeScrolls",
3429 "SmartPlacementIsReallySmart",
3430 "SmartPlacementIsNormal",
3431 "ClickToFocusDoesntPassClick",
3432 "ClickToFocusPassesClick",
3433 "ClickToFocusDoesntRaise",
3434 "ClickToFocusRaises",
3435 "MouseFocusClickDoesntRaise",
3436 "MouseFocusClickRaises",
3439 "CaptureHonorsStartsOnPage",
3440 "CaptureIgnoresStartsOnPage",
3441 "RecaptureHonorsStartsOnPage",
3442 "RecaptureIgnoresStartsOnPage",
3443 "ActivePlacementHonorsStartsOnPage",
3444 "ActivePlacementIgnoresStartsOnPage",
3445 "RaiseOverNativeWindows",
3446 "IgnoreNativeWindows",
3449 char *replacelist
[] = {
3450 /* These options are mapped to the Style * command */
3451 NULL
, /* NULL means to use "Style * <optionname>" */
3453 "* MinOverlapPlacement",
3454 "* TileCascadePlacement",
3455 "* ClickToFocusPassesClickOff",
3456 "* ClickToFocusPassesClick",
3457 "* ClickToFocusRaisesOff",
3458 "* ClickToFocusRaises",
3459 "* MouseFocusClickRaisesOff",
3460 "* MouseFocusClickRaises",
3461 "* StippledTitleOff",
3467 "* ManualPlacementHonorsStartsOnPage",
3468 "* ManualPlacementIgnoresStartsOnPage",
3469 /* These options are mapped to the BugOpts command */
3470 "RaiseOverNativeWindows on",
3471 "RaiseOverNativeWindows off"
3474 fvwm_msg(ERR
, "SetGlobalOptions",
3475 "The GlobalOpts command is obsolete.");
3476 for (action
= GetNextSimpleOption(action
, &opt
); opt
;
3477 action
= GetNextSimpleOption(action
, &opt
))
3482 i
= GetTokenIndex(opt
, optlist
, 0, NULL
);
3488 replace
= replacelist
[i
];
3489 if (replace
== NULL
)
3491 replace
= &(buf
[0]);
3492 sprintf(buf
, "* %s", opt
);
3494 else if (*replace
!= '*')
3502 CMD_Style(F_PASS_ARGS
);
3507 CMD_BugOpts(F_PASS_ARGS
);
3512 ERR
, "SetGlobalOptions",
3513 "Please replace 'GlobalOpts %s' with '%s %s'.",
3518 fvwm_msg(ERR
, "SetGlobalOptions",
3519 "Unknown Global Option '%s'", opt
);
3521 /* should never be null, but checking anyways... */
3535 void CMD_BugOpts(F_CMD_ARGS
)
3541 /* fvwm_msg(DBG,"SetGlobalOptions","init action == '%s'\n",action); */
3542 while (action
&& *action
&& *action
!= '\n')
3544 action
= GetNextFullOption(action
, &optstring
);
3547 /* no more options */
3550 toggle
= ParseToggleArgument(
3551 SkipNTokens(optstring
,1), NULL
, 2, False
);
3552 opt
= PeekToken(optstring
, NULL
);
3559 /* toggle = ParseToggleArgument(rest, &rest, 2, False);*/
3561 if (StrEquals(opt
, "FlickeringMoveWorkaround"))
3566 Scr
.bo
.do_disable_configure_notify
^= 1;
3570 Scr
.bo
.do_disable_configure_notify
= toggle
;
3573 Scr
.bo
.do_disable_configure_notify
= 0;
3577 else if (StrEquals(opt
, "MixedVisualWorkaround"))
3582 Scr
.bo
.do_install_root_cmap
^= 1;
3586 Scr
.bo
.do_install_root_cmap
= toggle
;
3589 Scr
.bo
.do_install_root_cmap
= 0;
3593 else if (StrEquals(opt
, "ModalityIsEvil"))
3598 Scr
.bo
.is_modality_evil
^= 1;
3602 Scr
.bo
.is_modality_evil
= toggle
;
3605 Scr
.bo
.is_modality_evil
= 0;
3608 if (Scr
.bo
.is_modality_evil
)
3610 SetMWM_INFO(Scr
.NoFocusWin
);
3613 else if (StrEquals(opt
, "RaiseOverNativeWindows"))
3618 Scr
.bo
.is_raise_hack_needed
^= 1;
3622 Scr
.bo
.is_raise_hack_needed
= toggle
;
3625 Scr
.bo
.is_raise_hack_needed
= 0;
3629 else if (StrEquals(opt
, "RaiseOverUnmanaged"))
3634 Scr
.bo
.do_raise_over_unmanaged
^= 1;
3638 Scr
.bo
.do_raise_over_unmanaged
= toggle
;
3641 Scr
.bo
.do_raise_over_unmanaged
= 0;
3645 else if (StrEquals(opt
, "FlickeringQtDialogsWorkaround"))
3650 Scr
.bo
.do_enable_flickering_qt_dialogs_workaround
^= 1;
3654 Scr
.bo
.do_enable_flickering_qt_dialogs_workaround
= toggle
;
3657 Scr
.bo
.do_enable_flickering_qt_dialogs_workaround
= 0;
3661 else if (StrEquals(opt
, "QtDragnDropWorkaround") )
3666 Scr
.bo
.do_enable_qt_drag_n_drop_workaround
^= 1;
3670 Scr
.bo
.do_enable_qt_drag_n_drop_workaround
= toggle
;
3673 Scr
.bo
.do_enable_qt_drag_n_drop_workaround
= 0;
3677 else if (EWMH_BugOpts(opt
, toggle
))
3679 /* work is done in EWMH_BugOpts */
3681 else if (StrEquals(opt
, "DisplayNewWindowNames"))
3686 Scr
.bo
.do_display_new_window_names
^= 1;
3690 Scr
.bo
.do_display_new_window_names
= toggle
;
3693 Scr
.bo
.do_display_new_window_names
= 0;
3697 else if (StrEquals(opt
, "ExplainWindowPlacement"))
3702 Scr
.bo
.do_explain_window_placement
^= 1;
3706 Scr
.bo
.do_explain_window_placement
= toggle
;
3709 Scr
.bo
.do_explain_window_placement
= 0;
3713 else if (StrEquals(opt
, "DebugCRMotionMethod"))
3718 Scr
.bo
.do_debug_cr_motion_method
^= 1;
3722 Scr
.bo
.do_debug_cr_motion_method
= toggle
;
3725 Scr
.bo
.do_debug_cr_motion_method
= 0;
3729 else if (StrEquals(opt
, "TransliterateUtf8"))
3731 FiconvSetTransliterateUtf8(toggle
);
3735 fvwm_msg(ERR
, "SetBugOptions",
3736 "Unknown Bug Option '%s'", opt
);
3743 void CMD_Emulate(F_CMD_ARGS
)
3747 style
= PeekToken(action
, NULL
);
3748 if (!style
|| StrEquals(style
, "fvwm"))
3750 Scr
.gs
.do_emulate_mwm
= False
;
3751 Scr
.gs
.do_emulate_win
= False
;
3753 else if (StrEquals(style
, "mwm"))
3755 Scr
.gs
.do_emulate_mwm
= True
;
3756 Scr
.gs
.do_emulate_win
= False
;
3758 else if (StrEquals(style
, "win"))
3760 Scr
.gs
.do_emulate_mwm
= False
;
3761 Scr
.gs
.do_emulate_win
= True
;
3765 fvwm_msg(ERR
, "Emulate", "Unknown style '%s'", style
);
3768 Scr
.flags
.do_need_window_update
= 1;
3769 Scr
.flags
.has_default_font_changed
= 1;
3770 Scr
.flags
.has_default_color_changed
= 1;
3775 void CMD_ColorLimit(F_CMD_ARGS
)
3778 WARN
, "ColorLimit", "ColorLimit is obsolete,\n\tuse the "
3779 "fvwm -color-limit option");
3785 /* set animation parameters */
3786 void CMD_SetAnimation(F_CMD_ARGS
)
3793 opt
= PeekToken(action
, &action
);
3794 if (!opt
|| sscanf(opt
,"%d",&delay
) != 1)
3796 fvwm_msg(ERR
,"SetAnimation",
3797 "Improper milli-second delay as first argument");
3802 fvwm_msg(WARN
,"SetAnimation",
3803 "Using longer than .5 seconds as between frame"
3804 " animation delay");
3806 cmsDelayDefault
= delay
;
3807 for (opt
= PeekToken(action
, &action
); opt
;
3808 opt
= PeekToken(action
, &action
))
3810 if (sscanf(opt
,"%f",&pct
) != 1)
3812 fvwm_msg(ERR
,"SetAnimation",
3813 "Use fractional values ending in 1.0 as args"
3817 rgpctMovementDefault
[i
++] = pct
;
3819 /* No pct entries means don't change them at all */
3820 if (i
> 0 && rgpctMovementDefault
[i
-1] != 1.0)
3822 rgpctMovementDefault
[i
++] = 1.0;
3828 /* Determine which modifiers are required with a keycode to make <keysym>. */
3829 static Bool
FKeysymToKeycode (Display
*dpy
, KeySym keysym
,
3830 unsigned int *keycode
, unsigned int *modifiers
)
3834 *keycode
= XKeysymToKeycode(dpy
, keysym
);
3837 for (m
= 0; m
<= 8; ++m
)
3839 KeySym ks
= XKeycodeToKeysym(dpy
, *keycode
, m
);
3844 case 0: /* No modifiers */
3846 case 1: /* Shift modifier */
3847 *modifiers
|= ShiftMask
;
3850 fvwm_msg(ERR
, "FKeysymToKeycode",
3851 "Unhandled modifier %d", m
);
3860 static void __fake_event(F_CMD_ARGS
, FakeEventType type
)
3871 unsigned int mask
= 0;
3872 Window root
= Scr
.Root
;
3874 static char args
[128];
3875 strncpy(args
, action
, sizeof(args
) - 1);
3877 /* get the mask of pressed/released buttons/keys */
3879 dpy
, Scr
.Root
, &root
, &JunkRoot
, &JunkX
, &JunkY
, &JunkX
,
3882 token
= PeekToken(action
, &action
);
3883 while (token
&& action
)
3885 int index
= GetTokenIndex(token
, optlist
, 0, NULL
);
3896 KeySym keysym
= NoSymbol
;
3908 /* key/button press or release */
3909 if (type
== FakeMouseEvent
)
3911 if ((GetIntegerArguments(
3912 action
, &action
, &val
, 1) != 1) ||
3914 val
> NUMBER_OF_EXTENDED_MOUSE_BUTTONS
)
3917 ERR
, "__fake_event",
3918 "Invalid button specifier in"
3919 " \"%s\" for FakeClick.", args
);
3923 else /* type == FakeKeyEvent */
3925 char *key
= PeekToken(action
, &action
);
3929 ERR
, "__fake_event",
3930 "No keysym specifier in \"%s\""
3931 " for FakeKeypress.", args
);
3935 /* Do *NOT* use FvwmStringToKeysym() as it is
3936 * case insensitive. */
3937 keysym
= XStringToKeysym(key
);
3938 if (keysym
== NoSymbol
)
3941 ERR
, "__fake_event",
3942 "Invalid keysym specifier (%s)"
3943 " in \"%s\" for FakeKeypress.",
3952 depth
!= maxdepth
&&
3953 w
!= child_w
&& child_w
!= None
;
3958 dpy
, w
, &root
, &child_w
,
3960 &JunkMask
) == False
)
3962 /* pointer is on a different
3963 * screen - that's okay here */
3967 if (type
== FakeMouseEvent
)
3969 e
.type
= (do_unset
) ?
3970 ButtonRelease
: ButtonPress
;
3971 e
.xbutton
.display
= dpy
;
3972 e
.xbutton
.window
= w
;
3973 e
.xbutton
.subwindow
= None
;
3974 e
.xbutton
.root
= root
;
3975 e
.xbutton
.time
= fev_get_evtime();
3978 e
.xbutton
.x_root
= rx
;
3979 e
.xbutton
.y_root
= ry
;
3980 e
.xbutton
.button
= val
;
3981 e
.xbutton
.state
= mask
;
3982 e
.xbutton
.same_screen
= (Scr
.Root
== root
);
3983 /* SS: I think this mask handling code is
3985 * The value of <mask> is overridden during a
3986 * "wait" operation. Also why are we only using
3987 * Button1Mask? What if the user has requested
3988 * a FakeClick using some other button? */
3989 /* DV: Button1Mask is actually a bit. Shifting
3990 * it by (val -1) bits to the left gives
3991 * Button2Mask, Button3Mask etc. */
3994 mask
&= ~(Button1Mask
<< (val
- 1));
3998 mask
|= (Button1Mask
<< (val
- 1));
4000 add_mask
= (do_unset
) ?
4001 ButtonPressMask
: ButtonReleaseMask
;
4005 /* type == FakeKeyEvent */
4006 e
.type
= (do_unset
? KeyRelease
: KeyPress
);
4007 e
.xkey
.display
= dpy
;
4008 e
.xkey
.subwindow
= None
;
4010 e
.xkey
.time
= fev_get_evtime();
4015 e
.xkey
.same_screen
= (Scr
.Root
== root
);
4017 w
= e
.xkey
.window
= exc
->w
.w
;
4019 if (FKeysymToKeycode(
4020 dpy
, keysym
, &(e
.xkey
.keycode
),
4021 &(e
.xkey
.state
)) != True
)
4023 fvwm_msg(DBG
, "__fake_event",
4024 "FKeysymToKeycode failed");
4027 e
.xkey
.state
|= mask
;
4028 add_mask
= (do_unset
) ?
4029 KeyReleaseMask
: KeyPressMask
;
4031 FSendEvent(dpy
, w
, True
,
4032 SubstructureNotifyMask
| add_mask
, &e
);
4038 if ((GetIntegerArguments(
4039 action
, &action
, &val
, 1) != 1) ||
4040 val
<= 0 || val
> 1000000)
4042 fvwm_msg(ERR
, "__fake_event",
4043 "Invalid wait value in \"%s\"", args
);
4049 dpy
, Scr
.Root
, &root
, &JunkRoot
,
4050 &JunkX
, &JunkY
, &JunkX
, &JunkY
,
4053 /* pointer is on a different screen -
4054 * that's okay here */
4060 if (GetIntegerArguments(action
, &action
, &val
, 1) != 1)
4063 ERR
, "__fake_event",
4064 "Invalid modifier value in \"%s\"",
4086 else if (val
>=1 && val
<= 5)
4088 val
= (Mod1Mask
<< (val
- 1));
4095 /* SS: Could be buggy if a "modifier" operation
4096 * preceeds a "wait" operation. */
4109 if (GetIntegerArguments(action
, &action
, &val
, 1) != 1)
4111 fvwm_msg(ERR
, "__fake_event",
4112 "Invalid depth value in \"%s\"", args
);
4118 fvwm_msg(ERR
, "__fake_event",
4119 "Invalid command (%s) in \"%s\"", token
, args
);
4124 token
= PeekToken(action
, &action
);
4131 void CMD_FakeClick(F_CMD_ARGS
)
4133 __fake_event(F_PASS_ARGS
, FakeMouseEvent
);
4138 void CMD_FakeKeypress(F_CMD_ARGS
)
4140 __fake_event(F_PASS_ARGS
, FakeKeyEvent
);
4145 /* A function to handle stroke (olicha Nov 11, 1999) */
4147 void CMD_StrokeFunc(F_CMD_ARGS
)
4151 int modifiers
= exc
->x
.etrigger
->xbutton
.state
;
4152 int start_event_type
= exc
->x
.etrigger
->type
;
4153 char sequence
[STROKE_MAX_SEQUENCE
+ 1];
4154 char *stroke_action
, *name
;
4156 Bool finish_on_release
= True
;
4158 Bool restore_repeat
= False
;
4159 Bool echo_sequence
= False
;
4160 Bool draw_motion
= False
;
4164 const int STROKE_CHUNK_SIZE
= 0xff;
4165 int coords_size
= STROKE_CHUNK_SIZE
;
4166 Window JunkRoot
, JunkChild
;
4169 unsigned int JunkMask
;
4170 Bool feed_back
= False
;
4171 int stroke_width
= 1;
4177 if (!GrabEm(CRS_STROKE
, GRAB_NORMAL
))
4182 x
= (int*)safemalloc(coords_size
* sizeof(int));
4183 y
= (int*)safemalloc(coords_size
* sizeof(int));
4184 e
= *exc
->x
.etrigger
;
4185 /* set the default option */
4186 if (e
.type
== KeyPress
|| e
.type
== ButtonPress
)
4188 finish_on_release
= True
;
4192 finish_on_release
= False
;
4195 /* parse the option */
4196 for (action
= GetNextSimpleOption(action
, &opt
); opt
;
4197 action
= GetNextSimpleOption(action
, &opt
))
4199 if (StrEquals("NotStayPressed",opt
))
4201 finish_on_release
= False
;
4203 else if (StrEquals("EchoSequence",opt
))
4205 echo_sequence
= True
;
4207 else if (StrEquals("DrawMotion",opt
))
4211 else if (StrEquals("FeedBack",opt
))
4215 else if (StrEquals("StrokeWidth",opt
))
4217 /* stroke width takes a positive integer argument */
4222 action
= GetNextToken(action
, &opt
);
4226 WARN
, "StrokeWidth",
4227 "needs an integer argument");
4229 /* we allow stroke_width == 0 which means drawing a
4230 * `fast' line of width 1; the upper level of 100 is
4232 else if (!sscanf(opt
, "%d", &stroke_width
) ||
4233 stroke_width
< 0 || stroke_width
> 100)
4236 WARN
, "StrokeWidth",
4237 "Bad integer argument %d",
4244 fvwm_msg(WARN
,"StrokeFunc","Unknown option %s", opt
);
4256 /* Force auto repeat off and grab the Keyboard to get proper
4257 * KeyRelease events if we need it.
4258 * Some computers do not support KeyRelease events, can we
4259 * check this here ? No ? */
4260 if (start_event_type
== KeyPress
&& finish_on_release
)
4262 XKeyboardState kstate
;
4264 XGetKeyboardControl(dpy
, &kstate
);
4265 if (kstate
.global_auto_repeat
== AutoRepeatModeOn
)
4267 XAutoRepeatOff(dpy
);
4268 restore_repeat
= True
;
4270 MyXGrabKeyboard(dpy
);
4273 /* be ready to get a stroke sequence */
4280 dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
, &x
[0], &y
[0],
4281 &JunkX
, &JunkY
, &JunkMask
) == False
)
4283 /* pointer is on a different screen */
4288 dpy
,Scr
.XorGC
,stroke_width
,LineSolid
,CapButt
,JoinMiter
);
4291 while (!finished
&& !abort
)
4293 /* block until there is an event */
4295 dpy
, ButtonPressMask
| ButtonReleaseMask
|
4296 KeyPressMask
| KeyReleaseMask
| ButtonMotionMask
|
4297 PointerMotionMask
, &e
);
4301 if (e
.xmotion
.same_screen
== False
)
4305 if (e
.xany
.window
!= Scr
.Root
)
4308 dpy
, Scr
.Root
, &JunkRoot
,
4309 &JunkChild
, &tmpx
, &tmpy
, &JunkX
,
4310 &JunkY
, &JunkMask
) == False
)
4312 /* pointer is on a different screen */
4322 stroke_record(tmpx
,tmpy
);
4323 if (draw_motion
&& (x
[i
] != tmpx
|| y
[i
] != tmpy
))
4326 if (i
>= coords_size
)
4328 coords_size
+= STROKE_CHUNK_SIZE
;
4329 x
= (int*)saferealloc(
4330 (void *)x
, coords_size
*
4332 y
= (int*)saferealloc(
4333 (void *)y
, coords_size
*
4339 dpy
, Scr
.Root
, Scr
.XorGC
, x
[i
-1],
4340 y
[i
-1], x
[i
], y
[i
]);
4344 if (finish_on_release
&& start_event_type
==
4351 if (finish_on_release
&& start_event_type
== KeyPress
)
4357 keysym
= XLookupKeysym(&e
.xkey
, 0);
4358 /* abort if Escape or Delete is pressed (as in menus.c)
4360 if (keysym
== XK_Escape
|| keysym
== XK_Delete
||
4361 keysym
== XK_KP_Separator
)
4365 /* finish on enter or space (as in menus.c) */
4366 if (keysym
== XK_Return
|| keysym
== XK_KP_Enter
||
4373 if (!finish_on_release
)
4388 dpy
, Scr
.Root
, Scr
.XorGC
, x
[i
-1], y
[i
-1], x
[i
],
4392 XSetLineAttributes(dpy
,Scr
.XorGC
,0,LineSolid
,CapButt
,JoinMiter
);
4393 MyXUngrabServer(dpy
);
4400 if (start_event_type
== KeyPress
&& finish_on_release
)
4402 MyXUngrabKeyboard(dpy
);
4404 UngrabEm(GRAB_NORMAL
);
4410 /* get the stroke sequence */
4411 stroke_trans(sequence
);
4415 char num_seq
[STROKE_MAX_SEQUENCE
+ 1];
4417 for (i
= 0; sequence
[i
] != '\0';i
++)
4419 /* Telephone to numeric pad */
4420 if ('7' <= sequence
[i
] && sequence
[i
] <= '9')
4422 num_seq
[i
] = sequence
[i
]-6;
4424 else if ('1' <= sequence
[i
] && sequence
[i
] <= '3')
4426 num_seq
[i
] = sequence
[i
]+6;
4430 num_seq
[i
] = sequence
[i
];
4433 num_seq
[i
++] = '\0';
4434 fvwm_msg(INFO
, "StrokeFunc", "stroke sequence: %s (N%s)",
4441 if (exc
->w
.fw
== NULL
)
4448 class = &exc
->w
.fw
->class;
4449 name
= exc
->w
.fw
->name
.name
;
4451 /* check for a binding */
4452 stroke_action
= CheckBinding(
4453 Scr
.AllBindings
, sequence
, 0, modifiers
, GetUnusedModifiers(),
4454 exc
->w
.wcontext
, BIND_STROKE
, class, name
);
4456 /* execute the action */
4457 if (stroke_action
!= NULL
)
4459 const exec_context_t
*exc2
;
4460 exec_context_changes_t ecc
;
4462 if (feed_back
&& atoi(sequence
) != 0)
4464 GrabEm(CRS_WAIT
, GRAB_BUSY
);
4466 UngrabEm(GRAB_BUSY
);
4468 ecc
.x
.etrigger
= &e
;
4469 exc2
= exc_clone_context(exc
, &ecc
, ECC_ETRIGGER
);
4470 execute_function(cond_rc
, exc2
, stroke_action
, 0);
4471 exc_destroy_context(exc2
);
4476 #endif /* HAVE_STROKE */
4478 void CMD_State(F_CMD_ARGS
)
4483 FvwmWindow
* const fw
= exc
->w
.fw
;
4485 n
= GetIntegerArguments(action
, &action
, (int *)&state
, 1);
4490 if (state
< 0 || state
> 31)
4492 fvwm_msg(ERR
, "CMD_State", "Illegal state %d\n", state
);
4495 toggle
= ParseToggleArgument(action
, NULL
, -1, 0);
4496 state
= (1 << state
);
4500 TOGGLE_USER_STATES(fw
, state
);
4503 CLEAR_USER_STATES(fw
, state
);
4507 SET_USER_STATES(fw
, state
);