mirror of
https://github.com/Stichting-MINIX-Research-Foundation/xsrc.git
synced 2025-09-24 04:03:13 -04:00
1167 lines
32 KiB
C
1167 lines
32 KiB
C
/*****************************************************************************/
|
|
/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
|
|
/** Salt Lake City, Utah **/
|
|
/** Portions Copyright 1989 by the Massachusetts Institute of Technology **/
|
|
/** Cambridge, Massachusetts **/
|
|
/** **/
|
|
/** All Rights Reserved **/
|
|
/** **/
|
|
/** Permission to use, copy, modify, and distribute this software and **/
|
|
/** its documentation for any purpose and without fee is hereby **/
|
|
/** granted, provided that the above copyright notice appear in all **/
|
|
/** copies and that both that copyright notice and this permis- **/
|
|
/** sion notice appear in supporting documentation, and that the **/
|
|
/** names of Evans & Sutherland and M.I.T. not be used in advertising **/
|
|
/** in publicity pertaining to distribution of the software without **/
|
|
/** specific, written prior permission. **/
|
|
/** **/
|
|
/** EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD **/
|
|
/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
|
|
/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND OR **/
|
|
/** M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
|
|
/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
|
|
/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
|
|
/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
|
|
/** OR PERFORMANCE OF THIS SOFTWARE. **/
|
|
/*****************************************************************************/
|
|
/*
|
|
* [ ctwm ]
|
|
*
|
|
* Copyright 1992 Claude Lecommandeur.
|
|
*
|
|
* Permission to use, copy, modify and distribute this software [ctwm] and
|
|
* its documentation for any purpose is hereby granted without fee, provided
|
|
* that the above copyright notice appear in all copies and that both that
|
|
* copyright notice and this permission notice appear in supporting documen-
|
|
* tation, and that the name of Claude Lecommandeur not be used in adverti-
|
|
* sing or publicity pertaining to distribution of the software without
|
|
* specific, written prior permission. Claude Lecommandeur make no represen-
|
|
* tations about the suitability of this software for any purpose. It is
|
|
* provided "as is" without express or implied warranty.
|
|
*
|
|
* Claude Lecommandeur DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
|
|
* EVENT SHALL Claude Lecommandeur BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
|
|
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
* Author: Claude Lecommandeur [ lecom@sic.epfl.ch ][ April 1992 ]
|
|
*/
|
|
|
|
/*********************************************************************
|
|
*
|
|
* This module has been modified by
|
|
* Matthew McNeill (21 Mar 1997) - University of Durham (UK)
|
|
* for the support of the X Session Management Protocol
|
|
*
|
|
*********************************************************************
|
|
*
|
|
* Copyright (c) 1996-1997 The University of Durham, UK -
|
|
* Department of Computer Science.
|
|
* All rights reserved.
|
|
*
|
|
* Permission is hereby granted, without written agreement and without
|
|
* licence or royalty fees, to use, copy, modify, and distribute this
|
|
* software and its documentation, provided that usage, copying, modification
|
|
* or distribution is not for direct commercial advantage and that the
|
|
* above copyright notice and the following two paragraphs appear in
|
|
* all copies of this software. To use, copy, modify or distribute this
|
|
* software and its documentation otherwise requires a fee and/or specific
|
|
* permission.
|
|
*
|
|
* IN NO EVENT SHALL THE UNIVERSITY OF DURHAM BE LIABLE TO ANY PARTY FOR
|
|
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
|
|
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
|
|
* DURHAM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* THE UNIVERSITY OF DURHAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
|
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
|
* ON AN "AS IS" BASIS, AND THE UNIVERSITY OF DURHAM HAS NO OBLIGATION TO
|
|
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
*
|
|
********************************************************************/
|
|
|
|
/**********************************************************************
|
|
*
|
|
* $XConsortium: session.c,v 1.18 95/01/04 22:28:37 mor Exp $
|
|
*
|
|
* Session support for the X11R6 XSMP (X Session Management Protocol)
|
|
*
|
|
* 95/01/04 Ralph Mor, X Consortium Initial Version.
|
|
*
|
|
* Do the necessary modification to be integrated in ctwm.
|
|
* Can no longer be used for the standard twm.
|
|
*
|
|
* 21 Mar 1997 Matthew McNeill, Durham University Modified Version.
|
|
*
|
|
**********************************************************************/
|
|
|
|
#include <X11/Xos.h>
|
|
|
|
#ifndef X_NOT_POSIX
|
|
#ifdef _POSIX_SOURCE
|
|
#include <limits.h>
|
|
#else
|
|
#define _POSIX_SOURCE
|
|
#include <limits.h>
|
|
#undef _POSIX_SOURCE
|
|
#endif
|
|
#endif /* X_NOT_POSIX */
|
|
#ifndef PATH_MAX
|
|
#include <sys/param.h>
|
|
#ifndef PATH_MAX
|
|
#ifdef MAXPATHLEN
|
|
#define PATH_MAX MAXPATHLEN
|
|
#else
|
|
#define PATH_MAX 1024
|
|
#endif
|
|
#endif
|
|
#endif /* PATH_MAX */
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xatom.h>
|
|
#include <stdio.h>
|
|
#include "twm.h"
|
|
#include "icons.h"
|
|
#include "screen.h"
|
|
#include "session.h"
|
|
|
|
SmcConn smcConn = NULL;
|
|
XtInputId iceInputId;
|
|
char *twm_clientId;
|
|
TWMWinConfigEntry *winConfigHead = NULL;
|
|
Bool gotFirstSave = 0;
|
|
Bool sent_save_done = 0;
|
|
|
|
#define SAVEFILE_VERSION 2
|
|
|
|
|
|
/*===[ Get Client SM_CLIENT_ID ]=============================================*/
|
|
|
|
char *GetClientID (Window window)
|
|
/* This function returns the value of the session manager client ID property
|
|
* given a valid window handle. If no such property exists on a window then
|
|
* null is returned
|
|
*/
|
|
{
|
|
char *client_id = NULL;
|
|
Window client_leader;
|
|
XTextProperty tp;
|
|
Atom actual_type;
|
|
int actual_format;
|
|
unsigned long nitems;
|
|
unsigned long bytes_after;
|
|
Window *prop = NULL;
|
|
|
|
if (XGetWindowProperty (dpy, window, _XA_WM_CLIENT_LEADER,
|
|
0L, 1L, False, AnyPropertyType, &actual_type, &actual_format,
|
|
&nitems, &bytes_after, (unsigned char **)&prop) == Success)
|
|
{
|
|
if (actual_type == XA_WINDOW && actual_format == 32 &&
|
|
nitems == 1 && bytes_after == 0)
|
|
{
|
|
client_leader = *prop;
|
|
|
|
if (XGetTextProperty (dpy, client_leader, &tp, _XA_SM_CLIENT_ID))
|
|
{
|
|
if (tp.encoding == XA_STRING &&
|
|
tp.format == 8 && tp.nitems != 0)
|
|
client_id = (char *) tp.value;
|
|
}
|
|
}
|
|
|
|
if (prop)
|
|
XFree (prop);
|
|
}
|
|
|
|
return client_id;
|
|
}
|
|
|
|
/*===[ Get Window Role ]=====================================================*/
|
|
|
|
char *GetWindowRole (Window window)
|
|
/* this function returns the WM_WINDOW_ROLE property of a window
|
|
*/
|
|
{
|
|
XTextProperty tp;
|
|
|
|
if (XGetTextProperty (dpy, window, &tp, _XA_WM_WINDOW_ROLE))
|
|
{
|
|
if (tp.encoding == XA_STRING && tp.format == 8 && tp.nitems != 0)
|
|
return ((char *) tp.value);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*===[ Various file write procedures ]=======================================*/
|
|
|
|
static int write_byte (FILE *file, unsigned char b)
|
|
{
|
|
if (fwrite ((char *) &b, 1, 1, file) != 1)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static int write_ushort (FILE *file, unsigned short s)
|
|
{
|
|
unsigned char file_short[2];
|
|
|
|
file_short[0] = (s & (unsigned)0xff00) >> 8;
|
|
file_short[1] = s & 0xff;
|
|
if (fwrite ((char *) file_short, (int) sizeof (file_short), 1, file) != 1)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static int write_short (FILE *file, short s)
|
|
{
|
|
unsigned char file_short[2];
|
|
|
|
file_short[0] = (s & (unsigned)0xff00) >> 8;
|
|
file_short[1] = s & 0xff;
|
|
if (fwrite ((char *) file_short, (int) sizeof (file_short), 1, file) != 1)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* Matthew McNeill Feb 1997 - required to save the occupation state as an
|
|
* integer.
|
|
*/
|
|
|
|
static int write_int (FILE *file, int i)
|
|
{
|
|
unsigned char file_int[4];
|
|
|
|
file_int[0] = (i & (unsigned)0xff000000) >> 24;
|
|
file_int[1] = (i & (unsigned)0x00ff0000) >> 16;
|
|
file_int[2] = (i & (unsigned)0x0000ff00) >> 8;
|
|
file_int[3] = (i & (unsigned)0x000000ff);
|
|
if (fwrite ((char *) file_int, (int) sizeof (file_int), 1, file) != 1)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static int write_counted_string (FILE *file, char *string)
|
|
{
|
|
if (string)
|
|
{
|
|
unsigned char count = strlen (string);
|
|
|
|
if (write_byte (file, count) == 0)
|
|
return 0;
|
|
if (fwrite (string, (int) sizeof (char), (int) count, file) != count)
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
if (write_byte (file, 0) == 0)
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*===[ various file read procedures ]========================================*/
|
|
|
|
static int read_byte (FILE *file, unsigned char *bp)
|
|
{
|
|
if (fread ((char *) bp, 1, 1, file) != 1)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static int read_ushort (FILE *file, unsigned short *shortp)
|
|
{
|
|
unsigned char file_short[2];
|
|
|
|
if (fread ((char *) file_short, (int) sizeof (file_short), 1, file) != 1)
|
|
return 0;
|
|
*shortp = file_short[0] * 256 + file_short[1];
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static int read_short (FILE *file, short *shortp)
|
|
{
|
|
unsigned char file_short[2];
|
|
|
|
if (fread ((char *) file_short, (int) sizeof (file_short), 1, file) != 1)
|
|
return 0;
|
|
*shortp = file_short[0] * 256 + file_short[1];
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* Matthew McNeill Feb 1997 - required to save the occupation state as an
|
|
* integer.
|
|
*/
|
|
|
|
static int read_int (FILE *file, int *intp)
|
|
{
|
|
unsigned char file_int[4];
|
|
|
|
if (fread ((char *) file_int, (int) sizeof (file_int), 1, file) != 1)
|
|
return 0;
|
|
*intp = (((int) file_int[0]) << 24) & 0xff000000;
|
|
*intp += (((int) file_int[1]) << 16) & 0x00ff0000;
|
|
*intp += (((int) file_int[2]) << 8) & 0x0000ff00;
|
|
*intp += ((int) file_int[3]);
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static int read_counted_string (FILE *file, char **stringp)
|
|
{
|
|
unsigned char len;
|
|
char *data;
|
|
|
|
if (read_byte (file, &len) == 0)
|
|
return 0;
|
|
if (len == 0) {
|
|
data = 0;
|
|
} else {
|
|
data = malloc ((unsigned) len + 1);
|
|
if (!data)
|
|
return 0;
|
|
if (fread (data, (int) sizeof (char), (int) len, file) != len) {
|
|
free (data);
|
|
return 0;
|
|
}
|
|
data[len] = '\0';
|
|
}
|
|
*stringp = data;
|
|
return 1;
|
|
}
|
|
|
|
/*===[ Definition of a window config entry ]===================================
|
|
*
|
|
* An entry in the saved window config file looks like this:
|
|
*
|
|
* FIELD BYTES
|
|
* ----- ----
|
|
* SM_CLIENT_ID ID len 1 (may be 0)
|
|
* SM_CLIENT_ID LIST of bytes (may be NULL)
|
|
*
|
|
* WM_WINDOW_ROLE length 1 (may be 0)
|
|
* WM_WINDOW_ROLE LIST of bytes (may be NULL)
|
|
*
|
|
* if no WM_WINDOW_ROLE (length = 0)
|
|
*
|
|
* WM_CLASS "res name" length 1
|
|
* WM_CLASS "res name" LIST of bytes
|
|
* WM_CLASS "res class" length 1
|
|
* WM_CLASS "res class" LIST of bytes
|
|
* WM_NAME length 1 (0 if name changed)
|
|
* WM_NAME LIST of bytes
|
|
* WM_COMMAND arg count 1 (0 if no SM_CLIENT_ID)
|
|
* For each arg in WM_COMMAND
|
|
* arg length 1
|
|
* arg LIST of bytes
|
|
*
|
|
* Iconified bool 1
|
|
* Icon info present bool 1
|
|
*
|
|
* if icon info present
|
|
* icon x 2
|
|
* icon y 2
|
|
*
|
|
* Geom x 2
|
|
* Geom y 2
|
|
* Geom width 2
|
|
* Geom height 2
|
|
*
|
|
* Width ever changed by user 1
|
|
* Height ever changed by user 1
|
|
*
|
|
* ------------------[ Matthew McNeill Feb 1997 ]----------------------------
|
|
*
|
|
* Workspace Occupation 4
|
|
*
|
|
*/
|
|
|
|
|
|
/*===[ Write Window Config Entry to file ]===================================*/
|
|
|
|
int WriteWinConfigEntry (FILE *configFile, TwmWindow *theWindow,
|
|
char *clientId, char *windowRole)
|
|
/* this function writes a window configuration entry of a given window to
|
|
* the given configuration file
|
|
*/
|
|
{
|
|
char **wm_command;
|
|
int wm_command_count, i;
|
|
|
|
/* ...unless the config file says otherwise. */
|
|
if (LookInList (Scr == NULL ? ScreenList [0]->DontSave : Scr->DontSave,
|
|
theWindow->full_name, &theWindow->class))
|
|
return 1;
|
|
|
|
if (!write_counted_string (configFile, clientId))
|
|
return 0;
|
|
|
|
if (!write_counted_string (configFile, windowRole))
|
|
return 0;
|
|
|
|
if (!windowRole)
|
|
{
|
|
if (!write_counted_string (configFile, theWindow->class.res_name))
|
|
return 0;
|
|
if (!write_counted_string (configFile, theWindow->class.res_class))
|
|
return 0;
|
|
if (theWindow->nameChanged)
|
|
{
|
|
/*
|
|
* If WM_NAME changed on this window, we can't use it as
|
|
* a criteria for looking up window configurations. See the
|
|
* longer explanation in the GetWindowConfig() function below.
|
|
*/
|
|
|
|
if (!write_counted_string (configFile, NULL))
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
if (!write_counted_string (configFile, theWindow->name))
|
|
return 0;
|
|
}
|
|
|
|
wm_command = NULL;
|
|
wm_command_count = 0;
|
|
XGetCommand (dpy, theWindow->w, &wm_command, &wm_command_count);
|
|
|
|
if (clientId || !wm_command || wm_command_count == 0)
|
|
{
|
|
if (!write_byte (configFile, 0))
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
if (!write_byte (configFile, (char) wm_command_count))
|
|
return 0;
|
|
for (i = 0; i < wm_command_count; i++)
|
|
if (!write_counted_string (configFile, wm_command[i]))
|
|
return 0;
|
|
XFreeStringList (wm_command);
|
|
}
|
|
}
|
|
|
|
/* ===================[ Matthew McNeill Feb 1997 ]========================= *
|
|
* there has been a structural change to TwmWindow in ctwm. The Icon information
|
|
* is in a sub-structure now. The presence of icon information is not indicative
|
|
* of its current state. There is a new boolean condition for this (isicon)
|
|
*/
|
|
|
|
if (!write_byte (configFile, theWindow->isicon ? 1 : 0)) return 0; /* iconified */
|
|
|
|
/* ===================[ Matthew McNeill Feb 1997 ]========================= *
|
|
* there has been a structural change to TwmWindow in ctwm. The Icon information
|
|
* is in a sub-structure now, if there is no icon, this sub-structure does
|
|
* not exist and the attempted access (below) causes a core dump.
|
|
* we need to check that the structure exists before trying to access it
|
|
*/
|
|
if (theWindow->icon)
|
|
{
|
|
if (!write_byte (configFile, theWindow->icon->w ? 1 : 0)) return 0; /* icon info exists */
|
|
if (theWindow->icon->w)
|
|
{
|
|
int icon_x, icon_y;
|
|
XGetGeometry (dpy, theWindow->icon->w, &JunkRoot, &icon_x,
|
|
&icon_y, &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth);
|
|
if (!write_short (configFile, (short) icon_x)) return 0;
|
|
if (!write_short (configFile, (short) icon_y)) return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!write_byte (configFile, 0)) return 0; /* icon does not have any information */
|
|
}
|
|
/* ======================================================================= */
|
|
|
|
if (!write_short (configFile, (short) theWindow->frame_x))
|
|
return 0;
|
|
if (!write_short (configFile, (short) theWindow->frame_y))
|
|
return 0;
|
|
if (!write_ushort (configFile, (unsigned short) theWindow->attr.width))
|
|
return 0;
|
|
if (!write_ushort (configFile, (unsigned short) theWindow->attr.height))
|
|
return 0;
|
|
if (!write_byte (configFile, theWindow->widthEverChangedByUser ? 1 : 0))
|
|
return 0;
|
|
if (!write_byte (configFile, theWindow->heightEverChangedByUser ? 1 : 0))
|
|
return 0;
|
|
|
|
/* ===================[ Matthew McNeill Feb 1997 ]=======================*
|
|
* write an extra piece of information to the file, this is the occupation
|
|
* number and is a bit field of the workspaces occupied by the client.
|
|
*/
|
|
|
|
if (!write_int (configFile, theWindow->occupation))
|
|
return 0;
|
|
|
|
/* ======================================================================*/
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*===[ Read Window Configuration Entry ]=====================================*/
|
|
|
|
int ReadWinConfigEntry (FILE *configFile, unsigned short version,
|
|
TWMWinConfigEntry **pentry)
|
|
/* this function reads the next window configuration entry from the given file
|
|
* else it returns FALSE if none exists or there is a problem
|
|
*/
|
|
{
|
|
TWMWinConfigEntry *entry;
|
|
unsigned char byte;
|
|
int i;
|
|
|
|
*pentry = entry = (TWMWinConfigEntry *) malloc (
|
|
sizeof (TWMWinConfigEntry));
|
|
if (!*pentry)
|
|
return 0;
|
|
|
|
entry->tag = 0;
|
|
entry->client_id = NULL;
|
|
entry->window_role = NULL;
|
|
entry->class.res_name = NULL;
|
|
entry->class.res_class = NULL;
|
|
entry->wm_name = NULL;
|
|
entry->wm_command = NULL;
|
|
entry->wm_command_count = 0;
|
|
|
|
if (!read_counted_string (configFile, &entry->client_id))
|
|
goto give_up;
|
|
|
|
if (!read_counted_string (configFile, &entry->window_role))
|
|
goto give_up;
|
|
|
|
if (!entry->window_role)
|
|
{
|
|
if (!read_counted_string (configFile, &entry->class.res_name))
|
|
goto give_up;
|
|
if (!read_counted_string (configFile, &entry->class.res_class))
|
|
goto give_up;
|
|
if (!read_counted_string (configFile, &entry->wm_name))
|
|
goto give_up;
|
|
|
|
if (!read_byte (configFile, &byte))
|
|
goto give_up;
|
|
entry->wm_command_count = byte;
|
|
|
|
if (entry->wm_command_count == 0)
|
|
entry->wm_command = NULL;
|
|
else
|
|
{
|
|
entry->wm_command = (char **) malloc (entry->wm_command_count *
|
|
sizeof (char *));
|
|
|
|
if (!entry->wm_command)
|
|
goto give_up;
|
|
|
|
for (i = 0; i < entry->wm_command_count; i++)
|
|
if (!read_counted_string (configFile, &entry->wm_command[i]))
|
|
goto give_up;
|
|
}
|
|
}
|
|
|
|
if (!read_byte (configFile, &byte))
|
|
goto give_up;
|
|
|
|
entry->iconified = byte;
|
|
|
|
if (!read_byte (configFile, &byte))
|
|
goto give_up;
|
|
|
|
entry->icon_info_present = byte;
|
|
|
|
if (entry->icon_info_present)
|
|
{
|
|
if (!read_short (configFile, (short *) &entry->icon_x))
|
|
goto give_up;
|
|
if (!read_short (configFile, (short *) &entry->icon_y))
|
|
goto give_up;
|
|
}
|
|
|
|
if (!read_short (configFile, (short *) &entry->x))
|
|
goto give_up;
|
|
if (!read_short (configFile, (short *) &entry->y))
|
|
goto give_up;
|
|
if (!read_ushort (configFile, &entry->width))
|
|
goto give_up;
|
|
if (!read_ushort (configFile, &entry->height))
|
|
goto give_up;
|
|
|
|
if (version > 1)
|
|
{
|
|
if (!read_byte (configFile, &byte))
|
|
goto give_up;
|
|
entry->width_ever_changed_by_user = byte;
|
|
|
|
if (!read_byte (configFile, &byte))
|
|
goto give_up;
|
|
entry->height_ever_changed_by_user = byte;
|
|
}
|
|
else
|
|
{
|
|
entry->width_ever_changed_by_user = False;
|
|
entry->height_ever_changed_by_user = False;
|
|
}
|
|
|
|
/* ===================[ Matthew McNeill Feb 1997 ]======================= *
|
|
* read in the occupation information to restore the windows to the
|
|
* correct workspaces.
|
|
*/
|
|
|
|
if (!read_int (configFile, &entry->occupation))
|
|
goto give_up;
|
|
|
|
/* ====================================================================== */
|
|
|
|
return 1;
|
|
|
|
give_up:
|
|
|
|
if (entry->client_id)
|
|
free (entry->client_id);
|
|
if (entry->window_role)
|
|
free (entry->window_role);
|
|
if (entry->class.res_name)
|
|
free (entry->class.res_name);
|
|
if (entry->class.res_class)
|
|
free (entry->class.res_class);
|
|
if (entry->wm_name)
|
|
free (entry->wm_name);
|
|
if (entry->wm_command_count)
|
|
{
|
|
for (i = 0; i < entry->wm_command_count; i++)
|
|
if (entry->wm_command[i])
|
|
free (entry->wm_command[i]);
|
|
}
|
|
if (entry->wm_command)
|
|
free ((char *) entry->wm_command);
|
|
|
|
free ((char *) entry);
|
|
*pentry = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*===[ Read In Win Config File ]=============================================*/
|
|
|
|
void ReadWinConfigFile (char *filename)
|
|
/* this function reads the window configuration file and stores the information
|
|
* in a data structure which is returned
|
|
*/
|
|
{
|
|
FILE *configFile;
|
|
TWMWinConfigEntry *entry;
|
|
int done = 0;
|
|
unsigned short version;
|
|
|
|
configFile = fopen (filename, "rb");
|
|
if (!configFile)
|
|
return;
|
|
|
|
if (!read_ushort (configFile, &version) ||
|
|
version > SAVEFILE_VERSION)
|
|
{
|
|
done = 1;
|
|
}
|
|
|
|
while (!done)
|
|
{
|
|
if (ReadWinConfigEntry (configFile, version, &entry))
|
|
{
|
|
entry->next = winConfigHead;
|
|
winConfigHead = entry;
|
|
}
|
|
else
|
|
done = 1;
|
|
}
|
|
|
|
fclose (configFile);
|
|
}
|
|
|
|
/*===[ Get Window Configuration ]============================================*
|
|
* Matthew McNeill Feb 1997 - added extra parameter (occupation) to return
|
|
* restored occupation of the window
|
|
*/
|
|
|
|
int GetWindowConfig (TwmWindow *theWindow, short *x, short *y,
|
|
unsigned short *width, unsigned short *height,
|
|
Bool *iconified, Bool *icon_info_present,
|
|
short *icon_x, short *icon_y,
|
|
Bool *width_ever_changed_by_user,
|
|
Bool *height_ever_changed_by_user,
|
|
int *occupation) /* <== [ Matthew McNeill Feb 1997 ] == */
|
|
/* This function attempts to extract all the relevant information from the
|
|
* given window and return values via the rest of the parameters to the
|
|
* function
|
|
*/
|
|
{
|
|
char *clientId, *windowRole;
|
|
TWMWinConfigEntry *ptr;
|
|
int found = 0;
|
|
|
|
ptr = winConfigHead;
|
|
|
|
if (!ptr)
|
|
return 0;
|
|
|
|
clientId = GetClientID (theWindow->w);
|
|
windowRole = GetWindowRole (theWindow->w);
|
|
|
|
while (ptr && !found)
|
|
{
|
|
int client_id_match = (!clientId && !ptr->client_id) ||
|
|
(clientId && ptr->client_id &&
|
|
strcmp (clientId, ptr->client_id) == 0);
|
|
|
|
if (!ptr->tag && client_id_match)
|
|
{
|
|
if (windowRole || ptr->window_role)
|
|
{
|
|
found = (windowRole && ptr->window_role &&
|
|
strcmp (windowRole, ptr->window_role) == 0);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Compare WM_CLASS + only compare WM_NAME if the
|
|
* WM_NAME in the saved file is non-NULL. If the
|
|
* WM_NAME in the saved file is NULL, this means that
|
|
* the client changed the value of WM_NAME during the
|
|
* session, and we can not use it as a criteria for
|
|
* our search. For example, with xmh, at save time
|
|
* the window name might be "xmh: folderY". However,
|
|
* if xmh does not properly restore state when it is
|
|
* restarted, the initial window name might be
|
|
* "xmh: folderX". This would cause the window manager
|
|
* to fail in finding the saved window configuration.
|
|
* The best we can do is ignore WM_NAME if its value
|
|
* changed in the previous session.
|
|
*/
|
|
|
|
if (strcmp (theWindow->class.res_name,
|
|
ptr->class.res_name) == 0 &&
|
|
strcmp (theWindow->class.res_class,
|
|
ptr->class.res_class) == 0 &&
|
|
(ptr->wm_name == NULL ||
|
|
strcmp (theWindow->name, ptr->wm_name) == 0))
|
|
{
|
|
if (clientId)
|
|
{
|
|
/*
|
|
* If a client ID was present, we should not check
|
|
* WM_COMMAND because Xt will put a -xtsessionID arg
|
|
* on the command line.
|
|
*/
|
|
|
|
found = 1;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* For non-XSMP clients, also check WM_COMMAND.
|
|
*/
|
|
|
|
char **wm_command = NULL;
|
|
int wm_command_count = 0, i;
|
|
|
|
XGetCommand (dpy, theWindow->w,
|
|
&wm_command, &wm_command_count);
|
|
|
|
if (wm_command_count == ptr->wm_command_count)
|
|
{
|
|
for (i = 0; i < wm_command_count; i++)
|
|
if (strcmp (wm_command[i],
|
|
ptr->wm_command[i]) != 0)
|
|
break;
|
|
|
|
if (i == wm_command_count)
|
|
found = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
ptr = ptr->next;
|
|
}
|
|
|
|
if (found)
|
|
{
|
|
*x = ptr->x;
|
|
*y = ptr->y;
|
|
*width = ptr->width;
|
|
*height = ptr->height;
|
|
*iconified = ptr->iconified;
|
|
*icon_info_present = ptr->icon_info_present;
|
|
*width_ever_changed_by_user = ptr->width_ever_changed_by_user;
|
|
*height_ever_changed_by_user = ptr->height_ever_changed_by_user;
|
|
|
|
if (*icon_info_present)
|
|
{
|
|
*icon_x = ptr->icon_x;
|
|
*icon_y = ptr->icon_y;
|
|
}
|
|
|
|
*occupation = ptr->occupation; /* <== [ Matthew McNeill Feb 1997 ] == */
|
|
|
|
ptr->tag = 1;
|
|
}
|
|
else
|
|
*iconified = 0;
|
|
|
|
if (clientId)
|
|
XFree (clientId);
|
|
|
|
if (windowRole)
|
|
XFree (windowRole);
|
|
|
|
return found;
|
|
}
|
|
|
|
/*===[ Unique Filename Generator ]===========================================*/
|
|
|
|
static char *unique_filename (char *path, char *prefix)
|
|
/* this function attempts to allocate a temporary filename to store the
|
|
* information of the windows
|
|
*/
|
|
{
|
|
|
|
#ifndef X_NOT_POSIX
|
|
return ((char *) tempnam (path, prefix));
|
|
#else
|
|
char tempFile[PATH_MAX];
|
|
char *tmp;
|
|
|
|
sprintf (tempFile, "%s/%sXXXXXX", path, prefix);
|
|
tmp = (char *) mktemp (tempFile);
|
|
if (tmp)
|
|
{
|
|
char *ptr = (char *) malloc (strlen (tmp) + 1);
|
|
strcpy (ptr, tmp);
|
|
return (ptr);
|
|
}
|
|
else
|
|
return (NULL);
|
|
#endif
|
|
}
|
|
|
|
/*===[ SAVE WINDOW INFORMATION ]=============================================*/
|
|
|
|
#ifndef PATH_MAX
|
|
# define PATH_MAX 1023
|
|
#endif
|
|
|
|
void SaveYourselfPhase2CB (SmcConn smcCon, SmPointer clientData)
|
|
/* this is where all the work is done in saving the state of the windows.
|
|
* it is not done in Phase One because phase one is used for the other clients
|
|
* to make sure that all the property information on their windows is correct
|
|
* and up to date
|
|
*/
|
|
{
|
|
int scrnum;
|
|
ScreenInfo *theScreen;
|
|
TwmWindow *theWindow;
|
|
char *clientId, *windowRole;
|
|
FILE *configFile = NULL;
|
|
char *path;
|
|
char *filename = NULL;
|
|
Bool success = False;
|
|
SmProp prop1, prop2, prop3, *props[3];
|
|
SmPropValue prop1val, prop2val, prop3val;
|
|
char discardCommand[PATH_MAX + 4];
|
|
int numVals, i;
|
|
static int first_time = 1;
|
|
|
|
if (first_time)
|
|
{
|
|
char userId[20];
|
|
char hint = SmRestartIfRunning;
|
|
|
|
prop1.name = SmProgram;
|
|
prop1.type = SmARRAY8;
|
|
prop1.num_vals = 1;
|
|
prop1.vals = &prop1val;
|
|
prop1val.value = Argv[0];
|
|
prop1val.length = strlen (Argv[0]);
|
|
|
|
sprintf (userId, "%d", getuid());
|
|
prop2.name = SmUserID;
|
|
prop2.type = SmARRAY8;
|
|
prop2.num_vals = 1;
|
|
prop2.vals = &prop2val;
|
|
prop2val.value = (SmPointer) userId;
|
|
prop2val.length = strlen (userId);
|
|
|
|
prop3.name = SmRestartStyleHint;
|
|
prop3.type = SmCARD8;
|
|
prop3.num_vals = 1;
|
|
prop3.vals = &prop3val;
|
|
prop3val.value = (SmPointer) &hint;
|
|
prop3val.length = 1;
|
|
|
|
props[0] = &prop1;
|
|
props[1] = &prop2;
|
|
props[2] = &prop3;
|
|
|
|
SmcSetProperties (smcCon, 3, props);
|
|
|
|
first_time = 0;
|
|
}
|
|
|
|
path = getenv ("SM_SAVE_DIR");
|
|
if (!path)
|
|
{
|
|
path = getenv ("HOME");
|
|
if (!path)
|
|
path = ".";
|
|
}
|
|
/*==============[ Matthew McNeill Feb 1997 ]==============*
|
|
* changed the unique name to CTWM rather than TWM
|
|
* this is tidier and more functional and prevents
|
|
* TWM picking up CTWM config files. The format is
|
|
* no longer the same since the new format supports
|
|
* virtaul workspaces.
|
|
*========================================================*/
|
|
if ((filename = unique_filename (path, ".ctwm")) == NULL)
|
|
goto bad;
|
|
|
|
if (!(configFile = fopen (filename, "wb"))) /* wb = write bytes ? */
|
|
goto bad;
|
|
|
|
if (!write_ushort (configFile, SAVEFILE_VERSION))
|
|
goto bad;
|
|
|
|
success = True;
|
|
|
|
for (scrnum = 0; scrnum < NumScreens && success; scrnum++)
|
|
{
|
|
if (ScreenList[scrnum] != NULL)
|
|
{
|
|
theScreen = ScreenList[scrnum];
|
|
theWindow = theScreen->FirstWindow;
|
|
|
|
while (theWindow && success)
|
|
{
|
|
clientId = GetClientID (theWindow->w);
|
|
windowRole = GetWindowRole (theWindow->w);
|
|
|
|
if (!WriteWinConfigEntry (configFile, theWindow,
|
|
clientId, windowRole))
|
|
success = False;
|
|
|
|
if (clientId)
|
|
XFree (clientId);
|
|
|
|
if (windowRole)
|
|
XFree (windowRole);
|
|
|
|
theWindow = theWindow->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
prop1.name = SmRestartCommand;
|
|
prop1.type = SmLISTofARRAY8;
|
|
|
|
prop1.vals = (SmPropValue *) malloc (
|
|
(Argc + 4) * sizeof (SmPropValue));
|
|
|
|
if (!prop1.vals)
|
|
{
|
|
success = False;
|
|
goto bad;
|
|
}
|
|
|
|
numVals = 0;
|
|
|
|
for (i = 0; i < Argc; i++)
|
|
{
|
|
if (strcmp (Argv[i], "-clientId") == 0 ||
|
|
strcmp (Argv[i], "-restore") == 0)
|
|
{
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
prop1.vals[numVals].value = (SmPointer) Argv[i];
|
|
prop1.vals[numVals++].length = strlen (Argv[i]);
|
|
}
|
|
}
|
|
|
|
prop1.vals[numVals].value = (SmPointer) "-clientId";
|
|
prop1.vals[numVals++].length = 9;
|
|
|
|
prop1.vals[numVals].value = (SmPointer) twm_clientId;
|
|
prop1.vals[numVals++].length = strlen (twm_clientId);
|
|
|
|
prop1.vals[numVals].value = (SmPointer) "-restore";
|
|
prop1.vals[numVals++].length = 8;
|
|
|
|
prop1.vals[numVals].value = (SmPointer) filename;
|
|
prop1.vals[numVals++].length = strlen (filename);
|
|
|
|
prop1.num_vals = numVals;
|
|
|
|
sprintf (discardCommand, "rm %s", filename);
|
|
prop2.name = SmDiscardCommand;
|
|
prop2.type = SmARRAY8;
|
|
prop2.num_vals = 1;
|
|
prop2.vals = &prop2val;
|
|
prop2val.value = (SmPointer) discardCommand;
|
|
prop2val.length = strlen (discardCommand);
|
|
|
|
props[0] = &prop1;
|
|
props[1] = &prop2;
|
|
|
|
SmcSetProperties (smcCon, 2, props);
|
|
free ((char *) prop1.vals);
|
|
|
|
bad:
|
|
SmcSaveYourselfDone (smcCon, success);
|
|
sent_save_done = 1;
|
|
|
|
if (configFile)
|
|
fclose (configFile);
|
|
|
|
if (filename)
|
|
free (filename);
|
|
}
|
|
|
|
/*===[ Save Yourself SM CallBack ]===========================================*/
|
|
|
|
void SaveYourselfCB (SmcConn smcCon, SmPointer clientData,
|
|
int saveType, Bool shutdown, int interactStyle, Bool fast)
|
|
/* this procedure is called by the session manager when requesting the
|
|
* window manager to save its status, ie all the window configurations
|
|
*/
|
|
{
|
|
if (!SmcRequestSaveYourselfPhase2 (smcCon, SaveYourselfPhase2CB, NULL))
|
|
{
|
|
SmcSaveYourselfDone (smcCon, False);
|
|
sent_save_done = 1;
|
|
}
|
|
else
|
|
sent_save_done = 0;
|
|
}
|
|
|
|
/*===[ Die SM Call Back ]====================================================*/
|
|
|
|
void DieCB (SmcConn smcCon, SmPointer clientData)
|
|
/* this procedure is called by the session manager when requesting that the
|
|
* application shut istelf down
|
|
*/
|
|
{
|
|
SmcCloseConnection (smcCon, 0, NULL);
|
|
XtRemoveInput (iceInputId);
|
|
Done(0);
|
|
}
|
|
|
|
/*===[ Save Complete SM Call Back ]==========================================*/
|
|
|
|
void SaveCompleteCB (SmcConn smcCon, SmPointer clientData)
|
|
/* This function is called to say that the save has been completed and that
|
|
* the program can continue its operation
|
|
*/
|
|
{
|
|
;
|
|
}
|
|
|
|
/*===[ Shutdown Cancelled SM Call Back ]=====================================*/
|
|
|
|
void ShutdownCancelledCB (SmcConn smcCon, SmPointer clientData)
|
|
|
|
{
|
|
if (!sent_save_done)
|
|
{
|
|
SmcSaveYourselfDone (smcCon, False);
|
|
sent_save_done = 1;
|
|
}
|
|
}
|
|
|
|
/*===[ Process ICE Message ]=================================================*/
|
|
|
|
void ProcessIceMsgProc (XtPointer client_data, int *source, XtInputId *id)
|
|
|
|
{
|
|
IceConn ice_conn = (IceConn) client_data;
|
|
IceProcessMessages (ice_conn, NULL, NULL);
|
|
}
|
|
|
|
|
|
/*===[ Connect To Session Manager ]==========================================*/
|
|
|
|
void ConnectToSessionManager (char *previous_id)
|
|
/* This procedure attempts to connect to the session manager and setup the
|
|
* interclent exchange via the Call Backs
|
|
*/
|
|
{
|
|
char errorMsg[256];
|
|
unsigned long mask;
|
|
SmcCallbacks callbacks;
|
|
IceConn iceConn;
|
|
|
|
mask = SmcSaveYourselfProcMask | SmcDieProcMask |
|
|
SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask;
|
|
|
|
callbacks.save_yourself.callback = SaveYourselfCB;
|
|
callbacks.save_yourself.client_data = (SmPointer) NULL;
|
|
|
|
callbacks.die.callback = DieCB;
|
|
callbacks.die.client_data = (SmPointer) NULL;
|
|
|
|
callbacks.save_complete.callback = SaveCompleteCB;
|
|
callbacks.save_complete.client_data = (SmPointer) NULL;
|
|
|
|
callbacks.shutdown_cancelled.callback = ShutdownCancelledCB;
|
|
callbacks.shutdown_cancelled.client_data = (SmPointer) NULL;
|
|
|
|
smcConn = SmcOpenConnection (
|
|
NULL, /* use SESSION_MANAGER env */
|
|
(SmPointer) appContext,
|
|
SmProtoMajor,
|
|
SmProtoMinor,
|
|
mask,
|
|
&callbacks,
|
|
previous_id,
|
|
&twm_clientId,
|
|
256, errorMsg);
|
|
|
|
if (smcConn == NULL)
|
|
{
|
|
#ifdef DEBUG
|
|
/* == [ Matthew McNeill Feb 1997 ] == */
|
|
fprintf (stderr, "%s : Connection to session manager failed. (%s)",ProgramName, errorMsg);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
iceConn = SmcGetIceConnection (smcConn);
|
|
|
|
iceInputId = XtAppAddInput (
|
|
appContext,
|
|
IceConnectionNumber (iceConn),
|
|
(XtPointer) XtInputReadMask,
|
|
ProcessIceMsgProc,
|
|
(XtPointer) iceConn);
|
|
}
|