/* This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/****************************************************************************
 * This module is all original code
 * by Rob Nation
 * Copyright 1993, Robert Nation
 *     You may use this code for any purpose, as long as the original
 *     copyright remains in the source code and all documentation
 ****************************************************************************/

#include "config.h"

#include <stdio.h>

#include "libs/fvwmlib.h"
#include "libs/FScreen.h"
#include "fvwm.h"
#include "externs.h"
#include "cursor.h"
#include "functions.h"
#include "bindings.h"
#include "misc.h"
#include "screen.h"
#include "update.h"
#include "style.h"
#include "focus.h"


/**********************************************************************
 * Parses the flag string and returns the text between [ ] or ( )
 * characters.  The start of the rest of the line is put in restptr.
 * Note that the returned string is allocated here and it must be
 * freed when it is not needed anymore.
 * NOTE - exported via .h
 **********************************************************************/
char *CreateFlagString(char *string, char **restptr)
{
  char *retval;
  char *c;
  char *start;
  char closeopt;
  int length;

  c = string;
  while (isspace((unsigned char)*c) && (*c != 0))
    c++;

  if (*c == '[' || *c == '(')
  {
    /* Get the text between [ ] or ( ) */
    if (*c == '[')
      closeopt = ']';
    else
      closeopt = ')';
    c++;
    start = c;
    length = 0;
    while (*c != closeopt) {
      char *d;
      if (*c == 0) {
	fvwm_msg(ERR, "CreateFlagString",
		 "Conditionals require closing parenthesis");
	*restptr = NULL;
	return NULL;
      }
      /* skip quoted string */
      d = SkipQuote(c, NULL, NULL, NULL);
      length += d - c;
      c = d;
    }

    /* We must allocate a new string because we null terminate the string
     * between the [ ] or ( ) characters.
     */
    retval = safemalloc(length + 1);
    strncpy(retval, start, length);
    retval[length] = 0;

    *restptr = c + 1;
  }
  else
  {
    retval = NULL;
    *restptr = c;
  }

  return retval;
}

/**********************************************************************
 * The name field of the mask is allocated in CreateConditionMask.
 * It must be freed.
 * NOTE - exported via .h
 **********************************************************************/
void FreeConditionMask(WindowConditionMask *mask)
{
  if (mask->my_flags.needs_name)
    free(mask->name);
  else if (mask->my_flags.needs_not_name)
    free(mask->name - 1);
}

/* Assign the default values for the window mask
 * NOTE - exported via .h
 */
void DefaultConditionMask(WindowConditionMask *mask)
{
  memset(mask, 0, sizeof(WindowConditionMask));
  mask->layer = -2; /* -2  means no layer condition, -1 means current */
}

/**********************************************************************
 * Note that this function allocates the name field of the mask struct.
 * FreeConditionMask must be called for the mask when the mask is discarded.
 * NOTE - exported via .h
 **********************************************************************/
void CreateConditionMask(char *flags, WindowConditionMask *mask)
{
  char *condition;
  char *prev_condition = NULL;
  char *tmp;

  if (flags == NULL)
    return;

  /* Next parse the flags in the string. */
  tmp = flags;
  tmp = GetNextSimpleOption(tmp, &condition);

  while (condition)
  {
    if (StrEquals(condition,"AcceptsFocus"))
    {
      mask->my_flags.do_accept_focus = 1;
      mask->my_flags.use_do_accept_focus = 1;
    }
    else if (StrEquals(condition,"!AcceptsFocus"))
    {
      mask->my_flags.do_accept_focus = 0;
      mask->my_flags.use_do_accept_focus = 1;
    }
    else if (StrEquals(condition,"Iconic"))
    {
      SET_ICONIFIED(mask, 1);
      SETM_ICONIFIED(mask, 1);
    }
    else if (StrEquals(condition,"!Iconic"))
    {
      SET_ICONIFIED(mask, 0);
      SETM_ICONIFIED(mask, 1);
    }
    else if (StrEquals(condition,"Visible"))
    {
      SET_PARTIALLY_VISIBLE(mask, 1);
      SETM_PARTIALLY_VISIBLE(mask, 1);
    }
    else if (StrEquals(condition,"!Visible"))
    {
      SET_PARTIALLY_VISIBLE(mask, 0);
      SETM_PARTIALLY_VISIBLE(mask, 1);
    }
    else if (StrEquals(condition,"PlacedByButton3"))
    {
      SET_PLACED_WB3(mask, 1);
      SETM_PLACED_WB3(mask, 1);
    }
    else if (StrEquals(condition,"!PlacedByButton3"))
    {
      SET_PLACED_WB3(mask, 0);
      SETM_PLACED_WB3(mask, 1);
    }
    else if (StrEquals(condition,"Raised"))
    {
      SET_FULLY_VISIBLE(mask, 1);
      SETM_FULLY_VISIBLE(mask, 1);
    }
    else if (StrEquals(condition,"!Raised"))
    {
      SET_FULLY_VISIBLE(mask, 0);
      SETM_FULLY_VISIBLE(mask, 1);
    }
    else if (StrEquals(condition,"Sticky"))
    {
      SET_STICKY(mask, 1);
      SETM_STICKY(mask, 1);
    }
    else if (StrEquals(condition,"!Sticky"))
    {
      SET_STICKY(mask, 0);
      SETM_STICKY(mask, 1);
    }
    else if (StrEquals(condition,"Maximized"))
    {
      SET_MAXIMIZED(mask, 1);
      SETM_MAXIMIZED(mask, 1);
    }
    else if (StrEquals(condition,"!Maximized"))
    {
      SET_MAXIMIZED(mask, 0);
      SETM_MAXIMIZED(mask, 1);
    }
    else if (StrEquals(condition,"Shaded"))
    {
      SET_SHADED(mask, 1);
      SETM_SHADED(mask, 1);
    }
    else if (StrEquals(condition,"!Shaded"))
    {
      SET_SHADED(mask, 0);
      SETM_SHADED(mask, 1);
    }
    else if (StrEquals(condition,"Transient"))
    {
      SET_TRANSIENT(mask, 1);
      SETM_TRANSIENT(mask, 1);
    }
    else if (StrEquals(condition,"!Transient"))
    {
      SET_TRANSIENT(mask, 0);
      SETM_TRANSIENT(mask, 1);
    }
    else if (StrEquals(condition,"PlacedByFvwm"))
    {
      SET_PLACED_BY_FVWM(mask, 1);
      SETM_PLACED_BY_FVWM(mask, 1);
    }
    else if (StrEquals(condition,"!PlacedByFvwm"))
    {
      SET_PLACED_BY_FVWM(mask, 0);
      SETM_PLACED_BY_FVWM(mask, 1);
    }
    else if (StrEquals(condition,"CurrentDesk"))
      mask->my_flags.needs_current_desk = 1;
    else if (StrEquals(condition,"CurrentPage"))
    {
      mask->my_flags.needs_current_desk = 1;
      mask->my_flags.needs_current_page = 1;
    }
    else if (StrEquals(condition,"CurrentGlobalPage"))
    {
      mask->my_flags.needs_current_desk = 1;
      mask->my_flags.needs_current_global_page = 1;
    }
    else if (StrEquals(condition,"CurrentPageAnyDesk") ||
	    StrEquals(condition,"CurrentScreen"))
      mask->my_flags.needs_current_page = 1;
    else if (StrEquals(condition,"CurrentGlobalPageAnyDesk"))
      mask->my_flags.needs_current_global_page = 1;
    else if (StrEquals(condition,"CirculateHit"))
      mask->my_flags.use_circulate_hit = 1;
    else if (StrEquals(condition,"CirculateHitIcon"))
      mask->my_flags.use_circulate_hit_icon = 1;
    else if (StrEquals(condition,"CirculateHitShaded"))
      mask->my_flags.use_circulate_hit_shaded = 1;
    else if (StrEquals(condition, "Layer"))
    {
       if (sscanf(tmp,"%d",&mask->layer))
       {
	  tmp = GetNextToken (tmp, &condition);
          if (mask->layer < 0)
            mask->layer = -2; /* silently ignore invalid layers */
       }
       else
       {
          mask->layer = -1; /* needs current layer */
       }
    }
    else if (!mask->my_flags.needs_name && !mask->my_flags.needs_not_name)
    {
      /* only 1st name to avoid mem leak */
      mask->name = condition;
      condition = NULL;
      if (mask->name[0] == '!')
      {
	mask->my_flags.needs_not_name = 1;
	mask->name++;
      }
      else
	mask->my_flags.needs_name = 1;
    }

    if (prev_condition)
      free(prev_condition);

    prev_condition = condition;
    tmp = GetNextSimpleOption(tmp, &condition);
  }

  if (prev_condition)
    free(prev_condition);
}

/**********************************************************************
 * Checks whether the given window matches the mask created with
 * CreateConditionMask.
 * NOTE - exported via .h
 **********************************************************************/
Bool MatchesConditionMask(FvwmWindow *fw, WindowConditionMask *mask)
{
  Bool fMatchesName;
  Bool fMatchesIconName;
  Bool fMatchesClass;
  Bool fMatchesResource;
  Bool fMatches;
  FvwmWindow *sf = get_focus_window();

  if (!blockcmpmask((char *)&(fw->flags), (char *)&(mask->flags),
                    (char *)&(mask->flag_mask), sizeof(fw->flags)))
    return 0;

  /*
  if ((mask->onFlags & fw->flags) != mask->onFlags)
    return 0;

  if ((mask->offFlags & fw->flags) != 0)
    return 0;
  */

  if (!mask->my_flags.use_circulate_hit && DO_SKIP_CIRCULATE(fw))
    return 0;

  if (!mask->my_flags.use_circulate_hit_icon && IS_ICONIFIED(fw) &&
      DO_SKIP_ICON_CIRCULATE(fw))
    return 0;

  if (!mask->my_flags.use_circulate_hit_shaded && IS_SHADED(fw) &&
      DO_SKIP_SHADED_CIRCULATE(fw))
    return 0;

  if (IS_ICONIFIED(fw) && IS_TRANSIENT(fw) && IS_ICONIFIED_BY_PARENT(fw))
    return 0;

  if (mask->my_flags.needs_current_desk && fw->Desk != Scr.CurrentDesk)
    return 0;
  if (mask->my_flags.needs_current_page)
  {
    if (FScreenIsEnabled())
    {
      if (!FScreenIsRectangleOnScreen(NULL, FSCREEN_CURRENT, &(fw->frame_g)))
	return 0;
    }
    else
    {
      if (!IsRectangleOnThisPage(&(fw->frame_g), Scr.CurrentDesk))
	return 0;
    }
  }
  else if (mask->my_flags.needs_current_global_page)
  {
    if (!IsRectangleOnThisPage(&(fw->frame_g), Scr.CurrentDesk))
      return 0;
  }

  /* Yes, I know this could be shorter, but it's hard to understand then */
  fMatchesName = matchWildcards(mask->name, fw->name);
  fMatchesIconName = matchWildcards(mask->name, fw->icon_name);
  fMatchesClass = (fw->class.res_class &&
		   matchWildcards(mask->name,fw->class.res_class));
  fMatchesResource = (fw->class.res_name &&
		      matchWildcards(mask->name, fw->class.res_name));
  fMatches = (fMatchesName || fMatchesIconName || fMatchesClass ||
	      fMatchesResource);

  if (mask->my_flags.needs_name && !fMatches)
    return 0;

  if (mask->my_flags.needs_not_name && fMatches)
    return 0;

  if ((mask->layer == -1) && (sf) && (fw->layer != sf->layer))
    return 0;

  if ((mask->layer >= 0) && (fw->layer != mask->layer))
    return 0;

  if (mask->my_flags.use_do_accept_focus)
  {
    Bool f;

    f = do_accept_input_focus(fw);
    if (fw && HAS_NEVER_FOCUS(fw))
    {
      f = 0;
    }
    else if (fw && IS_LENIENT(fw))
    {
      f = 1;
    }
    if (!f != !mask->my_flags.do_accept_focus)
    {
      return 0;
    }
  }

  return 1;
}

/**************************************************************************
 *
 * Direction = 1 ==> "Next" operation
 * Direction = -1 ==> "Previous" operation
 * Direction = 0 ==> operation on current window (returns pass or fail)
 *
 **************************************************************************/
static FvwmWindow *Circulate(char *action, int Direction, char **restofline)
{
  int pass = 0;
  FvwmWindow *fw, *found = NULL;
  FvwmWindow *sf;
  WindowConditionMask mask;
  char *flags;

  /* Create window mask */
  flags = CreateFlagString(action, restofline);
  DefaultConditionMask(&mask);
  if (Direction == 0)
  { /* override for Current [] */
    mask.my_flags.use_circulate_hit = 1;
    mask.my_flags.use_circulate_hit_icon = 1;
    mask.my_flags.use_circulate_hit_shaded = 1;
  }
  CreateConditionMask(flags, &mask);
  if (flags)
    free(flags);
  sf = get_focus_window();
  if (sf)
  {
    if (Direction > 0)
      fw = sf->prev;
    else if (Direction < 0)
      fw = sf->next;
    else
      fw = sf;
  }
  else
  {
    if (Direction == 0)
    {
      return NULL;
    }
    fw = NULL;
  }

  for (pass = 0; pass < 3 && !found; pass++)
  {
    while (fw && !found && fw != &Scr.FvwmRoot)
    {
#ifdef FVWM_DEBUG_MSGS
      fvwm_msg(DBG,"Circulate","Trying %s",fw->name);
#endif /* FVWM_DEBUG_MSGS */
      /* Make CirculateUp and CirculateDown take args. by Y.NOMURA */
      if (MatchesConditionMask(fw, &mask))
      {
	found = fw;
      }
      else
      {
	if (Direction > 0)
	  fw = fw->prev;
	else
	  fw = fw->next;
      }
      if (Direction == 0)
      {
	FreeConditionMask(&mask);
        return found;
      }
    }
    if (!fw || fw == &Scr.FvwmRoot)
    {
      if (Direction > 0)
      {
        /* Go to end of list */
	for (fw = &Scr.FvwmRoot; fw && fw->next; fw = fw->next)
	{
	  /* nop */
        }
      }
      else
      {
        /* Go to top of list */
        fw = Scr.FvwmRoot.next;
      }
    }
  }
  FreeConditionMask(&mask);

  return found;
}

void CMD_Prev(F_CMD_ARGS)
{
  FvwmWindow *found;
  char *restofline;

  found = Circulate(action, -1, &restofline);
  if(found && restofline)
  {
    old_execute_function(
      restofline, found, eventp, C_WINDOW, *Module, 0, NULL);
  }

}

void CMD_Next(F_CMD_ARGS)
{
  FvwmWindow *found;
  char *restofline;

  found = Circulate(action, 1, &restofline);
  if(found && restofline)
  {
    old_execute_function(
      restofline, found, eventp, C_WINDOW, *Module, 0, NULL);
  }

}

void CMD_None(F_CMD_ARGS)
{
  FvwmWindow *found;
  char *restofline;

  found = Circulate(action, 1, &restofline);
  if(!found && restofline)
  {
    old_execute_function(
      restofline, NULL, eventp, C_ROOT, *Module, 0, NULL);
  }
}

void CMD_Current(F_CMD_ARGS)
{
  FvwmWindow *found;
  char *restofline;

  found = Circulate(action, 0, &restofline);
  if(found && restofline)
  {
    old_execute_function(
      restofline, found, eventp, C_WINDOW, *Module, 0, NULL);
  }
}

void CMD_All(F_CMD_ARGS)
{
  FvwmWindow *t, **g;
  char *restofline;
  WindowConditionMask mask;
  char *flags;
  int num, i;

  flags = CreateFlagString(action, &restofline);
  DefaultConditionMask(&mask);
  CreateConditionMask(flags, &mask);
  if (flags)
    free(flags);
  mask.my_flags.use_circulate_hit = 1;
  mask.my_flags.use_circulate_hit_icon = 1;
  mask.my_flags.use_circulate_hit_shaded = 1;

  num = 0;
  for (t = Scr.FvwmRoot.next; t; t = t->next)
  {
    num++;
  }

  g = (FvwmWindow **) safemalloc (num * sizeof(FvwmWindow *));

  num = 0;
  for (t = Scr.FvwmRoot.next; t; t = t->next)
  {
    if (MatchesConditionMask(t, &mask))
    {
      g[num++] = t;
    }
  }

  for (i = 0; i < num; i++)
  {
    old_execute_function(
      restofline, g[i], eventp, C_WINDOW, *Module, 0, NULL);
  }

  free(g);
  FreeConditionMask(&mask);

  return;
}

static void GetDirectionReference(FvwmWindow *w, rectangle *r)
{
  if (IS_ICONIFIED(w))
    *r = w->icon_g;
  else
    *r = w->frame_g;
}

/**********************************************************************
 * Execute a function to the closest window in the given
 * direction.
 **********************************************************************/
void CMD_Direction(F_CMD_ARGS)
{
  static char *directions[] =
  {
    "North",
    "East",
    "South",
    "West",
    "NorthEast",
    "SouthEast",
    "SouthWest",
    "NorthWest",
    NULL
  };
  /* The rectangles are inteded for a future enhancement and are not used yet.
   */
  rectangle my_g;
  rectangle his_g;
  int my_cx;
  int my_cy;
  int his_cx;
  int his_cy;
  int offset = 0;
  int distance = 0;
  int score;
  int best_score;
  FvwmWindow *window;
  FvwmWindow *best_window;
  int dir;
  char *flags;
  char *restofline;
  char *tmp;
  WindowConditionMask mask;

  /* Parse the direction. */
  action = GetNextToken(action, &tmp);
  dir = GetTokenIndex(tmp, directions, 0, NULL);
  if (dir == -1)
  {
    fvwm_msg(ERR, "Direction", "Invalid direction %s", (tmp)? tmp : "");
    if (tmp)
      free(tmp);
    return;
  }
  if (tmp)
    free(tmp);

  /* Create the mask for flags */
  flags = CreateFlagString(action, &restofline);
  if (!restofline)
  {
    if (flags)
      free(flags);
    return;
  }
  DefaultConditionMask(&mask);
  CreateConditionMask(flags, &mask);
  if (flags)
    free(flags);

  /* If there is a focused window, use that as a starting point.
   * Otherwise we use the pointer as a starting point. */
  if (tmp_win)
  {
    GetDirectionReference(tmp_win, &my_g);
    my_cx = my_g.x + my_g.width / 2;
    my_cy = my_g.y + my_g.height / 2;
  }
  else
  {
    XQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild,
		  &my_g.x, &my_g.y, &JunkX, &JunkY, &JunkMask);
    my_g.width = 1;
    my_g.height = 1;
    my_cx = my_g.x;
    my_cy = my_g.y;
  }

  /* Next we iterate through all windows and choose the closest one in
   * the wanted direction.
   */
  best_window = NULL;
  best_score = -1;
  for (window = Scr.FvwmRoot.next; window; window = window->next)
  {
    /* Skip every window that does not match conditionals.
     * Skip also currently focused window.  That would be too close. :)
     */
    if (window == tmp_win || !MatchesConditionMask(window, &mask))
      continue;

    /* Calculate relative location of the window. */
    GetDirectionReference(window, &his_g);
    his_g.x -= my_cx;
    his_g.y -= my_cy;
    his_cx = his_g.x + his_g.width / 2;
    his_cy = his_g.y + his_g.height / 2;

    if (dir > 3)
    {
      int tx;
      /* Rotate the diagonals 45 degrees counterclockwise. To do this,
       * multiply the matrix /+h +h\ with the vector (x y).
       *                     \-h +h/
       * h = sqrt(0.5). We can set h := 1 since absolute distance doesn't
       * matter here. */
      tx = his_cx + his_cy;
      his_cy = -his_cx + his_cy;
      his_cx = tx;
    }
    /* Arrange so that distance and offset are positive in desired direction.
     */
    switch (dir)
    {
    case 0: /* N */
    case 2: /* S */
    case 4: /* NE */
    case 6: /* SW */
      offset = (his_cx < 0) ? -his_cx : his_cx;
      distance = (dir == 0 || dir == 4) ? -his_cy : his_cy;
      break;
    case 1: /* E */
    case 3: /* W */
    case 5: /* SE */
    case 7: /* NW */
      offset = (his_cy < 0) ? -his_cy : his_cy;
      distance = (dir == 3 || dir == 7) ? -his_cx : his_cx;
      break;
    }

    /* Target must be in given direction. */
    if (distance <= 0)
      continue;

    /* Calculate score for this window.  The smaller the better. */
    score = distance + offset;
    /* windows more than 45 degrees off the direction are heavily penalized
     * and will only be chosen if nothing else within a million pixels */
    if (offset > distance)
      score += 1000000;
    if (best_score == -1 || score < best_score)
    {
      best_window = window;
      best_score = score;
    }
  } /* for */

  if (best_window)
  {
    old_execute_function(
      restofline, best_window, eventp, C_WINDOW, *Module, 0,
      NULL);
  }

  FreeConditionMask(&mask);
}

/* A very simple function, but handy if you want to call
 * complex functions from root context without selecting a window
 * for every single function in it. */
void CMD_Pick(F_CMD_ARGS)
{
  char *restofline;
  char *flags;
  WindowConditionMask mask;

  if (DeferExecution(eventp,&w,&tmp_win,&context, CRS_SELECT,ButtonRelease))
    return;

  flags = CreateFlagString(action, &restofline);
  DefaultConditionMask(&mask);
  mask.my_flags.use_circulate_hit = 1;
  mask.my_flags.use_circulate_hit_icon = 1;
  mask.my_flags.use_circulate_hit_shaded = 1;
  CreateConditionMask(flags, &mask);
  if (flags)
    free(flags);
  if (MatchesConditionMask(tmp_win, &mask) && restofline)
  {
    old_execute_function(
      restofline, tmp_win, eventp, C_WINDOW, *Module, 0, NULL);
  }
  FreeConditionMask(&mask);
}

void CMD_ThisWindow(F_CMD_ARGS)
{
	char *restofline;
	char *flags;
	WindowConditionMask mask;

	if (!tmp_win)
	{
		return;
	}

	flags = CreateFlagString(action, &restofline);
	DefaultConditionMask(&mask);
	mask.my_flags.use_circulate_hit = 1;
	mask.my_flags.use_circulate_hit_icon = 1;
	CreateConditionMask(flags, &mask);
	if (flags)
	{
		free(flags);
	}

	if (MatchesConditionMask(tmp_win, &mask) && restofline)
	{
		old_execute_function(
			restofline, tmp_win, eventp, C_WINDOW, *Module, 0,
			NULL);
	}

	FreeConditionMask(&mask);
	return;
}

void CMD_WindowId(F_CMD_ARGS)
{
  FvwmWindow *t;
  char *token;
  char *naction;
  unsigned long win;
  Bool use_condition = False;
  Bool use_screenroot = False;
  WindowConditionMask mask;
  char *flags, *restofline;

  /* Get window ID */
  action = GetNextToken(action, &token);

  if (token && StrEquals(token, "root"))
  {
    int screen = Scr.screen;

    free(token);
    token = PeekToken(action, &naction);
    if (!token || GetIntegerArguments(token, NULL, &screen, 1) != 1)
    {
      screen = Scr.screen;
    }
    else
    {
      action = naction;
    }
    use_screenroot = True;
    if (screen < 0 || screen >= Scr.NumberOfScreens)
      screen = 0;
    win = XRootWindow(dpy, screen);
    if (win == None)
      return;
  }
  else if (token)
  {
    /* SunOS doesn't have strtoul */
    win = (unsigned long)strtol(token, NULL, 0);
    free(token);
  }
  else
  {
    win = 0;
  }

  /* Look for condition - CreateFlagString returns NULL if no '(' or '[' */
  if (!use_screenroot)
  {
    flags = CreateFlagString(action, &restofline);
    if (flags)
    {
      /* Create window mask */
      use_condition = True;
      DefaultConditionMask(&mask);

      /* override for Current [] */
      mask.my_flags.use_circulate_hit = 1;
      mask.my_flags.use_circulate_hit_icon = 1;

      CreateConditionMask(flags, &mask);
      free(flags);

      /* Relocate action */
      action = restofline;
    }
  }

  /* Search windows */
  for (t = Scr.FvwmRoot.next; t; t = t->next)
  {
    if (t->w == win)
    {
      /* do it if no conditions or the conditions match */
      if (action && (!use_condition || MatchesConditionMask(t, &mask)))
        old_execute_function(
	  action, t, eventp, C_WINDOW, *Module, 0, NULL);
      break;
    }
  }
  if (!t && !use_condition && action)
  {
    exec_func_args_type efa;

    /* The window is not managed by fvwm. Still some functions may work on it.
     */
    memset(&efa, 0, sizeof(efa));
    efa.eventp = eventp;
    efa.win = win;
    efa.action = action;
    efa.context = C_UNMANAGED;
    efa.module = *Module;
    efa.flags.is_window_unmanaged = 1;
    execute_function(&efa);
  }

  /* Tidy up */
  if (use_condition)
  {
    FreeConditionMask(&mask);
  }
}


syntax highlighted by Code2HTML, v. 0.9.1