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
);
2463 if (fd
!= STDIN_FILENO
)
2466 if (fvwm_setpgrp() == -1)
2468 fvwm_msg(ERR
, "exec_function", "setpgrp failed (%s)",
2472 if (execl(exec_shell_name
, exec_shell_name
, "-c", cmd
, NULL
) ==
2475 fvwm_msg(ERR
, "exec_function", "execl failed (%s)",
2485 void CMD_Refresh(F_CMD_ARGS
)
2487 refresh_window(Scr
.Root
, True
);
2492 void CMD_RefreshWindow(F_CMD_ARGS
)
2494 FvwmWindow
* const fw
= exc
->w
.fw
;
2497 (exc
->w
.wcontext
== C_ICON
) ?
2498 FW_W_ICON_TITLE(fw
) : FW_W_FRAME(fw
), True
);
2503 void CMD_Wait(F_CMD_ARGS
)
2506 Bool redefine_cursor
= False
;
2509 Window nonewin
= None
;
2510 char *wait_string
, *rest
;
2513 /* try to get a single token */
2514 rest
= GetNextToken(action
, &wait_string
);
2517 while (*rest
&& isspace((unsigned char)*rest
))
2526 /* nope, multiple tokens - try old syntax */
2528 /* strip leading and trailing whitespace */
2530 while (*temp
&& isspace((unsigned char)*temp
))
2534 wait_string
= safestrdup(temp
);
2535 for (i
= strlen(wait_string
) - 1; i
>= 0 &&
2536 isspace(wait_string
[i
]); i
--)
2544 wait_string
= safestrdup("");
2547 is_ungrabbed
= UngrabEm(GRAB_NORMAL
);
2548 while (!done
&& !isTerminated
)
2551 if (BUSY_WAIT
& Scr
.BusyCursor
)
2553 XDefineCursor(dpy
, Scr
.Root
, Scr
.FvwmCursors
[CRS_WAIT
]);
2554 redefine_cursor
= True
;
2556 if (My_XNextEvent(dpy
, &e
))
2560 dpy
, e
.xmap
.window
, FvwmContext
,
2561 (caddr_t
*)&t
) == XCNOENT
)
2566 if (e
.type
== MapNotify
&& e
.xmap
.event
== Scr
.Root
)
2572 if (t
&& matchWildcards(
2573 wait_string
, t
->name
.name
) == True
)
2577 else if (t
&& t
->class.res_class
&&
2580 t
->class.res_class
) == True
)
2584 else if (t
&& t
->class.res_name
&&
2587 t
->class.res_name
) == True
)
2592 else if (e
.type
== KeyPress
)
2594 /* should I be using <t> or <exc->w.fw>?
2601 context
= GetContext(&t
, t
, &e
, &nonewin
);
2604 class = &(t
->class);
2605 name
= t
->name
.name
;
2612 escape
= CheckBinding(
2613 Scr
.AllBindings
, STROKE_ARG(0)
2614 e
.xkey
.keycode
, e
.xkey
.state
,
2615 GetUnusedModifiers(), context
,
2616 BIND_KEYPRESS
, class, name
);
2619 if (!strcasecmp(escape
,"escapefunc"))
2627 if (redefine_cursor
)
2629 XDefineCursor(dpy
, Scr
.Root
, Scr
.FvwmCursors
[CRS_ROOT
]);
2633 GrabEm(CRS_NONE
, GRAB_NORMAL
);
2640 void CMD_Quit(F_CMD_ARGS
)
2642 if (master_pid
!= getpid())
2644 kill(master_pid
, SIGTERM
);
2651 void CMD_QuitScreen(F_CMD_ARGS
)
2658 void CMD_Echo(F_CMD_ARGS
)
2666 len
= strlen(action
);
2669 if (action
[len
-1]=='\n')
2674 fvwm_msg(ECHO
,"Echo",action
);
2679 void CMD_PrintInfo(F_CMD_ARGS
)
2682 char *rest
, *subject
= NULL
;
2684 rest
= GetNextToken(action
, &subject
);
2685 if (!rest
|| GetIntegerArguments(rest
, NULL
, &verbose
, 1) != 1)
2689 if (StrEquals(subject
, "Colors"))
2691 PicturePrintColorInfo(verbose
);
2693 else if (StrEquals(subject
, "Locale"))
2695 FlocalePrintLocaleInfo(dpy
, verbose
);
2697 else if (StrEquals(subject
, "NLS"))
2699 FGettextPrintLocalePath(verbose
);
2701 else if (StrEquals(subject
, "style"))
2703 print_styles(verbose
);
2705 else if (StrEquals(subject
, "ImageCache"))
2707 PicturePrintImageCache(verbose
);
2709 else if (StrEquals(subject
, "Bindings"))
2715 fvwm_msg(ERR
, "PrintInfo",
2716 "Unknown subject '%s'", action
);
2725 void CMD_ColormapFocus(F_CMD_ARGS
)
2727 if (MatchToken(action
,"FollowsFocus"))
2729 Scr
.ColormapFocus
= COLORMAP_FOLLOWS_FOCUS
;
2731 else if (MatchToken(action
,"FollowsMouse"))
2733 Scr
.ColormapFocus
= COLORMAP_FOLLOWS_MOUSE
;
2737 fvwm_msg(ERR
, "SetColormapFocus",
2738 "ColormapFocus requires 1 arg: FollowsFocus or"
2746 void CMD_ClickTime(F_CMD_ARGS
)
2750 if (GetIntegerArguments(action
, NULL
, &val
, 1) != 1)
2752 Scr
.ClickTime
= DEFAULT_CLICKTIME
;
2756 Scr
.ClickTime
= (val
< 0)? 0 : val
;
2759 /* Use a negative value during startup and change sign afterwards. This
2760 * speeds things up quite a bit. */
2763 Scr
.ClickTime
= -Scr
.ClickTime
;
2770 void CMD_ImagePath(F_CMD_ARGS
)
2772 PictureSetImagePath( action
);
2777 void CMD_IconPath(F_CMD_ARGS
)
2779 fvwm_msg(ERR
, "iconPath_function",
2780 "IconPath is deprecated since 2.3.0; use ImagePath instead.");
2781 obsolete_imagepaths( action
);
2786 void CMD_PixmapPath(F_CMD_ARGS
)
2788 fvwm_msg(ERR
, "pixmapPath_function",
2789 "PixmapPath is deprecated since 2.3.0; use ImagePath"
2791 obsolete_imagepaths( action
);
2796 void CMD_LocalePath(F_CMD_ARGS
)
2798 FGettextSetLocalePath( action
);
2803 void CMD_ModulePath(F_CMD_ARGS
)
2805 static int need_to_free
= 0;
2807 setPath( &ModulePath
, action
, need_to_free
);
2813 void CMD_ModuleTimeout(F_CMD_ARGS
)
2817 moduleTimeout
= DEFAULT_MODULE_TIMEOUT
;
2818 if (GetIntegerArguments(action
, NULL
, &timeout
, 1) == 1 && timeout
> 0)
2820 moduleTimeout
= timeout
;
2826 void CMD_HilightColor(F_CMD_ARGS
)
2831 if (Scr
.cur_decor
&& Scr
.cur_decor
!= &Scr
.DefaultDecor
)
2835 "Decors do not support the HilightColor command"
2836 " anymore. Please use"
2837 " 'Style <stylename> HilightFore <forecolor>' and"
2838 " 'Style <stylename> HilightBack <backcolor>' instead."
2839 " Sorry for the inconvenience.");
2843 action
= GetNextToken(action
, &fore
);
2844 GetNextToken(action
, &back
);
2847 action
= safemalloc(strlen(fore
) + strlen(back
) + 29);
2848 sprintf(action
, "* HilightFore %s, HilightBack %s", fore
, back
);
2849 CMD_Style(F_PASS_ARGS
);
2863 void CMD_HilightColorset(F_CMD_ARGS
)
2868 if (Scr
.cur_decor
&& Scr
.cur_decor
!= &Scr
.DefaultDecor
)
2871 ERR
, "SetHiColorset",
2872 "Decors do not support the HilightColorset command "
2873 "anymore. Please use "
2874 "'Style <stylename> HilightColorset <colorset>'"
2875 " instead. Sorry for the inconvenience.");
2881 newaction
= safemalloc(strlen(action
) + 32);
2882 sprintf(newaction
, "* HilightColorset %s", action
);
2884 CMD_Style(F_PASS_ARGS
);
2891 void CMD_TitleStyle(F_CMD_ARGS
)
2893 do_title_style(F_PASS_ARGS
, False
);
2896 } /* SetTitleStyle */
2900 * Appends a titlestyle (veliaa@rpi.edu)
2903 void CMD_AddTitleStyle(F_CMD_ARGS
)
2905 do_title_style(F_PASS_ARGS
, True
);
2910 void CMD_PropertyChange(F_CMD_ARGS
)
2916 unsigned long argument
;
2917 unsigned long data1
;
2918 unsigned long data2
;
2921 token
= PeekToken(action
, &rest
);
2926 ret
= sscanf(token
, "%lu", &argument
);
2933 token
= PeekToken(rest
, &rest
);
2936 ret
= sscanf(token
, "%lu", &data1
);
2944 token
= PeekToken(rest
, &rest
);
2947 ret
= sscanf(token
, "%lu", &data2
);
2954 memset(string
, 0, 256);
2957 ret
= sscanf(rest
, "%255c", &(string
[0]));
2959 BroadcastPropertyChange(argument
, data1
, data2
, string
);
2964 void CMD_DefaultIcon(F_CMD_ARGS
)
2966 if (Scr
.DefaultIcon
)
2968 free(Scr
.DefaultIcon
);
2970 GetNextToken(action
, &Scr
.DefaultIcon
);
2975 void CMD_DefaultColorset(F_CMD_ARGS
)
2979 if (GetIntegerArguments(action
, NULL
, &cset
, 1) != 1)
2983 Scr
.DefaultColorset
= cset
;
2984 if (Scr
.DefaultColorset
< 0)
2986 Scr
.DefaultColorset
= -1;
2988 alloc_colorset(Scr
.DefaultColorset
);
2989 Scr
.flags
.do_need_window_update
= 1;
2990 Scr
.flags
.has_default_color_changed
= 1;
2995 void CMD_DefaultColors(F_CMD_ARGS
)
3000 action
= GetNextToken(action
, &fore
);
3003 action
= GetNextToken(action
, &back
);
3007 back
= safestrdup(DEFAULT_BACK_COLOR
);
3011 fore
= safestrdup(DEFAULT_FORE_COLOR
);
3013 if (!StrEquals(fore
, "-"))
3015 PictureFreeColors(dpy
, Pcmap
, &Scr
.StdFore
, 1, 0, True
);
3016 Scr
.StdFore
= GetColor(fore
);
3018 if (!StrEquals(back
, "-"))
3020 PictureFreeColors(dpy
, Pcmap
, &Scr
.StdBack
, 3, 0, True
);
3021 Scr
.StdBack
= GetColor(back
);
3022 Scr
.StdHilite
= GetHilite(Scr
.StdBack
);
3023 Scr
.StdShadow
= GetShadow(Scr
.StdBack
);
3028 Scr
.DefaultColorset
= -1;
3029 Scr
.flags
.do_need_window_update
= 1;
3030 Scr
.flags
.has_default_color_changed
= 1;
3035 void CMD_DefaultFont(F_CMD_ARGS
)
3038 FlocaleFont
*new_font
;
3041 font
= PeekToken(action
, &action
);
3044 /* Try 'fixed', pass NULL font name */
3046 if (!(new_font
= FlocaleLoadFont(dpy
, font
, "fvwm")))
3048 if (Scr
.DefaultFont
== NULL
)
3057 FlocaleUnloadFont(dpy
, Scr
.DefaultFont
);
3058 Scr
.DefaultFont
= new_font
;
3059 /* we should do that here because a redraw can happen before
3060 flush_window_updates is called ... */
3061 for (t
= Scr
.FvwmRoot
.next
; t
!= NULL
; t
= t
->next
)
3063 if (USING_DEFAULT_ICON_FONT(t
))
3065 t
->icon_font
= Scr
.DefaultFont
;
3067 if (USING_DEFAULT_WINDOW_FONT(t
))
3069 t
->title_font
= Scr
.DefaultFont
;
3072 /* set flags to indicate that the font has changed */
3073 Scr
.flags
.do_need_window_update
= 1;
3074 Scr
.flags
.has_default_font_changed
= 1;
3079 void CMD_IconFont(F_CMD_ARGS
)
3084 if (Scr
.cur_decor
&& Scr
.cur_decor
!= &Scr
.DefaultDecor
)
3087 ERR
, "LoadIconFont",
3088 "Decors do not support the IconFont command anymore."
3089 " Please use 'Style <stylename> IconFont <fontname>'"
3090 " instead. Sorry for the inconvenience.");
3096 newaction
= safemalloc(strlen(action
) + 16);
3097 sprintf(newaction
, "* IconFont %s", action
);
3099 CMD_Style(F_PASS_ARGS
);
3106 void CMD_WindowFont(F_CMD_ARGS
)
3111 if (Scr
.cur_decor
&& Scr
.cur_decor
!= &Scr
.DefaultDecor
)
3114 ERR
, "LoadWindowFont",
3115 "Decors do not support the WindowFont command anymore."
3116 " Please use 'Style <stylename> Font <fontname>'"
3117 " instead. Sorry for the inconvenience.");
3123 newaction
= safemalloc(strlen(action
) + 16);
3124 sprintf(newaction
, "* Font %s", action
);
3126 CMD_Style(F_PASS_ARGS
);
3135 * Changes the window's FvwmDecor pointer (veliaa@rpi.edu)
3138 void CMD_ChangeDecor(F_CMD_ARGS
)
3142 FvwmDecor
*decor
= &Scr
.DefaultDecor
;
3143 FvwmDecor
*found
= NULL
;
3144 FvwmWindow
* const fw
= exc
->w
.fw
;
3146 item
= PeekToken(action
, &action
);
3147 if (!action
|| !item
)
3151 /* search for tag */
3152 for (; decor
; decor
= decor
->next
)
3154 if (decor
->tag
&& StrEquals(item
, decor
->tag
))
3165 SET_DECOR_CHANGED(fw
, 1);
3166 old_height
= (fw
->decor
) ? fw
->decor
->title_height
: 0;
3168 apply_decor_change(fw
);
3175 * Destroys an FvwmDecor (veliaa@rpi.edu)
3178 void CMD_DestroyDecor(F_CMD_ARGS
)
3181 FvwmDecor
*decor
= Scr
.DefaultDecor
.next
;
3182 FvwmDecor
*prev
= &Scr
.DefaultDecor
, *found
= NULL
;
3183 Bool do_recreate
= False
;
3185 item
= PeekToken(action
, &action
);
3190 if (StrEquals(item
, "recreate"))
3193 item
= PeekToken(action
, NULL
);
3200 /* search for tag */
3201 for (; decor
; decor
= decor
->next
)
3203 if (decor
->tag
&& StrEquals(item
, decor
->tag
))
3211 if (found
&& (found
!= &Scr
.DefaultDecor
|| do_recreate
))
3215 __remove_window_decors(F_PASS_ARGS
, found
);
3217 DestroyFvwmDecor(found
);
3222 InitFvwmDecor(found
);
3223 found
->tag
= safestrdup(item
);
3224 Scr
.flags
.do_need_window_update
= 1;
3225 found
->flags
.has_changed
= 1;
3226 found
->flags
.has_title_height_changed
= 0;
3227 found
->titlebar
.flags
.has_changed
= 1;
3228 for (i
= 0; i
< NUMBER_OF_TITLE_BUTTONS
; ++i
)
3230 TB_FLAGS(found
->buttons
[i
]).has_changed
= 1;
3235 prev
->next
= found
->next
;
3245 * Initiates an AddToDecor (veliaa@rpi.edu)
3248 void CMD_AddToDecor(F_CMD_ARGS
)
3251 FvwmDecor
*found
= NULL
;
3254 action
= GetNextToken(action
, &item
);
3264 /* search for tag */
3265 for (decor
= &Scr
.DefaultDecor
; decor
; decor
= decor
->next
)
3267 if (decor
->tag
&& StrEquals(item
, decor
->tag
))
3275 /* then make a new one */
3276 found
= (FvwmDecor
*)safemalloc(sizeof( FvwmDecor
));
3277 InitFvwmDecor(found
);
3278 found
->tag
= item
; /* tag it */
3279 /* add it to list */
3280 for (decor
= &Scr
.DefaultDecor
; decor
->next
;
3281 decor
= decor
->next
)
3285 decor
->next
= found
;
3294 AddToDecor(F_PASS_ARGS
, found
);
3295 /* Set + state to last decor */
3296 set_last_added_item(ADDED_DECOR
, found
);
3301 #endif /* USEDECOR */
3306 * Updates window decoration styles (veliaa@rpi.edu)
3309 void CMD_UpdateDecor(F_CMD_ARGS
)
3313 FvwmDecor
*decor
, *found
= NULL
;
3314 FvwmWindow
*hilight
= Scr
.Hilite
;
3317 action
= GetNextToken(action
, &item
);
3320 /* search for tag */
3321 for (decor
= &Scr
.DefaultDecor
; decor
; decor
= decor
->next
)
3323 if (decor
->tag
&& StrEquals(item
, decor
->tag
))
3333 for (fw2
= Scr
.FvwmRoot
.next
; fw2
; fw2
= fw2
->next
)
3336 /* update specific decor, or all */
3339 if (fw2
->decor
== found
)
3341 border_draw_decorations(
3342 fw2
, PART_ALL
, True
, True
, CLEAR_ALL
,
3344 border_draw_decorations(
3345 fw2
, PART_ALL
, False
, True
, CLEAR_ALL
,
3352 border_draw_decorations(
3353 fw2
, PART_ALL
, True
, True
, CLEAR_ALL
, NULL
,
3355 border_draw_decorations(
3356 fw2
, PART_ALL
, False
, True
, CLEAR_ALL
, NULL
,
3360 border_draw_decorations(
3361 hilight
, PART_ALL
, True
, True
, CLEAR_ALL
, NULL
, NULL
);
3364 void CMD_ButtonStyle(F_CMD_ARGS
)
3366 do_button_style(F_PASS_ARGS
, False
);
3373 * Appends a button decoration style (veliaa@rpi.edu)
3376 void CMD_AddButtonStyle(F_CMD_ARGS
)
3378 do_button_style(F_PASS_ARGS
, True
);
3383 void CMD_SetEnv(F_CMD_ARGS
)
3386 char *szValue
= NULL
;
3387 char *szPutenv
= NULL
;
3389 action
= GetNextToken(action
, &szVar
);
3394 action
= GetNextToken(action
, &szValue
);
3397 szValue
= safestrdup("");
3399 szPutenv
= safemalloc(strlen(szVar
) + strlen(szValue
) + 2);
3400 sprintf(szPutenv
,"%s=%s", szVar
, szValue
);
3401 flib_putenv(szVar
, szPutenv
);
3409 void CMD_UnsetEnv(F_CMD_ARGS
)
3413 szVar
= PeekToken(action
, &action
);
3418 flib_unsetenv(szVar
);
3423 void CMD_GlobalOpts(F_CMD_ARGS
)
3431 "WindowShadeShrinks",
3432 "WindowShadeScrolls",
3433 "SmartPlacementIsReallySmart",
3434 "SmartPlacementIsNormal",
3435 "ClickToFocusDoesntPassClick",
3436 "ClickToFocusPassesClick",
3437 "ClickToFocusDoesntRaise",
3438 "ClickToFocusRaises",
3439 "MouseFocusClickDoesntRaise",
3440 "MouseFocusClickRaises",
3443 "CaptureHonorsStartsOnPage",
3444 "CaptureIgnoresStartsOnPage",
3445 "RecaptureHonorsStartsOnPage",
3446 "RecaptureIgnoresStartsOnPage",
3447 "ActivePlacementHonorsStartsOnPage",
3448 "ActivePlacementIgnoresStartsOnPage",
3449 "RaiseOverNativeWindows",
3450 "IgnoreNativeWindows",
3453 char *replacelist
[] = {
3454 /* These options are mapped to the Style * command */
3455 NULL
, /* NULL means to use "Style * <optionname>" */
3457 "* MinOverlapPlacement",
3458 "* TileCascadePlacement",
3459 "* ClickToFocusPassesClickOff",
3460 "* ClickToFocusPassesClick",
3461 "* ClickToFocusRaisesOff",
3462 "* ClickToFocusRaises",
3463 "* MouseFocusClickRaisesOff",
3464 "* MouseFocusClickRaises",
3465 "* StippledTitleOff",
3471 "* ManualPlacementHonorsStartsOnPage",
3472 "* ManualPlacementIgnoresStartsOnPage",
3473 /* These options are mapped to the BugOpts command */
3474 "RaiseOverNativeWindows on",
3475 "RaiseOverNativeWindows off"
3478 fvwm_msg(ERR
, "SetGlobalOptions",
3479 "The GlobalOpts command is obsolete.");
3480 for (action
= GetNextSimpleOption(action
, &opt
); opt
;
3481 action
= GetNextSimpleOption(action
, &opt
))
3486 i
= GetTokenIndex(opt
, optlist
, 0, NULL
);
3492 replace
= replacelist
[i
];
3493 if (replace
== NULL
)
3495 replace
= &(buf
[0]);
3496 sprintf(buf
, "* %s", opt
);
3498 else if (*replace
!= '*')
3506 CMD_Style(F_PASS_ARGS
);
3511 CMD_BugOpts(F_PASS_ARGS
);
3516 ERR
, "SetGlobalOptions",
3517 "Please replace 'GlobalOpts %s' with '%s %s'.",
3522 fvwm_msg(ERR
, "SetGlobalOptions",
3523 "Unknown Global Option '%s'", opt
);
3525 /* should never be null, but checking anyways... */
3539 void CMD_BugOpts(F_CMD_ARGS
)
3545 /* fvwm_msg(DBG,"SetGlobalOptions","init action == '%s'\n",action); */
3546 while (action
&& *action
&& *action
!= '\n')
3548 action
= GetNextFullOption(action
, &optstring
);
3551 /* no more options */
3554 toggle
= ParseToggleArgument(
3555 SkipNTokens(optstring
,1), NULL
, 2, False
);
3556 opt
= PeekToken(optstring
, NULL
);
3563 /* toggle = ParseToggleArgument(rest, &rest, 2, False);*/
3565 if (StrEquals(opt
, "FlickeringMoveWorkaround"))
3570 Scr
.bo
.do_disable_configure_notify
^= 1;
3574 Scr
.bo
.do_disable_configure_notify
= toggle
;
3577 Scr
.bo
.do_disable_configure_notify
= 0;
3581 else if (StrEquals(opt
, "MixedVisualWorkaround"))
3586 Scr
.bo
.do_install_root_cmap
^= 1;
3590 Scr
.bo
.do_install_root_cmap
= toggle
;
3593 Scr
.bo
.do_install_root_cmap
= 0;
3597 else if (StrEquals(opt
, "ModalityIsEvil"))
3602 Scr
.bo
.is_modality_evil
^= 1;
3606 Scr
.bo
.is_modality_evil
= toggle
;
3609 Scr
.bo
.is_modality_evil
= 0;
3612 if (Scr
.bo
.is_modality_evil
)
3614 SetMWM_INFO(Scr
.NoFocusWin
);
3617 else if (StrEquals(opt
, "RaiseOverNativeWindows"))
3622 Scr
.bo
.is_raise_hack_needed
^= 1;
3626 Scr
.bo
.is_raise_hack_needed
= toggle
;
3629 Scr
.bo
.is_raise_hack_needed
= 0;
3633 else if (StrEquals(opt
, "RaiseOverUnmanaged"))
3638 Scr
.bo
.do_raise_over_unmanaged
^= 1;
3642 Scr
.bo
.do_raise_over_unmanaged
= toggle
;
3645 Scr
.bo
.do_raise_over_unmanaged
= 0;
3649 else if (StrEquals(opt
, "FlickeringQtDialogsWorkaround"))
3654 Scr
.bo
.do_enable_flickering_qt_dialogs_workaround
^= 1;
3658 Scr
.bo
.do_enable_flickering_qt_dialogs_workaround
= toggle
;
3661 Scr
.bo
.do_enable_flickering_qt_dialogs_workaround
= 0;
3665 else if (StrEquals(opt
, "QtDragnDropWorkaround") )
3670 Scr
.bo
.do_enable_qt_drag_n_drop_workaround
^= 1;
3674 Scr
.bo
.do_enable_qt_drag_n_drop_workaround
= toggle
;
3677 Scr
.bo
.do_enable_qt_drag_n_drop_workaround
= 0;
3681 else if (EWMH_BugOpts(opt
, toggle
))
3683 /* work is done in EWMH_BugOpts */
3685 else if (StrEquals(opt
, "DisplayNewWindowNames"))
3690 Scr
.bo
.do_display_new_window_names
^= 1;
3694 Scr
.bo
.do_display_new_window_names
= toggle
;
3697 Scr
.bo
.do_display_new_window_names
= 0;
3701 else if (StrEquals(opt
, "ExplainWindowPlacement"))
3706 Scr
.bo
.do_explain_window_placement
^= 1;
3710 Scr
.bo
.do_explain_window_placement
= toggle
;
3713 Scr
.bo
.do_explain_window_placement
= 0;
3717 else if (StrEquals(opt
, "DebugCRMotionMethod"))
3722 Scr
.bo
.do_debug_cr_motion_method
^= 1;
3726 Scr
.bo
.do_debug_cr_motion_method
= toggle
;
3729 Scr
.bo
.do_debug_cr_motion_method
= 0;
3733 else if (StrEquals(opt
, "TransliterateUtf8"))
3735 FiconvSetTransliterateUtf8(toggle
);
3739 fvwm_msg(ERR
, "SetBugOptions",
3740 "Unknown Bug Option '%s'", opt
);
3747 void CMD_Emulate(F_CMD_ARGS
)
3751 style
= PeekToken(action
, NULL
);
3752 if (!style
|| StrEquals(style
, "fvwm"))
3754 Scr
.gs
.do_emulate_mwm
= False
;
3755 Scr
.gs
.do_emulate_win
= False
;
3757 else if (StrEquals(style
, "mwm"))
3759 Scr
.gs
.do_emulate_mwm
= True
;
3760 Scr
.gs
.do_emulate_win
= False
;
3762 else if (StrEquals(style
, "win"))
3764 Scr
.gs
.do_emulate_mwm
= False
;
3765 Scr
.gs
.do_emulate_win
= True
;
3769 fvwm_msg(ERR
, "Emulate", "Unknown style '%s'", style
);
3772 Scr
.flags
.do_need_window_update
= 1;
3773 Scr
.flags
.has_default_font_changed
= 1;
3774 Scr
.flags
.has_default_color_changed
= 1;
3779 void CMD_ColorLimit(F_CMD_ARGS
)
3782 WARN
, "ColorLimit", "ColorLimit is obsolete,\n\tuse the "
3783 "fvwm -color-limit option");
3789 /* set animation parameters */
3790 void CMD_SetAnimation(F_CMD_ARGS
)
3797 opt
= PeekToken(action
, &action
);
3798 if (!opt
|| sscanf(opt
,"%d",&delay
) != 1)
3800 fvwm_msg(ERR
,"SetAnimation",
3801 "Improper milli-second delay as first argument");
3806 fvwm_msg(WARN
,"SetAnimation",
3807 "Using longer than .5 seconds as between frame"
3808 " animation delay");
3810 cmsDelayDefault
= delay
;
3811 for (opt
= PeekToken(action
, &action
); opt
;
3812 opt
= PeekToken(action
, &action
))
3814 if (sscanf(opt
,"%f",&pct
) != 1)
3816 fvwm_msg(ERR
,"SetAnimation",
3817 "Use fractional values ending in 1.0 as args"
3821 rgpctMovementDefault
[i
++] = pct
;
3823 /* No pct entries means don't change them at all */
3824 if (i
> 0 && rgpctMovementDefault
[i
-1] != 1.0)
3826 rgpctMovementDefault
[i
++] = 1.0;
3832 /* Determine which modifiers are required with a keycode to make <keysym>. */
3833 static Bool
FKeysymToKeycode (Display
*dpy
, KeySym keysym
,
3834 unsigned int *keycode
, unsigned int *modifiers
)
3838 *keycode
= XKeysymToKeycode(dpy
, keysym
);
3841 for (m
= 0; m
<= 8; ++m
)
3843 KeySym ks
= XKeycodeToKeysym(dpy
, *keycode
, m
);
3848 case 0: /* No modifiers */
3850 case 1: /* Shift modifier */
3851 *modifiers
|= ShiftMask
;
3854 fvwm_msg(ERR
, "FKeysymToKeycode",
3855 "Unhandled modifier %d", m
);
3864 static void __fake_event(F_CMD_ARGS
, FakeEventType type
)
3875 unsigned int mask
= 0;
3876 Window root
= Scr
.Root
;
3878 static char args
[128];
3879 strncpy(args
, action
, sizeof(args
) - 1);
3881 /* get the mask of pressed/released buttons/keys */
3883 dpy
, Scr
.Root
, &root
, &JunkRoot
, &JunkX
, &JunkY
, &JunkX
,
3886 token
= PeekToken(action
, &action
);
3887 while (token
&& action
)
3889 int index
= GetTokenIndex(token
, optlist
, 0, NULL
);
3900 KeySym keysym
= NoSymbol
;
3912 /* key/button press or release */
3913 if (type
== FakeMouseEvent
)
3915 if ((GetIntegerArguments(
3916 action
, &action
, &val
, 1) != 1) ||
3918 val
> NUMBER_OF_EXTENDED_MOUSE_BUTTONS
)
3921 ERR
, "__fake_event",
3922 "Invalid button specifier in"
3923 " \"%s\" for FakeClick.", args
);
3927 else /* type == FakeKeyEvent */
3929 char *key
= PeekToken(action
, &action
);
3933 ERR
, "__fake_event",
3934 "No keysym specifier in \"%s\""
3935 " for FakeKeypress.", args
);
3939 /* Do *NOT* use FvwmStringToKeysym() as it is
3940 * case insensitive. */
3941 keysym
= XStringToKeysym(key
);
3942 if (keysym
== NoSymbol
)
3945 ERR
, "__fake_event",
3946 "Invalid keysym specifier (%s)"
3947 " in \"%s\" for FakeKeypress.",
3956 depth
!= maxdepth
&&
3957 w
!= child_w
&& child_w
!= None
;
3962 dpy
, w
, &root
, &child_w
,
3964 &JunkMask
) == False
)
3966 /* pointer is on a different
3967 * screen - that's okay here */
3971 if (type
== FakeMouseEvent
)
3973 e
.type
= (do_unset
) ?
3974 ButtonRelease
: ButtonPress
;
3975 e
.xbutton
.display
= dpy
;
3976 e
.xbutton
.window
= w
;
3977 e
.xbutton
.subwindow
= None
;
3978 e
.xbutton
.root
= root
;
3979 e
.xbutton
.time
= fev_get_evtime();
3982 e
.xbutton
.x_root
= rx
;
3983 e
.xbutton
.y_root
= ry
;
3984 e
.xbutton
.button
= val
;
3985 e
.xbutton
.state
= mask
;
3986 e
.xbutton
.same_screen
= (Scr
.Root
== root
);
3987 /* SS: I think this mask handling code is
3989 * The value of <mask> is overridden during a
3990 * "wait" operation. Also why are we only using
3991 * Button1Mask? What if the user has requested
3992 * a FakeClick using some other button? */
3993 /* DV: Button1Mask is actually a bit. Shifting
3994 * it by (val -1) bits to the left gives
3995 * Button2Mask, Button3Mask etc. */
3998 mask
&= ~(Button1Mask
<< (val
- 1));
4002 mask
|= (Button1Mask
<< (val
- 1));
4004 add_mask
= (do_unset
) ?
4005 ButtonPressMask
: ButtonReleaseMask
;
4009 /* type == FakeKeyEvent */
4010 e
.type
= (do_unset
? KeyRelease
: KeyPress
);
4011 e
.xkey
.display
= dpy
;
4012 e
.xkey
.subwindow
= None
;
4014 e
.xkey
.time
= fev_get_evtime();
4019 e
.xkey
.same_screen
= (Scr
.Root
== root
);
4021 w
= e
.xkey
.window
= exc
->w
.w
;
4023 if (FKeysymToKeycode(
4024 dpy
, keysym
, &(e
.xkey
.keycode
),
4025 &(e
.xkey
.state
)) != True
)
4027 fvwm_msg(DBG
, "__fake_event",
4028 "FKeysymToKeycode failed");
4031 e
.xkey
.state
|= mask
;
4032 add_mask
= (do_unset
) ?
4033 KeyReleaseMask
: KeyPressMask
;
4035 FSendEvent(dpy
, w
, True
,
4036 SubstructureNotifyMask
| add_mask
, &e
);
4042 if ((GetIntegerArguments(
4043 action
, &action
, &val
, 1) != 1) ||
4044 val
<= 0 || val
> 1000000)
4046 fvwm_msg(ERR
, "__fake_event",
4047 "Invalid wait value in \"%s\"", args
);
4053 dpy
, Scr
.Root
, &root
, &JunkRoot
,
4054 &JunkX
, &JunkY
, &JunkX
, &JunkY
,
4057 /* pointer is on a different screen -
4058 * that's okay here */
4064 if (GetIntegerArguments(action
, &action
, &val
, 1) != 1)
4067 ERR
, "__fake_event",
4068 "Invalid modifier value in \"%s\"",
4090 else if (val
>=1 && val
<= 5)
4092 val
= (Mod1Mask
<< (val
- 1));
4099 /* SS: Could be buggy if a "modifier" operation
4100 * preceeds a "wait" operation. */
4113 if (GetIntegerArguments(action
, &action
, &val
, 1) != 1)
4115 fvwm_msg(ERR
, "__fake_event",
4116 "Invalid depth value in \"%s\"", args
);
4122 fvwm_msg(ERR
, "__fake_event",
4123 "Invalid command (%s) in \"%s\"", token
, args
);
4128 token
= PeekToken(action
, &action
);
4135 void CMD_FakeClick(F_CMD_ARGS
)
4137 __fake_event(F_PASS_ARGS
, FakeMouseEvent
);
4142 void CMD_FakeKeypress(F_CMD_ARGS
)
4144 __fake_event(F_PASS_ARGS
, FakeKeyEvent
);
4149 /* A function to handle stroke (olicha Nov 11, 1999) */
4151 void CMD_StrokeFunc(F_CMD_ARGS
)
4155 int modifiers
= exc
->x
.etrigger
->xbutton
.state
;
4156 int start_event_type
= exc
->x
.etrigger
->type
;
4157 char sequence
[STROKE_MAX_SEQUENCE
+ 1];
4158 char *stroke_action
, *name
;
4160 Bool finish_on_release
= True
;
4162 Bool restore_repeat
= False
;
4163 Bool echo_sequence
= False
;
4164 Bool draw_motion
= False
;
4168 const int STROKE_CHUNK_SIZE
= 0xff;
4169 int coords_size
= STROKE_CHUNK_SIZE
;
4170 Window JunkRoot
, JunkChild
;
4173 unsigned int JunkMask
;
4174 Bool feed_back
= False
;
4175 int stroke_width
= 1;
4181 if (!GrabEm(CRS_STROKE
, GRAB_NORMAL
))
4186 x
= (int*)safemalloc(coords_size
* sizeof(int));
4187 y
= (int*)safemalloc(coords_size
* sizeof(int));
4188 e
= *exc
->x
.etrigger
;
4189 /* set the default option */
4190 if (e
.type
== KeyPress
|| e
.type
== ButtonPress
)
4192 finish_on_release
= True
;
4196 finish_on_release
= False
;
4199 /* parse the option */
4200 for (action
= GetNextSimpleOption(action
, &opt
); opt
;
4201 action
= GetNextSimpleOption(action
, &opt
))
4203 if (StrEquals("NotStayPressed",opt
))
4205 finish_on_release
= False
;
4207 else if (StrEquals("EchoSequence",opt
))
4209 echo_sequence
= True
;
4211 else if (StrEquals("DrawMotion",opt
))
4215 else if (StrEquals("FeedBack",opt
))
4219 else if (StrEquals("StrokeWidth",opt
))
4221 /* stroke width takes a positive integer argument */
4226 action
= GetNextToken(action
, &opt
);
4230 WARN
, "StrokeWidth",
4231 "needs an integer argument");
4233 /* we allow stroke_width == 0 which means drawing a
4234 * `fast' line of width 1; the upper level of 100 is
4236 else if (!sscanf(opt
, "%d", &stroke_width
) ||
4237 stroke_width
< 0 || stroke_width
> 100)
4240 WARN
, "StrokeWidth",
4241 "Bad integer argument %d",
4248 fvwm_msg(WARN
,"StrokeFunc","Unknown option %s", opt
);
4260 /* Force auto repeat off and grab the Keyboard to get proper
4261 * KeyRelease events if we need it.
4262 * Some computers do not support KeyRelease events, can we
4263 * check this here ? No ? */
4264 if (start_event_type
== KeyPress
&& finish_on_release
)
4266 XKeyboardState kstate
;
4268 XGetKeyboardControl(dpy
, &kstate
);
4269 if (kstate
.global_auto_repeat
== AutoRepeatModeOn
)
4271 XAutoRepeatOff(dpy
);
4272 restore_repeat
= True
;
4274 MyXGrabKeyboard(dpy
);
4277 /* be ready to get a stroke sequence */
4284 dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
, &x
[0], &y
[0],
4285 &JunkX
, &JunkY
, &JunkMask
) == False
)
4287 /* pointer is on a different screen */
4292 dpy
,Scr
.XorGC
,stroke_width
,LineSolid
,CapButt
,JoinMiter
);
4295 while (!finished
&& !abort
)
4297 /* block until there is an event */
4299 dpy
, ButtonPressMask
| ButtonReleaseMask
|
4300 KeyPressMask
| KeyReleaseMask
| ButtonMotionMask
|
4301 PointerMotionMask
, &e
);
4305 if (e
.xmotion
.same_screen
== False
)
4309 if (e
.xany
.window
!= Scr
.Root
)
4312 dpy
, Scr
.Root
, &JunkRoot
,
4313 &JunkChild
, &tmpx
, &tmpy
, &JunkX
,
4314 &JunkY
, &JunkMask
) == False
)
4316 /* pointer is on a different screen */
4326 stroke_record(tmpx
,tmpy
);
4327 if (draw_motion
&& (x
[i
] != tmpx
|| y
[i
] != tmpy
))
4330 if (i
>= coords_size
)
4332 coords_size
+= STROKE_CHUNK_SIZE
;
4333 x
= (int*)saferealloc(
4334 (void *)x
, coords_size
*
4336 y
= (int*)saferealloc(
4337 (void *)y
, coords_size
*
4343 dpy
, Scr
.Root
, Scr
.XorGC
, x
[i
-1],
4344 y
[i
-1], x
[i
], y
[i
]);
4348 if (finish_on_release
&& start_event_type
==
4355 if (finish_on_release
&& start_event_type
== KeyPress
)
4361 keysym
= XLookupKeysym(&e
.xkey
, 0);
4362 /* abort if Escape or Delete is pressed (as in menus.c)
4364 if (keysym
== XK_Escape
|| keysym
== XK_Delete
||
4365 keysym
== XK_KP_Separator
)
4369 /* finish on enter or space (as in menus.c) */
4370 if (keysym
== XK_Return
|| keysym
== XK_KP_Enter
||
4377 if (!finish_on_release
)
4392 dpy
, Scr
.Root
, Scr
.XorGC
, x
[i
-1], y
[i
-1], x
[i
],
4396 XSetLineAttributes(dpy
,Scr
.XorGC
,0,LineSolid
,CapButt
,JoinMiter
);
4397 MyXUngrabServer(dpy
);
4404 if (start_event_type
== KeyPress
&& finish_on_release
)
4406 MyXUngrabKeyboard(dpy
);
4408 UngrabEm(GRAB_NORMAL
);
4414 /* get the stroke sequence */
4415 stroke_trans(sequence
);
4419 char num_seq
[STROKE_MAX_SEQUENCE
+ 1];
4421 for (i
= 0; sequence
[i
] != '\0';i
++)
4423 /* Telephone to numeric pad */
4424 if ('7' <= sequence
[i
] && sequence
[i
] <= '9')
4426 num_seq
[i
] = sequence
[i
]-6;
4428 else if ('1' <= sequence
[i
] && sequence
[i
] <= '3')
4430 num_seq
[i
] = sequence
[i
]+6;
4434 num_seq
[i
] = sequence
[i
];
4437 num_seq
[i
++] = '\0';
4438 fvwm_msg(INFO
, "StrokeFunc", "stroke sequence: %s (N%s)",
4445 if (exc
->w
.fw
== NULL
)
4452 class = &exc
->w
.fw
->class;
4453 name
= exc
->w
.fw
->name
.name
;
4455 /* check for a binding */
4456 stroke_action
= CheckBinding(
4457 Scr
.AllBindings
, sequence
, 0, modifiers
, GetUnusedModifiers(),
4458 exc
->w
.wcontext
, BIND_STROKE
, class, name
);
4460 /* execute the action */
4461 if (stroke_action
!= NULL
)
4463 const exec_context_t
*exc2
;
4464 exec_context_changes_t ecc
;
4466 if (feed_back
&& atoi(sequence
) != 0)
4468 GrabEm(CRS_WAIT
, GRAB_BUSY
);
4470 UngrabEm(GRAB_BUSY
);
4472 ecc
.x
.etrigger
= &e
;
4473 exc2
= exc_clone_context(exc
, &ecc
, ECC_ETRIGGER
);
4474 execute_function(cond_rc
, exc2
, stroke_action
, 0);
4475 exc_destroy_context(exc2
);
4480 #endif /* HAVE_STROKE */
4482 void CMD_State(F_CMD_ARGS
)
4487 FvwmWindow
* const fw
= exc
->w
.fw
;
4489 n
= GetIntegerArguments(action
, &action
, (int *)&state
, 1);
4494 if (state
< 0 || state
> 31)
4496 fvwm_msg(ERR
, "CMD_State", "Illegal state %d\n", state
);
4499 toggle
= ParseToggleArgument(action
, NULL
, -1, 0);
4500 state
= (1 << state
);
4504 TOGGLE_USER_STATES(fw
, state
);
4507 CLEAR_USER_STATES(fw
, state
);
4511 SET_USER_STATES(fw
, state
);