10
#include <sys/socket.h>
17
/* For some reason sys/un.h doesn't define this */
19
#define UNIX_PATH_MAX 108
22
/* Timeout in ms waiting for the status we expect */
23
#define STATUS_TIMEOUT 2000
25
/* Timeout in ms to wait for SIGTERM to kill compiz */
26
#define KILL_TIMEOUT 2000
28
static XigServer *xserver;
29
static GKeyFile *config;
30
static GPid compiz_pid = 0;
31
static GList *statuses = NULL;
32
static GList *script = NULL;
33
static GList *script_iter = NULL;
34
static guint status_timeout = 0;
35
static gboolean failed = FALSE;
36
static guint compiz_kill_timeout = 0;
38
static void check_status (const gchar *status);
41
compiz_kill_timeout_cb (gpointer data)
44
g_print ("Sending SIGKILL to compiz\n");
45
kill (compiz_pid, SIGKILL);
46
compiz_kill_timeout = 0;
53
if (compiz_pid && compiz_kill_timeout == 0)
56
g_print ("Sending SIGTERM to compiz process %d\n", compiz_pid);
57
kill (compiz_pid, SIGINT);
58
compiz_kill_timeout = g_timeout_add (KILL_TIMEOUT, compiz_kill_timeout_cb, NULL);
68
g_print ("Sending SIGHUP to compiz process %d\n", compiz_pid);
69
kill (compiz_pid, SIGHUP);
77
xig_server_stop (xserver);
79
kill (compiz_pid, SIGKILL);
85
fail (const gchar *event, const gchar *expected)
93
g_printerr ("Test failed, got the following events:\n");
94
for (link = statuses; link; link = link->next)
95
g_printerr (" %s\n", (gchar *)link->data);
97
g_printerr (" %s\n", event);
99
g_printerr (" ^^^ expected \"%s\"\n", expected);
101
g_printerr ("^^^ expected nothing\n");
103
/* Either wait for the compiz to quit, or stop now if it already is */
115
return script_iter->data;
119
compiz_exit_cb (GPid pid, gint status, gpointer data)
125
if (compiz_kill_timeout)
126
g_source_remove (compiz_kill_timeout);
127
compiz_kill_timeout = 0;
129
/* Quit when compiz does */
133
if (WIFEXITED (status))
134
status_text = g_strdup_printf ("COMPIZ EXIT STATUS=%d", WEXITSTATUS (status));
136
status_text = g_strdup_printf ("COMPIZ TERMINATE SIGNAL=%d", WTERMSIG (status));
137
check_status (status_text);
138
g_free (status_text);
142
unmap_notify_cb (XigWindow *window)
146
status_text = g_strdup_printf ("UNMAP-NOTIFY ID=%d", xig_window_get_id (window));
147
check_status (status_text);
148
g_free (status_text);
152
map_notify_cb (XigWindow *window)
156
status_text = g_strdup_printf ("MAP-NOTIFY ID=%d", xig_window_get_id (window));
157
check_status (status_text);
158
g_free (status_text);
162
reparent_notify_cb (XigWindow *window)
166
status_text = g_strdup_printf ("REPARENT-NOTIFY ID=%d", xig_window_get_id (window));
167
check_status (status_text);
168
g_free (status_text);
172
configure_notify_cb (XigWindow *window)
176
status_text = g_strdup_printf ("CONFIGURE-NOTIFY ID=%d", xig_window_get_id (window));
177
check_status (status_text);
178
g_free (status_text);
184
/* Stop compiz if requested */
187
gchar *command, *name = NULL, *c;
190
command = get_script_line ();
194
/* Commands start with an asterisk */
195
if (command[0] != '*')
197
statuses = g_list_append (statuses, g_strdup (command));
198
script_iter = script_iter->next;
201
while (*c && !isspace (*c))
203
name = g_strdup_printf ("%.*s", (int) (c - command - 1), command + 1);
205
params = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
208
gchar *start, *param_name, *param_value;
213
while (*c && !isspace (*c) && *c != '=')
218
param_name = g_strdup_printf ("%.*s", (int) (c - start), start);
227
gboolean escaped = FALSE;
231
value = g_string_new ("");
238
g_string_append_c (value, '\\');
244
else if (!escaped && *c == '\"')
247
g_string_append_c (value, *c);
250
param_value = value->str;
251
g_string_free (value, FALSE);
258
while (*c && !isspace (*c))
260
param_value = g_strdup_printf ("%.*s", (int) (c - start), start);
264
param_value = g_strdup ("");
266
g_hash_table_insert (params, param_name, param_value);
269
if (strcmp (name, "STOP-XSERVER") == 0)
270
xig_server_stop (xserver);
271
else if (strcmp (name, "STOP-COMPIZ") == 0)
273
else if (strcmp (name, "RESTART-COMPIZ") == 0)
275
else if (strcmp (name, "CREATE-WINDOW") == 0)
277
XigWindow *root, *window;
281
guint16 width = 0, height = 0, border_width = 0;
283
v = g_hash_table_lookup (params, "ID");
286
v = g_hash_table_lookup (params, "X");
289
v = g_hash_table_lookup (params, "Y");
292
v = g_hash_table_lookup (params, "WIDTH");
295
v = g_hash_table_lookup (params, "HEIGHT");
298
v = g_hash_table_lookup (params, "BORDER-WIDTH");
300
border_width = atoi (v);
302
root = xig_server_get_root (xserver, 0);
303
window = xig_window_add_child (root, NULL, id,
304
XIG_WINDOW_CLASS_InputOutput,
305
x, y, width, height, border_width,
306
xig_window_get_visual (root),
307
0, NULL, 0, NULL, 0, 0, 0, 0, 0, 0, FALSE, FALSE);
308
g_signal_connect (window, "unmap-notify", G_CALLBACK (unmap_notify_cb), NULL);
309
g_signal_connect (window, "map-notify", G_CALLBACK (map_notify_cb), NULL);
310
g_signal_connect (window, "reparent-notify", G_CALLBACK (reparent_notify_cb), NULL);
311
g_signal_connect (window, "configure-notify", G_CALLBACK (configure_notify_cb), NULL);
313
else if (strcmp (name, "MAP-WINDOW") == 0)
319
v = g_hash_table_lookup (params, "ID");
323
window = xig_server_get_window (xserver, id);
324
xig_window_map (window, NULL);
328
g_printerr ("Unknown command '%s'\n", name);
334
g_hash_table_unref (params);
337
gchar *l = get_script_line ();
339
/* Stop at the end of the script */
350
status_timeout_cb (gpointer data)
352
fail ("(timeout)", get_script_line ());
358
check_status (const gchar *status)
362
if (getenv ("DEBUG"))
363
g_print ("%s\n", status);
368
statuses = g_list_append (statuses, g_strdup (status));
370
/* Try and match against expected */
371
pattern = get_script_line ();
372
if (!pattern || !g_regex_match_simple (pattern, status, 0, 0))
374
fail (NULL, pattern);
377
script_iter = script_iter->next;
379
/* Restart timeout */
381
g_source_remove (status_timeout);
382
status_timeout = g_timeout_add (STATUS_TIMEOUT, status_timeout_cb, NULL);
388
signal_cb (int signum)
394
g_print ("Caught signal %d, killing Compiz\n", signum);
395
kill (compiz_pid, SIGKILL);
398
g_print ("Caught signal %d, quitting\n", signum);
402
g_print ("Caught signal %d, quitting\n", signum);
408
load_script (const gchar *filename)
411
gchar *data, **lines;
413
if (!g_file_get_contents (filename, &data, NULL, NULL))
415
g_printerr ("Unable to load script: %s\n", filename);
419
lines = g_strsplit (data, "\n", -1);
422
/* Load lines with #? prefix as expected behaviour */
423
for (i = 0; lines[i]; i++)
425
gchar *line = g_strstrip (lines[i]);
426
if (g_str_has_prefix (line, "#?"))
427
script = g_list_append (script, g_strdup (line+2));
429
script_iter = script;
434
client_connected_cb (XigServer *server,
435
XigRemoteClient *client)
437
check_status ("X CLIENT-CONNECTED");
441
client_disconnected_cb (XigServer *server, XigRemoteClient *client)
443
check_status ("X CLIENT-DISCONNECTED");
447
client_stdout_cb (GIOChannel *source,
448
GIOCondition condition,
453
gsize terminator_pos;
456
if (condition & G_IO_IN)
458
while (g_io_channel_read_line (source,
462
&error) == G_IO_STATUS_NORMAL)
464
if (getenv ("DEBUG"))
465
g_print ("%s", str_return);
467
/* This is a really bad heuristic, but its the only
468
* sane IPC I can think of right now */
469
if (strncmp ("execvp: ", str_return, 8) == 0)
471
/* Update the pid to the new compiz process */
472
sscanf (&str_return[8], "%d", &compiz_pid);
482
main (int argc, char **argv)
487
gchar *script_name, *config_file, *config_path;
488
GString *command_line;
489
gchar **compiz_env, **compiz_argv;
490
gint compiz_stdin, compiz_stdout, compiz_stderr;
491
GIOChannel *compiz_stdout_channel = NULL;
492
GError *error = NULL;
494
signal (SIGINT, signal_cb);
495
signal (SIGTERM, signal_cb);
499
loop = g_main_loop_new (NULL, FALSE);
503
g_printerr ("Usage %s SCRIPT-NAME\n", argv[0]);
506
script_name = argv[1];
507
config_file = g_strdup_printf ("%s.conf", script_name);
508
config_path = g_build_filename (COMPIZ_XIG_TEST_SOURCE_DIR "/scripts", config_file, NULL);
509
g_free (config_file);
511
config = g_key_file_new ();
512
g_key_file_load_from_file (config, config_path, G_KEY_FILE_NONE, NULL);
514
load_script (config_path);
516
/* Disable config if requested */
517
if (g_key_file_has_key (config, "test-runner-config", "have-config", NULL) &&
518
!g_key_file_get_boolean (config, "test-runner-config", "have-config", NULL))
521
g_print ("----------------------------------------\n");
522
g_print ("Running script %s\n", script_name);
524
/* Create an X server to test with */
525
xserver = xig_server_new ("compiz-test", 99);
526
xig_server_set_listen_tcp (xserver, FALSE);
527
g_signal_connect (xserver, "client-connected", G_CALLBACK (client_connected_cb), NULL);
528
g_signal_connect (xserver, "client-disconnected", G_CALLBACK (client_disconnected_cb), NULL);
529
xig_server_add_pixmap_format (xserver, 1, 1, 32);
530
xig_server_add_pixmap_format (xserver, 4, 8, 32);
531
xig_server_add_pixmap_format (xserver, 8, 8, 32);
532
xig_server_add_pixmap_format (xserver, 15, 16, 32);
533
xig_server_add_pixmap_format (xserver, 16, 16, 32);
534
xig_server_add_pixmap_format (xserver, 24, 32, 32);
535
xig_server_add_pixmap_format (xserver, 32, 32, 32);
536
screen = xig_server_add_screen (xserver, 0x00FFFFFF, 0x00000000, 1024, 768, 1024, 768);
537
visual = xig_screen_add_visual (screen, 24, XIG_VISUAL_CLASS_TrueColor, 8, 1, 0x00FF0000, 0x0000FF00, 0x000000FF);
538
xig_screen_add_root (screen, visual);
542
status_timeout = g_timeout_add (STATUS_TIMEOUT, status_timeout_cb, NULL);
544
if (!xig_server_start (xserver, &error))
546
g_printerr ("Failed to start Xig X server: %s", error->message);
550
compiz_env = g_strsplit ("DISPLAY=:99", " ", -1);
551
command_line = g_string_new (compiz_BINARY_DIR "/src/compiz");
552
g_print ("Start Compiz with command: %s\n", command_line->str);
553
if (!g_shell_parse_argv (command_line->str, NULL, &compiz_argv, &error))
555
g_warning ("Error parsing command line: %s", error->message);
558
g_clear_error (&error);
559
if (!g_spawn_async_with_pipes (NULL, /* working directory */
562
G_SPAWN_DO_NOT_REAP_CHILD,
563
NULL, NULL, /* child setup */
570
g_warning ("Error launching Compiz: %s", error->message);
573
g_clear_error (&error);
574
g_child_watch_add (compiz_pid, compiz_exit_cb, NULL);
575
if (getenv ("DEBUG"))
576
g_print ("Compiz running with PID %d\n", compiz_pid);
578
compiz_stdout_channel = g_io_channel_unix_new (compiz_stdout);
579
g_io_channel_set_flags (compiz_stdout_channel, G_IO_FLAG_NONBLOCK, NULL);
580
g_io_add_watch (compiz_stdout_channel, G_IO_IN, client_stdout_cb, NULL);
582
check_status ("COMPIZ START");
584
g_main_loop_run (loop);
586
g_object_unref (compiz_stdout_channel);