11c5ac21333f543680ce306d46f287d62c175d873mridge/*
21c5ac21333f543680ce306d46f287d62c175d873mridge * Add more stress to X server by moving, resizing and activating windows
31c5ac21333f543680ce306d46f287d62c175d873mridge * Author: Darrick Wong <djwong@us.ibm.com>
41c5ac21333f543680ce306d46f287d62c175d873mridge */
51c5ac21333f543680ce306d46f287d62c175d873mridge
61e6f5a673655551de5734ff31ef48cd63b604e6dGarrett Cooper/*
71c5ac21333f543680ce306d46f287d62c175d873mridge * Copyright (C) 2003-2006 IBM
81e6f5a673655551de5734ff31ef48cd63b604e6dGarrett Cooper *
91c5ac21333f543680ce306d46f287d62c175d873mridge * This program is free software; you can redistribute it and/or
101c5ac21333f543680ce306d46f287d62c175d873mridge * modify it under the terms of the GNU General Public License as
111c5ac21333f543680ce306d46f287d62c175d873mridge * published by the Free Software Foundation; either version 2 of the
121c5ac21333f543680ce306d46f287d62c175d873mridge * License, or (at your option) any later version.
131c5ac21333f543680ce306d46f287d62c175d873mridge *
141c5ac21333f543680ce306d46f287d62c175d873mridge * This program is distributed in the hope that it will be useful, but
151c5ac21333f543680ce306d46f287d62c175d873mridge * WITHOUT ANY WARRANTY; without even the implied warranty of
161c5ac21333f543680ce306d46f287d62c175d873mridge * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
171c5ac21333f543680ce306d46f287d62c175d873mridge * General Public License for more details.
181e6f5a673655551de5734ff31ef48cd63b604e6dGarrett Cooper *
191c5ac21333f543680ce306d46f287d62c175d873mridge * You should have received a copy of the GNU General Public License
201c5ac21333f543680ce306d46f287d62c175d873mridge * along with this program; if not, write to the Free Software
211c5ac21333f543680ce306d46f287d62c175d873mridge * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
221c5ac21333f543680ce306d46f287d62c175d873mridge * 02111-1307, USA.
231c5ac21333f543680ce306d46f287d62c175d873mridge */
241c5ac21333f543680ce306d46f287d62c175d873mridge
251c5ac21333f543680ce306d46f287d62c175d873mridge#include <stdio.h>
261c5ac21333f543680ce306d46f287d62c175d873mridge#include <sys/types.h>
271c5ac21333f543680ce306d46f287d62c175d873mridge#include <sys/stat.h>
281c5ac21333f543680ce306d46f287d62c175d873mridge#include <fcntl.h>
291c5ac21333f543680ce306d46f287d62c175d873mridge#include <unistd.h>
301c5ac21333f543680ce306d46f287d62c175d873mridge#include <stdlib.h>
311c5ac21333f543680ce306d46f287d62c175d873mridge#include <X11/Xlib.h>
321c5ac21333f543680ce306d46f287d62c175d873mridge#include <X11/Xatom.h>
331c5ac21333f543680ce306d46f287d62c175d873mridge#include <string.h>
341c5ac21333f543680ce306d46f287d62c175d873mridge#include <stdint.h>
351c5ac21333f543680ce306d46f287d62c175d873mridge#include <limits.h>
361c5ac21333f543680ce306d46f287d62c175d873mridge
371c5ac21333f543680ce306d46f287d62c175d873mridgestatic int enable_fullscreen = 0;
381c5ac21333f543680ce306d46f287d62c175d873mridge
391c5ac21333f543680ce306d46f287d62c175d873mridge#define MAX_PROPERTY_VALUE_LEN	4096
401c5ac21333f543680ce306d46f287d62c175d873mridge#define _NET_WM_STATE_TOGGLE	2
411c5ac21333f543680ce306d46f287d62c175d873mridge#define SLIDE_THRESHOLD 	32
421c5ac21333f543680ce306d46f287d62c175d873mridge
431c5ac21333f543680ce306d46f287d62c175d873mridge/* We assume that the workspace number will either be -1 or some
441c5ac21333f543680ce306d46f287d62c175d873mridge * huge number for "On All Workspaces" windows.  Presumably there
451c5ac21333f543680ce306d46f287d62c175d873mridge * aren't 1,000,000 workspaces, so that should be a safe number.
461c5ac21333f543680ce306d46f287d62c175d873mridge */
471c5ac21333f543680ce306d46f287d62c175d873mridge#define DESKTOP_MAX		1000000
481c5ac21333f543680ce306d46f287d62c175d873mridge
491c5ac21333f543680ce306d46f287d62c175d873mridge#define ACTION_MOVE_WINDOW		0
501c5ac21333f543680ce306d46f287d62c175d873mridge#define ACTION_ACTIVATE_WINDOW		1
511c5ac21333f543680ce306d46f287d62c175d873mridge#define ACTION_MAXIMIZE_WINDOW		2
521c5ac21333f543680ce306d46f287d62c175d873mridge#define ACTION_FULLSCREEN_WINDOW	3
531c5ac21333f543680ce306d46f287d62c175d873mridge#define ACTION_HIDDEN_WINDOW		4
541c5ac21333f543680ce306d46f287d62c175d873mridge#define ACTION_SLIDE_WINDOW_0		5
551c5ac21333f543680ce306d46f287d62c175d873mridge#define ACTION_SLIDE_WINDOW_1		6
561c5ac21333f543680ce306d46f287d62c175d873mridge#define ACTION_SLIDE_WINDOW_2		7
571c5ac21333f543680ce306d46f287d62c175d873mridge#define ACTION_SLIDE_WINDOW_3		8
581c5ac21333f543680ce306d46f287d62c175d873mridge#define ACTION_SLIDE_WINDOW_4		9
591c5ac21333f543680ce306d46f287d62c175d873mridge#define ACTION_SLIDE_WINDOW_5		10
601c5ac21333f543680ce306d46f287d62c175d873mridge#define ACTION_MIN		ACTION_MOVE_WINDOW
611c5ac21333f543680ce306d46f287d62c175d873mridge#define ACTION_MAX		ACTION_SLIDE_WINDOW_5
621c5ac21333f543680ce306d46f287d62c175d873mridge
631c5ac21333f543680ce306d46f287d62c175d873mridge/* The goal of this program:
641c5ac21333f543680ce306d46f287d62c175d873mridge * 0. Seed random number generator
651c5ac21333f543680ce306d46f287d62c175d873mridge * 1. Grab the list of windows and the desktop size.
661c5ac21333f543680ce306d46f287d62c175d873mridge * 2. Filter out the panel/desktop/whatever.  We're going to make
671c5ac21333f543680ce306d46f287d62c175d873mridge *    a cheesy assumption that a window on desktop -1 should be left
681c5ac21333f543680ce306d46f287d62c175d873mridge *    alone.  (Actually, the -1 denotes "all desktops")
691c5ac21333f543680ce306d46f287d62c175d873mridge * 3. For each window:
701c5ac21333f543680ce306d46f287d62c175d873mridge *    a. Figure out what we're going to do--activate, move/resize,
711c5ac21333f543680ce306d46f287d62c175d873mridge *       or maximize it.
721c5ac21333f543680ce306d46f287d62c175d873mridge *    b. If we're going to move/resize, grab 4 random numbers.
731c5ac21333f543680ce306d46f287d62c175d873mridge *    c. Actually perform the action.
741c5ac21333f543680ce306d46f287d62c175d873mridge * 4. Every so often, jump back to (2) in case there are new windows.
751c5ac21333f543680ce306d46f287d62c175d873mridge *    Maybe every 10,000 moves or so.
761c5ac21333f543680ce306d46f287d62c175d873mridge *
771c5ac21333f543680ce306d46f287d62c175d873mridge * Note that you do NOT want to run this on any X session you care about.
781c5ac21333f543680ce306d46f287d62c175d873mridge * It shouldn't take down X, but YMMV and in any case mad window resizing
791c5ac21333f543680ce306d46f287d62c175d873mridge * makes it hard to get work done.
801c5ac21333f543680ce306d46f287d62c175d873mridge */
811c5ac21333f543680ce306d46f287d62c175d873mridgestatic int seed_random(void);
82354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic int get_desktop_size(Display * disp, unsigned long *w, unsigned long *h);
83354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic char *get_property(Display * disp, Window win, Atom xa_prop_type,
84354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			  char *prop_name, unsigned long *size,
85354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			  unsigned long *items);
86354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic void go_bonkers(Display * disp, unsigned long iterations,
87354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		       unsigned long sleep);
88354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic Window *get_interesting_windows(Display * disp,
89354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				       unsigned long *num_windows);
90354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic Window *get_client_list(Display * disp, unsigned long *size,
91354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			       unsigned long *items);
921c5ac21333f543680ce306d46f287d62c175d873mridgestatic long get_randnum(long min, long max);
93354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic int send_client_msg(Display * disp, Window win, char *msg,
94354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			   unsigned long data0, unsigned long data1,
95354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			   unsigned long data2, unsigned long data3,
96354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			   unsigned long data4);
97354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic int activate_window(Display * disp, Window * win);
98354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic int wm_supports(Display * disp, const char *prop);
99354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic void move_window(Display * disp, Window * win, unsigned long desk_w,
100354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			unsigned long desk_h);
101354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic int toggle_property(Display * disp, Window * win, const char *property);
1021c5ac21333f543680ce306d46f287d62c175d873mridgestatic inline unsigned long clamp_value(unsigned long value,
103354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					unsigned long min, unsigned long max);
104354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic int ignore_xlib_error(Display * disp, XErrorEvent * xee);
1051c5ac21333f543680ce306d46f287d62c175d873mridge
1061c5ac21333f543680ce306d46f287d62c175d873mridge/* Actual functions begin here. */
1071c5ac21333f543680ce306d46f287d62c175d873mridge
108354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic int seed_random(void)
109354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao{
1101c5ac21333f543680ce306d46f287d62c175d873mridge	int fp;
1111c5ac21333f543680ce306d46f287d62c175d873mridge	long seed;
1121c5ac21333f543680ce306d46f287d62c175d873mridge
1131c5ac21333f543680ce306d46f287d62c175d873mridge	fp = open("/dev/urandom", O_RDONLY);
1141c5ac21333f543680ce306d46f287d62c175d873mridge	if (fp < 0) {
1151c5ac21333f543680ce306d46f287d62c175d873mridge		perror("/dev/urandom");
1161c5ac21333f543680ce306d46f287d62c175d873mridge		return 0;
1171c5ac21333f543680ce306d46f287d62c175d873mridge	}
1181c5ac21333f543680ce306d46f287d62c175d873mridge
1191c5ac21333f543680ce306d46f287d62c175d873mridge	if (read(fp, &seed, sizeof(seed)) != sizeof(seed)) {
1201c5ac21333f543680ce306d46f287d62c175d873mridge		perror("read random seed");
1211c5ac21333f543680ce306d46f287d62c175d873mridge		return 0;
1221c5ac21333f543680ce306d46f287d62c175d873mridge	}
1231c5ac21333f543680ce306d46f287d62c175d873mridge
1241c5ac21333f543680ce306d46f287d62c175d873mridge	close(fp);
1251c5ac21333f543680ce306d46f287d62c175d873mridge	srand(seed);
1261c5ac21333f543680ce306d46f287d62c175d873mridge
1271c5ac21333f543680ce306d46f287d62c175d873mridge	return 1;
1281c5ac21333f543680ce306d46f287d62c175d873mridge}
1291c5ac21333f543680ce306d46f287d62c175d873mridge
130354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic int get_desktop_size(Display * disp, unsigned long *w, unsigned long *h)
131354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao{
1321c5ac21333f543680ce306d46f287d62c175d873mridge	*w = DisplayWidth(disp, 0);
1331c5ac21333f543680ce306d46f287d62c175d873mridge	*h = DisplayHeight(disp, 0);
1341c5ac21333f543680ce306d46f287d62c175d873mridge
1351c5ac21333f543680ce306d46f287d62c175d873mridge	return 1;
1361c5ac21333f543680ce306d46f287d62c175d873mridge}
1371c5ac21333f543680ce306d46f287d62c175d873mridge
138354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic char *get_property(Display * disp, Window win, Atom xa_prop_type,
139354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			  char *prop_name, unsigned long *size,
140354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			  unsigned long *items)
1411c5ac21333f543680ce306d46f287d62c175d873mridge{
1421c5ac21333f543680ce306d46f287d62c175d873mridge	Atom xa_prop_name;
1431c5ac21333f543680ce306d46f287d62c175d873mridge	Atom xa_ret_type;
1441c5ac21333f543680ce306d46f287d62c175d873mridge	int ret_format;
1451c5ac21333f543680ce306d46f287d62c175d873mridge	unsigned long ret_nitems;
1461c5ac21333f543680ce306d46f287d62c175d873mridge	unsigned long ret_bytes_after;
1471c5ac21333f543680ce306d46f287d62c175d873mridge	unsigned long tmp_size;
1481c5ac21333f543680ce306d46f287d62c175d873mridge	unsigned char *ret_prop;
1491c5ac21333f543680ce306d46f287d62c175d873mridge	char *ret;
1501e6f5a673655551de5734ff31ef48cd63b604e6dGarrett Cooper
1511c5ac21333f543680ce306d46f287d62c175d873mridge	xa_prop_name = XInternAtom(disp, prop_name, False);
1521e6f5a673655551de5734ff31ef48cd63b604e6dGarrett Cooper
153354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (XGetWindowProperty
154354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	    (disp, win, xa_prop_name, 0, MAX_PROPERTY_VALUE_LEN / 4, False,
155354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	     xa_prop_type, &xa_ret_type, &ret_format, &ret_nitems,
156354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	     &ret_bytes_after, &ret_prop) != Success) {
1571c5ac21333f543680ce306d46f287d62c175d873mridge		fprintf(stderr, "Cannot get %s property.\n", prop_name);
1581c5ac21333f543680ce306d46f287d62c175d873mridge		return NULL;
1591c5ac21333f543680ce306d46f287d62c175d873mridge	}
1601e6f5a673655551de5734ff31ef48cd63b604e6dGarrett Cooper
1611c5ac21333f543680ce306d46f287d62c175d873mridge	if (xa_ret_type != xa_prop_type) {
1621c5ac21333f543680ce306d46f287d62c175d873mridge		fprintf(stderr, "Invalid type of %s property.\n", prop_name);
1631c5ac21333f543680ce306d46f287d62c175d873mridge		XFree(ret_prop);
1641c5ac21333f543680ce306d46f287d62c175d873mridge		return NULL;
1651c5ac21333f543680ce306d46f287d62c175d873mridge	}
1661c5ac21333f543680ce306d46f287d62c175d873mridge
1671c5ac21333f543680ce306d46f287d62c175d873mridge	/* XXX: EVIL HACK to get around a bug when sizeof(Window) is 8 yet ret_format
1681c5ac21333f543680ce306d46f287d62c175d873mridge	 * is listed as 32bits and we're trying to get the client list.  Just double
1691c5ac21333f543680ce306d46f287d62c175d873mridge	 * ret_format and proceed. */
1701c5ac21333f543680ce306d46f287d62c175d873mridge	if (ret_format == 32 && strcmp(prop_name, "_NET_CLIENT_LIST") == 0 &&
171354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	    sizeof(Window) == 8) {
1721c5ac21333f543680ce306d46f287d62c175d873mridge		ret_format *= 2;
1731c5ac21333f543680ce306d46f287d62c175d873mridge	}
1741c5ac21333f543680ce306d46f287d62c175d873mridge
1751c5ac21333f543680ce306d46f287d62c175d873mridge	/* null terminate the result to make string handling easier */
1761c5ac21333f543680ce306d46f287d62c175d873mridge	tmp_size = (ret_format / 8) * ret_nitems;
1771c5ac21333f543680ce306d46f287d62c175d873mridge	ret = calloc(tmp_size + 1, 1);
1781c5ac21333f543680ce306d46f287d62c175d873mridge	if (!ret) {
1791c5ac21333f543680ce306d46f287d62c175d873mridge		perror("get_property malloc failed");
1801c5ac21333f543680ce306d46f287d62c175d873mridge		return NULL;
1811c5ac21333f543680ce306d46f287d62c175d873mridge	}
1821c5ac21333f543680ce306d46f287d62c175d873mridge	memcpy(ret, ret_prop, tmp_size);
1831c5ac21333f543680ce306d46f287d62c175d873mridge	ret[tmp_size] = '\0';
1841c5ac21333f543680ce306d46f287d62c175d873mridge
1851c5ac21333f543680ce306d46f287d62c175d873mridge	if (size) {
1861c5ac21333f543680ce306d46f287d62c175d873mridge		*size = ret_format / 8;
1871c5ac21333f543680ce306d46f287d62c175d873mridge	}
1881c5ac21333f543680ce306d46f287d62c175d873mridge	if (items) {
1891c5ac21333f543680ce306d46f287d62c175d873mridge		*items = ret_nitems;
1901c5ac21333f543680ce306d46f287d62c175d873mridge	}
1911e6f5a673655551de5734ff31ef48cd63b604e6dGarrett Cooper
1921c5ac21333f543680ce306d46f287d62c175d873mridge	XFree(ret_prop);
1931c5ac21333f543680ce306d46f287d62c175d873mridge	return ret;
1941c5ac21333f543680ce306d46f287d62c175d873mridge}
1951c5ac21333f543680ce306d46f287d62c175d873mridge
196354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic long get_randnum(long min, long max)
197354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao{
1981c5ac21333f543680ce306d46f287d62c175d873mridge	return min + (long)((float)max * (rand() / (RAND_MAX + 1.0)));
1991c5ac21333f543680ce306d46f287d62c175d873mridge}
2001c5ac21333f543680ce306d46f287d62c175d873mridge
201354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic int wm_supports(Display * disp, const char *prop)
202354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao{
2031c5ac21333f543680ce306d46f287d62c175d873mridge	Atom xa_prop = XInternAtom(disp, prop, False);
2041c5ac21333f543680ce306d46f287d62c175d873mridge	Atom *list;
2051c5ac21333f543680ce306d46f287d62c175d873mridge	unsigned long size, items;
2061c5ac21333f543680ce306d46f287d62c175d873mridge	int i;
2071c5ac21333f543680ce306d46f287d62c175d873mridge
208354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (!(list = (Atom *) get_property(disp, DefaultRootWindow(disp),
209354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					   XA_ATOM, "_NET_SUPPORTED", &size,
210354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					   &items))) {
2111c5ac21333f543680ce306d46f287d62c175d873mridge		fprintf(stderr, "Cannot get _NET_SUPPORTED property.\n");
2121c5ac21333f543680ce306d46f287d62c175d873mridge		return 0;
2131c5ac21333f543680ce306d46f287d62c175d873mridge	}
2141c5ac21333f543680ce306d46f287d62c175d873mridge
2151c5ac21333f543680ce306d46f287d62c175d873mridge	size *= items;
2161c5ac21333f543680ce306d46f287d62c175d873mridge
2171c5ac21333f543680ce306d46f287d62c175d873mridge	for (i = 0; i < size / sizeof(Atom); i++) {
2181c5ac21333f543680ce306d46f287d62c175d873mridge		if (list[i] == xa_prop) {
2191c5ac21333f543680ce306d46f287d62c175d873mridge			free(list);
2201c5ac21333f543680ce306d46f287d62c175d873mridge			return 1;
2211c5ac21333f543680ce306d46f287d62c175d873mridge		}
2221c5ac21333f543680ce306d46f287d62c175d873mridge	}
2231e6f5a673655551de5734ff31ef48cd63b604e6dGarrett Cooper
2241c5ac21333f543680ce306d46f287d62c175d873mridge	free(list);
2251c5ac21333f543680ce306d46f287d62c175d873mridge	return 0;
2261c5ac21333f543680ce306d46f287d62c175d873mridge}
2271c5ac21333f543680ce306d46f287d62c175d873mridge
2281c5ac21333f543680ce306d46f287d62c175d873mridgestatic inline unsigned long clamp_value(unsigned long value,
229354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					unsigned long min, unsigned long max)
2301c5ac21333f543680ce306d46f287d62c175d873mridge{
2311c5ac21333f543680ce306d46f287d62c175d873mridge	return (value < min ? min : (value > max ? max : value));
2321c5ac21333f543680ce306d46f287d62c175d873mridge}
2331c5ac21333f543680ce306d46f287d62c175d873mridge
234354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic int ignore_xlib_error(Display * disp, XErrorEvent * xee)
235354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao{
2361c5ac21333f543680ce306d46f287d62c175d873mridge	char errbuf[256];
2371c5ac21333f543680ce306d46f287d62c175d873mridge
2381c5ac21333f543680ce306d46f287d62c175d873mridge	XGetErrorText(disp, xee->error_code, errbuf, 256);
239354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	fprintf(stderr,
240354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		"IGNORING Xlib error %d (%s) on request (%d.%d), sernum = %lu.\n",
2411c5ac21333f543680ce306d46f287d62c175d873mridge		xee->error_code, errbuf, xee->request_code, xee->minor_code,
2421c5ac21333f543680ce306d46f287d62c175d873mridge		xee->serial);
2431c5ac21333f543680ce306d46f287d62c175d873mridge	return 1;
2441c5ac21333f543680ce306d46f287d62c175d873mridge}
2451c5ac21333f543680ce306d46f287d62c175d873mridge
246354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic void slide_window(Display * disp, Window * win, unsigned long desk_w,
247354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			 unsigned long desk_h)
248354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao{
2491c5ac21333f543680ce306d46f287d62c175d873mridge	unsigned long x, y;
2501c5ac21333f543680ce306d46f287d62c175d873mridge	unsigned long w, h;
2511c5ac21333f543680ce306d46f287d62c175d873mridge	XWindowAttributes moo;
2521c5ac21333f543680ce306d46f287d62c175d873mridge	Window junk;
2531c5ac21333f543680ce306d46f287d62c175d873mridge
2541c5ac21333f543680ce306d46f287d62c175d873mridge	if (XGetWindowAttributes(disp, *win, &moo) != 1) {
255354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fprintf(stderr, "Cannot get attributes of window 0x%lx.\n",
256354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			*win);
2571c5ac21333f543680ce306d46f287d62c175d873mridge		return;
2581c5ac21333f543680ce306d46f287d62c175d873mridge	}
2591c5ac21333f543680ce306d46f287d62c175d873mridge
2601e6f5a673655551de5734ff31ef48cd63b604e6dGarrett Cooper	if (XTranslateCoordinates(disp, *win, moo.root,
261354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				  -moo.border_width, -moo.border_width, &moo.x,
262354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				  &moo.y, &junk) != 1) {
263354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fprintf(stderr,
264354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			"Cannot translate coordinates of window 0x%lx.\n",
265354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			*win);
2661c5ac21333f543680ce306d46f287d62c175d873mridge		return;
2671c5ac21333f543680ce306d46f287d62c175d873mridge	}
2681c5ac21333f543680ce306d46f287d62c175d873mridge
2691c5ac21333f543680ce306d46f287d62c175d873mridge	x = moo.x + get_randnum(-SLIDE_THRESHOLD, SLIDE_THRESHOLD);
2701c5ac21333f543680ce306d46f287d62c175d873mridge	y = moo.y + get_randnum(-SLIDE_THRESHOLD, SLIDE_THRESHOLD);
2711c5ac21333f543680ce306d46f287d62c175d873mridge	w = moo.width + get_randnum(-SLIDE_THRESHOLD, SLIDE_THRESHOLD);
2721c5ac21333f543680ce306d46f287d62c175d873mridge	h = moo.height + get_randnum(-SLIDE_THRESHOLD, SLIDE_THRESHOLD);
2731c5ac21333f543680ce306d46f287d62c175d873mridge
2741c5ac21333f543680ce306d46f287d62c175d873mridge	x = clamp_value(x, 0, desk_w);
2751c5ac21333f543680ce306d46f287d62c175d873mridge	y = clamp_value(y, 0, desk_h);
2761c5ac21333f543680ce306d46f287d62c175d873mridge	w = clamp_value(w, 0, desk_w);
2771c5ac21333f543680ce306d46f287d62c175d873mridge	h = clamp_value(h, 0, desk_h);
2781c5ac21333f543680ce306d46f287d62c175d873mridge
27943088e16aa60d69e3ec5a69cdd8bdd45b8891127Garrett Cooper	if (wm_supports(disp, "_NET_MOVERESIZE_WINDOW")) {
2801e6f5a673655551de5734ff31ef48cd63b604e6dGarrett Cooper		send_client_msg(disp, *win, "_NET_MOVERESIZE_WINDOW",
281354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				0, x, y, w, h);
2821c5ac21333f543680ce306d46f287d62c175d873mridge	} else {
2831c5ac21333f543680ce306d46f287d62c175d873mridge		XMoveResizeWindow(disp, *win, x, y, w, h);
2841c5ac21333f543680ce306d46f287d62c175d873mridge	}
2851c5ac21333f543680ce306d46f287d62c175d873mridge}
2861c5ac21333f543680ce306d46f287d62c175d873mridge
287354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic void move_window(Display * disp, Window * win, unsigned long desk_w,
288354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			unsigned long desk_h)
289354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao{
2901c5ac21333f543680ce306d46f287d62c175d873mridge	unsigned long x, y, w, h;
2911c5ac21333f543680ce306d46f287d62c175d873mridge
2921c5ac21333f543680ce306d46f287d62c175d873mridge	x = get_randnum(0, desk_w);
2931c5ac21333f543680ce306d46f287d62c175d873mridge	y = get_randnum(0, desk_h);
2941c5ac21333f543680ce306d46f287d62c175d873mridge	w = get_randnum(150, desk_w);
2951c5ac21333f543680ce306d46f287d62c175d873mridge	h = get_randnum(150, desk_h);
2961e6f5a673655551de5734ff31ef48cd63b604e6dGarrett Cooper
29743088e16aa60d69e3ec5a69cdd8bdd45b8891127Garrett Cooper	if (wm_supports(disp, "_NET_MOVERESIZE_WINDOW")) {
2981e6f5a673655551de5734ff31ef48cd63b604e6dGarrett Cooper		send_client_msg(disp, *win, "_NET_MOVERESIZE_WINDOW",
299354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				0, x, y, w, h);
3001c5ac21333f543680ce306d46f287d62c175d873mridge	} else {
3011c5ac21333f543680ce306d46f287d62c175d873mridge		XMoveResizeWindow(disp, *win, x, y, w, h);
3021c5ac21333f543680ce306d46f287d62c175d873mridge	}
3031c5ac21333f543680ce306d46f287d62c175d873mridge}
3041c5ac21333f543680ce306d46f287d62c175d873mridge
305354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic int toggle_property(Display * disp, Window * win, const char *property)
306354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao{
3071c5ac21333f543680ce306d46f287d62c175d873mridge	Atom prop;
3081c5ac21333f543680ce306d46f287d62c175d873mridge
3091c5ac21333f543680ce306d46f287d62c175d873mridge	prop = XInternAtom(disp, property, False);
3101c5ac21333f543680ce306d46f287d62c175d873mridge	return send_client_msg(disp, *win, "_NET_WM_STATE",
311354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			       _NET_WM_STATE_TOGGLE, prop, 0, 0, 0);
3121c5ac21333f543680ce306d46f287d62c175d873mridge}
3131c5ac21333f543680ce306d46f287d62c175d873mridge
314354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic void go_bonkers(Display * disp, unsigned long iterations,
315354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		       unsigned long sleep)
316354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao{
3171c5ac21333f543680ce306d46f287d62c175d873mridge	unsigned long desk_w, desk_h;
3181c5ac21333f543680ce306d46f287d62c175d873mridge	Window *windows, *window;
3191c5ac21333f543680ce306d46f287d62c175d873mridge	unsigned long windows_length = 0, i;
3201c5ac21333f543680ce306d46f287d62c175d873mridge
3211c5ac21333f543680ce306d46f287d62c175d873mridge	if (!get_desktop_size(disp, &desk_w, &desk_h)) {
3221c5ac21333f543680ce306d46f287d62c175d873mridge		fprintf(stderr, "WARNING: Assuming desktop to be 1024x768!\n");
3231c5ac21333f543680ce306d46f287d62c175d873mridge		desk_w = 1024;
3241c5ac21333f543680ce306d46f287d62c175d873mridge		desk_h = 768;
3251c5ac21333f543680ce306d46f287d62c175d873mridge	}
3261c5ac21333f543680ce306d46f287d62c175d873mridge	printf("Desktop is %lu by %lu.\n", desk_w, desk_h);
3271c5ac21333f543680ce306d46f287d62c175d873mridge
3281c5ac21333f543680ce306d46f287d62c175d873mridge	windows = get_interesting_windows(disp, &windows_length);
3291c5ac21333f543680ce306d46f287d62c175d873mridge	if (!windows) {
3301c5ac21333f543680ce306d46f287d62c175d873mridge		usleep(1000000);
3311c5ac21333f543680ce306d46f287d62c175d873mridge		return;
3321c5ac21333f543680ce306d46f287d62c175d873mridge	}
3331c5ac21333f543680ce306d46f287d62c175d873mridge	printf("There are %lu interesting windows.\n", windows_length);
3341c5ac21333f543680ce306d46f287d62c175d873mridge
3351c5ac21333f543680ce306d46f287d62c175d873mridge	/* Bump up the iteration count so that all windows get
3361c5ac21333f543680ce306d46f287d62c175d873mridge	 * some exercise. */
3371c5ac21333f543680ce306d46f287d62c175d873mridge	iterations += iterations % windows_length;
3381c5ac21333f543680ce306d46f287d62c175d873mridge
3391c5ac21333f543680ce306d46f287d62c175d873mridge	for (i = 0; i < iterations; i++) {
3401c5ac21333f543680ce306d46f287d62c175d873mridge		window = &windows[i % windows_length];
3411c5ac21333f543680ce306d46f287d62c175d873mridge		switch (get_randnum(ACTION_MIN, ACTION_MAX)) {
342354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case ACTION_MOVE_WINDOW:
343354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			move_window(disp, window, desk_w, desk_h);
344354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
345354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case ACTION_ACTIVATE_WINDOW:
346354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			activate_window(disp, window);
347354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
348354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case ACTION_MAXIMIZE_WINDOW:
349354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			toggle_property(disp, window,
3501c5ac21333f543680ce306d46f287d62c175d873mridge					"_NET_WM_STATE_MAXIMIZED_VERT");
351354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			toggle_property(disp, window,
3521c5ac21333f543680ce306d46f287d62c175d873mridge					"_NET_WM_STATE_MAXIMIZED_HORZ");
353354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
354354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case ACTION_FULLSCREEN_WINDOW:
355354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (!enable_fullscreen)
3561c5ac21333f543680ce306d46f287d62c175d873mridge				break;
357354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			toggle_property(disp, window,
3581c5ac21333f543680ce306d46f287d62c175d873mridge					"_NET_WM_STATE_FULLSCREEN");
359354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
360354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case ACTION_HIDDEN_WINDOW:
361354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			toggle_property(disp, window, "_NET_WM_STATE_HIDDEN");
362354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
363354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case ACTION_SLIDE_WINDOW_0:
364354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case ACTION_SLIDE_WINDOW_1:
365354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case ACTION_SLIDE_WINDOW_2:
366354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case ACTION_SLIDE_WINDOW_3:
367354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case ACTION_SLIDE_WINDOW_4:
368354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case ACTION_SLIDE_WINDOW_5:
369354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			slide_window(disp, window, desk_w, desk_h);
370354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
3711c5ac21333f543680ce306d46f287d62c175d873mridge		}
3721c5ac21333f543680ce306d46f287d62c175d873mridge		usleep(sleep);
3731c5ac21333f543680ce306d46f287d62c175d873mridge	}
3741c5ac21333f543680ce306d46f287d62c175d873mridge
3751c5ac21333f543680ce306d46f287d62c175d873mridge	free(windows);
3761c5ac21333f543680ce306d46f287d62c175d873mridge}
3771c5ac21333f543680ce306d46f287d62c175d873mridge
378354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic int send_client_msg(Display * disp, Window win, char *msg,
379354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			   unsigned long data0, unsigned long data1,
380354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			   unsigned long data2, unsigned long data3,
381354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			   unsigned long data4)
3821c5ac21333f543680ce306d46f287d62c175d873mridge{
3831c5ac21333f543680ce306d46f287d62c175d873mridge	XEvent event;
3841c5ac21333f543680ce306d46f287d62c175d873mridge	long mask = SubstructureRedirectMask | SubstructureNotifyMask;
3851c5ac21333f543680ce306d46f287d62c175d873mridge
3861c5ac21333f543680ce306d46f287d62c175d873mridge	event.xclient.type = ClientMessage;
3871c5ac21333f543680ce306d46f287d62c175d873mridge	event.xclient.serial = 0;
3881c5ac21333f543680ce306d46f287d62c175d873mridge	event.xclient.send_event = True;
3891c5ac21333f543680ce306d46f287d62c175d873mridge	event.xclient.message_type = XInternAtom(disp, msg, False);
3901c5ac21333f543680ce306d46f287d62c175d873mridge	event.xclient.window = win;
3911c5ac21333f543680ce306d46f287d62c175d873mridge	event.xclient.format = 32;
3921c5ac21333f543680ce306d46f287d62c175d873mridge	event.xclient.data.l[0] = data0;
3931c5ac21333f543680ce306d46f287d62c175d873mridge	event.xclient.data.l[1] = data1;
3941c5ac21333f543680ce306d46f287d62c175d873mridge	event.xclient.data.l[2] = data2;
3951c5ac21333f543680ce306d46f287d62c175d873mridge	event.xclient.data.l[3] = data3;
3961c5ac21333f543680ce306d46f287d62c175d873mridge	event.xclient.data.l[4] = data4;
3971e6f5a673655551de5734ff31ef48cd63b604e6dGarrett Cooper
3981c5ac21333f543680ce306d46f287d62c175d873mridge	if (XSendEvent(disp, DefaultRootWindow(disp), False, mask, &event)) {
3991c5ac21333f543680ce306d46f287d62c175d873mridge		return 1;
4001c5ac21333f543680ce306d46f287d62c175d873mridge	} else {
4011c5ac21333f543680ce306d46f287d62c175d873mridge		fprintf(stderr, "Cannot send %s event.\n", msg);
4021c5ac21333f543680ce306d46f287d62c175d873mridge		return 0;
4031c5ac21333f543680ce306d46f287d62c175d873mridge	}
4041c5ac21333f543680ce306d46f287d62c175d873mridge}
4051c5ac21333f543680ce306d46f287d62c175d873mridge
406354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic int activate_window(Display * disp, Window * win)
407354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao{
4081c5ac21333f543680ce306d46f287d62c175d873mridge	int ret;
4091e6f5a673655551de5734ff31ef48cd63b604e6dGarrett Cooper
410354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	ret = send_client_msg(disp, *win, "_NET_ACTIVE_WINDOW", 0, 0, 0, 0, 0);
4111c5ac21333f543680ce306d46f287d62c175d873mridge	XMapRaised(disp, *win);
4121c5ac21333f543680ce306d46f287d62c175d873mridge
4131c5ac21333f543680ce306d46f287d62c175d873mridge	return ret;
4141c5ac21333f543680ce306d46f287d62c175d873mridge}
4151c5ac21333f543680ce306d46f287d62c175d873mridge
416354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic Window *get_client_list(Display * disp, unsigned long *size,
417354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			       unsigned long *items)
418354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao{
4191c5ac21333f543680ce306d46f287d62c175d873mridge	void *res;
4201c5ac21333f543680ce306d46f287d62c175d873mridge
421354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if ((res = (Window *) get_property(disp, DefaultRootWindow(disp),
422354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					   XA_WINDOW, "_NET_CLIENT_LIST", size,
423354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					   items)) == NULL) {
424354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if ((res =
425354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		     (Window *) get_property(disp, DefaultRootWindow(disp),
426354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					     XA_CARDINAL, "_WIN_CLIENT_LIST",
427354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					     size, items)) == NULL) {
428354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			fprintf(stderr,
429354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				"Cannot get client list properties. \n"
430354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				"(_NET_CLIENT_LIST or _WIN_CLIENT_LIST)" "\n");
4311c5ac21333f543680ce306d46f287d62c175d873mridge			return NULL;
4321c5ac21333f543680ce306d46f287d62c175d873mridge		}
4331c5ac21333f543680ce306d46f287d62c175d873mridge	}
4341c5ac21333f543680ce306d46f287d62c175d873mridge
435354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	return (Window *) res;
4361c5ac21333f543680ce306d46f287d62c175d873mridge}
4371c5ac21333f543680ce306d46f287d62c175d873mridge
438354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic Window *get_interesting_windows(Display * disp,
439354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				       unsigned long *num_windows)
440354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao{
4411c5ac21333f543680ce306d46f287d62c175d873mridge	Window *client_list, *ret, *tmp;
4421c5ac21333f543680ce306d46f287d62c175d873mridge	unsigned long client_list_size, client_list_items, i;
4431c5ac21333f543680ce306d46f287d62c175d873mridge	long *desktop;
4441c5ac21333f543680ce306d46f287d62c175d873mridge	unsigned long num_needed = 0;
4451c5ac21333f543680ce306d46f287d62c175d873mridge
4461c5ac21333f543680ce306d46f287d62c175d873mridge	if ((client_list = get_client_list(disp, &client_list_size,
447354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					   &client_list_items)) == NULL) {
4481c5ac21333f543680ce306d46f287d62c175d873mridge		return NULL;
4491c5ac21333f543680ce306d46f287d62c175d873mridge	}
4501c5ac21333f543680ce306d46f287d62c175d873mridge
4511c5ac21333f543680ce306d46f287d62c175d873mridge	/* Figure out how many Window structs we'll ultimately need. */
4521c5ac21333f543680ce306d46f287d62c175d873mridge	for (i = 0; i < client_list_items; i++) {
4531c5ac21333f543680ce306d46f287d62c175d873mridge		/* desktop ID */
4541c5ac21333f543680ce306d46f287d62c175d873mridge		if ((desktop = (long *)get_property(disp, client_list[i],
455354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						    XA_CARDINAL,
456354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						    "_NET_WM_DESKTOP", NULL,
457354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						    NULL)) == NULL) {
458354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			desktop =
459354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			    (long *)get_property(disp, client_list[i],
460354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						 XA_CARDINAL, "_WIN_WORKSPACE",
461354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						 NULL, NULL);
4621c5ac21333f543680ce306d46f287d62c175d873mridge		}
4631e6f5a673655551de5734ff31ef48cd63b604e6dGarrett Cooper
4641c5ac21333f543680ce306d46f287d62c175d873mridge		/* Ignore windows on unknown desktops */
4651c5ac21333f543680ce306d46f287d62c175d873mridge		if (desktop && *desktop >= 0 && *desktop < DESKTOP_MAX) {
4661c5ac21333f543680ce306d46f287d62c175d873mridge			num_needed++;
4671c5ac21333f543680ce306d46f287d62c175d873mridge			free(desktop);
4681c5ac21333f543680ce306d46f287d62c175d873mridge		}
4691c5ac21333f543680ce306d46f287d62c175d873mridge	}
4701c5ac21333f543680ce306d46f287d62c175d873mridge
4711c5ac21333f543680ce306d46f287d62c175d873mridge	ret = calloc(num_needed, sizeof(Window));
4721c5ac21333f543680ce306d46f287d62c175d873mridge	if (!ret) {
4731c5ac21333f543680ce306d46f287d62c175d873mridge		perror("get_interesting_window allocations");
4741c5ac21333f543680ce306d46f287d62c175d873mridge		free(client_list);
4751c5ac21333f543680ce306d46f287d62c175d873mridge		return NULL;
4761c5ac21333f543680ce306d46f287d62c175d873mridge	}
4771c5ac21333f543680ce306d46f287d62c175d873mridge	tmp = ret;
4781c5ac21333f543680ce306d46f287d62c175d873mridge
4791c5ac21333f543680ce306d46f287d62c175d873mridge	/* Now copy all that crud. */
4801c5ac21333f543680ce306d46f287d62c175d873mridge	for (i = 0; i < client_list_items; i++) {
4811c5ac21333f543680ce306d46f287d62c175d873mridge		/* desktop ID */
4821c5ac21333f543680ce306d46f287d62c175d873mridge		if ((desktop = (long *)get_property(disp, client_list[i],
483354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						    XA_CARDINAL,
484354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						    "_NET_WM_DESKTOP", NULL,
485354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						    NULL)) == NULL) {
486354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			desktop =
487354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			    (long *)get_property(disp, client_list[i],
488354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						 XA_CARDINAL, "_WIN_WORKSPACE",
489354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						 NULL, NULL);
4901c5ac21333f543680ce306d46f287d62c175d873mridge		}
4911c5ac21333f543680ce306d46f287d62c175d873mridge
4921c5ac21333f543680ce306d46f287d62c175d873mridge		if (desktop && *desktop >= 0 && *desktop < DESKTOP_MAX) {
4931c5ac21333f543680ce306d46f287d62c175d873mridge			memcpy(tmp, &client_list[i], sizeof(Window));
4941c5ac21333f543680ce306d46f287d62c175d873mridge			tmp++;
4951c5ac21333f543680ce306d46f287d62c175d873mridge			free(desktop);
4961c5ac21333f543680ce306d46f287d62c175d873mridge		}
4971c5ac21333f543680ce306d46f287d62c175d873mridge	}
4981c5ac21333f543680ce306d46f287d62c175d873mridge	free(client_list);
4991c5ac21333f543680ce306d46f287d62c175d873mridge
5001c5ac21333f543680ce306d46f287d62c175d873mridge	*num_windows = num_needed;
5011c5ac21333f543680ce306d46f287d62c175d873mridge	return ret;
5021c5ac21333f543680ce306d46f287d62c175d873mridge}
5031c5ac21333f543680ce306d46f287d62c175d873mridge
504354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaoint main(int argc, char *argv[])
505354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao{
5061c5ac21333f543680ce306d46f287d62c175d873mridge	char *disp_string = NULL;
5071c5ac21333f543680ce306d46f287d62c175d873mridge	unsigned long iterations = 10000, rounds = -1, i;
5081c5ac21333f543680ce306d46f287d62c175d873mridge	unsigned long sleep = 100000;
5091c5ac21333f543680ce306d46f287d62c175d873mridge	int opt;
5101c5ac21333f543680ce306d46f287d62c175d873mridge	Display *disp;
5111c5ac21333f543680ce306d46f287d62c175d873mridge
5121c5ac21333f543680ce306d46f287d62c175d873mridge	while ((opt = getopt(argc, argv, "d:i:r:s:f")) != -1) {
5131c5ac21333f543680ce306d46f287d62c175d873mridge		switch (opt) {
514354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 'd':
515354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			disp_string = optarg;
516354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
517354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 'i':
518354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			iterations = atoi(optarg);
519354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
520354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 'r':
521354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			rounds = atoi(optarg);
522354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
523354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 's':
524354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			sleep = atoi(optarg);
525354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
526354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 'f':
527354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			enable_fullscreen = 1;
528354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
529354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		default:
530354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			fprintf(stderr,
531354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				"Usage: %s [-d DISPLAY] [-i ITERATIONS] [-r ROUNDS] [-s SLEEP] [-f]\n\
5321c5ac21333f543680ce306d46f287d62c175d873mridge	DISPLAY is an X11 display string.\n\
5331c5ac21333f543680ce306d46f287d62c175d873mridge	ITERATIONS is the approximate number of windows to play with before generating a new window list.\n\
5341c5ac21333f543680ce306d46f287d62c175d873mridge	SLEEP is the amount of time (in usec) to sleep between window tweaks.\n\
5351c5ac21333f543680ce306d46f287d62c175d873mridge	-f enables fullscreen toggling.\n\
536354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	ROUNDS is the number of iterations to run, or -1 to run forever.\n",
537354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				argv[0]);
538354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			return 0;
5391c5ac21333f543680ce306d46f287d62c175d873mridge		}
5401c5ac21333f543680ce306d46f287d62c175d873mridge	}
5411c5ac21333f543680ce306d46f287d62c175d873mridge
5421c5ac21333f543680ce306d46f287d62c175d873mridge	if (!(disp = XOpenDisplay(disp_string))) {
5431c5ac21333f543680ce306d46f287d62c175d873mridge		fprintf(stderr, "Unable to connect to display '%s'.\n",
544354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			(disp_string !=
545354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			 NULL ? disp_string : getenv("DISPLAY")));
5461c5ac21333f543680ce306d46f287d62c175d873mridge		return 1;
5471c5ac21333f543680ce306d46f287d62c175d873mridge	}
5481c5ac21333f543680ce306d46f287d62c175d873mridge
5491c5ac21333f543680ce306d46f287d62c175d873mridge	seed_random();
5501c5ac21333f543680ce306d46f287d62c175d873mridge
5511c5ac21333f543680ce306d46f287d62c175d873mridge	XSetErrorHandler(&ignore_xlib_error);
5521c5ac21333f543680ce306d46f287d62c175d873mridge
5531c5ac21333f543680ce306d46f287d62c175d873mridge	for (i = 0; i < rounds || rounds == -1; i++) {
5541c5ac21333f543680ce306d46f287d62c175d873mridge		go_bonkers(disp, iterations, sleep);
5551c5ac21333f543680ce306d46f287d62c175d873mridge	}
5561c5ac21333f543680ce306d46f287d62c175d873mridge
5571c5ac21333f543680ce306d46f287d62c175d873mridge	printf("Enough of that; I'm done.\n");
5581c5ac21333f543680ce306d46f287d62c175d873mridge
5591c5ac21333f543680ce306d46f287d62c175d873mridge	XCloseDisplay(disp);
5601c5ac21333f543680ce306d46f287d62c175d873mridge
5611c5ac21333f543680ce306d46f287d62c175d873mridge	return 0;
562ec6edca7aa42b6affd989ef91b5897f96795e40fChris Dearman}
563