1 |
/* Session management module for systems which understand the X Session |
/* Session management module for systems which understand the X Session |
2 |
management protocol. |
management protocol. |
3 |
Copyright (C) 2002, 2002 Free Software Foundation, Inc. |
Copyright (C) 2002 Free Software Foundation, Inc. |
4 |
|
|
5 |
This file is part of GNU Emacs. |
This file is part of GNU Emacs. |
6 |
|
|
57 |
|
|
58 |
extern Lisp_Object Vuser_login_name; |
extern Lisp_Object Vuser_login_name; |
59 |
|
|
60 |
/* This is the event used when save_session occurs */ |
/* This is the event used when SAVE_SESSION_EVENT occurs. */ |
61 |
|
|
62 |
static struct input_event emacs_event; |
static struct input_event emacs_event; |
63 |
|
|
64 |
/* The descriptor that we use to check for data from the session manager. */ |
/* The descriptor that we use to check for data from the session manager. */ |
65 |
|
|
66 |
static int ice_fd = -1; |
static int ice_fd = -1; |
67 |
|
|
68 |
/* A flag that says if we are in shutdown interactions or not. */ |
/* A flag that says if we are in shutdown interactions or not. */ |
69 |
|
|
70 |
static int doing_interact = False; |
static int doing_interact = False; |
71 |
|
|
94 |
#define SMID_OPT "--smid=" |
#define SMID_OPT "--smid=" |
95 |
|
|
96 |
|
|
97 |
|
/* The option to start Emacs without the splash screen when |
98 |
|
restarting Emacs. */ |
99 |
|
|
100 |
|
#define NOSPLASH_OPT "--no-splash" |
101 |
|
|
102 |
|
|
103 |
/* Handle any messages from the session manager. If no connection is |
/* Handle any messages from the session manager. If no connection is |
104 |
open to a session manager, just return 0. |
open to a session manager, just return 0. |
105 |
Otherwise returns the number of events stored in buffer BUFP, |
Otherwise returns the number of events stored in buffer BUFP, |
106 |
which can hold up to *NUMCHARS characters. At most one event is |
which can hold up to *NUMCHARS characters. At most one event is |
107 |
stored, an save_session_event. */ |
stored, a SAVE_SESSION_EVENT. */ |
108 |
int |
int |
109 |
x_session_check_input (bufp, numchars) |
x_session_check_input (bufp, numchars) |
110 |
struct input_event *bufp; |
struct input_event *bufp; |
112 |
{ |
{ |
113 |
SELECT_TYPE read_fds; |
SELECT_TYPE read_fds; |
114 |
EMACS_TIME tmout; |
EMACS_TIME tmout; |
115 |
|
|
116 |
if (ice_fd == -1) return 0; |
if (ice_fd == -1) return 0; |
117 |
|
|
118 |
FD_ZERO (&read_fds); |
FD_ZERO (&read_fds); |
119 |
FD_SET (ice_fd, &read_fds); |
FD_SET (ice_fd, &read_fds); |
120 |
|
|
121 |
tmout.tv_sec = 0; |
tmout.tv_sec = 0; |
122 |
tmout.tv_usec = 0; |
tmout.tv_usec = 0; |
123 |
|
|
124 |
/* Reset this so wo can check kind after callbacks have been called by |
/* Reset this so wo can check kind after callbacks have been called by |
125 |
IceProcessMessages. The smc_interact_CB sets the kind to |
IceProcessMessages. The smc_interact_CB sets the kind to |
126 |
save_session_event, but we don't know beforehand if that callback |
SAVE_SESSION_EVENT, but we don't know beforehand if that callback |
127 |
will be called. */ |
will be called. */ |
128 |
emacs_event.kind = no_event; |
emacs_event.kind = NO_EVENT; |
129 |
|
|
130 |
if (select (ice_fd+1, &read_fds, |
if (select (ice_fd+1, &read_fds, |
131 |
(SELECT_TYPE *)0, (SELECT_TYPE *)0, &tmout) < 0) |
(SELECT_TYPE *)0, (SELECT_TYPE *)0, &tmout) < 0) |
133 |
ice_fd = -1; |
ice_fd = -1; |
134 |
return 0; |
return 0; |
135 |
} |
} |
136 |
|
|
137 |
|
|
138 |
if (FD_ISSET (ice_fd, &read_fds)) |
if (FD_ISSET (ice_fd, &read_fds)) |
139 |
IceProcessMessages (SmcGetIceConnection (smc_conn), |
IceProcessMessages (SmcGetIceConnection (smc_conn), |
140 |
(IceReplyWaitInfo *)0, (Bool *)0); |
(IceReplyWaitInfo *)0, (Bool *)0); |
141 |
|
|
142 |
|
|
143 |
/* Check if smc_interact_CB was called and we shall generate a |
/* Check if smc_interact_CB was called and we shall generate a |
144 |
save_session event. */ |
SAVE_SESSION_EVENT. */ |
145 |
if (*numchars > 0 && emacs_event.kind != no_event) |
if (*numchars > 0 && emacs_event.kind != NO_EVENT) |
146 |
{ |
{ |
147 |
bcopy (&emacs_event, bufp, sizeof (struct input_event)); |
bcopy (&emacs_event, bufp, sizeof (struct input_event)); |
148 |
bufp++; |
bufp++; |
162 |
} |
} |
163 |
|
|
164 |
/* This is called when the session manager says it is OK to interact with the |
/* This is called when the session manager says it is OK to interact with the |
165 |
user. Here we set the kind to save_session so an event is generated. |
user. Here we set the kind to SAVE_SESSION_EVENT so an event is generated. |
166 |
Then lisp code can interact with the user. */ |
Then lisp code can interact with the user. */ |
167 |
static void |
static void |
168 |
smc_interact_CB (smcConn, clientData) |
smc_interact_CB (smcConn, clientData) |
170 |
SmPointer clientData; |
SmPointer clientData; |
171 |
{ |
{ |
172 |
doing_interact = True; |
doing_interact = True; |
173 |
emacs_event.kind = save_session_event; |
emacs_event.kind = SAVE_SESSION_EVENT; |
174 |
} |
} |
175 |
|
|
176 |
/* This is called when the session manager tells us to save ourself. |
/* This is called when the session manager tells us to save ourselves. |
177 |
We set the required properties so the session manager can restart us, |
We set the required properties so the session manager can restart us, |
178 |
plus the current working directory property (not mandatory) so we |
plus the current working directory property (not mandatory) so we |
179 |
are started in the correct directory. |
are started in the correct directory. |
195 |
Bool fast; |
Bool fast; |
196 |
{ |
{ |
197 |
#define NR_PROPS 5 |
#define NR_PROPS 5 |
198 |
|
|
199 |
SmProp *props[NR_PROPS]; |
SmProp *props[NR_PROPS]; |
200 |
SmProp prop_ptr[NR_PROPS]; |
SmProp prop_ptr[NR_PROPS]; |
201 |
|
|
202 |
SmPropValue values[20]; |
SmPropValue values[20]; |
203 |
int val_idx = 0; |
int val_idx = 0; |
204 |
int props_idx = 0; |
int props_idx = 0; |
205 |
|
|
206 |
char cwd[MAXPATHLEN+1]; |
char cwd[MAXPATHLEN+1]; |
207 |
char *smid_opt; |
char *smid_opt; |
208 |
|
|
222 |
props[props_idx]->type = SmARRAY8; |
props[props_idx]->type = SmARRAY8; |
223 |
props[props_idx]->num_vals = 1; |
props[props_idx]->num_vals = 1; |
224 |
props[props_idx]->vals = &values[val_idx++]; |
props[props_idx]->vals = &values[val_idx++]; |
225 |
props[props_idx]->vals[0].length = strlen (XSTRING (Vinvocation_name)->data); |
props[props_idx]->vals[0].length = strlen (SDATA (Vinvocation_name)); |
226 |
props[props_idx]->vals[0].value = XSTRING (Vinvocation_name)->data; |
props[props_idx]->vals[0].value = SDATA (Vinvocation_name); |
227 |
++props_idx; |
++props_idx; |
228 |
|
|
229 |
/* How to restart Emacs (i.e.: /path/to/emacs --smid=xxxx). */ |
/* How to restart Emacs (i.e.: /path/to/emacs --smid=xxxx --no-splash). */ |
230 |
props[props_idx] = &prop_ptr[props_idx]; |
props[props_idx] = &prop_ptr[props_idx]; |
231 |
props[props_idx]->name = SmRestartCommand; |
props[props_idx]->name = SmRestartCommand; |
232 |
props[props_idx]->type = SmLISTofARRAY8; |
props[props_idx]->type = SmLISTofARRAY8; |
233 |
props[props_idx]->num_vals = 2; /* 2 values: /path/to/emacs, --smid=xxx */ |
props[props_idx]->num_vals = 3; /* /path/to/emacs, --smid=xxx --no-splash */ |
234 |
props[props_idx]->vals = &values[val_idx]; |
props[props_idx]->vals = &values[val_idx]; |
235 |
props[props_idx]->vals[0].length = strlen (emacs_program); |
props[props_idx]->vals[0].length = strlen (emacs_program); |
236 |
props[props_idx]->vals[0].value = emacs_program; |
props[props_idx]->vals[0].value = emacs_program; |
238 |
smid_opt = xmalloc (strlen (SMID_OPT) + strlen (client_id) + 1); |
smid_opt = xmalloc (strlen (SMID_OPT) + strlen (client_id) + 1); |
239 |
strcpy (smid_opt, SMID_OPT); |
strcpy (smid_opt, SMID_OPT); |
240 |
strcat (smid_opt, client_id); |
strcat (smid_opt, client_id); |
241 |
|
|
242 |
props[props_idx]->vals[1].length = strlen (smid_opt); |
props[props_idx]->vals[1].length = strlen (smid_opt); |
243 |
props[props_idx]->vals[1].value = smid_opt; |
props[props_idx]->vals[1].value = smid_opt; |
244 |
val_idx += 2; |
|
245 |
|
props[props_idx]->vals[2].length = strlen (NOSPLASH_OPT); |
246 |
|
props[props_idx]->vals[2].value = NOSPLASH_OPT; |
247 |
|
val_idx += 3; |
248 |
++props_idx; |
++props_idx; |
249 |
|
|
250 |
/* User id */ |
/* User id */ |
253 |
props[props_idx]->type = SmARRAY8; |
props[props_idx]->type = SmARRAY8; |
254 |
props[props_idx]->num_vals = 1; |
props[props_idx]->num_vals = 1; |
255 |
props[props_idx]->vals = &values[val_idx++]; |
props[props_idx]->vals = &values[val_idx++]; |
256 |
props[props_idx]->vals[0].length = strlen (XSTRING (Vuser_login_name)->data); |
props[props_idx]->vals[0].length = strlen (SDATA (Vuser_login_name)); |
257 |
props[props_idx]->vals[0].value = XSTRING (Vuser_login_name)->data; |
props[props_idx]->vals[0].value = SDATA (Vuser_login_name); |
258 |
++props_idx; |
++props_idx; |
259 |
|
|
260 |
/* The current directory property, not mandatory */ |
/* The current directory property, not mandatory */ |
273 |
props[props_idx]->vals[0].value = cwd; |
props[props_idx]->vals[0].value = cwd; |
274 |
++props_idx; |
++props_idx; |
275 |
} |
} |
276 |
|
|
277 |
|
|
278 |
SmcSetProperties (smcConn, props_idx, props); |
SmcSetProperties (smcConn, props_idx, props); |
279 |
|
|
280 |
xfree (smid_opt); |
xfree (smid_opt); |
321 |
/* Empty */ |
/* Empty */ |
322 |
} |
} |
323 |
|
|
324 |
/* Error handlers for SM and ICE. We don't wan't to exit Emacs just |
/* Error handlers for SM and ICE. We don't want to exit Emacs just |
325 |
because there is some error in the session management. */ |
because there is some error in the session management. */ |
326 |
static void |
static void |
327 |
smc_error_handler (smcConn, |
smc_error_handler (smcConn, |
384 |
ice_fd = -1; |
ice_fd = -1; |
385 |
return; |
return; |
386 |
} |
} |
387 |
|
|
388 |
ice_fd = IceConnectionNumber (iceConn); |
ice_fd = IceConnectionNumber (iceConn); |
389 |
#ifndef F_SETOWN_BUG |
#ifndef F_SETOWN_BUG |
390 |
#ifdef F_SETOWN |
#ifdef F_SETOWN |
412 |
char* previous_id = NULL; |
char* previous_id = NULL; |
413 |
SmcCallbacks callbacks; |
SmcCallbacks callbacks; |
414 |
int name_len = 0; |
int name_len = 0; |
415 |
|
|
416 |
/* Check if we where started by the session manager. If so, we will |
/* Check if we where started by the session manager. If so, we will |
417 |
have a previous id. */ |
have a previous id. */ |
418 |
if (! EQ (Vx_session_previous_id, Qnil) && STRINGP (Vx_session_previous_id)) |
if (! EQ (Vx_session_previous_id, Qnil) && STRINGP (Vx_session_previous_id)) |
419 |
previous_id = XSTRING (Vx_session_previous_id)->data; |
previous_id = SDATA (Vx_session_previous_id); |
420 |
|
|
421 |
/* Construct the path to the Emacs program. */ |
/* Construct the path to the Emacs program. */ |
422 |
if (! EQ (Vinvocation_directory, Qnil)) |
if (! EQ (Vinvocation_directory, Qnil)) |
423 |
name_len += strlen (XSTRING (Vinvocation_directory)->data); |
name_len += strlen (SDATA (Vinvocation_directory)); |
424 |
name_len += strlen (XSTRING (Vinvocation_name)->data); |
name_len += strlen (SDATA (Vinvocation_name)); |
425 |
|
|
426 |
/* This malloc will not be freed, but it is only done once, and hopefully |
/* This malloc will not be freed, but it is only done once, and hopefully |
427 |
not very large */ |
not very large */ |
429 |
emacs_program[0] = '\0'; |
emacs_program[0] = '\0'; |
430 |
|
|
431 |
if (! EQ (Vinvocation_directory, Qnil)) |
if (! EQ (Vinvocation_directory, Qnil)) |
432 |
strcpy (emacs_program, XSTRING (Vinvocation_directory)->data); |
strcpy (emacs_program, SDATA (Vinvocation_directory)); |
433 |
strcat (emacs_program, XSTRING (Vinvocation_name)->data); |
strcat (emacs_program, SDATA (Vinvocation_name)); |
434 |
|
|
435 |
/* The SM protocol says all callbacks are mandatory, so set up all |
/* The SM protocol says all callbacks are mandatory, so set up all |
436 |
here and in the mask passed to SmcOpenConnection */ |
here and in the mask passed to SmcOpenConnection */ |
437 |
callbacks.save_yourself.callback = smc_save_yourself_CB; |
callbacks.save_yourself.callback = smc_save_yourself_CB; |
452 |
IceAddConnectionWatch (ice_conn_watch_CB, 0); |
IceAddConnectionWatch (ice_conn_watch_CB, 0); |
453 |
|
|
454 |
/* Open the connection to the session manager. A failure is not |
/* Open the connection to the session manager. A failure is not |
455 |
critical, it usualy means that no session manager is running. |
critical, it usually means that no session manager is running. |
456 |
The errorstring is here for debugging. */ |
The errorstring is here for debugging. */ |
457 |
smc_conn = SmcOpenConnection (NULL, NULL, 1, 0, |
smc_conn = SmcOpenConnection (NULL, NULL, 1, 0, |
458 |
(SmcSaveYourselfProcMask| |
(SmcSaveYourselfProcMask| |
473 |
DEFUN ("handle-save-session", Fhandle_save_session, |
DEFUN ("handle-save-session", Fhandle_save_session, |
474 |
Shandle_save_session, 1, 1, "e", |
Shandle_save_session, 1, 1, "e", |
475 |
doc: /* Handle the save_yourself event from a session manager. |
doc: /* Handle the save_yourself event from a session manager. |
476 |
A session manager can tell Emacs that the window system is shutting down |
A session manager can tell Emacs that the window system is shutting down |
477 |
by sending Emacs a save_yourself message. Emacs executes this function when |
by sending Emacs a save_yourself message. Emacs executes this function when |
478 |
such an event occurs. This function then executes `emacs-session-save'. |
such an event occurs. This function then executes `emacs-session-save'. |
479 |
After that, this function informs the session manager that it can continue |
After that, this function informs the session manager that it can continue |
519 |
|
|
520 |
DEFVAR_LISP ("x-session-previous-id", &Vx_session_previous_id, |
DEFVAR_LISP ("x-session-previous-id", &Vx_session_previous_id, |
521 |
doc: /* The previous session id Emacs got from session manager. |
doc: /* The previous session id Emacs got from session manager. |
522 |
If Emacs is running on a window system that has a session manager, the |
If Emacs is running on a window system that has a session manager, the |
523 |
session manager gives Emacs a session id. It is feasible for Emacs lisp |
session manager gives Emacs a session id. It is feasible for Emacs lisp |
524 |
code to use the session id to save configuration in, for example, a file |
code to use the session id to save configuration in, for example, a file |
525 |
with a file name based on the session id. If Emacs is running when the |
with a file name based on the session id. If Emacs is running when the |
526 |
window system is shut down, the session manager remembers that Emacs was |
window system is shut down, the session manager remembers that Emacs was |
527 |
running and saves the session id Emacs had. |
running and saves the session id Emacs had. |
528 |
|
|
529 |
When the window system is started again, the session manager restarts |
When the window system is started again, the session manager restarts |
530 |
Emacs and hands Emacs the session id it had the last time it was |
Emacs and hands Emacs the session id it had the last time it was |
531 |
running. This is now the previous session id and the value of this |
running. This is now the previous session id and the value of this |
532 |
variable. If configuration was saved in a file as stated above, the |
variable. If configuration was saved in a file as stated above, the |
533 |
previous session id shall be used to reconstruct the file name. |
previous session id shall be used to reconstruct the file name. |
534 |
|
|
535 |
The session id Emacs has while it is running is in the variable |
The session id Emacs has while it is running is in the variable |
536 |
`x-session-id'. The value of this variable and `x-session-id' may be the |
`x-session-id'. The value of this variable and `x-session-id' may be the |
537 |
same, depending on how the session manager works. |
same, depending on how the session manager works. |
538 |
|
|
539 |
See also `emacs-save-session-functions', `emacs-session-save' and |
See also `emacs-save-session-functions', `emacs-session-save' and |
540 |
`emacs-session-restore'." */); |
`emacs-session-restore'." */); |
541 |
Vx_session_previous_id = Qnil; |
Vx_session_previous_id = Qnil; |
542 |
|
|
543 |
defsubr (&Shandle_save_session); |
defsubr (&Shandle_save_session); |
544 |
} |
} |
545 |
|
|