emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Session management patch, please comment.


From: Jan D.
Subject: Session management patch, please comment.
Date: Sun, 17 Feb 2002 20:11:37 +0100 (CET)

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;
+ }
+ 
+ 
+ /***********************************************************************
+                           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))
+ 
  
  ;;
  ;; 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,



reply via email to

[Prev in Thread] Current Thread [Next in Thread]