]> Pileus Git - ~andy/gtk/blob - gdk/broadway/gdkdisplay-broadway.c
Add initial http server
[~andy/gtk] / gdk / broadway / gdkdisplay-broadway.c
1 /* GDK - The GIMP Drawing Kit
2  * gdkdisplay-broadway.c
3  * 
4  * Copyright 2001 Sun Microsystems Inc.
5  * Copyright (C) 2004 Nokia Corporation
6  *
7  * Erwann Chenede <erwann.chenede@sun.com>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 #include "config.h"
26
27 #include "gdkdisplay-broadway.h"
28
29 #include "gdkdisplay.h"
30 #include "gdkeventsource.h"
31 #include "gdkscreen.h"
32 #include "gdkscreen-broadway.h"
33 #include "gdkinternals.h"
34 #include "gdkdeviceprivate.h"
35 #include "gdkdevicemanager.h"
36
37 #include <glib.h>
38 #include <glib/gprintf.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <errno.h>
42 #include <unistd.h>
43
44 static void   gdk_display_broadway_dispose            (GObject            *object);
45 static void   gdk_display_broadway_finalize           (GObject            *object);
46
47 G_DEFINE_TYPE (GdkDisplayBroadway, _gdk_display_broadway, GDK_TYPE_DISPLAY)
48
49
50 static void
51 _gdk_display_broadway_class_init (GdkDisplayBroadwayClass * class)
52 {
53   GObjectClass *object_class = G_OBJECT_CLASS (class);
54
55   object_class->dispose = gdk_display_broadway_dispose;
56   object_class->finalize = gdk_display_broadway_finalize;
57 }
58
59 static void
60 _gdk_display_broadway_init (GdkDisplayBroadway *display)
61 {
62 }
63
64 static void
65 _gdk_event_init (GdkDisplay *display)
66 {
67   GdkDisplayBroadway *display_broadway;
68
69   display_broadway = GDK_DISPLAY_BROADWAY (display);
70   display_broadway->event_source = gdk_event_source_new (display);
71 }
72
73 static void
74 _gdk_input_init (GdkDisplay *display)
75 {
76   GdkDisplayBroadway *display_broadway;
77   GdkDeviceManager *device_manager;
78   GdkDevice *device;
79   GList *list, *l;
80
81   display_broadway = GDK_DISPLAY_BROADWAY (display);
82   device_manager = gdk_display_get_device_manager (display);
83
84   /* For backwards compatibility, just add
85    * floating devices that are not keyboards.
86    */
87   list = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING);
88
89   for (l = list; l; l = l->next)
90     {
91       device = l->data;
92
93       if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
94         continue;
95
96       display_broadway->input_devices = g_list_prepend (display_broadway->input_devices,
97                                                    g_object_ref (l->data));
98     }
99
100   g_list_free (list);
101
102   /* Now set "core" pointer to the first
103    * master device that is a pointer.
104    */
105   list = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
106
107   for (l = list; l; l = l->next)
108     {
109       device = list->data;
110
111       if (gdk_device_get_source (device) != GDK_SOURCE_MOUSE)
112         continue;
113
114       display->core_pointer = device;
115       break;
116     }
117
118   /* Add the core pointer to the devices list */
119   display_broadway->input_devices = g_list_prepend (display_broadway->input_devices,
120                                                g_object_ref (display->core_pointer));
121
122   g_list_free (list);
123 }
124
125 typedef struct {
126   GdkDisplay *display;
127   GSocketConnection *connection;
128   GDataInputStream *data;
129   GString *request;
130 } HttpRequest;
131
132 static void
133 http_request_free (HttpRequest *request)
134 {
135   g_object_unref (request->connection);
136   g_object_unref (request->data);
137   g_string_free (request->request, TRUE);
138   g_free (request);
139 }
140
141 static void
142 send_error (HttpRequest *request,
143             int error_code,
144             const char *reason)
145 {
146   char *res;
147
148   res = g_strdup_printf ("HTTP/1.0 %d %s\r\n\r\n"
149                          "<html><head><title>%d %s</title></head>"
150                          "<body>%s</body></html>",
151                          error_code, reason,
152                          error_code, reason,
153                          reason);
154   /* TODO: This should really be async */
155   g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
156                              res, strlen (res), NULL, NULL, NULL);
157   g_free (res);
158   http_request_free (request);
159 }
160
161 static void
162 got_request (HttpRequest *request)
163 {
164   g_print ("got request:\n%s", request->request->str);
165   send_error (request, 404, "Not implemented yet");
166 }
167
168 static void
169 got_http_request_line (GOutputStream *stream,
170                        GAsyncResult *result,
171                        HttpRequest *request)
172 {
173   char *line;
174
175   line = g_data_input_stream_read_line_finish (G_DATA_INPUT_STREAM (stream), result, NULL, NULL);
176   if (line == NULL)
177     {
178       http_request_free (request);
179       g_printerr ("Error reading request lines\n");
180       return;
181     }
182   if (strlen (line) == 0)
183     got_request (request);
184   else
185     {
186       /* Protect against overflow in request length */
187       if (request->request->len > 1024 * 5)
188         {
189           send_error (request, 400, "Request to long");
190         }
191       else
192         {
193           g_string_append_printf (request->request, "%s\n", line);
194           g_data_input_stream_read_line_async (request->data, 0, NULL,
195                                                (GAsyncReadyCallback)got_http_request_line, request);
196         }
197     }
198   g_free (line);
199 }
200
201 static gboolean
202 handle_incoming_connection (GSocketService    *service,
203                             GSocketConnection *connection,
204                             GObject           *source_object)
205 {
206   HttpRequest *request;
207   GInputStream *in;
208
209   request = g_new0 (HttpRequest, 1);
210   request->connection = g_object_ref (connection);
211   request->display = (GdkDisplay *) source_object;
212   request->request = g_string_new ("");
213
214   in = g_io_stream_get_input_stream (G_IO_STREAM (connection));
215
216   request->data = g_data_input_stream_new (in);
217   /* Be tolerant of input */
218   g_data_input_stream_set_newline_type (request->data, G_DATA_STREAM_NEWLINE_TYPE_ANY);
219
220   g_data_input_stream_read_line_async (request->data, 0, NULL,
221                                        (GAsyncReadyCallback)got_http_request_line, request);
222   return TRUE;
223 }
224
225 GdkDisplay *
226 gdk_display_open (const gchar *display_name)
227 {
228   GdkDisplay *display;
229   GdkDisplayBroadway *display_broadway;
230   const char *sm_client_id;
231   int fd;
232   GError *error;
233
234   fd = dup(STDOUT_FILENO);
235   dup2(STDERR_FILENO, STDOUT_FILENO);
236
237   display = g_object_new (GDK_TYPE_DISPLAY_BROADWAY, NULL);
238   display_broadway = GDK_DISPLAY_BROADWAY (display);
239
240   display_broadway->connection = broadway_client_new (fd);
241
242   /* initialize the display's screens */
243   display_broadway->screens = g_new (GdkScreen *, 1);
244   display_broadway->screens[0] = _gdk_broadway_screen_new (display, 0);
245
246   /* We need to initialize events after we have the screen
247    * structures in places
248    */
249   _gdk_screen_broadway_events_init (display_broadway->screens[0]);
250
251   /*set the default screen */
252   display_broadway->default_screen = display_broadway->screens[0];
253
254   display->device_manager = _gdk_device_manager_new (display);
255
256   _gdk_event_init (display);
257
258   sm_client_id = _gdk_get_sm_client_id ();
259   if (sm_client_id)
260     _gdk_windowing_display_set_sm_client_id (display, sm_client_id);
261
262   _gdk_input_init (display);
263   _gdk_dnd_init (display);
264
265   _gdk_broadway_screen_setup (display_broadway->screens[0]);
266
267   display_broadway->service = g_socket_service_new ();
268   if (!g_socket_listener_add_inet_port (G_SOCKET_LISTENER (display_broadway->service),
269                                         8080,
270                                         G_OBJECT (display),
271                                         &error))
272     {
273       g_printerr ("Unable to listen to port %d: %s\n", 8080, error->message);
274       g_error_free (error);
275       return NULL;
276     }
277   g_signal_connect (display_broadway->service, "incoming", G_CALLBACK (handle_incoming_connection), NULL);
278
279   g_signal_emit_by_name (display, "opened");
280   g_signal_emit_by_name (gdk_display_manager_get (), "display-opened", display);
281
282   return display;
283 }
284
285
286 G_CONST_RETURN gchar *
287 gdk_display_get_name (GdkDisplay *display)
288 {
289   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
290
291   return (gchar *) "Broadway";
292 }
293
294 gint
295 gdk_display_get_n_screens (GdkDisplay *display)
296 {
297   g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
298
299   return 1;
300 }
301
302 GdkScreen *
303 gdk_display_get_screen (GdkDisplay *display,
304                         gint        screen_num)
305 {
306   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
307   g_return_val_if_fail (screen_num == 0, NULL);
308
309   return GDK_DISPLAY_BROADWAY (display)->screens[screen_num];
310 }
311
312 GdkScreen *
313 gdk_display_get_default_screen (GdkDisplay *display)
314 {
315   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
316
317   return GDK_DISPLAY_BROADWAY (display)->default_screen;
318 }
319
320 void
321 gdk_device_ungrab (GdkDevice  *device,
322                    guint32     time_)
323 {
324 }
325
326 void
327 gdk_display_beep (GdkDisplay *display)
328 {
329   g_return_if_fail (GDK_IS_DISPLAY (display));
330 }
331
332 void
333 gdk_display_sync (GdkDisplay *display)
334 {
335   g_return_if_fail (GDK_IS_DISPLAY (display));
336
337 }
338
339 void
340 gdk_display_flush (GdkDisplay *display)
341 {
342   g_return_if_fail (GDK_IS_DISPLAY (display));
343
344 }
345
346 GdkWindow *
347 gdk_display_get_default_group (GdkDisplay *display)
348 {
349   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
350
351   return NULL;
352 }
353
354 void
355 gdk_broadway_display_grab (GdkDisplay *display)
356 {
357 }
358
359 void
360 gdk_broadway_display_ungrab (GdkDisplay *display)
361 {
362 }
363
364 static void
365 gdk_display_broadway_dispose (GObject *object)
366 {
367   GdkDisplayBroadway *display_broadway = GDK_DISPLAY_BROADWAY (object);
368
369   g_list_foreach (display_broadway->input_devices, (GFunc) g_object_run_dispose, NULL);
370
371   _gdk_screen_close (display_broadway->screens[0]);
372
373   if (display_broadway->event_source)
374     {
375       g_source_destroy (display_broadway->event_source);
376       g_source_unref (display_broadway->event_source);
377       display_broadway->event_source = NULL;
378     }
379
380   G_OBJECT_CLASS (_gdk_display_broadway_parent_class)->dispose (object);
381 }
382
383 static void
384 gdk_display_broadway_finalize (GObject *object)
385 {
386   GdkDisplayBroadway *display_broadway = GDK_DISPLAY_BROADWAY (object);
387
388   /* Keymap */
389   if (display_broadway->keymap)
390     g_object_unref (display_broadway->keymap);
391
392   _gdk_broadway_cursor_display_finalize (GDK_DISPLAY_OBJECT(display_broadway));
393
394   /* Atom Hashtable */
395   g_hash_table_destroy (display_broadway->atom_from_virtual);
396   g_hash_table_destroy (display_broadway->atom_to_virtual);
397
398   /* input GdkDevice list */
399   g_list_foreach (display_broadway->input_devices, (GFunc) g_object_unref, NULL);
400   g_list_free (display_broadway->input_devices);
401   /* Free all GdkScreens */
402   g_object_unref (display_broadway->screens[0]);
403   g_free (display_broadway->screens);
404
405   G_OBJECT_CLASS (_gdk_display_broadway_parent_class)->finalize (object);
406 }
407
408 void
409 _gdk_windowing_set_default_display (GdkDisplay *display)
410 {
411 }
412
413 void
414 gdk_notify_startup_complete (void)
415 {
416 }
417
418 void
419 gdk_notify_startup_complete_with_id (const gchar* startup_id)
420 {
421 }
422
423 gboolean
424 gdk_display_supports_selection_notification (GdkDisplay *display)
425 {
426   return FALSE;
427 }
428
429 gboolean
430 gdk_display_request_selection_notification (GdkDisplay *display,
431                                             GdkAtom     selection)
432
433 {
434     return FALSE;
435 }
436
437 gboolean
438 gdk_display_supports_clipboard_persistence (GdkDisplay *display)
439 {
440   return FALSE;
441 }
442
443 void
444 gdk_display_store_clipboard (GdkDisplay    *display,
445                              GdkWindow     *clipboard_window,
446                              guint32        time_,
447                              const GdkAtom *targets,
448                              gint           n_targets)
449 {
450 }
451
452 guint32
453 gdk_broadway_display_get_user_time (GdkDisplay *display)
454 {
455   return GDK_DISPLAY_BROADWAY (display)->user_time;
456 }
457
458 gboolean
459 gdk_display_supports_shapes (GdkDisplay *display)
460 {
461   return FALSE;
462 }
463
464 gboolean
465 gdk_display_supports_input_shapes (GdkDisplay *display)
466 {
467   return FALSE;
468 }
469
470 gboolean
471 gdk_display_supports_composite (GdkDisplay *display)
472 {
473   return FALSE;
474 }
475
476 GList *
477 gdk_display_list_devices (GdkDisplay *display)
478 {
479   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
480
481   return GDK_DISPLAY_BROADWAY (display)->input_devices;
482 }
483
484 gboolean
485 gdk_event_send_client_message_for_display (GdkDisplay     *display,
486                                            GdkEvent       *event,
487                                            GdkNativeWindow winid)
488 {
489   return FALSE;
490 }
491
492 void
493 gdk_display_add_client_message_filter (GdkDisplay   *display,
494                                        GdkAtom       message_type,
495                                        GdkFilterFunc func,
496                                        gpointer      data)
497 {
498 }
499
500 void
501 gdk_add_client_message_filter (GdkAtom       message_type,
502                                GdkFilterFunc func,
503                                gpointer      data)
504 {
505 }
506
507 void
508 gdk_flush (void)
509 {
510   GSList *tmp_list = _gdk_displays;
511
512   while (tmp_list)
513     {
514       gdk_display_flush (GDK_DISPLAY_OBJECT (tmp_list->data));
515       tmp_list = tmp_list->next;
516     }
517 }
518
519 gulong
520 _gdk_windowing_window_get_next_serial (GdkDisplay *display)
521 {
522   return 0;
523 }