~kaozilon/totem/test

« back to all changes in this revision

Viewing changes to src/eggsmclient-osx.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
 * Copyright (C) 2008 Red Hat, Inc.
 
4
 *
 
5
 * This library is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU Library General Public
 
7
 * License as published by the Free Software Foundation; either
 
8
 * version 2 of the License, or (at your option) any later version.
 
9
 *
 
10
 * This library is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
 * Library General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU Library General Public
 
16
 * License along with this library; if not, write to the
 
17
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
18
 * Boston, MA 02111-1307, USA.
 
19
 */
 
20
 
 
21
/* EggSMClientOSX
 
22
 *
 
23
 * For details on the OS X logout process, see:
 
24
 * http://developer.apple.com/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/BootProcess.html#//apple_ref/doc/uid/20002130-114618
 
25
 *
 
26
 * EggSMClientOSX registers for the kAEQuitApplication AppleEvent; the
 
27
 * handler we register (quit_requested()) will be invoked from inside
 
28
 * the quartz event-handling code (specifically, from inside
 
29
 * [NSApplication nextEventMatchingMask]) when an AppleEvent arrives.
 
30
 * We use AESuspendTheCurrentEvent() and AEResumeTheCurrentEvent() to
 
31
 * allow asynchronous / non-main-loop-reentering processing of the
 
32
 * quit request. (These are part of the Carbon framework; it doesn't
 
33
 * seem to be possible to handle AppleEvents asynchronously from
 
34
 * Cocoa.)
 
35
 */
 
36
 
 
37
#include "config.h"
 
38
 
 
39
#include "eggsmclient-private.h"
 
40
#include <gdk/gdkquartz.h>
 
41
#include <Carbon/Carbon.h>
 
42
#include <CoreServices/CoreServices.h>
 
43
 
 
44
#define EGG_TYPE_SM_CLIENT_OSX            (egg_sm_client_osx_get_type ())
 
45
#define EGG_SM_CLIENT_OSX(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT_OSX, EggSMClientOSX))
 
46
#define EGG_SM_CLIENT_OSX_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT_OSX, EggSMClientOSXClass))
 
47
#define EGG_IS_SM_CLIENT_OSX(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT_OSX))
 
48
#define EGG_IS_SM_CLIENT_OSX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT_OSX))
 
49
#define EGG_SM_CLIENT_OSX_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT_OSX, EggSMClientOSXClass))
 
50
 
 
51
typedef struct _EggSMClientOSX        EggSMClientOSX;
 
52
typedef struct _EggSMClientOSXClass   EggSMClientOSXClass;
 
53
 
 
54
struct _EggSMClientOSX {
 
55
  EggSMClient parent;
 
56
 
 
57
  AppleEvent quit_event, quit_reply;
 
58
  gboolean quit_requested, quitting;
 
59
};
 
60
 
 
61
struct _EggSMClientOSXClass
 
62
{
 
63
  EggSMClientClass parent_class;
 
64
 
 
65
};
 
66
 
 
67
static void     sm_client_osx_startup (EggSMClient *client,
 
68
                                       const char  *client_id);
 
69
static void     sm_client_osx_will_quit (EggSMClient *client,
 
70
                                         gboolean     will_quit);
 
71
static gboolean sm_client_osx_end_session (EggSMClient         *client,
 
72
                                           EggSMClientEndStyle  style,
 
73
                                           gboolean  request_confirmation);
 
74
 
 
75
static pascal OSErr quit_requested (const AppleEvent *, AppleEvent *, long);
 
76
 
 
77
G_DEFINE_TYPE (EggSMClientOSX, egg_sm_client_osx, EGG_TYPE_SM_CLIENT)
 
78
 
 
79
static void
 
80
egg_sm_client_osx_init (EggSMClientOSX *osx)
 
81
{
 
82
  ;
 
83
}
 
84
 
 
85
static void
 
86
egg_sm_client_osx_class_init (EggSMClientOSXClass *klass)
 
87
{
 
88
  EggSMClientClass *sm_client_class = EGG_SM_CLIENT_CLASS (klass);
 
89
 
 
90
  sm_client_class->startup             = sm_client_osx_startup;
 
91
  sm_client_class->will_quit           = sm_client_osx_will_quit;
 
92
  sm_client_class->end_session         = sm_client_osx_end_session;
 
93
}
 
94
 
 
95
EggSMClient *
 
96
egg_sm_client_osx_new (void)
 
97
{
 
98
  return g_object_new (EGG_TYPE_SM_CLIENT_OSX, NULL);
 
99
}
 
100
 
 
101
static void
 
102
sm_client_osx_startup (EggSMClient *client,
 
103
                       const char  *client_id)
 
104
{
 
105
  AEInstallEventHandler (kCoreEventClass, kAEQuitApplication,
 
106
                         NewAEEventHandlerUPP (quit_requested),
 
107
                         (long)GPOINTER_TO_SIZE (client), false);
 
108
}
 
109
 
 
110
static gboolean
 
111
idle_quit_requested (gpointer client)
 
112
{
 
113
  egg_sm_client_quit_requested (client);
 
114
  return FALSE;
 
115
}
 
116
 
 
117
static pascal OSErr
 
118
quit_requested (const AppleEvent *aevt, AppleEvent *reply, long refcon)
 
119
{
 
120
  EggSMClient *client = GSIZE_TO_POINTER ((gsize)refcon);
 
121
  EggSMClientOSX *osx = GSIZE_TO_POINTER ((gsize)refcon);
 
122
 
 
123
  g_return_val_if_fail (!osx->quit_requested, userCanceledErr);
 
124
    
 
125
  /* FIXME AEInteractWithUser? */
 
126
 
 
127
  osx->quit_requested = TRUE;
 
128
  AEDuplicateDesc (aevt, &osx->quit_event);
 
129
  AEDuplicateDesc (reply, &osx->quit_reply);
 
130
  AESuspendTheCurrentEvent (aevt);
 
131
 
 
132
  /* Don't emit the "quit_requested" signal immediately, since we're
 
133
   * called from a weird point in the guts of gdkeventloop-quartz.c
 
134
   */
 
135
  g_idle_add (idle_quit_requested, client);
 
136
  return noErr;
 
137
}
 
138
 
 
139
static pascal OSErr
 
140
quit_requested_resumed (const AppleEvent *aevt, AppleEvent *reply, long refcon)
 
141
{
 
142
  EggSMClientOSX *osx = GSIZE_TO_POINTER ((gsize)refcon);
 
143
 
 
144
  osx->quit_requested = FALSE;
 
145
  return osx->quitting ? noErr : userCanceledErr;
 
146
}
 
147
 
 
148
static gboolean
 
149
idle_will_quit (gpointer client)
 
150
{
 
151
  EggSMClientOSX *osx = (EggSMClientOSX *)client;
 
152
 
 
153
  /* Resume the event with a new handler that will return a value to
 
154
   * the system.
 
155
   */
 
156
  AEResumeTheCurrentEvent (&osx->quit_event, &osx->quit_reply,
 
157
                           NewAEEventHandlerUPP (quit_requested_resumed),
 
158
                           (long)GPOINTER_TO_SIZE (client));
 
159
  AEDisposeDesc (&osx->quit_event);
 
160
  AEDisposeDesc (&osx->quit_reply);
 
161
 
 
162
  if (osx->quitting)
 
163
    egg_sm_client_quit (client);
 
164
  return FALSE;
 
165
}
 
166
 
 
167
static void
 
168
sm_client_osx_will_quit (EggSMClient *client,
 
169
                         gboolean     will_quit)
 
170
{
 
171
  EggSMClientOSX *osx = (EggSMClientOSX *)client;
 
172
 
 
173
  g_return_if_fail (osx->quit_requested);
 
174
 
 
175
  osx->quitting = will_quit;
 
176
 
 
177
  /* Finish in an idle handler since the caller might have called
 
178
   * egg_sm_client_will_quit() from inside the "quit_requested" signal
 
179
   * handler, but may not expect the "quit" signal to arrive during
 
180
   * the _will_quit() call.
 
181
   */
 
182
  g_idle_add (idle_will_quit, client);
 
183
}
 
184
 
 
185
static gboolean
 
186
sm_client_osx_end_session (EggSMClient         *client,
 
187
                           EggSMClientEndStyle  style,
 
188
                           gboolean             request_confirmation)
 
189
{
 
190
  static const ProcessSerialNumber loginwindow_psn = { 0, kSystemProcess };
 
191
  AppleEvent event = { typeNull, NULL }, reply = { typeNull, NULL };
 
192
  AEAddressDesc target;
 
193
  AEEventID id;
 
194
  OSErr err;
 
195
 
 
196
  switch (style)
 
197
    {
 
198
    case EGG_SM_CLIENT_END_SESSION_DEFAULT:
 
199
    case EGG_SM_CLIENT_LOGOUT:
 
200
      id = request_confirmation ? kAELogOut : kAEReallyLogOut;
 
201
      break;
 
202
    case EGG_SM_CLIENT_REBOOT:
 
203
      id = request_confirmation ? kAEShowRestartDialog : kAERestart;
 
204
      break;
 
205
    case EGG_SM_CLIENT_SHUTDOWN:
 
206
      id = request_confirmation ? kAEShowShutdownDialog : kAEShutDown;
 
207
      break;
 
208
    }
 
209
 
 
210
  err = AECreateDesc (typeProcessSerialNumber, &loginwindow_psn, 
 
211
                      sizeof (loginwindow_psn), &target);
 
212
  if (err != noErr)
 
213
    {
 
214
      g_warning ("Could not create descriptor for loginwindow: %d", err);
 
215
      return FALSE;
 
216
    }
 
217
 
 
218
  err = AECreateAppleEvent (kCoreEventClass, id, &target,
 
219
                            kAutoGenerateReturnID, kAnyTransactionID,
 
220
                            &event);
 
221
  AEDisposeDesc (&target);
 
222
  if (err != noErr)
 
223
    {
 
224
      g_warning ("Could not create logout AppleEvent: %d", err);
 
225
      return FALSE;
 
226
    }
 
227
 
 
228
  err = AESend (&event, &reply, kAENoReply, kAENormalPriority,
 
229
                kAEDefaultTimeout, NULL, NULL);
 
230
  AEDisposeDesc (&event);
 
231
  if (err == noErr)
 
232
    AEDisposeDesc (&reply);
 
233
 
 
234
  return err == noErr;
 
235
}