libegg r906 - trunk/libegg/smclient



Author: danw
Date: Sun Oct  5 20:03:33 2008
New Revision: 906
URL: http://svn.gnome.org/viewvc/libegg?rev=906&view=rev

Log:
	* eggsmclient-win32.c: Redo using native Windows thread methods so
	we don't require g_thread_init() on Windows only.

	* egg-session-end.c (main):
	* logout-test.c (main): Remove g_thread_init()


Modified:
   trunk/libegg/smclient/ChangeLog
   trunk/libegg/smclient/egg-session-end.c
   trunk/libegg/smclient/eggsmclient-win32.c
   trunk/libegg/smclient/logout-test.c

Modified: trunk/libegg/smclient/egg-session-end.c
==============================================================================
--- trunk/libegg/smclient/egg-session-end.c	(original)
+++ trunk/libegg/smclient/egg-session-end.c	Sun Oct  5 20:03:33 2008
@@ -73,7 +73,6 @@
   GError *err = NULL;
 
   g_type_init ();
-  g_thread_init (NULL);
 
   goption_context = g_option_context_new (_("- End the current session"));
   g_option_context_add_main_entries (goption_context, options, NULL);

Modified: trunk/libegg/smclient/eggsmclient-win32.c
==============================================================================
--- trunk/libegg/smclient/eggsmclient-win32.c	(original)
+++ trunk/libegg/smclient/eggsmclient-win32.c	Sun Oct  5 20:03:33 2008
@@ -17,6 +17,35 @@
  * Boston, MA 02111-1307, USA.
  */
 
+/* EggSMClientWin32
+ *
+ * For details on the Windows XP logout process, see:
+ * http://msdn.microsoft.com/en-us/library/aa376876.aspx.
+ *
+ * Vista adds some new APIs which EggSMClient does not make use of; see
+ * http://msdn.microsoft.com/en-us/library/ms700677(VS.85).aspx
+ *
+ * When shutting down, Windows sends every top-level window a
+ * WM_QUERYENDSESSION event, which the application must respond to
+ * synchronously, saying whether or not it will quit. To avoid main
+ * loop re-entrancy problems (and to avoid having to muck about too
+ * much with the guts of the gdk-win32 main loop), we watch for this
+ * event in a separate thread, which then signals the main thread and
+ * waits for the main thread to handle the event. Since we don't want
+ * to require g_thread_init() to be called, we do this all using
+ * Windows-specific thread methods.
+ *
+ * After the application handles the WM_QUERYENDSESSION event,
+ * Windows then sends it a WM_ENDSESSION event with a TRUE or FALSE
+ * parameter indicating whether the session is or is not actually
+ * going to end now. We handle this from the other thread as well.
+ *
+ * As mentioned above, Vista introduces several additional new APIs
+ * that don't fit into the (current) EggSMClient API. Windows also has
+ * an entirely separate shutdown-notification scheme for non-GUI apps,
+ * which we also don't handle here.
+ */
+
 #include "config.h"
 
 #include "eggsmclient-private.h"
@@ -25,6 +54,7 @@
 #define WIN32_LEAN_AND_MEAN
 #define UNICODE
 #include <windows.h>
+#include <process.h>
 
 #define EGG_TYPE_SM_CLIENT_WIN32            (egg_sm_client_win32_get_type ())
 #define EGG_SM_CLIENT_WIN32(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT_WIN32, EggSMClientWin32))
@@ -39,7 +69,10 @@
 struct _EggSMClientWin32 {
   EggSMClient parent;
 
-  GAsyncQueue *msg_queue;
+  HANDLE message_event, response_event;
+
+  volatile GSourceFunc event;
+  volatile gboolean will_quit;
 };
 
 struct _EggSMClientWin32Class
@@ -56,7 +89,10 @@
 					     EggSMClientEndStyle  style,
 					     gboolean  request_confirmation);
 
-static gpointer sm_client_thread (gpointer data);
+static GSource *g_win32_handle_source_add (HANDLE handle, GSourceFunc callback,
+					gpointer user_data);
+static gboolean got_message (gpointer user_data);
+static void sm_client_thread (gpointer data);
 
 G_DEFINE_TYPE (EggSMClientWin32, egg_sm_client_win32, EGG_TYPE_SM_CLIENT)
 
@@ -88,9 +124,10 @@
 {
   EggSMClientWin32 *win32 = (EggSMClientWin32 *)client;
 
-  /* spawn another thread to listen for logout signals on */
-  win32->msg_queue = g_async_queue_new ();
-  g_thread_create (sm_client_thread, client, FALSE, NULL);
+  win32->message_event = CreateEvent (NULL, FALSE, FALSE, NULL);
+  win32->response_event = CreateEvent (NULL, FALSE, FALSE, NULL);
+  g_win32_handle_source_add (win32->message_event, got_message, win32);  
+  _beginthread (sm_client_thread, 0, client);
 }
 
 static void
@@ -99,8 +136,8 @@
 {
   EggSMClientWin32 *win32 = (EggSMClientWin32 *)client;
 
-  /* Can't push NULL onto a GAsyncQueue, so we add 1 to the value... */
-  g_async_queue_push (win32->msg_queue, GINT_TO_POINTER (will_quit + 1));
+  win32->will_quit = will_quit;
+  SetEvent (win32->response_event);
 }
 
 static gboolean
@@ -159,7 +196,7 @@
   egg_sm_client_quit (smclient);
   gdk_threads_leave ();
 
-  g_async_queue_push (win32->msg_queue, GINT_TO_POINTER (1));
+  SetEvent (win32->response_event);
   return FALSE;
 }
 
@@ -172,25 +209,80 @@
   egg_sm_client_quit_cancelled (smclient);
   gdk_threads_leave ();
 
-  g_async_queue_push (win32->msg_queue, GINT_TO_POINTER (1));
+  SetEvent (win32->response_event);
   return FALSE;
 }
 
+static gboolean
+got_message (gpointer smclient)
+{
+  EggSMClientWin32 *win32 = smclient;
+
+  win32->event (win32);
+  return TRUE;
+}
 
-/* logout-listener thread */
+/* Windows HANDLE GSource */
+
+typedef struct {
+  GSource source;
+  GPollFD pollfd;
+} GWin32HandleSource;
+
+static gboolean
+g_win32_handle_source_prepare (GSource *source, gint *timeout)
+{
+  *timeout = -1;
+  return FALSE;
+}
+
+static gboolean
+g_win32_handle_source_check (GSource *source)
+{
+  GWin32HandleSource *hsource = (GWin32HandleSource *)source;
+
+  return hsource->pollfd.revents;
+}
+
+static gboolean
+g_win32_handle_source_dispatch (GSource *source, GSourceFunc callback, gpointer user_data)
+{
+  return (*callback) (user_data);
+}
+
+static void
+g_win32_handle_source_finalize (GSource *source)
+{
+  ;
+}
 
-static int
-async_emit (EggSMClientWin32 *win32, GSourceFunc emitter)
+GSourceFuncs g_win32_handle_source_funcs = {
+  g_win32_handle_source_prepare,
+  g_win32_handle_source_check,
+  g_win32_handle_source_dispatch,
+  g_win32_handle_source_finalize
+};
+
+static GSource *
+g_win32_handle_source_add (HANDLE handle, GSourceFunc callback, gpointer user_data)
 {
-  /* ensure message queue is empty */
-  while (g_async_queue_try_pop (win32->msg_queue))
-    ;
-
-  /* Emit signal in the main thread and wait for a response */
-  g_idle_add (emitter, win32);
-  return GPOINTER_TO_INT (g_async_queue_pop (win32->msg_queue)) - 1;
+  GWin32HandleSource *hsource;
+  GSource *source;
+
+  source = g_source_new (&g_win32_handle_source_funcs, sizeof (GWin32HandleSource));
+  hsource = (GWin32HandleSource *)source;
+  hsource->pollfd.fd = (int)handle;
+  hsource->pollfd.events = G_IO_IN;
+  hsource->pollfd.revents = 0;
+  g_source_add_poll (source, &hsource->pollfd);
+
+  g_source_set_callback (source, callback, user_data, NULL);
+  g_source_attach (source, NULL);
+  return source;
 }
 
+/* logout-listener thread */
+
 LRESULT CALLBACK
 sm_client_win32_window_procedure (HWND   hwnd,
 				  UINT   message,
@@ -203,19 +295,27 @@
   switch (message)
     {
     case WM_QUERYENDSESSION:
-      return async_emit (win32, emit_quit_requested);
+      win32->event = emit_quit_requested;
+      SetEvent (win32->message_event);
+
+      WaitForSingleObject (win32->response_event, INFINITE);
+      return win32->will_quit;
 
     case WM_ENDSESSION:
       if (wParam)
 	{
 	  /* The session is ending */
-	  async_emit (win32, emit_quit);
+	  win32->event = emit_quit;
 	}
       else
 	{
 	  /* Nope, the session *isn't* ending */
-	  async_emit (win32, emit_quit_cancelled);
+	  win32->event = emit_quit_cancelled;
 	}
+
+      SetEvent (win32->message_event);
+      WaitForSingleObject (win32->response_event, INFINITE);
+
       return 0;
 
     default:
@@ -223,7 +323,7 @@
     }
 }
 
-static gpointer
+static void
 sm_client_thread (gpointer smclient)
 {
   HINSTANCE instance;
@@ -250,6 +350,4 @@
   /* main loop */
   while (GetMessage (&msg, NULL, 0, 0))
     DispatchMessage (&msg);
-
-  return NULL;
 }

Modified: trunk/libegg/smclient/logout-test.c
==============================================================================
--- trunk/libegg/smclient/logout-test.c	(original)
+++ trunk/libegg/smclient/logout-test.c	Sun Oct  5 20:03:33 2008
@@ -102,7 +102,6 @@
   GtkWidget *label;
 
   g_type_init ();
-  g_thread_init (NULL);
 
   goption_context = g_option_context_new (_("- Test logout functionality"));
   g_option_context_add_group (goption_context, gtk_get_option_group (TRUE));



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]