+ MSG msg;
+ GIOWin32Watch *watch = (GIOWin32Watch *)source;
+ GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
+ GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
+ WSANETWORKEVENTS events;
+
+ if (channel->debug)
+ g_print ("g_io_win32_check: source=%p channel=%p", source, channel);
+
+ switch (channel->type)
+ {
+ case G_IO_WIN32_WINDOWS_MESSAGES:
+ if (channel->debug)
+ g_print (" MSG\n");
+ return (PeekMessage (&msg, channel->hwnd, 0, 0, PM_NOREMOVE));
+
+ case G_IO_WIN32_FILE_DESC:
+ if (channel->debug)
+ g_print (" FD thread=%#x buffer_condition=%s\n"
+ " watch->pollfd.events={%s} watch->pollfd.revents={%s} channel->revents={%s}\n",
+ channel->thread_id, condition_to_string (buffer_condition),
+ condition_to_string (watch->pollfd.events),
+ condition_to_string (watch->pollfd.revents),
+ condition_to_string (channel->revents));
+
+ watch->pollfd.revents = (watch->pollfd.events & channel->revents);
+
+ return ((watch->pollfd.revents | buffer_condition) & watch->condition);
+
+ case G_IO_WIN32_CONSOLE:
+ if (channel->debug)
+ g_print (" CON\n");
+ if (watch->channel->is_writeable)
+ return TRUE;
+ else if (watch->channel->is_readable)
+ {
+ INPUT_RECORD buffer;
+ DWORD n;
+ if (PeekConsoleInput ((HANDLE) watch->pollfd.fd, &buffer, 1, &n) &&
+ n == 1)
+ {
+ /* _kbhit() does quite complex processing to find out
+ * whether at least one of the key events pending corresponds
+ * to a "real" character that can be read.
+ */
+ if (_kbhit ())
+ return TRUE;
+
+ /* Discard all other kinds of events */
+ ReadConsoleInput ((HANDLE) watch->pollfd.fd, &buffer, 1, &n);
+ }
+ }
+ return FALSE;
+
+ case G_IO_WIN32_SOCKET:
+ if (channel->debug)
+ g_print (" SOCK");
+ if (channel->last_events & FD_WRITE)
+ {
+ if (channel->debug)
+ g_print (" sock=%d event=%p last_events has FD_WRITE",
+ channel->fd, (HANDLE) watch->pollfd.fd);
+ }
+ else
+ {
+ WSAEnumNetworkEvents (channel->fd, 0, &events);
+
+ if (channel->debug)
+ g_print ("\n revents={%s} condition={%s}"
+ "\n WSAEnumNetworkEvents(%d,0) sets events={%s}",
+ condition_to_string (watch->pollfd.revents),
+ condition_to_string (watch->condition),
+ channel->fd,
+ event_mask_to_string (events.lNetworkEvents));
+
+ if (watch->pollfd.revents != 0 &&
+ events.lNetworkEvents == 0 &&
+ !(channel->event_mask & FD_WRITE))
+ {
+ channel->event_mask = 0;
+ if (channel->debug)
+ g_print ("\n WSAEventSelect(%d,%p,{})",
+ channel->fd, (HANDLE) watch->pollfd.fd);
+ WSAEventSelect (channel->fd, (HANDLE) watch->pollfd.fd, 0);
+ if (channel->debug)
+ g_print (" ResetEvent(%p)",
+ (HANDLE) watch->pollfd.fd);
+ ResetEvent ((HANDLE) watch->pollfd.fd);
+ }
+ else if (events.lNetworkEvents & FD_WRITE)
+ channel->ever_writable = TRUE;
+ channel->last_events = events.lNetworkEvents;
+ }
+
+ watch->pollfd.revents = 0;
+ if (channel->last_events & (FD_READ | FD_ACCEPT))
+ watch->pollfd.revents |= G_IO_IN;
+
+ if (channel->last_events & FD_WRITE)
+ watch->pollfd.revents |= G_IO_OUT;
+ else
+ {
+ /* We have called WSAEnumNetworkEvents() above but it didn't
+ * set FD_WRITE.
+ */
+ if (events.lNetworkEvents & FD_CONNECT)
+ {
+ if (events.iErrorCode[FD_CONNECT_BIT] == 0)
+ watch->pollfd.revents |= G_IO_OUT;
+ else
+ watch->pollfd.revents |= (G_IO_HUP | G_IO_ERR);
+ }
+ if (watch->pollfd.revents == 0 && (channel->last_events & (FD_CLOSE)))
+ watch->pollfd.revents |= G_IO_HUP;
+ }
+
+ /* Regardless of WSAEnumNetworkEvents() result, if watching for
+ * writability, and if we have ever got a FD_WRITE event, and
+ * unless last write would have blocked, set G_IO_OUT. But never
+ * set both G_IO_OUT and G_IO_HUP.
+ */
+ if (!(watch->pollfd.revents & G_IO_HUP) &&
+ channel->ever_writable &&
+ !channel->write_would_have_blocked &&
+ (channel->event_mask & FD_WRITE))
+ watch->pollfd.revents |= G_IO_OUT;
+
+ if (channel->debug)
+ g_print ("\n revents={%s} retval={%s}\n",
+ condition_to_string (watch->pollfd.revents),
+ condition_to_string ((watch->pollfd.revents | buffer_condition) & watch->condition));
+
+ return ((watch->pollfd.revents | buffer_condition) & watch->condition);
+
+ default:
+ g_assert_not_reached ();
+ abort ();
+ }
+}
+
+static gboolean
+g_io_win32_dispatch (GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ GIOFunc func = (GIOFunc)callback;
+ GIOWin32Watch *watch = (GIOWin32Watch *)source;
+ GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
+ GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
+
+ if (!func)
+ {
+ g_warning ("IO Watch dispatched without callback\n"
+ "You must call g_source_connect().");
+ return FALSE;
+ }
+
+ if (channel->debug)
+ g_print ("g_io_win32_dispatch: pollfd.revents=%s condition=%s result=%s\n",
+ condition_to_string (watch->pollfd.revents),
+ condition_to_string (watch->condition),
+ condition_to_string ((watch->pollfd.revents | buffer_condition) & watch->condition));
+
+ return (*func) (watch->channel,
+ (watch->pollfd.revents | buffer_condition) & watch->condition,
+ user_data);
+}
+
+static void
+g_io_win32_finalize (GSource *source)
+{
+ GIOWin32Watch *watch = (GIOWin32Watch *)source;
+ GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
+
+ if (channel->debug)
+ g_print ("g_io_win32_finalize: source=%p channel=%p", source, channel);
+
+ switch (channel->type)
+ {
+ case G_IO_WIN32_WINDOWS_MESSAGES:
+ if (channel->debug)
+ g_print (" MSG");
+ break;
+
+ case G_IO_WIN32_CONSOLE:
+ if (channel->debug)
+ g_print (" CON");
+ break;
+
+ case G_IO_WIN32_FILE_DESC:
+ if (channel->debug)
+ g_print (" FD thread=%#x", channel->thread_id);
+ break;
+
+ case G_IO_WIN32_SOCKET:
+ if (channel->debug)
+ g_print (" SOCK sock=%d", channel->fd);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ abort ();
+ }
+ if (channel->debug)
+ g_print ("\n");
+ g_io_channel_unref (watch->channel);
+}
+
+GSourceFuncs g_io_watch_funcs = {
+ g_io_win32_prepare,
+ g_io_win32_check,
+ g_io_win32_dispatch,
+ g_io_win32_finalize
+};
+
+static GIOStatus
+g_io_win32_msg_read (GIOChannel *channel,
+ gchar *buf,
+ gsize count,
+ gsize *bytes_read,
+ GError **err)
+{
+ GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
+ MSG msg; /* In case of alignment problems */
+
+ if (count < sizeof (MSG))
+ {
+ g_set_error_literal (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
+ "Incorrect message size"); /* Informative enough error message? */
+ return G_IO_STATUS_ERROR;
+ }
+
+ if (win32_channel->debug)
+ g_print ("g_io_win32_msg_read: channel=%p hwnd=%p\n",
+ channel, win32_channel->hwnd);
+ if (!PeekMessage (&msg, win32_channel->hwnd, 0, 0, PM_REMOVE))
+ return G_IO_STATUS_AGAIN;
+