]> Pileus Git - ~andy/gtk/blob - gdk/broadway/gdkdisplay-broadway.c
[broadway] Wire up the delete event
[~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-broadway.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_broadway_display_dispose            (GObject            *object);
45 static void   gdk_broadway_display_finalize           (GObject            *object);
46
47 G_DEFINE_TYPE (GdkBroadwayDisplay, gdk_broadway_display, GDK_TYPE_DISPLAY)
48
49 static void
50 gdk_broadway_display_init (GdkBroadwayDisplay *display)
51 {
52   _gdk_broadway_display_manager_add_display (gdk_display_manager_get (),
53                                              GDK_DISPLAY_OBJECT (display));
54   display->id_ht = g_hash_table_new (NULL, NULL);
55 }
56
57 static void
58 gdk_event_init (GdkDisplay *display)
59 {
60   GdkBroadwayDisplay *broadway_display;
61
62   broadway_display = GDK_BROADWAY_DISPLAY (display);
63   broadway_display->event_source = _gdk_broadway_event_source_new (display);
64   broadway_display->saved_serial = 1;
65 }
66
67 static void
68 gdk_broadway_display_init_input (GdkDisplay *display)
69 {
70   GdkBroadwayDisplay *broadway_display;
71   GdkDeviceManager *device_manager;
72   GdkDevice *device;
73   GList *list, *l;
74
75   broadway_display = GDK_BROADWAY_DISPLAY (display);
76   device_manager = gdk_display_get_device_manager (display);
77
78   /* For backwards compatibility, just add
79    * floating devices that are not keyboards.
80    */
81   list = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING);
82
83   for (l = list; l; l = l->next)
84     {
85       device = l->data;
86
87       if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
88         continue;
89
90       broadway_display->input_devices = g_list_prepend (broadway_display->input_devices,
91                                                    g_object_ref (l->data));
92     }
93
94   g_list_free (list);
95
96   /* Now set "core" pointer to the first
97    * master device that is a pointer.
98    */
99   list = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
100
101   for (l = list; l; l = l->next)
102     {
103       device = list->data;
104
105       if (gdk_device_get_source (device) != GDK_SOURCE_MOUSE)
106         continue;
107
108       display->core_pointer = device;
109       break;
110     }
111
112   /* Add the core pointer to the devices list */
113   broadway_display->input_devices = g_list_prepend (broadway_display->input_devices,
114                                                g_object_ref (display->core_pointer));
115
116   g_list_free (list);
117 }
118
119 typedef struct HttpRequest {
120   GdkDisplay *display;
121   GSocketConnection *connection;
122   GDataInputStream *data;
123   GString *request;
124 }  HttpRequest;
125
126 static void
127 http_request_free (HttpRequest *request)
128 {
129   g_object_unref (request->connection);
130   g_object_unref (request->data);
131   g_string_free (request->request, TRUE);
132   g_free (request);
133 }
134
135 struct BroadwayInput {
136   GdkDisplay *display;
137   GSocketConnection *connection;
138   GByteArray *buffer;
139   GSource *source;
140 };
141
142 static void
143 broadway_input_free (BroadwayInput *input)
144 {
145   g_object_unref (input->connection);
146   g_byte_array_free (input->buffer, FALSE);
147   g_source_destroy (input->source);
148   g_free (input);
149 }
150
151 static void
152 process_input_messages (GdkBroadwayDisplay *broadway_display)
153 {
154   BroadwayInputMsg *message;
155
156   while (broadway_display->input_messages)
157     {
158       message = broadway_display->input_messages->data;
159       broadway_display->input_messages =
160         g_list_delete_link (broadway_display->input_messages,
161                             broadway_display->input_messages);
162
163       _gdk_broadway_events_got_input (GDK_DISPLAY (broadway_display), message);
164       g_free (message);
165     }
166 }
167
168 static char *
169 parse_pointer_data (char *p, BroadwayInputPointerMsg *data)
170 {
171   data->mouse_window_id = strtol (p, &p, 10);
172   p++; /* Skip , */
173   data->event_window_id = strtol (p, &p, 10);
174   p++; /* Skip , */
175   data->root_x = strtol (p, &p, 10);
176   p++; /* Skip , */
177   data->root_y = strtol (p, &p, 10);
178   p++; /* Skip , */
179   data->win_x = strtol (p, &p, 10);
180   p++; /* Skip , */
181   data->win_y = strtol (p, &p, 10);
182   p++; /* Skip , */
183   data->state = strtol (p, &p, 10);
184
185   return p;
186 }
187
188 static void
189 update_future_pointer_info (GdkBroadwayDisplay *broadway_display, BroadwayInputPointerMsg *data)
190 {
191   broadway_display->future_root_x = data->root_x;
192   broadway_display->future_root_y = data->root_y;
193   broadway_display->future_mouse_in_toplevel = data->mouse_window_id;
194 }
195
196 static void
197 parse_input_message (BroadwayInput *input, const char *message)
198 {
199   GdkBroadwayDisplay *broadway_display;
200   BroadwayInputMsg msg;
201   char *p;
202
203   broadway_display = GDK_BROADWAY_DISPLAY (input->display);
204
205   p = (char *)message;
206   msg.base.type = *p++;
207   msg.base.serial = (guint32)strtol (p, &p, 10);
208   p++; /* Skip , */
209   msg.base.time = strtol(p, &p, 10);
210   p++; /* Skip , */
211
212   switch (msg.base.type) {
213   case 'e': /* Enter */
214   case 'l': /* Leave */
215     p = parse_pointer_data (p, &msg.pointer);
216     update_future_pointer_info (broadway_display, &msg.pointer);
217     p++; /* Skip , */
218     msg.crossing.mode = strtol(p, &p, 10);
219     break;
220
221   case 'm': /* Mouse move */
222     p = parse_pointer_data (p, &msg.pointer);
223     update_future_pointer_info (broadway_display, &msg.pointer);
224     break;
225
226   case 'b':
227   case 'B':
228     p = parse_pointer_data (p, &msg.pointer);
229     update_future_pointer_info (broadway_display, &msg.pointer);
230     p++; /* Skip , */
231     msg.button.button = strtol(p, &p, 10);
232     break;
233
234   case 's':
235     p = parse_pointer_data (p, &msg.pointer);
236     update_future_pointer_info (broadway_display, &msg.pointer);
237     p++; /* Skip , */
238     msg.scroll.dir = strtol(p, &p, 10);
239     break;
240
241   case 'k':
242   case 'K':
243     msg.key.key = strtol(p, &p, 10);
244     break;
245
246   case 'g':
247   case 'u':
248     msg.grab_reply.res = strtol(p, &p, 10);
249     break;
250
251   case 'w':
252     msg.configure_notify.id = strtol(p, &p, 10);
253     p++; /* Skip , */
254     msg.configure_notify.x = strtol (p, &p, 10);
255     p++; /* Skip , */
256     msg.configure_notify.y = strtol (p, &p, 10);
257     p++; /* Skip , */
258     msg.configure_notify.width = strtol (p, &p, 10);
259     p++; /* Skip , */
260     msg.configure_notify.height = strtol (p, &p, 10);
261     break;
262
263   case 'W':
264     msg.delete_notify.id = strtol(p, &p, 10);
265     break;
266
267   default:
268     g_printerr ("Unknown input command %s\n", message);
269     break;
270   }
271
272   broadway_display->input_messages = g_list_append (broadway_display->input_messages, g_memdup (&msg, sizeof (msg)));
273
274 }
275
276 static void
277 parse_input (BroadwayInput *input)
278 {
279   GdkBroadwayDisplay *broadway_display;
280   char *buf, *ptr;
281   gsize len;
282
283   broadway_display = GDK_BROADWAY_DISPLAY (input->display);
284
285   buf = (char *)input->buffer->data;
286   len = input->buffer->len;
287
288   if (len == 0)
289     return;
290
291   if (buf[0] != 0)
292     {
293       broadway_display->input = NULL;
294       broadway_input_free (input);
295       return;
296     }
297
298   while ((ptr = memchr (buf, 0xff, len)) != NULL)
299     {
300       *ptr = 0;
301       ptr++;
302
303       parse_input_message (input, buf + 1);
304
305       len -= ptr - buf;
306       buf = ptr;
307
308       if (len > 0 && buf[0] != 0)
309         {
310           broadway_display->input = NULL;
311           broadway_input_free (input);
312           break;
313         }
314     }
315
316   g_byte_array_remove_range (input->buffer, 0, buf - (char *)input->buffer->data);
317 }
318
319
320 static gboolean
321 process_input_idle_cb (GdkBroadwayDisplay *display)
322 {
323   display->process_input_idle = 0;
324   process_input_messages (display);
325   return FALSE;
326 }
327
328 static void
329 queue_process_input_at_idle (GdkBroadwayDisplay *broadway_display)
330 {
331   if (broadway_display->process_input_idle == 0)
332     broadway_display->process_input_idle =
333       g_idle_add_full (GDK_PRIORITY_EVENTS, (GSourceFunc)process_input_idle_cb, broadway_display, NULL);
334 }
335
336 static void
337 _gdk_broadway_display_read_all_input_nonblocking (GdkDisplay *display)
338 {
339   GdkBroadwayDisplay *broadway_display;
340   GInputStream *in;
341   gssize res;
342   guint8 buffer[1024];
343   GError *error;
344   BroadwayInput *input;
345
346   broadway_display = GDK_BROADWAY_DISPLAY (display);
347   if (broadway_display->input == NULL)
348     return;
349
350   input = broadway_display->input;
351
352   in = g_io_stream_get_input_stream (G_IO_STREAM (input->connection));
353
354   error = NULL;
355   res = g_pollable_input_stream_read_nonblocking (G_POLLABLE_INPUT_STREAM (in),
356                                                   buffer, sizeof (buffer), NULL, &error);
357
358   if (res <= 0)
359     {
360       if (res < 0 &&
361           g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
362         {
363           g_error_free (error);
364           return;
365         }
366
367       broadway_display->input = NULL;
368       broadway_input_free (input);
369       if (res < 0)
370         {
371           g_print ("input error %s", error->message);
372           g_error_free (error);
373         }
374       return;
375     }
376
377   g_byte_array_append (input->buffer, buffer, res);
378
379   parse_input (input);
380 }
381
382 void
383 _gdk_broadway_display_consume_all_input (GdkDisplay *display)
384 {
385   GdkBroadwayDisplay *broadway_display;
386
387   broadway_display = GDK_BROADWAY_DISPLAY (display);
388   _gdk_broadway_display_read_all_input_nonblocking (display);
389
390   /* Since we're parsing input but not processing the resulting messages
391      we might not get a readable callback on the stream, so queue an idle to
392      process the messages */
393   queue_process_input_at_idle (broadway_display);
394 }
395
396
397 static gboolean
398 input_data_cb (GObject  *stream,
399                BroadwayInput *input)
400 {
401   GdkBroadwayDisplay *broadway_display;
402
403   broadway_display = GDK_BROADWAY_DISPLAY (input->display);
404   _gdk_broadway_display_read_all_input_nonblocking (input->display);
405
406   process_input_messages (broadway_display);
407
408   return TRUE;
409 }
410
411 /* Note: This may be called while handling a message (i.e. sorta recursively) */
412 BroadwayInputMsg *
413 _gdk_broadway_display_block_for_input (GdkDisplay *display, char op,
414                                        guint32 serial, gboolean remove_message)
415 {
416   GdkBroadwayDisplay *broadway_display;
417   BroadwayInputMsg *message;
418   gssize res;
419   guint8 buffer[1024];
420   BroadwayInput *input;
421   GInputStream *in;
422   GList *l;
423
424   gdk_display_flush (display);
425
426   broadway_display = GDK_BROADWAY_DISPLAY (display);
427   if (broadway_display->input == NULL)
428     return NULL;
429
430   input = broadway_display->input;
431
432   while (TRUE) {
433     /* Check for existing reply in queue */
434
435     for (l = broadway_display->input_messages; l != NULL; l = l->next)
436       {
437         message = l->data;
438
439         if (message->base.type == op)
440           {
441             if (message->base.serial == serial)
442               {
443                 if (remove_message)
444                   broadway_display->input_messages =
445                     g_list_delete_link (broadway_display->input_messages, l);
446                 return message;
447               }
448           }
449       }
450
451     /* Not found, read more, blocking */
452
453     in = g_io_stream_get_input_stream (G_IO_STREAM (input->connection));
454     res = g_input_stream_read (in, buffer, sizeof (buffer), NULL, NULL);
455     if (res <= 0)
456       return NULL;
457     g_byte_array_append (input->buffer, buffer, res);
458
459     parse_input (input);
460
461     /* Since we're parsing input but not processing the resulting messages
462        we might not get a readable callback on the stream, so queue an idle to
463        process the messages */
464     queue_process_input_at_idle (broadway_display);
465   }
466 }
467
468 #include <unistd.h>
469 #include <fcntl.h>
470 static void
471 set_fd_blocking (int fd)
472 {
473   glong arg;
474
475   if ((arg = fcntl (fd, F_GETFL, NULL)) < 0)
476     arg = 0;
477
478   arg = arg & ~O_NONBLOCK;
479
480   fcntl (fd, F_SETFL, arg);
481 }
482
483 static char *
484 parse_line (char *line, char *key)
485 {
486   char *p;
487
488   if (!g_str_has_prefix (line, key))
489     return NULL;
490   p = line + strlen (key);
491   if (*p != ':')
492     return NULL;
493   p++;
494   /* Skip optional initial space */
495   if (*p == ' ')
496     p++;
497   return p;
498 }
499 static void
500 send_error (HttpRequest *request,
501             int error_code,
502             const char *reason)
503 {
504   char *res;
505
506   res = g_strdup_printf ("HTTP/1.0 %d %s\r\n\r\n"
507                          "<html><head><title>%d %s</title></head>"
508                          "<body>%s</body></html>",
509                          error_code, reason,
510                          error_code, reason,
511                          reason);
512   /* TODO: This should really be async */
513   g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
514                              res, strlen (res), NULL, NULL, NULL);
515   g_free (res);
516   http_request_free (request);
517 }
518
519 static void
520 start_input (HttpRequest *request)
521 {
522   char **lines;
523   char *p;
524   int num_key1, num_key2;
525   guint64 key1, key2;
526   int num_space;
527   int i;
528   guint8 challenge[16];
529   char *res;
530   gsize len;
531   GChecksum *checksum;
532   char *origin, *host;
533   GdkBroadwayDisplay *broadway_display;
534   BroadwayInput *input;
535   const void *data_buffer;
536   gsize data_buffer_size;
537   GInputStream *in;
538
539   broadway_display = GDK_BROADWAY_DISPLAY (request->display);
540
541   if (broadway_display->input != NULL)
542     {
543       send_error (request, 409, "Input already handled");
544       return;
545     }
546
547   lines = g_strsplit (request->request->str, "\n", 0);
548
549   num_key1 = 0;
550   num_key2 = 0;
551   key1 = 0;
552   key2 = 0;
553   origin = NULL;
554   host = NULL;
555   for (i = 0; lines[i] != NULL; i++)
556     {
557       if ((p = parse_line (lines[i], "Sec-WebSocket-Key1")))
558         {
559           num_space = 0;
560           while (*p != 0)
561             {
562               if (g_ascii_isdigit (*p))
563                 key1 = key1 * 10 + g_ascii_digit_value (*p);
564               else if (*p == ' ')
565                 num_space++;
566
567               p++;
568             }
569           key1 /= num_space;
570           num_key1++;
571         }
572       else if ((p = parse_line (lines[i], "Sec-WebSocket-Key2")))
573         {
574           num_space = 0;
575           while (*p != 0)
576             {
577               if (g_ascii_isdigit (*p))
578                 key2 = key2 * 10 + g_ascii_digit_value (*p);
579               else if (*p == ' ')
580                 num_space++;
581
582               p++;
583             }
584           key2 /= num_space;
585           num_key2++;
586         }
587       else if ((p = parse_line (lines[i], "Origin")))
588         {
589           origin = p;
590         }
591       else if ((p = parse_line (lines[i], "Host")))
592         {
593           host = p;
594         }
595     }
596
597   if (num_key1 != 1 || num_key2 != 1 || origin == NULL || host == NULL)
598     {
599       g_strfreev (lines);
600       send_error (request, 400, "Bad websocket request");
601       return;
602     }
603
604   challenge[0] = (key1 >> 24) & 0xff;
605   challenge[1] = (key1 >> 16) & 0xff;
606   challenge[2] = (key1 >>  8) & 0xff;
607   challenge[3] = (key1 >>  0) & 0xff;
608   challenge[4] = (key2 >> 24) & 0xff;
609   challenge[5] = (key2 >> 16) & 0xff;
610   challenge[6] = (key2 >>  8) & 0xff;
611   challenge[7] = (key2 >>  0) & 0xff;
612
613   if (!g_input_stream_read_all (G_INPUT_STREAM (request->data), challenge+8, 8, NULL, NULL, NULL))
614     {
615       g_strfreev (lines);
616       send_error (request, 400, "Bad websocket request");
617       return;
618     }
619
620   checksum = g_checksum_new (G_CHECKSUM_MD5);
621   g_checksum_update (checksum, challenge, 16);
622   len = 16;
623   g_checksum_get_digest (checksum, challenge, &len);
624   g_checksum_free (checksum);
625
626   res = g_strdup_printf ("HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
627                          "Upgrade: WebSocket\r\n"
628                          "Connection: Upgrade\r\n"
629                          "Sec-WebSocket-Origin: %s\r\n"
630                          "Sec-WebSocket-Location: ws://%s/input\r\n"
631                          "Sec-WebSocket-Protocol: broadway\r\n"
632                          "\r\n",
633                          origin, host);
634
635   g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
636                              res, strlen (res), NULL, NULL, NULL);
637   g_free (res);
638   g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
639                              challenge, 16, NULL, NULL, NULL);
640
641   input = g_new0 (BroadwayInput, 1);
642
643   input->display = request->display;
644   input->connection = g_object_ref (request->connection);
645
646   data_buffer = g_buffered_input_stream_peek_buffer (G_BUFFERED_INPUT_STREAM (request->data), &data_buffer_size);
647   input->buffer = g_byte_array_sized_new (data_buffer_size);
648   g_byte_array_append (input->buffer, data_buffer, data_buffer_size);
649
650   broadway_display->input = input;
651
652   /* This will free and close the data input stream, but we got all the buffered content already */
653   http_request_free (request);
654
655   in = g_io_stream_get_input_stream (G_IO_STREAM (input->connection));
656   input->source = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (in), NULL);
657   g_source_set_callback (input->source, (GSourceFunc)input_data_cb, input, NULL);
658   g_source_attach (input->source, NULL);
659
660   /* Process any data in the pipe already */
661   parse_input (input);
662   process_input_messages (broadway_display);
663
664   g_strfreev (lines);
665 }
666
667 static void
668 start_output (HttpRequest *request)
669 {
670   GSocket *socket;
671   GdkBroadwayDisplay *broadway_display;
672   int fd;
673
674   socket = g_socket_connection_get_socket (request->connection);
675
676   broadway_display = GDK_BROADWAY_DISPLAY (request->display);
677   fd = g_socket_get_fd (socket);
678   set_fd_blocking (fd);
679   /* We dup this because otherwise it'll be closed with the request SocketConnection */
680
681   if (broadway_display->output)
682     {
683       broadway_display->saved_serial = broadway_output_get_next_serial (broadway_display->output);
684       broadway_output_free (broadway_display->output);
685     }
686
687   broadway_display->output = broadway_output_new (dup(fd), broadway_display->saved_serial);
688   _gdk_broadway_resync_windows ();
689
690   if (broadway_display->pointer_grab_window)
691     broadway_output_grab_pointer (broadway_display->output,
692                                   GDK_WINDOW_IMPL_BROADWAY (broadway_display->pointer_grab_window->impl)->id,
693                                   broadway_display->pointer_grab_owner_events);
694
695   http_request_free (request);
696 }
697
698 static void
699 send_data (HttpRequest *request,
700              const char *mimetype,
701              const char *data, gsize len)
702 {
703   char *res;
704
705   res = g_strdup_printf ("HTTP/1.0 200 OK\r\n"
706                          "Content-Type: %s\r\n"
707                          "Content-Length: %"G_GSIZE_FORMAT"\r\n"
708                          "\r\n",
709                          mimetype, len);
710   /* TODO: This should really be async */
711   g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
712                              res, strlen (res), NULL, NULL, NULL);
713   g_free (res);
714   g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
715                              data, len, NULL, NULL, NULL);
716   http_request_free (request);
717 }
718
719 #include "clienthtml.h"
720 #include "broadwayjs.h"
721
722 static void
723 got_request (HttpRequest *request)
724 {
725   char *start, *escaped, *tmp, *version;
726
727   if (!g_str_has_prefix (request->request->str, "GET "))
728     {
729       send_error (request, 501, "Only GET implemented");
730       return;
731     }
732
733   start = request->request->str + 4; /* Skip "GET " */
734
735   while (*start == ' ')
736     start++;
737
738   for (tmp = start; *tmp != 0 && *tmp != ' ' && *tmp != '\n'; tmp++)
739     ;
740   escaped = g_strndup (start, tmp - start);
741   version = NULL;
742   if (*tmp == ' ')
743     {
744       start = tmp;
745       while (*start == ' ')
746         start++;
747       for (tmp = start; *tmp != 0 && *tmp != ' ' && *tmp != '\n'; tmp++)
748         ;
749       version = g_strndup (start, tmp - start);
750     }
751
752   if (strcmp (escaped, "/client.html") == 0 || strcmp (escaped, "/") == 0)
753     send_data (request, "text/html", client_html, G_N_ELEMENTS(client_html) - 1);
754   else if (strcmp (escaped, "/broadway.js") == 0)
755     send_data (request, "text/javascript", broadway_js, G_N_ELEMENTS(broadway_js) - 1);
756   else if (strcmp (escaped, "/output") == 0)
757     start_output (request);
758   else if (strcmp (escaped, "/input") == 0)
759     start_input (request);
760   else
761     send_error (request, 404, "File not found");
762 }
763
764 static void
765 got_http_request_line (GInputStream *stream,
766                        GAsyncResult *result,
767                        HttpRequest *request)
768 {
769   char *line;
770
771   line = g_data_input_stream_read_line_finish (G_DATA_INPUT_STREAM (stream), result, NULL, NULL);
772   if (line == NULL)
773     {
774       http_request_free (request);
775       g_printerr ("Error reading request lines\n");
776       return;
777     }
778   if (strlen (line) == 0)
779     got_request (request);
780   else
781     {
782       /* Protect against overflow in request length */
783       if (request->request->len > 1024 * 5)
784         {
785           send_error (request, 400, "Request to long");
786         }
787       else
788         {
789           g_string_append_printf (request->request, "%s\n", line);
790           g_data_input_stream_read_line_async (request->data, 0, NULL,
791                                                (GAsyncReadyCallback)got_http_request_line, request);
792         }
793     }
794   g_free (line);
795 }
796
797 static gboolean
798 handle_incoming_connection (GSocketService    *service,
799                             GSocketConnection *connection,
800                             GObject           *source_object)
801 {
802   HttpRequest *request;
803   GInputStream *in;
804
805   request = g_new0 (HttpRequest, 1);
806   request->connection = g_object_ref (connection);
807   request->display = (GdkDisplay *) source_object;
808   request->request = g_string_new ("");
809
810   in = g_io_stream_get_input_stream (G_IO_STREAM (connection));
811
812   request->data = g_data_input_stream_new (in);
813   g_filter_input_stream_set_close_base_stream (G_FILTER_INPUT_STREAM (request->data), FALSE);
814   /* Be tolerant of input */
815   g_data_input_stream_set_newline_type (request->data, G_DATA_STREAM_NEWLINE_TYPE_ANY);
816
817   g_data_input_stream_read_line_async (request->data, 0, NULL,
818                                        (GAsyncReadyCallback)got_http_request_line, request);
819   return TRUE;
820 }
821
822 GdkDisplay *
823 _gdk_broadway_display_open (const gchar *display_name)
824 {
825   GdkDisplay *display;
826   GdkBroadwayDisplay *broadway_display;
827   GError *error;
828   int port;
829
830   display = g_object_new (GDK_TYPE_BROADWAY_DISPLAY, NULL);
831   broadway_display = GDK_BROADWAY_DISPLAY (display);
832
833   broadway_display->output = NULL;
834
835   /* initialize the display's screens */
836   broadway_display->screens = g_new (GdkScreen *, 1);
837   broadway_display->screens[0] = _gdk_broadway_screen_new (display, 0);
838
839   /* We need to initialize events after we have the screen
840    * structures in places
841    */
842   _gdk_broadway_screen_events_init (broadway_display->screens[0]);
843
844   /*set the default screen */
845   broadway_display->default_screen = broadway_display->screens[0];
846
847   display->device_manager = _gdk_broadway_device_manager_new (display);
848
849   gdk_event_init (display);
850
851   gdk_broadway_display_init_input (display);
852   _gdk_broadway_display_init_dnd (display);
853
854   _gdk_broadway_screen_setup (broadway_display->screens[0]);
855
856   if (display_name == NULL)
857     display_name = g_getenv ("BROADWAY_DISPLAY");
858
859   port = 0;
860   if (display_name != NULL)
861     port = strtol(display_name, NULL, 10);
862   if (port == 0)
863     port = 8080;
864
865   broadway_display->service = g_socket_service_new ();
866   if (!g_socket_listener_add_inet_port (G_SOCKET_LISTENER (broadway_display->service),
867                                         port,
868                                         G_OBJECT (display),
869                                         &error))
870     {
871       g_printerr ("Unable to listen to port %d: %s\n", 8080, error->message);
872       g_error_free (error);
873       return NULL;
874     }
875   g_signal_connect (broadway_display->service, "incoming", G_CALLBACK (handle_incoming_connection), NULL);
876
877   g_signal_emit_by_name (display, "opened");
878   g_signal_emit_by_name (gdk_display_manager_get (), "display-opened", display);
879
880   return display;
881 }
882
883
884 static G_CONST_RETURN gchar *
885 gdk_broadway_display_get_name (GdkDisplay *display)
886 {
887   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
888
889   return (gchar *) "Broadway";
890 }
891
892 static gint
893 gdk_broadway_display_get_n_screens (GdkDisplay *display)
894 {
895   g_return_val_if_fail (GDK_IS_DISPLAY (display), 0);
896
897   return 1;
898 }
899
900 static GdkScreen *
901 gdk_broadway_display_get_screen (GdkDisplay *display,
902                                  gint        screen_num)
903 {
904   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
905   g_return_val_if_fail (screen_num == 0, NULL);
906
907   return GDK_BROADWAY_DISPLAY (display)->screens[screen_num];
908 }
909
910 static GdkScreen *
911 gdk_broadway_display_get_default_screen (GdkDisplay *display)
912 {
913   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
914
915   return GDK_BROADWAY_DISPLAY (display)->default_screen;
916 }
917
918 static void
919 gdk_broadway_display_beep (GdkDisplay *display)
920 {
921   g_return_if_fail (GDK_IS_DISPLAY (display));
922 }
923
924 static void
925 gdk_broadway_display_sync (GdkDisplay *display)
926 {
927   g_return_if_fail (GDK_IS_DISPLAY (display));
928
929 }
930
931 static void
932 gdk_broadway_display_flush (GdkDisplay *display)
933 {
934   GdkBroadwayDisplay *broadway_display = GDK_BROADWAY_DISPLAY (display);
935
936   g_return_if_fail (GDK_IS_DISPLAY (display));
937
938   if (broadway_display->output &&
939       !broadway_output_flush (broadway_display->output))
940     {
941       broadway_display->saved_serial = broadway_output_get_next_serial (broadway_display->output);
942       broadway_output_free (broadway_display->output);
943       broadway_display->output = NULL;
944     }
945 }
946
947 static gboolean
948 gdk_broadway_display_has_pending (GdkDisplay *display)
949 {
950   return FALSE;
951 }
952
953 static GdkWindow *
954 gdk_broadway_display_get_default_group (GdkDisplay *display)
955 {
956   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
957
958   return NULL;
959 }
960
961 static void
962 gdk_broadway_display_dispose (GObject *object)
963 {
964   GdkBroadwayDisplay *broadway_display = GDK_BROADWAY_DISPLAY (object);
965
966   _gdk_broadway_display_manager_remove_display (gdk_display_manager_get (),
967                                                 GDK_DISPLAY_OBJECT (object));
968
969   g_list_foreach (broadway_display->input_devices, (GFunc) g_object_run_dispose, NULL);
970
971   _gdk_screen_close (broadway_display->screens[0]);
972
973   if (broadway_display->event_source)
974     {
975       g_source_destroy (broadway_display->event_source);
976       g_source_unref (broadway_display->event_source);
977       broadway_display->event_source = NULL;
978     }
979
980   G_OBJECT_CLASS (gdk_broadway_display_parent_class)->dispose (object);
981 }
982
983 static void
984 gdk_broadway_display_finalize (GObject *object)
985 {
986   GdkBroadwayDisplay *broadway_display = GDK_BROADWAY_DISPLAY (object);
987
988   /* Keymap */
989   if (broadway_display->keymap)
990     g_object_unref (broadway_display->keymap);
991
992   _gdk_broadway_cursor_display_finalize (GDK_DISPLAY_OBJECT(broadway_display));
993
994   /* Atom Hashtable */
995   g_hash_table_destroy (broadway_display->atom_from_virtual);
996   g_hash_table_destroy (broadway_display->atom_to_virtual);
997
998   /* input GdkDevice list */
999   g_list_foreach (broadway_display->input_devices, (GFunc) g_object_unref, NULL);
1000   g_list_free (broadway_display->input_devices);
1001   /* Free all GdkScreens */
1002   g_object_unref (broadway_display->screens[0]);
1003   g_free (broadway_display->screens);
1004
1005   G_OBJECT_CLASS (gdk_broadway_display_parent_class)->finalize (object);
1006 }
1007
1008 void
1009 _gdk_broadway_display_make_default (GdkDisplay *display)
1010 {
1011 }
1012
1013 static void
1014 gdk_broadway_display_notify_startup_complete (GdkDisplay  *display,
1015                                               const gchar *startup_id)
1016 {
1017 }
1018
1019 static gboolean
1020 gdk_broadway_display_supports_selection_notification (GdkDisplay *display)
1021 {
1022   return FALSE;
1023 }
1024
1025 static gboolean
1026 gdk_broadway_display_request_selection_notification (GdkDisplay *display,
1027                                                      GdkAtom     selection)
1028
1029 {
1030     return FALSE;
1031 }
1032
1033 static gboolean
1034 gdk_broadway_display_supports_clipboard_persistence (GdkDisplay *display)
1035 {
1036   return FALSE;
1037 }
1038
1039 static void
1040 gdk_broadway_display_store_clipboard (GdkDisplay    *display,
1041                                       GdkWindow     *clipboard_window,
1042                                       guint32        time_,
1043                                       const GdkAtom *targets,
1044                                       gint           n_targets)
1045 {
1046 }
1047
1048 static gboolean
1049 gdk_broadway_display_supports_shapes (GdkDisplay *display)
1050 {
1051   return FALSE;
1052 }
1053
1054 static gboolean
1055 gdk_broadway_display_supports_input_shapes (GdkDisplay *display)
1056 {
1057   return FALSE;
1058 }
1059
1060 static gboolean
1061 gdk_broadway_display_supports_composite (GdkDisplay *display)
1062 {
1063   return FALSE;
1064 }
1065
1066 static GList *
1067 gdk_broadway_display_list_devices (GdkDisplay *display)
1068 {
1069   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
1070
1071   return GDK_BROADWAY_DISPLAY (display)->input_devices;
1072 }
1073
1074 static gulong
1075 gdk_broadway_display_get_next_serial (GdkDisplay *display)
1076 {
1077   GdkBroadwayDisplay *broadway_display;
1078   broadway_display = GDK_BROADWAY_DISPLAY (display);
1079   if (broadway_display->output)
1080     return broadway_output_get_next_serial (broadway_display->output);
1081   return broadway_display->saved_serial;
1082 }
1083
1084
1085 static void
1086 gdk_broadway_display_event_data_copy (GdkDisplay    *display,
1087                                       const GdkEvent *src,
1088                                       GdkEvent       *dst)
1089 {
1090 }
1091
1092 static void
1093 gdk_broadway_display_event_data_free (GdkDisplay    *display,
1094                                       GdkEvent *event)
1095 {
1096 }
1097
1098 static void
1099 gdk_broadway_display_class_init (GdkBroadwayDisplayClass * class)
1100 {
1101   GObjectClass *object_class = G_OBJECT_CLASS (class);
1102   GdkDisplayClass *display_class = GDK_DISPLAY_CLASS (class);
1103
1104   object_class->dispose = gdk_broadway_display_dispose;
1105   object_class->finalize = gdk_broadway_display_finalize;
1106
1107   display_class->window_type = GDK_TYPE_BROADWAY_WINDOW;
1108
1109   display_class->get_name = gdk_broadway_display_get_name;
1110   display_class->get_n_screens = gdk_broadway_display_get_n_screens;
1111   display_class->get_screen = gdk_broadway_display_get_screen;
1112   display_class->get_default_screen = gdk_broadway_display_get_default_screen;
1113   display_class->beep = gdk_broadway_display_beep;
1114   display_class->sync = gdk_broadway_display_sync;
1115   display_class->flush = gdk_broadway_display_flush;
1116   display_class->has_pending = gdk_broadway_display_has_pending;
1117   display_class->queue_events = _gdk_broadway_display_queue_events;
1118   display_class->get_default_group = gdk_broadway_display_get_default_group;
1119   display_class->supports_selection_notification = gdk_broadway_display_supports_selection_notification;
1120   display_class->request_selection_notification = gdk_broadway_display_request_selection_notification;
1121   display_class->supports_clipboard_persistence = gdk_broadway_display_supports_clipboard_persistence;
1122   display_class->store_clipboard = gdk_broadway_display_store_clipboard;
1123   display_class->supports_shapes = gdk_broadway_display_supports_shapes;
1124   display_class->supports_input_shapes = gdk_broadway_display_supports_input_shapes;
1125   display_class->supports_composite = gdk_broadway_display_supports_composite;
1126   display_class->list_devices = gdk_broadway_display_list_devices;
1127   display_class->get_cursor_for_type = _gdk_broadway_display_get_cursor_for_type;
1128   display_class->get_cursor_for_name = _gdk_broadway_display_get_cursor_for_name;
1129   display_class->get_cursor_for_pixbuf = _gdk_broadway_display_get_cursor_for_pixbuf;
1130   display_class->get_default_cursor_size = _gdk_broadway_display_get_default_cursor_size;
1131   display_class->get_maximal_cursor_size = _gdk_broadway_display_get_maximal_cursor_size;
1132   display_class->supports_cursor_alpha = _gdk_broadway_display_supports_cursor_alpha;
1133   display_class->supports_cursor_color = _gdk_broadway_display_supports_cursor_color;
1134
1135   display_class->before_process_all_updates = _gdk_broadway_display_before_process_all_updates;
1136   display_class->after_process_all_updates = _gdk_broadway_display_after_process_all_updates;
1137   display_class->get_next_serial = gdk_broadway_display_get_next_serial;
1138   display_class->notify_startup_complete = gdk_broadway_display_notify_startup_complete;
1139   display_class->event_data_copy = gdk_broadway_display_event_data_copy;
1140   display_class->event_data_free = gdk_broadway_display_event_data_free;
1141   display_class->create_window_impl = _gdk_broadway_display_create_window_impl;
1142   display_class->get_keymap = _gdk_broadway_display_get_keymap;
1143   display_class->get_selection_owner = _gdk_broadway_display_get_selection_owner;
1144   display_class->set_selection_owner = _gdk_broadway_display_set_selection_owner;
1145   display_class->send_selection_notify = _gdk_broadway_display_send_selection_notify;
1146   display_class->get_selection_property = _gdk_broadway_display_get_selection_property;
1147   display_class->convert_selection = _gdk_broadway_display_convert_selection;
1148   display_class->text_property_to_utf8_list = _gdk_broadway_display_text_property_to_utf8_list;
1149   display_class->utf8_to_string_target = _gdk_broadway_display_utf8_to_string_target;
1150 }
1151