* Session management patch, please comment. @ 2002-02-17 19:11 Jan D. 2002-02-19 6:37 ` Richard Stallman 0 siblings, 1 reply; 23+ messages in thread From: Jan D. @ 2002-02-17 19:11 UTC (permalink / raw) Hello. I finally got some time to make this presentable. This patch doesn't actually save or restore any session, it is just the mechanism to enable Emacs to do that in lisp that is in this patch. The idea is that lisp code that saves and restores session uses the two hooks save-yourself-hook to save state and restart-yourself-hook to restore or possible discard state. To be able to get control to lisp and call hooks in save-yourself-hook, I added a new event, save_yourself_event. I could not find another way to do that. I initialize session management calls in x_initialize so it only gets done once, and check for session management events in XTread_socket. Some lisp code for session management is in term/x-win.el, there might be a better place for that code? ChangeLogs and documentation not done yet, util I know that this is an okay way to do things. Jan D. Index: emacs/src/xterm.c *** emacs/src/xterm.c.orig Sun Feb 17 00:55:57 2002 --- emacs/src/xterm.c Sun Feb 17 20:03:35 2002 *************** *** 10030,10035 **** --- 10030,10041 ---- x_io_error_quitter (dpyinfo->display); } + #ifdef HAVE_X_SM + BLOCK_INPUT; + count += x_sm_check_input (bufp, &numchars); + UNBLOCK_INPUT; + #endif + while (XPending (dpyinfo->display)) { XNextEvent (dpyinfo->display, &event); *************** *** 10112,10122 **** the session manager, who's looking for such a PropertyNotify. Can restart processing when a keyboard or mouse event arrives. */ ! if (numchars > 0) { f = x_top_window_to_frame (dpyinfo, event.xclient.window); - /* This is just so we only give real data once for a single Emacs process. */ if (f == SELECTED_FRAME ()) --- 10118,10134 ---- the session manager, who's looking for such a PropertyNotify. Can restart processing when a keyboard or mouse event arrives. */ ! /* If we have a session manager, don't set this. ! KDE will then start two Emacsen, one for the ! session manager and one for this. */ ! if (numchars > 0 ! #ifdef HAVE_X_SM ! && ! x_sm_have_connection () ! #endif ! ) { f = x_top_window_to_frame (dpyinfo, event.xclient.window); /* This is just so we only give real data once for a single Emacs process. */ if (f == SELECTED_FRAME ()) *************** *** 15044,15049 **** --- 15056,15065 ---- #endif /* ! defined (SIGWINCH) */ signal (SIGPIPE, x_connection_signal); + + #ifdef HAVE_X_SM + x_sm_initialize (); + #endif } Index: emacs/src/xterm.h *** emacs/src/xterm.h.orig Sun Feb 17 00:54:42 2002 --- emacs/src/xterm.h Sun Feb 17 20:03:33 2002 *************** *** 1098,1100 **** --- 1098,1107 ---- #ifdef USE_X_TOOLKIT extern void widget_store_internal_border P_ ((Widget)); #endif + + /* Defined in xsmfns.c */ + #ifdef JAVE_X_SM + extern void x_sm_initialize P_ ((void)); + extern int x_sm_check_input P_ ((struct input_event *bufp, int *numchars)); + extern int x_sm_have_connection P_ ((void)); + #endif Index: emacs/src/xsmfns.c *** emacs/src/xsmfns.c.orig Sun Feb 17 01:58:43 2002 --- emacs/src/xsmfns.c Sun Feb 17 20:04:58 2002 *************** *** 0 **** --- 1,513 ---- + /* Session management module for systems which understand the X Session + management protocol. + Copyright (C) 2002 Free Software Foundation, Inc. + + This file is part of GNU Emacs. + + GNU Emacs is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Emacs is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Emacs; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + + #include <config.h> + + #ifdef HAVE_X_SM + + #include <X11/SM/SMlib.h> + #ifdef HAVE_STRING_H + #include <string.h> + #else + #ifdef HAVE_STRINGS_H + #include <strings.h> + #endif + #endif + + #include <sys/types.h> + + #ifdef HAVE_UNISTD_H + #include <unistd.h> + #endif + #ifdef HAVE_STDLIB_H + #include <stdlib.h> + #endif + + #include "systime.h" + #include "sysselect.h" + #include "lisp.h" + #include "termhooks.h" + + + /* This is the event used when save_yourself occurs */ + + static struct input_event emacs_event; + + /* Initial values of argv. */ + + extern char **initial_argv; + + /* The descriptor that we use to check for data from the session manager. */ + + static int ice_fd = -1; + + /* The session manager object for the session manager connection */ + + static SmcConn smc_conn; + + /* The client session id for this session */ + static char *client_id; + + /* The client session id for this session as a lisp object. */ + + Lisp_Object Vx_sm_id; + + /* The id we had the previous session. This is only available if we + have been started by the session manager with SMID_OPT. */ + + Lisp_Object Vx_sm_previous_id; + + /* When the event save_yourself have been processed by the lisp code, + and this is non-nil, we tell the session manager to cancel the shutdown. + This is the way for lisp code to inform us to cancel the shutdown. */ + + Lisp_Object Vx_sm_cancel_shutdown; + + /* The option we tell the session manager to start Emacs with when + restarting Emacs. The client_id is appended. */ + + #define SMID_OPT "--smid=" + + + + /* Handle any messages from the session manager. If no connection is + open to a session manager, just return 0. + Otherwise returns the number of events stored in buffer BUFP, + which can hold up to *NUMCHARS characters. At most one event is + stored, an save_yourself_event. */ + int + x_sm_check_input (bufp, numchars) + struct input_event *bufp; + int *numchars; + { + SELECT_TYPE read_fds; + EMACS_TIME tmout; + + if (ice_fd == -1) return 0; + + FD_ZERO (&read_fds); + FD_SET (ice_fd, &read_fds); + + tmout.tv_sec = 0; + tmout.tv_usec = 0; + + /* Reset this so wo can check kind after callbacks have been called by + IceProcessMessages. The smc_interact_CB sets the kind to + save_yourself_event, but we don't know beforehand if that callback + will be called. */ + emacs_event.kind = no_event; + + if (select (ice_fd+1, &read_fds, + (SELECT_TYPE *)0, (SELECT_TYPE *)0, &tmout) < 0) + { + ice_fd = -1; + return 0; + } + + + if (FD_ISSET (ice_fd, &read_fds)) + IceProcessMessages (SmcGetIceConnection (smc_conn), + (IceReplyWaitInfo *)0, (Bool *)0); + + + /* Check if smc_interact_CB was called and we shall generate a + save_yourself event. */ + if (*numchars > 0 && emacs_event.kind != no_event) + { + bcopy (&emacs_event, bufp, sizeof (struct input_event)); + bufp++; + (*numchars)--; + + return 1; + } + + return 0; + } + + /* Return non-zero if we have a connection to a session manager.*/ + int + x_sm_have_connection () + { + return ice_fd != -1; + } + + /* This is called when the session manager says it is OK to interact with the + user. Here we set the kind to save_yourself so an event is generated. + Then lisp code can interact with the user. */ + static void + smc_interact_CB (smcConn, clientData) + SmcConn smcConn; + SmPointer clientData; + { + emacs_event.kind = save_yourself_event; + } + + /* This is called when the session manager tells us to save ourself. + We set the required properties so the session manager can restart us, + plus the current working directory property (not mandatory) so we + are started in the correct directory. + + If this is a shutdown and we can request to interact with the user, + we do so, because we don't know what the lisp code might do. */ + static void + smc_save_yourself_CB (smcConn, + clientData, + saveType, + shutdown, + interactStyle, + fast) + SmcConn smcConn; + SmPointer clientData; + int saveType; + Bool shutdown; + int interactStyle; + Bool fast; + { + #define NR_PROPS 5 + + SmProp *props[NR_PROPS]; + SmProp prop_ptr[NR_PROPS]; + + SmPropValue values[20]; + int val_idx = 0; + int props_idx = 0; + int has_cwd; + + #ifndef MAXPATHLEN + #define MAXPATHLEN 1024 + #endif /* not MAXPATHLEN */ + + char cwd[MAXPATHLEN+1]; + char user_id[16]; + + char *program; + char *smid_opt; + + #ifdef HAVE_GETCWD + has_cwd = getcwd (cwd, MAXPATHLEN+1) != 0; + #else + has_cwd = getwd (cwd) != 0; + #endif + + if (initial_argv[0][0] != '/' && has_cwd) + { + /* If the program name doesn't start with a / prepend the current + directory in the hope that it is a relative path starting + from here. Maybe a PATH search should be done? */ + program = xmalloc (strlen (cwd)+strlen (initial_argv[0])+2); + strcpy (program, cwd); + strcat (program, "/"); + strcat (program, initial_argv[0]); + } + else + program = xstrdup (initial_argv[0]); + + /* How to start a new instance of Emacs */ + props[props_idx] = &prop_ptr[props_idx]; + props[props_idx]->name = SmCloneCommand; + props[props_idx]->type = SmLISTofARRAY8; + props[props_idx]->num_vals = 1; + props[props_idx]->vals = &values[val_idx++]; + props[props_idx]->vals[0].length = strlen (program); + props[props_idx]->vals[0].value = program; + ++props_idx; + + /* The name of the program */ + props[props_idx] = &prop_ptr[props_idx]; + props[props_idx]->name = SmProgram; + props[props_idx]->type = SmARRAY8; + props[props_idx]->num_vals = 1; + props[props_idx]->vals = &values[val_idx++]; + props[props_idx]->vals[0].length = strlen (initial_argv[0]); + props[props_idx]->vals[0].value = initial_argv[0]; + ++props_idx; + + /* How to restart Emacs (i.e.: /path/to/emacs --smid=xxxx). */ + props[props_idx] = &prop_ptr[props_idx]; + props[props_idx]->name = SmRestartCommand; + props[props_idx]->type = SmLISTofARRAY8; + props[props_idx]->num_vals = 2; /* 2 values: /path/to/emacs, --smid=xxx */ + props[props_idx]->vals = &values[val_idx]; + props[props_idx]->vals[0].length = strlen (program); + props[props_idx]->vals[0].value = program; + + smid_opt = xmalloc (strlen (SMID_OPT) + strlen (client_id) + 1); + strcpy(smid_opt, SMID_OPT); + strcat(smid_opt, client_id); + + props[props_idx]->vals[1].length = strlen (smid_opt); + props[props_idx]->vals[1].value = smid_opt; + val_idx += 2; + ++props_idx; + + /* User id */ + sprintf(user_id, "%d", getpid()); + props[props_idx] = &prop_ptr[props_idx]; + props[props_idx]->name = SmUserID; + props[props_idx]->type = SmARRAY8; + props[props_idx]->num_vals = 1; + props[props_idx]->vals = &values[val_idx++]; + props[props_idx]->vals[0].length = strlen (user_id); + props[props_idx]->vals[0].value = user_id; + ++props_idx; + + /* The current directory property, not mandatory */ + if (has_cwd) + { + props[props_idx] = &prop_ptr[props_idx]; + props[props_idx]->name = SmCurrentDirectory; + props[props_idx]->type = SmARRAY8; + props[props_idx]->num_vals = 1; + props[props_idx]->vals = &values[val_idx++]; + props[props_idx]->vals[0].length = strlen (cwd); + props[props_idx]->vals[0].value = cwd; + ++props_idx; + } + + + SmcSetProperties (smcConn, NR_PROPS, props); + + xfree (program); + xfree (smid_opt); + + /* See if we maybe shall interact with the user. */ + if (interactStyle != SmInteractStyleAny + || ! shutdown + || saveType == SmSaveLocal + || ! SmcInteractRequest(smcConn, SmDialogNormal, smc_interact_CB, 0)) + { + /* No interaction, we are done saving ourself. */ + SmcSaveYourselfDone (smcConn, True); + } + } + + /* According to the SM specification, this shall close the connection */ + static void + smc_die_CB (smcConn, clientData) + SmcConn smcConn; + SmPointer clientData; + { + SmcCloseConnection (smcConn, 0, 0); + ice_fd = -1; + } + + /* We don't use the next two but they are mandatory, leave them empty. + According to the SM specification, we should not interact with the + user between smc_save_yourself_CB is called and until smc_save_complete_CB + is called. It seems like a lot of job to implement this and it doesn't + even seem necessary. */ + static void + smc_save_complete_CB (smcConn, clientData) + SmcConn smcConn; + SmPointer clientData; + { + } + + static void + smc_shutdown_cancelled_CB (smcConn, clientData) + SmcConn smcConn; + SmPointer clientData; + { + } + + /* Error handlers for SM and ICE. We don't wan't to exit Emacs just + because there is some error in the session management. */ + static void + smc_error_handler (smcConn, + swap, + offendingMinorOpcode, + offendingSequence, + errorClass, + severity, + values) + SmcConn smcConn; + Bool swap; + int offendingMinorOpcode; + unsigned long offendingSequence; + int errorClass; + int severity; + SmPointer values; + { + /* Empty */ + } + + static void + ice_error_handler (iceConn, + swap, + offendingMinorOpcode, + offendingSequence, + errorClass, + severity, + values) + IceConn iceConn; + Bool swap; + int offendingMinorOpcode; + unsigned long offendingSequence; + int errorClass; + int severity; + IcePointer values; + { + /* Empty */ + } + + + static void + ice_io_error_handler (iceConn) + IceConn iceConn; + { + /* Connection probably gone. */ + ice_fd = -1; + } + + /* This is called when the ICE connection is created or closed. The SM library + uses ICE as it transport protocol. */ + static void + ice_conn_watch_CB (iceConn, clientData, opening, watchData) + IceConn iceConn; + IcePointer clientData; + Bool opening; + IcePointer *watchData; + { + if (! opening) + { + ice_fd = -1; + return; + } + + ice_fd = IceConnectionNumber (iceConn); + #ifndef F_SETOWN_BUG + #ifdef F_SETOWN + #ifdef F_SETOWN_SOCK_NEG + /* stdin is a socket here */ + fcntl (ice_fd, F_SETOWN, -getpid ()); + #else /* ! defined (F_SETOWN_SOCK_NEG) */ + fcntl (ice_fd, F_SETOWN, getpid ()); + #endif /* ! defined (F_SETOWN_SOCK_NEG) */ + #endif /* ! defined (F_SETOWN) */ + #endif /* F_SETOWN_BUG */ + + #ifdef SIGIO + if (interrupt_input) + init_sigio (ice_fd); + #endif /* ! defined (SIGIO) */ + } + + /* Try to open a connection to the session manager. */ + void + x_sm_initialize () + { + #define SM_ERRORSTRING_LEN 512 + char errorstring[SM_ERRORSTRING_LEN]; + char* previous_id = NULL; + SmcCallbacks callbacks; + + /* Check if we where started by the session manager. If so, we will + have a previous id. */ + if (! EQ (Vx_sm_previous_id, Qnil) && STRINGP (Vx_sm_previous_id)) + previous_id = XSTRING (Vx_sm_previous_id)->data; + + /* The SM protocol says all callbacks are mandatory, so set up all + here and in the mask passed to SmcOpenConnection */ + callbacks.save_yourself.callback = smc_save_yourself_CB; + callbacks.save_yourself.client_data = 0; + callbacks.die.callback = smc_die_CB; + callbacks.die.client_data = 0; + callbacks.save_complete.callback = smc_save_complete_CB; + callbacks.save_complete.client_data = 0; + callbacks.shutdown_cancelled.callback = smc_shutdown_cancelled_CB; + callbacks.shutdown_cancelled.client_data = 0; + + /* Set error handlers. */ + SmcSetErrorHandler (smc_error_handler); + IceSetErrorHandler (ice_error_handler); + IceSetIOErrorHandler (ice_io_error_handler); + + /* Install callback for when connection status changes. */ + IceAddConnectionWatch (ice_conn_watch_CB, 0); + + /* Open the connection to the session manager. A failure is not + critical, it usualy means that no session manager is running. + The errorstring is here for debugging. */ + smc_conn = SmcOpenConnection (NULL, NULL, 1, 0, + (SmcSaveYourselfProcMask| + SmcDieProcMask| + SmcSaveCompleteProcMask| + SmcShutdownCancelledProcMask), + &callbacks, + previous_id, + &client_id, + SM_ERRORSTRING_LEN, + errorstring); + + if (smc_conn != 0) + Vx_sm_id = make_string (client_id, strlen (client_id)); + } + + + DEFUN ("x-sm-interact-done", Fx_sm_interact_done, Sx_sm_interact_done, 1, 1, 0, + doc: /* End interaction as a response to save_yourself. + If the argument CANCEL is non-nil, Emacs will tell the session manager + to cancel the shutdown */) + (cancel) + Lisp_Object cancel; + { + Bool cancel_shutdown = ! EQ (cancel, Qnil); + + SmcInteractDone (smc_conn, cancel_shutdown); + SmcSaveYourselfDone (smc_conn, True); + + /* Reset Vx_sm_cancel_shutdown for possibly next shutdown. */ + Vx_sm_cancel_shutdown = Qnil; + } + + \f + /*********************************************************************** + Initialization + ***********************************************************************/ + void + syms_of_xsmfns () + { + DEFVAR_LISP ("x-sm-id", &Vx_sm_id, + doc: /* The session id Emacs got from the session manager for this session. + Changing the value does not change the session id used by Emacs. + The value is nil if no session manager is running. + See also `x-sm-previous-id'. */); + Vx_sm_id = Qnil; + + DEFVAR_LISP ("x-sm-previous-id", &Vx_sm_previous_id, + doc: /* The previous session id Emacs got from session manager. + This is nil if Emacs was not started by the session manager. + The value of this variable and `x-sm-id' may be the same, depending on how + the session manager works. + See also `x-sm-id'.*/); + Vx_sm_previous_id = Qnil; + + DEFVAR_LISP ("x-sm-cancel-shutdown", &Vx_sm_cancel_shutdown, + doc: /* If non-nil, Emacs will cancel the session manager shutdown. + Setting this variable enables hooks in `save-yourself-hook' to cancel + a shutdown. This should only be done at an explicit user request to do + so.*/); + Vx_sm_cancel_shutdown = Qnil; + + defsubr (&Sx_sm_interact_done); + } + + #endif /* HAVE_X_SM */ Index: emacs/src/Makefile.in *** emacs/src/Makefile.in.orig Sat Feb 16 18:27:39 2002 --- emacs/src/Makefile.in Sun Feb 17 01:57:15 2002 *************** *** 294,300 **** #ifdef HAVE_MENUS /* Include xmenu.o in the list of X object files. */ ! XOBJ= xterm.o xfns.o xselect.o xrdb.o fontset.o /* The X Menu stuff is present in the X10 distribution, but missing from X11. If we have X10, just use the installed library; --- 294,300 ---- #ifdef HAVE_MENUS /* Include xmenu.o in the list of X object files. */ ! XOBJ= xterm.o xfns.o xselect.o xrdb.o fontset.o xsmfns.o /* The X Menu stuff is present in the X10 distribution, but missing from X11. If we have X10, just use the installed library; *************** *** 315,321 **** /* Otherwise, omit xmenu.o from the list of X object files, and don't worry about the menu library at all. */ ! XOBJ= xterm.o xfns.o xselect.o xrdb.o fontset.o LIBXMENU= #endif /* not HAVE_MENUS */ --- 315,321 ---- /* Otherwise, omit xmenu.o from the list of X object files, and don't worry about the menu library at all. */ ! XOBJ= xterm.o xfns.o xselect.o xrdb.o fontset.o xsmfns.o LIBXMENU= #endif /* not HAVE_MENUS */ *************** *** 366,372 **** --- 366,376 ---- #endif /* not LIBXT_STATIC */ #else /* not USE_X_TOOLKIT */ + #ifdef HAVE_X_SM + LIBXT=-lSM -lICE + #else LIBXT= + #endif #endif /* not USE_X_TOOLKIT */ #if HAVE_XPM *************** *** 549,555 **** These go in the DOC file on all machines in case they are needed there. */ SOME_MACHINE_OBJECTS = sunfns.o dosfns.o msdos.o \ ! xterm.o xfns.o xmenu.o xselect.o xrdb.o #ifdef TERMINFO --- 553,559 ---- These go in the DOC file on all machines in case they are needed there. */ SOME_MACHINE_OBJECTS = sunfns.o dosfns.o msdos.o \ ! xterm.o xfns.o xmenu.o xselect.o xrdb.o xsmfns.o #ifdef TERMINFO *************** *** 1126,1131 **** --- 1130,1136 ---- xselect.o: xselect.c dispextern.h frame.h xterm.h blockinput.h charset.h \ coding.h ccl.h buffer.h atimer.h systime.h $(config_h) xrdb.o: xrdb.c $(config_h) epaths.h + xsmfns.o: xsmfns.c $(config_h) systime.h sysselect.h lisp.h termhooks.h hftctl.o: hftctl.c $(config_h) sound.o: sound.c dispextern.h $(config_h) atimer.o: atimer.c atimer.h systime.h $(config_h) Index: emacs/src/termhooks.h *** emacs/src/termhooks.h.orig Sat Oct 20 07:51:38 2001 --- emacs/src/termhooks.h Sun Feb 17 01:57:15 2002 *************** *** 323,329 **** /* Queued from XTread_socket on FocusIn events. Translated into `switch-frame' events in kbd_buffer_get_event, if necessary. */ ! FOCUS_IN_EVENT }; /* If a struct input_event has a kind which is selection_request_event --- 323,333 ---- /* Queued from XTread_socket on FocusIn events. Translated into `switch-frame' events in kbd_buffer_get_event, if necessary. */ ! FOCUS_IN_EVENT, ! ! /* Queued from XTread_socket when session management sends ! save yourself before shutdown. */ ! save_yourself_event }; /* If a struct input_event has a kind which is selection_request_event Index: emacs/src/keyboard.c *** emacs/src/keyboard.c.orig Sat Feb 16 10:51:31 2002 --- emacs/src/keyboard.c Sun Feb 17 01:57:15 2002 *************** *** 554,559 **** --- 554,561 ---- Lisp_Object Qlanguage_change; #endif Lisp_Object Qdrag_n_drop; + Lisp_Object Qsave_yourself; + /* Lisp_Object Qmouse_movement; - also an event header */ /* Properties of event headers. */ *************** *** 3727,3732 **** --- 3729,3739 ---- kbd_fetch_ptr = event + 1; } #endif + else if (event->kind == save_yourself_event) + { + obj = Fcons (Qsave_yourself, Qnil); + kbd_fetch_ptr = event + 1; + } /* Just discard these, by returning nil. With MULTI_KBOARD, these events are used as placeholders when we need to randomly delete events from the queue. *************** *** 5391,5396 **** --- 5398,5406 ---- /* A user signal. */ return *lispy_user_signals[event->code]; + case save_yourself_event: + return Qsave_yourself; + /* The 'kind' field of the event is something we don't recognize. */ default: abort (); *************** *** 10404,10409 **** --- 10414,10422 ---- Qdrag_n_drop = intern ("drag-n-drop"); staticpro (&Qdrag_n_drop); + Qsave_yourself = intern ("save-yourself"); + staticpro(&Qsave_yourself); + Qusr1_signal = intern ("usr1-signal"); staticpro (&Qusr1_signal); Qusr2_signal = intern ("usr2-signal"); *************** *** 10988,10991 **** --- 11001,11006 ---- "ignore-event"); initial_define_lispy_key (Vspecial_event_map, "make-frame-visible", "ignore-event"); + initial_define_lispy_key (Vspecial_event_map, "save-yourself", + "handle-save-yourself"); } Index: emacs/src/lisp.h *** emacs/src/lisp.h.orig Thu Feb 7 21:22:19 2002 --- emacs/src/lisp.h Sun Feb 17 01:57:15 2002 *************** *** 3040,3045 **** --- 3040,3048 ---- EXFUN (Fx_file_dialog, 4); #endif /* HAVE_X_WINDOWS */ + /* Defined in xsmfns.c */ + extern void syms_of_xsmfns P_ ((void)); + /* Defined in xselect.c */ extern void syms_of_xselect P_ ((void)); Index: emacs/src/emacs.c *** emacs/src/emacs.c.orig Mon Jan 14 14:47:56 2002 --- emacs/src/emacs.c Sun Feb 17 01:57:15 2002 *************** *** 1464,1469 **** --- 1464,1470 ---- syms_of_xterm (); syms_of_xfns (); syms_of_fontset (); + syms_of_xsmfns (); #ifdef HAVE_X11 syms_of_xselect (); #endif Index: emacs/src/config.in *** emacs/src/config.in.orig Fri Dec 28 20:06:08 2001 --- emacs/src/config.in Sun Feb 17 01:57:15 2002 *************** *** 92,97 **** --- 92,100 ---- /* Define if we should use XIM, if it is available. */ #undef USE_XIM + /* Define if we have the session management (SM) library. */ + #undef HAVE_X_SM + /* Define if netdb.h declares h_errno. */ #undef HAVE_H_ERRNO Index: emacs/lisp/term/x-win.el *** emacs/lisp/term/x-win.el.orig Thu Jan 24 20:20:12 2002 --- emacs/lisp/term/x-win.el Sun Feb 17 02:56:11 2002 *************** *** 234,239 **** --- 234,268 ---- (funcall handler this-switch)) (setq args (cons orig-this-switch args))))) (nconc (nreverse args) x-invocation-args)) + + ;; Handle the --smid switch. This is used by the session manager + ;; to give us back our session id we had on the previous run. + (defun x-handle-smid (switch) + (or (consp x-invocation-args) + (error "%s: missing argument to `%s' option" (invocation-name) switch)) + (setq x-sm-previous-id (car x-invocation-args) + x-invocation-args (cdr x-invocation-args))) + + (defvar save-yourself-hook nil + "Hooks run when a save-yourself event occurs. + The hook gets one argument, the current session id. This is a string and + can for example, be used to create a unique file name.") + + (defvar restart-yourself-hook nil + "Hooks run when Emacs is started by a session manager.. + The hook gets two arguments, PREV-SESSID and SESSID. + PREV-SESSID is the previous session id, that is the session id Emacs + had when Emacs ran the last time. + SESSID is the session id Emacs has on this run. + PREV-SESSID and SESSID are strings and may have the same value.") + + (defun handle-save-yourself (event) + (interactive "e") + (condition-case nil + (run-hook-with-args 'save-yourself-hook x-sm-id) + (error nil)) + (x-sm-interact-done x-sm-cancel-shutdown)) + \f ;; ;; Standard X cursor shapes, courtesy of Mr. Fox, who wanted ALL of them. Index: emacs/lisp/startup.el *** emacs/lisp/startup.el.orig Wed Feb 6 15:59:10 2002 --- emacs/lisp/startup.el Sun Feb 17 02:55:38 2002 *************** *** 236,242 **** ("--cursor-color" 1 x-handle-switch cursor-color) ("--vertical-scroll-bars" 0 x-handle-switch vertical-scroll-bars t) ("--line-spacing" 1 x-handle-numeric-switch line-spacing) ! ("--border-color" 1 x-handle-switch border-width)) "Alist of X Windows options. Each element has the form (NAME NUMARGS HANDLER FRAME-PARAM VALUE) --- 236,243 ---- ("--cursor-color" 1 x-handle-switch cursor-color) ("--vertical-scroll-bars" 0 x-handle-switch vertical-scroll-bars t) ("--line-spacing" 1 x-handle-numeric-switch line-spacing) ! ("--border-color" 1 x-handle-switch border-width) ! ("--smid" 1 x-handle-smid)) "Alist of X Windows options. Each element has the form (NAME NUMARGS HANDLER FRAME-PARAM VALUE) *************** *** 1028,1034 **** (command-line-1 (cdr command-line-args)) ;; If -batch, terminate after processing the command options. ! (if noninteractive (kill-emacs t))) (defcustom initial-scratch-message (purecopy "\ ;; This buffer is for notes you don't want to save, and for Lisp evaluation. --- 1029,1040 ---- (command-line-1 (cdr command-line-args)) ;; If -batch, terminate after processing the command options. ! (if noninteractive (kill-emacs t)) ! ! ;; Run restart-yourself hooks (session management) if started by ! ;; the session manager and we have a session manager connection. ! (if (and (stringp x-sm-previous-id) (stringp x-sm-id)) ! (run-hook-with-args 'restart-yourself-hook x-sm-previous-id x-sm-id))) (defcustom initial-scratch-message (purecopy "\ ;; This buffer is for notes you don't want to save, and for Lisp evaluation. Index: emacs/configure.in *** emacs/configure.in.orig Sun Jan 27 11:03:14 2002 --- emacs/configure.in Sun Feb 17 01:57:15 2002 *************** *** 1915,1920 **** --- 1915,1935 ---- fi fi + ### Use session management (-lSM -lICE) if available + HAVE_X_SM=no + if test "${HAVE_X11}" = "yes"; then + AC_CHECK_HEADER(X11/SM/SMlib.h, + AC_CHECK_LIB(SM, SmcOpenConnection, HAVE_X_SM=yes, -lICE)) + + if test "${HAVE_X_SM}" = "yes"; then + AC_DEFINE(HAVE_X_SM) + case "$LIBS" in + *-lSM*) ;; + *) LIBS="-lSM -lICE $LIBS" ;; + esac + fi + fi + # If netdb.h doesn't declare h_errno, we must declare it by hand. AC_CACHE_CHECK(whether netdb declares h_errno, emacs_cv_netdb_declares_h_errno, _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Session management patch, please comment. 2002-02-17 19:11 Session management patch, please comment Jan D. @ 2002-02-19 6:37 ` Richard Stallman 2002-02-19 8:40 ` Kim F. Storm 2002-02-19 20:12 ` Jan D. 0 siblings, 2 replies; 23+ messages in thread From: Richard Stallman @ 2002-02-19 6:37 UTC (permalink / raw) Cc: emacs-devel It is an amazingly large amount of code, but I suppose there is no easier way. What a pity. Did you copy any substantial part of it from the X distribution, or anywhere else? Or did you write all of it afresh? + DEFUN ("x-sm-interact-done", Fx_sm_interact_done, Sx_sm_interact_done, 1, 1, 0, + doc: /* End interaction as a response to save_yourself. + If the argument CANCEL is non-nil, Emacs will tell the session manager + to cancel the shutdown */) This isn't clear enough--it doesn't tell me when to use this function or how. Perhaps it would be clear to a person who knows this relates to the session manager *and* knows all about the session manager, but that is not good enough; this doc string ought to make sense to an ordinary Emacs Lisp programmer who knows nothing about the session manager. + doc: /* The previous session id Emacs got from session manager. + This is nil if Emacs was not started by the session manager. + The value of this variable and `x-sm-id' may be the same, depending on how + the session manager works. + See also `x-sm-id'.*/); This doc string should explain what the previous session id is good for. What does it mean? Documentation for data should explain its overall meaning, not just what it looks like and what values are found when. + DEFVAR_LISP ("x-sm-cancel-shutdown", &Vx_sm_cancel_shutdown, + doc: /* If non-nil, Emacs will cancel the session manager shutdown. + Setting this variable enables hooks in `save-yourself-hook' to cancel + a shutdown. This should only be done at an explicit user request to do + so.*/); When should the Lisp programmer set or use this? When is it tested? I don't see anything in the code that ever tests this variable, so I am at a loss to understand its purpose. + (defvar save-yourself-hook nil + "Hooks run when a save-yourself event occurs. + The hook gets one argument, the current session id. This is a string and + can for example, be used to create a unique file name.") Since this is not a normal hook, it should have a different name. Perhaps save-yourself-functions. But I think save-session-functions is a clearer name; it gives the user more information and is more natural. + (defvar restart-yourself-hook nil + "Hooks run when Emacs is started by a session manager.. + The hook gets two arguments, PREV-SESSID and SESSID. Likewise this. Perhaps restart-session-functions. In general, replacing "yourself" with "session" in all the function and variable names would be an improvement. _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Session management patch, please comment. 2002-02-19 6:37 ` Richard Stallman @ 2002-02-19 8:40 ` Kim F. Storm 2002-02-19 20:13 ` Jan D. 2002-02-19 20:12 ` Jan D. 1 sibling, 1 reply; 23+ messages in thread From: Kim F. Storm @ 2002-02-19 8:40 UTC (permalink / raw) Cc: emacs-devel Richard Stallman <rms@gnu.org> writes: > In general, replacing "yourself" with "session" in all the function > and variable names would be an improvement. I suggest to also replace the -sm- with -session- (or -session-manager-) in names. That allows me to use `M-x apropos session' to easily find all the related functions and variables. -- Kim F. Storm <storm@cua.dk> http://www.cua.dk _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Session management patch, please comment. 2002-02-19 8:40 ` Kim F. Storm @ 2002-02-19 20:13 ` Jan D. 0 siblings, 0 replies; 23+ messages in thread From: Jan D. @ 2002-02-19 20:13 UTC (permalink / raw) Cc: emacs-devel Kim F. Storm wrote: > Richard Stallman <rms@gnu.org> writes: > > >>In general, replacing "yourself" with "session" in all the function >>and variable names would be an improvement. >> > > I suggest to also replace the -sm- with -session- (or -session-manager-) in names. > > That allows me to use `M-x apropos session' to easily find all > the related functions and variables. Good thinking, I will do that. Jan D. _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Session management patch, please comment. 2002-02-19 6:37 ` Richard Stallman 2002-02-19 8:40 ` Kim F. Storm @ 2002-02-19 20:12 ` Jan D. 2002-02-19 22:43 ` Kim F. Storm 2002-02-20 22:13 ` Richard Stallman 1 sibling, 2 replies; 23+ messages in thread From: Jan D. @ 2002-02-19 20:12 UTC (permalink / raw) Cc: emacs-devel Richard Stallman wrote: > It is an amazingly large amount of code, but I suppose there is no > easier way. What a pity. Yes, the use of callbacks for everything makes it look larger than it is. > > Did you copy any substantial part of it from the X distribution, or > anywhere else? Or did you write all of it afresh? It is all my code from scratch. I wanted to do it all afresh to get a better understanding of X session management. I just used the specification. > > + DEFUN ("x-sm-interact-done", Fx_sm_interact_done, Sx_sm_interact_done, 1, 1, 0, > + doc: /* End interaction as a response to save_yourself. > + If the argument CANCEL is non-nil, Emacs will tell the session manager > + to cancel the shutdown */) > > This isn't clear enough--it doesn't tell me when to use this function > or how. Perhaps it would be clear to a person who knows this relates > to the session manager *and* knows all about the session manager, but > that is not good enough; this doc string ought to make sense to an > ordinary Emacs Lisp programmer who knows nothing about the session > manager. Well, actually I didn't even want this function, but I could not find another way to call C from lisp. It is not meant to be "external", rather a link between the C part and the lisp part of the session management code. But I don't think lisp has some kind of "private" functions, or? I'll try to explain. The session manager sends Emacs a save_yourself message telling Emacs that the window system is shutting down. Emacs then requests from the session manager that it would like to interact with its user (i.e. pop up windows and such). The session manager replies that that is OK. In response the session manager wants a interact_done when interaction is done. Emacs is executing C code when this happens. To get into lisp code, a save-yourself-event is generated and the lisp function bound to the event executes (handle-save-yourself). handle-save-yourself then executes functions in the save-yourself-hook and by calling x-sm-interact-done it finally informs the C code that it shall send the interaction-done message to the session manager. Ideally, (as I am a C/C++/Java kind of person) I would like save-yourself-event, handle-save-yourself and x-sm-interact-done to be "private" so that users can't override any part of the chain they form (the thought of that happening makes me a bit uneasy). If there is a way to make that happen, I'd be glad to know. If not, how about this documentation: "End interaction as a response to save_yourself. A session manager can tell Emacs that the window system is shutting down by sending Emacs a save_yourself message. Emacs then executes functions in `save-yourself-hook'. After that, this function shall be called to inform the session manager that it can continue or abort shutting down the window system. If the argument CANCEL is non-nil, Emacs will tell the session manager to cancel the shutdown." > + doc: /* The previous session id Emacs got from session manager. > + This is nil if Emacs was not started by the session manager. > + The value of this variable and `x-sm-id' may be the same, depending on how > + the session manager works. > + See also `x-sm-id'.*/); > > This doc string should explain what the previous session id is good > for. What does it mean? Documentation for data should explain its > overall meaning, not just what it looks like and what values are found > when. How about this (a bit long perhaps): "The previous session id Emacs got from session manager. If Emacs is running on a window system that has a session manager, the session manager gives Emacs a session id. It is feasible for Emacs lisp code to use the session id to save configuration in, for example, a file with a file name based on the session id. If Emacs is running when the window system is shut down, the session manager remembers that Emacs was running and saves the session id Emacs had. When the window system is started again, the session manager restarts Emacs and hands Emacs the session id it had the last time it was running. This is now the previous session id and the value of this variable. If configuration was saved in a file as stated above, the previous session id shall be used to reconstruct the file name. The session id Emacs has while it is running is in the variable `x-sm-id'. The value of this variable and `x-sm-id' may be the same, depending on how the session manager works. See also `save-yourself-hook'." > > + DEFVAR_LISP ("x-sm-cancel-shutdown", &Vx_sm_cancel_shutdown, > + doc: /* If non-nil, Emacs will cancel the session manager shutdown. > + Setting this variable enables hooks in `save-yourself-hook' to cancel > + a shutdown. This should only be done at an explicit user request to do > + so.*/); > > When should the Lisp programmer set or use this? When is it tested? > I don't see anything in the code that ever tests this variable, so I > am at a loss to understand its purpose. In the lisp function handle-save-yourself, it is used as an argument to x-sm-interact-done. The idea was that as functions in save-yourself-hook are executing, they might interact with the user, for instance pop up a dialog. That dialog can have the possibility to cancel the whole window system shutdown. If the lisp code wants to do that, it shall set this variable to something non-nil. > > + (defvar save-yourself-hook nil > + "Hooks run when a save-yourself event occurs. > + The hook gets one argument, the current session id. This is a string and > + can for example, be used to create a unique file name.") > > Since this is not a normal hook, it should have a different name. > Perhaps save-yourself-functions. But I think save-session-functions > is a clearer name; it gives the user more information and is more > natural. > > + (defvar restart-yourself-hook nil > + "Hooks run when Emacs is started by a session manager.. > + The hook gets two arguments, PREV-SESSID and SESSID. > > Likewise this. Perhaps restart-session-functions. > > In general, replacing "yourself" with "session" in all the function and variable names would be an improvement. Yes, this is a good idea, I just used the names in the SM specification without much thought. Jan D. _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Session management patch, please comment. 2002-02-19 20:12 ` Jan D. @ 2002-02-19 22:43 ` Kim F. Storm 2002-02-20 20:29 ` Jan Djärv 2002-02-20 22:13 ` Richard Stallman 1 sibling, 1 reply; 23+ messages in thread From: Kim F. Storm @ 2002-02-19 22:43 UTC (permalink / raw) Cc: emacs-devel "Jan D." <Jan.Djarv@mbox200.swipnet.se> writes: > > + DEFUN ("x-sm-interact-done", Fx_sm_interact_done, > > Emacs is executing C code when this happens. To get into lisp code, a > save-yourself-event is generated and the lisp function bound to the > event executes (handle-save-yourself). > > handle-save-yourself then executes functions in the save-yourself-hook > and by calling x-sm-interact-done it finally informs the C code that > it shall send the interaction-done message to the session manager. > What about this approach: In C, you declare a hook variable emacs-session-save-function. In Lisp, you bind a save-session-state function to this variable. When the save_yourself event arrives, the function bound to emacs-session-save-function is called (with whatever arguments you think it needs). The save-session-state function runs the save-session-state-hook hooks. The return value from save-session-state is nil or t - corresponding to the CANCEL argument of your x-sm-interact-done function. I.e. instead of explicitly calling x-sm-interact-done, the return value from the function bound to emacs-session-save-function indicates whether it succeeded or not. So you wont need x-sm-interact-done. Similarly, there should be a C level emacs-session-restore-function variable. This is called with the previous and current session id as arguments. It runs the restore-session-state-hook hooks. > > + doc: /* The previous session id Emacs got from session manager. > > + This is nil if Emacs was not started by the session manager. > > + The value of this variable and `x-sm-id' may be the same, depending on how > > + the session manager works. > > + See also `x-sm-id'.*/); > > This doc string should explain what the previous session id is good > > for. What does it mean? Documentation for data should explain its > > overall meaning, not just what it looks like and what values are found > > when. Does these really need to be a C-level lisp variables? Isn't it enough that the previous session id is passed as an argument to the emacs-session-restore-function and the current session id is an argument to emacs-session-save-function? In general, I would suspect that you only need to know either the previous session id (when doing restore), or the current session id (when doing save). If necessary, the restore-session-state function could store it in a lisp variable for the hooks to access -- or you can rely on the dynamic binding of the argument to restore-session-state, e.g. (defun save-session-state (session-id) ;; current session-id ...) (defun restore-session-state (session-id) ;; previous session-id ...) > > + DEFVAR_LISP ("x-sm-cancel-shutdown", &Vx_sm_cancel_shutdown, With the suggested solution above, this variable could also be declared in lisp (actually it could be dynamically bound in the save-session-state function): (defun save-session-state (session-id) (let ((cancel-session-shutdown nil)) (run-hooks 'save-session-state-hook) cancel-session-shutdown)) -- Kim F. Storm <storm@cua.dk> http://www.cua.dk _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Session management patch, please comment. 2002-02-19 22:43 ` Kim F. Storm @ 2002-02-20 20:29 ` Jan Djärv 2002-02-20 22:50 ` Kim F. Storm 0 siblings, 1 reply; 23+ messages in thread From: Jan Djärv @ 2002-02-20 20:29 UTC (permalink / raw) Cc: emacs-devel tisdagen den 19 februari 2002 kl 23.43 skrev Kim F. Storm: > "Jan D." <Jan.Djarv@mbox200.swipnet.se> writes: > >>> + DEFUN ("x-sm-interact-done", Fx_sm_interact_done, >> >> Emacs is executing C code when this happens. To get into lisp code, a >> save-yourself-event is generated and the lisp function bound to the >> event executes (handle-save-yourself). >> >> handle-save-yourself then executes functions in the save-yourself-hook >> and by calling x-sm-interact-done it finally informs the C code that >> it shall send the interaction-done message to the session manager. >> > > What about this approach: > > In C, you declare a hook variable emacs-session-save-function. > > In Lisp, you bind a save-session-state function to this variable. > > When the save_yourself event arrives, the function bound to > emacs-session-save-function is called (with whatever arguments you > think it needs). I don't quite understand. What purpose does the emacs-session-save-function serve, why not call a lisp function directly? And if one can call lisp functions, why not call the functions in save-session-state-hook from C? The reason I did it the way presented, is was I think you can't call lisp functions from the X event input handler. Thus an Emacs event is used to get control to the lisp part. But maybe this can be made an internal event and the hooks can be called from Emacs input loop. I did not know how to do that, I was not sure where such code should go to not mess things up with recursive calls. But if someone knows and can give a pointer I can modify the code. > > The save-session-state function runs the save-session-state-hook hooks. > > The return value from save-session-state is nil or t - corresponding > to the CANCEL argument of your x-sm-interact-done function. > > >>> + doc: /* The previous session id Emacs got from session manager. >>> + This is nil if Emacs was not started by the session manager. >>> + The value of this variable and `x-sm-id' may be the same, >>> depending on how >>> + the session manager works. >>> + See also `x-sm-id'.*/); >>> This doc string should explain what the previous session id is good >>> for. What does it mean? Documentation for data should explain its >>> overall meaning, not just what it looks like and what values are found >>> when. > > Does these really need to be a C-level lisp variables? > > Isn't it enough that the previous session id is passed as an argument > to the emacs-session-restore-function and the current session id is an > argument to emacs-session-save-function? > > In general, I would suspect that you only need to know either the > previous session id (when doing restore), or the current session id > (when doing save). If you have saved state in a file with a filename based on the previous id, you presumably would want remove or move that file, either when doing restore or save session. > If necessary, the restore-session-state function could store it in a > lisp variable for the hooks to access -- or you can rely on the > dynamic binding of the argument to restore-session-state, e.g. > > (defun save-session-state (session-id) ;; current session-id > ...) > > (defun restore-session-state (session-id) ;; previous session-id > ...) > >>> + DEFVAR_LISP ("x-sm-cancel-shutdown", &Vx_sm_cancel_shutdown, > > With the suggested solution above, this variable could also be declared in > lisp > (actually it could be dynamically bound in the save-session-state function) > : > > (defun save-session-state (session-id) > (let ((cancel-session-shutdown nil)) > (run-hooks 'save-session-state-hook) > cancel-session-shutdown)) > This looks useful, thanks for the hint. Jan D. _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Session management patch, please comment. 2002-02-20 20:29 ` Jan Djärv @ 2002-02-20 22:50 ` Kim F. Storm 2002-02-21 19:57 ` Jan D. 2002-02-22 4:32 ` Session management patch, please comment Richard Stallman 0 siblings, 2 replies; 23+ messages in thread From: Kim F. Storm @ 2002-02-20 22:50 UTC (permalink / raw) Cc: emacs-devel Jan Djärv <Jan.Djarv@mbox200.swipnet.se> writes: > > What about this approach: > > > > In C, you declare a hook variable emacs-session-save-function. > > > > In Lisp, you bind a save-session-state function to this variable. > > > > When the save_yourself event arrives, the function bound to > > emacs-session-save-function is called (with whatever arguments you > > think it needs). > > I don't quite understand. What purpose does the > emacs-session-save-function serve, why not call a lisp function > directly? And if one can call lisp functions, why not call the > functions in save-session-state-hook from C? I believe the normal approach when calling lisp functions from C is to run a hook, i.e. call the function(s) bound to a variable defined in C. By doing that, you don't require lisp functions to have a specific name (or being defined), and it uses a well-defined method to invoke a lisp function from C. > > The reason I did it the way presented, is was I think you can't call > lisp functions from the X event input handler. Thus an Emacs event is > used to get control to the lisp part. Using `special-event-map' as you do is the right approach (I think). The only thing I suggest to change is to define the handle-save-yourself function in C. It should call the function bound to the variable `emacs-session-save-function' (that function is written in lisp and runs the save session hooks), and depending on whether that function returns nil or t, it will execute the relevant parts of the code currently located in x-sm-interact-done. That way, you don't need the x-sm-interact-done callback from lisp to C. > > > > In general, I would suspect that you only need to know either the > > previous session id (when doing restore), or the current session id > > (when doing save). > > If you have saved state in a file with a filename based on the previous id, > you presumably would want remove or move that file, either when > doing restore or save session. Ok, but if that is necessary, you can save the `session-id' parameter (of the restore function) in a variable defined in lisp - to be used later by the save function. However, I would expect the restore function to remove that file. But again, that would be decided in lisp rather than the core emacs functions. ++kfs _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Session management patch, please comment. 2002-02-20 22:50 ` Kim F. Storm @ 2002-02-21 19:57 ` Jan D. 2002-02-21 21:18 ` Kim F. Storm 2002-02-22 4:32 ` Session management patch, please comment Richard Stallman 1 sibling, 1 reply; 23+ messages in thread From: Jan D. @ 2002-02-21 19:57 UTC (permalink / raw) Cc: emacs-devel > Jan Djärv <Jan.Djarv@mbox200.swipnet.se> writes: > > > > What about this approach: > > > > > > In C, you declare a hook variable emacs-session-save-function. > > > > > > In Lisp, you bind a save-session-state function to this variable. > > > > > > When the save_yourself event arrives, the function bound to > > > emacs-session-save-function is called (with whatever arguments you > > > think it needs). > > > > I don't quite understand. What purpose does the > > emacs-session-save-function serve, why not call a lisp function > > directly? And if one can call lisp functions, why not call the > > functions in save-session-state-hook from C? > > I believe the normal approach when calling lisp functions from C is to > run a hook, i.e. call the function(s) bound to a variable defined in C. > > By doing that, you don't require lisp functions to have a specific > name (or being defined), and it uses a well-defined method to invoke a > lisp function from C. Okay. > > The reason I did it the way presented, is was I think you can't call > > lisp functions from the X event input handler. Thus an Emacs event is > > used to get control to the lisp part. > > Using `special-event-map' as you do is the right approach (I think). > The only thing I suggest to change is to define the handle-save-yourself > function in C. > > It should call the function bound to the variable `emacs-session-save-function' > (that function is written in lisp and runs the save session hooks), and > depending on whether that function returns nil or t, it will execute the > relevant parts of the code currently located in x-sm-interact-done. > > That way, you don't need the x-sm-interact-done callback from lisp to C. Right, now I see. I didn't think about that. Good idea. But if handle-save-yourself is in C, it should be able to call the save session hooks by itself, and then do what x-sm-interact-done does, could it not? That way, less code (marginal) and more straight forward logic is achived. I'll send an updated patch shortly. > > > > > > > In general, I would suspect that you only need to know either the > > > previous session id (when doing restore), or the current session id > > > (when doing save). > > > > If you have saved state in a file with a filename based on the previous id, > > you presumably would want remove or move that file, either when > > doing restore or save session. > > Ok, but if that is necessary, you can save the `session-id' parameter > (of the restore function) in a variable defined in lisp - to be used > later by the save function. > > However, I would expect the restore function to remove that file. > But again, that would be decided in lisp rather than the core emacs > functions. I just wanted to make all info available. I haven't looked at other implementations so I really don't know what the convention is. Jan D. _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Session management patch, please comment. 2002-02-21 19:57 ` Jan D. @ 2002-02-21 21:18 ` Kim F. Storm 2002-02-26 22:49 ` New session management patch Jan D. 0 siblings, 1 reply; 23+ messages in thread From: Kim F. Storm @ 2002-02-21 21:18 UTC (permalink / raw) Cc: emacs-devel "Jan D." <Jan.Djarv@mbox200.swipnet.se> writes: > > Right, now I see. I didn't think about that. Good idea. > But if handle-save-yourself is in C, it should be able to call the save > session hooks by itself, and then do what x-sm-interact-done does, could > it not? That way, less code (marginal) and more straight forward logic > is achived. Yes, that would be a possibility, but in lisp you (and others) have much more freedom to tune the behaviour, such as defining the cancel-shutdown variable, store everything in one file, etc. I think the general philosophy is to have the basic functionality in C and as much flexibility in lisp. E.g. you can define the save function in lisp like this (defun save-myself-function (prev-session-id cur-session-id) (let ((cancel-shutdown nil) (filename (concat .... session-id)) (buf (get-buffer-create (concat "*SES " cur-session-id)))) (with-current-buffer buf ;; save hooks should use `insert' to add to the save file (run-hook save-session-hook) (unless cancel-shutdown (write-file filename))) (kill-buffer buf) cancel-shutdown)) Another problem is how to restore things after restarting emacs. I don't think you can rely on a hook to do this. Some things may not have been added to the restore-hook when you run it (e.g. if gnus stores its state in a file, there need to be a gnus-restore-session function in the hook list for this to work.) One possible fix would be to let the save-hook functions insert lisp code in the session save file which - when emacs restarts - is eval'ed to restore the previous state. You should make a default choice of how the session file is named based on the session-id (define a function emacs-session-save-filename in x-win.el which the user can rewrite), and then -- at the place where you now do (if (and (stringp x-sm-previous-id) (stringp x-sm-id)) (run-hook-with-args 'restart-yourself-hook x-sm-previous-id x-sm-id))) you should simply insert a call to a function: (if (and (stringp x-sm-previous-id) (stringp x-sm-id) (fboundp 'emacs-session-restore-session)) (emacs-session-restore-session x-sm-previous-id x-sm-id)) This function is defined in x-win.el along with your other lisp code and does something like this: (let ((filename (emacs-session-save-filename x-sm-previous-id)) (when (file-exists-p filename) (load-file filename) (delete-file filename) (message "Restored session data"))) Maybe you should look at desktop.el to see how it does things? (I don't know whether it is relevant, though). -- Kim F. Storm <storm@cua.dk> http://www.cua.dk _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
* New session management patch. 2002-02-21 21:18 ` Kim F. Storm @ 2002-02-26 22:49 ` Jan D. 2002-02-27 5:51 ` Richard Stallman 0 siblings, 1 reply; 23+ messages in thread From: Jan D. @ 2002-02-26 22:49 UTC (permalink / raw) Cc: emacs-devel Kim F. Storm wrote: > Another problem is how to restore things after restarting emacs. I > don't think you can rely on a hook to do this. Some things may not > have been added to the restore-hook when you run it (e.g. if gnus > stores its state in a file, there need to be a gnus-restore-session > function in the hook list for this to work.) > > One possible fix would be to let the save-hook functions insert lisp > code in the session save file which - when emacs restarts - is eval'ed > to restore the previous state. > > You should make a default choice of how the session file is named > based on the session-id (define a function emacs-session-save-filename > in x-win.el which the user can rewrite), and then -- at the place > where you now do ... I have incorporated your ideas almost verbatim, Your remark about the problem of restore is well put. Also a default filename makes it easier for functions to save state. But I haven't made variables for functions emacs-session-save and emacs-session-restore. I figured that anyone can redefine the functions if they so wish. Another thing is that I had to make a PATH search for emacs to find the absolute path for the emacs exeutable. In the path search and also in some lisp code that makes the filename, the directory separator "/" is hard coded. Is this OK? Is there a variable to look at instead? I found directory-sep-char but it is deprecated. I know VMS for instance has X, but does it have SM and ICE also? This patch still doesn't save any state, but it is getting closer. Jan D. Index: lisp/term/x-win.el --- lisp/term/x-win.el.orig Thu Jan 24 20:20:12 2002 +++ lisp/term/x-win.el Tue Feb 26 22:48:49 2002 @@ -234,6 +234,72 @@ (funcall handler this-switch)) (setq args (cons orig-this-switch args))))) (nconc (nreverse args) x-invocation-args)) + +;; Handle the --smid switch. This is used by the session manager +;; to give us back our session id we had on the previous run. +(defun x-handle-smid (switch) + (or (consp x-invocation-args) + (error "%s: missing argument to `%s' option" (invocation-name) switch)) + (setq x-session-previous-id (car x-invocation-args) + x-invocation-args (cdr x-invocation-args))) + +(defvar emacs-save-session-functions nil + "Functions to run when a save-session event occurs. +The functions does not get any argument. +Functions can return non-nil to inform the session manager that the +window system shutdown should be aborted. + +See also `emacs-session-save'.") + +(defun emacs-session-filename (session-id) + "Construct a filename to save the session in based on SESSION-ID. +If the directory ~/.emacs.d exists, we make a filename in there, otherwise +a file in the home directory." + (let ((basename (concat "emacs." session-id)) + (emacs-dir "~/.emacs.d/")) + (expand-file-name (if (file-directory-p emacs-dir) + (concat emacs-dir basename) + (concat "~/." basename))))) + + (defun emacs-session-save () + "Run the `emacs-save-session-functions' when window system is closing. +When a session manager tells Emacs that the window system is shutting +down, this function is called. It calls the functions in the hook +`emacs-save-session-functions'. Functions are called with the current +buffer set to a temporary buffer. Functions should use `insert' to insert +lisp code to save the session state. The buffer is saved +in a file in the home directory of the user running Emacs. The file +is evaluated when Emacs is restarted by the session manager. + +If any of the functions returns non-nil, no more functions are called +and this function returns non-nil. This will inform the session manager +that it should abort the window system shutdown." + (let ((filename (emacs-session-filename x-session-id)) + (buf (get-buffer-create (concat " *SES " x-session-id)))) + (when (file-exists-p filename) + (delete-file filename)) + (with-current-buffer buf + (let ((cancel-shutdown (condition-case nil + (run-hook-with-args-until-success + 'emacs-save-session-functions x-session-id) + (error t)))) + (unless cancel-shutdown + (write-file filename)) + (kill-buffer buf) + cancel-shutdown)))) + +(defun emacs-session-restore () + "Restore the Emacs session if started by a session manager. +The file saved by `emacs-session-save' is evaluated and deleted if it +exists." + (let ((filename (emacs-session-filename x-session-previous-id))) + (when (file-exists-p filename) + (load-file filename) + (delete-file filename) + (message "Restored session data")))) + + + \f ;; ;; Standard X cursor shapes, courtesy of Mr. Fox, who wanted ALL of them. Index: lisp/startup.el --- lisp/startup.el.orig Wed Feb 6 15:59:10 2002 +++ lisp/startup.el Tue Feb 26 22:48:49 2002 @@ -236,7 +236,8 @@ ("--cursor-color" 1 x-handle-switch cursor-color) ("--vertical-scroll-bars" 0 x-handle-switch vertical-scroll-bars t) ("--line-spacing" 1 x-handle-numeric-switch line-spacing) - ("--border-color" 1 x-handle-switch border-width)) + ("--border-color" 1 x-handle-switch border-width) + ("--smid" 1 x-handle-smid)) "Alist of X Windows options. Each element has the form (NAME NUMARGS HANDLER FRAME-PARAM VALUE) @@ -1028,7 +1029,12 @@ (command-line-1 (cdr command-line-args)) ;; If -batch, terminate after processing the command options. - (if noninteractive (kill-emacs t))) + (if noninteractive (kill-emacs t)) + + ;; Run emacs-session-restore (session management) if started by + ;; the session manager and we have a session manager connection. + (if (and (stringp x-session-previous-id) (stringp x-session-id)) + (emacs-session-restore))) (defcustom initial-scratch-message (purecopy "\ ;; This buffer is for notes you don't want to save, and for Lisp evaluation. Index: src/Makefile.in --- src/Makefile.in.orig Tue Feb 26 22:44:10 2002 +++ src/Makefile.in Tue Feb 26 22:48:49 2002 @@ -294,7 +294,7 @@ #ifdef HAVE_MENUS /* Include xmenu.o in the list of X object files. */ -XOBJ= xterm.o xfns.o xselect.o xrdb.o fontset.o +XOBJ= xterm.o xfns.o xselect.o xrdb.o fontset.o xsmfns.o /* The X Menu stuff is present in the X10 distribution, but missing from X11. If we have X10, just use the installed library; @@ -315,7 +315,7 @@ /* Otherwise, omit xmenu.o from the list of X object files, and don't worry about the menu library at all. */ -XOBJ= xterm.o xfns.o xselect.o xrdb.o fontset.o +XOBJ= xterm.o xfns.o xselect.o xrdb.o fontset.o xsmfns.o LIBXMENU= #endif /* not HAVE_MENUS */ @@ -366,7 +366,11 @@ #endif /* not LIBXT_STATIC */ #else /* not USE_X_TOOLKIT */ +#ifdef HAVE_X_SM +LIBXT=-lSM -lICE +#else LIBXT= +#endif #endif /* not USE_X_TOOLKIT */ #if HAVE_XPM @@ -549,7 +553,7 @@ These go in the DOC file on all machines in case they are needed there. */ SOME_MACHINE_OBJECTS = sunfns.o dosfns.o msdos.o \ - xterm.o xfns.o xmenu.o xselect.o xrdb.o + xterm.o xfns.o xmenu.o xselect.o xrdb.o xsmfns.o #ifdef TERMINFO @@ -1128,6 +1132,7 @@ xselect.o: xselect.c dispextern.h frame.h xterm.h blockinput.h charset.h \ coding.h ccl.h buffer.h atimer.h systime.h $(config_h) xrdb.o: xrdb.c $(config_h) epaths.h +xsmfns.o: xsmfns.c $(config_h) systime.h sysselect.h lisp.h termhooks.h hftctl.o: hftctl.c $(config_h) sound.o: sound.c dispextern.h $(config_h) atimer.o: atimer.c atimer.h systime.h $(config_h) Index: src/xterm.c --- src/xterm.c.orig Tue Feb 26 22:44:13 2002 +++ src/xterm.c Tue Feb 26 22:48:49 2002 @@ -10032,6 +10032,12 @@ x_io_error_quitter (dpyinfo->display); } +#ifdef HAVE_X_SM + BLOCK_INPUT; + count += x_session_check_input (bufp, &numchars); + UNBLOCK_INPUT; +#endif + while (XPending (dpyinfo->display)) { XNextEvent (dpyinfo->display, &event); @@ -10114,11 +10120,17 @@ the session manager, who's looking for such a PropertyNotify. Can restart processing when a keyboard or mouse event arrives. */ - if (numchars > 0) + /* If we have a session manager, don't set this. + KDE will then start two Emacsen, one for the + session manager and one for this. */ + if (numchars > 0 +#ifdef HAVE_X_SM + && ! x_session_have_connection () +#endif + ) { f = x_top_window_to_frame (dpyinfo, event.xclient.window); - /* This is just so we only give real data once for a single Emacs process. */ if (f == SELECTED_FRAME ()) @@ -15046,6 +15058,10 @@ #endif /* ! defined (SIGWINCH) */ signal (SIGPIPE, x_connection_signal); + +#ifdef HAVE_X_SM + x_session_initialize (); +#endif } Index: src/xterm.h --- src/xterm.h.orig Tue Feb 26 22:44:13 2002 +++ src/xterm.h Tue Feb 26 22:48:49 2002 @@ -1098,3 +1098,11 @@ #ifdef USE_X_TOOLKIT extern void widget_store_internal_border P_ ((Widget)); #endif + +/* Defined in xsmfns.c */ +#ifdef HAVE_X_SM +extern void x_session_initialize P_ ((void)); +extern int x_session_check_input P_ ((struct input_event *bufp, + int *numchars)); +extern int x_session_have_connection P_ ((void)); +#endif Index: src/termhooks.h --- src/termhooks.h.orig Sat Oct 20 07:51:38 2001 +++ src/termhooks.h Tue Feb 26 22:48:49 2002 @@ -323,7 +323,11 @@ /* Queued from XTread_socket on FocusIn events. Translated into `switch-frame' events in kbd_buffer_get_event, if necessary. */ - FOCUS_IN_EVENT + FOCUS_IN_EVENT, + + /* Queued from XTread_socket when session manager sends + save yourself before shutdown. */ + save_session_event }; /* If a struct input_event has a kind which is selection_request_event Index: src/keyboard.c --- src/keyboard.c.orig Tue Feb 26 22:44:10 2002 +++ src/keyboard.c Tue Feb 26 22:48:49 2002 @@ -554,6 +554,8 @@ Lisp_Object Qlanguage_change; #endif Lisp_Object Qdrag_n_drop; +Lisp_Object Qsave_session; + /* Lisp_Object Qmouse_movement; - also an event header */ /* Properties of event headers. */ @@ -3725,6 +3727,11 @@ kbd_fetch_ptr = event + 1; } #endif + else if (event->kind == save_session_event) + { + obj = Fcons (Qsave_session, Qnil); + kbd_fetch_ptr = event + 1; + } /* Just discard these, by returning nil. With MULTI_KBOARD, these events are used as placeholders when we need to randomly delete events from the queue. @@ -5389,6 +5396,9 @@ /* A user signal. */ return *lispy_user_signals[event->code]; + case save_session_event: + return Qsave_session; + /* The 'kind' field of the event is something we don't recognize. */ default: abort (); @@ -10351,6 +10361,9 @@ Qdrag_n_drop = intern ("drag-n-drop"); staticpro (&Qdrag_n_drop); + Qsave_session = intern ("save-session"); + staticpro(&Qsave_session); + Qusr1_signal = intern ("usr1-signal"); staticpro (&Qusr1_signal); Qusr2_signal = intern ("usr2-signal"); @@ -10935,4 +10948,6 @@ "ignore-event"); initial_define_lispy_key (Vspecial_event_map, "make-frame-visible", "ignore-event"); + initial_define_lispy_key (Vspecial_event_map, "save-session", + "handle-save-session"); } Index: src/lisp.h --- src/lisp.h.orig Thu Feb 7 21:22:19 2002 +++ src/lisp.h Tue Feb 26 22:48:49 2002 @@ -3040,6 +3040,9 @@ EXFUN (Fx_file_dialog, 4); #endif /* HAVE_X_WINDOWS */ +/* Defined in xsmfns.c */ +extern void syms_of_xsmfns P_ ((void)); + /* Defined in xselect.c */ extern void syms_of_xselect P_ ((void)); Index: src/emacs.c --- src/emacs.c.orig Mon Jan 14 14:47:56 2002 +++ src/emacs.c Tue Feb 26 22:48:49 2002 @@ -1464,6 +1464,7 @@ syms_of_xterm (); syms_of_xfns (); syms_of_fontset (); + syms_of_xsmfns (); #ifdef HAVE_X11 syms_of_xselect (); #endif Index: src/config.in --- src/config.in.orig Fri Dec 28 20:06:08 2001 +++ src/config.in Tue Feb 26 22:48:49 2002 @@ -92,6 +92,9 @@ /* Define if we should use XIM, if it is available. */ #undef USE_XIM +/* Define if we have the session management (SM) library. */ +#undef HAVE_X_SM + /* Define if netdb.h declares h_errno. */ #undef HAVE_H_ERRNO Index: src/xsmfns.c --- src/xsmfns.c.orig Sun Feb 17 01:58:43 2002 +++ src/xsmfns.c Tue Feb 26 22:48:49 2002 @@ -0,0 +1,626 @@ +/* Session management module for systems which understand the X Session + management protocol. + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include <config.h> + +#ifdef HAVE_X_SM + +#include <X11/SM/SMlib.h> +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#include <sys/types.h> +#include <sys/stat.h> + +#include "systime.h" +#include "sysselect.h" +#include "lisp.h" +#include "termhooks.h" + +#if !defined(S_ISDIR) && defined(S_IFDIR) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif + +#define PATH_SEP_CHAR '/' +#define PATH_SEP_STR "/" + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif /* not MAXPATHLEN */ + + +extern char *getenv (); + + +/* This is the event used when save_session occurs */ + +static struct input_event emacs_event; + +/* The descriptor that we use to check for data from the session manager. */ + +static int ice_fd = -1; + +/* A flag that says if we are in shutdown interactions or not. */ + +static int doing_interact = False; + +/* Initial values of argv. */ + +extern char **initial_argv; + +/* The session manager object for the session manager connection */ + +static SmcConn smc_conn; + +/* The client session id for this session */ +static char *client_id; + +/* The client session id for this session as a lisp object. */ + +Lisp_Object Vx_session_id; + +/* The id we had the previous session. This is only available if we + have been started by the session manager with SMID_OPT. */ + +Lisp_Object Vx_session_previous_id; + +/* The option we tell the session manager to start Emacs with when + restarting Emacs. The client_id is appended. */ + +#define SMID_OPT "--smid=" + + +/* Return non-zero if PATH is an executable file. */ +static int +executable_file_p (path) + char *path; +{ + struct stat status; + + return (access (path, X_OK) == 0 /* exists and is executable */ + && stat (path, &status) == 0 /* get the status */ + && (S_ISDIR (status.st_mode)) == 0); /* not a directory */ +} + +/* If FILENAME is not an absolute path, make it so by prepending + CURRENT_DIRECTORY. The return value is allocated with malloc and + the caller must free it. */ +static char* +make_absolute_path (filename, current_directory) + char *filename; + char *current_directory; +{ + if (filename[0] == PATH_SEP_CHAR || ! current_directory) + return xstrdup (filename); + + if (strchr (filename, PATH_SEP_CHAR)) + { + char *ret; + + ret = xmalloc (strlen (filename)+strlen (current_directory)+2); + strcpy (ret, current_directory); + strcat (ret, PATH_SEP_STR); + strcat (ret, filename); + + return ret; + } + + return xstrdup (filename); +} + +/* Try to find program by searching path from environment. If not found, + the CURRENT_DIRECTORY concatenated with PROGRAM is returned. + The return value is allocated with malloc and the caller must free it. */ +static char* +path_search (program, current_directory) + char *program; + char *current_directory; +{ + char* bp; + char* ep; + char *ret; + size_t proglen = strlen (program); + + if (strchr(program, PATH_SEP_CHAR) || ! (bp = getenv ("PATH"))) + return make_absolute_path (program, current_directory); + + while (bp) + { + size_t len; + + ep = strchr (bp, ':'); + if (ep == bp || bp[0] == '\0') + { + /* Empty PATH component, treat as current directory */ + bp = "."; + len = 1; + } + else if (ep) len = ep-bp; + else len = strlen (bp); + + if (proglen+len+1 <= MAXPATHLEN) + { + char maybe[MAXPATHLEN+1]; + + strncpy (maybe, bp, len); + maybe[len] = '\0'; + strcat (maybe, PATH_SEP_STR); + strcat (maybe, program); + if (executable_file_p (maybe)) + return make_absolute_path (maybe, current_directory); + } + + if (ep) bp = ep+1; + else bp = ep; + } + + return make_absolute_path (program, current_directory); +} + +/* Handle any messages from the session manager. If no connection is + open to a session manager, just return 0. + Otherwise returns the number of events stored in buffer BUFP, + which can hold up to *NUMCHARS characters. At most one event is + stored, an save_session_event. */ +int +x_session_check_input (bufp, numchars) + struct input_event *bufp; + int *numchars; +{ + SELECT_TYPE read_fds; + EMACS_TIME tmout; + + if (ice_fd == -1) return 0; + + FD_ZERO (&read_fds); + FD_SET (ice_fd, &read_fds); + + tmout.tv_sec = 0; + tmout.tv_usec = 0; + + /* Reset this so wo can check kind after callbacks have been called by + IceProcessMessages. The smc_interact_CB sets the kind to + save_session_event, but we don't know beforehand if that callback + will be called. */ + emacs_event.kind = no_event; + + if (select (ice_fd+1, &read_fds, + (SELECT_TYPE *)0, (SELECT_TYPE *)0, &tmout) < 0) + { + ice_fd = -1; + return 0; + } + + + if (FD_ISSET (ice_fd, &read_fds)) + IceProcessMessages (SmcGetIceConnection (smc_conn), + (IceReplyWaitInfo *)0, (Bool *)0); + + + /* Check if smc_interact_CB was called and we shall generate a + save_session event. */ + if (*numchars > 0 && emacs_event.kind != no_event) + { + bcopy (&emacs_event, bufp, sizeof (struct input_event)); + bufp++; + (*numchars)--; + + return 1; + } + + return 0; +} + +/* Return non-zero if we have a connection to a session manager.*/ +int +x_session_have_connection () +{ + return ice_fd != -1; +} + +/* This is called when the session manager says it is OK to interact with the + user. Here we set the kind to save_session so an event is generated. + Then lisp code can interact with the user. */ +static void +smc_interact_CB (smcConn, clientData) + SmcConn smcConn; + SmPointer clientData; +{ + doing_interact = True; + emacs_event.kind = save_session_event; +} + +/* This is called when the session manager tells us to save ourself. + We set the required properties so the session manager can restart us, + plus the current working directory property (not mandatory) so we + are started in the correct directory. + + If this is a shutdown and we can request to interact with the user, + we do so, because we don't know what the lisp code might do. */ +static void +smc_save_yourself_CB (smcConn, + clientData, + saveType, + shutdown, + interactStyle, + fast) + SmcConn smcConn; + SmPointer clientData; + int saveType; + Bool shutdown; + int interactStyle; + Bool fast; +{ +#define NR_PROPS 5 + + SmProp *props[NR_PROPS]; + SmProp prop_ptr[NR_PROPS]; + + SmPropValue values[20]; + int val_idx = 0; + int props_idx = 0; + int has_cwd; + + char cwd[MAXPATHLEN+1]; + char user_id[16]; + + char *program; + char *smid_opt; + +#ifdef HAVE_GETCWD + has_cwd = getcwd (cwd, MAXPATHLEN+1) != 0; +#else + has_cwd = getwd (cwd) != 0; +#endif + + if (has_cwd) + program = path_search (initial_argv[0], cwd); + else + program = path_search (initial_argv[0], 0); + + /* How to start a new instance of Emacs */ + props[props_idx] = &prop_ptr[props_idx]; + props[props_idx]->name = SmCloneCommand; + props[props_idx]->type = SmLISTofARRAY8; + props[props_idx]->num_vals = 1; + props[props_idx]->vals = &values[val_idx++]; + props[props_idx]->vals[0].length = strlen (program); + props[props_idx]->vals[0].value = program; + ++props_idx; + + /* The name of the program */ + props[props_idx] = &prop_ptr[props_idx]; + props[props_idx]->name = SmProgram; + props[props_idx]->type = SmARRAY8; + props[props_idx]->num_vals = 1; + props[props_idx]->vals = &values[val_idx++]; + props[props_idx]->vals[0].length = strlen (initial_argv[0]); + props[props_idx]->vals[0].value = initial_argv[0]; + ++props_idx; + + /* How to restart Emacs (i.e.: /path/to/emacs --smid=xxxx). */ + props[props_idx] = &prop_ptr[props_idx]; + props[props_idx]->name = SmRestartCommand; + props[props_idx]->type = SmLISTofARRAY8; + props[props_idx]->num_vals = 2; /* 2 values: /path/to/emacs, --smid=xxx */ + props[props_idx]->vals = &values[val_idx]; + props[props_idx]->vals[0].length = strlen (program); + props[props_idx]->vals[0].value = program; + + smid_opt = xmalloc (strlen (SMID_OPT) + strlen (client_id) + 1); + strcpy(smid_opt, SMID_OPT); + strcat(smid_opt, client_id); + + props[props_idx]->vals[1].length = strlen (smid_opt); + props[props_idx]->vals[1].value = smid_opt; + val_idx += 2; + ++props_idx; + + /* User id */ + sprintf(user_id, "%d", getpid()); + props[props_idx] = &prop_ptr[props_idx]; + props[props_idx]->name = SmUserID; + props[props_idx]->type = SmARRAY8; + props[props_idx]->num_vals = 1; + props[props_idx]->vals = &values[val_idx++]; + props[props_idx]->vals[0].length = strlen (user_id); + props[props_idx]->vals[0].value = user_id; + ++props_idx; + + /* The current directory property, not mandatory */ + if (has_cwd) + { + props[props_idx] = &prop_ptr[props_idx]; + props[props_idx]->name = SmCurrentDirectory; + props[props_idx]->type = SmARRAY8; + props[props_idx]->num_vals = 1; + props[props_idx]->vals = &values[val_idx++]; + props[props_idx]->vals[0].length = strlen (cwd); + props[props_idx]->vals[0].value = cwd; + ++props_idx; + } + + + SmcSetProperties (smcConn, props_idx, props); + + xfree (program); + xfree (smid_opt); + + /* See if we maybe shall interact with the user. */ + if (interactStyle != SmInteractStyleAny + || ! shutdown + || saveType == SmSaveLocal + || ! SmcInteractRequest(smcConn, SmDialogNormal, smc_interact_CB, 0)) + { + /* No interaction, we are done saving ourself. */ + SmcSaveYourselfDone (smcConn, True); + } +} + +/* According to the SM specification, this shall close the connection */ +static void +smc_die_CB (smcConn, clientData) + SmcConn smcConn; + SmPointer clientData; +{ + SmcCloseConnection (smcConn, 0, 0); + ice_fd = -1; +} + +/* We don't use the next two but they are mandatory, leave them empty. + According to the SM specification, we should not interact with the + user between smc_save_yourself_CB is called and until smc_save_complete_CB + is called. It seems like a lot of job to implement this and it doesn't + even seem necessary. */ +static void +smc_save_complete_CB (smcConn, clientData) + SmcConn smcConn; + SmPointer clientData; +{ + /* Empty */ +} + +static void +smc_shutdown_cancelled_CB (smcConn, clientData) + SmcConn smcConn; + SmPointer clientData; +{ + /* Empty */ +} + +/* Error handlers for SM and ICE. We don't wan't to exit Emacs just + because there is some error in the session management. */ +static void +smc_error_handler (smcConn, + swap, + offendingMinorOpcode, + offendingSequence, + errorClass, + severity, + values) + SmcConn smcConn; + Bool swap; + int offendingMinorOpcode; + unsigned long offendingSequence; + int errorClass; + int severity; + SmPointer values; +{ + /* Empty */ +} + +static void +ice_error_handler (iceConn, + swap, + offendingMinorOpcode, + offendingSequence, + errorClass, + severity, + values) + IceConn iceConn; + Bool swap; + int offendingMinorOpcode; + unsigned long offendingSequence; + int errorClass; + int severity; + IcePointer values; +{ + /* Empty */ +} + + +static void +ice_io_error_handler (iceConn) + IceConn iceConn; +{ + /* Connection probably gone. */ + ice_fd = -1; +} + +/* This is called when the ICE connection is created or closed. The SM library + uses ICE as it transport protocol. */ +static void +ice_conn_watch_CB (iceConn, clientData, opening, watchData) + IceConn iceConn; + IcePointer clientData; + Bool opening; + IcePointer *watchData; +{ + if (! opening) + { + ice_fd = -1; + return; + } + + ice_fd = IceConnectionNumber (iceConn); +#ifndef F_SETOWN_BUG +#ifdef F_SETOWN +#ifdef F_SETOWN_SOCK_NEG + /* stdin is a socket here */ + fcntl (ice_fd, F_SETOWN, -getpid ()); +#else /* ! defined (F_SETOWN_SOCK_NEG) */ + fcntl (ice_fd, F_SETOWN, getpid ()); +#endif /* ! defined (F_SETOWN_SOCK_NEG) */ +#endif /* ! defined (F_SETOWN) */ +#endif /* F_SETOWN_BUG */ + +#ifdef SIGIO + if (interrupt_input) + init_sigio (ice_fd); +#endif /* ! defined (SIGIO) */ +} + +/* Try to open a connection to the session manager. */ +void +x_session_initialize () +{ +#define SM_ERRORSTRING_LEN 512 + char errorstring[SM_ERRORSTRING_LEN]; + char* previous_id = NULL; + SmcCallbacks callbacks; + + /* Check if we where started by the session manager. If so, we will + have a previous id. */ + if (! EQ (Vx_session_previous_id, Qnil) && STRINGP (Vx_session_previous_id)) + previous_id = XSTRING (Vx_session_previous_id)->data; + + /* The SM protocol says all callbacks are mandatory, so set up all + here and in the mask passed to SmcOpenConnection */ + callbacks.save_yourself.callback = smc_save_yourself_CB; + callbacks.save_yourself.client_data = 0; + callbacks.die.callback = smc_die_CB; + callbacks.die.client_data = 0; + callbacks.save_complete.callback = smc_save_complete_CB; + callbacks.save_complete.client_data = 0; + callbacks.shutdown_cancelled.callback = smc_shutdown_cancelled_CB; + callbacks.shutdown_cancelled.client_data = 0; + + /* Set error handlers. */ + SmcSetErrorHandler (smc_error_handler); + IceSetErrorHandler (ice_error_handler); + IceSetIOErrorHandler (ice_io_error_handler); + + /* Install callback for when connection status changes. */ + IceAddConnectionWatch (ice_conn_watch_CB, 0); + + /* Open the connection to the session manager. A failure is not + critical, it usualy means that no session manager is running. + The errorstring is here for debugging. */ + smc_conn = SmcOpenConnection (NULL, NULL, 1, 0, + (SmcSaveYourselfProcMask| + SmcDieProcMask| + SmcSaveCompleteProcMask| + SmcShutdownCancelledProcMask), + &callbacks, + previous_id, + &client_id, + SM_ERRORSTRING_LEN, + errorstring); + + if (smc_conn != 0) + Vx_session_id = make_string (client_id, strlen (client_id)); +} + + +DEFUN ("handle-save-session", Fhandle_save_session, + Shandle_save_session, 1, 1, "e", + doc: /* Handle the save_yourself event from a session manager. +A session manager can tell Emacs that the window system is shutting down +by sending Emacs a save_yourself message. Emacs executes this function when +such an event occurs. This function then executes `emacs-session-save'. +After that, this function informs the session manager that it can continue +or abort shutting down the window system depending on the return value +from `emacs-session-save' If the return value is non-nil the session manager +is told to abort the window system shutdown. + +Do not call this function yourself. */) + (event) + Lisp_Object event; +{ + /* Check doing_interact so that we don't do anything if someone called + this at the wrong time. */ + if (doing_interact) + { + Bool cancel_shutdown = False; + + cancel_shutdown = ! EQ (call0 (intern ("emacs-session-save")), Qnil); + + SmcInteractDone (smc_conn, cancel_shutdown); + SmcSaveYourselfDone (smc_conn, True); + + doing_interact = False; + } +} + +\f +/*********************************************************************** + Initialization + ***********************************************************************/ +void +syms_of_xsmfns () +{ + DEFVAR_LISP ("x-session-id", &Vx_session_id, + doc: /* The session id Emacs got from the session manager for this session. +Changing the value does not change the session id used by Emacs. +The value is nil if no session manager is running. +See also `x-session-previous-id', `emacs-save-session-functions', +`emacs-session-save' and `emacs-session-restore'." */); + Vx_session_id = Qnil; + + DEFVAR_LISP ("x-session-previous-id", &Vx_session_previous_id, + doc: /* The previous session id Emacs got from session manager. +If Emacs is running on a window system that has a session manager, the +session manager gives Emacs a session id. It is feasible for Emacs lisp +code to use the session id to save configuration in, for example, a file +with a file name based on the session id. If Emacs is running when the +window system is shut down, the session manager remembers that Emacs was +running and saves the session id Emacs had. + +When the window system is started again, the session manager restarts +Emacs and hands Emacs the session id it had the last time it was +running. This is now the previous session id and the value of this +variable. If configuration was saved in a file as stated above, the +previous session id shall be used to reconstruct the file name. + +The session id Emacs has while it is running is in the variable +`x-session-id'. The value of this variable and `x-session-id' may be the +same, depending on how the session manager works. + +See also `emacs-save-session-functions', `emacs-session-save' and +`emacs-session-restore'." */); + Vx_session_previous_id = Qnil; + + defsubr (&Shandle_save_session); +} + +#endif /* HAVE_X_SM */ Index: configure.in --- configure.in.orig Sun Jan 27 11:03:14 2002 +++ configure.in Tue Feb 26 22:48:49 2002 @@ -1915,6 +1915,21 @@ fi fi +### Use session management (-lSM -lICE) if available +HAVE_X_SM=no +if test "${HAVE_X11}" = "yes"; then + AC_CHECK_HEADER(X11/SM/SMlib.h, + AC_CHECK_LIB(SM, SmcOpenConnection, HAVE_X_SM=yes, -lICE)) + + if test "${HAVE_X_SM}" = "yes"; then + AC_DEFINE(HAVE_X_SM) + case "$LIBS" in + *-lSM*) ;; + *) LIBS="-lSM -lICE $LIBS" ;; + esac + fi +fi + # If netdb.h doesn't declare h_errno, we must declare it by hand. AC_CACHE_CHECK(whether netdb declares h_errno, emacs_cv_netdb_declares_h_errno, _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: New session management patch. 2002-02-26 22:49 ` New session management patch Jan D. @ 2002-02-27 5:51 ` Richard Stallman 2002-02-27 10:23 ` Eli Zaretskii ` (2 more replies) 0 siblings, 3 replies; 23+ messages in thread From: Richard Stallman @ 2002-02-27 5:51 UTC (permalink / raw) Cc: storm, emacs-devel +/* Return non-zero if PATH is an executable file. */ +static int +executable_file_p (path) + char *path; In GNU we don't call these things "paths", we call them file names. We use the term "path" only for a list of directories to search. Would you please change names accordingly? +/* Try to find program by searching path from environment. If not found, + the CURRENT_DIRECTORY concatenated with PROGRAM is returned. + The return value is allocated with malloc and the caller must free it. */ +static char* +path_search (program, current_directory) Why not use openp for this? Is there some reason you can't? But why do you need this anyway? Can't you get the info from Vinvocation_name and Vinvocation_directory? + if (strchr(program, PATH_SEP_CHAR) || ! (bp = getenv ("PATH"))) + return make_absolute_path (program, current_directory); Please write a space before an open paren after a function name. Likewise everywhere else. Also, the indentation there is not correct. + if (proglen+len+1 <= MAXPATHLEN) + { + char maybe[MAXPATHLEN+1]; That is an arbitrary limit, so please remove it. openp avoids having such a limit. _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: New session management patch. 2002-02-27 5:51 ` Richard Stallman @ 2002-02-27 10:23 ` Eli Zaretskii 2002-02-27 15:25 ` Andreas Schwab ` (2 more replies) 2002-02-27 19:43 ` Jan D. 2002-02-28 15:36 ` Kim F. Storm 2 siblings, 3 replies; 23+ messages in thread From: Eli Zaretskii @ 2002-02-27 10:23 UTC (permalink / raw) Cc: Jan.Djarv, storm, emacs-devel On Tue, 26 Feb 2002, Richard Stallman wrote: > + if (proglen+len+1 <= MAXPATHLEN) > + { > + char maybe[MAXPATHLEN+1]; > > That is an arbitrary limit, so please remove it. openp avoids having > such a limit. AFAIK, MAXPATHLEN is not an arbitrary limit, it's something specific to each platform. It tells how long can a file name be on that system. _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: New session management patch. 2002-02-27 10:23 ` Eli Zaretskii @ 2002-02-27 15:25 ` Andreas Schwab 2002-02-27 18:11 ` Colin Walters 2002-02-28 4:08 ` Richard Stallman 2 siblings, 0 replies; 23+ messages in thread From: Andreas Schwab @ 2002-02-27 15:25 UTC (permalink / raw) Cc: Richard Stallman, Jan.Djarv, storm, emacs-devel Eli Zaretskii <eliz@is.elta.co.il> writes: |> On Tue, 26 Feb 2002, Richard Stallman wrote: |> |> > + if (proglen+len+1 <= MAXPATHLEN) |> > + { |> > + char maybe[MAXPATHLEN+1]; |> > |> > That is an arbitrary limit, so please remove it. openp avoids having |> > such a limit. |> |> AFAIK, MAXPATHLEN is not an arbitrary limit, it's something specific to |> each platform. It tells how long can a file name be on that system. No, it's not a system limit as is, it can vary depending on file systems and directories (at least PATH_MAX can, which is the POSIX equivalent; MAXPATHLEN is actually pre-POSIX). Andreas. -- Andreas Schwab, SuSE Labs, schwab@suse.de SuSE GmbH, Deutschherrnstr. 15-19, D-90429 Nürnberg Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5 "And now for something completely different." _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: New session management patch. 2002-02-27 10:23 ` Eli Zaretskii 2002-02-27 15:25 ` Andreas Schwab @ 2002-02-27 18:11 ` Colin Walters 2002-02-28 4:08 ` Richard Stallman 2 siblings, 0 replies; 23+ messages in thread From: Colin Walters @ 2002-02-27 18:11 UTC (permalink / raw) On Wed, 2002-02-27 at 05:23, Eli Zaretskii wrote: > > On Tue, 26 Feb 2002, Richard Stallman wrote: > > > + if (proglen+len+1 <= MAXPATHLEN) > > + { > > + char maybe[MAXPATHLEN+1]; > > > > That is an arbitrary limit, so please remove it. openp avoids having > > such a limit. > > AFAIK, MAXPATHLEN is not an arbitrary limit, it's something specific to > each platform. It tells how long can a file name be on that system. It can even not exist at all; e.g. on the Hurd. _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: New session management patch. 2002-02-27 10:23 ` Eli Zaretskii 2002-02-27 15:25 ` Andreas Schwab 2002-02-27 18:11 ` Colin Walters @ 2002-02-28 4:08 ` Richard Stallman 2 siblings, 0 replies; 23+ messages in thread From: Richard Stallman @ 2002-02-28 4:08 UTC (permalink / raw) Cc: Jan.Djarv, storm, emacs-devel AFAIK, MAXPATHLEN is not an arbitrary limit, it's something specific to each platform. It tells how long can a file name be on that system. There isn't really any such limit in the system. The symbol MAXPATHLEN is just a recommended arbitrary limit for user programs to impose. However, in GNU our convention is that you shouldn't have arbitrary limits. _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: New session management patch. 2002-02-27 5:51 ` Richard Stallman 2002-02-27 10:23 ` Eli Zaretskii @ 2002-02-27 19:43 ` Jan D. 2002-02-28 18:22 ` Richard Stallman 2002-02-28 15:36 ` Kim F. Storm 2 siblings, 1 reply; 23+ messages in thread From: Jan D. @ 2002-02-27 19:43 UTC (permalink / raw) Cc: emacs-devel Richard Stallman wrote: > > +/* Return non-zero if PATH is an executable file. */ > +static int > +executable_file_p (path) > + char *path; > > In GNU we don't call these things "paths", we call them file names. > We use the term "path" only for a list of directories to search. > Would you please change names accordingly? This function will go away. But it was modeled after file_p in xrdb.c, maybe that should be changed: static int file_p (path) char *path; { ... > > +/* Try to find program by searching path from environment. If not found, > + the CURRENT_DIRECTORY concatenated with PROGRAM is returned. > + The return value is allocated with malloc and the caller must free it. */ > +static char* > +path_search (program, current_directory) > > Why not use openp for this? Is there some reason you can't? > > But why do you need this anyway? Can't you get the info > from Vinvocation_name and Vinvocation_directory? I didn't know about those. I will use Vinvocation_name and Vinvocation_directory instead, it will simplify things. Do I nead to GCPRO these before use? Are the rules for using GCPRO/UNGCPRO written down somewhere? > > + if (strchr(program, PATH_SEP_CHAR) || ! (bp = getenv ("PATH"))) > + return make_absolute_path (program, current_directory); > > Please write a space before an open paren after a function name. > Likewise everywhere else. > > Also, the indentation there is not correct. I have a conflicting rule at work, so when I switch to Emacs it comes out wrong. I will fix this. > > + if (proglen+len+1 <= MAXPATHLEN) > + { > + char maybe[MAXPATHLEN+1]; > > That is an arbitrary limit, so please remove it. openp avoids having > such a limit. Yes and no as several has pointed out. But since this will be done in a much more simpler way, the code will be removed. MAXPATHLEN is used in other places in Emacs, like buffer.c and fileio.c, that is why I used it. Jan D. _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: New session management patch. 2002-02-27 19:43 ` Jan D. @ 2002-02-28 18:22 ` Richard Stallman 0 siblings, 0 replies; 23+ messages in thread From: Richard Stallman @ 2002-02-28 18:22 UTC (permalink / raw) Cc: emacs-devel I didn't know about those. I will use Vinvocation_name and Vinvocation_directory instead, it will simplify things. Do I nead to GCPRO these before use? GCPRO is used for local variables, not for global or static ones such as these. Yes and no as several has pointed out. But since this will be done in a much more simpler way, the code will be removed. MAXPATHLEN is used in other places in Emacs, like buffer.c and fileio.c, that is why I used it. I see that MAXPATHLEN is used in fileio.c in DOS_NT conditionals. Maybe on Muckrosoft systems that limit is a hard limit in the system; if so, this code could be correct. If not, it is a bug, and someone might want to fix it, but I won't spend time on it myself. In buffer.c it is used only when building Emacs, so it is no disaster. On systems that had only getwd, there was no way to avoid this arbitrary limit, but using the newer getcwd it is possible to avoid the limit. It ought to get fixed, and that should not be too hard. _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: New session management patch. 2002-02-27 5:51 ` Richard Stallman 2002-02-27 10:23 ` Eli Zaretskii 2002-02-27 19:43 ` Jan D. @ 2002-02-28 15:36 ` Kim F. Storm 2002-03-01 1:11 ` Richard Stallman 2 siblings, 1 reply; 23+ messages in thread From: Kim F. Storm @ 2002-02-28 15:36 UTC (permalink / raw) Cc: emacs-devel "Jan D." <Jan.Djarv@mbox200.swipnet.se> writes: > ... > > I have incorporated your ideas almost verbatim, Your remark about the > problem of restore is well put. Also a default filename makes it > easier for functions to save state. > I think your patch is in very good shape now. RMS already commented on a few things, but other than that, there are only minor things I would like to suggest you change: 1) Maybe you should use [.]emacs-session.%s for the save file name rather than just [.]emacs.%s 2) The first line of the doc-string for emacs-session-save could be a little more generic, as the functionality is explained in the text, i.e. change: "Run the `emacs-save-session-functions' when window system is closing. into something like "This function is called when the window system wants emacs to terminate. If this function returns non-nil, the window system shutdown is cancelled. > But I haven't made variables for functions emacs-session-save and > emacs-session-restore. I figured that anyone can redefine the > functions if they so wish. > That is ok. Other parts of emacs "core" already calls lisp level functions in the same way. Richard Stallman <rms@gnu.org> writes: > + if (proglen+len+1 <= MAXPATHLEN) > + { > + char maybe[MAXPATHLEN+1]; > > That is an arbitrary limit, so please remove it. openp avoids having > such a limit. alloca is your friend :-) -- Kim F. Storm <storm@cua.dk> http://www.cua.dk _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: New session management patch. 2002-02-28 15:36 ` Kim F. Storm @ 2002-03-01 1:11 ` Richard Stallman 0 siblings, 0 replies; 23+ messages in thread From: Richard Stallman @ 2002-03-01 1:11 UTC (permalink / raw) Cc: Jan.Djarv, emacs-devel 1) Maybe you should use [.]emacs-session.%s for the save file name rather than just [.]emacs.%s If it is in the .emacs.d directory, then there is no need for `emacs' in the file name too. It could be just session.%s. _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Session management patch, please comment. 2002-02-20 22:50 ` Kim F. Storm 2002-02-21 19:57 ` Jan D. @ 2002-02-22 4:32 ` Richard Stallman 1 sibling, 0 replies; 23+ messages in thread From: Richard Stallman @ 2002-02-22 4:32 UTC (permalink / raw) Cc: Jan.Djarv, emacs-devel I believe the normal approach when calling lisp functions from C is to run a hook, i.e. call the function(s) bound to a variable defined in C. Not necessarily. We handle this in various ways. Sometimes a hook is useful, sometimes not. Using `special-event-map' as you do is the right approach (I think). I agree. I don't quite understand. What purpose does the emacs-session-save-function serve, why not call a lisp function directly? emacs-session-save-function would serve no purpose as far as I can see. We might as well put the code of that function directly into the function that calls it. However, to have a non-normal hook emacs-session-save-functions, a list of functions, might be useful. Various packages might add hooks to this list. _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Session management patch, please comment. 2002-02-19 20:12 ` Jan D. 2002-02-19 22:43 ` Kim F. Storm @ 2002-02-20 22:13 ` Richard Stallman 2002-02-21 20:01 ` Jan D. 1 sibling, 1 reply; 23+ messages in thread From: Richard Stallman @ 2002-02-20 22:13 UTC (permalink / raw) Cc: emacs-devel Well, actually I didn't even want this function, but I could not find another way to call C from lisp. It is not meant to be "external", rather a link between the C part and the lisp part of the session management code. It is a good idea to document it clearly anyway, even though it is not meant for general use. The doc string can say "Don't call this yourself." "End interaction as a response to save_yourself. A session manager can tell Emacs that the window system is shutting down by sending Emacs a save_yourself message. Emacs then executes functions in `save-yourself-hook'. After that, this function shall be called to inform the session manager that it can continue or abort shutting down the window system. If the argument CANCEL is non-nil, Emacs will tell the session manager to cancel the shutdown." That is good, except for "this function shall be called", which is vague. What code is supposed to call this function? How about this (a bit long perhaps): "The previous session id Emacs got from session manager. If Emacs is running on a window system that has a session manager, the session manager gives Emacs a session id. It is feasible for Emacs lisp code to use the session id to save configuration in, for example, a file with a file name based on the session id... That is good. The idea was that as functions in save-yourself-hook are executing, they might interact with the user, for instance pop up a dialog. That dialog can have the possibility to cancel the whole window system shutdown. If the lisp code wants to do that, it shall set this variable to something non-nil. Please document that clearly (but don't use "shall"). _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Session management patch, please comment. 2002-02-20 22:13 ` Richard Stallman @ 2002-02-21 20:01 ` Jan D. 0 siblings, 0 replies; 23+ messages in thread From: Jan D. @ 2002-02-21 20:01 UTC (permalink / raw) Cc: emacs-devel > Well, actually I didn't even want this function, but I could not find > another way to call C from lisp. It is not meant to be "external", > rather a link between the C part and the lisp part of the session > management code. > > It is a good idea to document it clearly anyway, even though it is not > meant for general use. The doc string can say "Don't call this > yourself." > > "End interaction as a response to save_yourself. > A session manager can tell Emacs that the window system is shutting down > by sending Emacs a save_yourself message. Emacs then executes functions > in `save-yourself-hook'. After that, this function shall be called to > inform the session manager that it can continue or abort shutting down > the window system. > > If the argument CANCEL is non-nil, Emacs will tell the session manager > to cancel the shutdown." > > That is good, except for "this function shall be called", which is vague. > What code is supposed to call this function? Yes, that wasn't so good. I will fix that, or if I get the approach suggested by Kim Storm to work, remove this function. > The idea was that as functions in save-yourself-hook are executing, they > might interact with the user, for instance pop up a dialog. That dialog > can have the possibility to cancel the whole window system shutdown. If > the lisp code wants to do that, it shall set this variable to something > non-nil. > > Please document that clearly (but don't use "shall"). I will do that. I guess I've been reading too many ISO-standards lately, thus the "shall" :-) Jan D. _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2002-03-01 1:11 UTC | newest] Thread overview: 23+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2002-02-17 19:11 Session management patch, please comment Jan D. 2002-02-19 6:37 ` Richard Stallman 2002-02-19 8:40 ` Kim F. Storm 2002-02-19 20:13 ` Jan D. 2002-02-19 20:12 ` Jan D. 2002-02-19 22:43 ` Kim F. Storm 2002-02-20 20:29 ` Jan Djärv 2002-02-20 22:50 ` Kim F. Storm 2002-02-21 19:57 ` Jan D. 2002-02-21 21:18 ` Kim F. Storm 2002-02-26 22:49 ` New session management patch Jan D. 2002-02-27 5:51 ` Richard Stallman 2002-02-27 10:23 ` Eli Zaretskii 2002-02-27 15:25 ` Andreas Schwab 2002-02-27 18:11 ` Colin Walters 2002-02-28 4:08 ` Richard Stallman 2002-02-27 19:43 ` Jan D. 2002-02-28 18:22 ` Richard Stallman 2002-02-28 15:36 ` Kim F. Storm 2002-03-01 1:11 ` Richard Stallman 2002-02-22 4:32 ` Session management patch, please comment Richard Stallman 2002-02-20 22:13 ` Richard Stallman 2002-02-21 20:01 ` Jan D.
Code repositories for project(s) associated with this external index https://git.savannah.gnu.org/cgit/emacs.git https://git.savannah.gnu.org/cgit/emacs/org-mode.git This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.