~ubuntu-branches/ubuntu/trusty/totem/trusty-proposed

« back to all changes in this revision

Viewing changes to src/eggsmclient-win32.c

  • Committer: Bazaar Package Importer
  • Author(s): Sjoerd Simons, Josselin Mouette, Sjoerd Simons, Emilio Pozuelo Monfort
  • Date: 2009-04-19 17:28:51 UTC
  • mfrom: (1.2.52 upstream) (5.1.1 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090419172851-epoqimnq62akn294
Tags: 2.26.1-1
[ Josselin Mouette ]
* totem-plugins depends on python-gdbm. Closes: #523582.

[ Sjoerd Simons ]
* New upstream release (2.26.1)
* debian/patches/02_flv.patch: Dropped, fixed upstream
* debian/patches/04_tracker_build.patch: Dropped, fixed upstream
* debian/patches/01_fake_keypresses.patch: Updated and simplified
* debian/patches/70_bbc_plugin.patch: Updated
* debian/patches/90_autotools.patch: Updated

[ Emilio Pozuelo Monfort ]
* Recommend gnome-codec-install rather than gnome-app-install.
  Closes: #523052.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2007 Novell, Inc.
 
3
 *
 
4
 * This library is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU Library General Public
 
6
 * License as published by the Free Software Foundation; either
 
7
 * version 2 of the License, or (at your option) any later version.
 
8
 *
 
9
 * This library is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
 * Library General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU Library General Public
 
15
 * License along with this library; if not, write to the
 
16
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
17
 * Boston, MA 02111-1307, USA.
 
18
 */
 
19
 
 
20
/* EggSMClientWin32
 
21
 *
 
22
 * For details on the Windows XP logout process, see:
 
23
 * http://msdn.microsoft.com/en-us/library/aa376876.aspx.
 
24
 *
 
25
 * Vista adds some new APIs which EggSMClient does not make use of; see
 
26
 * http://msdn.microsoft.com/en-us/library/ms700677(VS.85).aspx
 
27
 *
 
28
 * When shutting down, Windows sends every top-level window a
 
29
 * WM_QUERYENDSESSION event, which the application must respond to
 
30
 * synchronously, saying whether or not it will quit. To avoid main
 
31
 * loop re-entrancy problems (and to avoid having to muck about too
 
32
 * much with the guts of the gdk-win32 main loop), we watch for this
 
33
 * event in a separate thread, which then signals the main thread and
 
34
 * waits for the main thread to handle the event. Since we don't want
 
35
 * to require g_thread_init() to be called, we do this all using
 
36
 * Windows-specific thread methods.
 
37
 *
 
38
 * After the application handles the WM_QUERYENDSESSION event,
 
39
 * Windows then sends it a WM_ENDSESSION event with a TRUE or FALSE
 
40
 * parameter indicating whether the session is or is not actually
 
41
 * going to end now. We handle this from the other thread as well.
 
42
 *
 
43
 * As mentioned above, Vista introduces several additional new APIs
 
44
 * that don't fit into the (current) EggSMClient API. Windows also has
 
45
 * an entirely separate shutdown-notification scheme for non-GUI apps,
 
46
 * which we also don't handle here.
 
47
 */
 
48
 
 
49
#include "config.h"
 
50
 
 
51
#include "eggsmclient-private.h"
 
52
#include <gdk/gdk.h>
 
53
 
 
54
#define WIN32_LEAN_AND_MEAN
 
55
#define UNICODE
 
56
#include <windows.h>
 
57
#include <process.h>
 
58
 
 
59
#define EGG_TYPE_SM_CLIENT_WIN32            (egg_sm_client_win32_get_type ())
 
60
#define EGG_SM_CLIENT_WIN32(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT_WIN32, EggSMClientWin32))
 
61
#define EGG_SM_CLIENT_WIN32_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT_WIN32, EggSMClientWin32Class))
 
62
#define EGG_IS_SM_CLIENT_WIN32(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT_WIN32))
 
63
#define EGG_IS_SM_CLIENT_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT_WIN32))
 
64
#define EGG_SM_CLIENT_WIN32_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT_WIN32, EggSMClientWin32Class))
 
65
 
 
66
typedef struct _EggSMClientWin32        EggSMClientWin32;
 
67
typedef struct _EggSMClientWin32Class   EggSMClientWin32Class;
 
68
 
 
69
struct _EggSMClientWin32 {
 
70
  EggSMClient parent;
 
71
 
 
72
  HANDLE message_event, response_event;
 
73
 
 
74
  volatile GSourceFunc event;
 
75
  volatile gboolean will_quit;
 
76
};
 
77
 
 
78
struct _EggSMClientWin32Class
 
79
{
 
80
  EggSMClientClass parent_class;
 
81
 
 
82
};
 
83
 
 
84
static void     sm_client_win32_startup (EggSMClient *client,
 
85
                                         const char  *client_id);
 
86
static void     sm_client_win32_will_quit (EggSMClient *client,
 
87
                                           gboolean     will_quit);
 
88
static gboolean sm_client_win32_end_session (EggSMClient         *client,
 
89
                                             EggSMClientEndStyle  style,
 
90
                                             gboolean  request_confirmation);
 
91
 
 
92
static GSource *g_win32_handle_source_add (HANDLE handle, GSourceFunc callback,
 
93
                                        gpointer user_data);
 
94
static gboolean got_message (gpointer user_data);
 
95
static void sm_client_thread (gpointer data);
 
96
 
 
97
G_DEFINE_TYPE (EggSMClientWin32, egg_sm_client_win32, EGG_TYPE_SM_CLIENT)
 
98
 
 
99
static void
 
100
egg_sm_client_win32_init (EggSMClientWin32 *win32)
 
101
{
 
102
  ;
 
103
}
 
104
 
 
105
static void
 
106
egg_sm_client_win32_class_init (EggSMClientWin32Class *klass)
 
107
{
 
108
  EggSMClientClass *sm_client_class = EGG_SM_CLIENT_CLASS (klass);
 
109
 
 
110
  sm_client_class->startup             = sm_client_win32_startup;
 
111
  sm_client_class->will_quit           = sm_client_win32_will_quit;
 
112
  sm_client_class->end_session         = sm_client_win32_end_session;
 
113
}
 
114
 
 
115
EggSMClient *
 
116
egg_sm_client_win32_new (void)
 
117
{
 
118
  return g_object_new (EGG_TYPE_SM_CLIENT_WIN32, NULL);
 
119
}
 
120
 
 
121
static void
 
122
sm_client_win32_startup (EggSMClient *client,
 
123
                         const char  *client_id)
 
124
{
 
125
  EggSMClientWin32 *win32 = (EggSMClientWin32 *)client;
 
126
 
 
127
  win32->message_event = CreateEvent (NULL, FALSE, FALSE, NULL);
 
128
  win32->response_event = CreateEvent (NULL, FALSE, FALSE, NULL);
 
129
  g_win32_handle_source_add (win32->message_event, got_message, win32);  
 
130
  _beginthread (sm_client_thread, 0, client);
 
131
}
 
132
 
 
133
static void
 
134
sm_client_win32_will_quit (EggSMClient *client,
 
135
                           gboolean     will_quit)
 
136
{
 
137
  EggSMClientWin32 *win32 = (EggSMClientWin32 *)client;
 
138
 
 
139
  win32->will_quit = will_quit;
 
140
  SetEvent (win32->response_event);
 
141
}
 
142
 
 
143
static gboolean
 
144
sm_client_win32_end_session (EggSMClient         *client,
 
145
                             EggSMClientEndStyle  style,
 
146
                             gboolean             request_confirmation)
 
147
{
 
148
  UINT uFlags = EWX_LOGOFF;
 
149
 
 
150
  switch (style)
 
151
    {
 
152
    case EGG_SM_CLIENT_END_SESSION_DEFAULT:
 
153
    case EGG_SM_CLIENT_LOGOUT:
 
154
      uFlags = EWX_LOGOFF;
 
155
      break;
 
156
    case EGG_SM_CLIENT_REBOOT:
 
157
      uFlags = EWX_REBOOT;
 
158
      break;
 
159
    case EGG_SM_CLIENT_SHUTDOWN:
 
160
      uFlags = EWX_POWEROFF;
 
161
      break;
 
162
    }
 
163
 
 
164
  /* There's no way to make ExitWindowsEx() show a logout dialog, so
 
165
   * we ignore @request_confirmation.
 
166
   */
 
167
 
 
168
#ifdef SHTDN_REASON_FLAG_PLANNED
 
169
  ExitWindowsEx (uFlags, SHTDN_REASON_FLAG_PLANNED);
 
170
#else
 
171
  ExitWindowsEx (uFlags, 0);
 
172
#endif
 
173
 
 
174
  return TRUE;
 
175
}
 
176
 
 
177
 
 
178
/* callbacks from logout-listener thread */
 
179
 
 
180
static gboolean
 
181
emit_quit_requested (gpointer smclient)
 
182
{
 
183
  gdk_threads_enter ();
 
184
  egg_sm_client_quit_requested (smclient);
 
185
  gdk_threads_leave ();
 
186
 
 
187
  return FALSE;
 
188
}
 
189
 
 
190
static gboolean
 
191
emit_quit (gpointer smclient)
 
192
{
 
193
  EggSMClientWin32 *win32 = smclient;
 
194
 
 
195
  gdk_threads_enter ();
 
196
  egg_sm_client_quit (smclient);
 
197
  gdk_threads_leave ();
 
198
 
 
199
  SetEvent (win32->response_event);
 
200
  return FALSE;
 
201
}
 
202
 
 
203
static gboolean
 
204
emit_quit_cancelled (gpointer smclient)
 
205
{
 
206
  EggSMClientWin32 *win32 = smclient;
 
207
 
 
208
  gdk_threads_enter ();
 
209
  egg_sm_client_quit_cancelled (smclient);
 
210
  gdk_threads_leave ();
 
211
 
 
212
  SetEvent (win32->response_event);
 
213
  return FALSE;
 
214
}
 
215
 
 
216
static gboolean
 
217
got_message (gpointer smclient)
 
218
{
 
219
  EggSMClientWin32 *win32 = smclient;
 
220
 
 
221
  win32->event (win32);
 
222
  return TRUE;
 
223
}
 
224
 
 
225
/* Windows HANDLE GSource */
 
226
 
 
227
typedef struct {
 
228
  GSource source;
 
229
  GPollFD pollfd;
 
230
} GWin32HandleSource;
 
231
 
 
232
static gboolean
 
233
g_win32_handle_source_prepare (GSource *source, gint *timeout)
 
234
{
 
235
  *timeout = -1;
 
236
  return FALSE;
 
237
}
 
238
 
 
239
static gboolean
 
240
g_win32_handle_source_check (GSource *source)
 
241
{
 
242
  GWin32HandleSource *hsource = (GWin32HandleSource *)source;
 
243
 
 
244
  return hsource->pollfd.revents;
 
245
}
 
246
 
 
247
static gboolean
 
248
g_win32_handle_source_dispatch (GSource *source, GSourceFunc callback, gpointer user_data)
 
249
{
 
250
  return (*callback) (user_data);
 
251
}
 
252
 
 
253
static void
 
254
g_win32_handle_source_finalize (GSource *source)
 
255
{
 
256
  ;
 
257
}
 
258
 
 
259
GSourceFuncs g_win32_handle_source_funcs = {
 
260
  g_win32_handle_source_prepare,
 
261
  g_win32_handle_source_check,
 
262
  g_win32_handle_source_dispatch,
 
263
  g_win32_handle_source_finalize
 
264
};
 
265
 
 
266
static GSource *
 
267
g_win32_handle_source_add (HANDLE handle, GSourceFunc callback, gpointer user_data)
 
268
{
 
269
  GWin32HandleSource *hsource;
 
270
  GSource *source;
 
271
 
 
272
  source = g_source_new (&g_win32_handle_source_funcs, sizeof (GWin32HandleSource));
 
273
  hsource = (GWin32HandleSource *)source;
 
274
  hsource->pollfd.fd = (int)handle;
 
275
  hsource->pollfd.events = G_IO_IN;
 
276
  hsource->pollfd.revents = 0;
 
277
  g_source_add_poll (source, &hsource->pollfd);
 
278
 
 
279
  g_source_set_callback (source, callback, user_data, NULL);
 
280
  g_source_attach (source, NULL);
 
281
  return source;
 
282
}
 
283
 
 
284
/* logout-listener thread */
 
285
 
 
286
LRESULT CALLBACK
 
287
sm_client_win32_window_procedure (HWND   hwnd,
 
288
                                  UINT   message,
 
289
                                  WPARAM wParam,
 
290
                                  LPARAM lParam)
 
291
{
 
292
  EggSMClientWin32 *win32 =
 
293
    (EggSMClientWin32 *)GetWindowLongPtr (hwnd, GWLP_USERDATA);
 
294
 
 
295
  switch (message)
 
296
    {
 
297
    case WM_QUERYENDSESSION:
 
298
      win32->event = emit_quit_requested;
 
299
      SetEvent (win32->message_event);
 
300
 
 
301
      WaitForSingleObject (win32->response_event, INFINITE);
 
302
      return win32->will_quit;
 
303
 
 
304
    case WM_ENDSESSION:
 
305
      if (wParam)
 
306
        {
 
307
          /* The session is ending */
 
308
          win32->event = emit_quit;
 
309
        }
 
310
      else
 
311
        {
 
312
          /* Nope, the session *isn't* ending */
 
313
          win32->event = emit_quit_cancelled;
 
314
        }
 
315
 
 
316
      SetEvent (win32->message_event);
 
317
      WaitForSingleObject (win32->response_event, INFINITE);
 
318
 
 
319
      return 0;
 
320
 
 
321
    default:
 
322
      return DefWindowProc (hwnd, message, wParam, lParam);
 
323
    }
 
324
}
 
325
 
 
326
static void
 
327
sm_client_thread (gpointer smclient)
 
328
{
 
329
  HINSTANCE instance;
 
330
  WNDCLASSEXW wcl; 
 
331
  ATOM klass;
 
332
  HWND window;
 
333
  MSG msg;
 
334
 
 
335
  instance = GetModuleHandle (NULL);
 
336
 
 
337
  memset (&wcl, 0, sizeof (WNDCLASSEX));
 
338
  wcl.cbSize = sizeof (WNDCLASSEX);
 
339
  wcl.lpfnWndProc = sm_client_win32_window_procedure;
 
340
  wcl.hInstance = instance;
 
341
  wcl.lpszClassName = L"EggSmClientWindow";
 
342
  klass = RegisterClassEx (&wcl);
 
343
 
 
344
  window = CreateWindowEx (0, MAKEINTRESOURCE (klass),
 
345
                           L"EggSmClientWindow", 0,
 
346
                           10, 10, 50, 50, GetDesktopWindow (),
 
347
                           NULL, instance, NULL);
 
348
  SetWindowLongPtr (window, GWLP_USERDATA, (LONG_PTR)smclient);
 
349
 
 
350
  /* main loop */
 
351
  while (GetMessage (&msg, NULL, 0, 0))
 
352
    DispatchMessage (&msg);
 
353
}