Improvement based on suggestion by Thorsten Maerz:
[platform/upstream/glib.git] / glib / giowin32.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * giowin32.c: IO Channels for Win32.
5  * Copyright 1998 Owen Taylor and Tor Lillqvist
6  * Copyright 1999-2000 Tor Lillqvist and Craig Setera
7  * Copyright 2001 Andrew Lanoix
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser 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  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser 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 /*
26  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
27  * file for a list of people on the GLib Team.  See the ChangeLog
28  * files for a list of changes.  These files are distributed with
29  * GLib at ftp://ftp.gtk.org/pub/gtk/.
30  */
31
32 /* Define this to get (very) verbose logging of all channels */
33 /* #define G_IO_WIN32_DEBUG */
34
35 #include "config.h"
36
37 #include "glib.h"
38
39 #include <stdlib.h>
40 #include <windows.h>
41 #include <winsock.h>          /* Not everybody has winsock2 */
42 #include <fcntl.h>
43 #include <io.h>
44 #include <process.h>
45 #include <errno.h>
46 #include <sys/stat.h>
47
48 #include "glibintl.h"
49
50 typedef struct _GIOWin32Channel GIOWin32Channel;
51 typedef struct _GIOWin32Watch GIOWin32Watch;
52
53 #define BUFFER_SIZE 4096
54
55 typedef enum {
56   G_IO_WIN32_WINDOWS_MESSAGES,  /* Windows messages */
57   G_IO_WIN32_FILE_DESC,         /* Unix-like file descriptors from
58                                  * _open() or _pipe(). Read with read().
59                                  * Have to create separate thread to read.
60                                  */
61   G_IO_WIN32_SOCKET             /* Sockets. A separate thread is blocked
62                                  * in select() most of the time.
63                                  */
64 } GIOWin32ChannelType;
65
66 struct _GIOWin32Channel {
67   GIOChannel channel;
68   gint fd;                      /* Either a Unix-like file handle as provided
69                                  * by the Microsoft C runtime, or a SOCKET
70                                  * as provided by WinSock.
71                                  */
72   GIOWin32ChannelType type;
73   
74   gboolean debug;
75
76   CRITICAL_SECTION mutex;
77
78   /* This is used by G_IO_WIN32_WINDOWS_MESSAGES channels */
79   HWND hwnd;                    /* handle of window, or NULL */
80   
81   /* Following fields are used by both fd and socket channels. */
82   gboolean running;             /* Is reader thread running. FALSE if
83                                  * EOF has been reached.
84                                  */
85   gboolean needs_close;         /* If the channel has been closed while
86                                  * the reader thread was still running.
87                                  */
88   guint thread_id;              /* If non-NULL has a reader thread, or has
89                                  * had.*/
90   HANDLE data_avail_event;
91
92   gushort revents;
93
94   /* Following fields used by fd channels for input */
95   
96   /* Data is kept in a circular buffer. To be able to distinguish between
97    * empty and full buffer, we cannot fill it completely, but have to
98    * leave a one character gap.
99    *
100    * Data available is between indexes rdp and wrp-1 (modulo BUFFER_SIZE).
101    *
102    * Empty:    wrp == rdp
103    * Full:     (wrp + 1) % BUFFER_SIZE == rdp
104    * Partial:  otherwise
105    */
106   guchar *buffer;               /* (Circular) buffer */
107   gint wrp, rdp;                /* Buffer indices for writing and reading */
108   HANDLE space_avail_event;
109
110   /* Following fields used by socket channels */
111   GSList *watches;
112   HANDLE data_avail_noticed_event;
113 };
114
115 #define LOCK(mutex) EnterCriticalSection (&mutex)
116 #define UNLOCK(mutex) LeaveCriticalSection (&mutex)
117
118 struct _GIOWin32Watch {
119   GSource       source;
120   GPollFD       pollfd;
121   GIOChannel   *channel;
122   GIOCondition  condition;
123 };
124
125 static void
126 g_win32_print_access_mode (int flags)
127 {
128   g_print ("%s%s%s%s%s%s%s%s%s%s",
129            ((flags & 0x3) == _O_RDWR ? "O_RDWR" :
130             ((flags & 0x3) == _O_RDONLY ? "O_RDONLY" :
131              ((flags & 0x3) == _O_WRONLY ? "O_WRONLY" : "0"))),
132            (flags & _O_APPEND ? "|O_APPEND" : ""),
133            (flags & _O_RANDOM ? "|O_RANDOM" : ""),
134            (flags & _O_SEQUENTIAL ? "|O_SEQUENTIAL" : ""),
135            (flags & _O_TEMPORARY ? "|O_TEMPORARY" : ""),
136            (flags & _O_CREAT ? "|O_CREAT" : ""),
137            (flags & _O_TRUNC ? "|O_TRUNC" : ""),
138            (flags & _O_EXCL ? "|O_EXCL" : ""),
139            (flags & _O_TEXT ? "|O_TEXT" : ""),
140            (flags & _O_BINARY ? "|O_BINARY" : ""));
141 }
142
143 static void
144 g_win32_print_gioflags (GIOFlags flags)
145 {
146   char *bar = "";
147
148   if (flags & G_IO_FLAG_APPEND)
149     bar = "|", g_print ("APPEND");
150   if (flags & G_IO_FLAG_NONBLOCK)
151     g_print ("%sNONBLOCK", bar), bar = "|";
152   if (flags & G_IO_FLAG_IS_READABLE)
153     g_print ("%sREADABLE", bar), bar = "|";
154   if (flags & G_IO_FLAG_IS_WRITEABLE)
155     g_print ("%sWRITEABLE", bar), bar = "|";
156   if (flags & G_IO_FLAG_IS_WRITEABLE)
157     g_print ("%sWRITEABLE", bar), bar = "|";
158   if (flags & G_IO_FLAG_IS_SEEKABLE)
159     g_print ("%sSEEKABLE", bar), bar = "|";
160 }
161
162 static gboolean
163 g_io_win32_get_debug_flag (void)
164 {
165 #ifdef G_IO_WIN32_DEBUG
166   return TRUE;
167 #else
168   if (getenv ("G_IO_WIN32_DEBUG") != NULL)
169     return TRUE;
170   else
171     return FALSE;
172 #endif
173 }  
174
175 static void
176 g_io_channel_win32_init (GIOWin32Channel *channel)
177 {
178   channel->debug = g_io_win32_get_debug_flag ();
179   channel->buffer = NULL;
180   channel->running = FALSE;
181   channel->needs_close = FALSE;
182   channel->thread_id = 0;
183   channel->data_avail_event = NULL;
184   channel->revents = 0;
185   channel->space_avail_event = NULL;
186   channel->data_avail_noticed_event = NULL;
187   channel->watches = NULL;
188   InitializeCriticalSection (&channel->mutex);
189 }
190
191 static void
192 create_events (GIOWin32Channel *channel)
193 {
194   SECURITY_ATTRIBUTES sec_attrs;
195   
196   sec_attrs.nLength = sizeof (SECURITY_ATTRIBUTES);
197   sec_attrs.lpSecurityDescriptor = NULL;
198   sec_attrs.bInheritHandle = FALSE;
199
200   /* The data available event is manual reset, the space available event
201    * is automatic reset.
202    */
203   if (!(channel->data_avail_event = CreateEvent (&sec_attrs, TRUE, FALSE, NULL))
204       || !(channel->space_avail_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL))
205       || !(channel->data_avail_noticed_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL)))
206     {
207       gchar *emsg = g_win32_error_message (GetLastError ());
208       g_error ("Error creating event: %s", emsg);
209       g_free (emsg);
210     }
211 }
212
213 static unsigned __stdcall
214 read_thread (void *parameter)
215 {
216   GIOWin32Channel *channel = parameter;
217   guchar *buffer;
218   guint nbytes;
219
220   g_io_channel_ref ((GIOChannel *)channel);
221
222   if (channel->debug)
223     g_print ("read_thread %#x: start fd:%d, data_avail:%#x space_avail:%#x\n",
224              channel->thread_id,
225              channel->fd,
226              (guint) channel->data_avail_event,
227              (guint) channel->space_avail_event);
228   
229   channel->buffer = g_malloc (BUFFER_SIZE);
230   channel->rdp = channel->wrp = 0;
231   channel->running = TRUE;
232
233   SetEvent (channel->space_avail_event);
234   
235   while (channel->running)
236     {
237       LOCK (channel->mutex);
238       if (channel->debug)
239         g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
240                  channel->thread_id, channel->rdp, channel->wrp);
241       if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp)
242         {
243           /* Buffer is full */
244           if (channel->debug)
245             g_print ("read_thread %#x: resetting space_avail\n",
246                      channel->thread_id);
247           ResetEvent (channel->space_avail_event);
248           if (channel->debug)
249             g_print ("read_thread %#x: waiting for space\n",
250                      channel->thread_id);
251           UNLOCK (channel->mutex);
252           WaitForSingleObject (channel->space_avail_event, INFINITE);
253           LOCK (channel->mutex);
254           if (channel->debug)
255             g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
256                      channel->thread_id, channel->rdp, channel->wrp);
257         }
258       
259       buffer = channel->buffer + channel->wrp;
260       
261       /* Always leave at least one byte unused gap to be able to
262        * distinguish between the full and empty condition...
263        */
264       nbytes = MIN ((channel->rdp + BUFFER_SIZE - channel->wrp - 1) % BUFFER_SIZE,
265                     BUFFER_SIZE - channel->wrp);
266
267       if (channel->debug)
268         g_print ("read_thread %#x: calling read() for %d bytes\n",
269                  channel->thread_id, nbytes);
270
271       UNLOCK (channel->mutex);
272
273       nbytes = read (channel->fd, buffer, nbytes);
274       
275       LOCK (channel->mutex);
276
277       channel->revents = G_IO_IN;
278       if (nbytes == 0)
279         channel->revents |= G_IO_HUP;
280       else if (nbytes < 0)
281         channel->revents |= G_IO_ERR;
282
283       if (channel->debug)
284         g_print ("read_thread %#x: read() returned %d, rdp=%d, wrp=%d\n",
285                  channel->thread_id, nbytes, channel->rdp, channel->wrp);
286
287       if (nbytes <= 0)
288         break;
289
290       channel->wrp = (channel->wrp + nbytes) % BUFFER_SIZE;
291       if (channel->debug)
292         g_print ("read_thread %#x: rdp=%d, wrp=%d, setting data_avail\n",
293                  channel->thread_id, channel->rdp, channel->wrp);
294       SetEvent (channel->data_avail_event);
295       UNLOCK (channel->mutex);
296     }
297   
298   channel->running = FALSE;
299   if (channel->needs_close)
300     {
301       if (channel->debug)
302         g_print ("read_thread %#x: channel fd %d needs closing\n",
303                  channel->thread_id, channel->fd);
304       close (channel->fd);
305       channel->fd = -1;
306     }
307
308   if (channel->debug)
309     g_print ("read_thread %#x: EOF, rdp=%d, wrp=%d, setting data_avail\n",
310              channel->thread_id, channel->rdp, channel->wrp);
311   SetEvent (channel->data_avail_event);
312   UNLOCK (channel->mutex);
313   
314   g_io_channel_unref((GIOChannel *)channel);
315   
316   /* No need to call _endthreadex(), the actual thread starter routine
317    * in MSVCRT (see crt/src/threadex.c:_threadstartex) calls
318    * _endthreadex() for us.
319    */
320
321   return 0;
322 }
323
324 static void
325 create_thread (GIOWin32Channel     *channel,
326                GIOCondition         condition,
327                unsigned (__stdcall *thread) (void *parameter))
328 {
329   HANDLE thread_handle;
330
331   thread_handle = (HANDLE) _beginthreadex (NULL, 0, thread, channel, 0,
332                                            &channel->thread_id);
333   if (thread_handle == 0)
334     g_warning (G_STRLOC ": Error creating reader thread: %s",
335                g_strerror (errno));
336   else if (!CloseHandle (thread_handle))
337     g_warning (G_STRLOC ": Error closing thread handle: %s\n",
338                g_win32_error_message (GetLastError ()));
339
340   WaitForSingleObject (channel->space_avail_event, INFINITE);
341 }
342
343 static GIOStatus
344 buffer_read (GIOWin32Channel *channel,
345              guchar          *dest,
346              gsize            count,
347              gsize           *bytes_read,
348              GError         **err)
349 {
350   guint nbytes;
351   guint left = count;
352   
353   LOCK (channel->mutex);
354   if (channel->debug)
355     g_print ("reading from thread %#x %d bytes, rdp=%d, wrp=%d\n",
356              channel->thread_id, count, channel->rdp, channel->wrp);
357   
358   if (channel->wrp == channel->rdp)
359     {
360       UNLOCK (channel->mutex);
361       if (channel->debug)
362         g_print ("waiting for data from thread %#x\n", channel->thread_id);
363       WaitForSingleObject (channel->data_avail_event, INFINITE);
364       if (channel->debug)
365         g_print ("done waiting for data from thread %#x\n", channel->thread_id);
366       LOCK (channel->mutex);
367       if (channel->wrp == channel->rdp && !channel->running)
368         {
369           if (channel->debug)
370             g_print ("wrp==rdp, !running\n");
371           UNLOCK (channel->mutex);
372           *bytes_read = 0;
373           return G_IO_STATUS_EOF;
374         }
375     }
376   
377   if (channel->rdp < channel->wrp)
378     nbytes = channel->wrp - channel->rdp;
379   else
380     nbytes = BUFFER_SIZE - channel->rdp;
381   UNLOCK (channel->mutex);
382   nbytes = MIN (left, nbytes);
383   if (channel->debug)
384     g_print ("moving %d bytes from thread %#x\n",
385              nbytes, channel->thread_id);
386   memcpy (dest, channel->buffer + channel->rdp, nbytes);
387   dest += nbytes;
388   left -= nbytes;
389   LOCK (channel->mutex);
390   channel->rdp = (channel->rdp + nbytes) % BUFFER_SIZE;
391   if (channel->debug)
392     g_print ("setting space_avail for thread %#x\n", channel->thread_id);
393   SetEvent (channel->space_avail_event);
394   if (channel->debug)
395     g_print ("for thread %#x: rdp=%d, wrp=%d\n",
396              channel->thread_id, channel->rdp, channel->wrp);
397   if (channel->running && channel->wrp == channel->rdp)
398     {
399       if (channel->debug)
400         g_print ("resetting data_avail of thread %#x\n",
401                  channel->thread_id);
402       ResetEvent (channel->data_avail_event);
403     };
404   UNLOCK (channel->mutex);
405   
406   /* We have no way to indicate any errors form the actual
407    * read() or recv() call in the reader thread. Should we have?
408    */
409   *bytes_read = count - left;
410   return (*bytes_read > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
411 }
412
413 static unsigned __stdcall
414 select_thread (void *parameter)
415 {
416   GIOWin32Channel *channel = parameter;
417   fd_set read_fds, write_fds, except_fds;
418   GSList *tmp;
419   int n;
420
421   g_io_channel_ref ((GIOChannel *)channel);
422
423   if (channel->debug)
424     g_print ("select_thread %#x: start fd:%d data_avail:%#x data_avail_noticed:%#x\n",
425              channel->thread_id,
426              channel->fd,
427              (guint) channel->data_avail_event,
428              (guint) channel->data_avail_noticed_event);
429   
430   channel->rdp = channel->wrp = 0;
431   channel->running = TRUE;
432
433   SetEvent (channel->space_avail_event);
434   
435   while (channel->running)
436     {
437       FD_ZERO (&read_fds);
438       FD_ZERO (&write_fds);
439       FD_ZERO (&except_fds);
440
441       tmp = channel->watches;
442       while (tmp)
443         {
444           GIOWin32Watch *watch = (GIOWin32Watch *)tmp->data;
445
446           if (watch->condition & (G_IO_IN | G_IO_HUP))
447             FD_SET (channel->fd, &read_fds);
448           if (watch->condition & G_IO_OUT)
449             FD_SET (channel->fd, &write_fds);
450           if (watch->condition & G_IO_ERR)
451             FD_SET (channel->fd, &except_fds);
452           
453           tmp = tmp->next;
454         }
455       if (channel->debug)
456         g_print ("select_thread %#x: calling select() for%s%s%s\n",
457                  channel->thread_id,
458                  (FD_ISSET (channel->fd, &read_fds) ? " IN" : ""),
459                  (FD_ISSET (channel->fd, &write_fds) ? " OUT" : ""),
460                  (FD_ISSET (channel->fd, &except_fds) ? " ERR" : ""));
461
462       n = select (1, &read_fds, &write_fds, &except_fds, NULL);
463       
464       if (n == SOCKET_ERROR)
465         {
466           if (channel->debug)
467             g_print ("select_thread %#x: select returned SOCKET_ERROR\n",
468                      channel->thread_id);
469           break;
470         }
471
472       if (channel->debug)
473         g_print ("select_thread %#x: got%s%s%s\n",
474                  channel->thread_id,
475                  (FD_ISSET (channel->fd, &read_fds) ? " IN" : ""),
476                  (FD_ISSET (channel->fd, &write_fds) ? " OUT" : ""),
477                  (FD_ISSET (channel->fd, &except_fds) ? " ERR" : ""));
478
479       if (FD_ISSET (channel->fd, &read_fds))
480         channel->revents |= G_IO_IN;
481       if (FD_ISSET (channel->fd, &write_fds))
482         channel->revents |= G_IO_OUT;
483       if (FD_ISSET (channel->fd, &except_fds))
484         channel->revents |= G_IO_ERR;
485
486       if (channel->debug)
487         g_print ("select_thread %#x: resetting data_avail_noticed, setting data_avail\n",
488                  channel->thread_id);
489       ResetEvent (channel->data_avail_noticed_event);
490       SetEvent (channel->data_avail_event);
491
492       LOCK (channel->mutex);
493       if (channel->needs_close)
494         {
495           UNLOCK (channel->mutex);
496           break;
497         }
498       UNLOCK (channel->mutex);
499
500       if (channel->debug)
501         g_print ("select_thread %#x: waiting for data_avail_noticed\n",
502                  channel->thread_id);
503
504       WaitForSingleObject (channel->data_avail_noticed_event, INFINITE);
505       if (channel->debug)
506         g_print ("select_thread %#x: got data_avail_noticed\n",
507                  channel->thread_id);
508     }
509   
510   channel->running = FALSE;
511   LOCK (channel->mutex);
512   if (channel->fd != -1)
513     {
514       /* DO NOT close the fd here */
515       channel->fd = -1;
516     }
517
518   if (channel->debug)
519     g_print ("select_thread %#x: got error, setting data_avail\n",
520              channel->thread_id);
521   SetEvent (channel->data_avail_event);
522   UNLOCK (channel->mutex);
523   
524   g_io_channel_unref((GIOChannel *)channel);
525   
526   /* No need to call _endthreadex(), the actual thread starter routine
527    * in MSVCRT (see crt/src/threadex.c:_threadstartex) calls
528    * _endthreadex() for us.
529    */
530
531   return 0;
532 }
533
534 static gboolean
535 g_io_win32_prepare (GSource *source,
536                     gint    *timeout)
537 {
538   GIOWin32Watch *watch = (GIOWin32Watch *)source;
539   GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
540   GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
541   
542   *timeout = -1;
543   
544   if (channel->debug)
545     g_print ("g_io_win32_prepare: for thread %#x buffer_condition:%#x\n"
546              "  watch->pollfd.events:%#x watch->pollfd.revents:%#x channel->revents:%#x\n",
547              channel->thread_id, buffer_condition,
548              watch->pollfd.events, watch->pollfd.revents, channel->revents);
549
550   if (channel->type == G_IO_WIN32_FILE_DESC)
551     {
552       LOCK (channel->mutex);
553       if (channel->running && channel->wrp == channel->rdp)
554         {
555           if (channel->debug)
556             g_print ("g_io_win32_prepare: for thread %#x, setting channel->revents = 0\n",
557                      channel->thread_id);
558           channel->revents = 0;
559         }
560       UNLOCK (channel->mutex);
561     }
562   else if (channel->type == G_IO_WIN32_SOCKET)
563     {
564       channel->revents = 0;
565
566       if (channel->debug)
567         g_print ("g_io_win32_prepare: for thread %#x, setting data_avail_noticed\n",
568                  channel->thread_id);
569       SetEvent (channel->data_avail_noticed_event);
570       if (channel->debug)
571         g_print ("g_io_win32_prepare: thread %#x, there.\n",
572                  channel->thread_id);
573     }
574
575   return ((watch->condition & buffer_condition) == watch->condition);
576 }
577
578 static gboolean
579 g_io_win32_check (GSource *source)
580 {
581   MSG msg;
582   GIOWin32Watch *watch = (GIOWin32Watch *)source;
583   GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
584   GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
585
586   if (channel->debug)
587     g_print ("g_io_win32_check: for thread %#x buffer_condition:%#x\n"
588              "  watch->pollfd.events:%#x watch->pollfd.revents:%#x channel->revents:%#x\n",
589              channel->thread_id, buffer_condition,
590              watch->pollfd.events, watch->pollfd.revents, channel->revents);
591
592   if (channel->type != G_IO_WIN32_WINDOWS_MESSAGES)
593     {
594       watch->pollfd.revents = (watch->pollfd.events & channel->revents);
595     }
596   else
597     {
598       return (PeekMessage (&msg, channel->hwnd, 0, 0, PM_NOREMOVE));
599     }
600   
601   if (channel->type == G_IO_WIN32_SOCKET)
602     {
603       if (channel->debug)
604         g_print ("g_io_win32_check: thread %#x, resetting data_avail\n",
605                  channel->thread_id);
606       ResetEvent (channel->data_avail_event);
607       if (channel->debug)
608         g_print ("g_io_win32_check: thread %#x, there.\n",
609                  channel->thread_id);
610     }
611
612   return ((watch->pollfd.revents | buffer_condition) & watch->condition);
613 }
614
615 static gboolean
616 g_io_win32_dispatch (GSource     *source,
617                      GSourceFunc  callback,
618                      gpointer     user_data)
619 {
620   GIOFunc func = (GIOFunc)callback;
621   GIOWin32Watch *watch = (GIOWin32Watch *)source;
622   GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
623   
624   if (!func)
625     {
626       g_warning (G_STRLOC ": GIOWin32Watch dispatched without callback\n"
627                  "You must call g_source_connect().");
628       return FALSE;
629     }
630   
631   return (*func) (watch->channel,
632                   (watch->pollfd.revents | buffer_condition) & watch->condition,
633                   user_data);
634 }
635
636 static void
637 g_io_win32_finalize (GSource *source)
638 {
639   GIOWin32Watch *watch = (GIOWin32Watch *)source;
640   GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
641   
642   if (channel->debug)
643     g_print ("g_io_win32_finalize: channel with thread %#x\n",
644              channel->thread_id);
645
646   channel->watches = g_slist_remove (channel->watches, watch);
647
648   SetEvent (channel->data_avail_noticed_event);
649   g_io_channel_unref (watch->channel);
650 }
651
652 #if defined(G_PLATFORM_WIN32) && defined(__GNUC__)
653 __declspec(dllexport)
654 #endif
655 GSourceFuncs g_io_watch_funcs = {
656   g_io_win32_prepare,
657   g_io_win32_check,
658   g_io_win32_dispatch,
659   g_io_win32_finalize
660 };
661
662 static GSource *
663 g_io_win32_create_watch (GIOChannel    *channel,
664                          GIOCondition   condition,
665                          unsigned (__stdcall *thread) (void *parameter))
666 {
667   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
668   GIOWin32Watch *watch;
669   GSource *source;
670
671   source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
672   watch = (GIOWin32Watch *)source;
673   
674   watch->channel = channel;
675   g_io_channel_ref (channel);
676   
677   watch->condition = condition;
678   
679   if (win32_channel->data_avail_event == NULL)
680     create_events (win32_channel);
681
682   watch->pollfd.fd = (gint) win32_channel->data_avail_event;
683   watch->pollfd.events = condition;
684   
685   if (win32_channel->debug)
686     g_print ("g_io_win32_create_watch: fd:%d condition:%#x handle:%#x\n",
687              win32_channel->fd, condition, watch->pollfd.fd);
688   
689   win32_channel->watches = g_slist_append (win32_channel->watches, watch);
690
691   if (win32_channel->thread_id == 0)
692     create_thread (win32_channel, condition, thread);
693
694   g_source_add_poll (source, &watch->pollfd);
695   
696   return source;
697 }
698
699 static GIOStatus
700 g_io_win32_msg_read (GIOChannel *channel,
701                      gchar      *buf,
702                      gsize       count,
703                      gsize      *bytes_read,
704                      GError    **err)
705 {
706   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
707   MSG msg;               /* In case of alignment problems */
708   
709   if (count < sizeof (MSG))
710     {
711       g_set_error(err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
712         _("Incorrect message size")); /* Informative enough error message? */
713       return G_IO_STATUS_ERROR;
714     }
715   
716   if (win32_channel->debug)
717     g_print ("g_io_win32_msg_read: for %#x\n",
718              (guint) win32_channel->hwnd);
719   if (!PeekMessage (&msg, win32_channel->hwnd, 0, 0, PM_REMOVE))
720     return G_IO_STATUS_AGAIN;
721
722   memmove (buf, &msg, sizeof (MSG));
723   *bytes_read = sizeof (MSG);
724
725   return G_IO_STATUS_NORMAL;
726 }
727
728 static GIOStatus
729 g_io_win32_msg_write (GIOChannel  *channel,
730                       const gchar *buf,
731                       gsize        count,
732                       gsize       *bytes_written,
733                       GError     **err)
734 {
735   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
736   MSG msg;
737   
738   if (count != sizeof (MSG))
739     {
740       g_set_error(err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
741         _("Incorrect message size")); /* Informative enough error message? */
742       return G_IO_STATUS_ERROR;
743     }
744   
745   /* In case of alignment problems */
746   memmove (&msg, buf, sizeof (MSG));
747   if (!PostMessage (win32_channel->hwnd, msg.message, msg.wParam, msg.lParam))
748     {
749       gchar *emsg = g_win32_error_message (GetLastError ());
750       g_set_error(err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, emsg);
751       g_free (emsg);
752       return G_IO_STATUS_ERROR;
753     }
754
755   *bytes_written = sizeof (MSG);
756
757   return G_IO_STATUS_NORMAL;
758 }
759
760 static GIOStatus
761 g_io_win32_msg_close (GIOChannel *channel,
762                       GError    **err)
763 {
764   /* Nothing to be done. Or should we set hwnd to some invalid value? */
765
766   return G_IO_STATUS_NORMAL;
767 }
768
769 static void
770 g_io_win32_free (GIOChannel *channel)
771 {
772   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
773   
774   if (win32_channel->debug)
775     g_print ("thread %#x: freeing channel, fd: %d\n",
776              win32_channel->thread_id,
777              win32_channel->fd);
778
779   if (win32_channel->data_avail_event)
780     CloseHandle (win32_channel->data_avail_event);
781   if (win32_channel->space_avail_event)
782     CloseHandle (win32_channel->space_avail_event);
783   if (win32_channel->data_avail_noticed_event)
784     CloseHandle (win32_channel->data_avail_noticed_event);
785   DeleteCriticalSection (&win32_channel->mutex);
786
787   g_free (win32_channel->buffer);
788   g_slist_free (win32_channel->watches);
789   g_free (win32_channel);
790 }
791
792 static GSource *
793 g_io_win32_msg_create_watch (GIOChannel    *channel,
794                              GIOCondition   condition)
795 {
796   GIOWin32Watch *watch;
797   GSource *source;
798
799   source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
800   watch = (GIOWin32Watch *)source;
801   
802   watch->channel = channel;
803   g_io_channel_ref (channel);
804   
805   watch->condition = condition;
806   
807   watch->pollfd.fd = G_WIN32_MSG_HANDLE;
808   watch->pollfd.events = condition;
809   
810   g_source_add_poll (source, &watch->pollfd);
811   
812   return source;
813 }
814
815 static GIOStatus
816 g_io_win32_fd_read (GIOChannel *channel,
817                     gchar      *buf,
818                     gsize       count,
819                     gsize      *bytes_read,
820                     GError    **err)
821 {
822   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
823   gint result;
824   
825   if (win32_channel->debug)
826     g_print ("g_io_win32_fd_read: fd:%d count:%d\n",
827              win32_channel->fd, count);
828   
829   if (win32_channel->thread_id)
830     {
831       return buffer_read (win32_channel, buf, count, bytes_read, err);
832     }
833
834   result = read (win32_channel->fd, buf, count);
835
836   if (win32_channel->debug)
837     g_print ("g_io_win32_fd_read: read() = %d\n", result);
838
839   if (result < 0)
840     {
841       *bytes_read = 0;
842
843       switch(errno)
844         {
845 #ifdef EAGAIN
846           case EAGAIN:
847             return G_IO_STATUS_AGAIN;
848 #endif
849           default:
850             g_set_error (err, G_IO_CHANNEL_ERROR,
851                          g_io_channel_error_from_errno (errno),
852                          g_strerror (errno));
853             return G_IO_STATUS_ERROR;
854         }
855     }
856
857   *bytes_read = result;
858
859   return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
860 }
861
862 static GIOStatus
863 g_io_win32_fd_write (GIOChannel  *channel,
864                      const gchar *buf,
865                      gsize        count,
866                      gsize       *bytes_written,
867                      GError     **err)
868 {
869   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
870   gint result;
871   
872   result = write (win32_channel->fd, buf, count);
873   if (win32_channel->debug)
874     g_print ("g_io_win32_fd_write: fd:%d count:%d = %d\n",
875              win32_channel->fd, count, result);
876
877   if (result < 0)
878     {
879       *bytes_written = 0;
880
881       switch(errno)
882         {
883 #ifdef EAGAIN
884           case EAGAIN:
885             return G_IO_STATUS_AGAIN;
886 #endif
887           default:
888             g_set_error (err, G_IO_CHANNEL_ERROR,
889                          g_io_channel_error_from_errno (errno),
890                          g_strerror (errno));
891             return G_IO_STATUS_ERROR;
892         }
893     }
894
895   *bytes_written = result;
896
897   return G_IO_STATUS_NORMAL;
898 }
899
900 static GIOStatus
901 g_io_win32_fd_seek (GIOChannel *channel,
902                     gint64      offset,
903                     GSeekType   type,
904                     GError    **err)
905 {
906   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
907   int whence;
908   off_t tmp_offset;
909   off_t result;
910   
911   switch (type)
912     {
913     case G_SEEK_SET:
914       whence = SEEK_SET;
915       break;
916     case G_SEEK_CUR:
917       whence = SEEK_CUR;
918       break;
919     case G_SEEK_END:
920       whence = SEEK_END;
921       break;
922     default:
923       whence = -1; /* Keep the compiler quiet */
924       g_assert_not_reached();
925     }
926
927   tmp_offset = offset;
928   if (tmp_offset != offset)
929     {
930       g_set_error (err, G_IO_CHANNEL_ERROR,
931                    g_io_channel_error_from_errno (EINVAL),
932                    g_strerror (EINVAL));
933       return G_IO_STATUS_ERROR;
934     }
935   
936   result = lseek (win32_channel->fd, tmp_offset, whence);
937   
938   if (result < 0)
939     {
940       g_set_error (err, G_IO_CHANNEL_ERROR,
941                    g_io_channel_error_from_errno (errno),
942                    g_strerror (errno));
943       return G_IO_STATUS_ERROR;
944     }
945
946   return G_IO_STATUS_NORMAL;
947 }
948
949 static GIOStatus
950 g_io_win32_fd_close (GIOChannel *channel,
951                      GError    **err)
952 {
953   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
954   
955   if (win32_channel->debug)
956     g_print ("thread %#x: closing fd %d\n",
957              win32_channel->thread_id,
958              win32_channel->fd);
959   LOCK (win32_channel->mutex);
960   if (win32_channel->running)
961     {
962       if (win32_channel->debug)
963         g_print ("thread %#x: running, marking fd %d for later close\n",
964                  win32_channel->thread_id, win32_channel->fd);
965       win32_channel->running = FALSE;
966       win32_channel->needs_close = TRUE;
967       SetEvent (win32_channel->data_avail_event);
968     }
969   else
970     {
971       if (win32_channel->debug)
972         g_print ("closing fd %d\n", win32_channel->fd);
973       close (win32_channel->fd);
974       if (win32_channel->debug)
975         g_print ("closed fd %d, setting to -1\n",
976                  win32_channel->fd);
977       win32_channel->fd = -1;
978     }
979   UNLOCK (win32_channel->mutex);
980
981   /* FIXME error detection? */
982
983   return G_IO_STATUS_NORMAL;
984 }
985
986 static GSource *
987 g_io_win32_fd_create_watch (GIOChannel    *channel,
988                             GIOCondition   condition)
989 {
990   return g_io_win32_create_watch (channel, condition, read_thread);
991 }
992
993 static GIOStatus
994 g_io_win32_sock_read (GIOChannel *channel,
995                       gchar      *buf,
996                       gsize       count,
997                       gsize      *bytes_read,
998                       GError    **err)
999 {
1000   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1001   gint result;
1002   GIOChannelError error;
1003
1004   if (win32_channel->debug)
1005     g_print ("g_io_win32_sock_read: sockfd:%d count:%d\n",
1006              win32_channel->fd, count);
1007 #ifdef WE_NEED_TO_HANDLE_WSAEINTR
1008 repeat:
1009 #endif
1010   result = recv (win32_channel->fd, buf, count, 0);
1011
1012   if (win32_channel->debug)
1013     g_print ("g_io_win32_sock_read: recv:%d\n", result);
1014   
1015   if (result == SOCKET_ERROR)
1016     {
1017       *bytes_read = 0;
1018
1019       switch (WSAGetLastError ())
1020         {
1021         case WSAEINVAL:
1022           error = G_IO_CHANNEL_ERROR_INVAL;
1023           break;
1024         case WSAEWOULDBLOCK:
1025           return G_IO_STATUS_AGAIN;
1026 #ifdef WE_NEED_TO_HANDLE_WSAEINTR /* not anymore with wsock2 ? */
1027         case WSAEINTR:
1028           goto repeat;
1029 #endif
1030         default:
1031           error = G_IO_CHANNEL_ERROR_FAILED;
1032           break;
1033         }
1034       g_set_error(err, G_IO_CHANNEL_ERROR, error, _("Socket error"));
1035       return G_IO_STATUS_ERROR;
1036       /* FIXME get all errors, better error messages */
1037     }
1038   else
1039     {
1040       *bytes_read = result;
1041
1042       return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
1043     }
1044 }
1045
1046 static GIOStatus
1047 g_io_win32_sock_write (GIOChannel  *channel,
1048                        const gchar *buf,
1049                        gsize        count,
1050                        gsize       *bytes_written,
1051                        GError     **err)
1052 {
1053   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1054   gint result;
1055   GIOChannelError error;
1056   
1057   if (win32_channel->debug)
1058     g_print ("g_io_win32_sock_write: sockfd:%d count:%d\n",
1059              win32_channel->fd, count);
1060 #ifdef WE_NEED_TO_HANDLE_WSAEINTR
1061 repeat:
1062 #endif
1063   result = send (win32_channel->fd, buf, count, 0);
1064   
1065   if (win32_channel->debug)
1066     g_print ("g_io_win32_sock_write: send:%d\n", result);
1067   
1068   if (result == SOCKET_ERROR)
1069     {
1070       *bytes_written = 0;
1071
1072       switch (WSAGetLastError ())
1073         {
1074         case WSAEINVAL:
1075           error = G_IO_CHANNEL_ERROR_INVAL;
1076           break;
1077         case WSAEWOULDBLOCK:
1078           return G_IO_STATUS_AGAIN;
1079 #ifdef WE_NEED_TO_HANDLE_WSAEINTR /* not anymore with wsock2 ? */
1080         case WSAEINTR:
1081           goto repeat;
1082 #endif
1083         default:
1084           error = G_IO_CHANNEL_ERROR_FAILED;
1085           break;
1086         }
1087       g_set_error(err, G_IO_CHANNEL_ERROR, error, _("Socket error"));
1088       return G_IO_STATUS_ERROR;
1089       /* FIXME get all errors, better error messages */
1090     }
1091   else
1092     {
1093       *bytes_written = result;
1094
1095       return G_IO_STATUS_NORMAL;
1096     }
1097 }
1098
1099 static GIOStatus
1100 g_io_win32_sock_close (GIOChannel *channel,
1101                        GError    **err)
1102 {
1103   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1104
1105   LOCK(win32_channel->mutex);
1106   if (win32_channel->running)
1107     {
1108       if (win32_channel->debug)
1109         g_print ("thread %#x: running, marking for later close\n",
1110                  win32_channel->thread_id);
1111       win32_channel->running = FALSE;
1112       win32_channel->needs_close = TRUE;
1113       SetEvent(win32_channel->data_avail_noticed_event);
1114     }
1115   if (win32_channel->fd != -1)
1116     {
1117       if (win32_channel->debug)
1118         g_print ("thread %#x: closing socket %d\n",
1119                  win32_channel->thread_id,
1120                  win32_channel->fd);
1121       
1122       closesocket (win32_channel->fd);
1123       win32_channel->fd = -1;
1124     }
1125   UNLOCK(win32_channel->mutex);
1126
1127   /* FIXME error detection? */
1128
1129   return G_IO_STATUS_NORMAL;
1130 }
1131
1132 static GSource *
1133 g_io_win32_sock_create_watch (GIOChannel    *channel,
1134                               GIOCondition   condition)
1135 {
1136   return g_io_win32_create_watch (channel, condition, select_thread);
1137 }
1138
1139 GIOChannel *
1140 g_io_channel_new_file (const gchar  *filename,
1141                        const gchar  *mode,
1142                        GError      **error)
1143 {
1144   int fid, flags, pmode;
1145   GIOChannel *channel;
1146
1147   enum { /* Cheesy hack */
1148     MODE_R = 1 << 0,
1149     MODE_W = 1 << 1,
1150     MODE_A = 1 << 2,
1151     MODE_PLUS = 1 << 3,
1152   } mode_num;
1153
1154   g_return_val_if_fail (filename != NULL, NULL);
1155   g_return_val_if_fail (mode != NULL, NULL);
1156   g_return_val_if_fail ((error == NULL) || (*error == NULL), NULL);
1157
1158   switch (mode[0])
1159     {
1160       case 'r':
1161         mode_num = MODE_R;
1162         break;
1163       case 'w':
1164         mode_num = MODE_W;
1165         break;
1166       case 'a':
1167         mode_num = MODE_A;
1168         break;
1169       default:
1170         g_warning ("Invalid GIOFileMode %s.\n", mode);
1171         return NULL;
1172     }
1173
1174   switch (mode[1])
1175     {
1176       case '\0':
1177         break;
1178       case '+':
1179         if (mode[2] == '\0')
1180           {
1181             mode_num |= MODE_PLUS;
1182             break;
1183           }
1184         /* Fall through */
1185       default:
1186         g_warning ("Invalid GIOFileMode %s.\n", mode);
1187         return NULL;
1188     }
1189
1190   switch (mode_num)
1191     {
1192       case MODE_R:
1193         flags = O_RDONLY;
1194         pmode = _S_IREAD;
1195         break;
1196       case MODE_W:
1197         flags = O_WRONLY | O_TRUNC | O_CREAT;
1198         pmode = _S_IWRITE;
1199         break;
1200       case MODE_A:
1201         flags = O_WRONLY | O_APPEND | O_CREAT;
1202         pmode = _S_IWRITE;
1203         break;
1204       case MODE_R | MODE_PLUS:
1205         flags = O_RDWR;
1206         pmode = _S_IREAD | _S_IWRITE;
1207         break;
1208       case MODE_W | MODE_PLUS:
1209         flags = O_RDWR | O_TRUNC | O_CREAT;
1210         pmode = _S_IREAD | _S_IWRITE;
1211         break;
1212       case MODE_A | MODE_PLUS:
1213         flags = O_RDWR | O_APPEND | O_CREAT;
1214         pmode = _S_IREAD | _S_IWRITE;
1215         break;
1216       default:
1217         g_assert_not_reached ();
1218         flags = 0;
1219         pmode = 0;
1220     }
1221
1222   /* always open 'untranslated' */
1223   fid = open (filename, flags | _O_BINARY, pmode);
1224
1225   if (g_io_win32_get_debug_flag ())
1226     {
1227       g_print ("g_io_channel_win32_new_file: open(\"%s\", ", filename);
1228       g_win32_print_access_mode (flags|_O_BINARY);
1229       g_print (",%#o)=%d\n", pmode, fid);
1230     }
1231
1232   if (fid < 0)
1233     {
1234       g_set_error (error, G_FILE_ERROR,
1235                    g_file_error_from_errno (errno),
1236                    g_strerror (errno));
1237       return (GIOChannel *)NULL;
1238     }
1239
1240   channel = g_io_channel_win32_new_fd (fid);
1241
1242   /* XXX: move this to g_io_channel_win32_new_fd () */
1243   channel->close_on_unref = TRUE;
1244   channel->is_seekable = TRUE;
1245
1246   /* g_io_channel_win32_new_fd sets is_readable and is_writeable to
1247    * correspond to actual readability/writeability. Set to FALSE those
1248    * that mode doesn't allow
1249    */
1250   switch (mode_num)
1251     {
1252       case MODE_R:
1253         channel->is_writeable = FALSE;
1254         break;
1255       case MODE_W:
1256       case MODE_A:
1257         channel->is_readable = FALSE;
1258         break;
1259       case MODE_R | MODE_PLUS:
1260       case MODE_W | MODE_PLUS:
1261       case MODE_A | MODE_PLUS:
1262         break;
1263       default:
1264         g_assert_not_reached ();
1265     }
1266
1267   return channel;
1268 }
1269
1270 static GIOStatus
1271 g_io_win32_set_flags (GIOChannel *channel,
1272                       GIOFlags    flags,
1273                       GError    **err)
1274 {
1275   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1276
1277   if (win32_channel->debug)
1278     {
1279       g_print ("g_io_win32_set_flags: ");
1280       g_win32_print_gioflags (flags);
1281       g_print ("\n");
1282     }
1283
1284   g_warning ("g_io_win32_set_flags () not implemented.\n");
1285
1286   return G_IO_STATUS_NORMAL;
1287 }
1288
1289 static GIOFlags
1290 g_io_win32_fd_get_flags_internal (GIOChannel  *channel,
1291                                   struct stat *st)
1292 {
1293   GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
1294   gchar c;
1295   DWORD count;
1296
1297   if (st->st_mode & _S_IFIFO)
1298     {
1299       channel->is_readable =
1300         (PeekNamedPipe ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL, NULL) == 0);
1301       channel->is_writeable =
1302         (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) == 0);
1303       channel->is_seekable  = FALSE;
1304     }
1305   else if (st->st_mode & _S_IFCHR)
1306     {
1307       /* XXX Seems there is no way to find out the readability of file
1308        * handles to device files (consoles, mostly) without doing a
1309        * blocking read. So punt, use st->st_mode.
1310        */
1311       channel->is_readable  = !!(st->st_mode & _S_IREAD);
1312
1313       channel->is_writeable =
1314         (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) == 0);
1315
1316       /* XXX What about devices that actually *are* seekable? But those would probably
1317        * not be handled using the C runtime anyway, but using Windows-specific code.
1318        */
1319       channel->is_seekable = FALSE;
1320     }
1321   else
1322     {
1323       channel->is_readable =
1324         (ReadFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) == 0);
1325       channel->is_writeable =
1326         (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) == 0);
1327       channel->is_seekable = TRUE;
1328     }
1329
1330   /* XXX: G_IO_FLAG_APPEND */
1331   /* XXX: G_IO_FLAG_NONBLOCK */
1332
1333   return 0;
1334 }
1335
1336 static GIOFlags
1337 g_io_win32_fd_get_flags (GIOChannel *channel)
1338 {
1339   struct stat st;
1340   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1341
1342   g_return_val_if_fail (win32_channel != NULL, 0);
1343   g_return_val_if_fail (win32_channel->type == G_IO_WIN32_FILE_DESC, 0);
1344
1345   if (0 == fstat (win32_channel->fd, &st))
1346     return g_io_win32_fd_get_flags_internal (channel, &st);
1347   else
1348     return 0;
1349 }
1350
1351 static GIOFlags
1352 g_io_win32_msg_get_flags (GIOChannel *channel)
1353 {
1354   return 0;
1355 }
1356
1357 static GIOFlags
1358 g_io_win32_sock_get_flags (GIOChannel *channel)
1359 {
1360   /* XXX Could do something here. */
1361   return 0;
1362 }
1363
1364 static GIOFuncs win32_channel_msg_funcs = {
1365   g_io_win32_msg_read,
1366   g_io_win32_msg_write,
1367   NULL,
1368   g_io_win32_msg_close,
1369   g_io_win32_msg_create_watch,
1370   g_io_win32_free,
1371   g_io_win32_set_flags,
1372   g_io_win32_msg_get_flags,
1373 };
1374
1375 static GIOFuncs win32_channel_fd_funcs = {
1376   g_io_win32_fd_read,
1377   g_io_win32_fd_write,
1378   g_io_win32_fd_seek,
1379   g_io_win32_fd_close,
1380   g_io_win32_fd_create_watch,
1381   g_io_win32_free,
1382   g_io_win32_set_flags,
1383   g_io_win32_fd_get_flags,
1384 };
1385
1386 static GIOFuncs win32_channel_sock_funcs = {
1387   g_io_win32_sock_read,
1388   g_io_win32_sock_write,
1389   NULL,
1390   g_io_win32_sock_close,
1391   g_io_win32_sock_create_watch,
1392   g_io_win32_free,
1393   g_io_win32_set_flags,
1394   g_io_win32_sock_get_flags,
1395 };
1396
1397 GIOChannel *
1398 g_io_channel_win32_new_messages (guint hwnd)
1399 {
1400   GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
1401   GIOChannel *channel = (GIOChannel *)win32_channel;
1402
1403   g_io_channel_init (channel);
1404   g_io_channel_win32_init (win32_channel);
1405   if (win32_channel->debug)
1406     g_print ("g_io_channel_win32_new_messages: hwnd = %ud\n", hwnd);
1407   channel->funcs = &win32_channel_msg_funcs;
1408   win32_channel->type = G_IO_WIN32_WINDOWS_MESSAGES;
1409   win32_channel->hwnd = (HWND) hwnd;
1410
1411   /* XXX: check this. */
1412   channel->is_readable = IsWindow (win32_channel->hwnd);
1413   channel->is_writeable = IsWindow (win32_channel->hwnd);
1414
1415   channel->is_seekable = FALSE;
1416
1417   return channel;
1418 }
1419
1420 static GIOChannel *
1421 g_io_channel_win32_new_fd_internal (gint         fd,
1422                                     struct stat *st)
1423 {
1424   GIOWin32Channel *win32_channel;
1425   GIOChannel *channel;
1426
1427   win32_channel = g_new (GIOWin32Channel, 1);
1428   channel = (GIOChannel *)win32_channel;
1429
1430   g_io_channel_init (channel);
1431   g_io_channel_win32_init (win32_channel);
1432   if (win32_channel->debug)
1433     g_print ("g_io_channel_win32_new_fd: %u\n", fd);
1434   channel->funcs = &win32_channel_fd_funcs;
1435   win32_channel->type = G_IO_WIN32_FILE_DESC;
1436   win32_channel->fd = fd;
1437
1438   g_io_win32_fd_get_flags_internal (channel, st);
1439   
1440   return channel;
1441 }
1442
1443 GIOChannel *
1444 g_io_channel_win32_new_fd (gint fd)
1445 {
1446   struct stat st;
1447
1448   if (fstat (fd, &st) == -1)
1449     {
1450       g_warning (G_STRLOC ": %d isn't a C library file descriptor", fd);
1451       return NULL;
1452     }
1453
1454   return g_io_channel_win32_new_fd_internal (fd, &st);
1455 }
1456
1457 gint
1458 g_io_channel_win32_get_fd (GIOChannel *channel)
1459 {
1460   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1461
1462   return win32_channel->fd;
1463 }
1464
1465 GIOChannel *
1466 g_io_channel_win32_new_socket (int socket)
1467 {
1468   GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
1469   GIOChannel *channel = (GIOChannel *)win32_channel;
1470
1471   g_io_channel_init (channel);
1472   g_io_channel_win32_init (win32_channel);
1473   if (win32_channel->debug)
1474     g_print ("g_io_channel_win32_new_socket: sockfd:%d\n", socket);
1475   channel->funcs = &win32_channel_sock_funcs;
1476   win32_channel->type = G_IO_WIN32_SOCKET;
1477   win32_channel->fd = socket;
1478
1479   /* XXX: check this */
1480   channel->is_readable = TRUE;
1481   channel->is_writeable = TRUE;
1482
1483   channel->is_seekable = FALSE;
1484
1485   return channel;
1486 }
1487
1488 GIOChannel *
1489 g_io_channel_unix_new (gint fd)
1490 {
1491   struct stat st;
1492
1493   if (fstat (fd, &st) == 0)
1494     return g_io_channel_win32_new_fd_internal (fd, &st);
1495   
1496   if (getsockopt (fd, SOL_SOCKET, SO_TYPE, NULL, NULL) != SO_ERROR)
1497     return g_io_channel_win32_new_socket(fd);
1498
1499   g_warning (G_STRLOC ": %d is neither a file descriptor or a socket", fd);
1500   return NULL;
1501 }
1502
1503 gint
1504 g_io_channel_unix_get_fd (GIOChannel *channel)
1505 {
1506   return g_io_channel_win32_get_fd (channel);
1507 }
1508
1509 void
1510 g_io_channel_win32_set_debug (GIOChannel *channel,
1511                               gboolean    flag)
1512 {
1513   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1514
1515   win32_channel->debug = flag;
1516 }
1517
1518 gint
1519 g_io_channel_win32_poll (GPollFD *fds,
1520                          gint     n_fds,
1521                          gint     timeout)
1522 {
1523   int result;
1524
1525   g_return_val_if_fail (n_fds >= 0, 0);
1526
1527   result = (*g_main_context_get_poll_func (NULL)) (fds, n_fds, timeout);
1528
1529   return result;
1530 }
1531
1532 void
1533 g_io_channel_win32_make_pollfd (GIOChannel   *channel,
1534                                 GIOCondition  condition,
1535                                 GPollFD      *fd)
1536 {
1537   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1538
1539   if (win32_channel->data_avail_event == NULL)
1540     create_events (win32_channel);
1541   
1542   fd->fd = (gint) win32_channel->data_avail_event;
1543   fd->events = condition;
1544
1545   if (win32_channel->thread_id == 0)
1546     {
1547       if ((condition & G_IO_IN) && win32_channel->type == G_IO_WIN32_FILE_DESC)
1548         create_thread (win32_channel, condition, read_thread);
1549       else if (win32_channel->type == G_IO_WIN32_SOCKET)
1550         create_thread (win32_channel, condition, select_thread);
1551     }
1552 }
1553
1554 /* Binary compatibility */
1555 GIOChannel *
1556 g_io_channel_win32_new_stream_socket (int socket)
1557 {
1558   return g_io_channel_win32_new_socket (socket);
1559 }