static void __execute_function( cond_rc_t *cond_rc, const exec_context_t *exc, char *action, FUNC_FLAGS_TYPE exec_flags, char *args[], Bool has_ref_window_moved) { static int func_depth = 0; cond_rc_t *func_rc = NULL; cond_rc_t dummy_rc; Window w; int j; char *function; char *taction; char *trash; char *trash2; char *expaction = NULL; char *arguments[11]; const func_t *bif; Bool set_silent; Bool must_free_string = False; Bool must_free_function = False; Bool do_keep_rc = False; /* needed to be able to avoid resize to use moved windows for base */ extern Window PressedW; Window dummy_w; if (!action) { return; } /* ignore whitespace at the beginning of all config lines */ action = SkipSpaces(action, NULL, 0); if (!action || action[0] == 0) { /* impossibly short command */ return; } if (action[0] == '#') { /* a comment */ return; } func_depth++; if (func_depth > MAX_FUNCTION_DEPTH) { fvwm_msg( ERR, "__execute_function", "Function '%s' called with a depth of %i, " "stopping function execution!", action, func_depth); func_depth--; return; } if (args) { for (j = 0; j < 11; j++) { arguments[j] = args[j]; } } else { for (j = 0; j < 11; j++) { arguments[j] = NULL; } } if (exc->w.fw == NULL || IS_EWMH_DESKTOP(FW_W(exc->w.fw))) { if (exec_flags & FUNC_IS_UNMANAGED) { w = exc->w.w; } else { w = Scr.Root; } } else { FvwmWindow *tw; w = GetSubwindowFromEvent(dpy, exc->x.elast); if (w == None) { w = exc->x.elast->xany.window; } tw = NULL; if (w != None) { if (XFindContext( dpy, w, FvwmContext, (caddr_t *)&tw) == XCNOENT) { tw = NULL; } } if (w == None || tw != exc->w.fw) { w = FW_W(exc->w.fw); } } set_silent = False; if (action[0] == '-') { exec_flags |= FUNC_DONT_EXPAND_COMMAND; action++; } taction = action; /* parse prefixes */ trash = PeekToken(taction, &trash2); while (trash) { if (StrEquals(trash, PRE_SILENT)) { if (Scr.flags.are_functions_silent == 0) { set_silent = 1; Scr.flags.are_functions_silent = 1; } taction = trash2; trash = PeekToken(taction, &trash2); } else if (StrEquals(trash, PRE_KEEPRC)) { do_keep_rc = True; taction = trash2; trash = PeekToken(taction, &trash2); } else { break; } } if (taction == NULL) { if (set_silent) { Scr.flags.are_functions_silent = 0; } func_depth--; return; } if (cond_rc == NULL || do_keep_rc == True) { condrc_init(&dummy_rc); func_rc = &dummy_rc; } else { func_rc = cond_rc; } GetNextToken(taction, &function); if (function) { char *tmp = function; function = expand_vars( function, arguments, False, False, func_rc, exc); free(tmp); } if (function && function[0] != '*') { #if 1 /* DV: with this piece of code it is impossible to have a * complex function with embedded whitespace that begins with a * builtin function name, e.g. a function "echo hello". */ /* DV: ... and without it some of the complex functions will * fail */ char *tmp = function; while (*tmp && !isspace(*tmp)) { tmp++; } *tmp = 0; #endif bif = find_builtin_function(function); must_free_function = True; } else { bif = NULL; if (function) { free(function); } function = ""; } if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor && (!bif || !(bif->flags & FUNC_DECOR))) { fvwm_msg( ERR, "__execute_function", "Command can not be added to a decor; executing" " command now: '%s'", action); } if (!(exec_flags & FUNC_DONT_EXPAND_COMMAND)) { expaction = expand_vars( taction, arguments, (bif) ? !!(bif->flags & FUNC_ADD_TO) : False, (taction[0] == '*'), func_rc, exc); if (func_depth <= 1) { must_free_string = set_repeat_data( expaction, REPEAT_COMMAND, bif); } else { must_free_string = True; } } else { expaction = taction; } #ifdef FVWM_COMMAND_LOG fvwm_msg(INFO, "LOG", "%c: %s", (char)exc->type, expaction); #endif /* Note: the module config command, "*" can not be handled by the * regular command table because there is no required white space after * the asterisk. */ if (expaction[0] == '*') { if (Scr.cur_decor && Scr.cur_decor != &Scr.DefaultDecor) { fvwm_msg( WARN, "__execute_function", "Command can not be added to a decor;" " executing command now: '%s'", expaction); } /* process a module config command */ ModuleConfig(expaction); } else { const exec_context_t *exc2; exec_context_changes_t ecc; exec_context_change_mask_t mask; mask = (w != exc->w.w) ? ECC_W : 0; ecc.w.fw = exc->w.fw; ecc.w.w = w; ecc.w.wcontext = exc->w.wcontext; if (bif && bif->func_t != F_FUNCTION) { char *runaction; Bool rc = False; runaction = SkipNTokens(expaction, 1); if ((bif->flags & FUNC_NEEDS_WINDOW) && !(exec_flags & FUNC_DONT_DEFER)) { rc = DeferExecution( &ecc, &mask, bif->cursor, exc->x.elast->type, (bif->flags & FUNC_ALLOW_UNMANAGED)); } else if ((bif->flags & FUNC_NEEDS_WINDOW) && !__context_has_window( exc, bif->flags & FUNC_ALLOW_UNMANAGED)) { /* no context window and not allowed to defer, * skip command */ rc = True; } if (rc == False) { exc2 = exc_clone_context(exc, &ecc, mask); if (has_ref_window_moved && (bif->func_t == F_ANIMATED_MOVE || bif->func_t == F_MOVE || bif->func_t == F_RESIZE || bif->func_t == F_RESIZEMOVE || bif->func_t == F_RESIZE_MAXIMIZE || bif->func_t == F_RESIZEMOVE_MAXIMIZE)) { dummy_w = PressedW; PressedW = None; bif->action(func_rc, exc2, runaction); PressedW = dummy_w; } else { bif->action(func_rc, exc2, runaction); } exc_destroy_context(exc2); } } else { Bool desperate = 1; char *runaction; if (bif) { /* strip "function" command */ runaction = SkipNTokens(expaction, 1); } else { runaction = expaction; } exc2 = exc_clone_context(exc, &ecc, mask); execute_complex_function( func_rc, exc2, runaction, &desperate, has_ref_window_moved); if (!bif && desperate) { if (executeModuleDesperate( func_rc, exc, runaction) == NULL && *function != 0 && !set_silent) { fvwm_msg( ERR, "__execute_function", "No such command '%s'", function); } } exc_destroy_context(exc2); } } if (set_silent) { Scr.flags.are_functions_silent = 0; } if (cond_rc != NULL) { cond_rc->break_levels = func_rc->break_levels; } if (must_free_string) { free(expaction); } if (must_free_function) { free(function); } func_depth--; return; }
static signed int expand_vars_extended( char *var_name, char *output, cond_rc_t *cond_rc, const exec_context_t *exc) { char *rest; char dummy[64] = "\0"; char *target = (output) ? output : dummy; int cs = -1; int n; int i; int l; int x; int y; Pixel pixel = 0; int val = -12345678; const char *string = NULL; char *allocated_string = NULL; char *quoted_string = NULL; Bool should_quote = False; Bool is_numeric = False; Bool is_target = False; Bool is_x; Window context_w = Scr.Root; FvwmWindow *fw = exc->w.fw; signed int len = -1; /* allow partial matches for *.cs, gt, ... etc. variables */ switch ((i = GetTokenIndex(var_name, partial_function_vars, -1, &rest))) { case VAR_FG_CS: case VAR_BG_CS: case VAR_HILIGHT_CS: case VAR_SHADOW_CS: case VAR_FGSH_CS: if (!isdigit(*rest) || (*rest == '0' && *(rest + 1) != 0)) { /* not a non-negative integer without leading zeros */ return -1; } if (sscanf(rest, "%d%n", &cs, &n) < 1) { return -1; } if (*(rest + n) != 0) { /* trailing characters */ return -1; } if (cs < 0) { return -1; } alloc_colorset(cs); switch (i) { case VAR_FG_CS: pixel = Colorset[cs].fg; break; case VAR_BG_CS: pixel = Colorset[cs].bg; break; case VAR_HILIGHT_CS: pixel = Colorset[cs].hilite; break; case VAR_SHADOW_CS: pixel = Colorset[cs].shadow; break; case VAR_FGSH_CS: pixel = Colorset[cs].fgsh; break; } is_target = True; len = pixel_to_color_string(dpy, Pcmap, pixel, target, False); goto GOT_STRING; case VAR_GT_: if (rest == NULL) { return -1; } string = _(rest); goto GOT_STRING; case VAR_INFOSTORE_: if (rest == NULL) return -1; if ((string = get_metainfo_value(rest)) == NULL) return -1; goto GOT_STRING; case VAR_DESK_NAME: if (sscanf(rest, "%d%n", &cs, &n) < 1) { return -1; } if (*(rest + n) != 0) { /* trailing characters */ return -1; } string = GetDesktopName(cs); if (string == NULL) { const char *ddn = _("Desk"); allocated_string = (char *)safemalloc(19 + strlen(ddn)); sprintf(allocated_string, "%s %i", ddn, cs); string = allocated_string; } goto GOT_STRING; default: break; } /* only exact matches for all other variables */ switch ((i = GetTokenIndex(var_name, function_vars, 0, &rest))) { case VAR_DESK_N: is_numeric = True; val = Scr.CurrentDesk; break; case VAR_DESK_WIDTH: is_numeric = True; val = Scr.VxMax + Scr.MyDisplayWidth; break; case VAR_DESK_HEIGHT: is_numeric = True; val = Scr.VyMax + Scr.MyDisplayHeight; break; case VAR_DESK_PAGESX: is_numeric = True; val = (int)(Scr.VxMax / Scr.MyDisplayWidth) + 1; break; case VAR_DESK_PAGESY: is_numeric = True; val = (int)(Scr.VyMax / Scr.MyDisplayHeight) + 1; break; case VAR_VP_X: is_numeric = True; val = Scr.Vx; break; case VAR_VP_Y: is_numeric = True; val = Scr.Vy; break; case VAR_VP_WIDTH: is_numeric = True; val = Scr.MyDisplayWidth; break; case VAR_VP_HEIGHT: is_numeric = True; val = Scr.MyDisplayHeight; break; case VAR_WA_HEIGHT: is_numeric = True; val = Scr.Desktops->ewmh_working_area.height; break; case VAR_WA_WIDTH: is_numeric = True; val = Scr.Desktops->ewmh_working_area.width; break; case VAR_WA_X: is_numeric = True; val = Scr.Desktops->ewmh_working_area.x; break; case VAR_WA_Y: is_numeric = True; val = Scr.Desktops->ewmh_working_area.y; break; case VAR_DWA_HEIGHT: is_numeric = True; val = Scr.Desktops->ewmh_dyn_working_area.height; break; case VAR_DWA_WIDTH: is_numeric = True; val = Scr.Desktops->ewmh_dyn_working_area.width; break; case VAR_DWA_X: is_numeric = True; val = Scr.Desktops->ewmh_dyn_working_area.x; break; case VAR_DWA_Y: is_numeric = True; val = Scr.Desktops->ewmh_dyn_working_area.y; break; case VAR_PAGE_NX: is_numeric = True; val = (int)(Scr.Vx / Scr.MyDisplayWidth); break; case VAR_PAGE_NY: is_numeric = True; val = (int)(Scr.Vy / Scr.MyDisplayHeight); break; case VAR_W_ID: if (fw && !IS_EWMH_DESKTOP(FW_W(fw))) { is_target = True; sprintf(target, "0x%x", (int)FW_W(fw)); } break; case VAR_W_NAME: if (fw && !IS_EWMH_DESKTOP(FW_W(fw))) { string = fw->name.name; should_quote = True; } break; case VAR_W_ICONNAME: if (fw && !IS_EWMH_DESKTOP(FW_W(fw))) { string = fw->icon_name.name; should_quote = True; } break; case VAR_W_ICONFILE: case VAR_W_MINIICONFILE: if (fw && !IS_EWMH_DESKTOP(FW_W(fw))) { char *t; t = (i == VAR_W_ICONFILE) ? fw->icon_bitmap_file : fw->mini_pixmap_file; /* expand the path if possible */ allocated_string = PictureFindImageFile(t, NULL, R_OK); if (allocated_string == NULL) { string = t; } else if (USE_SVG && *allocated_string == ':' && (string = strchr(allocated_string + 1, ':'))) { string++; } else { string = allocated_string; } } break; case VAR_W_ICONFILE_SVGOPTS: case VAR_W_MINIICONFILE_SVGOPTS: if (fw && !IS_EWMH_DESKTOP(FW_W(fw))) { char *t; if (!USE_SVG) { return -1; } t = (i == VAR_W_ICONFILE_SVGOPTS) ? fw->icon_bitmap_file : fw->mini_pixmap_file; /* expand the path if possible */ allocated_string = PictureFindImageFile(t, NULL, R_OK); string = allocated_string; if (string && *string == ':' && (t = strchr(string + 1, ':'))) { *t = 0; } else { string = ""; } } break; case VAR_W_CLASS: if (fw && !IS_EWMH_DESKTOP(FW_W(fw))) { string = fw->class.res_class; should_quote = True; } break; case VAR_W_RESOURCE: if (fw && !IS_EWMH_DESKTOP(FW_W(fw))) { string = fw->class.res_name; should_quote = True; }
/* * Defer the execution of a function to the next button press if the context is * C_ROOT * * Inputs: * cursor - the cursor to display while waiting */ static Bool DeferExecution( exec_context_changes_t *ret_ecc, exec_context_change_mask_t *ret_mask, cursor_t cursor, int trigger_evtype, int do_allow_unmanaged) { int done; int finished = 0; int just_waiting_for_finish = 0; Window dummy; Window original_w; static XEvent e; Window w; int wcontext; FvwmWindow *fw; int FinishEvent; fw = ret_ecc->w.fw; w = ret_ecc->w.w; original_w = w; wcontext = ret_ecc->w.wcontext; FinishEvent = ((fw != NULL) ? ButtonRelease : ButtonPress); if (wcontext == C_UNMANAGED && do_allow_unmanaged) { return False; } if (wcontext != C_ROOT && wcontext != C_NO_CONTEXT && fw != NULL && wcontext != C_EWMH_DESKTOP) { if (FinishEvent == ButtonPress || (FinishEvent == ButtonRelease && trigger_evtype != ButtonPress)) { return False; } else if (FinishEvent == ButtonRelease) { /* We are only waiting until the user releases the * button. Do not change the cursor. */ cursor = CRS_NONE; just_waiting_for_finish = 1; } } if (Scr.flags.are_functions_silent) { return True; } if (!GrabEm(cursor, GRAB_NORMAL)) { XBell(dpy, 0); return True; } MyXGrabKeyboard(dpy); while (!finished) { done = 0; /* block until there is an event */ FMaskEvent( dpy, ButtonPressMask | ButtonReleaseMask | ExposureMask | KeyPressMask | VisibilityChangeMask | ButtonMotionMask | PointerMotionMask /* | EnterWindowMask | LeaveWindowMask*/, &e); if (e.type == KeyPress) { KeySym keysym = XLookupKeysym(&e.xkey, 0); if (keysym == XK_Escape) { ret_ecc->x.etrigger = &e; *ret_mask |= ECC_ETRIGGER; UngrabEm(GRAB_NORMAL); MyXUngrabKeyboard(dpy); return True; } Keyboard_shortcuts(&e, NULL, NULL, NULL, FinishEvent); } if (e.type == FinishEvent) { finished = 1; } switch (e.type) { case KeyPress: case ButtonPress: if (e.type != FinishEvent) { original_w = e.xany.window; } done = 1; break; case ButtonRelease: done = 1; break; default: break; } if (!done) { dispatch_event(&e); } } MyXUngrabKeyboard(dpy); UngrabEm(GRAB_NORMAL); if (just_waiting_for_finish) { return False; } w = e.xany.window; ret_ecc->x.etrigger = &e; *ret_mask |= ECC_ETRIGGER | ECC_W | ECC_WCONTEXT; if ((w == Scr.Root || w == Scr.NoFocusWin) && e.xbutton.subwindow != None) { w = e.xbutton.subwindow; e.xany.window = w; } if (w == Scr.Root || IS_EWMH_DESKTOP(w)) { ret_ecc->w.w = w; ret_ecc->w.wcontext = C_ROOT; XBell(dpy, 0); return True; } *ret_mask |= ECC_FW; if (XFindContext(dpy, w, FvwmContext, (caddr_t *)&fw) == XCNOENT) { ret_ecc->w.fw = NULL; ret_ecc->w.w = w; ret_ecc->w.wcontext = C_ROOT; XBell(dpy, 0); return (True); } if (w == FW_W_PARENT(fw)) { w = FW_W(fw); } if (original_w == FW_W_PARENT(fw)) { original_w = FW_W(fw); } /* this ugly mess attempts to ensure that the release and press * are in the same window. */ if (w != original_w && original_w != Scr.Root && original_w != None && original_w != Scr.NoFocusWin && !IS_EWMH_DESKTOP(original_w)) { if (w != FW_W_FRAME(fw) || original_w != FW_W(fw)) { ret_ecc->w.fw = fw; ret_ecc->w.w = w; ret_ecc->w.wcontext = C_ROOT; XBell(dpy, 0); return True; } } if (IS_EWMH_DESKTOP(FW_W(fw))) { ret_ecc->w.fw = fw; ret_ecc->w.w = w; ret_ecc->w.wcontext = C_ROOT; XBell(dpy, 0); return True; } wcontext = GetContext(NULL, fw, &e, &dummy); ret_ecc->w.fw = fw; ret_ecc->w.w = w; ret_ecc->w.wcontext = C_ROOT; return False; }