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