Beispiel #1
0
void CMD_Focus(F_CMD_ARGS)
{
  if (DeferExecution(eventp,&w,&tmp_win,&context,CRS_SELECT,ButtonRelease))
    return;

  FocusOn(tmp_win, FALSE, action);
}
Beispiel #2
0
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);
}
Beispiel #3
0
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);
  }
}
Beispiel #4
0
/*****************************************************************************
 *
 * 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]);
}
Beispiel #5
0
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)));
		}
Beispiel #6
0
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;
}