/* This program 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 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/****************************************************************************
* This module is all original code
* by Rob Nation
* Copyright 1993, Robert Nation
* You may use this code for any purpose, as long as the original
* copyright remains in the source code and all documentation
****************************************************************************/
/***********************************************************************
* fvwm - "F? Virtual Window Manager"
***********************************************************************/
#include "config.h"
#include <stdio.h>
#include <signal.h>
#include <sys/wait.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_GETPWUID
# include <pwd.h>
#endif
#include "libs/fvwmlib.h"
#include "libs/FScreen.h"
#include "libs/FShape.h"
#include "fvwm.h"
#include "externs.h"
#include "cursor.h"
#include "functions.h"
#include "bindings.h"
#include "misc.h"
#include "screen.h"
#include "defaults.h"
#include "builtins.h"
#include "menus.h"
#include "module_interface.h"
#include "libs/Colorset.h"
#include "icccm2.h"
#include "gnome.h"
#include "icons.h"
#include "add_window.h"
#include "fvwmsignal.h"
#include "colormaps.h"
#include "stack.h"
#include "virtual.h"
#include "session.h"
#include "events.h"
#include "read.h"
#include "colors.h"
#include "focus.h"
#include "update.h"
#include "window_flags.h"
#include "move_resize.h"
#include <X11/Xproto.h>
#include <X11/Xatom.h>
/* need to get prototype for XrmUniqueQuark for XUniqueContext call */
#include <X11/Xresource.h>
#if defined(I18N_MB) || defined(COMPOUND_TEXT)
#include <X11/Xlocale.h>
#endif
#if HAVE_SYS_SYSTEMINFO_H
/* Solaris has sysinfo instead of gethostname. */
#include <sys/systeminfo.h>
#endif
#define MAXHOSTNAME 255
#ifndef lint
static char sccsid[] __attribute__((__unused__))
= "@(#)fvwm.c " VERSION " " __DATE__ " fvwm";
#endif
int master_pid; /* process number of 1st fvwm process */
ScreenInfo Scr; /* structures for the screen */
MenuInfo Menus; /* structures for menus */
Display *dpy = NULL; /* which display are we talking to */
Bool fFvwmInStartup = True; /* Set to False when startup has finished */
Bool DoingCommandLine = False; /* Set True before each cmd line arg */
/* Grab pointer state. Set by GrabEm, UngrabEm, menus.c and StartupStuff */
#define MAX_CFG_CMDS 10
static char *config_commands[MAX_CFG_CMDS];
static int num_config_commands=0;
/* Is this definition of mkdir portable? */
int mkdir(const char *, mode_t);
int FvwmErrorHandler(Display *, XErrorEvent *);
int CatchFatal(Display *);
int CatchRedirectError(Display *, XErrorEvent *);
void InstallSignals(void);
void SaveDesktopState(void);
void SetRCDefaults(void);
void StartupStuff(void);
static void catch_exit(void);
static RETSIGTYPE SigDone(int);
static RETSIGTYPE Restart(int);
static RETSIGTYPE ReapChildren(int);
static int parseCommandArgs(
const char *command, char **argv, int maxArgc, const char **errorMsg);
static void InternUsefulAtoms(void);
static void InitVariables(void);
static void usage(void);
static void setVersionInfo(void);
XContext FvwmContext; /* context for fvwm windows */
XContext MenuContext; /* context for fvwm menus */
int JunkX = 0, JunkY = 0;
Window JunkRoot, JunkChild; /* junk window */
unsigned int JunkWidth, JunkHeight, JunkBW, JunkDepth, JunkMask;
Bool debugging = False;
Bool debugging_stack_ring = False;
Window bad_window = None;
char **g_argv;
int g_argc;
char *state_filename = NULL;
char *restart_state_filename = NULL; /* $HOME/.fs-restart */
/* assorted gray bitmaps for decorative borders */
#define g_width 2
#define g_height 2
static char g_bits[] = {0x02, 0x01};
#define l_g_width 4
#define l_g_height 2
static char l_g_bits[] = {0x08, 0x02};
#define s_g_width 4
#define s_g_height 4
static char s_g_bits[] = {0x01, 0x02, 0x04, 0x08};
extern XEvent Event;
Bool Restarting = False;
int fd_width, x_fd;
char *display_name = NULL;
char *fvwm_userdir;
static char *home_dir;
char const *Fvwm_VersionInfo;
char const *Fvwm_SupportInfo;
typedef enum { FVWM_RUNNING=0, FVWM_DONE, FVWM_RESTART } FVWM_STATE;
static volatile sig_atomic_t fvwmRunState = FVWM_RUNNING;
/***********************************************************************
*
* Procedure:
* main - start of fvwm
*
***********************************************************************
*/
int main(int argc, char **argv)
{
unsigned long valuemask; /* mask for create windows */
XSetWindowAttributes attributes; /* attributes for create windows */
int i;
extern int x_fd;
int len;
char *display_string;
char message[255];
Bool do_force_single_screen = False;
Bool replace_wm = False;
Bool option_error = False;
int visualClass = -1;
int visualId = -1;
/* for use on restart */
g_argv = (char **)safemalloc((argc + 4) * sizeof(char *));
g_argc = argc;
for (i = 0; i < argc; i++)
g_argv[i] = argv[i];
g_argv[g_argc] = NULL;
DBUG("main","Entered, about to parse args");
setVersionInfo();
#if defined(I18N_MB) || defined(COMPOUND_TEXT)
{
char *s;
if ((s = setlocale(LC_CTYPE, "")) == NULL)
{
fvwm_msg(ERR, "main","Can't set locale. Check your $LC_CTYPE or $LANG.\n");
}
else if (!XSupportsLocale())
{
fvwm_msg(WARN, "main", "X does not support current locale: %s\n", s);
}
#ifdef I18N_MB
else if (XSetLocaleModifiers("") == NULL)
{
fvwm_msg(WARN, "main", "Cannot set locale modifiers\n");
}
#endif
}
#endif
/* Put the default module directory into the environment so it can be used
later by the config file, etc. */
putenv("FVWM_MODULEDIR=" FVWM_MODULEDIR);
/* Figure out user's home directory */
home_dir = getenv("HOME");
#ifdef HAVE_GETPWUID
if (home_dir == NULL) {
struct passwd* pw = getpwuid(getuid());
if (pw != NULL)
home_dir = safestrdup(pw->pw_dir);
}
#endif
if (home_dir == NULL)
home_dir = "/"; /* give up and use root dir */
/* Figure out where to read and write user's data files. */
fvwm_userdir = getenv("FVWM_USERDIR");
if (fvwm_userdir == NULL)
{
fvwm_userdir = safestrdup(CatString2(home_dir, "/.fvwm"));
/* Put the user directory into the environment so it can be used
later everywhere. */
putenv(safestrdup(CatString2("FVWM_USERDIR=", fvwm_userdir)));
}
/* Create FVWM_USERDIR directory if needed */
if (access(fvwm_userdir, F_OK) != 0)
mkdir(fvwm_userdir, 0777);
if (access(fvwm_userdir, W_OK) != 0)
fvwm_msg(ERR, "main", "No write permissions in `%s/'.\n", fvwm_userdir);
for (i = 1; i < argc; i++)
{
if (strncasecmp(argv[i],"-debug_stack_ring", 17)==0)
{
debugging_stack_ring = True;
}
else if (strncasecmp(argv[i],"-debug",6)==0)
{
debugging = True;
}
else if (strncasecmp(argv[i], "-clientId", 9) == 0)
{
if (++i >= argc)
usage();
SetClientID(argv[i]);
}
else if (strncasecmp(argv[i], "-restore", 8) == 0)
{
if (++i >= argc)
usage();
state_filename = argv[i];
}
else if (strncasecmp(argv[i],"-s",2)==0)
{
do_force_single_screen = True;
}
else if (strncasecmp(argv[i],"-d",2)==0)
{
if (++i >= argc)
usage();
display_name = argv[i];
}
else if (strncasecmp(argv[i],"-f",2)==0)
{
if (++i >= argc)
usage();
if (num_config_commands < MAX_CFG_CMDS)
{
config_commands[num_config_commands] =
(char *)malloc(6+strlen(argv[i]));
strcpy(config_commands[num_config_commands],"Read ");
strcat(config_commands[num_config_commands],argv[i]);
num_config_commands++;
}
else
{
fvwm_msg(ERR,"main","only %d -f and -cmd parms allowed!",MAX_CFG_CMDS);
}
}
else if (strncasecmp(argv[i],"-cmd",4)==0)
{
if (++i >= argc)
usage();
if (num_config_commands < MAX_CFG_CMDS)
{
config_commands[num_config_commands] = safestrdup(argv[i]);
num_config_commands++;
}
else
{
fvwm_msg(ERR,"main","only %d -f and -cmd parms allowed!",MAX_CFG_CMDS);
}
}
else if (strncasecmp(argv[i],"-h",2)==0)
{
usage();
exit(0);
}
else if (strncasecmp(argv[i],"-blackout",9)==0)
{
/* obsolete option */
fvwm_msg(WARN, "main", "The -blackout option is obsolete, it may be "
"removed in the future.",
VERSION,__DATE__,__TIME__);
}
else if (strncasecmp(argv[i], "-replace", 8) == 0)
{
replace_wm = True;
}
/* check for visualId before visual to remove ambiguity */
else if (strncasecmp(argv[i],"-visualId",9)==0) {
visualClass = -1;
if (++i >= argc)
usage();
if (sscanf(argv[i], "0x%x", &visualId) == 0)
if (sscanf(argv[i], "%d", &visualId) == 0)
usage();
}
else if (strncasecmp(argv[i],"-visual",7)==0) {
visualId = None;
if (++i >= argc)
usage();
if (strncasecmp(argv[i], "staticg", 7) == 0)
visualClass = StaticGray;
else if (strncasecmp(argv[i], "g", 1) == 0)
visualClass = GrayScale;
else if (strncasecmp(argv[i], "staticc", 7) == 0)
visualClass = StaticColor;
else if (strncasecmp(argv[i], "p", 1) == 0)
visualClass = PseudoColor;
else if (strncasecmp(argv[i], "t", 1) == 0)
visualClass = TrueColor;
else if (strncasecmp(argv[i], "d", 1) == 0)
visualClass = DirectColor;
else
usage();
}
else if (strncasecmp(argv[i], "-version", 8) == 0)
{
printf("%s\n%s\n", Fvwm_VersionInfo, Fvwm_SupportInfo);
exit(0);
}
else
{
fvwm_msg(ERR,"main","Unknown option: `%s'", argv[i]);
option_error = TRUE;
}
}
DBUG("main","Done parsing args");
if (option_error)
{
usage();
}
DBUG("main","Installing signal handlers");
InstallSignals();
if (!(Pdpy = dpy = XOpenDisplay(display_name)))
{
fvwm_msg(ERR,"main","can't open display %s", XDisplayName(display_name));
exit (1);
}
atexit(catch_exit);
Scr.screen= DefaultScreen(dpy);
Scr.NumberOfScreens = ScreenCount(dpy);
master_pid = getpid();
if(!do_force_single_screen)
{
int myscreen = 0;
char *cp;
strcpy(message, XDisplayString(dpy));
for(i=0;i<Scr.NumberOfScreens;i++)
{
if (i != Scr.screen && fork() == 0)
{
myscreen = i;
/*
* Truncate the string 'whatever:n.n' to 'whatever:n',
* and then append the screen number.
*/
cp = strchr(message, ':');
if (cp != NULL)
{
cp = strchr(cp, '.');
if (cp != NULL)
*cp = '\0'; /* truncate at display part */
}
sprintf(message + strlen(message), ".%d", myscreen);
Pdpy = dpy = XOpenDisplay(message);
Scr.screen = myscreen;
Scr.NumberOfScreens = ScreenCount(dpy);
break;
}
}
g_argv[argc++] = "-s";
/*
g_argv[argc++] = "-d";
g_argv[argc++] = safestrdup(XDisplayString(dpy));
*/
g_argv[argc] = NULL;
}
FScreenInit(dpy);
x_fd = XConnectionNumber(dpy);
fd_width = GetFdWidth();
#ifdef HAVE_X11_FD
if (fcntl(x_fd, F_SETFD, 1) == -1)
{
fvwm_msg(ERR,"main","close-on-exec failed");
exit (1);
}
#endif
/* Add a DISPLAY entry to the environment, incase we were started
* with fvwm -display term:0.0
*/
len = strlen(XDisplayString(dpy));
display_string = safemalloc(len+10);
sprintf(display_string,"DISPLAY=%s",XDisplayString(dpy));
putenv(display_string);
/* Add a HOSTDISPLAY environment variable, which is the same as
* DISPLAY, unless display = :0.0 or unix:0.0, in which case the full
* host name will be used for ease in networking . */
/* Note: Can't free the rdisplay_string after putenv, because it
* becomes part of the environment! */
if(strncmp(display_string,"DISPLAY=:",9)==0)
{
char client[MAXHOSTNAME], *rdisplay_string;
gethostname(client,MAXHOSTNAME);
rdisplay_string = safemalloc(len+14 + strlen(client));
sprintf(rdisplay_string,"HOSTDISPLAY=%s:%s",client,&display_string[9]);
putenv(rdisplay_string);
}
else if(strncmp(display_string,"DISPLAY=unix:",13)==0)
{
char client[MAXHOSTNAME], *rdisplay_string;
gethostname(client,MAXHOSTNAME);
rdisplay_string = safemalloc(len+14 + strlen(client));
sprintf(rdisplay_string,"HOSTDISPLAY=%s:%s",client,
&display_string[13]);
putenv(rdisplay_string);
}
else
{
char *rdisplay_string;
rdisplay_string = safemalloc(len+14);
sprintf(rdisplay_string,"HOSTDISPLAY=%s",XDisplayString(dpy));
putenv(rdisplay_string);
}
Scr.Root = RootWindow(dpy, Scr.screen);
if(Scr.Root == None)
{
fvwm_msg(ERR,"main","Screen %d is not a valid screen",(char *)Scr.screen);
exit(1);
}
if (visualClass != -1) {
/* grab the best visual of the required class */
XVisualInfo template, *vizinfo;
int total, i;
Pdepth = 0;
template.screen = Scr.screen;
template.class = visualClass;
vizinfo = XGetVisualInfo(dpy, VisualScreenMask | VisualClassMask, &template,
&total);
if (total) {
for (i = 0; i < total; i++) {
if (vizinfo[i].depth > Pdepth) {
Pvisual = vizinfo[i].visual;
Pdepth = vizinfo[i].depth;
}
}
XFree(vizinfo);
/* have to have a colormap for non-default visual windows */
Pcmap = XCreateColormap(dpy, Scr.Root, Pvisual, AllocNone);
Pdefault = False;
} else {
fvwm_msg(ERR, "main","Cannot find visual class %d", visualClass);
visualClass = -1;
}
} else if (visualId != -1) {
/* grab visual id asked for */
XVisualInfo template, *vizinfo;
int total;
Pdepth = 0;
template.screen = Scr.screen;
template.visualid = visualId;
vizinfo = XGetVisualInfo(dpy, VisualScreenMask | VisualIDMask, &template,
&total);
if (total) {
/* visualID's are unique so there will only be one */
Pvisual = vizinfo[0].visual;
Pdepth = vizinfo[0].depth;
XFree(vizinfo);
/* have to have a colormap for non-default visual windows */
Pcmap = XCreateColormap(dpy, Scr.Root, Pvisual, AllocNone);
Pdefault = False;
} else {
fvwm_msg(ERR, "main", "VisualId 0x%x is not valid ", visualId);
visualId = -1;
}
}
/* use default visuals if none found so far */
if (visualClass == -1 && visualId == -1) {
Pvisual = DefaultVisual(dpy, Scr.screen);
Pdepth = DefaultDepth(dpy, Scr.screen);
Pcmap = DefaultColormap(dpy, Scr.screen);
Pdefault = True;
}
/* make a copy of the visual stuff so that XorPixmap can swap with root */
SaveFvwmVisual();
FShapeInit(dpy);
Scr.pscreen = XScreenOfDisplay(dpy, Scr.screen);
Scr.use_backing_store = DoesBackingStore(Scr.pscreen);
Scr.flags.do_save_under = DoesSaveUnders(Scr.pscreen);
InternUsefulAtoms ();
/* Make sure property priority colors is empty */
XChangeProperty(dpy, Scr.Root, _XA_MIT_PRIORITY_COLORS,
XA_CARDINAL, 32, PropModeReplace, NULL, 0);
/* create a window which will accept the keyboard focus when no other
windows have it */
/* do this before any RC parsing as some GC's are created from this window
* rather than the root window */
attributes.event_mask = XEVMASK_NOFOCUSW;
attributes.override_redirect = True;
attributes.colormap = Pcmap;
attributes.background_pixmap = None;
attributes.border_pixel = 0;
Scr.NoFocusWin=XCreateWindow(dpy, Scr.Root, -10, -10, 10, 10, 0, Pdepth,
InputOutput, Pvisual,
CWEventMask | CWOverrideRedirect | CWColormap
| CWBackPixmap | CWBorderPixel, &attributes);
XMapWindow(dpy, Scr.NoFocusWin);
SetMWM_INFO(Scr.NoFocusWin);
FOCUS_SET(Scr.NoFocusWin);
XSync(dpy, 0);
if(debugging)
XSynchronize(dpy,1);
SetupICCCM2 (replace_wm);
XSetErrorHandler(CatchRedirectError);
XSetIOErrorHandler(CatchFatal);
XSelectInput(dpy, Scr.Root, XEVMASK_ROOTW);
XSync(dpy, 0);
XSetErrorHandler(FvwmErrorHandler);
{
/* do not grab the pointer earlier because if fvwm exits with the pointer
* grabbed while a different display is visible, XFree 4.0 freezes. */
Cursor cursor = XCreateFontCursor(dpy, XC_watch);
XGrabPointer(dpy, Scr.Root, 0, 0, GrabModeAsync, GrabModeAsync,
None, cursor, CurrentTime);
}
{
Atom atype;
int aformat;
unsigned long nitems, bytes_remain;
unsigned char *prop;
if (
XGetWindowProperty(
dpy, Scr.Root, _XA_WM_DESKTOP, 0L, 1L, True, _XA_WM_DESKTOP,
&atype, &aformat, &nitems, &bytes_remain, &prop
) == Success
) {
if (prop != NULL) {
Restarting = True;
/* do_force_single_screen = True; */
}
}
}
restart_state_filename =
safestrdup(
CatString3(fvwm_userdir, "/.fs-restart-", getenv("HOSTDISPLAY")));
if (!state_filename && Restarting)
state_filename = restart_state_filename;
/*
This should be done early enough to have the window states loaded
before the first call to AddWindow.
*/
LoadWindowStates(state_filename);
Scr.FvwmCursors = CreateCursors(dpy);
InitVariables();
if (visualClass != -1 || visualId != -1) {
/* this is so that menus use the (non-default) fvwm colormap */
Scr.FvwmRoot.w = Scr.NoFocusWin;
Scr.FvwmRoot.number_cmap_windows = 1;
Scr.FvwmRoot.cmap_windows = &Scr.NoFocusWin;
}
InitEventHandlerJumpTable();
initModules();
Scr.gray_bitmap =
XCreateBitmapFromData(dpy,Scr.Root,g_bits, g_width,g_height);
DBUG("main","Setting up rc file defaults...");
SetRCDefaults();
flush_window_updates();
simplify_style_list();
DBUG("main","Running config_commands...");
if (num_config_commands > 0)
{
int i;
for(i=0;i<num_config_commands;i++)
{
DoingCommandLine = True;
old_execute_function(
config_commands[i], NULL, &Event, C_ROOT, 1, 0, NULL);
free(config_commands[i]);
}
DoingCommandLine = False;
} else {
/* Run startup command file in 5 places: FVWM_USERDIR, FVWM_DATADIR,
and for compatibility: ~/.fvwm2rc, $sysconfdir/system.fvwm2rc */
if (
!run_command_file( CatString3(fvwm_userdir, "/", FVWMRC),
&Event, NULL, C_ROOT, 1 ) &&
!run_command_file( CatString3(home_dir, "/", FVWMRC),
&Event, NULL, C_ROOT, 1 ) &&
!run_command_file( CatString3(FVWM_DATADIR, "/", FVWMRC),
&Event, NULL, C_ROOT, 1 ) &&
!run_command_file( CatString3(FVWM_DATADIR, "/system", FVWMRC),
&Event, NULL, C_ROOT, 1 ) &&
!run_command_file( CatString3(FVWM_CONFDIR, "/system", FVWMRC),
&Event, NULL, C_ROOT, 1 ) )
{
fvwm_msg( ERR, "main", "Cannot read startup file, tried: "
"\n\t%s/%s\n\t%s/%s\n\t%s/%s\n\t%s/system%s\n\t%s/system%s",
fvwm_userdir, FVWMRC,
home_dir, FVWMRC,
FVWM_DATADIR, FVWMRC,
FVWM_DATADIR, FVWMRC,
FVWM_CONFDIR, FVWMRC);
}
}
DBUG("main","Done running config_commands");
if(Pdepth<2)
{
Scr.gray_pixmap =
XCreatePixmapFromBitmapData(dpy,Scr.NoFocusWin, g_bits, g_width,
g_height, BlackPixel(dpy, Scr.screen),
WhitePixel(dpy, Scr.screen), Pdepth);
Scr.light_gray_pixmap =
XCreatePixmapFromBitmapData(dpy, Scr.NoFocusWin, l_g_bits, l_g_width,
l_g_height, BlackPixel(dpy, Scr.screen),
WhitePixel(dpy, Scr.screen), Pdepth);
Scr.sticky_gray_pixmap =
XCreatePixmapFromBitmapData(dpy, Scr.NoFocusWin, s_g_bits, s_g_width,
s_g_height, BlackPixel(dpy, Scr.screen),
WhitePixel(dpy, Scr.screen), Pdepth);
}
attributes.background_pixel = Scr.StdBack;
attributes.colormap = Pcmap;
attributes.border_pixel = 0;
valuemask = CWBackPixel | CWColormap | CWBorderPixel;
Scr.SizeWindow = XCreateWindow(
dpy, Scr.Root, 0, 0, 1, 1, (unsigned int)0, Pdepth, InputOutput, Pvisual,
valuemask, &attributes);
resize_geometry_window();
initPanFrames();
MyXGrabServer(dpy);
checkPanFrames();
MyXUngrabServer(dpy);
CoerceEnterNotifyOnCurrentWindow();
SessionInit();
GNOME_Init();
DBUG("main","Entering HandleEvents loop...");
HandleEvents();
switch( fvwmRunState )
{
case FVWM_DONE:
Done(0, NULL); /* does not return */
case FVWM_RESTART:
Done(1, ""); /* does not return */
default:
DBUG("main","Unknown FVWM run-state");
}
exit(0);
}
/* exit handler that will try to release any grabs */
static void catch_exit(void)
{
if (dpy != NULL)
{
/* Don't care if this is called from an X error handler. We *have* to try
* this, whatever happens. XFree 4.0 may freeze if we don't do this. */
XUngrabServer(dpy);
XUngrabPointer(dpy, CurrentTime);
XUngrabKeyboard(dpy, CurrentTime);
}
return;
}
/*
** StartupStuff
**
** Does initial window captures and runs init/restart function
*/
void StartupStuff(void)
{
#define startFuncName "StartFunction"
const char *initFuncName;
CaptureAllWindows(False);
/* Turn off the SM stuff after the initial capture so that new windows will
* not be matched by accident. */
if (Restarting)
DisableRestoringState();
/* Have to do this here too because preprocessor modules have not run to the
* end when HandleEvents is entered from the main loop. */
checkPanFrames();
fFvwmInStartup = False;
/* Make sure we have the correct click time now. */
if (Scr.ClickTime < 0)
Scr.ClickTime = -Scr.ClickTime;
# if 0
/* It is safe to ungrab here: if not, and one of the init functions
* does not finish, we've got a complete freeze! */
/* DV (15-Jul-2004): No, it is not safe to ungrab. If another application
* grabs the pointer before execute_function gets it, the start functions
* are not executed. And the pointer is grabbed during function execution
* anyway, so releasing it here buys us nothing. */
UngrabEm(GRAB_STARTUP);
XUngrabPointer(dpy, CurrentTime);
#endif
/* migo (04-Sep-1999): execute StartFunction */
if (FindFunction(startFuncName)) {
char *action = "Function " startFuncName;
old_execute_function(action, NULL, &Event, C_ROOT, 1, 0, NULL);
}
/* migo (03-Jul-1999): execute [Session]{Init|Restart}Function */
initFuncName = getInitFunctionName(Restarting == True);
if (FindFunction(initFuncName)) {
char *action = safestrdup(CatString2("Function ", initFuncName));
old_execute_function(action, NULL, &Event, C_ROOT, 1, 0, NULL);
free(action);
}
/* see comment above */
UngrabEm(GRAB_STARTUP);
XUngrabPointer(dpy, CurrentTime);
/*
This should be done after the initialization is finished, since
it directly changes the global state.
*/
LoadGlobalState(state_filename);
/*
** migo (20-Jun-1999): Remove state file after usage.
** migo (09-Jul-1999): but only on restart, otherwise it can be reused.
*/
if (Restarting)
unlink(state_filename);
} /* StartupStuff */
/*
** SetRCDefaults
**
** Sets some initial style values & such
*/
void SetRCDefaults(void)
{
/* set up default colors, fonts, etc */
char *defaults[] = {
"XORValue 0",
"DefaultFont fixed",
"DefaultColors black grey",
DEFAULT_MENU_STYLE,
"TitleStyle Centered -- Raised",
"Style * Color lightgrey/dimgrey",
"Style * HilightFore black, HilightBack grey",
"AddToMenu MenuFvwmRoot \"Builtin Menu\" Title",
"+ \"&1. XTerm\" Exec xterm",
"+ \"&2. Setup Form\" Module FvwmForm FvwmForm-Setup",
"+ \"&3. Setup 95 Script\" Module FvwmScript FvwmScript-Setup95",
"+ \"&4. Issue FVWM commands\" Module FvwmConsole",
"+ \"&R. Restart FVWM\" Restart",
"+ \"&X. Exit FVWM\" Quit",
"Mouse 0 R N Menu MenuFvwmRoot",
"Read "FVWM_DATADIR"/ConfigFvwmDefaults",
NULL
};
int i=0;
while (defaults[i])
{
old_execute_function(defaults[i], NULL, &Event, C_ROOT, 1, 0, NULL);
i++;
}
} /* SetRCDefaults */
/***********************************************************************
*
* Procedure:
* InternUsefulAtoms:
* Dont really know what it does
*
***********************************************************************
*/
Atom _XA_MIT_PRIORITY_COLORS;
Atom _XA_WM_CHANGE_STATE;
Atom _XA_WM_STATE;
Atom _XA_WM_COLORMAP_WINDOWS;
extern Atom _XA_WM_PROTOCOLS;
Atom _XA_WM_TAKE_FOCUS;
Atom _XA_WM_DELETE_WINDOW;
Atom _XA_WM_DESKTOP;
Atom _XA_MwmAtom;
Atom _XA_MOTIF_WM;
Atom _XA_OL_WIN_ATTR;
Atom _XA_OL_WT_BASE;
Atom _XA_OL_WT_CMD;
Atom _XA_OL_WT_HELP;
Atom _XA_OL_WT_NOTICE;
Atom _XA_OL_WT_OTHER;
Atom _XA_OL_DECOR_ADD;
Atom _XA_OL_DECOR_DEL;
Atom _XA_OL_DECOR_CLOSE;
Atom _XA_OL_DECOR_RESIZE;
Atom _XA_OL_DECOR_HEADER;
Atom _XA_OL_DECOR_ICON_NAME;
Atom _XA_WM_WINDOW_ROLE;
Atom _XA_WM_CLIENT_LEADER;
Atom _XA_SM_CLIENT_ID;
static void InternUsefulAtoms (void)
{
/*
* Create priority colors if necessary.
*/
_XA_MIT_PRIORITY_COLORS = XInternAtom(dpy, "_MIT_PRIORITY_COLORS", False);
_XA_WM_CHANGE_STATE = XInternAtom (dpy, "WM_CHANGE_STATE", False);
_XA_WM_STATE = XInternAtom (dpy, "WM_STATE", False);
_XA_WM_COLORMAP_WINDOWS = XInternAtom (dpy, "WM_COLORMAP_WINDOWS", False);
_XA_WM_PROTOCOLS = XInternAtom (dpy, "WM_PROTOCOLS", False);
_XA_WM_TAKE_FOCUS = XInternAtom (dpy, "WM_TAKE_FOCUS", False);
_XA_WM_DELETE_WINDOW = XInternAtom (dpy, "WM_DELETE_WINDOW", False);
_XA_WM_DESKTOP = XInternAtom (dpy, "WM_DESKTOP", False);
_XA_MwmAtom=XInternAtom(dpy,"_MOTIF_WM_HINTS",False);
_XA_MOTIF_WM=XInternAtom(dpy,"_MOTIF_WM_INFO",False);
_XA_OL_WIN_ATTR=XInternAtom(dpy,"_OL_WIN_ATTR",False);
_XA_OL_WT_BASE=XInternAtom(dpy,"_OL_WT_BASE",False);
_XA_OL_WT_CMD=XInternAtom(dpy,"_OL_WT_CMD",False);
_XA_OL_WT_HELP=XInternAtom(dpy,"_OL_WT_HELP",False);
_XA_OL_WT_NOTICE=XInternAtom(dpy,"_OL_WT_NOTICE",False);
_XA_OL_WT_OTHER=XInternAtom(dpy,"_OL_WT_OTHER",False);
_XA_OL_DECOR_ADD=XInternAtom(dpy,"_OL_DECOR_ADD",False);
_XA_OL_DECOR_DEL=XInternAtom(dpy,"_OL_DECOR_DEL",False);
_XA_OL_DECOR_CLOSE=XInternAtom(dpy,"_OL_DECOR_CLOSE",False);
_XA_OL_DECOR_RESIZE=XInternAtom(dpy,"_OL_DECOR_RESIZE",False);
_XA_OL_DECOR_HEADER=XInternAtom(dpy,"_OL_DECOR_HEADER",False);
_XA_OL_DECOR_ICON_NAME=XInternAtom(dpy,"_OL_DECOR_ICON_NAME",False);
_XA_WM_WINDOW_ROLE=XInternAtom(dpy, "WM_WINDOW_ROLE",False);
_XA_WM_CLIENT_LEADER=XInternAtom(dpy, "WM_CLIENT_LEADER",False);
_XA_SM_CLIENT_ID=XInternAtom(dpy, "SM_CLIENT_ID",False);
return;
}
/***********************************************************************
*
* Procedure:
* InstallSignals: install the signal handlers, using whatever
* means we have at our disposal. The more POSIXy, the better
*
************************************************************************/
void
InstallSignals(void)
{
#ifdef HAVE_SIGACTION
struct sigaction sigact;
/*
* All signals whose handlers call fvwmSetTerminate()
* must be mutually exclusive - we mustn't receive one
* while processing any of the others ...
*/
sigemptyset(&sigact.sa_mask);
sigaddset(&sigact.sa_mask, SIGINT);
sigaddset(&sigact.sa_mask, SIGHUP);
sigaddset(&sigact.sa_mask, SIGQUIT);
sigaddset(&sigact.sa_mask, SIGTERM);
sigaddset(&sigact.sa_mask, SIGUSR1);
#ifdef SA_RESTART
sigact.sa_flags = SA_RESTART;
#else
sigact.sa_flags = 0;
#endif
sigact.sa_handler = DeadPipe;
sigaction(SIGPIPE, &sigact, NULL);
sigact.sa_handler = Restart;
sigaction(SIGUSR1, &sigact, NULL);
sigact.sa_handler = SigDone;
sigaction(SIGINT, &sigact, NULL);
sigaction(SIGHUP, &sigact, NULL);
sigaction(SIGQUIT, &sigact, NULL);
sigaction(SIGTERM, &sigact, NULL);
/*
* Reap all zombies automatically! This signal handler will
* only be called if a child process dies, not if someone
* sends a child a STOP signal. Note that none of our "terminate"
* signals can be delivered until the SIGCHLD handler completes,
* and this is a Good Thing because the terminate handlers
* might exit abruptly via "siglongjmp". This could potentially
* leave SIGCHLD handler with unfinished business ...
*
* NOTE: We could still receive SIGPIPE signals within the
* SIGCHLD handler, but the SIGPIPE handler has the
* SA_RESTART flag set and so should not affect our
* "wait" system call.
*/
sigact.sa_flags |= SA_NOCLDSTOP;
sigact.sa_handler = ReapChildren;
sigaction(SIGCHLD, &sigact, NULL);
#else
#ifdef USE_BSD_SIGNALS
fvwmSetSignalMask( sigmask(SIGUSR1) |
sigmask(SIGINT) |
sigmask(SIGHUP) |
sigmask(SIGQUIT) |
sigmask(SIGTERM) );
#endif
/*
* We don't have sigaction(), so fall back on
* less reliable methods ...
*/
signal(SIGPIPE, DeadPipe);
signal(SIGUSR1, Restart);
#ifdef HAVE_SIGINTERRUPT
siginterrupt(SIGUSR1, 0);
#endif
signal(SIGINT, SigDone);
#ifdef HAVE_SIGINTERRUPT
siginterrupt(SIGINT, 0);
#endif
signal(SIGHUP, SigDone);
#ifdef HAVE_SIGINTERRUPT
siginterrupt(SIGHUP, 0);
#endif
signal(SIGQUIT, SigDone);
#ifdef HAVE_SIGINTERRUPT
siginterrupt(SIGQUIT, 0);
#endif
signal(SIGTERM, SigDone);
#ifdef HAVE_SIGINTERRUPT
siginterrupt(SIGTERM, 0);
#endif
signal(SIGCHLD, ReapChildren);
#ifdef HAVE_SIGINTERRUPT
siginterrupt(SIGCHLD, 0);
#endif
#endif
/* When FVWM restarts, the SIGCHLD handler is automatically reset
* to the default handler. This means that Zombies left over from
* the previous instance of FVWM could still be roaming the process
* table if they exited while the default handler was in place.
* We fix this by invoking the SIGCHLD handler NOW, so that they
* may finally rest in peace. */
ReapChildren(0);
}
/*************************************************************************
* Reap child processes, preventing them from becoming zombies.
* We do this asynchronously within the SIGCHLD handler so that
* "it just happens".
************************************************************************/
static RETSIGTYPE
ReapChildren(int sig)
{
(void)sig;
BSD_BLOCK_SIGNALS;
/*
* This is a signal handler, AND SO MUST BE REENTRANT!
* Now the wait() functions are safe here, but please don't
* add anything unless you're SURE that the new functions
* (plus EVERYTHING they call) are also reentrant. There
* are very few functions which are truly safe.
*/
#if HAVE_WAITPID
while (waitpid(-1, NULL, WNOHANG) > 0)
;
#elif HAVE_WAIT3
while (wait3(NULL, WNOHANG, NULL) > 0)
;
#else
# error One of waitpid or wait3 is needed.
#endif
BSD_UNBLOCK_SIGNALS;
}
/*************************************************************************
* Restart on a signal
************************************************************************/
static RETSIGTYPE
Restart(int sig)
{
fvwmRunState = FVWM_RESTART;
/*
* This function might not return - it could "long-jump"
* right out, so we need to do everything we need to do
* BEFORE we call it ...
*/
fvwmSetTerminate(sig);
}
/***********************************************************************
*
* LoadDefaultLeftButton -- loads default left button # into
* assumes associated button memory is already free
*
************************************************************************/
static void LoadDefaultLeftButton(DecorFace *df, int i)
{
struct vector_coords *v = &df->u.vector;
memset(&df->style, 0, sizeof(df->style));
DFS_FACE_TYPE(df->style) = DefaultVectorButton;
switch (i % 5)
{
case 0:
case 4:
v->num = 5;
v->line_style = 0;
v->x = (int *) safemalloc (sizeof(int) * v->num);
v->y = (int *) safemalloc (sizeof(int) * v->num);
v->x[0] = 22;
v->y[0] = 39;
v->line_style |= (1 << 0);
v->x[1] = 78;
v->y[1] = 39;
v->line_style |= (1 << 1);
v->x[2] = 78;
v->y[2] = 61;
v->x[3] = 22;
v->y[3] = 61;
v->x[4] = 22;
v->y[4] = 39;
v->line_style |= (1 << 4);
break;
case 1:
v->num = 5;
v->line_style = 0;
v->x = (int *) safemalloc (sizeof(int) * v->num);
v->y = (int *) safemalloc (sizeof(int) * v->num);
v->x[0] = 32;
v->y[0] = 45;
v->x[1] = 68;
v->y[1] = 45;
v->x[2] = 68;
v->y[2] = 55;
v->line_style |= (1 << 2);
v->x[3] = 32;
v->y[3] = 55;
v->line_style |= (1 << 3);
v->x[4] = 32;
v->y[4] = 45;
break;
case 2:
v->num = 5;
v->line_style = 0;
v->x = (int *) safemalloc (sizeof(int) * v->num);
v->y = (int *) safemalloc (sizeof(int) * v->num);
v->x[0] = 49;
v->y[0] = 49;
v->line_style |= (1 << 0);
v->x[1] = 51;
v->y[1] = 49;
v->line_style |= (1 << 1);
v->x[2] = 51;
v->y[2] = 51;
v->x[3] = 49;
v->y[3] = 51;
v->x[4] = 49;
v->y[4] = 49;
v->line_style |= (1 << 4);
break;
case 3:
v->num = 5;
v->line_style = 0;
v->x = (int *) safemalloc (sizeof(int) * v->num);
v->y = (int *) safemalloc (sizeof(int) * v->num);
v->x[0] = 32;
v->y[0] = 45;
v->line_style |= (1 << 0);
v->x[1] = 68;
v->y[1] = 45;
v->line_style |= (1 << 1);
v->x[2] = 68;
v->y[2] = 55;
v->x[3] = 32;
v->y[3] = 55;
v->x[4] = 32;
v->y[4] = 45;
v->line_style |= (1 << 4);
break;
}
}
/***********************************************************************
*
* LoadDefaultRightButton -- loads default left button # into
* assumes associated button memory is already free
*
************************************************************************/
static void LoadDefaultRightButton(DecorFace *df, int i)
{
struct vector_coords *v = &df->u.vector;
memset(&df->style, 0, sizeof(df->style));
DFS_FACE_TYPE(df->style) = DefaultVectorButton;
switch (i % 5)
{
case 0:
case 3:
v->num = 5;
v->line_style = 0;
v->x = (int *) safemalloc (sizeof(int) * v->num);
v->y = (int *) safemalloc (sizeof(int) * v->num);
v->x[0] = 25;
v->y[0] = 25;
v->line_style |= (1 << 0);
v->x[1] = 75;
v->y[1] = 25;
v->line_style |= (1 << 1);
v->x[2] = 75;
v->y[2] = 75;
v->x[3] = 25;
v->y[3] = 75;
v->x[4] = 25;
v->y[4] = 25;
v->line_style |= (1 << 4);
break;
case 1:
v->num = 5;
v->line_style = 0;
v->x = (int *) safemalloc (sizeof(int) * v->num);
v->y = (int *) safemalloc (sizeof(int) * v->num);
v->x[0] = 39;
v->y[0] = 39;
v->line_style |= (1 << 0);
v->x[1] = 61;
v->y[1] = 39;
v->line_style |= (1 << 1);
v->x[2] = 61;
v->y[2] = 61;
v->x[3] = 39;
v->y[3] = 61;
v->x[4] = 39;
v->y[4] = 39;
v->line_style |= (1 << 4);
break;
case 2:
v->num = 5;
v->line_style = 0;
v->x = (int *) safemalloc (sizeof(int) * v->num);
v->y = (int *) safemalloc (sizeof(int) * v->num);
v->x[0] = 49;
v->y[0] = 49;
v->line_style |= (1 << 0);
v->x[1] = 51;
v->y[1] = 49;
v->line_style |= (1 << 1);
v->x[2] = 51;
v->y[2] = 51;
v->x[3] = 49;
v->y[3] = 51;
v->x[4] = 49;
v->y[4] = 49;
v->line_style |= (1 << 4);
break;
case 4:
v->num = 5;
v->line_style = 0;
v->x = (int *) safemalloc (sizeof(int) * v->num);
v->y = (int *) safemalloc (sizeof(int) * v->num);
v->x[0] = 36;
v->y[0] = 36;
v->line_style |= (1 << 0);
v->x[1] = 64;
v->y[1] = 36;
v->line_style |= (1 << 1);
v->x[2] = 64;
v->y[2] = 64;
v->x[3] = 36;
v->y[3] = 64;
v->x[4] = 36;
v->y[4] = 36;
v->line_style |= (1 << 4);
break;
}
}
/***********************************************************************
*
* LoadDefaultButton -- loads default button # into button structure
* assumes associated button memory is already free
*
************************************************************************/
void LoadDefaultButton(DecorFace *df, int i)
{
if (i & 1)
LoadDefaultRightButton(df, i / 2);
else
LoadDefaultLeftButton(df, i / 2);
}
extern void FreeDecorFace(Display *dpy, DecorFace *df);
/***********************************************************************
*
* ResetOrDestroyAllButtons -- resets all buttons to defaults
* destroys existing buttons
*
************************************************************************/
void DestroyAllButtons(FvwmDecor *decor)
{
TitleButton *tbp;
DecorFace *face;
int i;
int j;
for (tbp = decor->buttons, i = 0; i < NUMBER_OF_BUTTONS; i++, tbp++)
{
for (j = 0, face = TB_STATE(*tbp); j < BS_MaxButtonState; j++, face++)
{
FreeDecorFace(dpy, face);
}
}
return;
}
void ResetAllButtons(FvwmDecor *decor)
{
TitleButton *tbp;
DecorFace *face;
int i;
int j;
for (tbp = decor->buttons, i = 0; i < NUMBER_OF_BUTTONS; i++, tbp++)
{
memset(&TB_FLAGS(*tbp), 0, sizeof(TB_FLAGS(*tbp)));
TB_JUSTIFICATION(*tbp) = JUST_CENTER;
for (face = TB_STATE(*tbp), j = 0; j < BS_MaxButtonState; j++, face++)
{
LoadDefaultButton(face, i);
}
}
/* standard MWM decoration hint assignments (veliaa@rpi.edu)
[Menu] - Title Bar - [Minimize] [Maximize] */
TB_MWM_DECOR_FLAGS(decor->buttons[0]) |= MWM_DECOR_MENU;
TB_MWM_DECOR_FLAGS(decor->buttons[1]) |= MWM_DECOR_MAXIMIZE;
TB_MWM_DECOR_FLAGS(decor->buttons[3]) |= MWM_DECOR_MINIMIZE;
}
/***********************************************************************
*
* Procedure:
* CreateGCs - open fonts and create all the needed GC's. I only
* want to do this once, hence the first_time flag.
*
***********************************************************************/
static void CreateGCs(void)
{
XGCValues gcv;
unsigned long gcm;
XColor c;
/* create scratch GC's */
gcm = GCFunction|GCLineWidth;
gcv.function = GXcopy;
gcv.line_width = 0;
Scr.ScratchGC1 = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
Scr.ScratchGC2 = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
Scr.ScratchGC3 = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
Scr.ScratchGC4 = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
Scr.TitleGC = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
Scr.TransMaskGC = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
c.pixel = GetColor(DEFAULT_FORE_COLOR);
Scr.ScratchMonoPixmap = XCreatePixmap(dpy, Scr.Root, 1, 1, 1);
Scr.MonoGC = fvwmlib_XCreateGC(dpy, Scr.ScratchMonoPixmap, gcm, &gcv);
}
/***********************************************************************
*
* Procedure:
* InitVariables - initialize fvwm variables
*
************************************************************************/
static void InitVariables(void)
{
FvwmContext = XUniqueContext();
MenuContext = XUniqueContext();
/* initialize some lists */
Scr.AllBindings = NULL;
Scr.functions = NULL;
Menus.all = NULL;
Menus.DefaultStyle = NULL;
Menus.LastStyle = NULL;
Scr.last_added_item.type = ADDED_NONE;
Scr.DefaultIcon = NULL;
Scr.DefaultColorset = -1;
AllocColorset(0);
/* set up colorset 0 so that if FvwmTheme fails to start any modules
* using colorsets don't appear black on black */
Colorset[0].fg = Scr.StdFore = GetColor(DEFAULT_FORE_COLOR);
Colorset[0].bg = Scr.StdBack = GetColor(DEFAULT_BACK_COLOR);
Colorset[0].hilite = Scr.StdHilite = GetHilite(Scr.StdBack);
Colorset[0].shadow = Scr.StdShadow = GetShadow(Scr.StdBack);
Scr.StdGC = 0;
Scr.StdReliefGC = 0;
Scr.StdShadowGC = 0;
Scr.XorGC = 0;
/* zero all flags */
memset(&Scr.flags, 0, sizeof(Scr.flags));
/* create graphics contexts */
CreateGCs();
if (Pdepth <= 8) { /* if the color is limited */
/* a number > than the builtin table! */
Scr.ColorLimit = 255;
}
Scr.FvwmRoot.w = Scr.Root;
Scr.FvwmRoot.next = 0;
init_stack_and_layers();
if (!XGetWindowAttributes(dpy,Scr.Root,&(Scr.FvwmRoot.attr)))
{
fvwm_msg(ERR, "InitVariables", "Could not get root window attributes");
exit(0);
}
Scr.root_pushes = 0;
Scr.fvwm_pushes = 0;
Scr.pushed_window = &Scr.FvwmRoot;
Scr.FvwmRoot.number_cmap_windows = 0;
Scr.MyDisplayWidth = DisplayWidth(dpy, Scr.screen);
Scr.MyDisplayHeight = DisplayHeight(dpy, Scr.screen);
Scr.BusyCursor = BUSY_NONE;
Scr.Hilite = NULL;
/* this indicates that the root window was never entered since the startup of
* fvwm. */
Scr.Ungrabbed = NULL;
Scr.DefaultFont.font = NULL;
Scr.VxMax = 2*Scr.MyDisplayWidth;
Scr.VyMax = 2*Scr.MyDisplayHeight;
Scr.Vx = Scr.Vy = 0;
Scr.SizeWindow = None;
/* Sets the current desktop number to zero */
/* Multiple desks are available even in non-virtual
* compilations */
Scr.CurrentDesk = 0;
Scr.EdgeScrollX = DEFAULT_EDGE_SCROLL * Scr.MyDisplayWidth / 100;
Scr.EdgeScrollY = DEFAULT_EDGE_SCROLL * Scr.MyDisplayHeight / 100;
Scr.ScrollResistance = DEFAULT_SCROLL_RESISTANCE;
Scr.MoveResistance = DEFAULT_MOVE_RESISTANCE;
Scr.XiMoveResistance = DEFAULT_XIMOVE_RESISTANCE;
Scr.SnapAttraction = DEFAULT_SNAP_ATTRACTION;
Scr.SnapMode = DEFAULT_SNAP_ATTRACTION_MODE;
Scr.SnapGridX = DEFAULT_SNAP_GRID_X;
Scr.SnapGridY = DEFAULT_SNAP_GRID_Y;
Scr.OpaqueSize = DEFAULT_OPAQUE_MOVE_SIZE;
Scr.MoveThreshold = DEFAULT_MOVE_THRESHOLD;
/* ClickTime is set to the positive value upon entering the event loop. */
Scr.ClickTime = -DEFAULT_CLICKTIME;
Scr.ColormapFocus = COLORMAP_FOLLOWS_MOUSE;
/* set major operating modes */
Scr.NumBoxes = 0;
Scr.randomx = Scr.randomy = 0;
Scr.buttons2grab = 0;
InitFvwmDecor(&Scr.DefaultDecor);
#ifdef USEDECOR
Scr.DefaultDecor.tag = "Default";
#endif
/* Initialize RaiseHackNeeded by identifying X servers
possibly running under NT. This is probably not an
ideal solution, since eg NCD also produces X servers
which do not run under NT.
"Hummingbird Communications Ltd."
is the ServerVendor string of the Exceed X server under NT,
"Network Computing Devices Inc."
is the ServerVendor string of the PCXware X server under Windows.
"WRQ, Inc."
is the ServerVendor string of the Reflection X server under Windows.
*/
Scr.bo.RaiseHackNeeded =
(strcmp (ServerVendor (dpy), "Hummingbird Communications Ltd.") == 0) ||
(strcmp (ServerVendor (dpy), "Network Computing Devices Inc.") == 0) ||
(strcmp (ServerVendor (dpy), "WRQ, Inc.") == 0);
Scr.bo.ModalityIsEvil = 0;
Scr.bo.DisableConfigureNotify = 0;
Scr.bo.InstallRootCmap = 0;
Scr.bo.FlickeringQtDialogsWorkaround = 1;
Scr.gs.EmulateMWM = DEFAULT_EMULATE_MWM;
Scr.gs.EmulateWIN = DEFAULT_EMULATE_WIN;
Scr.gs.use_active_down_buttons = DEFAULT_USE_ACTIVE_DOWN_BUTTONS;
Scr.gs.use_inactive_buttons = DEFAULT_USE_INACTIVE_BUTTONS;
/* Not the right place for this, should only be called once somewhere .. */
Scr.flags.is_pointer_on_this_screen = !!XQueryPointer(
dpy, Scr.Root, &JunkRoot, &JunkChild, &JunkX, &JunkY, &JunkX, &JunkY,
&JunkMask);
return;
}
/***********************************************************************
*
* Procedure:
* Done - tells FVWM to clean up and exit
*
***********************************************************************
*/
static RETSIGTYPE
SigDone(int sig)
{
fvwmRunState = FVWM_DONE;
/*
* This function might not return - it could "long-jump"
* right out, so we need to do everything we need to do
* BEFORE we call it ...
*/
fvwmSetTerminate(sig);
}
/* if restart is true, command must not be NULL... */
void Done(int restart, char *command)
{
const char *exitFuncName;
/* XFree freeze hack */
XUngrabPointer(dpy, CurrentTime);
XUngrabKeyboard(dpy, CurrentTime);
XUngrabServer(dpy);
if (!restart)
{
MoveViewport(0,0,False);
}
/* migo (03/Jul/1999): execute [Session]ExitFunction */
exitFuncName = getInitFunctionName(2);
if (FindFunction(exitFuncName))
{
char *action = safestrdup(CatString2("Function ", exitFuncName));
old_execute_function(action, NULL, &Event, C_ROOT, 1, 0, NULL);
free(action);
}
if (!restart)
{
Reborder();
}
if (restart)
{
Bool doPreserveState = True;
SaveDesktopState();
if (command)
{
while (isspace(command[0])) command++;
if (strncmp(command, "--dont-preserve-state", 21) == 0)
{
doPreserveState = False;
command += 21;
while (isspace(command[0])) command++;
}
}
if (command[0] == '\0')
command = NULL; /* native restart */
/* won't return under SM on Restart without parameters */
RestartInSession(restart_state_filename, command == NULL, doPreserveState);
/*
RBW - 06/08/1999 - without this, windows will wander to other pages on
a Restart/Recapture because Restart gets the window position information
out of sync. There may be a better way to do this (i.e., adjust the
Restart code), but this works for now.
*/
MoveViewport(0,0,False);
Reborder();
/* Really make sure that the connection is closed and cleared! */
CloseICCCM2();
catch_exit();
XCloseDisplay(dpy);
dpy = NULL;
/* really need to destroy all windows, explicitly,
* not sleep, but this is adequate for now */
sleep(1);
if (command)
{
#define MAX_ARG_SIZE 25
char *my_argv[MAX_ARG_SIZE];
const char *errorMsg;
int n = parseCommandArgs(command, my_argv, MAX_ARG_SIZE, &errorMsg);
if (n <= 0)
{
fvwm_msg(ERR, "Done", "Restart command parsing error in (%s): [%s]",
command, errorMsg);
}
else if (StrEquals(my_argv[0], "--pass-args"))
{
if (n != 2)
{
fvwm_msg(ERR, "Done",
"Restart --pass-args: single name expected. "
"(restarting '%s' instead)",
g_argv[0]);
}
else
{
int i;
my_argv[0] = my_argv[1];
for (i = 1; i < g_argc && i < MAX_ARG_SIZE - 1; i++)
my_argv[i] = g_argv[i];
my_argv[i] = NULL;
execvp(my_argv[0], my_argv);
fvwm_msg(ERR, "Done",
"Call of '%s' failed! (restarting '%s' instead)",
my_argv[0], g_argv[0]);
perror(" system error description");
}
}
else
{
/* Warn against an old 'Restart fvwm2' usage */
if (n == 1 && strcmp(my_argv[0], "fvwm2") == 0)
{
fvwm_msg(WARN, "Done",
"`Restart fvwm2' might not do what you want, see the man page.\n\t"
"Use Restart without parameters if you mean to restart the same WM."
);
}
execvp(my_argv[0], my_argv);
fvwm_msg(ERR, "Done", "Call of '%s' failed! (restarting '%s' instead)",
my_argv[0], g_argv[0]);
perror(" system error description");
}
}
execvp(g_argv[0], g_argv); /* that _should_ work */
fvwm_msg(ERR, "Done", "Call of '%s' failed!", g_argv[0]);
perror(" system error description");
}
else
{
CloseICCCM2();
catch_exit();
XCloseDisplay(dpy);
dpy = NULL;
}
/* Close all my pipes */
/* domivogt (15-Jan-2000): This must be done after calling CloseICCCM2()!
* Otherwise fvwm ignores map requests while it still has
* SubstructureRedirect selected on the root window ==> windows end up in
* nirvana. This explicitly happened with windows unswallowed by FvwmButtons.
*/
ClosePipes();
exit(0);
}
int CatchRedirectError(Display *dpy, XErrorEvent *event)
{
fvwm_msg(ERR,"CatchRedirectError","another WM is running");
exit(1);
/* to make insure happy */
return 0;
}
/***********************************************************************
*
* Procedure:
* CatchFatal - Shuts down if the server connection is lost
*
************************************************************************/
int CatchFatal(Display *dpy)
{
/* No action is taken because usually this action is caused by someone
using "xlogout" to be able to switch between multiple window managers
*/
ClosePipes();
exit(1);
/* to make insure happy */
return 0;
}
/***********************************************************************
*
* Procedure:
* FvwmErrorHandler - displays info on internal errors
*
************************************************************************/
int FvwmErrorHandler(Display *dpy, XErrorEvent *event)
{
extern int last_event_type;
if (event->error_code == BadWindow)
{
bad_window = event->resourceid;
return 0;
}
/* some errors are acceptable, mostly they're caused by
* trying to update a lost window or free'ing another modules colors */
if(event->error_code == BadWindow ||
event->request_code == X_GetGeometry ||
event->error_code == BadDrawable ||
event->request_code == X_ConfigureWindow ||
event->request_code == X_SetInputFocus||
event->request_code == X_GrabButton ||
event->request_code == X_ChangeWindowAttributes ||
event->request_code == X_InstallColormap ||
event->request_code == X_FreePixmap ||
event->request_code == X_FreeColors)
return 0;
fvwm_msg(ERR,"FvwmErrorHandler","*** internal error ***");
fvwm_msg(ERR,"FvwmErrorHandler","Request %d, Error %d, EventType: %d",
event->request_code,
event->error_code,
last_event_type);
return 0;
}
static void usage(void)
{
fprintf(stderr,"\nFVWM version %s Usage:\n\n",VERSION);
fprintf(stderr," %s [-d dpy] [-debug] [-f config_file] [-cmd config_cmd] [-s] [-version] [-h] [-replace] [-clientId id] [-restore file] [-visualId id] [-visual class]\n\n",g_argv[0]);
exit(1);
}
/****************************************************************************
*
* Save Desktop State
*
****************************************************************************/
void SaveDesktopState()
{
FvwmWindow *t;
unsigned long data[1];
for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
{
data[0] = (unsigned long) t->Desk;
XChangeProperty (dpy, t->w, _XA_WM_DESKTOP, _XA_WM_DESKTOP, 32,
PropModeReplace, (unsigned char *) data, 1);
}
data[0] = (unsigned long) Scr.CurrentDesk;
XChangeProperty (dpy, Scr.Root, _XA_WM_DESKTOP, _XA_WM_DESKTOP, 32,
PropModeReplace, (unsigned char *) data, 1);
XSync(dpy, 0);
}
void SetMWM_INFO(Window window)
{
struct mwminfo
{
long flags;
Window win;
} motif_wm_info;
static char set_yorn='n';
if(set_yorn=='y') {
return;
}
if (Scr.bo.ModalityIsEvil)
{
/* Set Motif WM_INFO atom to make motif relinquish
* broken handling of modal dialogs */
motif_wm_info.flags = 2;
motif_wm_info.win = window;
XChangeProperty(dpy,Scr.Root,_XA_MOTIF_WM,_XA_MOTIF_WM,32,
PropModeReplace,(unsigned char *)&motif_wm_info,2);
set_yorn='y';
}
}
/*
* parseCommandArgs - parses a given command string into a given limited
* argument array suitable for execv*. The parsing is similar to shell's.
* Returns:
* positive number of parsed arguments - on success,
* 0 - on empty command (only spaces),
* negative - on no command or parsing error.
*
* Any character can be quoted with a backslash (even inside single quotes).
* Every command argument is separated by a space/tab/new-line from both sizes
* or is at the start/end of the command. Sequential spaces are ignored.
* An argument can be enclosed into single quotes (no further expanding)
* or double quotes (expending environmental variables $VAR or ${VAR}).
* The character '~' is expanded into user home directory (if not in quotes).
*
* In the current implementation, parsed arguments are stored in one
* large static string pointed by returned argv[0], so they will be lost
* on the next function call. This can be changed using dynamic allocation,
* in this case the caller must free the string pointed by argv[0].
*/
static int parseCommandArgs(
const char *command, char **argv, int maxArgc, const char **errorMsg)
{
/* It is impossible to guess the exact length because of expanding */
#define MAX_TOTAL_ARG_LEN 256
/* char *argString = safemalloc(MAX_TOTAL_ARG_LEN); */
static char argString[MAX_TOTAL_ARG_LEN];
int totalArgLen = 0;
int errorCode = 0;
int argc;
char *aptr = argString;
const char *cptr = command;
#define theChar (*cptr)
#define advChar (cptr++)
#define topChar (*cptr == '\\'? *(cptr+1): *cptr)
#define popChar (*(cptr++) == '\\'? *(cptr++): *(cptr-1))
#define canAddArgChar (totalArgLen < MAX_TOTAL_ARG_LEN-1)
#define addArgChar(ch) (++totalArgLen, *(aptr++) = ch)
#define canAddArgStr(str) (totalArgLen < MAX_TOTAL_ARG_LEN-strlen(str))
#define addArgStr(str) {const char *tmp = str; while (*tmp) { addArgChar(*(tmp++)); }}
*errorMsg = "";
if (!command) { *errorMsg = "No command"; return -1; }
for (argc = 0; argc < maxArgc - 1; argc++) {
int sQuote = 0;
argv[argc] = aptr;
while (isspace(theChar)) advChar;
if (theChar == '\0') break;
while ((sQuote || !isspace(theChar)) && theChar != '\0' && canAddArgChar) {
if (theChar == '"') {
if (sQuote) { sQuote = 0; }
else { sQuote = 1; }
advChar;
} else if (!sQuote && theChar == '\'') {
advChar;
while (theChar != '\'' && theChar != '\0' && canAddArgChar) {
addArgChar(popChar);
}
if (theChar == '\'') advChar;
else if (!canAddArgChar) break;
else { *errorMsg = "No closing single quote"; errorCode = -3; break; }
} else if (!sQuote && theChar == '~') {
if (!canAddArgStr(home_dir)) break;
addArgStr(home_dir);
advChar;
} else if (theChar == '$') {
int beg, len;
const char *str = getFirstEnv(cptr, &beg, &len);
if (!str || beg) { addArgChar(theChar); advChar; continue; }
if (!canAddArgStr(str)) { break; }
addArgStr(str);
cptr += len;
} else {
if (addArgChar(popChar) == '\0') break;
}
}
if (*(aptr-1) == '\0')
{
*errorMsg = "Unexpected last backslash";
errorCode = -2;
break;
}
if (errorCode)
break;
if (theChar == '~' || theChar == '$' || !canAddArgChar)
{
*errorMsg = "The command is too long";
errorCode = -argc - 100;
break;
}
if (sQuote)
{
*errorMsg = "No closing double quote";
errorCode = -4;
break;
}
addArgChar('\0');
}
#undef theChar
#undef advChar
#undef topChar
#undef popChar
#undef canAddArgChar
#undef addArgChar
#undef canAddArgStr
#undef addArgStr
argv[argc] = NULL;
if (argc == 0 && !errorCode) *errorMsg = "Void command";
return errorCode? errorCode: argc;
}
/*
* setInitFunctionName - sets one of the init, restart or exit function names
* getInitFunctionName - gets one of the init, restart or exit function names
*
* First parameter defines a function type: 0 - init, 1 - restart, 2 - exit.
*/
static const char *initFunctionNames[4] = {
"InitFunction", "RestartFunction", "ExitFunction", "Nop"
};
void setInitFunctionName(int n, const char *name)
{
initFunctionNames[n >= 0 && n < 3? n: 3] = name;
}
const char *getInitFunctionName(int n)
{
return initFunctionNames[n >= 0 && n < 3? n: 3];
}
static void setVersionInfo(void)
{
char version_str[256];
char support_str[512] = "";
int support_len;
/* Set version information string */
sprintf(version_str, "FVWM version %s compiled on %s at %s",
VERSION, __DATE__, __TIME__);
Fvwm_VersionInfo = safestrdup(version_str);
#ifdef HAVE_READLINE
strcat(support_str, " ReadLine,");
#endif
#ifdef HAVE_RPLAY
strcat(support_str, " RPlay,");
#endif
#ifdef HAVE_STROKE
strcat(support_str, " Stroke,");
#endif
#ifdef XPM
strcat(support_str, " XPM,");
#endif
#ifdef GNOME
strcat(support_str, " GNOME WM hints,");
#endif
if (FHaveShapeExtension)
strcat(support_str, " Shape,");
#ifdef SESSION
strcat(support_str, " SM,");
#endif
#ifdef I18N_MB
strcat(support_str, " Multibyte,");
#endif
#ifdef HAVE_XINERAMA
strcat(support_str, " Xinerama,");
#endif
support_len = strlen(support_str);
if (support_len > 0)
{
/* strip last comma */
support_str[support_len - 1] = '\0';
Fvwm_SupportInfo = safestrdup(CatString2("with support for:", support_str));
}
else
Fvwm_SupportInfo = "with no optional feature support";
}
syntax highlighted by Code2HTML, v. 0.9.1