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