~ubuntu-branches/debian/sid/gnome-terminal/sid

« back to all changes in this revision

Viewing changes to src/eggsmclient.c

  • Committer: Package Import Robot
  • Author(s): Michael Biebl, Emilio Pozuelo Monfort, Michael Biebl
  • Date: 2013-06-05 22:23:26 UTC
  • mfrom: (1.6.15) (10.1.9 experimental)
  • Revision ID: package-import@ubuntu.com-20130605222326-ymxsw4ia0vri1zwh
Tags: 3.8.2-1
[ Emilio Pozuelo Monfort ]
* Remove obsolete build dependency on scrollkeeper.

[ Michael Biebl ]
* Upload to unstable.
* New upstream release.
* Bump Standards-Version to 3.9.4. No further changes.
* Add Build-Depends on autotools-dev as lintian was complaining about
  outdated config.{guess,sub}.

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 Lesser General Public
6
 
 * License as published by the Free Software Foundation; either
7
 
 * version 3 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
 
 * Lesser General Public License for more details.
13
 
 *
14
 
 * You should have received a copy of the GNU Lesser 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
 
#include "config.h"
21
 
 
22
 
#include <string.h>
23
 
#include <glib/gi18n.h>
24
 
 
25
 
#include "eggsmclient.h"
26
 
#include "eggsmclient-private.h"
27
 
 
28
 
static void egg_sm_client_debug_handler (const char *log_domain,
29
 
                                         GLogLevelFlags log_level,
30
 
                                         const char *message,
31
 
                                         gpointer user_data);
32
 
 
33
 
enum {
34
 
  SAVE_STATE,
35
 
  QUIT_REQUESTED,
36
 
  QUIT_CANCELLED,
37
 
  QUIT,
38
 
  LAST_SIGNAL
39
 
};
40
 
 
41
 
static guint signals[LAST_SIGNAL];
42
 
 
43
 
struct _EggSMClientPrivate {
44
 
  GKeyFile *state_file;
45
 
};
46
 
 
47
 
#define EGG_SM_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), EGG_TYPE_SM_CLIENT, EggSMClientPrivate))
48
 
 
49
 
G_DEFINE_TYPE (EggSMClient, egg_sm_client, G_TYPE_OBJECT)
50
 
 
51
 
static EggSMClient *global_client;
52
 
static EggSMClientMode global_client_mode = EGG_SM_CLIENT_MODE_NORMAL;
53
 
 
54
 
static void
55
 
egg_sm_client_init (EggSMClient *client)
56
 
{
57
 
  ;
58
 
}
59
 
 
60
 
static void
61
 
egg_sm_client_class_init (EggSMClientClass *klass)
62
 
{
63
 
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
64
 
 
65
 
  g_type_class_add_private (klass, sizeof (EggSMClientPrivate));
66
 
 
67
 
  /**
68
 
   * EggSMClient::save_state:
69
 
   * @client: the client
70
 
   * @state_file: a #GKeyFile to save state information into
71
 
   *
72
 
   * Emitted when the session manager has requested that the
73
 
   * application save information about its current state. The
74
 
   * application should save its state into @state_file, and then the
75
 
   * session manager may then restart the application in a future
76
 
   * session and tell it to initialize itself from that state.
77
 
   *
78
 
   * You should not save any data into @state_file's "start group"
79
 
   * (ie, the %NULL group). Instead, applications should save their
80
 
   * data into groups with names that start with the application name,
81
 
   * and libraries that connect to this signal should save their data
82
 
   * into groups with names that start with the library name.
83
 
   *
84
 
   * Alternatively, rather than (or in addition to) using @state_file,
85
 
   * the application can save its state by calling
86
 
   * egg_sm_client_set_restart_command() during the processing of this
87
 
   * signal (eg, to include a list of files to open).
88
 
   **/
89
 
  signals[SAVE_STATE] =
90
 
    g_signal_new ("save_state",
91
 
                  G_OBJECT_CLASS_TYPE (object_class),
92
 
                  G_SIGNAL_RUN_LAST,
93
 
                  G_STRUCT_OFFSET (EggSMClientClass, save_state),
94
 
                  NULL, NULL,
95
 
                  g_cclosure_marshal_VOID__POINTER,
96
 
                  G_TYPE_NONE,
97
 
                  1, G_TYPE_POINTER);
98
 
 
99
 
  /**
100
 
   * EggSMClient::quit_requested:
101
 
   * @client: the client
102
 
   *
103
 
   * Emitted when the session manager requests that the application
104
 
   * exit (generally because the user is logging out). The application
105
 
   * should decide whether or not it is willing to quit (perhaps after
106
 
   * asking the user what to do with documents that have unsaved
107
 
   * changes) and then call egg_sm_client_will_quit(), passing %TRUE
108
 
   * or %FALSE to give its answer to the session manager. (It does not
109
 
   * need to give an answer before returning from the signal handler;
110
 
   * it can interact with the user asynchronously and then give its
111
 
   * answer later on.) If the application does not connect to this
112
 
   * signal, then #EggSMClient will automatically return %TRUE on its
113
 
   * behalf.
114
 
   *
115
 
   * The application should not save its session state as part of
116
 
   * handling this signal; if the user has requested that the session
117
 
   * be saved when logging out, then ::save_state will be emitted
118
 
   * separately.
119
 
   * 
120
 
   * If the application agrees to quit, it should then wait for either
121
 
   * the ::quit_cancelled or ::quit signals to be emitted.
122
 
   **/
123
 
  signals[QUIT_REQUESTED] =
124
 
    g_signal_new ("quit_requested",
125
 
                  G_OBJECT_CLASS_TYPE (object_class),
126
 
                  G_SIGNAL_RUN_LAST,
127
 
                  G_STRUCT_OFFSET (EggSMClientClass, quit_requested),
128
 
                  NULL, NULL,
129
 
                  g_cclosure_marshal_VOID__VOID,
130
 
                  G_TYPE_NONE,
131
 
                  0);
132
 
 
133
 
  /**
134
 
   * EggSMClient::quit_cancelled:
135
 
   * @client: the client
136
 
   *
137
 
   * Emitted when the session manager decides to cancel a logout after
138
 
   * the application has already agreed to quit. After receiving this
139
 
   * signal, the application can go back to what it was doing before
140
 
   * receiving the ::quit_requested signal.
141
 
   **/
142
 
  signals[QUIT_CANCELLED] =
143
 
    g_signal_new ("quit_cancelled",
144
 
                  G_OBJECT_CLASS_TYPE (object_class),
145
 
                  G_SIGNAL_RUN_LAST,
146
 
                  G_STRUCT_OFFSET (EggSMClientClass, quit_cancelled),
147
 
                  NULL, NULL,
148
 
                  g_cclosure_marshal_VOID__VOID,
149
 
                  G_TYPE_NONE,
150
 
                  0);
151
 
 
152
 
  /**
153
 
   * EggSMClient::quit:
154
 
   * @client: the client
155
 
   *
156
 
   * Emitted when the session manager wants the application to quit
157
 
   * (generally because the user is logging out). The application
158
 
   * should exit as soon as possible after receiving this signal; if
159
 
   * it does not, the session manager may choose to forcibly kill it.
160
 
   *
161
 
   * Normally a GUI application would only be sent a ::quit if it
162
 
   * agreed to quit in response to a ::quit_requested signal. However,
163
 
   * this is not guaranteed; in some situations the session manager
164
 
   * may decide to end the session without giving applications a
165
 
   * chance to object.
166
 
   **/
167
 
  signals[QUIT] =
168
 
    g_signal_new ("quit",
169
 
                  G_OBJECT_CLASS_TYPE (object_class),
170
 
                  G_SIGNAL_RUN_LAST,
171
 
                  G_STRUCT_OFFSET (EggSMClientClass, quit),
172
 
                  NULL, NULL,
173
 
                  g_cclosure_marshal_VOID__VOID,
174
 
                  G_TYPE_NONE,
175
 
                  0);
176
 
}
177
 
 
178
 
static gboolean sm_client_disable = FALSE;
179
 
static char *sm_client_state_file = NULL;
180
 
static char *sm_client_id = NULL;
181
 
static char *sm_config_prefix = NULL;
182
 
 
183
 
static gboolean
184
 
sm_client_post_parse_func (GOptionContext  *context,
185
 
                           GOptionGroup    *group,
186
 
                           gpointer         data,
187
 
                           GError         **error)
188
 
{
189
 
  EggSMClient *client = egg_sm_client_get ();
190
 
 
191
 
  if (sm_client_id == NULL)
192
 
    {
193
 
      const gchar *desktop_autostart_id;
194
 
 
195
 
      desktop_autostart_id = g_getenv ("DESKTOP_AUTOSTART_ID");
196
 
 
197
 
      if (desktop_autostart_id != NULL)
198
 
        sm_client_id = g_strdup (desktop_autostart_id);
199
 
    }
200
 
 
201
 
  /* Unset DESKTOP_AUTOSTART_ID in order to avoid child processes to
202
 
   * use the same client id. */
203
 
  g_unsetenv ("DESKTOP_AUTOSTART_ID");
204
 
 
205
 
  if (global_client_mode != EGG_SM_CLIENT_MODE_DISABLED &&
206
 
      EGG_SM_CLIENT_GET_CLASS (client)->startup)
207
 
    EGG_SM_CLIENT_GET_CLASS (client)->startup (client, sm_client_id);
208
 
  return TRUE;
209
 
}
210
 
 
211
 
/**
212
 
 * egg_sm_client_get_option_group:
213
 
 *
214
 
 * Creates a %GOptionGroup containing the session-management-related
215
 
 * options. You should add this group to the application's
216
 
 * %GOptionContext if you want to use #EggSMClient.
217
 
 *
218
 
 * Return value: the %GOptionGroup
219
 
 **/
220
 
GOptionGroup *
221
 
egg_sm_client_get_option_group (void)
222
 
{
223
 
  const GOptionEntry entries[] = {
224
 
    { "sm-client-disable", 0, 0,
225
 
      G_OPTION_ARG_NONE, &sm_client_disable,
226
 
      N_("Disable connection to session manager"), NULL },
227
 
    { "sm-client-state-file", 0, 0,
228
 
      G_OPTION_ARG_FILENAME, &sm_client_state_file,
229
 
      N_("Specify file containing saved configuration"), N_("FILE") },
230
 
    { "sm-client-id", 0, 0,
231
 
      G_OPTION_ARG_STRING, &sm_client_id,
232
 
      N_("Specify session management ID"), N_("ID") },
233
 
    /* GnomeClient compatibility option */
234
 
    { "sm-disable", 0, G_OPTION_FLAG_HIDDEN,
235
 
      G_OPTION_ARG_NONE, &sm_client_disable,
236
 
      NULL, NULL },
237
 
    /* GnomeClient compatibility option. This is a dummy option that only
238
 
     * exists so that sessions saved by apps with GnomeClient can be restored
239
 
     * later when they've switched to EggSMClient. See bug #575308.
240
 
     */
241
 
    { "sm-config-prefix", 0, G_OPTION_FLAG_HIDDEN,
242
 
      G_OPTION_ARG_STRING, &sm_config_prefix,
243
 
      NULL, NULL },
244
 
    { NULL }
245
 
  };
246
 
  GOptionGroup *group;
247
 
 
248
 
  /* Use our own debug handler for the "EggSMClient" domain. */
249
 
  g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,
250
 
                     egg_sm_client_debug_handler, NULL);
251
 
 
252
 
  group = g_option_group_new ("sm-client",
253
 
                              _("Session management options:"),
254
 
                              _("Show session management options"),
255
 
                              NULL, NULL);
256
 
  g_option_group_add_entries (group, entries);
257
 
  g_option_group_set_parse_hooks (group, NULL, sm_client_post_parse_func);
258
 
 
259
 
  return group;
260
 
}
261
 
 
262
 
/**
263
 
 * egg_sm_client_set_mode:
264
 
 * @mode: an #EggSMClient mode
265
 
 *
266
 
 * Sets the "mode" of #EggSMClient as follows:
267
 
 *
268
 
 *    %EGG_SM_CLIENT_MODE_DISABLED: Session management is completely
269
 
 *    disabled, until the mode is changed again. The application will
270
 
 *    not even connect to the session manager. (egg_sm_client_get()
271
 
 *    will still return an #EggSMClient object.)
272
 
 *
273
 
 *    %EGG_SM_CLIENT_MODE_NO_RESTART: The application will connect to
274
 
 *    the session manager (and thus will receive notification when the
275
 
 *    user is logging out, etc), but will request to not be
276
 
 *    automatically restarted with saved state in future sessions.
277
 
 *
278
 
 *    %EGG_SM_CLIENT_MODE_NORMAL: The default. #EggSMCLient will
279
 
 *    function normally.
280
 
 *
281
 
 * This must be called before the application's main loop begins and
282
 
 * before any call to egg_sm_client_get(), unless the mode was set
283
 
 * earlier to %EGG_SM_CLIENT_MODE_DISABLED and this call enables
284
 
 * session management. Note that option parsing will call
285
 
 * egg_sm_client_get().
286
 
 **/
287
 
void
288
 
egg_sm_client_set_mode (EggSMClientMode mode)
289
 
{
290
 
  EggSMClientMode old_mode = global_client_mode;
291
 
 
292
 
  g_return_if_fail (global_client == NULL || global_client_mode == EGG_SM_CLIENT_MODE_DISABLED);
293
 
  g_return_if_fail (!(global_client != NULL && mode == EGG_SM_CLIENT_MODE_DISABLED));
294
 
 
295
 
  global_client_mode = mode;
296
 
 
297
 
  if (global_client != NULL && old_mode == EGG_SM_CLIENT_MODE_DISABLED)
298
 
    {
299
 
      if (EGG_SM_CLIENT_GET_CLASS (global_client)->startup)
300
 
        EGG_SM_CLIENT_GET_CLASS (global_client)->startup (global_client, sm_client_id);
301
 
    }
302
 
}
303
 
 
304
 
/**
305
 
 * egg_sm_client_get_mode:
306
 
 *
307
 
 * Gets the global #EggSMClientMode. See egg_sm_client_set_mode()
308
 
 * for details.
309
 
 *
310
 
 * Return value: the global #EggSMClientMode
311
 
 **/
312
 
EggSMClientMode
313
 
egg_sm_client_get_mode (void)
314
 
{
315
 
  return global_client_mode;
316
 
}
317
 
 
318
 
/**
319
 
 * egg_sm_client_get:
320
 
 *
321
 
 * Returns the master #EggSMClient for the application.
322
 
 *
323
 
 * On platforms that support saved sessions (ie, POSIX/X11), the
324
 
 * application will only request to be restarted by the session
325
 
 * manager if you call egg_set_desktop_file() to set an application
326
 
 * desktop file. In particular, if the desktop file contains the key
327
 
 * "X
328
 
 *
329
 
 * Return value: the master #EggSMClient.
330
 
 **/
331
 
EggSMClient *
332
 
egg_sm_client_get (void)
333
 
{
334
 
  if (!global_client)
335
 
    {
336
 
      if (!sm_client_disable)
337
 
        {
338
 
#if defined (GDK_WINDOWING_WIN32)
339
 
          global_client = egg_sm_client_win32_new ();
340
 
#elif defined (GDK_WINDOWING_QUARTZ)
341
 
          global_client = egg_sm_client_osx_new ();
342
 
#else
343
 
          /* If both D-Bus and XSMP are compiled in, try XSMP first
344
 
           * (since it supports state saving) and fall back to D-Bus
345
 
           * if XSMP isn't available.
346
 
           */
347
 
# ifdef EGG_SM_CLIENT_BACKEND_XSMP
348
 
          global_client = egg_sm_client_xsmp_new ();
349
 
# endif
350
 
# ifdef EGG_SM_CLIENT_BACKEND_DBUS
351
 
          if (!global_client)
352
 
            global_client = egg_sm_client_dbus_new ();
353
 
# endif
354
 
#endif
355
 
        }
356
 
 
357
 
      /* Fallback: create a dummy client, so that callers don't have
358
 
       * to worry about a %NULL return value.
359
 
       */
360
 
      if (!global_client)
361
 
        global_client = g_object_new (EGG_TYPE_SM_CLIENT, NULL);
362
 
    }
363
 
 
364
 
  return global_client;
365
 
}
366
 
 
367
 
/**
368
 
 * egg_sm_client_is_resumed:
369
 
 * @client: the client
370
 
 *
371
 
 * Checks whether or not the current session has been resumed from
372
 
 * a previous saved session. If so, the application should call
373
 
 * egg_sm_client_get_state_file() and restore its state from the
374
 
 * returned #GKeyFile.
375
 
 *
376
 
 * Return value: %TRUE if the session has been resumed
377
 
 **/
378
 
gboolean
379
 
egg_sm_client_is_resumed (EggSMClient *client)
380
 
{
381
 
  g_return_val_if_fail (client == global_client, FALSE);
382
 
 
383
 
  return sm_client_state_file != NULL;
384
 
}
385
 
 
386
 
/**
387
 
 * egg_sm_client_get_state_file:
388
 
 * @client: the client
389
 
 *
390
 
 * If the application was resumed by the session manager, this will
391
 
 * return the #GKeyFile containing its state from the previous
392
 
 * session.
393
 
 *
394
 
 * Note that other libraries and #EggSMClient itself may also store
395
 
 * state in the key file, so if you call egg_sm_client_get_groups(),
396
 
 * on it, the return value will likely include groups that you did not
397
 
 * put there yourself. (It is also not guaranteed that the first
398
 
 * group created by the application will still be the "start group"
399
 
 * when it is resumed.)
400
 
 *
401
 
 * Return value: the #GKeyFile containing the application's earlier
402
 
 * state, or %NULL on error. You should not free this key file; it
403
 
 * is owned by @client.
404
 
 **/
405
 
GKeyFile *
406
 
egg_sm_client_get_state_file (EggSMClient *client)
407
 
{
408
 
  EggSMClientPrivate *priv = EGG_SM_CLIENT_GET_PRIVATE (client);
409
 
  char *state_file_path;
410
 
  GError *err = NULL;
411
 
 
412
 
  g_return_val_if_fail (client == global_client, NULL);
413
 
 
414
 
  if (!sm_client_state_file)
415
 
    return NULL;
416
 
  if (priv->state_file)
417
 
    return priv->state_file;
418
 
 
419
 
  if (!strncmp (sm_client_state_file, "file://", 7))
420
 
    state_file_path = g_filename_from_uri (sm_client_state_file, NULL, NULL);
421
 
  else
422
 
    state_file_path = g_strdup (sm_client_state_file);
423
 
 
424
 
  priv->state_file = g_key_file_new ();
425
 
  if (!g_key_file_load_from_file (priv->state_file, state_file_path, 0, &err))
426
 
    {
427
 
      g_warning ("Could not load SM state file '%s': %s",
428
 
                 sm_client_state_file, err->message);
429
 
      g_clear_error (&err);
430
 
      g_key_file_free (priv->state_file);
431
 
      priv->state_file = NULL;
432
 
    }
433
 
 
434
 
  g_free (state_file_path);
435
 
  return priv->state_file;
436
 
}
437
 
 
438
 
/**
439
 
 * egg_sm_client_set_restart_command:
440
 
 * @client: the client
441
 
 * @argc: the length of @argv
442
 
 * @argv: argument vector
443
 
 *
444
 
 * Sets the command used to restart @client if it does not have a
445
 
 * .desktop file that can be used to find its restart command.
446
 
 *
447
 
 * This can also be used when handling the ::save_state signal, to
448
 
 * save the current state via an updated command line. (Eg, providing
449
 
 * a list of filenames to open when the application is resumed.)
450
 
 **/
451
 
void
452
 
egg_sm_client_set_restart_command (EggSMClient  *client,
453
 
                                   int           argc,
454
 
                                   const char  **argv)
455
 
{
456
 
  g_return_if_fail (EGG_IS_SM_CLIENT (client));
457
 
 
458
 
  if (EGG_SM_CLIENT_GET_CLASS (client)->set_restart_command)
459
 
    EGG_SM_CLIENT_GET_CLASS (client)->set_restart_command (client, argc, argv);
460
 
}
461
 
 
462
 
/**
463
 
 * egg_sm_client_set_discard_command:
464
 
 * @client: the client
465
 
 * @argc: the length of @argv
466
 
 * @argv: argument vector
467
 
 *
468
 
 * Sets the command used to discard a custom state file if using
469
 
 * egg_sm_client_set_restart_command(), which must be called before 
470
 
 * using this function.
471
 
 **/
472
 
void
473
 
egg_sm_client_set_discard_command (EggSMClient  *client,
474
 
                                   int           argc,
475
 
                                   const char  **argv)
476
 
{
477
 
  g_return_if_fail (EGG_IS_SM_CLIENT (client));
478
 
 
479
 
  if (EGG_SM_CLIENT_GET_CLASS (client)->set_discard_command)
480
 
    EGG_SM_CLIENT_GET_CLASS (client)->set_discard_command (client, argc, argv);
481
 
}
482
 
 
483
 
/**
484
 
 * egg_sm_client_will_quit:
485
 
 * @client: the client
486
 
 * @will_quit: whether or not the application is willing to quit
487
 
 *
488
 
 * This MUST be called in response to the ::quit_requested signal, to
489
 
 * indicate whether or not the application is willing to quit. The
490
 
 * application may call it either directly from the signal handler, or
491
 
 * at some later point (eg, after asynchronously interacting with the
492
 
 * user).
493
 
 *
494
 
 * If the application does not connect to ::quit_requested,
495
 
 * #EggSMClient will call this method on its behalf (passing %TRUE
496
 
 * for @will_quit).
497
 
 *
498
 
 * After calling this method, the application should wait to receive
499
 
 * either ::quit_cancelled or ::quit.
500
 
 **/
501
 
void
502
 
egg_sm_client_will_quit (EggSMClient *client,
503
 
                         gboolean     will_quit)
504
 
{
505
 
  g_return_if_fail (EGG_IS_SM_CLIENT (client));
506
 
 
507
 
  if (EGG_SM_CLIENT_GET_CLASS (client)->will_quit)
508
 
    EGG_SM_CLIENT_GET_CLASS (client)->will_quit (client, will_quit);
509
 
}
510
 
 
511
 
/**
512
 
 * egg_sm_client_end_session:
513
 
 * @style: a hint at how to end the session
514
 
 * @request_confirmation: whether or not the user should get a chance
515
 
 * to confirm the action
516
 
 *
517
 
 * Requests that the session manager end the current session. @style
518
 
 * indicates how the session should be ended, and
519
 
 * @request_confirmation indicates whether or not the user should be
520
 
 * given a chance to confirm the logout/reboot/shutdown. Both of these
521
 
 * flags are merely hints though; the session manager may choose to
522
 
 * ignore them.
523
 
 *
524
 
 * Return value: %TRUE if the request was sent; %FALSE if it could not
525
 
 * be (eg, because it could not connect to the session manager).
526
 
 **/
527
 
gboolean
528
 
egg_sm_client_end_session (EggSMClientEndStyle  style,
529
 
                           gboolean             request_confirmation)
530
 
{
531
 
  EggSMClient *client = egg_sm_client_get ();
532
 
 
533
 
  g_return_val_if_fail (EGG_IS_SM_CLIENT (client), FALSE);
534
 
 
535
 
  if (EGG_SM_CLIENT_GET_CLASS (client)->end_session)
536
 
    {
537
 
      return EGG_SM_CLIENT_GET_CLASS (client)->end_session (client, style,
538
 
                                                            request_confirmation);
539
 
    }
540
 
  else
541
 
    return FALSE;
542
 
}
543
 
 
544
 
/* Signal-emitting callbacks from platform-specific code */
545
 
 
546
 
GKeyFile *
547
 
egg_sm_client_save_state (EggSMClient *client)
548
 
{
549
 
  GKeyFile *state_file;
550
 
  char *group;
551
 
 
552
 
  g_return_val_if_fail (client == global_client, NULL);
553
 
 
554
 
  state_file = g_key_file_new ();
555
 
 
556
 
  g_debug ("Emitting save_state");
557
 
  g_signal_emit (client, signals[SAVE_STATE], 0, state_file);
558
 
  g_debug ("Done emitting save_state");
559
 
 
560
 
  group = g_key_file_get_start_group (state_file);
561
 
  if (group)
562
 
    {
563
 
      g_free (group);
564
 
      return state_file;
565
 
    }
566
 
  else
567
 
    {
568
 
      g_key_file_free (state_file);
569
 
      return NULL;
570
 
    }
571
 
}
572
 
 
573
 
void
574
 
egg_sm_client_quit_requested (EggSMClient *client)
575
 
{
576
 
  g_return_if_fail (client == global_client);
577
 
 
578
 
  if (!g_signal_has_handler_pending (client, signals[QUIT_REQUESTED], 0, FALSE))
579
 
    {
580
 
      g_debug ("Not emitting quit_requested because no one is listening");
581
 
      egg_sm_client_will_quit (client, TRUE);
582
 
      return;
583
 
    }
584
 
 
585
 
  g_debug ("Emitting quit_requested");
586
 
  g_signal_emit (client, signals[QUIT_REQUESTED], 0);
587
 
  g_debug ("Done emitting quit_requested");
588
 
}
589
 
 
590
 
void
591
 
egg_sm_client_quit_cancelled (EggSMClient *client)
592
 
{
593
 
  g_return_if_fail (client == global_client);
594
 
 
595
 
  g_debug ("Emitting quit_cancelled");
596
 
  g_signal_emit (client, signals[QUIT_CANCELLED], 0);
597
 
  g_debug ("Done emitting quit_cancelled");
598
 
}
599
 
 
600
 
void
601
 
egg_sm_client_quit (EggSMClient *client)
602
 
{
603
 
  g_return_if_fail (client == global_client);
604
 
 
605
 
  g_debug ("Emitting quit");
606
 
  g_signal_emit (client, signals[QUIT], 0);
607
 
  g_debug ("Done emitting quit");
608
 
 
609
 
  /* FIXME: should we just call gtk_main_quit() here? */
610
 
}
611
 
 
612
 
static void
613
 
egg_sm_client_debug_handler (const char *log_domain,
614
 
                             GLogLevelFlags log_level,
615
 
                             const char *message,
616
 
                             gpointer user_data)
617
 
{
618
 
  static int debug = -1;
619
 
 
620
 
  if (debug < 0)
621
 
    debug = (g_getenv ("EGG_SM_CLIENT_DEBUG") != NULL);
622
 
 
623
 
  if (debug)
624
 
    g_log_default_handler (log_domain, log_level, message, NULL);
625
 
}