Пример #1
0
void get_shaded_client_window_pos(
	FvwmWindow *fw, rectangle *ret_g)
{
	rectangle big_g;
	size_borders b;

	get_window_borders(fw, &b);
	big_g = (IS_MAXIMIZED(fw)) ? fw->g.max : fw->g.normal;
	get_relative_geometry(&big_g, &big_g);
	switch (SHADED_DIR(fw))
	{
	case DIR_S:
	case DIR_SW:
	case DIR_SE:
		ret_g->y = 1 - big_g.height + b.total_size.height;
		break;
	default:
		ret_g->y = 0;
		break;
	}
	switch (SHADED_DIR(fw))
	{
	case DIR_E:
	case DIR_NE:
	case DIR_SE:
		ret_g->x = 1 - big_g.width + b.total_size.width;
		break;
	default:
		ret_g->x = 0;
		break;
	}

	return;
}
Пример #2
0
/* Decorate the rectangle.  Resize and shift it according to gravity. */
void gravity_add_decoration(
	int gravity, FvwmWindow *t, rectangle *dest_g, rectangle *orig_g)
{
	size_borders b;

	get_window_borders(t, &b);
	*dest_g = *orig_g;
	gravity_resize(
		gravity, dest_g, b.total_size.width, b.total_size.height);

	return;
}
Пример #3
0
/* This function returns the geometry of the client window.  If the window is
 * shaded, the unshaded geometry is used instead. */
void get_client_geometry(
	FvwmWindow *fw, rectangle *ret_g)
{
	size_borders borders;

	get_unshaded_geometry(fw, ret_g);
	get_window_borders(fw, &borders);
	ret_g->x += borders.top_left.width;
	ret_g->y += borders.top_left.height;
	ret_g->width -= borders.total_size.width;
	ret_g->height -= borders.total_size.height;

	return;
}
Пример #4
0
/* Removes decorations from the source rectangle and moves it according to the
 * gravity specification. */
void gravity_get_naked_geometry(
	int gravity, FvwmWindow *t, rectangle *dest_g, rectangle *orig_g)
{
	int xoff;
	int yoff;
	size_borders b;

	get_window_borders(t, &b);
	gravity_get_offsets(gravity, &xoff, &yoff);
	dest_g->x = orig_g->x + ((xoff + 1) * (orig_g->width - 1)) / 2;
	dest_g->y = orig_g->y + ((yoff + 1) * (orig_g->height - 1)) / 2;
	dest_g->width = orig_g->width - b.total_size.width;
	dest_g->height = orig_g->height - b.total_size.height;

	return;
}
Пример #5
0
void get_title_geometry(
	FvwmWindow *fw, rectangle *ret_g)
{
	size_borders b;
	size_borders nt;
	int w;
	int h;

	get_window_borders(fw, &b);
	get_window_borders_no_title(fw, &nt);
	w = (ret_g->width > 0) ? ret_g->width : fw->g.frame.width;
	h = (ret_g->height > 0) ? ret_g->height : fw->g.frame.height;
	ret_g->x = nt.top_left.width;
	ret_g->y = nt.top_left.height;
	switch (GET_TITLE_DIR(fw))
	{
	case DIR_S:
		ret_g->y = h - b.bottom_right.height;
		/* fall through */
	case DIR_N:
		ret_g->width = w - b.total_size.width;
		ret_g->height = fw->title_thickness;
		break;
	case DIR_E:
		ret_g->x = w - b.bottom_right.width;
		/* fall through */
	case DIR_W:
		ret_g->width = fw->title_thickness;
		ret_g->height = h - b.total_size.height;
		break;
	default:
		break;
	}

	return;
}
Пример #6
0
/*
 *
 *  Procedure:
 *      constrain_size - adjust the given width and height to account for the
 *              constraints imposed by size hints
 */
void constrain_size(
	FvwmWindow *fw, const XEvent *e, int *widthp, int *heightp,
	int xmotion, int ymotion, int flags)
{
	size_rect min;
	size_rect max;
	size_rect inc;
	size_rect base;
	size_rect round_up;
	size_rect d;
	size_rect old;
	size_borders b;

	if (DO_DISABLE_CONSTRAIN_SIZE_FULLSCREEN(fw) == 1)
	{
		return;
	}
	if (HAS_NEW_WM_NORMAL_HINTS(fw))
	{
		/* get the latest size hints */
		XSync(dpy, 0);
		GetWindowSizeHints(fw);
		SET_HAS_NEW_WM_NORMAL_HINTS(fw, 0);
	}
	if (IS_MAXIMIZED(fw) && (flags & CS_UPDATE_MAX_DEFECT))
	{
		*widthp += fw->g.max_defect.width;
		*heightp += fw->g.max_defect.height;
	}
	/* gcc 4.1.1 warns about these not being initialized at the end,
	 * but the conditions for the use are the same...*/
	old.width = *widthp;
	old.height = *heightp;

	d.width = *widthp;
	d.height = *heightp;
	get_window_borders(fw, &b);
	d.width -= b.total_size.width;
	d.height -= b.total_size.height;

	min.width = fw->hints.min_width;
	min.height = fw->hints.min_height;
	if (min.width < fw->min_window_width - b.total_size.width)
	{
		min.width = fw->min_window_width - b.total_size.width;
	}
	if (min.height < fw->min_window_height - b.total_size.height)
	{
		min.height =
			fw->min_window_height - b.total_size.height;
	}

	max.width = fw->hints.max_width;
	max.height =  fw->hints.max_height;
	if (max.width > fw->max_window_width - b.total_size.width)
	{
		max.width = fw->max_window_width - b.total_size.width;
	}
	if (max.height > fw->max_window_height - b.total_size.height)
	{
		max.height =
			fw->max_window_height - b.total_size.height;
	}

	if (min.width > max.width)
	{
		min.width = max.width;
	}
	if (min.height > max.height)
	{
		min.height = max.height;
	}

	base.width = fw->hints.base_width;
	base.height = fw->hints.base_height;

	inc.width = fw->hints.width_inc;
	inc.height = fw->hints.height_inc;

	/*
	 * First, clamp to min and max values
	 */
	if (d.width < min.width)
	{
		d.width = min.width;
	}
	if (d.height < min.height)
	{
		d.height = min.height;
	}
	if (d.width > max.width)
	{
		d.width = max.width;
	}
	if (d.height > max.height)
	{
		d.height = max.height;
	}

	/*
	 * Second, round to base + N * inc (up or down depending on resize
	 * type) if rounding up store amount
	 */
	if (!(flags & CS_ROUND_UP))
	{
		d.width = ((d.width - base.width) / inc.width) *
			inc.width + base.width;
		d.height = ((d.height - base.height) / inc.height) *
			inc.height + base.height;
	}
	else
	{
		round_up.width = d.width;
		round_up.height = d.height;
		d.width = ((d.width - base.width + inc.width - 1) /
			   inc.width) * inc.width + base.width;
		d.height = ((d.height - base.height + inc.height - 1) /
			    inc.height) * inc.height + base.height;
		round_up.width = d.width - round_up.width;
		round_up.height = d.height - round_up.height;
	}

	/*
	 * Step 2a: check we didn't move the edge off screen in interactive
	 * moves
	 */
	if ((flags & CS_ROUND_UP) && e != NULL && e->type == MotionNotify)
	{
		if (xmotion > 0 && e->xmotion.x_root < round_up.width)
		{
			d.width -= inc.width;
		}
		else if (
			xmotion < 0 && e->xmotion.x_root >=
			Scr.MyDisplayWidth - round_up.width)
		{
			d.width -= inc.width;
		}
		if (ymotion > 0 && e->xmotion.y_root < round_up.height)
		{
			d.height -= inc.height;
		}
		else if (
			ymotion < 0 && e->xmotion.y_root >=
			Scr.MyDisplayHeight - round_up.height)
		{
			d.height -= inc.height;
		}
	}

	/*
	 * Step 2b: Check that we didn't violate min and max.
	 */
	if (d.width < min.width)
	{
		d.width += inc.width;
	}
	if (d.height < min.height)
	{
		d.height += inc.height;
	}
	if (d.width > max.width)
	{
		d.width -= inc.width;
	}
	if (d.height > max.height)
	{
		d.height -= inc.height;
	}

	/*
	 * Third, adjust for aspect ratio
	 */
	if (fw->hints.flags & PAspect)
	{
		__cs_handle_aspect_ratio(
			&d, fw, d, base, inc, min, max, xmotion, ymotion,
			flags);
	}

	/*
	 * Fourth, account for border width and title height
	 */
	*widthp = d.width + b.total_size.width;
	*heightp = d.height + b.total_size.height;
	if (IS_MAXIMIZED(fw) && (flags & CS_UPDATE_MAX_DEFECT))
	{
		/* update size defect for maximized window */
		fw->g.max_defect.width = old.width - *widthp;
		fw->g.max_defect.height = old.height - *heightp;
	}

	return;
}
Пример #7
0
void get_shaded_geometry(
	FvwmWindow *fw, rectangle *small_g, rectangle *big_g)
{
	size_borders b;
	/* this variable is necessary so the function can be called with
	 * small_g == big_g */
	int big_width = big_g->width;
	int big_height = big_g->height;
	int d;

	switch (SHADED_DIR(fw))
	{
	case DIR_SW:
	case DIR_SE:
	case DIR_NW:
	case DIR_NE:
		get_window_borders_no_title(fw, &b);
		break;
	default:
		get_window_borders(fw, &b);
		break;
	}
	*small_g = *big_g;
	d = 0;
	switch (SHADED_DIR(fw))
	{
	case DIR_S:
	case DIR_SW:
	case DIR_SE:
		small_g->y = big_g->y + big_height - b.total_size.height;
		d = 1;
		/* fall through */
	case DIR_N:
	case DIR_NW:
	case DIR_NE:
		small_g->height = b.total_size.height;
		if (small_g->height == 0)
		{
			small_g->height = 1;
			small_g->y -= d;
		}
		break;
	default:
		break;
	}
	d = 0;
	switch (SHADED_DIR(fw))
	{
	case DIR_E:
	case DIR_NE:
	case DIR_SE:
		small_g->x = big_g->x + big_width - b.total_size.width;
		d = 1;
		/* fall through */
	case DIR_W:
	case DIR_NW:
	case DIR_SW:
		small_g->width = b.total_size.width;
		if (small_g->width == 0)
		{
			small_g->width = 1;
			small_g->x -= d;
		}
		break;
	default:
		break;
	}

	return;
}
Пример #8
0
/*
 * Change by PRB ([email protected]), 31/10/93.  Prepend a hot key
 * specifier to each item in the list.  This means allocating the
 * memory for each item (& freeing it) rather than just using the window
 * title directly. */
void CMD_WindowList(F_CMD_ARGS)
{
	struct MenuRoot *mr;
	struct MenuParameters mp;
	char* ret_action = NULL;
	FvwmWindow *t;
	FvwmWindow **windowList;
	FvwmWindow **iconifiedList = NULL;
	int numWindows;
	int ii;
	char tname[128];
	char loc[64];
	char *name=NULL;
	Bool free_name = False;
	int dwidth;
	int dheight;
	char *tlabel;
	int last_desk_done = INT_MIN;
	int last_desk_displayed = INT_MIN;
	int next_desk = 0;
	char *t_hot=NULL;             /* Menu label with hotkey added */
	char scut = '0';              /* Current short cut key */
	char *opts=NULL;
	char *tok=NULL;
	int desk = Scr.CurrentDesk;
	unsigned long flags = SHOW_DEFAULT;
	char *func = NULL;
	char *ffunc = NULL;
	char *tfunc = NULL;
	char *default_action = NULL;
	MenuReturn mret;
	MenuOptions mops;
	int low_layer = 0;  /* show all layers by default */
	int high_layer = INT_MAX;
	int max_label_width = 0;
	int skiplist_mode = 0; /* do not show skiplist by default */
	Bool use_hotkey = True;
	KeyCode old_sor_keycode;
	char sor_default_keyname[8] = { 'M', 'e', 't', 'a', '_', 'L' };
	char *sor_keyname = sor_default_keyname;
	/* Condition vars. */
	Bool use_condition = False;
	Bool current_at_end = False;
	Bool iconified_at_end = False;
	int ic = 0;
	int ij;
	WindowConditionMask mask;
	char *cond_flags;
	Bool first_desk = True;
	Bool empty_menu = True;
	Bool was_get_menu_opts_called = False;
	FvwmWindow * const fw = exc->w.fw;
	const Window w = exc->w.w;
	const exec_context_t *exc2;

	memset(&mops, 0, sizeof(mops));
	memset(&mret, 0, sizeof(MenuReturn));
	/* parse postitioning args - must call this even if no action is given
	 * because it sets the xinerama screen origin */
	if (action && *action)
	{
		/* Look for condition - CreateFlagString returns NULL if no '('
		 * or '[' */
		cond_flags = CreateFlagString(action, &action);
		if (cond_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(cond_flags, &mask);
			free(cond_flags);
		}
		opts = get_menu_options(
			action, w, fw, NULL, NULL, NULL, &mops);
		was_get_menu_opts_called = True;

		/* parse options */
		while (opts && *opts)
		{
			opts = GetNextSimpleOption(opts, &tok);
			if (!tok)
			{
				break;
			}

			if (StrEquals(tok,"NoHotkeys"))
			{
				use_hotkey = False;
			}
			else if (StrEquals(tok,"Function"))
			{
				opts = GetNextSimpleOption(opts, &func);
			}
			else if (StrEquals(tok,"Desk"))
			{
				free(tok);
				opts = GetNextSimpleOption(opts, &tok);
				if (tok)
				{
					desk = atoi(tok);
					flags &= ~SHOW_ALLDESKS;
				}
			}
			else if (StrEquals(tok,"CurrentDesk"))
			{
				desk = Scr.CurrentDesk;
				flags &= ~SHOW_ALLDESKS;
			}
			else if (StrEquals(tok,"NotAlphabetic"))
			{
				flags &= ~SHOW_ALPHABETIC;
			}
			else if (StrEquals(tok,"Alphabetic"))
			{
				flags |= SHOW_ALPHABETIC;
			}
			else if (StrEquals(tok,"SortByClass"))
			{
				flags |= SORT_BYCLASS;
			}
			else if (StrEquals(tok,"SortByResource"))
			{
				flags |= SORT_BYRESOURCE;
			}
			else if (StrEquals(tok,"ReverseOrder"))
			{
				flags |= SORT_REVERSE;
			}
			else if (StrEquals(tok,"CurrentAtEnd"))
			{
				current_at_end = True;
			}
			else if (StrEquals(tok,"IconifiedAtEnd"))
			{
				iconified_at_end = True;
			}
			else if (StrEquals(tok,"NoDeskSort"))
			{
				flags |= NO_DESK_SORT;
			}
			else if (StrEquals(tok,"ShowPage"))
			{
				flags |= SHOW_PAGE_X | SHOW_PAGE_Y;
			}
			else if (StrEquals(tok,"ShowPageX"))
			{
				flags |= SHOW_PAGE_X;
			}
			else if (StrEquals(tok,"ShowPageY"))
			{
				flags |= SHOW_PAGE_Y;
			}
			else if (StrEquals(tok,"ShowScreen"))
			{
				flags |= SHOW_SCREEN;
			}
			else if (StrEquals(tok,"UseIconName"))
			{
				flags |= SHOW_ICONNAME;
			}
			else if (StrEquals(tok,"NoGeometry"))
			{
				flags &= ~SHOW_GEOMETRY;
				flags &= ~SHOW_INFONOTGEO;
			}
			else if (StrEquals(tok,"NoGeometryWithInfo"))
			{
				flags &= ~SHOW_GEOMETRY;
				flags |= SHOW_INFONOTGEO;
			}
			else if (StrEquals(tok,"Geometry"))
			{
				flags |= SHOW_GEOMETRY;
				flags &= ~SHOW_INFONOTGEO;
			}
			else if (StrEquals(tok,"NoIcons"))
			{
				flags &= ~SHOW_ICONIC;
			}
			else if (StrEquals(tok,"Icons"))
			{
				flags |= SHOW_ICONIC;
			}
			else if (StrEquals(tok,"OnlyIcons"))
			{
				flags = SHOW_ICONIC;
			}
			else if (StrEquals(tok,"NoNormal"))
			{
				flags &= ~SHOW_NORMAL;
			}
			else if (StrEquals(tok,"Normal"))
			{
				flags |= SHOW_NORMAL;
			}
			else if (StrEquals(tok,"OnlyNormal"))
			{
				flags = SHOW_NORMAL;
			}
			else if (StrEquals(tok,"NoSticky"))
			{
				flags &= ~(SHOW_STICKY_ACROSS_PAGES);
				flags &= ~(SHOW_STICKY_ACROSS_DESKS);
			}
			else if (StrEquals(tok,"NoStickyPage"))
			{
				flags &= ~(SHOW_STICKY_ACROSS_PAGES);
			}
			else if (StrEquals(tok,"NoStickyDesk"))
			{
				flags &= ~(SHOW_STICKY_ACROSS_DESKS);
			}
			else if (StrEquals(tok,"Sticky"))
			{
				flags |= SHOW_STICKY_ACROSS_PAGES;
				flags |= SHOW_STICKY_ACROSS_DESKS;
			}
			else if (StrEquals(tok,"StickyPage"))
			{
				flags |= SHOW_STICKY_ACROSS_PAGES;
			}
			else if (StrEquals(tok,"StickyDesk"))
			{
				flags |= SHOW_STICKY_ACROSS_DESKS;
			}
			else if (StrEquals(tok,"OnlySticky"))
			{
				flags = SHOW_STICKY_ACROSS_PAGES;
				flags = SHOW_STICKY_ACROSS_DESKS;
			}
			else if (StrEquals(tok,"OnlyStickyPage"))
			{
				flags = SHOW_STICKY_ACROSS_PAGES;
			}
			else if (StrEquals(tok,"OnlyStickyDesk"))
			{
				flags = SHOW_STICKY_ACROSS_DESKS;
			}
			else if (StrEquals(tok,"UseListSkip"))
			{
				/* deprecated as of 02-May-2007 (SS) */
				fprintf(stderr, "UseListSkip is deprecated. Please use \"UseSkipList\".\n");
				skiplist_mode = 1;
			}
			else if (StrEquals(tok,"UseSkipList"))
			{
				skiplist_mode = 1;
			}
			else if (StrEquals(tok,"OnlyListSkip"))
			{
				/* deprecated as of 02-May-2007 (SS) */
				fprintf(stderr, "OnlyListSkip is deprecated. Please use \"OnlySkipList\".\n");
				skiplist_mode = 2;
			}
			else if (StrEquals(tok,"OnlySkipList"))
			{
				skiplist_mode = 2;
			}
			else if (StrEquals(tok,"NoDeskNum"))
			{
				flags |= NO_DESK_NUM;
			}
			else if (StrEquals(tok,"NoLayer"))
			{
				flags |= NO_LAYER;
			}
			else if (StrEquals(tok,"NoCurrentDeskTitle"))
			{
				flags |= NO_CURRENT_DESK_TITLE;
			}
			else if (StrEquals(tok,"TitleForAllDesks"))
			{
				flags |= TITLE_FOR_ALL_DESKS;
			}
			else if (StrEquals(tok,"NoNumInDeskTitle"))
			{
				flags |= NO_NUM_IN_DESK_TITLE;
			}
			/* these are a bit dubious, but we should keep the
			 * OnTop options for compatibility */
			else if (StrEquals(tok, "NoOnTop"))
			{
				if (high_layer >= Scr.TopLayer)
				{
					high_layer = Scr.TopLayer - 1;
				}
			}
			else if (StrEquals(tok, "OnTop"))
			{
				if (high_layer < Scr.TopLayer)
				{
					high_layer = Scr.TopLayer;
				}
			}
			else if (StrEquals(tok, "OnlyOnTop"))
			{
				high_layer = low_layer = Scr.TopLayer;
			}
			else if (StrEquals(tok, "NoOnBottom"))
			{
				if (low_layer <= Scr.BottomLayer)
				{
					low_layer = Scr.BottomLayer - 1;
				}
			}
			else if (StrEquals(tok, "OnBottom"))
			{
				if (low_layer > Scr.BottomLayer)
				{
					low_layer = Scr.BottomLayer;
				}
			}
			else if (StrEquals(tok, "OnlyOnBottom"))
			{
				high_layer = low_layer = Scr.BottomLayer;
			}
			else if (StrEquals(tok, "Layer"))
			{
				free(tok);
				opts = GetNextSimpleOption(opts, &tok);
				if (tok)
				{
					low_layer = high_layer = atoi(tok);
					free(tok);
					opts = GetNextSimpleOption(opts, &tok);
					if (tok)
					{
						high_layer = atoi(tok);
					}
				}
			}
			else if (StrEquals(tok, "SelectOnRelease"))
			{
				if (sor_keyname != sor_default_keyname)
				{
					free(sor_keyname);
				}
				sor_keyname = NULL;
				opts = GetNextSimpleOption(opts, &sor_keyname);
			}
			else if (StrEquals(tok, "MaxLabelWidth"))
			{
				char *wid;

				opts = GetNextSimpleOption(opts, &wid);
				if (wid)
				{
					max_label_width = atoi(wid);
					if (max_label_width < 1)
					{
						max_label_width = 1;
					}
					free(wid);
				}
			}
			else if (!opts || !*opts)
			{
				default_action = safestrdup(tok);
			}
			else
			{
				fvwm_msg(
					ERR, "WindowList","Unknown option '%s'",
					tok);
			}
			if (tok)
			{
				free(tok);
			}
		}
	}
	if (was_get_menu_opts_called == False)
	{
		opts = get_menu_options(
			action, w, fw, NULL, NULL, NULL, &mops);
	}

	tlabel = get_desk_title(desk, flags, True);
	mr = NewMenuRoot(tlabel);
	if (!(flags & NO_CURRENT_DESK_TITLE))
	{
		AddToMenu(mr, tlabel, "TITLE", False, False, False);
		empty_menu = False;
	}
	free(tlabel);

	numWindows = 0;
	for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
	{
		numWindows++;
	}
	windowList = malloc(numWindows*sizeof(t));
	if (windowList == NULL)
	{
		return;
	}
	if (iconified_at_end)
	{
		iconifiedList = malloc(numWindows*sizeof(t));
		if (iconifiedList == NULL)
		{
			free(windowList);
			return;
		}
	}
	/* get the windowlist starting from the current window (if any)*/
	t = get_focus_window();
	if (t == NULL)
	{
		t = Scr.FvwmRoot.next;
	}
	else if (current_at_end)
	{
		if (t->next)
		{
			t = t->next;
		}
		else
		{
			t = Scr.FvwmRoot.next;
		}
	}
	for (ii = 0; ii < numWindows; ii++)
	{
		if (flags & SORT_REVERSE)
		{
			windowList[numWindows - ii - 1] = t;
		}
		else if (iconified_at_end && IS_ICONIFIED(t))
		{
			iconifiedList[ic++] = t;
		}
		else
		{
			windowList[ii - ic] = t;
		}
		if (t->next)
		{
			t = t->next;
		}
		else
		{
			t = Scr.FvwmRoot.next;
		}
	}
	if (iconified_at_end && ic > 0)
	{
		if (current_at_end && ii > ic)
		{
			windowList[numWindows - 1] = windowList[--ii - ic];
		}
		for (ij = 0; ij < ic; ij++)
		{
			windowList[ij + (ii - ic)] = iconifiedList[ij];
		}
	}

	/* Do alphabetic sort */
	if (flags & (SHOW_ALPHABETIC | SORT_BYCLASS | SORT_BYRESOURCE))
	{
		/* This will be compare or compareReverse if a reverse order
		 * is selected. */
		int (*sort)(const FvwmWindow **a, const FvwmWindow **b);

		switch (flags & (SHOW_ALPHABETIC | SHOW_ICONNAME | \
			SORT_BYCLASS | SORT_BYRESOURCE))
		{
		case SHOW_ALPHABETIC:
			compare = visibleCompare;
			break;
		case SHOW_ALPHABETIC | SHOW_ICONNAME:
			compare = iconCompare;
			break;
		/* Sorting based on class name produces an alphabetic
		 * order so the keyword alphabetic is redundant. */
		case SORT_BYCLASS:
		case SORT_BYCLASS | SHOW_ALPHABETIC:
			compare = classCompare;
			break;
		case SORT_BYCLASS | SHOW_ICONNAME:
		case SORT_BYCLASS | SHOW_ICONNAME | SHOW_ALPHABETIC:
			compare = classIconCompare;
			break;
		case SORT_BYRESOURCE:
		case SORT_BYRESOURCE | SORT_BYCLASS:
		case SORT_BYRESOURCE | SORT_BYCLASS | SHOW_ALPHABETIC:
			compare = resourceCompare;
			break;
		case SORT_BYRESOURCE | SHOW_ICONNAME:
		case SORT_BYRESOURCE | SHOW_ICONNAME | SORT_BYCLASS:
		case SORT_BYRESOURCE | SHOW_ICONNAME | SORT_BYCLASS | \
		SHOW_ALPHABETIC:
			compare = resourceIconCompare;
			break;

		/* All current cases are covered, but if something
		 * changes in the future we leave compare valid even if
		 * it isn't what is expected. */
		default:
			compare = visibleCompare;
			break;
		}

		if ( flags & SORT_REVERSE )
		{
			sort = compareReverse;
		}
		else
		{
			sort = compare;
		}
		qsort(windowList, numWindows, sizeof(t),
		      (int(*)(const void*, const void*))sort);
	}

	while(next_desk != INT_MAX)
	{
		/* Sort window list by desktop number */
		if ((flags & SHOW_ALLDESKS) && !(flags & NO_DESK_SORT))
		{
			/* run through the windowlist finding the first desk
			 * not already processed */
			next_desk = INT_MAX;
			for (ii = 0; ii < numWindows; ii++)
			{
				t = windowList[ii];
				if (t->Desk >last_desk_done &&
				    t->Desk < next_desk)
				{
					next_desk = t->Desk;
				}
			}
		}
		if (!(flags & SHOW_ALLDESKS))
		{
			/* if only doing one desk and it hasn't been done */
			if (last_desk_done  == INT_MIN)
				next_desk = desk; /* select the desk */
			else
				next_desk = INT_MAX; /* flag completion */
		}
		if (flags & NO_DESK_SORT)
			next_desk = INT_MAX; /* only go through loop once */

		last_desk_done = next_desk;
		for (ii = 0; ii < numWindows; ii++)
		{
			t = windowList[ii];
			if (t->Desk != next_desk && !(flags & NO_DESK_SORT))
			{
				continue;
			}
			if (skiplist_mode == 0 && DO_SKIP_WINDOW_LIST(t))
			{
				/* don't want skiplist windows - skip */
				continue;
			}
			if (skiplist_mode == 2 && !DO_SKIP_WINDOW_LIST(t))
			{
				/* don't want no skiplist one - skip */
				continue;
			}
			if (use_condition && !MatchesConditionMask(t, &mask))
			{
				/* doesn't match specified condition */
				continue;
			}
			if (!(flags & SHOW_ICONIC) && (IS_ICONIFIED(t)))
			{
				/* don't want icons - skip */
				continue;
			}
			if (!(flags & SHOW_STICKY_ACROSS_PAGES) &&
			    (IS_STICKY_ACROSS_PAGES(t)))
			{
				/* don't want sticky ones - skip */
				continue;
			}
			if (!(flags & SHOW_STICKY_ACROSS_DESKS) &&
			    (IS_STICKY_ACROSS_DESKS(t)))
			{
				/* don't want sticky ones - skip */
				continue;
			}
			if (!(flags & SHOW_NORMAL) &&
			    !(IS_ICONIFIED(t) ||
			      IS_STICKY_ACROSS_PAGES(t) ||
			      IS_STICKY_ACROSS_DESKS(t)))
			{
				/* don't want "normal" ones - skip */
				continue;
			}
			if (get_layer(t) < low_layer ||
			    get_layer(t) > high_layer)
			{
				/* don't want this layer */
				continue;
			}

			empty_menu = False;
			/* add separator between desks when geometry
			 * shown but not at the top*/
			if (t->Desk != last_desk_displayed)
			{
				if (last_desk_displayed != INT_MIN)
				{
					if (((flags & SHOW_GEOMETRY) ||
					     (flags & SHOW_INFONOTGEO)) &&
					    !(flags & TITLE_FOR_ALL_DESKS))
					{
						AddToMenu(
							mr, NULL, NULL, False,
							False, False);
					}
					if (flags & TITLE_FOR_ALL_DESKS)
					{
						tlabel = get_desk_title(
							t->Desk, flags, False);
						AddToMenu(
							mr, tlabel, "TITLE",
							False, False, False);
						free(tlabel);
					}
				}
				last_desk_displayed = t->Desk;
			}
			if (first_desk && flags & TITLE_FOR_ALL_DESKS)
			{
				tlabel = get_desk_title(t->Desk, flags, False);
				AddToMenu(
					mr, tlabel, "TITLE", False, False,
					False);
				free(tlabel);
			}
			first_desk = False;

			if (flags & SHOW_ICONNAME)
			{
				name = t->visible_icon_name;
			}
			else
			{
				name = t->visible_name;
			}

			free_name = False;
			if (!name)
			{
				name = "NULL_NAME";
			}
			else if (max_label_width > 0 &&
				 strlen(name) > max_label_width)
			{
				name = strdup(name);
				name[max_label_width] = '\0';
				free_name = True;
			}

			t_hot = safemalloc(strlen(name) + 80);
			if (use_hotkey)
			{
				/* Generate label */
				sprintf(t_hot, "&%c. ", scut);
			}
			else
			{
				*t_hot = 0;
			}
			if (!(flags & SHOW_INFONOTGEO))
			{
				strcat(t_hot, name);
			}
			if (*t_hot == 0)
			{
				strcpy(t_hot, " ");
			}

			/* Next shortcut key */
			if (scut == '9')
			{
				scut = 'A';
			}
			else if (scut == 'Z')
			{
				scut = '0';
			}
			else
			{
				scut++;
			}

			if (flags & SHOW_INFONOTGEO)
			{
				tname[0]=0;
				if (!IS_ICONIFIED(t) &&
				    !(flags & NO_DESK_NUM))
				{
					sprintf(loc,"%d:", t->Desk);
					strcat(tname,loc);
				}
				if (IS_ICONIFIED(t))
				{
					strcat(tname, "(");
				}
				strcat(t_hot,"\t");
				strcat(t_hot,tname);
				strcat(t_hot, name);
				if (IS_ICONIFIED(t))
				{
					strcat(t_hot, ")");
				}
			}
			else if (flags & SHOW_GEOMETRY)
			{
				size_borders b;

				tname[0]=0;
				if (IS_ICONIFIED(t))
				{
					strcpy(tname, "(");
				}
				if (!(flags & NO_DESK_NUM))
				{
					sprintf(loc, "%d", t->Desk);
					strcat(tname, loc);
				}
				if (flags & SHOW_SCREEN)
				{
					fscreen_scr_arg fscr;
					int scr;

					fscr.xypos.x =
						Scr.Vx + t->g.frame.x +
						t->g.frame.width / 2;
					fscr.xypos.y =
						Scr.Vy + t->g.frame.y +
						t->g.frame.height / 2;
					scr = FScreenGetScrId(
						&fscr, FSCREEN_XYPOS);
					sprintf(loc, "@%d", scr);
					strcat(tname, loc);
				}
				if (flags & SHOW_PAGE_X)
				{
					sprintf(loc, "+%d",
						(Scr.Vx + t->g.frame.x +
						 t->g.frame.width / 2) /
						Scr.MyDisplayWidth);
					strcat(tname, loc);
				}
				if (flags & SHOW_PAGE_Y)
				{
					sprintf(loc, "+%d",
						(Scr.Vy + t->g.frame.y +
						 t->g.frame.height/2) /
						Scr.MyDisplayHeight);
					strcat(tname, loc);
				}
				if (!(flags & NO_LAYER))
				{
					sprintf(loc, "(%d)",
						(get_layer(t)));
					strcat(tname, loc);
				}
				strcat(tname, ":");
				get_window_borders(t, &b);
				dheight = t->g.frame.height -
					b.total_size.height;
				dwidth = t->g.frame.width -
					b.total_size.width;

				dwidth = (dwidth - t->hints.base_width)
					  /t->orig_hints.width_inc;
				dheight = (dheight - t->hints.base_height)
					  /t->orig_hints.height_inc;

				sprintf(loc,"%d",dwidth);
				strcat(tname, loc);
				sprintf(loc,"x%d",dheight);
				strcat(tname, loc);
				if (t->g.frame.x >=0)
				{
					sprintf(loc,"+%d",t->g.frame.x);
				}
				else
				{
					sprintf(loc,"%d",t->g.frame.x);
				}
				strcat(tname, loc);
				if (t->g.frame.y >=0)
				{
					sprintf(loc,"+%d",t->g.frame.y);
				}
				else
				{
					sprintf(loc,"%d",t->g.frame.y);
				}
				strcat(tname, loc);

				if (IS_STICKY_ACROSS_PAGES(t) ||
				    IS_STICKY_ACROSS_DESKS(t))
				{
					strcat(tname, " S");
				}
				if (IS_ICONIFIED(t))
				{
					strcat(tname, ")");
				}
				strcat(t_hot,"\t");
				strcat(t_hot,tname);
			}
			ffunc = func ? func : "WindowListFunc";
			tfunc = safemalloc(strlen(ffunc) + 36);
			/* support two ways for now: window context
			 * (new) and window id param (old) */
			sprintf(tfunc, "WindowId %lu %s %lu",
				FW_W(t), ffunc, FW_W(t));
			AddToMenu(
				mr, t_hot, tfunc, False, False, False);
			free(tfunc);
			/* Add the title pixmap */
			if (FMiniIconsSupported && t->mini_icon)
			{
				MI_MINI_ICON(MR_LAST_ITEM(mr))[0] =
					t->mini_icon;
				/* increase the cache count. Otherwise the
				 * pixmap will be eventually removed from the
				 * cache by DestroyMenu */
				t->mini_icon->count++;
			}
			if (t_hot)
			{
				free(t_hot);
			}
			if (free_name)
			{
				free(name);
			}
		}
	}

	if (empty_menu)
	{
		/* force current desk title */
		tlabel = get_desk_title(desk, flags, True);
		AddToMenu(mr, tlabel, "TITLE", False, False, False);
		free(tlabel);
	}

	if (func)
	{
		free(func);
	}
	free(windowList);
	if (iconified_at_end)
	{
		free(iconifiedList);
	}
	/* Use the WindowList menu style if there is one */
	change_mr_menu_style(mr, "WindowList");

	/* Activate select_on_release style */
	old_sor_keycode = MST_SELECT_ON_RELEASE_KEY(mr);
	if (sor_keyname &&
	    (!MST_SELECT_ON_RELEASE_KEY(mr) ||
	     sor_keyname != sor_default_keyname))
	{
		MST_SELECT_ON_RELEASE_KEY(mr) =
			XKeysymToKeycode(
				dpy, FvwmStringToKeysym(dpy, sor_keyname));
	}

	memset(&mp, 0, sizeof(mp));
	mp.menu = mr;
	exc2 = exc_clone_context(exc, NULL, 0);
	mp.pexc = &exc2;
	mp.flags.has_default_action = (default_action && *default_action != 0);
	mp.flags.is_sticky = 1;
	mp.flags.is_submenu = 0;
	mp.flags.is_already_mapped = 0;
	mp.flags.is_triggered_by_keypress =
		(!default_action && exc->x.etrigger->type == KeyPress);
	mp.pops = &mops;
	mp.ret_paction = &ret_action;
	do_menu(&mp, &mret);
	/* Restore old menu style */
	MST_SELECT_ON_RELEASE_KEY(mr) = old_sor_keycode;
	if (ret_action)
	{
		free(ret_action);
	}
	DestroyMenu(mr, False, False);
	if (mret.rc == MENU_DOUBLE_CLICKED &&
	    default_action && *default_action)
	{
		execute_function(cond_rc, exc2, default_action, 0);
	}
	if (default_action != NULL)
	{
		free(default_action);
	}
	if (use_condition)
	{
		FreeConditionMask(&mask);
	}
	if (sor_keyname && sor_keyname != sor_default_keyname)
	{
		free(sor_keyname);
	}
	exc_destroy_context(exc2);

	return;
}