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