diff options
| author | Jan Djärv | 2002-03-10 16:02:47 +0000 |
|---|---|---|
| committer | Jan Djärv | 2002-03-10 16:02:47 +0000 |
| commit | afb4ecad4b64b73807c02003f3137745481232f6 (patch) | |
| tree | 7a77b13ec05fe0612385a09b7472d521eb778a2f /src | |
| parent | 945a8e9b9563e0d4131777181d04a20d7c6f708d (diff) | |
| download | emacs-afb4ecad4b64b73807c02003f3137745481232f6.tar.gz emacs-afb4ecad4b64b73807c02003f3137745481232f6.zip | |
New file for X session management.
Diffstat (limited to 'src')
| -rw-r--r-- | src/xsmfns.c | 533 |
1 files changed, 533 insertions, 0 deletions
diff --git a/src/xsmfns.c b/src/xsmfns.c new file mode 100644 index 00000000000..fe0570b665a --- /dev/null +++ b/src/xsmfns.c | |||
| @@ -0,0 +1,533 @@ | |||
| 1 | /* Session management module for systems which understand the X Session | ||
| 2 | management protocol. | ||
| 3 | Copyright (C) 2002 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software; you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation; either version 2, or (at your option) | ||
| 10 | any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs; see the file COPYING. If not, write to | ||
| 19 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
| 20 | Boston, MA 02111-1307, USA. */ | ||
| 21 | |||
| 22 | #include <config.h> | ||
| 23 | |||
| 24 | #ifdef HAVE_X_SM | ||
| 25 | |||
| 26 | #include <X11/SM/SMlib.h> | ||
| 27 | #ifdef HAVE_STRING_H | ||
| 28 | #include <string.h> | ||
| 29 | #else | ||
| 30 | #ifdef HAVE_STRINGS_H | ||
| 31 | #include <strings.h> | ||
| 32 | #endif | ||
| 33 | #endif | ||
| 34 | |||
| 35 | #ifdef HAVE_UNISTD_H | ||
| 36 | #include <unistd.h> | ||
| 37 | #endif | ||
| 38 | #ifdef HAVE_STDLIB_H | ||
| 39 | #include <stdlib.h> | ||
| 40 | #endif | ||
| 41 | |||
| 42 | #include <sys/param.h> | ||
| 43 | |||
| 44 | #include "systime.h" | ||
| 45 | #include "sysselect.h" | ||
| 46 | #include "lisp.h" | ||
| 47 | #include "termhooks.h" | ||
| 48 | |||
| 49 | #ifndef MAXPATHLEN | ||
| 50 | #define MAXPATHLEN 1024 | ||
| 51 | #endif /* not MAXPATHLEN */ | ||
| 52 | |||
| 53 | |||
| 54 | /* The user login name. */ | ||
| 55 | |||
| 56 | extern Lisp_Object Vuser_login_name; | ||
| 57 | |||
| 58 | /* This is the event used when save_session occurs */ | ||
| 59 | |||
| 60 | static struct input_event emacs_event; | ||
| 61 | |||
| 62 | /* The descriptor that we use to check for data from the session manager. */ | ||
| 63 | |||
| 64 | static int ice_fd = -1; | ||
| 65 | |||
| 66 | /* A flag that says if we are in shutdown interactions or not. */ | ||
| 67 | |||
| 68 | static int doing_interact = False; | ||
| 69 | |||
| 70 | /* The session manager object for the session manager connection */ | ||
| 71 | |||
| 72 | static SmcConn smc_conn; | ||
| 73 | |||
| 74 | /* The client session id for this session */ | ||
| 75 | static char *client_id; | ||
| 76 | |||
| 77 | /* The full path name to the Emacs program */ | ||
| 78 | static char *emacs_program; | ||
| 79 | |||
| 80 | /* The client session id for this session as a lisp object. */ | ||
| 81 | |||
| 82 | Lisp_Object Vx_session_id; | ||
| 83 | |||
| 84 | /* The id we had the previous session. This is only available if we | ||
| 85 | have been started by the session manager with SMID_OPT. */ | ||
| 86 | |||
| 87 | Lisp_Object Vx_session_previous_id; | ||
| 88 | |||
| 89 | /* The option we tell the session manager to start Emacs with when | ||
| 90 | restarting Emacs. The client_id is appended. */ | ||
| 91 | |||
| 92 | #define SMID_OPT "--smid=" | ||
| 93 | |||
| 94 | |||
| 95 | /* Handle any messages from the session manager. If no connection is | ||
| 96 | open to a session manager, just return 0. | ||
| 97 | Otherwise returns the number of events stored in buffer BUFP, | ||
| 98 | which can hold up to *NUMCHARS characters. At most one event is | ||
| 99 | stored, an save_session_event. */ | ||
| 100 | int | ||
| 101 | x_session_check_input (bufp, numchars) | ||
| 102 | struct input_event *bufp; | ||
| 103 | int *numchars; | ||
| 104 | { | ||
| 105 | SELECT_TYPE read_fds; | ||
| 106 | EMACS_TIME tmout; | ||
| 107 | |||
| 108 | if (ice_fd == -1) return 0; | ||
| 109 | |||
| 110 | FD_ZERO (&read_fds); | ||
| 111 | FD_SET (ice_fd, &read_fds); | ||
| 112 | |||
| 113 | tmout.tv_sec = 0; | ||
| 114 | tmout.tv_usec = 0; | ||
| 115 | |||
| 116 | /* Reset this so wo can check kind after callbacks have been called by | ||
| 117 | IceProcessMessages. The smc_interact_CB sets the kind to | ||
| 118 | save_session_event, but we don't know beforehand if that callback | ||
| 119 | will be called. */ | ||
| 120 | emacs_event.kind = no_event; | ||
| 121 | |||
| 122 | if (select (ice_fd+1, &read_fds, | ||
| 123 | (SELECT_TYPE *)0, (SELECT_TYPE *)0, &tmout) < 0) | ||
| 124 | { | ||
| 125 | ice_fd = -1; | ||
| 126 | return 0; | ||
| 127 | } | ||
| 128 | |||
| 129 | |||
| 130 | if (FD_ISSET (ice_fd, &read_fds)) | ||
| 131 | IceProcessMessages (SmcGetIceConnection (smc_conn), | ||
| 132 | (IceReplyWaitInfo *)0, (Bool *)0); | ||
| 133 | |||
| 134 | |||
| 135 | /* Check if smc_interact_CB was called and we shall generate a | ||
| 136 | save_session event. */ | ||
| 137 | if (*numchars > 0 && emacs_event.kind != no_event) | ||
| 138 | { | ||
| 139 | bcopy (&emacs_event, bufp, sizeof (struct input_event)); | ||
| 140 | bufp++; | ||
| 141 | (*numchars)--; | ||
| 142 | |||
| 143 | return 1; | ||
| 144 | } | ||
| 145 | |||
| 146 | return 0; | ||
| 147 | } | ||
| 148 | |||
| 149 | /* Return non-zero if we have a connection to a session manager.*/ | ||
| 150 | int | ||
| 151 | x_session_have_connection () | ||
| 152 | { | ||
| 153 | return ice_fd != -1; | ||
| 154 | } | ||
| 155 | |||
| 156 | /* This is called when the session manager says it is OK to interact with the | ||
| 157 | user. Here we set the kind to save_session so an event is generated. | ||
| 158 | Then lisp code can interact with the user. */ | ||
| 159 | static void | ||
| 160 | smc_interact_CB (smcConn, clientData) | ||
| 161 | SmcConn smcConn; | ||
| 162 | SmPointer clientData; | ||
| 163 | { | ||
| 164 | doing_interact = True; | ||
| 165 | emacs_event.kind = save_session_event; | ||
| 166 | } | ||
| 167 | |||
| 168 | /* This is called when the session manager tells us to save ourself. | ||
| 169 | We set the required properties so the session manager can restart us, | ||
| 170 | plus the current working directory property (not mandatory) so we | ||
| 171 | are started in the correct directory. | ||
| 172 | |||
| 173 | If this is a shutdown and we can request to interact with the user, | ||
| 174 | we do so, because we don't know what the lisp code might do. */ | ||
| 175 | static void | ||
| 176 | smc_save_yourself_CB (smcConn, | ||
| 177 | clientData, | ||
| 178 | saveType, | ||
| 179 | shutdown, | ||
| 180 | interactStyle, | ||
| 181 | fast) | ||
| 182 | SmcConn smcConn; | ||
| 183 | SmPointer clientData; | ||
| 184 | int saveType; | ||
| 185 | Bool shutdown; | ||
| 186 | int interactStyle; | ||
| 187 | Bool fast; | ||
| 188 | { | ||
| 189 | #define NR_PROPS 5 | ||
| 190 | |||
| 191 | SmProp *props[NR_PROPS]; | ||
| 192 | SmProp prop_ptr[NR_PROPS]; | ||
| 193 | |||
| 194 | SmPropValue values[20]; | ||
| 195 | int val_idx = 0; | ||
| 196 | int props_idx = 0; | ||
| 197 | |||
| 198 | char cwd[MAXPATHLEN+1]; | ||
| 199 | char *smid_opt; | ||
| 200 | |||
| 201 | /* How to start a new instance of Emacs */ | ||
| 202 | props[props_idx] = &prop_ptr[props_idx]; | ||
| 203 | props[props_idx]->name = SmCloneCommand; | ||
| 204 | props[props_idx]->type = SmLISTofARRAY8; | ||
| 205 | props[props_idx]->num_vals = 1; | ||
| 206 | props[props_idx]->vals = &values[val_idx++]; | ||
| 207 | props[props_idx]->vals[0].length = strlen (emacs_program); | ||
| 208 | props[props_idx]->vals[0].value = emacs_program; | ||
| 209 | ++props_idx; | ||
| 210 | |||
| 211 | /* The name of the program */ | ||
| 212 | props[props_idx] = &prop_ptr[props_idx]; | ||
| 213 | props[props_idx]->name = SmProgram; | ||
| 214 | props[props_idx]->type = SmARRAY8; | ||
| 215 | props[props_idx]->num_vals = 1; | ||
| 216 | props[props_idx]->vals = &values[val_idx++]; | ||
| 217 | props[props_idx]->vals[0].length = strlen (XSTRING (Vinvocation_name)->data); | ||
| 218 | props[props_idx]->vals[0].value = XSTRING (Vinvocation_name)->data; | ||
| 219 | ++props_idx; | ||
| 220 | |||
| 221 | /* How to restart Emacs (i.e.: /path/to/emacs --smid=xxxx). */ | ||
| 222 | props[props_idx] = &prop_ptr[props_idx]; | ||
| 223 | props[props_idx]->name = SmRestartCommand; | ||
| 224 | props[props_idx]->type = SmLISTofARRAY8; | ||
| 225 | props[props_idx]->num_vals = 2; /* 2 values: /path/to/emacs, --smid=xxx */ | ||
| 226 | props[props_idx]->vals = &values[val_idx]; | ||
| 227 | props[props_idx]->vals[0].length = strlen (emacs_program); | ||
| 228 | props[props_idx]->vals[0].value = emacs_program; | ||
| 229 | |||
| 230 | smid_opt = xmalloc (strlen (SMID_OPT) + strlen (client_id) + 1); | ||
| 231 | strcpy (smid_opt, SMID_OPT); | ||
| 232 | strcat (smid_opt, client_id); | ||
| 233 | |||
| 234 | props[props_idx]->vals[1].length = strlen (smid_opt); | ||
| 235 | props[props_idx]->vals[1].value = smid_opt; | ||
| 236 | val_idx += 2; | ||
| 237 | ++props_idx; | ||
| 238 | |||
| 239 | /* User id */ | ||
| 240 | props[props_idx] = &prop_ptr[props_idx]; | ||
| 241 | props[props_idx]->name = SmUserID; | ||
| 242 | props[props_idx]->type = SmARRAY8; | ||
| 243 | props[props_idx]->num_vals = 1; | ||
| 244 | props[props_idx]->vals = &values[val_idx++]; | ||
| 245 | props[props_idx]->vals[0].length = strlen (XSTRING (Vuser_login_name)->data); | ||
| 246 | props[props_idx]->vals[0].value = XSTRING (Vuser_login_name)->data; | ||
| 247 | ++props_idx; | ||
| 248 | |||
| 249 | /* The current directory property, not mandatory */ | ||
| 250 | #ifdef HAVE_GETCWD | ||
| 251 | if (getcwd (cwd, MAXPATHLEN+1) != 0) | ||
| 252 | #else | ||
| 253 | if (getwd (cwd) != 0) | ||
| 254 | #endif | ||
| 255 | { | ||
| 256 | props[props_idx] = &prop_ptr[props_idx]; | ||
| 257 | props[props_idx]->name = SmCurrentDirectory; | ||
| 258 | props[props_idx]->type = SmARRAY8; | ||
| 259 | props[props_idx]->num_vals = 1; | ||
| 260 | props[props_idx]->vals = &values[val_idx++]; | ||
| 261 | props[props_idx]->vals[0].length = strlen (cwd); | ||
| 262 | props[props_idx]->vals[0].value = cwd; | ||
| 263 | ++props_idx; | ||
| 264 | } | ||
| 265 | |||
| 266 | |||
| 267 | SmcSetProperties (smcConn, props_idx, props); | ||
| 268 | |||
| 269 | xfree (smid_opt); | ||
| 270 | |||
| 271 | /* See if we maybe shall interact with the user. */ | ||
| 272 | if (interactStyle != SmInteractStyleAny | ||
| 273 | || ! shutdown | ||
| 274 | || saveType == SmSaveLocal | ||
| 275 | || ! SmcInteractRequest (smcConn, SmDialogNormal, smc_interact_CB, 0)) | ||
| 276 | { | ||
| 277 | /* No interaction, we are done saving ourself. */ | ||
| 278 | SmcSaveYourselfDone (smcConn, True); | ||
| 279 | } | ||
| 280 | } | ||
| 281 | |||
| 282 | /* According to the SM specification, this shall close the connection */ | ||
| 283 | static void | ||
| 284 | smc_die_CB (smcConn, clientData) | ||
| 285 | SmcConn smcConn; | ||
| 286 | SmPointer clientData; | ||
| 287 | { | ||
| 288 | SmcCloseConnection (smcConn, 0, 0); | ||
| 289 | ice_fd = -1; | ||
| 290 | } | ||
| 291 | |||
| 292 | /* We don't use the next two but they are mandatory, leave them empty. | ||
| 293 | According to the SM specification, we should not interact with the | ||
| 294 | user between smc_save_yourself_CB is called and until smc_save_complete_CB | ||
| 295 | is called. It seems like a lot of job to implement this and it doesn't | ||
| 296 | even seem necessary. */ | ||
| 297 | static void | ||
| 298 | smc_save_complete_CB (smcConn, clientData) | ||
| 299 | SmcConn smcConn; | ||
| 300 | SmPointer clientData; | ||
| 301 | { | ||
| 302 | /* Empty */ | ||
| 303 | } | ||
| 304 | |||
| 305 | static void | ||
| 306 | smc_shutdown_cancelled_CB (smcConn, clientData) | ||
| 307 | SmcConn smcConn; | ||
| 308 | SmPointer clientData; | ||
| 309 | { | ||
| 310 | /* Empty */ | ||
| 311 | } | ||
| 312 | |||
| 313 | /* Error handlers for SM and ICE. We don't wan't to exit Emacs just | ||
| 314 | because there is some error in the session management. */ | ||
| 315 | static void | ||
| 316 | smc_error_handler (smcConn, | ||
| 317 | swap, | ||
| 318 | offendingMinorOpcode, | ||
| 319 | offendingSequence, | ||
| 320 | errorClass, | ||
| 321 | severity, | ||
| 322 | values) | ||
| 323 | SmcConn smcConn; | ||
| 324 | Bool swap; | ||
| 325 | int offendingMinorOpcode; | ||
| 326 | unsigned long offendingSequence; | ||
| 327 | int errorClass; | ||
| 328 | int severity; | ||
| 329 | SmPointer values; | ||
| 330 | { | ||
| 331 | /* Empty */ | ||
| 332 | } | ||
| 333 | |||
| 334 | static void | ||
| 335 | ice_error_handler (iceConn, | ||
| 336 | swap, | ||
| 337 | offendingMinorOpcode, | ||
| 338 | offendingSequence, | ||
| 339 | errorClass, | ||
| 340 | severity, | ||
| 341 | values) | ||
| 342 | IceConn iceConn; | ||
| 343 | Bool swap; | ||
| 344 | int offendingMinorOpcode; | ||
| 345 | unsigned long offendingSequence; | ||
| 346 | int errorClass; | ||
| 347 | int severity; | ||
| 348 | IcePointer values; | ||
| 349 | { | ||
| 350 | /* Empty */ | ||
| 351 | } | ||
| 352 | |||
| 353 | |||
| 354 | static void | ||
| 355 | ice_io_error_handler (iceConn) | ||
| 356 | IceConn iceConn; | ||
| 357 | { | ||
| 358 | /* Connection probably gone. */ | ||
| 359 | ice_fd = -1; | ||
| 360 | } | ||
| 361 | |||
| 362 | /* This is called when the ICE connection is created or closed. The SM library | ||
| 363 | uses ICE as it transport protocol. */ | ||
| 364 | static void | ||
| 365 | ice_conn_watch_CB (iceConn, clientData, opening, watchData) | ||
| 366 | IceConn iceConn; | ||
| 367 | IcePointer clientData; | ||
| 368 | Bool opening; | ||
| 369 | IcePointer *watchData; | ||
| 370 | { | ||
| 371 | if (! opening) | ||
| 372 | { | ||
| 373 | ice_fd = -1; | ||
| 374 | return; | ||
| 375 | } | ||
| 376 | |||
| 377 | ice_fd = IceConnectionNumber (iceConn); | ||
| 378 | #ifndef F_SETOWN_BUG | ||
| 379 | #ifdef F_SETOWN | ||
| 380 | #ifdef F_SETOWN_SOCK_NEG | ||
| 381 | /* stdin is a socket here */ | ||
| 382 | fcntl (ice_fd, F_SETOWN, -getpid ()); | ||
| 383 | #else /* ! defined (F_SETOWN_SOCK_NEG) */ | ||
| 384 | fcntl (ice_fd, F_SETOWN, getpid ()); | ||
| 385 | #endif /* ! defined (F_SETOWN_SOCK_NEG) */ | ||
| 386 | #endif /* ! defined (F_SETOWN) */ | ||
| 387 | #endif /* F_SETOWN_BUG */ | ||
| 388 | |||
| 389 | #ifdef SIGIO | ||
| 390 | if (interrupt_input) | ||
| 391 | init_sigio (ice_fd); | ||
| 392 | #endif /* ! defined (SIGIO) */ | ||
| 393 | } | ||
| 394 | |||
| 395 | /* Try to open a connection to the session manager. */ | ||
| 396 | void | ||
| 397 | x_session_initialize () | ||
| 398 | { | ||
| 399 | #define SM_ERRORSTRING_LEN 512 | ||
| 400 | char errorstring[SM_ERRORSTRING_LEN]; | ||
| 401 | char* previous_id = NULL; | ||
| 402 | SmcCallbacks callbacks; | ||
| 403 | int name_len = 0; | ||
| 404 | |||
| 405 | /* Check if we where started by the session manager. If so, we will | ||
| 406 | have a previous id. */ | ||
| 407 | if (! EQ (Vx_session_previous_id, Qnil) && STRINGP (Vx_session_previous_id)) | ||
| 408 | previous_id = XSTRING (Vx_session_previous_id)->data; | ||
| 409 | |||
| 410 | /* Construct the path to the Emacs program. */ | ||
| 411 | if (! EQ (Vinvocation_directory, Qnil)) | ||
| 412 | name_len += strlen (XSTRING (Vinvocation_directory)->data); | ||
| 413 | name_len += strlen (XSTRING (Vinvocation_name)->data); | ||
| 414 | |||
| 415 | /* This malloc will not be freed, but it is only done once, and hopefully | ||
| 416 | not very large */ | ||
| 417 | emacs_program = xmalloc (name_len + 1); | ||
| 418 | emacs_program[0] = '\0'; | ||
| 419 | |||
| 420 | if (! EQ (Vinvocation_directory, Qnil)) | ||
| 421 | strcpy (emacs_program, XSTRING (Vinvocation_directory)->data); | ||
| 422 | strcat (emacs_program, XSTRING (Vinvocation_name)->data); | ||
| 423 | |||
| 424 | /* The SM protocol says all callbacks are mandatory, so set up all | ||
| 425 | here and in the mask passed to SmcOpenConnection */ | ||
| 426 | callbacks.save_yourself.callback = smc_save_yourself_CB; | ||
| 427 | callbacks.save_yourself.client_data = 0; | ||
| 428 | callbacks.die.callback = smc_die_CB; | ||
| 429 | callbacks.die.client_data = 0; | ||
| 430 | callbacks.save_complete.callback = smc_save_complete_CB; | ||
| 431 | callbacks.save_complete.client_data = 0; | ||
| 432 | callbacks.shutdown_cancelled.callback = smc_shutdown_cancelled_CB; | ||
| 433 | callbacks.shutdown_cancelled.client_data = 0; | ||
| 434 | |||
| 435 | /* Set error handlers. */ | ||
| 436 | SmcSetErrorHandler (smc_error_handler); | ||
| 437 | IceSetErrorHandler (ice_error_handler); | ||
| 438 | IceSetIOErrorHandler (ice_io_error_handler); | ||
| 439 | |||
| 440 | /* Install callback for when connection status changes. */ | ||
| 441 | IceAddConnectionWatch (ice_conn_watch_CB, 0); | ||
| 442 | |||
| 443 | /* Open the connection to the session manager. A failure is not | ||
| 444 | critical, it usualy means that no session manager is running. | ||
| 445 | The errorstring is here for debugging. */ | ||
| 446 | smc_conn = SmcOpenConnection (NULL, NULL, 1, 0, | ||
| 447 | (SmcSaveYourselfProcMask| | ||
| 448 | SmcDieProcMask| | ||
| 449 | SmcSaveCompleteProcMask| | ||
| 450 | SmcShutdownCancelledProcMask), | ||
| 451 | &callbacks, | ||
| 452 | previous_id, | ||
| 453 | &client_id, | ||
| 454 | SM_ERRORSTRING_LEN, | ||
| 455 | errorstring); | ||
| 456 | |||
| 457 | if (smc_conn != 0) | ||
| 458 | Vx_session_id = make_string (client_id, strlen (client_id)); | ||
| 459 | } | ||
| 460 | |||
| 461 | |||
| 462 | DEFUN ("handle-save-session", Fhandle_save_session, | ||
| 463 | Shandle_save_session, 1, 1, "e", | ||
| 464 | doc: /* Handle the save_yourself event from a session manager. | ||
| 465 | A session manager can tell Emacs that the window system is shutting down | ||
| 466 | by sending Emacs a save_yourself message. Emacs executes this function when | ||
| 467 | such an event occurs. This function then executes `emacs-session-save'. | ||
| 468 | After that, this function informs the session manager that it can continue | ||
| 469 | or abort shutting down the window system depending on the return value | ||
| 470 | from `emacs-session-save' If the return value is non-nil the session manager | ||
| 471 | is told to abort the window system shutdown. | ||
| 472 | |||
| 473 | Do not call this function yourself. */) | ||
| 474 | (event) | ||
| 475 | Lisp_Object event; | ||
| 476 | { | ||
| 477 | /* Check doing_interact so that we don't do anything if someone called | ||
| 478 | this at the wrong time. */ | ||
| 479 | if (doing_interact) | ||
| 480 | { | ||
| 481 | Bool cancel_shutdown = False; | ||
| 482 | |||
| 483 | cancel_shutdown = ! EQ (call0 (intern ("emacs-session-save")), Qnil); | ||
| 484 | |||
| 485 | SmcInteractDone (smc_conn, cancel_shutdown); | ||
| 486 | SmcSaveYourselfDone (smc_conn, True); | ||
| 487 | |||
| 488 | doing_interact = False; | ||
| 489 | } | ||
| 490 | } | ||
| 491 | |||
| 492 | |||
| 493 | /*********************************************************************** | ||
| 494 | Initialization | ||
| 495 | ***********************************************************************/ | ||
| 496 | void | ||
| 497 | syms_of_xsmfns () | ||
| 498 | { | ||
| 499 | DEFVAR_LISP ("x-session-id", &Vx_session_id, | ||
| 500 | doc: /* The session id Emacs got from the session manager for this session. | ||
| 501 | Changing the value does not change the session id used by Emacs. | ||
| 502 | The value is nil if no session manager is running. | ||
| 503 | See also `x-session-previous-id', `emacs-save-session-functions', | ||
| 504 | `emacs-session-save' and `emacs-session-restore'." */); | ||
| 505 | Vx_session_id = Qnil; | ||
| 506 | |||
| 507 | DEFVAR_LISP ("x-session-previous-id", &Vx_session_previous_id, | ||
| 508 | doc: /* The previous session id Emacs got from session manager. | ||
| 509 | If Emacs is running on a window system that has a session manager, the | ||
| 510 | session manager gives Emacs a session id. It is feasible for Emacs lisp | ||
| 511 | code to use the session id to save configuration in, for example, a file | ||
| 512 | with a file name based on the session id. If Emacs is running when the | ||
| 513 | window system is shut down, the session manager remembers that Emacs was | ||
| 514 | running and saves the session id Emacs had. | ||
| 515 | |||
| 516 | When the window system is started again, the session manager restarts | ||
| 517 | Emacs and hands Emacs the session id it had the last time it was | ||
| 518 | running. This is now the previous session id and the value of this | ||
| 519 | variable. If configuration was saved in a file as stated above, the | ||
| 520 | previous session id shall be used to reconstruct the file name. | ||
| 521 | |||
| 522 | The session id Emacs has while it is running is in the variable | ||
| 523 | `x-session-id'. The value of this variable and `x-session-id' may be the | ||
| 524 | same, depending on how the session manager works. | ||
| 525 | |||
| 526 | See also `emacs-save-session-functions', `emacs-session-save' and | ||
| 527 | `emacs-session-restore'." */); | ||
| 528 | Vx_session_previous_id = Qnil; | ||
| 529 | |||
| 530 | defsubr (&Shandle_save_session); | ||
| 531 | } | ||
| 532 | |||
| 533 | #endif /* HAVE_X_SM */ | ||