unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* 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  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  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 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-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 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-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

* 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

* 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

* 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  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 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 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-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-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

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 public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).