]> Pileus Git - ~andy/gtk/blob - tests/testsocket.c
Merge branch 'master' into broadway2
[~andy/gtk] / tests / testsocket.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 2 -*- */
2 /* testsocket.c
3  * Copyright (C) 2001 Red Hat, Inc
4  * Author: Owen Taylor
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include "config.h"
23 #include <gtk/gtk.h>
24
25 #include <string.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28
29 int n_children = 0;
30
31 GSList *sockets = NULL;
32
33 GtkWidget *window;
34 GtkWidget *box;
35
36 typedef struct 
37 {
38   GtkWidget *box;
39   GtkWidget *frame;
40   GtkWidget *socket;
41 } Socket;
42
43 extern guint32 create_child_plug (guint32  xid,
44                                   gboolean local);
45
46 static void
47 quit_cb (gpointer        callback_data,
48          guint           callback_action,
49          GtkWidget      *widget)
50 {
51   GtkWidget *message_dialog = gtk_message_dialog_new (GTK_WINDOW (window), 0,
52                                                       GTK_MESSAGE_QUESTION,
53                                                       GTK_BUTTONS_YES_NO,
54                                                       "Really Quit?");
55   gtk_dialog_set_default_response (GTK_DIALOG (message_dialog), GTK_RESPONSE_NO);
56
57   if (gtk_dialog_run (GTK_DIALOG (message_dialog)) == GTK_RESPONSE_YES)
58     gtk_widget_destroy (window);
59
60   gtk_widget_destroy (message_dialog);
61 }
62
63 static void
64 socket_destroyed (GtkWidget *widget,
65                   Socket    *socket)
66 {
67   sockets = g_slist_remove (sockets, socket);
68   g_free (socket);
69 }
70
71 static void
72 plug_added (GtkWidget *widget,
73             Socket    *socket)
74 {
75   g_print ("Plug added to socket\n");
76   
77   gtk_widget_show (socket->socket);
78   gtk_widget_hide (socket->frame);
79 }
80
81 static gboolean
82 plug_removed (GtkWidget *widget,
83               Socket    *socket)
84 {
85   g_print ("Plug removed from socket\n");
86   
87   gtk_widget_hide (socket->socket);
88   gtk_widget_show (socket->frame);
89   
90   return TRUE;
91 }
92
93 static Socket *
94 create_socket (void)
95 {
96   GtkWidget *label;
97   
98   Socket *socket = g_new (Socket, 1);
99   
100   socket->box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
101
102   socket->socket = gtk_socket_new ();
103   
104   gtk_box_pack_start (GTK_BOX (socket->box), socket->socket, TRUE, TRUE, 0);
105   
106   socket->frame = gtk_frame_new (NULL);
107   gtk_frame_set_shadow_type (GTK_FRAME (socket->frame), GTK_SHADOW_IN);
108   gtk_box_pack_start (GTK_BOX (socket->box), socket->frame, TRUE, TRUE, 0);
109   gtk_widget_show (socket->frame);
110   
111   label = gtk_label_new (NULL);
112   gtk_label_set_markup (GTK_LABEL (label), "<span color=\"red\">Empty</span>");
113   gtk_container_add (GTK_CONTAINER (socket->frame), label);
114   gtk_widget_show (label);
115
116   sockets = g_slist_prepend (sockets, socket);
117
118
119   g_signal_connect (socket->socket, "destroy",
120                     G_CALLBACK (socket_destroyed), socket);
121   g_signal_connect (socket->socket, "plug_added",
122                     G_CALLBACK (plug_added), socket);
123   g_signal_connect (socket->socket, "plug_removed",
124                     G_CALLBACK (plug_removed), socket);
125
126   return socket;
127 }
128
129 void
130 remove_child (GtkWidget *window)
131 {
132   if (sockets)
133     {
134       Socket *socket = sockets->data;
135       gtk_widget_destroy (socket->box);
136     }
137 }
138
139 static gboolean
140 child_read_watch (GIOChannel *channel, GIOCondition cond, gpointer data)
141 {
142   GIOStatus status;
143   GError *error = NULL;
144   char *line;
145   gsize term;
146   int xid;
147   
148   status = g_io_channel_read_line (channel, &line, NULL, &term, &error);
149   switch (status)
150     {
151     case G_IO_STATUS_NORMAL:
152       line[term] = '\0';
153       xid = strtol (line, NULL, 0);
154       if (xid == 0)
155         {
156           fprintf (stderr, "Invalid window id '%s'\n", line);
157         }
158       else
159         {
160           Socket *socket = create_socket ();
161           gtk_box_pack_start (GTK_BOX (box), socket->box, TRUE, TRUE, 0);
162           gtk_widget_show (socket->box);
163           
164           gtk_socket_add_id (GTK_SOCKET (socket->socket), xid);
165         }
166       g_free (line);
167       return TRUE;
168     case G_IO_STATUS_AGAIN:
169       return TRUE;
170     case G_IO_STATUS_EOF:
171       n_children--;
172       return FALSE;
173     case G_IO_STATUS_ERROR:
174       fprintf (stderr, "Error reading fd from child: %s\n", error->message);
175       exit (1);
176       return FALSE;
177     default:
178       g_assert_not_reached ();
179       return FALSE;
180     }
181   
182 }
183
184 void
185 add_child (GtkWidget *window,
186            gboolean   active)
187 {
188   Socket *socket;
189   char *argv[3] = { "./testsocket_child", NULL, NULL };
190   char buffer[20];
191   int out_fd;
192   GIOChannel *channel;
193   GError *error = NULL;
194
195   if (active)
196     {
197       socket = create_socket ();
198       gtk_box_pack_start (GTK_BOX (box), socket->box, TRUE, TRUE, 0);
199       gtk_widget_show (socket->box);
200       sprintf(buffer, "%#lx", (gulong) gtk_socket_get_id (GTK_SOCKET (socket->socket)));
201       argv[1] = buffer;
202     }
203   
204   if (!g_spawn_async_with_pipes (NULL, argv, NULL, 0, NULL, NULL, NULL, NULL, &out_fd, NULL, &error))
205     {
206       fprintf (stderr, "Can't exec testsocket_child: %s\n", error->message);
207       exit (1);
208     }
209
210   n_children++;
211   channel = g_io_channel_unix_new (out_fd);
212   g_io_channel_set_close_on_unref (channel, TRUE);
213   g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, &error);
214   if (error)
215     {
216       fprintf (stderr, "Error making channel non-blocking: %s\n", error->message);
217       exit (1);
218     }
219   
220   g_io_add_watch (channel, G_IO_IN | G_IO_HUP, child_read_watch, NULL);
221   g_io_channel_unref (channel);
222 }
223
224 void
225 add_active_child (GtkWidget *window)
226 {
227   add_child (window, TRUE);
228 }
229
230 void
231 add_passive_child (GtkWidget *window)
232 {
233   add_child (window, FALSE);
234 }
235
236 void
237 add_local_active_child (GtkWidget *window)
238 {
239   Socket *socket;
240
241   socket = create_socket ();
242   gtk_box_pack_start (GTK_BOX (box), socket->box, TRUE, TRUE, 0);
243   gtk_widget_show (socket->box);
244
245   create_child_plug (gtk_socket_get_id (GTK_SOCKET (socket->socket)), TRUE);
246 }
247
248 void
249 add_local_passive_child (GtkWidget *window)
250 {
251   Socket *socket;
252   GdkNativeWindow xid;
253
254   socket = create_socket ();
255   gtk_box_pack_start (GTK_BOX (box), socket->box, TRUE, TRUE, 0);
256   gtk_widget_show (socket->box);
257
258   xid = create_child_plug (0, TRUE);
259   gtk_socket_add_id (GTK_SOCKET (socket->socket), xid);
260 }
261
262 static const char *
263 grab_string (int status)
264 {
265   switch (status) {
266   case GDK_GRAB_SUCCESS:          return "GrabSuccess";
267   case GDK_GRAB_ALREADY_GRABBED:  return "AlreadyGrabbed";
268   case GDK_GRAB_INVALID_TIME:     return "GrabInvalidTime";
269   case GDK_GRAB_NOT_VIEWABLE:     return "GrabNotViewable";
270   case GDK_GRAB_FROZEN:           return "GrabFrozen";
271   default:
272     {
273       static char foo [255];
274       sprintf (foo, "unknown status: %d", status);
275       return foo;
276     }
277   }
278 }
279
280 static void
281 grab_window_toggled (GtkToggleButton *button,
282                      GtkWidget       *widget)
283 {
284   GdkDevice *device = gtk_get_current_event_device ();
285
286   if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
287     device = gdk_device_get_associated_device (device);
288
289   if (gtk_toggle_button_get_active (button))
290     {
291       int status;
292
293       status = gdk_device_grab (device,
294                                 gtk_widget_get_window (widget),
295                                 GDK_OWNERSHIP_NONE,
296                                 FALSE,
297                                 GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
298                                 NULL,
299                                 GDK_CURRENT_TIME);
300
301       if (status != GDK_GRAB_SUCCESS)
302         g_warning ("Could not grab keyboard!  (%s)", grab_string (status));
303
304     } 
305   else 
306     {
307       gdk_device_ungrab (device, GDK_CURRENT_TIME);
308     }
309 }
310
311 int
312 main (int argc, char *argv[])
313 {
314   GtkWidget *button;
315   GtkWidget *hbox;
316   GtkWidget *vbox;
317   GtkWidget *menubar;
318   GtkWidget *menuitem;
319   GtkWidget *menu;
320   GtkWidget *entry;
321   GtkWidget *checkbutton;
322   GtkAccelGroup *accel_group;
323
324   gtk_init (&argc, &argv);
325
326   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
327   g_signal_connect (window, "destroy",
328                     G_CALLBACK (gtk_main_quit), NULL);
329   
330   gtk_window_set_title (GTK_WINDOW (window), "Socket Test");
331   gtk_container_set_border_width (GTK_CONTAINER (window), 0);
332
333   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
334   gtk_container_add (GTK_CONTAINER (window), vbox);
335
336   menubar = gtk_menu_bar_new ();
337   menuitem = gtk_menu_item_new_with_mnemonic ("_File");
338   gtk_menu_shell_append (GTK_MENU_SHELL (menubar), menuitem);
339
340   menu = gtk_menu_new ();
341   gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), menu);
342   menuitem = gtk_menu_item_new_with_mnemonic ("_Quit");
343   g_signal_connect (menuitem, "activate", G_CALLBACK (quit_cb), window);
344   gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
345
346   accel_group = gtk_accel_group_new ();
347   gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
348   gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, FALSE, 0);
349
350   button = gtk_button_new_with_label ("Add Active Child");
351   gtk_box_pack_start (GTK_BOX(vbox), button, FALSE, FALSE, 0);
352
353   g_signal_connect_swapped (button, "clicked",
354                             G_CALLBACK (add_active_child), vbox);
355
356   button = gtk_button_new_with_label ("Add Passive Child");
357   gtk_box_pack_start (GTK_BOX(vbox), button, FALSE, FALSE, 0);
358
359   g_signal_connect_swapped (button, "clicked",
360                             G_CALLBACK (add_passive_child), vbox);
361
362   button = gtk_button_new_with_label ("Add Local Active Child");
363   gtk_box_pack_start (GTK_BOX(vbox), button, FALSE, FALSE, 0);
364
365   g_signal_connect_swapped (button, "clicked",
366                             G_CALLBACK (add_local_active_child), vbox);
367
368   button = gtk_button_new_with_label ("Add Local Passive Child");
369   gtk_box_pack_start (GTK_BOX(vbox), button, FALSE, FALSE, 0);
370
371   g_signal_connect_swapped (button, "clicked",
372                             G_CALLBACK (add_local_passive_child), vbox);
373
374   button = gtk_button_new_with_label ("Remove Last Child");
375   gtk_box_pack_start (GTK_BOX(vbox), button, FALSE, FALSE, 0);
376
377   g_signal_connect_swapped (button, "clicked",
378                             G_CALLBACK (remove_child), vbox);
379
380   checkbutton = gtk_check_button_new_with_label ("Grab keyboard");
381   gtk_box_pack_start (GTK_BOX (vbox), checkbutton, FALSE, FALSE, 0);
382
383   g_signal_connect (checkbutton, "toggled",
384                     G_CALLBACK (grab_window_toggled),
385                     window);
386
387   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
388   gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
389
390   entry = gtk_entry_new ();
391   gtk_box_pack_start (GTK_BOX(hbox), entry, FALSE, FALSE, 0);
392
393   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
394   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
395
396   box = hbox;
397   
398   gtk_widget_show_all (window);
399
400   gtk_main ();
401
402   if (n_children)
403     {
404       g_print ("Waiting for children to exit\n");
405
406       while (n_children)
407         g_main_context_iteration (NULL, TRUE);
408     }
409
410   return 0;
411 }