73 |
|
|
74 |
static int doing_interact = False; |
static int doing_interact = False; |
75 |
|
|
76 |
/* The session manager object for the session manager connection */ |
/* The session manager object for the session manager connection. */ |
77 |
|
|
78 |
static SmcConn smc_conn; |
static SmcConn smc_conn; |
79 |
|
|
80 |
/* The client session id for this session */ |
/* The client session id for this session. */ |
81 |
|
|
82 |
static char *client_id; |
static char *client_id; |
83 |
|
|
84 |
/* The full path name to the Emacs program */ |
/* The full path name to the Emacs program. */ |
85 |
|
|
86 |
static char *emacs_program; |
static char *emacs_program; |
87 |
|
|
88 |
/* The client session id for this session as a lisp object. */ |
/* The client session id for this session as a lisp object. */ |
89 |
|
|
90 |
Lisp_Object Vx_session_id; |
Lisp_Object Vx_session_id; |
91 |
|
|
92 |
/* The id we had the previous session. This is only available if we |
/* The id we had the previous session. This is only available if we |
93 |
have been started by the session manager with SMID_OPT. */ |
have been started by the session manager with SMID_OPT. */ |
94 |
|
|
95 |
Lisp_Object Vx_session_previous_id; |
Lisp_Object Vx_session_previous_id; |
96 |
|
|
97 |
/* The option we tell the session manager to start Emacs with when |
/* The option we tell the session manager to start Emacs with when |
98 |
restarting Emacs. The client_id is appended. */ |
restarting Emacs. The client_id is appended. */ |
99 |
|
|
100 |
#define SMID_OPT "--smid=" |
#define SMID_OPT "--smid=" |
101 |
|
|
102 |
|
|
103 |
/* The option to start Emacs without the splash screen when |
/* The option to start Emacs without the splash screen when |
104 |
restarting Emacs. */ |
restarting Emacs. */ |
105 |
|
|
106 |
#define NOSPLASH_OPT "--no-splash" |
#define NOSPLASH_OPT "--no-splash" |
107 |
|
|
109 |
/* Handle any messages from the session manager. If no connection is |
/* Handle any messages from the session manager. If no connection is |
110 |
open to a session manager, just return 0. |
open to a session manager, just return 0. |
111 |
Otherwise returns 1 if SAVE_SESSION_EVENT is stored in buffer BUFP. */ |
Otherwise returns 1 if SAVE_SESSION_EVENT is stored in buffer BUFP. */ |
112 |
|
|
113 |
int |
int |
114 |
x_session_check_input (bufp) |
x_session_check_input (bufp) |
115 |
struct input_event *bufp; |
struct input_event *bufp; |
128 |
/* 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 |
129 |
IceProcessMessages. The smc_interact_CB sets the kind to |
IceProcessMessages. The smc_interact_CB sets the kind to |
130 |
SAVE_SESSION_EVENT, but we don't know beforehand if that callback |
SAVE_SESSION_EVENT, but we don't know beforehand if that callback |
131 |
will be called. */ |
will be called. */ |
132 |
emacs_event.kind = NO_EVENT; |
emacs_event.kind = NO_EVENT; |
133 |
|
|
134 |
if (select (ice_fd+1, &read_fds, |
if (select (ice_fd+1, &read_fds, |
145 |
|
|
146 |
|
|
147 |
/* Check if smc_interact_CB was called and we shall generate a |
/* Check if smc_interact_CB was called and we shall generate a |
148 |
SAVE_SESSION_EVENT. */ |
SAVE_SESSION_EVENT. */ |
149 |
if (emacs_event.kind == NO_EVENT) |
if (emacs_event.kind == NO_EVENT) |
150 |
return 0; |
return 0; |
151 |
|
|
153 |
return 1; |
return 1; |
154 |
} |
} |
155 |
|
|
156 |
/* Return non-zero if we have a connection to a session manager.*/ |
/* Return non-zero if we have a connection to a session manager. */ |
157 |
|
|
158 |
int |
int |
159 |
x_session_have_connection () |
x_session_have_connection () |
160 |
{ |
{ |
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_EVENT 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 |
|
|
168 |
static void |
static void |
169 |
smc_interact_CB (smcConn, clientData) |
smc_interact_CB (smcConn, clientData) |
170 |
SmcConn smcConn; |
SmcConn smcConn; |
180 |
are started in the correct directory. |
are started in the correct directory. |
181 |
|
|
182 |
If this is a shutdown and we can request to interact with the user, |
If this is a shutdown and we can request to interact with the user, |
183 |
we do so, because we don't know what the lisp code might do. */ |
we do so, because we don't know what the lisp code might do. */ |
184 |
|
|
185 |
static void |
static void |
186 |
smc_save_yourself_CB (smcConn, |
smc_save_yourself_CB (smcConn, |
187 |
clientData, |
clientData, |
208 |
char cwd[MAXPATHLEN+1]; |
char cwd[MAXPATHLEN+1]; |
209 |
char *smid_opt; |
char *smid_opt; |
210 |
|
|
211 |
/* How to start a new instance of Emacs */ |
/* How to start a new instance of Emacs. */ |
212 |
props[props_idx] = &prop_ptr[props_idx]; |
props[props_idx] = &prop_ptr[props_idx]; |
213 |
props[props_idx]->name = SmCloneCommand; |
props[props_idx]->name = SmCloneCommand; |
214 |
props[props_idx]->type = SmLISTofARRAY8; |
props[props_idx]->type = SmLISTofARRAY8; |
218 |
props[props_idx]->vals[0].value = emacs_program; |
props[props_idx]->vals[0].value = emacs_program; |
219 |
++props_idx; |
++props_idx; |
220 |
|
|
221 |
/* The name of the program */ |
/* The name of the program. */ |
222 |
props[props_idx] = &prop_ptr[props_idx]; |
props[props_idx] = &prop_ptr[props_idx]; |
223 |
props[props_idx]->name = SmProgram; |
props[props_idx]->name = SmProgram; |
224 |
props[props_idx]->type = SmARRAY8; |
props[props_idx]->type = SmARRAY8; |
228 |
props[props_idx]->vals[0].value = SDATA (Vinvocation_name); |
props[props_idx]->vals[0].value = SDATA (Vinvocation_name); |
229 |
++props_idx; |
++props_idx; |
230 |
|
|
231 |
/* How to restart Emacs (i.e.: /path/to/emacs --smid=xxxx --no-splash). */ |
/* How to restart Emacs (i.e.: /path/to/emacs --smid=xxxx --no-splash). */ |
232 |
props[props_idx] = &prop_ptr[props_idx]; |
props[props_idx] = &prop_ptr[props_idx]; |
233 |
props[props_idx]->name = SmRestartCommand; |
props[props_idx]->name = SmRestartCommand; |
234 |
props[props_idx]->type = SmLISTofARRAY8; |
props[props_idx]->type = SmLISTofARRAY8; |
235 |
props[props_idx]->num_vals = 3; /* /path/to/emacs, --smid=xxx --no-splash */ |
props[props_idx]->num_vals = 3; /* /path/to/emacs, --smid=xxx --no-splash */ |
236 |
props[props_idx]->vals = &values[val_idx]; |
props[props_idx]->vals = &values[val_idx]; |
237 |
props[props_idx]->vals[0].length = strlen (emacs_program); |
props[props_idx]->vals[0].length = strlen (emacs_program); |
238 |
props[props_idx]->vals[0].value = emacs_program; |
props[props_idx]->vals[0].value = emacs_program; |
249 |
val_idx += 3; |
val_idx += 3; |
250 |
++props_idx; |
++props_idx; |
251 |
|
|
252 |
/* User id */ |
/* User id. */ |
253 |
props[props_idx] = &prop_ptr[props_idx]; |
props[props_idx] = &prop_ptr[props_idx]; |
254 |
props[props_idx]->name = SmUserID; |
props[props_idx]->name = SmUserID; |
255 |
props[props_idx]->type = SmARRAY8; |
props[props_idx]->type = SmARRAY8; |
259 |
props[props_idx]->vals[0].value = SDATA (Vuser_login_name); |
props[props_idx]->vals[0].value = SDATA (Vuser_login_name); |
260 |
++props_idx; |
++props_idx; |
261 |
|
|
262 |
/* The current directory property, not mandatory */ |
/* The current directory property, not mandatory. */ |
263 |
#ifdef HAVE_GETCWD |
#ifdef HAVE_GETCWD |
264 |
if (getcwd (cwd, MAXPATHLEN+1) != 0) |
if (getcwd (cwd, MAXPATHLEN+1) != 0) |
265 |
#else |
#else |
281 |
|
|
282 |
xfree (smid_opt); |
xfree (smid_opt); |
283 |
|
|
284 |
/* See if we maybe shall interact with the user. */ |
/* See if we maybe shall interact with the user. */ |
285 |
if (interactStyle != SmInteractStyleAny |
if (interactStyle != SmInteractStyleAny |
286 |
|| ! shutdown |
|| ! shutdown |
287 |
|| saveType == SmSaveLocal |
|| saveType == SmSaveLocal |
288 |
|| ! SmcInteractRequest (smcConn, SmDialogNormal, smc_interact_CB, 0)) |
|| ! SmcInteractRequest (smcConn, SmDialogNormal, smc_interact_CB, 0)) |
289 |
{ |
{ |
290 |
/* No interaction, we are done saving ourself. */ |
/* No interaction, we are done saving ourself. */ |
291 |
SmcSaveYourselfDone (smcConn, True); |
SmcSaveYourselfDone (smcConn, True); |
292 |
} |
} |
293 |
} |
} |
294 |
|
|
295 |
/* According to the SM specification, this shall close the connection */ |
/* According to the SM specification, this shall close the connection. */ |
296 |
|
|
297 |
static void |
static void |
298 |
smc_die_CB (smcConn, clientData) |
smc_die_CB (smcConn, clientData) |
299 |
SmcConn smcConn; |
SmcConn smcConn; |
307 |
According to the SM specification, we should not interact with the |
According to the SM specification, we should not interact with the |
308 |
user between smc_save_yourself_CB is called and until smc_save_complete_CB |
user between smc_save_yourself_CB is called and until smc_save_complete_CB |
309 |
is called. It seems like a lot of job to implement this and it doesn't |
is called. It seems like a lot of job to implement this and it doesn't |
310 |
even seem necessary. */ |
even seem necessary. */ |
311 |
|
|
312 |
static void |
static void |
313 |
smc_save_complete_CB (smcConn, clientData) |
smc_save_complete_CB (smcConn, clientData) |
314 |
SmcConn smcConn; |
SmcConn smcConn; |
326 |
} |
} |
327 |
|
|
328 |
/* Error handlers for SM and ICE. We don't want to exit Emacs just |
/* Error handlers for SM and ICE. We don't want to exit Emacs just |
329 |
because there is some error in the session management. */ |
because there is some error in the session management. */ |
330 |
|
|
331 |
static void |
static void |
332 |
smc_error_handler (smcConn, |
smc_error_handler (smcConn, |
333 |
swap, |
swap, |
344 |
int severity; |
int severity; |
345 |
SmPointer values; |
SmPointer values; |
346 |
{ |
{ |
347 |
/* Empty */ |
/* Empty */ |
348 |
} |
} |
349 |
|
|
350 |
static void |
static void |
363 |
int severity; |
int severity; |
364 |
IcePointer values; |
IcePointer values; |
365 |
{ |
{ |
366 |
/* Empty */ |
/* Empty */ |
367 |
} |
} |
368 |
|
|
369 |
|
|
371 |
ice_io_error_handler (iceConn) |
ice_io_error_handler (iceConn) |
372 |
IceConn iceConn; |
IceConn iceConn; |
373 |
{ |
{ |
374 |
/* Connection probably gone. */ |
/* Connection probably gone. */ |
375 |
ice_fd = -1; |
ice_fd = -1; |
376 |
} |
} |
377 |
|
|
378 |
/* This is called when the ICE connection is created or closed. The SM library |
/* This is called when the ICE connection is created or closed. The SM library |
379 |
uses ICE as it transport protocol. */ |
uses ICE as it transport protocol. */ |
380 |
|
|
381 |
static void |
static void |
382 |
ice_conn_watch_CB (iceConn, clientData, opening, watchData) |
ice_conn_watch_CB (iceConn, clientData, opening, watchData) |
383 |
IceConn iceConn; |
IceConn iceConn; |
410 |
} |
} |
411 |
|
|
412 |
/* Create the client leader window. */ |
/* Create the client leader window. */ |
413 |
|
|
414 |
static void |
static void |
415 |
create_client_leader_window (dpyinfo, client_id) |
create_client_leader_window (dpyinfo, client_id) |
416 |
struct x_display_info *dpyinfo; |
struct x_display_info *dpyinfo; |
437 |
dpyinfo->client_leader_window = w; |
dpyinfo->client_leader_window = w; |
438 |
} |
} |
439 |
|
|
440 |
/* Try to open a connection to the session manager. */ |
/* Try to open a connection to the session manager. */ |
441 |
|
|
442 |
void |
void |
443 |
x_session_initialize (dpyinfo) |
x_session_initialize (dpyinfo) |
444 |
struct x_display_info *dpyinfo; |
struct x_display_info *dpyinfo; |
450 |
int name_len = 0; |
int name_len = 0; |
451 |
|
|
452 |
/* 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 |
453 |
have a previous id. */ |
have a previous id. */ |
454 |
if (! EQ (Vx_session_previous_id, Qnil) && STRINGP (Vx_session_previous_id)) |
if (! EQ (Vx_session_previous_id, Qnil) && STRINGP (Vx_session_previous_id)) |
455 |
previous_id = SDATA (Vx_session_previous_id); |
previous_id = SDATA (Vx_session_previous_id); |
456 |
|
|
457 |
/* Construct the path to the Emacs program. */ |
/* Construct the path to the Emacs program. */ |
458 |
if (! EQ (Vinvocation_directory, Qnil)) |
if (! EQ (Vinvocation_directory, Qnil)) |
459 |
name_len += strlen (SDATA (Vinvocation_directory)); |
name_len += strlen (SDATA (Vinvocation_directory)); |
460 |
name_len += strlen (SDATA (Vinvocation_name)); |
name_len += strlen (SDATA (Vinvocation_name)); |
461 |
|
|
462 |
/* 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 |
463 |
not very large */ |
not very large */ |
464 |
emacs_program = xmalloc (name_len + 1); |
emacs_program = xmalloc (name_len + 1); |
465 |
emacs_program[0] = '\0'; |
emacs_program[0] = '\0'; |
466 |
|
|
469 |
strcat (emacs_program, SDATA (Vinvocation_name)); |
strcat (emacs_program, SDATA (Vinvocation_name)); |
470 |
|
|
471 |
/* The SM protocol says all callbacks are mandatory, so set up all |
/* The SM protocol says all callbacks are mandatory, so set up all |
472 |
here and in the mask passed to SmcOpenConnection */ |
here and in the mask passed to SmcOpenConnection. */ |
473 |
callbacks.save_yourself.callback = smc_save_yourself_CB; |
callbacks.save_yourself.callback = smc_save_yourself_CB; |
474 |
callbacks.save_yourself.client_data = 0; |
callbacks.save_yourself.client_data = 0; |
475 |
callbacks.die.callback = smc_die_CB; |
callbacks.die.callback = smc_die_CB; |
479 |
callbacks.shutdown_cancelled.callback = smc_shutdown_cancelled_CB; |
callbacks.shutdown_cancelled.callback = smc_shutdown_cancelled_CB; |
480 |
callbacks.shutdown_cancelled.client_data = 0; |
callbacks.shutdown_cancelled.client_data = 0; |
481 |
|
|
482 |
/* Set error handlers. */ |
/* Set error handlers. */ |
483 |
SmcSetErrorHandler (smc_error_handler); |
SmcSetErrorHandler (smc_error_handler); |
484 |
IceSetErrorHandler (ice_error_handler); |
IceSetErrorHandler (ice_error_handler); |
485 |
IceSetIOErrorHandler (ice_io_error_handler); |
IceSetIOErrorHandler (ice_io_error_handler); |
486 |
|
|
487 |
/* Install callback for when connection status changes. */ |
/* Install callback for when connection status changes. */ |
488 |
IceAddConnectionWatch (ice_conn_watch_CB, 0); |
IceAddConnectionWatch (ice_conn_watch_CB, 0); |
489 |
|
|
490 |
/* Open the connection to the session manager. A failure is not |
/* Open the connection to the session manager. A failure is not |
491 |
critical, it usually means that no session manager is running. |
critical, it usually means that no session manager is running. |
492 |
The errorstring is here for debugging. */ |
The errorstring is here for debugging. */ |
493 |
smc_conn = SmcOpenConnection (NULL, NULL, 1, 0, |
smc_conn = SmcOpenConnection (NULL, NULL, 1, 0, |
494 |
(SmcSaveYourselfProcMask| |
(SmcSaveYourselfProcMask| |
495 |
SmcDieProcMask| |
SmcDieProcMask| |