]> Pileus Git - ~andy/gtk/blob - tests/testsocket.c
3b44fd0bb8206c1ce2d6524b72246ae2b38083a0
[~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, FALSE, 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
285   if (gtk_toggle_button_get_active (button))
286     {
287       int status;
288
289       status = gdk_keyboard_grab (gtk_widget_get_window (widget),
290                                   FALSE, GDK_CURRENT_TIME);
291
292       if (status != GDK_GRAB_SUCCESS)
293         g_warning ("Could not grab keyboard!  (%s)", grab_string (status));
294
295     } 
296   else 
297     {
298       gdk_keyboard_ungrab (GDK_CURRENT_TIME);
299     }
300 }
301
302 int
303 main (int argc, char *argv[])
304 {
305   GtkWidget *button;
306   GtkWidget *hbox;
307   GtkWidget *vbox;
308   GtkWidget *menubar;
309   GtkWidget *menuitem;
310   GtkWidget *menu;
311   GtkWidget *entry;
312   GtkWidget *checkbutton;
313   GtkAccelGroup *accel_group;
314
315   gtk_init (&argc, &argv);
316
317   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
318   g_signal_connect (window, "destroy",
319                     G_CALLBACK (gtk_main_quit), NULL);
320   
321   gtk_window_set_title (GTK_WINDOW (window), "Socket Test");
322   gtk_container_set_border_width (GTK_CONTAINER (window), 0);
323
324   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 0);
325   gtk_container_add (GTK_CONTAINER (window), vbox);
326
327   menubar = gtk_menu_bar_new ();
328   menuitem = gtk_menu_item_new_with_mnemonic ("_File");
329   gtk_menu_shell_append (GTK_MENU_SHELL (menubar), menuitem);
330
331   menu = gtk_menu_new ();
332   gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), menu);
333   menuitem = gtk_menu_item_new_with_mnemonic ("_Quit");
334   g_signal_connect (menuitem, "activate", G_CALLBACK (quit_cb), window);
335   gtk_menu_shell_append (GTK_MENU_SHELL (menu), 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_box_new (GTK_ORIENTATION_HORIZONTAL, 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_box_new (GTK_ORIENTATION_HORIZONTAL, 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 }