This source file includes following definitions.
- ice_connection_closed
- x_session_check_input
- x_session_have_connection
- smc_interact_CB
- smc_save_yourself_CB
- smc_die_CB
- smc_save_complete_CB
- smc_shutdown_cancelled_CB
- smc_error_handler
- ice_error_handler
- ice_io_error_handler
- ice_conn_watch_CB
- create_client_leader_window
- x_session_initialize
- x_session_close
- DEFUN
- syms_of_xsmfns
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 #include <config.h>
22
23 #ifdef HAVE_X_SM
24
25 #include <X11/SM/SMlib.h>
26 #include <X11/Xlib.h>
27 #include <X11/Xutil.h>
28
29 #include <unistd.h>
30 #include <sys/param.h>
31 #include <errno.h>
32 #include <stdio.h>
33
34 #include "lisp.h"
35 #include "frame.h"
36 #include "termhooks.h"
37 #include "xterm.h"
38 #include "process.h"
39 #include "keyboard.h"
40
41 #if defined USE_GTK && !defined HAVE_GTK3
42 #define gdk_x11_set_sm_client_id(w) gdk_set_sm_client_id (w)
43 #endif
44
45
46
47 static struct input_event emacs_event;
48
49
50
51 static int ice_fd = -1;
52
53
54
55 static bool doing_interact;
56
57
58
59 static SmcConn smc_conn;
60
61
62
63 static char *client_id;
64
65
66
67 static char *emacs_program;
68
69
70
71
72 #define SMID_OPT "--smid="
73
74
75
76
77
78 static char NOSPLASH_OPT[] = "--no-splash";
79
80
81
82 #define CHDIR_OPT "--chdir="
83
84 static void
85 ice_connection_closed (void)
86 {
87 if (ice_fd >= 0)
88 delete_read_fd (ice_fd);
89 ice_fd = -1;
90 }
91
92
93
94
95
96 static void
97 x_session_check_input (int fd, void *data)
98 {
99 int ret;
100
101 if (ice_fd == -1) return;
102
103
104
105
106
107 emacs_event.kind = NO_EVENT;
108
109 ret = IceProcessMessages (SmcGetIceConnection (smc_conn), 0, 0);
110 if (ret != IceProcessMessagesSuccess)
111 {
112
113 if (ret == IceProcessMessagesIOError)
114 IceCloseConnection (SmcGetIceConnection (smc_conn));
115
116 ice_connection_closed ();
117 }
118
119
120
121 if (emacs_event.kind != NO_EVENT)
122 kbd_buffer_store_event (&emacs_event);
123 }
124
125
126
127 bool
128 x_session_have_connection (void)
129 {
130 return ice_fd != -1;
131 }
132
133
134
135
136
137 static void
138 smc_interact_CB (SmcConn smcConn, SmPointer clientData)
139 {
140 doing_interact = true;
141 emacs_event.kind = SAVE_SESSION_EVENT;
142 emacs_event.arg = Qnil;
143 }
144
145
146
147
148
149
150
151
152
153 static void
154 smc_save_yourself_CB (SmcConn smcConn,
155 SmPointer clientData,
156 int saveType,
157 Bool shutdown,
158 int interactStyle,
159 Bool fast)
160 {
161 #define NR_PROPS 5
162
163 SmProp *props[NR_PROPS];
164 SmProp prop_ptr[NR_PROPS];
165
166 SmPropValue values[20], *vp;
167 int val_idx = 0, vp_idx = 0;
168 int props_idx = 0;
169 int i;
170 char *smid_opt, *chdir_opt = NULL;
171 Lisp_Object user_login_name = Fuser_login_name (Qnil);
172
173
174 if (! STRINGP (Vinvocation_name) || ! STRINGP (user_login_name))
175 return;
176
177
178 props[props_idx] = &prop_ptr[props_idx];
179 props[props_idx]->name = xstrdup (SmCloneCommand);
180 props[props_idx]->type = xstrdup (SmLISTofARRAY8);
181 props[props_idx]->num_vals = 1;
182 props[props_idx]->vals = &values[val_idx++];
183 props[props_idx]->vals[0].length = strlen (emacs_program);
184 props[props_idx]->vals[0].value = emacs_program;
185 ++props_idx;
186
187
188 props[props_idx] = &prop_ptr[props_idx];
189 props[props_idx]->name = xstrdup (SmProgram);
190 props[props_idx]->type = xstrdup (SmARRAY8);
191 props[props_idx]->num_vals = 1;
192 props[props_idx]->vals = &values[val_idx++];
193 props[props_idx]->vals[0].length = SBYTES (Vinvocation_name);
194 props[props_idx]->vals[0].value = SDATA (Vinvocation_name);
195 ++props_idx;
196
197
198 props[props_idx] = &prop_ptr[props_idx];
199 props[props_idx]->name = xstrdup (SmUserID);
200 props[props_idx]->type = xstrdup (SmARRAY8);
201 props[props_idx]->num_vals = 1;
202 props[props_idx]->vals = &values[val_idx++];
203 props[props_idx]->vals[0].length = SBYTES (user_login_name);
204 props[props_idx]->vals[0].value = SDATA (user_login_name);
205 ++props_idx;
206
207 char *cwd = emacs_get_current_dir_name ();
208 if (cwd)
209 {
210 props[props_idx] = &prop_ptr[props_idx];
211 props[props_idx]->name = xstrdup (SmCurrentDirectory);
212 props[props_idx]->type = xstrdup (SmARRAY8);
213 props[props_idx]->num_vals = 1;
214 props[props_idx]->vals = &values[val_idx++];
215 props[props_idx]->vals[0].length = strlen (cwd);
216 props[props_idx]->vals[0].value = cwd;
217 ++props_idx;
218 }
219
220
221
222 props[props_idx] = &prop_ptr[props_idx];
223 props[props_idx]->name = xstrdup (SmRestartCommand);
224 props[props_idx]->type = xstrdup (SmLISTofARRAY8);
225
226 if (ckd_add (&i, initial_argc, 3))
227 memory_full (SIZE_MAX);
228 props[props_idx]->num_vals = i;
229 vp = xnmalloc (i, sizeof *vp);
230 props[props_idx]->vals = vp;
231 props[props_idx]->vals[vp_idx].length = strlen (emacs_program);
232 props[props_idx]->vals[vp_idx++].value = emacs_program;
233
234 smid_opt = xmalloc (strlen (SMID_OPT) + strlen (client_id) + 1);
235 strcpy (stpcpy (smid_opt, SMID_OPT), client_id);
236
237 props[props_idx]->vals[vp_idx].length = strlen (smid_opt);
238 props[props_idx]->vals[vp_idx++].value = smid_opt;
239
240 props[props_idx]->vals[vp_idx].length = strlen (NOSPLASH_OPT);
241 props[props_idx]->vals[vp_idx++].value = NOSPLASH_OPT;
242
243 if (cwd)
244 {
245 chdir_opt = xmalloc (strlen (CHDIR_OPT) + strlen (cwd) + 1);
246 strcpy (stpcpy (chdir_opt, CHDIR_OPT), cwd);
247
248 props[props_idx]->vals[vp_idx].length = strlen (chdir_opt);
249 props[props_idx]->vals[vp_idx++].value = chdir_opt;
250 }
251
252 for (i = 1; i < initial_argc; ++i)
253 {
254 props[props_idx]->vals[vp_idx].length = strlen (initial_argv[i]);
255 props[props_idx]->vals[vp_idx++].value = initial_argv[i];
256 }
257
258 ++props_idx;
259
260 SmcSetProperties (smcConn, props_idx, props);
261
262 xfree (smid_opt);
263 xfree (chdir_opt);
264 xfree (cwd);
265 xfree (vp);
266
267 for (i = 0; i < props_idx; ++i)
268 {
269 xfree (props[i]->type);
270 xfree (props[i]->name);
271 }
272
273
274 if (interactStyle != SmInteractStyleAny
275 || ! shutdown
276 || saveType == SmSaveLocal
277 || ! SmcInteractRequest (smcConn, SmDialogNormal, smc_interact_CB, 0))
278 {
279
280 SmcSaveYourselfDone (smcConn, True);
281 }
282 }
283
284
285
286 static void
287 smc_die_CB (SmcConn smcConn, SmPointer clientData)
288 {
289 emacs_event.kind = SAVE_SESSION_EVENT;
290 emacs_event.arg = Qt;
291 }
292
293
294
295
296
297
298
299 static void
300 smc_save_complete_CB (SmcConn smcConn, SmPointer clientData)
301 {
302
303 }
304
305 static void
306 smc_shutdown_cancelled_CB (SmcConn smcConn, SmPointer clientData)
307 {
308
309 }
310
311
312
313
314 static void
315 smc_error_handler (SmcConn smcConn,
316 Bool swap,
317 int offendingMinorOpcode,
318 unsigned long offendingSequence,
319 int errorClass,
320 int severity,
321 SmPointer values)
322 {
323
324 }
325
326 static void
327 ice_error_handler (IceConn iceConn,
328 Bool swap,
329 int offendingMinorOpcode,
330 unsigned long offendingSequence,
331 int errorClass,
332 int severity,
333 IcePointer values)
334 {
335
336 }
337
338
339 static void
340 ice_io_error_handler (IceConn iceConn)
341 {
342
343 ice_connection_closed ();
344 }
345
346
347
348
349 static void
350 ice_conn_watch_CB (IceConn iceConn, IcePointer clientData,
351 int opening, IcePointer *watchData)
352 {
353 if (! opening)
354 {
355 ice_connection_closed ();
356 return;
357 }
358
359 ice_fd = IceConnectionNumber (iceConn);
360 add_non_keyboard_read_fd (ice_fd, x_session_check_input, NULL);
361 }
362
363
364
365 #ifndef USE_GTK
366 static void
367 create_client_leader_window (struct x_display_info *dpyinfo, char *client_ID)
368 {
369 Window w;
370 XClassHint class_hints;
371
372 w = XCreateSimpleWindow (dpyinfo->display,
373 dpyinfo->root_window,
374 -1, -1, 1, 1,
375 CopyFromParent, CopyFromParent, CopyFromParent);
376
377 validate_x_resource_name ();
378 class_hints.res_name = SSDATA (Vx_resource_name);
379 class_hints.res_class = SSDATA (Vx_resource_class);
380 XSetClassHint (dpyinfo->display, w, &class_hints);
381 XStoreName (dpyinfo->display, w, class_hints.res_name);
382
383 XChangeProperty (dpyinfo->display, w, dpyinfo->Xatom_SM_CLIENT_ID,
384 XA_STRING, 8, PropModeReplace,
385 (unsigned char *) client_ID, strlen (client_ID));
386
387 dpyinfo->client_leader_window = w;
388 }
389 #endif
390
391
392
393
394 void
395 x_session_initialize (struct x_display_info *dpyinfo)
396 {
397 #define SM_ERRORSTRING_LEN 512
398 char errorstring[SM_ERRORSTRING_LEN];
399 char *previous_id = NULL;
400 SmcCallbacks callbacks;
401 ptrdiff_t name_len = 0;
402
403
404 char *pwd = emacs_get_current_dir_name ();
405 if (!pwd)
406 {
407 fprintf (stderr, "Disabling session management due to pwd error: %s\n",
408 emacs_strerror (errno));
409 return;
410 }
411 xfree (pwd);
412
413 ice_fd = -1;
414 doing_interact = false;
415
416
417
418 if (STRINGP (Vx_session_previous_id))
419 previous_id = SSDATA (Vx_session_previous_id);
420
421
422 if (STRINGP (Vinvocation_directory))
423 name_len += SBYTES (Vinvocation_directory);
424 if (STRINGP (Vinvocation_name))
425 name_len += SBYTES (Vinvocation_name);
426
427
428
429 emacs_program = xmalloc (name_len + 1);
430 char *z = emacs_program;
431
432 if (STRINGP (Vinvocation_directory))
433 z = lispstpcpy (z, Vinvocation_directory);
434 if (STRINGP (Vinvocation_name))
435 lispstpcpy (z, Vinvocation_name);
436
437
438
439 callbacks.save_yourself.callback = smc_save_yourself_CB;
440 callbacks.save_yourself.client_data = 0;
441 callbacks.die.callback = smc_die_CB;
442 callbacks.die.client_data = 0;
443 callbacks.save_complete.callback = smc_save_complete_CB;
444 callbacks.save_complete.client_data = 0;
445 callbacks.shutdown_cancelled.callback = smc_shutdown_cancelled_CB;
446 callbacks.shutdown_cancelled.client_data = 0;
447
448
449 SmcSetErrorHandler (smc_error_handler);
450 IceSetErrorHandler (ice_error_handler);
451 IceSetIOErrorHandler (ice_io_error_handler);
452
453
454 IceAddConnectionWatch (ice_conn_watch_CB, 0);
455
456
457
458
459 smc_conn = SmcOpenConnection (NULL, NULL, 1, 0,
460 (SmcSaveYourselfProcMask|
461 SmcDieProcMask|
462 SmcSaveCompleteProcMask|
463 SmcShutdownCancelledProcMask),
464 &callbacks,
465 previous_id,
466 &client_id,
467 SM_ERRORSTRING_LEN,
468 errorstring);
469
470 if (smc_conn != 0)
471 {
472 Vx_session_id = build_string (client_id);
473
474 #ifdef USE_GTK
475
476
477 gdk_x11_set_sm_client_id (client_id);
478 #else
479 create_client_leader_window (dpyinfo, client_id);
480 #endif
481 }
482 }
483
484
485
486 void
487 x_session_close (void)
488 {
489 ice_connection_closed ();
490 }
491
492
493 DEFUN ("handle-save-session", Fhandle_save_session,
494 Shandle_save_session, 1, 1, "e",
495 doc:
496
497
498
499
500
501
502
503
504 )
505 (Lisp_Object event)
506 {
507 bool kill_emacs = (CONSP (event) && CONSP (XCDR (event))
508 && EQ (Qt, XCAR (XCDR (event))));
509
510
511
512 if (doing_interact && ! kill_emacs)
513 {
514 bool cancel_shutdown = ! NILP (call0 (Qemacs_session_save));
515
516 SmcInteractDone (smc_conn, cancel_shutdown);
517 SmcSaveYourselfDone (smc_conn, True);
518
519 doing_interact = false;
520 }
521 else if (kill_emacs)
522 {
523
524
525 Fkill_emacs (Qnil, Qnil);
526
527 #if false
528
529 SmcCloseConnection (smc_conn, 0, 0);
530 ice_connection_closed ();
531 #endif
532 }
533
534 return Qnil;
535 }
536
537
538
539
540
541
542 void
543 syms_of_xsmfns (void)
544 {
545 DEFSYM (Qemacs_session_save, "emacs-session-save");
546
547 DEFVAR_LISP ("x-session-id", Vx_session_id,
548 doc:
549
550
551
552 );
553 Vx_session_id = Qnil;
554
555 DEFVAR_LISP ("x-session-previous-id", Vx_session_previous_id,
556 doc:
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575 );
576 Vx_session_previous_id = Qnil;
577
578 defsubr (&Shandle_save_session);
579 }
580
581 #endif