Mercurial > audlegacy
diff src/libeggsmclient/eggsmclient-win32.c @ 4315:c942eaef7bc6
Implement session management.
author | Ivan N. Zlatev <contact@i-nz.net> |
---|---|
date | Mon, 03 Mar 2008 18:42:36 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libeggsmclient/eggsmclient-win32.c Mon Mar 03 18:42:36 2008 +0000 @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2007 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "eggsmclient-private.h" +#include <gdk/gdk.h> + +#define WIN32_LEAN_AND_MEAN +#define UNICODE +#include <windows.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)) +#define EGG_SM_CLIENT_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT_WIN32, EggSMClientWin32Class)) +#define EGG_IS_SM_CLIENT_WIN32(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT_WIN32)) +#define EGG_IS_SM_CLIENT_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT_WIN32)) +#define EGG_SM_CLIENT_WIN32_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT_WIN32, EggSMClientWin32Class)) + +typedef struct _EggSMClientWin32 EggSMClientWin32; +typedef struct _EggSMClientWin32Class EggSMClientWin32Class; + +struct _EggSMClientWin32 { + EggSMClient parent; + + GAsyncQueue *msg_queue; +}; + +struct _EggSMClientWin32Class +{ + EggSMClientClass parent_class; + +}; + +static void sm_client_win32_startup (EggSMClient *client, + const char *client_id); +static void sm_client_win32_will_quit (EggSMClient *client, + gboolean will_quit); +static gboolean sm_client_win32_end_session (EggSMClient *client, + EggSMClientEndStyle style, + gboolean request_confirmation); + +static gpointer sm_client_thread (gpointer data); + +G_DEFINE_TYPE (EggSMClientWin32, egg_sm_client_win32, EGG_TYPE_SM_CLIENT) + +static void +egg_sm_client_win32_init (EggSMClientWin32 *win32) +{ + ; +} + +static void +egg_sm_client_win32_class_init (EggSMClientWin32Class *klass) +{ + EggSMClientClass *sm_client_class = EGG_SM_CLIENT_CLASS (klass); + + sm_client_class->startup = sm_client_win32_startup; + sm_client_class->will_quit = sm_client_win32_will_quit; + sm_client_class->end_session = sm_client_win32_end_session; +} + +EggSMClient * +egg_sm_client_win32_new (void) +{ + return g_object_new (EGG_TYPE_SM_CLIENT_WIN32, NULL); +} + +static void +sm_client_win32_startup (EggSMClient *client, + const char *client_id) +{ + 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); +} + +static void +sm_client_win32_will_quit (EggSMClient *client, + gboolean will_quit) +{ + 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)); +} + +static gboolean +sm_client_win32_end_session (EggSMClient *client, + EggSMClientEndStyle style, + gboolean request_confirmation) +{ + UINT uFlags = EWX_LOGOFF; + + switch (style) + { + case EGG_SM_CLIENT_END_SESSION_DEFAULT: + case EGG_SM_CLIENT_LOGOUT: + uFlags = EWX_LOGOFF; + break; + case EGG_SM_CLIENT_REBOOT: + uFlags = EWX_REBOOT; + break; + case EGG_SM_CLIENT_SHUTDOWN: + uFlags = EWX_POWEROFF; + break; + } + + /* There's no way to make ExitWindowsEx() show a logout dialog, so + * we ignore @request_confirmation. + */ + +#ifdef SHTDN_REASON_FLAG_PLANNED + ExitWindowsEx (uFlags, SHTDN_REASON_FLAG_PLANNED); +#else + ExitWindowsEx (uFlags, 0); +#endif + + return TRUE; +} + + +/* callbacks from logout-listener thread */ + +static gboolean +emit_quit_requested (gpointer smclient) +{ + gdk_threads_enter (); + egg_sm_client_quit_requested (smclient); + gdk_threads_leave (); + + return FALSE; +} + +static gboolean +emit_quit (gpointer smclient) +{ + EggSMClientWin32 *win32 = smclient; + + gdk_threads_enter (); + egg_sm_client_quit (smclient); + gdk_threads_leave (); + + g_async_queue_push (win32->msg_queue, GINT_TO_POINTER (1)); + return FALSE; +} + +static gboolean +emit_quit_cancelled (gpointer smclient) +{ + EggSMClientWin32 *win32 = smclient; + + gdk_threads_enter (); + egg_sm_client_quit_cancelled (smclient); + gdk_threads_leave (); + + g_async_queue_push (win32->msg_queue, GINT_TO_POINTER (1)); + return FALSE; +} + + +/* logout-listener thread */ + +static int +async_emit (EggSMClientWin32 *win32, GSourceFunc emitter) +{ + /* 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; +} + +LRESULT CALLBACK +sm_client_win32_window_procedure (HWND hwnd, + UINT message, + WPARAM wParam, + LPARAM lParam) +{ + EggSMClientWin32 *win32 = + (EggSMClientWin32 *)GetWindowLongPtr (hwnd, GWLP_USERDATA); + + switch (message) + { + case WM_QUERYENDSESSION: + return async_emit (win32, emit_quit_requested); + + case WM_ENDSESSION: + if (wParam) + { + /* The session is ending */ + async_emit (win32, emit_quit); + } + else + { + /* Nope, the session *isn't* ending */ + async_emit (win32, emit_quit_cancelled); + } + return 0; + + default: + return DefWindowProc (hwnd, message, wParam, lParam); + } +} + +static gpointer +sm_client_thread (gpointer smclient) +{ + HINSTANCE instance; + WNDCLASSEXW wcl; + ATOM klass; + HWND window; + MSG msg; + + instance = GetModuleHandle (NULL); + + memset (&wcl, 0, sizeof (WNDCLASSEX)); + wcl.cbSize = sizeof (WNDCLASSEX); + wcl.lpfnWndProc = sm_client_win32_window_procedure; + wcl.hInstance = instance; + wcl.lpszClassName = L"EggSmClientWindow"; + klass = RegisterClassEx (&wcl); + + window = CreateWindowEx (0, MAKEINTRESOURCE (klass), + L"EggSmClientWindow", 0, + 10, 10, 50, 50, GetDesktopWindow (), + NULL, instance, NULL); + SetWindowLongPtr (window, GWLP_USERDATA, (LONG_PTR)smclient); + + /* main loop */ + while (GetMessage (&msg, NULL, 0, 0)) + DispatchMessage (&msg); + + return NULL; +}