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
16 /* ---------------------------- included header files ---------------------- */
23 #include "libs/fvwmlib.h"
24 #include "libs/Parse.h"
25 #include "libs/Strings.h"
26 #include "libs/ColorUtils.h"
30 #include "functions.h"
32 #include "move_resize.h"
39 #include "libs/FGettext.h"
40 #include "libs/charmap.h"
41 #include "libs/wcontext.h"
42 #include "libs/Fsvg.h"
44 /* ---------------------------- local definitions -------------------------- */
46 /* ---------------------------- local macros ------------------------------- */
48 /* ---------------------------- imports ------------------------------------ */
50 extern char const * const Fvwm_VersionInfo
;
52 /* ---------------------------- included code files ------------------------ */
54 /* ---------------------------- local types -------------------------------- */
56 /* ---------------------------- forward declarations ----------------------- */
58 /* ---------------------------- local variables ---------------------------- */
60 static char *partial_function_vars
[] =
72 static char *function_vars
[] =
120 "w.iconfile.svgopts",
121 "w.miniiconfile.svgopts",
143 } partial_extended_vars
;
193 VAR_W_ICONFILE_SVGOPTS
,
194 VAR_W_MINIICONFILE_SVGOPTS
,
206 /* ---------------------------- exported variables (globals) --------------- */
208 /* ---------------------------- local functions ---------------------------- */
210 int __eae_parse_range(char *input
, int *lower
, int *upper
)
221 if (!isdigit(*input
))
225 rc
= sscanf(input
, "%d-%d%n", lower
, upper
, &n
);
228 rc
= sscanf(input
, "%d%n", lower
, &n
);
231 /* not a positional argument */
248 /* trailing characters - not good */
253 /* the range is reverse - not good */
260 static signed int expand_args_extended(
261 char *input
, char *argument_string
, char *output
)
269 rc
= __eae_parse_range(input
, &lower
, &upper
);
274 /* Skip to the start of the requested argument range */
277 argument_string
= SkipNTokens(argument_string
, lower
);
279 if (!argument_string
)
281 /* replace with empty string */
284 /* TODO: optimise handling of $[0] to $[9] which have already been
286 for (i
= lower
, len
= 0; i
<= upper
; i
++)
291 token
= PeekToken(argument_string
, &argument_string
);
306 tlen
= strlen(token
);
307 if (output
!= NULL
&& tlen
> 0)
309 memcpy(output
, token
, tlen
);
318 static signed int expand_vars_extended(
319 char *var_name
, char *output
, cond_rc_t
*cond_rc
,
320 const exec_context_t
*exc
)
323 char dummy
[64] = "\0";
324 char *target
= (output
) ? output
: dummy
;
333 const char *string
= NULL
;
334 char *allocated_string
= NULL
;
335 char *quoted_string
= NULL
;
336 Bool should_quote
= False
;
337 Bool is_numeric
= False
;
338 Bool is_target
= False
;
340 Window context_w
= Scr
.Root
;
341 FvwmWindow
*fw
= exc
->w
.fw
;
344 /* allow partial matches for *.cs, gt, ... etc. variables */
345 switch ((i
= GetTokenIndex(var_name
, partial_function_vars
, -1, &rest
)))
352 if (!isdigit(*rest
) || (*rest
== '0' && *(rest
+ 1) != 0))
354 /* not a non-negative integer without leading zeros */
357 if (sscanf(rest
, "%d%n", &cs
, &n
) < 1)
361 if (*(rest
+ n
) != 0)
363 /* trailing characters */
374 pixel
= Colorset
[cs
].fg
;
377 pixel
= Colorset
[cs
].bg
;
380 pixel
= Colorset
[cs
].hilite
;
383 pixel
= Colorset
[cs
].shadow
;
386 pixel
= Colorset
[cs
].fgsh
;
390 len
= pixel_to_color_string(dpy
, Pcmap
, pixel
, target
, False
);
400 if (sscanf(rest
, "%d%n", &cs
, &n
) < 1)
404 if (*(rest
+ n
) != 0)
406 /* trailing characters */
409 string
= GetDesktopName(cs
);
412 const char *ddn
= _("Desk");
413 allocated_string
= (char *)safemalloc(19 + strlen(ddn
));
414 sprintf(allocated_string
, "%s %i", ddn
, cs
);
415 string
= allocated_string
;
422 /* only exact matches for all other variables */
423 switch ((i
= GetTokenIndex(var_name
, function_vars
, 0, &rest
)))
427 val
= Scr
.CurrentDesk
;
431 val
= Scr
.VxMax
+ Scr
.MyDisplayWidth
;
433 case VAR_DESK_HEIGHT
:
435 val
= Scr
.VyMax
+ Scr
.MyDisplayHeight
;
437 case VAR_DESK_PAGESX
:
439 val
= (int)(Scr
.VxMax
/ Scr
.MyDisplayWidth
) + 1;
441 case VAR_DESK_PAGESY
:
443 val
= (int)(Scr
.VyMax
/ Scr
.MyDisplayHeight
) + 1;
455 val
= Scr
.MyDisplayWidth
;
459 val
= Scr
.MyDisplayHeight
;
463 val
= (int)(Scr
.Vx
/ Scr
.MyDisplayWidth
);
467 val
= (int)(Scr
.Vy
/ Scr
.MyDisplayHeight
);
470 if (fw
&& !IS_EWMH_DESKTOP(FW_W(fw
)))
473 sprintf(target
, "0x%x", (int)FW_W(fw
));
477 if (fw
&& !IS_EWMH_DESKTOP(FW_W(fw
)))
479 string
= fw
->name
.name
;
484 if (fw
&& !IS_EWMH_DESKTOP(FW_W(fw
)))
486 string
= fw
->icon_name
.name
;
491 case VAR_W_MINIICONFILE
:
492 if (fw
&& !IS_EWMH_DESKTOP(FW_W(fw
)))
496 t
= (i
== VAR_W_ICONFILE
) ?
497 fw
->icon_bitmap_file
: fw
->mini_pixmap_file
;
498 /* expand the path if possible */
499 allocated_string
= PictureFindImageFile(t
, NULL
, R_OK
);
500 if (allocated_string
== NULL
)
504 else if (USE_SVG
&& *allocated_string
== ':' &&
505 (string
= strchr(allocated_string
+ 1, ':')))
511 string
= allocated_string
;
515 case VAR_W_ICONFILE_SVGOPTS
:
516 case VAR_W_MINIICONFILE_SVGOPTS
:
517 if (fw
&& !IS_EWMH_DESKTOP(FW_W(fw
)))
525 t
= (i
== VAR_W_ICONFILE_SVGOPTS
) ?
526 fw
->icon_bitmap_file
: fw
->mini_pixmap_file
;
527 /* expand the path if possible */
528 allocated_string
= PictureFindImageFile(t
, NULL
, R_OK
);
529 string
= allocated_string
;
530 if (string
&& *string
== ':' &&
531 (t
= strchr(string
+ 1, ':')))
542 if (fw
&& !IS_EWMH_DESKTOP(FW_W(fw
)))
544 string
= fw
->class.res_class
;
549 if (fw
&& !IS_EWMH_DESKTOP(FW_W(fw
)))
551 string
= fw
->class.res_name
;
555 case VAR_W_VISIBLE_NAME
:
556 if (fw
&& !IS_EWMH_DESKTOP(FW_W(fw
)))
558 string
= fw
->visible_name
;
566 if (!fw
|| IS_ICONIFIED(fw
) || IS_EWMH_DESKTOP(FW_W(fw
)))
575 get_unshaded_geometry(fw
, &g
);
599 if (!fw
|| IS_ICONIFIED(fw
) || IS_EWMH_DESKTOP(FW_W(fw
)))
608 get_client_geometry(fw
, &g
);
632 if (!fw
|| IS_EWMH_DESKTOP(FW_W(fw
)))
640 if (get_visible_icon_title_geometry(fw
, &g
) == False
)
668 if (!fw
|| IS_EWMH_DESKTOP(FW_W(fw
)))
676 if (get_visible_icon_picture_geometry(fw
, &g
) == False
)
704 if (!fw
|| IS_EWMH_DESKTOP(FW_W(fw
)))
712 if (get_visible_icon_geometry(fw
, &g
) == False
)
737 if (!fw
|| IS_EWMH_DESKTOP(FW_W(fw
)))
742 if (is_window_sticky_across_desks(fw
))
744 val
= Scr
.CurrentDesk
;
752 if (!fw
|| IS_EWMH_DESKTOP(FW_W(fw
)))
763 case VAR_SCHEDULE_LAST
:
765 val
= squeue_get_last_id();
767 case VAR_SCHEDULE_NEXT
:
769 val
= squeue_get_next_id();
779 case COND_RC_NO_MATCH
:
782 val
= (int)(cond_rc
->rc
);
791 if (is_numeric
== False
)
794 context_w
= Scr
.Root
;
799 if (is_numeric
== False
)
801 if (!fw
|| IS_ICONIFIED(fw
)
802 || IS_EWMH_DESKTOP(FW_W(fw
)))
807 context_w
= FW_W_FRAME(fw
);
812 if (is_numeric
== False
)
814 if (!fw
|| IS_ICONIFIED(fw
) || IS_SHADED(fw
)
815 || IS_EWMH_DESKTOP(FW_W(fw
)))
820 context_w
= FW_W(fw
);
830 if (FQueryPointer(dpy
, context_w
, &JunkRoot
, &JunkChild
,
831 &JunkX
, &JunkY
, &x
, &y
, &JunkMask
) == False
)
833 /* pointer is on a different screen, don't expand */
836 val
= (is_x
) ? x
: y
;
838 case VAR_VERSION_NUM
:
841 case VAR_VERSION_INFO
:
842 string
= VERSIONINFO
;
844 case VAR_VERSION_LINE
:
845 string
= Fvwm_VersionInfo
;
847 case VAR_FUNC_CONTEXT
:
849 target
[0] = wcontext_wcontext_to_char(exc
->w
.wcontext
);
853 /* unknown variable - try to find it in the environment */
854 string
= getenv(var_name
);
857 /* Replace it with unexpanded variable. This is needed
858 * since var_name might have been expanded */
859 l
= strlen(var_name
) + 3;
862 strcpy(output
, "$[");
863 strcpy(output
+ 2, var_name
);
875 sprintf(target
, "%d", val
);
889 strcpy(output
, string
);
894 len
= strlen(string
);
898 quoted_string
= (char *)safemalloc(len
* 2 + 3);
899 len
= QuoteString(quoted_string
, string
) - quoted_string
;
902 strcpy(output
, quoted_string
);
906 if (allocated_string
)
908 free(allocated_string
);
913 /* ---------------------------- interface functions ------------------------ */
916 char *input
, char *arguments
[], Bool addto
, Bool ismod
,
917 cond_rc_t
*cond_rc
, const exec_context_t
*exc
)
919 int l
, i
, l2
, n
, k
, j
, m
;
921 Bool name_has_dollar
;
924 const char *string
= NULL
;
925 Bool is_string
= False
;
926 FvwmWindow
*fw
= exc
->w
.fw
;
931 if (input
[0] == '+' && Scr
.last_added_item
.type
== ADDED_FUNCTION
)
936 /* Calculate best guess at length of expanded string */
940 if (input
[i
] == '$' && (!ismod
|| !isalpha(input
[i
+ 1])))
942 switch (input
[i
+ 1])
945 /* skip the second $, it is not a part of
950 /* extended variables */
954 name_has_dollar
= False
;
955 while (m
< l
&& xlevel
&& input
[m
])
957 /* handle nested variables */
962 else if (input
[m
] == '[')
966 else if (input
[m
] == '$')
968 name_has_dollar
= True
;
978 /* handle variable name */
989 var
, arguments
, addto
,
990 ismod
, cond_rc
, exc
);
992 xlen
= expand_args_extended(
993 var
, arguments
? arguments
[0] :
997 xlen
= expand_vars_extended(
1001 if (name_has_dollar
)
1007 l2
+= xlen
- (k
+ 2);
1024 if (input
[i
+ 1] == '*')
1030 n
= input
[i
+ 1] - '0' + 1;
1032 if (arguments
[n
] != NULL
)
1034 l2
+= strlen(arguments
[n
]) - 2;
1039 string
= get_current_read_dir();
1051 if (fw
&& !IS_EWMH_DESKTOP(FW_W(fw
)))
1053 switch(input
[i
+ 1])
1056 if (fw
->class.res_class
&&
1057 fw
->class.res_class
[0])
1064 if (fw
->class.res_name
&&
1065 fw
->class.res_name
[0])
1072 if (fw
->name
.name
&&
1075 string
= fw
->name
.name
;
1082 if (fw
&& !IS_EWMH_DESKTOP(FW_W(fw
)))
1084 switch(input
[i
+ 1])
1087 if(fw
->visible_name
)
1089 string
= fw
->visible_name
;
1095 if (Fvwm_VersionInfo
)
1097 l2
+= strlen(Fvwm_VersionInfo
) + 2;
1103 for (k
= 0; string
[k
] != 0; k
++, l2
++)
1105 if (string
[k
] == '\'')
1117 /* Actually create expanded string */
1119 out
= safemalloc(l2
+ 1);
1123 if (input
[i
] == '$' && (!ismod
|| !isalpha(input
[i
+ 1])))
1125 switch (input
[i
+ 1])
1128 /* extended variables */
1131 /* Don't expand these in an 'AddToFunc'
1133 out
[j
++] = input
[i
];
1139 name_has_dollar
= False
;
1140 while (m
< l
&& xlevel
&& input
[m
])
1142 /* handle nested variables */
1143 if (input
[m
] == ']')
1147 else if (input
[m
] == '[')
1151 else if (input
[m
] == '$')
1153 name_has_dollar
= True
;
1160 if (input
[m
] == ']')
1163 /* handle variable name */
1165 if (name_has_dollar
)
1168 var
, arguments
, addto
,
1169 ismod
, cond_rc
, exc
);
1171 xlen
= expand_args_extended(
1173 arguments
[0] : NULL
,
1177 xlen
= expand_vars_extended(
1178 var
, &out
[j
], cond_rc
,
1181 if (name_has_dollar
)
1193 /* copy the whole string in
1194 * square brackets */
1195 for ( ; i
<= m
; i
++, j
++)
1204 out
[j
++] = input
[i
];
1218 if (input
[i
+ 1] == '*')
1224 n
= input
[i
+ 1] - '0' + 1;
1226 if (arguments
[n
] != NULL
)
1228 for (k
= 0; arguments
[n
][k
]; k
++)
1230 out
[j
++] = arguments
[n
][k
];
1234 else if (addto
== 1)
1244 string
= get_current_read_dir();
1248 if (fw
&& !IS_EWMH_DESKTOP(FW_W(fw
)))
1250 fvwm_msg(OLD
, "expand_vars",
1251 "Use $[w.id] instead of $w");
1252 sprintf(&out
[j
], "0x%x",
1257 sprintf(&out
[j
], "$w");
1259 j
+= strlen(&out
[j
]);
1263 fvwm_msg(OLD
, "expand_vars",
1264 "Use $[desk.n] instead of $d");
1265 sprintf(&out
[j
], "%d", Scr
.CurrentDesk
);
1266 j
+= strlen(&out
[j
]);
1270 fvwm_msg(OLD
, "expand_vars",
1271 "Use $[vp.x] instead of $x");
1272 sprintf(&out
[j
], "%d", Scr
.Vx
);
1273 j
+= strlen(&out
[j
]);
1277 fvwm_msg(OLD
, "expand_vars",
1278 "Use $[vp.y] instead of $y");
1279 sprintf(&out
[j
], "%d", Scr
.Vy
);
1280 j
+= strlen(&out
[j
]);
1287 if (fw
&& !IS_EWMH_DESKTOP(FW_W(fw
)))
1289 switch(input
[i
+ 1])
1292 fvwm_msg(OLD
, "expand_vars",
1295 if (fw
->class.res_class
&&
1296 fw
->class.res_class
[0])
1303 fvwm_msg(OLD
, "expand_vars",
1304 "Use $[w.resource] "
1306 if (fw
->class.res_name
&&
1307 fw
->class.res_name
[0])
1314 fvwm_msg(OLD
, "expand_vars",
1317 if (fw
->name
.name
&&
1320 string
= fw
->name
.name
;
1328 fvwm_msg(OLD
, "expand_vars",
1329 "Use $[version.line] instead of $v");
1330 sprintf(&out
[j
], "%s", (Fvwm_VersionInfo
) ?
1331 Fvwm_VersionInfo
: "");
1332 j
+= strlen(&out
[j
]);
1340 out
[j
++] = input
[i
];
1343 if (is_string
&& string
)
1345 j
= QuoteString(&out
[j
], string
) - out
;
1358 out
[j
++] = input
[i
];