2007-01-22 08:17:46 -06:00
|
|
|
/*
|
|
|
|
* 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"
|
2007-06-13 23:59:24 -05:00
|
|
|
#include <gdk/gdk.h>
|
|
|
|
|
2007-01-22 08:17:46 -06:00
|
|
|
#include <windows.h>
|
|
|
|
|
2007-11-15 22:47:51 -06:00
|
|
|
#define EGG_TYPE_SM_CLIENT_WIN32 (egg_sm_client_win32_get_type ())
|
2007-01-22 08:17:46 -06:00
|
|
|
#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;
|
|
|
|
|
2007-06-13 23:59:24 -05:00
|
|
|
GAsyncQueue *msg_queue;
|
2007-01-22 08:17:46 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2007-06-13 23:59:24 -05:00
|
|
|
static gpointer sm_client_thread (gpointer data);
|
2007-01-22 08:17:46 -06:00
|
|
|
|
2007-11-15 22:47:51 -06:00
|
|
|
G_DEFINE_TYPE (EggSMClientWin32, egg_sm_client_win32, EGG_TYPE_SM_CLIENT)
|
2007-01-22 08:17:46 -06:00
|
|
|
|
|
|
|
static void
|
2007-11-15 22:47:51 -06:00
|
|
|
egg_sm_client_win32_init (EggSMClientWin32 *win32)
|
2007-01-22 08:17:46 -06:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2007-11-15 22:47:51 -06:00
|
|
|
egg_sm_client_win32_class_init (EggSMClientWin32Class *klass)
|
2007-01-22 08:17:46 -06:00
|
|
|
{
|
|
|
|
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 *
|
2007-11-15 22:47:51 -06:00
|
|
|
egg_sm_client_win32_new (void)
|
2007-01-22 08:17:46 -06:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2007-06-13 23:59:24 -05:00
|
|
|
/* 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);
|
2007-01-22 08:17:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sm_client_win32_will_quit (EggSMClient *client,
|
|
|
|
gboolean will_quit)
|
|
|
|
{
|
|
|
|
EggSMClientWin32 *win32 = (EggSMClientWin32 *)client;
|
|
|
|
|
2007-06-13 23:59:24 -05:00
|
|
|
/* 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));
|
2007-01-22 08:17:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2007-06-13 23:59:24 -05:00
|
|
|
/* There's no way to make ExitWindowsEx() show a logout dialog, so
|
|
|
|
* we ignore @request_confirmation.
|
|
|
|
*/
|
2007-01-22 08:17:46 -06:00
|
|
|
|
|
|
|
#ifdef SHTDN_REASON_FLAG_PLANNED
|
|
|
|
ExitWindowsEx (uFlags, SHTDN_REASON_FLAG_PLANNED);
|
|
|
|
#else
|
|
|
|
ExitWindowsEx (uFlags, 0);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2007-06-13 23:59:24 -05:00
|
|
|
|
|
|
|
/* callbacks from logout-listener thread */
|
|
|
|
|
2007-01-22 08:17:46 -06:00
|
|
|
static gboolean
|
2007-06-13 23:59:24 -05:00
|
|
|
emit_quit_requested (gpointer smclient)
|
2007-01-22 08:17:46 -06:00
|
|
|
{
|
2007-06-13 23:59:24 -05:00
|
|
|
gdk_threads_enter ();
|
2007-11-15 22:47:51 -06:00
|
|
|
egg_sm_client_quit_requested (smclient);
|
2007-06-13 23:59:24 -05:00
|
|
|
gdk_threads_leave ();
|
2007-01-26 10:01:54 -06:00
|
|
|
|
2007-06-13 23:59:24 -05:00
|
|
|
return FALSE;
|
|
|
|
}
|
2007-01-22 08:17:46 -06:00
|
|
|
|
2007-06-13 23:59:24 -05:00
|
|
|
static gboolean
|
|
|
|
emit_quit (gpointer smclient)
|
|
|
|
{
|
|
|
|
EggSMClientWin32 *win32 = smclient;
|
2007-01-26 10:01:54 -06:00
|
|
|
|
2007-06-13 23:59:24 -05:00
|
|
|
gdk_threads_enter ();
|
2007-11-15 22:47:51 -06:00
|
|
|
egg_sm_client_quit (smclient);
|
2007-06-13 23:59:24 -05:00
|
|
|
gdk_threads_leave ();
|
2007-01-26 10:01:54 -06:00
|
|
|
|
2007-06-13 23:59:24 -05:00
|
|
|
g_async_queue_push (win32->msg_queue, GINT_TO_POINTER (1));
|
|
|
|
return FALSE;
|
|
|
|
}
|
2007-01-22 08:17:46 -06:00
|
|
|
|
2007-06-13 23:59:24 -05:00
|
|
|
static gboolean
|
|
|
|
emit_quit_cancelled (gpointer smclient)
|
|
|
|
{
|
|
|
|
EggSMClientWin32 *win32 = smclient;
|
2007-01-26 10:01:54 -06:00
|
|
|
|
2007-06-13 23:59:24 -05:00
|
|
|
gdk_threads_enter ();
|
2007-11-15 22:47:51 -06:00
|
|
|
egg_sm_client_quit_cancelled (smclient);
|
2007-06-13 23:59:24 -05:00
|
|
|
gdk_threads_leave ();
|
2007-01-26 10:01:54 -06:00
|
|
|
|
2007-06-13 23:59:24 -05:00
|
|
|
g_async_queue_push (win32->msg_queue, GINT_TO_POINTER (1));
|
|
|
|
return FALSE;
|
2007-01-22 08:17:46 -06:00
|
|
|
}
|
|
|
|
|
2007-06-13 23:59:24 -05:00
|
|
|
|
|
|
|
/* logout-listener thread */
|
|
|
|
|
|
|
|
static int
|
|
|
|
async_emit (EggSMClientWin32 *win32, GSourceFunc emitter)
|
2007-01-22 08:17:46 -06:00
|
|
|
{
|
2007-06-13 23:59:24 -05:00
|
|
|
/* ensure message queue is empty */
|
|
|
|
while (g_async_queue_try_pop (win32->msg_queue))
|
|
|
|
;
|
2007-01-22 08:17:46 -06:00
|
|
|
|
2007-06-13 23:59:24 -05:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static LRESULT CALLBACK
|
|
|
|
sm_client_win32_window_procedure (HWND hwnd,
|
|
|
|
UINT message,
|
|
|
|
WPARAM wParam,
|
|
|
|
LPARAM lParam)
|
|
|
|
{
|
|
|
|
EggSMClientWin32 *win32 =
|
|
|
|
(EggSMClientWin32 *)GetWindowLongPtr (hwnd, GWLP_USERDATA);
|
|
|
|
|
|
|
|
switch (message)
|
2007-01-22 08:17:46 -06:00
|
|
|
{
|
|
|
|
case WM_QUERYENDSESSION:
|
2007-06-13 23:59:24 -05:00
|
|
|
return async_emit (win32, emit_quit_requested);
|
2007-01-22 08:17:46 -06:00
|
|
|
|
|
|
|
case WM_ENDSESSION:
|
2007-06-13 23:59:24 -05:00
|
|
|
if (wParam)
|
2007-01-22 08:17:46 -06:00
|
|
|
{
|
|
|
|
/* The session is ending */
|
2007-06-13 23:59:24 -05:00
|
|
|
async_emit (win32, emit_quit);
|
2007-01-22 08:17:46 -06:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-06-13 23:59:24 -05:00
|
|
|
/* Nope, the session *isn't* ending */
|
|
|
|
async_emit (win32, emit_quit_cancelled);
|
2007-01-22 08:17:46 -06:00
|
|
|
}
|
2007-06-13 23:59:24 -05:00
|
|
|
return 0;
|
2007-01-22 08:17:46 -06:00
|
|
|
|
|
|
|
default:
|
2007-06-13 23:59:24 -05:00
|
|
|
return DefWindowProc (hwnd, message, wParam, lParam);
|
2007-01-22 08:17:46 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-13 23:59:24 -05:00
|
|
|
static gpointer
|
|
|
|
sm_client_thread (gpointer smclient)
|
2007-01-22 08:17:46 -06:00
|
|
|
{
|
2007-06-13 23:59:24 -05:00
|
|
|
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;
|
2007-01-22 08:17:46 -06:00
|
|
|
}
|