void CMD_Focus(F_CMD_ARGS) { if (DeferExecution(eventp,&w,&tmp_win,&context,CRS_SELECT,ButtonRelease)) return; FocusOn(tmp_win, FALSE, action); }
void CMD_FlipFocus(F_CMD_ARGS) { if (DeferExecution(eventp,&w,&tmp_win,&context,CRS_SELECT,ButtonRelease)) return; /* Reorder the window list */ FocusOn(tmp_win, TRUE, action); }
void CMD_WarpToWindow(F_CMD_ARGS) { int val1_unit, val2_unit, n; int val1, val2; n = GetTwoArguments(action, &val1, &val2, &val1_unit, &val2_unit); if (context != C_UNMANAGED) { if (DeferExecution(eventp,&w,&tmp_win,&context,CRS_SELECT,ButtonRelease)) return; if (n == 2) warp_to_fvwm_window(eventp, tmp_win, val1, val1_unit, val2, val2_unit); else warp_to_fvwm_window(eventp, tmp_win, 0, 0, 0, 0); } else { int x = 0; int y = 0; if (n == 2) { int wx; int wy; unsigned int ww; unsigned int wh; if (!XGetGeometry( dpy, w, &JunkRoot, &wx, &wy, &ww, &wh, &JunkBW, &JunkDepth)) { return; } if (val1_unit != Scr.MyDisplayWidth) x = val1; else x = (ww - 1) * val1 / 100; if (val2_unit != Scr.MyDisplayHeight) y = val2; else y = (wh - 1) * val2 / 100; if (x < 0) x += ww; if (y < 0) y += wh; } XWarpPointer(dpy, None, w, 0, 0, 0, 0, x, y); } }
/***************************************************************************** * * Builtin which determines if the button press was a click or double click... * ****************************************************************************/ void ComplexFunction(XEvent * eventp, Window w, FvwmWindow * tmp_win, unsigned long context, char *action, int *Module) { char type = MOTION; char c; MenuItem *mi; Bool Persist = False; Bool HaveDoubleClick = False; Bool NeedsTarget = False; char *arguments[10], *junk, *taction; int x, y, i; XEvent d, *ev; MenuRoot *mr; extern Bool desperate; mr = FindPopup(action); if (mr == NULL) { if (!desperate) fvwm_msg(ERR, "ComplexFunction", "No such function %s", action); return; } desperate = 0; /* Get the argument list */ /* First entry in action is the function-name, ignore it */ action = GetNextToken(action, &junk); if (junk != NULL) free(junk); for (i = 0; i < 10; i++) action = GetNextToken(action, &arguments[i]); /* These built-ins require a selected window * The function code is >= 100 and < 1000 * F_RESIZE * F_MOVE * F_ICONIFY * F_RAISE * F_LOWER * F_DESTROY * F_DELETE * F_STICK * F_RAISELOWER * F_MAXIMIZE * F_FOCUS * * These do not: * The function code is < 100 * F_NOP * F_TITLE * F_BEEP * F_SCROLL * F_MOVECURSOR * F_RESTART * F_EXEC * F_REFRESH * F_GOTO_PAGE * F_TOGGLE_PAGE * F_CIRCULATE_UP * F_CIRCULATE_DOWN * F_WARP * F_DESK * F_MODULE * F_POPUP * F_QUIT * F_WINDOWLIST * F_FUNCTION * F_SEND_WINDOW_LIST */ ev = eventp; /* In case we want to perform an action on a button press, we * need to fool other routines */ if (eventp->type == ButtonPress) eventp->type = ButtonRelease; mi = mr->first; while (mi != NULL) { /* make lower case */ c = *(mi->item); if ((mi->func_type >= 100) && (mi->func_type < 1000)) NeedsTarget = True; if (isupper(c)) c = tolower(c); if (c == DOUBLE_CLICK) { HaveDoubleClick = True; Persist = True; } else if (c == IMMEDIATE) { if (tmp_win) w = tmp_win->frame; else w = None; taction = expand(mi->action, arguments, tmp_win); ExecuteFunction(taction, tmp_win, eventp, context, -2); free(taction); } else Persist = True; mi = mi->next; } if (!Persist) { for (i = 0; i < 10; i++) if (arguments[i] != NULL) free(arguments[i]); return; } /* Only defer execution if there is a possibility of needing * a window to operate on */ if (NeedsTarget) { if (DeferExecution (eventp, &w, &tmp_win, &context, SELECT, ButtonPress)) { WaitForButtonsUp(); for (i = 0; i < 10; i++) if (arguments[i] != NULL) free(arguments[i]); return; } } if (!GrabEm(SELECT)) { XBell(dpy, Scr.screen); for (i = 0; i < 10; i++) if (arguments[i] != NULL) free(arguments[i]); return; } XQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild, &x, &y, &JunkX, &JunkY, &JunkMask); /* Wait and see if we have a click, or a move */ /* wait 100 msec, see if the user releases the button */ if (IsClick(x, y, ButtonReleaseMask, &d)) { ev = &d; type = CLICK; } /* If it was a click, wait to see if its a double click */ if ((HaveDoubleClick) && (type == CLICK) && (IsClick(x, y, ButtonPressMask, &d))) { type = ONE_AND_A_HALF_CLICKS; ev = &d; } if ((HaveDoubleClick) && (type == ONE_AND_A_HALF_CLICKS) && (IsClick(x, y, ButtonReleaseMask, &d))) { type = DOUBLE_CLICK; ev = &d; } /* some functions operate on button release instead of * presses. These gets really weird for complex functions ... */ if (ev->type == ButtonPress) ev->type = ButtonRelease; mi = mr->first; while (mi != NULL) { /* make lower case */ c = *(mi->item); if (isupper(c)) c = tolower(c); if (c == type) { if (tmp_win) w = tmp_win->frame; else w = None; taction = expand(mi->action, arguments, tmp_win); ExecuteFunction(taction, tmp_win, ev, context, -2); free(taction); } mi = mi->next; } WaitForButtonsUp(); UngrabEm(); for (i = 0; i < 10; i++) if (arguments[i] != NULL) free(arguments[i]); }
static void execute_complex_function( cond_rc_t *cond_rc, const exec_context_t *exc, char *action, Bool *desperate, Bool has_ref_window_moved) { cond_rc_t tmp_rc; cfunc_action_t type = CF_MOTION; char c; FunctionItem *fi; Bool Persist = False; Bool HaveDoubleClick = False; Bool HaveHold = False; Bool NeedsTarget = False; Bool ImmediateNeedsTarget = False; int do_allow_unmanaged = FUNC_ALLOW_UNMANAGED; int do_allow_unmanaged_immediate = FUNC_ALLOW_UNMANAGED; char *arguments[11], *taction; char *func_name; int x, y ,i; XEvent d; FvwmFunction *func; static int depth = 0; const exec_context_t *exc2; exec_context_changes_t ecc; exec_context_change_mask_t mask; int trigger_evtype; int button; XEvent *te; if (cond_rc == NULL) { condrc_init(&tmp_rc); cond_rc = &tmp_rc; } cond_rc->rc = COND_RC_OK; mask = 0; d.type = 0; ecc.w.fw = exc->w.fw; ecc.w.w = exc->w.w; ecc.w.wcontext = exc->w.wcontext; /* find_complex_function expects a token, not just a quoted string */ func_name = PeekToken(action, &taction); if (!func_name) { return; } func = find_complex_function(func_name); if (func == NULL) { if (*desperate == 0) { fvwm_msg( ERR, "ComplexFunction", "No such function %s", action); } return; } if (!depth) { Scr.flags.is_executing_complex_function = 1; } depth++; *desperate = 0; /* duplicate the whole argument list for use as '$*' */ if (taction) { arguments[0] = safestrdup(taction); /* strip trailing newline */ if (arguments[0][0]) { int l= strlen(arguments[0]); if (arguments[0][l - 1] == '\n') { arguments[0][l - 1] = 0; } } /* Get the argument list */ for (i = 1; i < 11; i++) { taction = GetNextToken(taction, &arguments[i]); } } else { for (i = 0; i < 11; i++) { arguments[i] = NULL; } } /* In case we want to perform an action on a button press, we * need to fool other routines */ te = exc->x.elast; if (te->type == ButtonPress) { trigger_evtype = ButtonRelease; } else { trigger_evtype = te->type; } func->use_depth++; for (fi = func->first_item; fi != NULL; fi = fi->next_item) { if (fi->flags & FUNC_NEEDS_WINDOW) { NeedsTarget = True; do_allow_unmanaged &= fi->flags; if (fi->condition == CF_IMMEDIATE) { do_allow_unmanaged_immediate &= fi->flags; ImmediateNeedsTarget = True; break; } } } if (ImmediateNeedsTarget) { if (DeferExecution( &ecc, &mask, CRS_SELECT, trigger_evtype, do_allow_unmanaged_immediate)) { func->use_depth--; __cf_cleanup(&depth, arguments, cond_rc); return; } NeedsTarget = False; } else { ecc.w.w = (ecc.w.fw) ? FW_W_FRAME(ecc.w.fw) : None; mask |= ECC_W; } /* we have to grab buttons before executing immediate actions because * these actions can move the window away from the pointer so that a * button release would go to the application below. */ if (!GrabEm(CRS_NONE, GRAB_NORMAL)) { func->use_depth--; fvwm_msg( ERR, "ComplexFunction", "Grab failed in function %s," " unable to execute immediate action", action); __cf_cleanup(&depth, arguments, cond_rc); return; } exc2 = exc_clone_context(exc, &ecc, mask); __run_complex_function_items( cond_rc, CF_IMMEDIATE, func, exc2, arguments, has_ref_window_moved); exc_destroy_context(exc2); for (fi = func->first_item; fi != NULL && cond_rc->break_levels == 0; fi = fi->next_item) { /* c is already lowercase here */ c = fi->condition; switch (c) { case CF_IMMEDIATE: break; case CF_DOUBLE_CLICK: HaveDoubleClick = True; Persist = True; break; case CF_HOLD: HaveHold = True; Persist = True; break; default: Persist = True; break; } } if (!Persist || cond_rc->break_levels != 0) { func->use_depth--; __cf_cleanup(&depth, arguments, cond_rc); UngrabEm(GRAB_NORMAL); return; } /* Only defer execution if there is a possibility of needing * a window to operate on */ if (NeedsTarget) { if (DeferExecution( &ecc, &mask, CRS_SELECT, trigger_evtype, do_allow_unmanaged)) { func->use_depth--; __cf_cleanup(&depth, arguments, cond_rc); UngrabEm(GRAB_NORMAL); return; } } te = (mask & ECC_ETRIGGER) ? ecc.x.etrigger : exc->x.elast; switch (te->xany.type) { case ButtonPress: case ButtonRelease: x = te->xbutton.x_root; y = te->xbutton.y_root; button = te->xbutton.button; /* Take the click which started this fuction off the * Event queue. -DDN- Dan D Niles [email protected] */ FCheckMaskEvent(dpy, ButtonPressMask, &d); break; default: if (FQueryPointer( dpy, Scr.Root, &JunkRoot, &JunkChild, &x, &y, &JunkX, &JunkY, &JunkMask) == False) { /* pointer is on a different screen */ x = 0; y = 0; } button = 0; break; } /* Wait and see if we have a click, or a move */ /* wait forever, see if the user releases the button */ type = CheckActionType(x, y, &d, HaveHold, True, &button); if (type == CF_CLICK) { int button2; /* If it was a click, wait to see if its a double click */ if (HaveDoubleClick) { type = CheckActionType( x, y, &d, True, False, &button2); switch (type) { case CF_HOLD: case CF_MOTION: case CF_CLICK: if (button == button2) { type = CF_DOUBLE_CLICK; } else { type = CF_CLICK; } break; case CF_TIMEOUT: type = CF_CLICK; break; default: /* can't happen */ break; } } } else if (type == CF_TIMEOUT) { type = CF_HOLD; } /* some functions operate on button release instead of presses. These * gets really weird for complex functions ... */ if (d.type == ButtonPress) { d.type = ButtonRelease; if (d.xbutton.button > 0 && d.xbutton.button <= NUMBER_OF_MOUSE_BUTTONS) { d.xbutton.state &= (~(Button1Mask >> (d.xbutton.button - 1))); }
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; }