--- giowin32.c	2007-07-06 03:51:16.890625000 +0300
+++ giowin32.yaro.c	2007-07-06 04:31:38.593750000 +0300
@@ -113,6 +113,7 @@ struct _GIOWin32Channel {
   int event_mask;
   int last_events;
   int event;
+  gboolean FD_WRITE_received;
   gboolean write_would_have_blocked;
 };
 
@@ -355,6 +356,7 @@ g_io_channel_win32_init (GIOWin32Channel
   channel->event_mask = 0;
   channel->last_events = 0;
   channel->event = 0;
+  channel->FD_WRITE_received = FALSE;
   channel->write_would_have_blocked = FALSE;
   InitializeCriticalSection (&channel->mutex);
 }
@@ -823,13 +825,26 @@ g_io_win32_prepare (GSource *source,
 
       if (channel->event_mask != event_mask /* || channel->event != watch->pollfd.fd*/)
 	{
+	  int augmented_event_mask = channel->FD_WRITE_received ? event_mask : event_mask | FD_WRITE;
 	  if (channel->debug)
 	    g_print ("g_io_win32_prepare: WSAEventSelect(%d, %#x, {%s}\n",
 		     channel->fd, watch->pollfd.fd,
-		     event_mask_to_string (event_mask));
+		     event_mask_to_string (augmented_event_mask));
+	  /* We have to receive the first FD_WRITE even if the user
+	   * didn't request it to be able to set G_IO_OUT later
+	   * correctly. This will make sure, user callback will be
+	   * notified of G_IO_OUT if socket is ready and the last send
+	   * didn't return WSAEWOULDBLOCK
+	   */
 	  if (WSAEventSelect (channel->fd, (HANDLE) watch->pollfd.fd,
-			      event_mask) == SOCKET_ERROR)
-	    ;			/* What? */
+			      augmented_event_mask) == SOCKET_ERROR)
+	    {
+	      if (channel->debug)
+		g_print ("g_io_win32_prepare: WSAEventSelect(%d, %#x, {%s}): %s\n",
+			 channel->fd, watch->pollfd.fd,
+			 event_mask_to_string (augmented_event_mask),
+			 winsock_error_message (WSAGetLastError ()));
+	    }
 	  channel->event_mask = event_mask;
 #if 0
 	  channel->event = watch->pollfd.fd;
@@ -873,6 +888,10 @@ g_io_win32_check (GSource *source)
       return ((watch->pollfd.revents | buffer_condition) & watch->condition);
 
     case G_IO_WIN32_SOCKET:
+#if 0
+      /* If we get one FD_WRITE we could get stuck here as 
+       * channel->last_events would not be updated.
+       */
       if (channel->last_events & FD_WRITE)
 	{
 	  if (channel->debug)
@@ -880,6 +899,7 @@ g_io_win32_check (GSource *source)
 		     channel->fd, watch->pollfd.fd);
 	}
       else
+#endif
 	{
 	  WSAEnumNetworkEvents (channel->fd, 0, &events);
 
@@ -909,8 +929,17 @@ g_io_win32_check (GSource *source)
       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;
+	{
+	  watch->pollfd.revents |= G_IO_OUT;
+	  if (!channel->FD_WRITE_received)
+	    {
+	      channel->FD_WRITE_received = TRUE;
+	      if (channel->debug)
+		g_print ("g_io_win32_check: channel->FD_WRITE_received = TRUE;\n");
+	    }
+        }
       else
 	{
 	  /* We have called WSAEnumNetworkEvents() above but it didn't
@@ -923,15 +952,27 @@ g_io_win32_check (GSource *source)
 	      else
 		watch->pollfd.revents |= (G_IO_HUP | G_IO_ERR);
 	    }
-	  if (watch->pollfd.revents == 0 && (channel->last_events & (FD_CLOSE)))
+
+	  /* We have to dispatch on FD_CLOSE too, because
+	   * WSAEnumNetworkEvents automatically clears network events
+	   * and FD_CLOSE would be lost. Let the callback decide what
+	   * to do if both G_IO_IN & G_IO_HUP are received. Another
+	   * possibility would be to dispatch G_IO_IN first and then
+	   * G_IO_HUP. Never set both G_IO_OUT and G_IO_HUP.
+	   */
+	  if (!(watch->pollfd.revents & G_IO_OUT) &&
+	      (events.lNetworkEvents & FD_CLOSE))
 	    watch->pollfd.revents |= G_IO_HUP;
 	}
 
-      /* Regardless of WSAEnumNetworkEvents() result, if watching for
-       * writability, unless last write would have blocked set
-       * G_IO_OUT. But never set both G_IO_OUT and G_IO_HUP.
+      /* G_IO_OUT should be sent only once we receive first FD_WRITE
+       * event. To make sure we don't miss it (could happen if user
+       * didn't ask for it), we have to set WSAEventSelect to listen
+       * for FD_WRITE until we get the first FD_WRITE even if the user
+       * doesn't ask for it. Never set both G_IO_OUT and G_IO_HUP.
        */
       if (!(watch->pollfd.revents & G_IO_HUP) &&
+	  channel->FD_WRITE_received &&
 	  !channel->write_would_have_blocked &&
 	  (channel->event_mask & FD_WRITE))
 	watch->pollfd.revents |= G_IO_OUT;
@@ -1907,6 +1948,8 @@ g_io_channel_win32_new_socket (int socke
 {
   GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
   GIOChannel *channel = (GIOChannel *)win32_channel;
+  fd_set writefds;
+  struct timeval zero_timeout = { 0, 0 };
 
   g_io_channel_init (channel);
   g_io_channel_win32_init (win32_channel);
@@ -1916,6 +1959,16 @@ g_io_channel_win32_new_socket (int socke
   win32_channel->type = G_IO_WIN32_SOCKET;
   win32_channel->fd = socket;
 
+  FD_ZERO (&writefds);
+  FD_SET (socket, &writefds);
+
+  if (select (0, NULL, &writefds, NULL, &zero_timeout) > 0)
+    {
+      if (win32_channel->debug)
+	g_print ("g_io_channel_win32_new_socket: channel->FD_WRITE_received = TRUE;\n");
+      win32_channel->FD_WRITE_received = TRUE;
+    }
+
   channel->is_readable = TRUE;
   channel->is_writeable = TRUE;
   channel->is_seekable = FALSE;
