/* * Window Maker window manager * * Copyright (c) 1997-2003 Alfredo K. Kojima * * 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. */ #include "wconfig.h" #include #include #include #include #include #include #include #include #include /* Xlocale.h and locale.h are the same if X_LOCALE is undefind in wconfig.h, * and if X_LOCALE is defined, X's locale emulating functions will be used. * See Xlocale.h for more information. */ #include #define MAINFILE #include "WindowMaker.h" #include "window.h" #include "funcs.h" #include "menu.h" #include "keybind.h" #include "xmodifier.h" #include "defaults.h" #include "session.h" #include "dialog.h" #include /****** Global Variables ******/ /* general info */ Display *dpy; char *ProgName; unsigned int ValidModMask = 0xff; /* locale to use. NULL==POSIX or C */ char *Locale=NULL; int wScreenCount=0; WPreferences wPreferences; WMPropList *wDomainName; WMPropList *wAttributeDomainName; WShortKey wKeyBindings[WKBD_LAST]; /* defaults domains */ WDDomain *WDWindowMaker = NULL; WDDomain *WDWindowAttributes = NULL; WDDomain *WDRootMenu = NULL; /* XContexts */ XContext wWinContext; XContext wAppWinContext; XContext wStackContext; /* Atoms */ Atom _XA_WM_STATE; Atom _XA_WM_CHANGE_STATE; Atom _XA_WM_PROTOCOLS; Atom _XA_WM_TAKE_FOCUS; Atom _XA_WM_DELETE_WINDOW; Atom _XA_WM_SAVE_YOURSELF; Atom _XA_WM_CLIENT_LEADER; Atom _XA_WM_COLORMAP_WINDOWS; Atom _XA_WM_COLORMAP_NOTIFY; Atom _XA_GNUSTEP_WM_ATTR; Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW; Atom _XA_GNUSTEP_WM_RESIZEBAR; Atom _XA_GNUSTEP_TITLEBAR_STATE; Atom _XA_WINDOWMAKER_MENU; Atom _XA_WINDOWMAKER_WM_PROTOCOLS; Atom _XA_WINDOWMAKER_STATE; Atom _XA_WINDOWMAKER_WM_FUNCTION; Atom _XA_WINDOWMAKER_NOTICEBOARD; Atom _XA_WINDOWMAKER_COMMAND; Atom _XA_WINDOWMAKER_ICON_SIZE; Atom _XA_WINDOWMAKER_ICON_TILE; #ifdef OFFIX_DND Atom _XA_DND_PROTOCOL; Atom _XA_DND_SELECTION; #endif /* cursors */ Cursor wCursor[WCUR_LAST]; /* last event timestamp for XSetInputFocus */ Time LastTimestamp; /* timestamp on the last time we did XSetInputFocus() */ Time LastFocusChange; #ifdef SHAPE Bool wShapeSupported; int wShapeEventBase; #endif #ifdef KEEP_XKB_LOCK_STATUS Bool wXkbSupported; int wXkbEventBase; #endif /* special flags */ char WProgramSigState = 0; char WProgramState = WSTATE_NORMAL; char WDelayedActionSet = 0; /* temporary stuff */ int wVisualID = -1; /* notifications */ const char *WMNManaged = "WMNManaged"; const char *WMNUnmanaged = "WMNUnmanaged"; const char *WMNChangedWorkspace = "WMNChangedWorkspace"; const char *WMNChangedState = "WMNChangedState"; const char *WMNChangedFocus = "WMNChangedFocus"; const char *WMNChangedStacking = "WMNChangedStacking"; const char *WMNChangedName = "WMNChangedName"; const char *WMNWorkspaceCreated = "WMNWorkspaceCreated"; const char *WMNWorkspaceDestroyed = "WMNWorkspaceDestroyed"; const char *WMNWorkspaceChanged = "WMNWorkspaceChanged"; const char *WMNWorkspaceNameChanged = "WMNWorkspaceNameChanged"; const char *WMNResetStacking = "WMNResetStacking"; /******** End Global Variables *****/ static char *DisplayName = NULL; static char **Arguments; static int ArgCount; extern void EventLoop(); extern void StartUp(); static Bool multiHead = True; /* stdi/o for log shell */ static int LogStdIn = -1, LogStdOut = -1, LogStdErr = -1; void Exit(int status) { #ifdef XSMP_ENABLED wSessionDisconnectManager(); #endif if (dpy) XCloseDisplay(dpy); exit(status); } void Restart(char *manager, Bool abortOnFailure) { char *prog=NULL; char *argv[MAX_RESTART_ARGS]; int i; if (manager && manager[0]!=0) { prog = argv[0] = strtok(manager, " "); for (i=1; iscreen); strcat(tmp, buf); putenv(tmp); } tmp = wmalloc(60); snprintf(tmp, 60, "WRASTER_COLOR_RESOLUTION%i=%i", scr->screen, scr->rcontext->attribs->colors_per_channel); putenv(tmp); } typedef struct { WScreen *scr; char *command; } _tuple; static void shellCommandHandler(pid_t pid, unsigned char status, _tuple *data) { if (status == 127) { char *buffer; buffer = wstrconcat(_("Could not execute command: "), data->command); wMessageDialog(data->scr, _("Error"), buffer, _("OK"), NULL, NULL); wfree(buffer); } else if (status != 127) { /* printf("%s: %i\n", data->command, status); */ } wfree(data->command); wfree(data); } void ExecuteShellCommand(WScreen *scr, char *command) { static char *shell = NULL; pid_t pid; /* * This have a problem: if the shell is tcsh (not sure about others) * and ~/.tcshrc have /bin/stty erase ^H somewhere on it, the shell * will block and the command will not be executed. if (!shell) { shell = getenv("SHELL"); if (!shell) shell = "/bin/sh"; } */ shell = "/bin/sh"; pid = fork(); if (pid==0) { SetupEnvironment(scr); #ifdef HAVE_SETSID setsid(); #endif execl(shell, shell, "-c", command, NULL); wsyserror("could not execute %s -c %s", shell, command); Exit(-1); } else if (pid < 0) { wsyserror("cannot fork a new process"); } else { _tuple *data = wmalloc(sizeof(_tuple)); data->scr = scr; data->command = wstrdup(command); wAddDeathHandler(pid, (WDeathHandler*)shellCommandHandler, data); } } /* *--------------------------------------------------------------------------- * StartLogShell * Start a shell that will receive all stdin and stdout from processes * forked by wmaker. *--------------------------------------------------------------------------- */ void StartLogShell(WScreen *scr) { int in_fd[2]; int out_fd[2]; int err_fd[2]; pid_t pid; SetupEnvironment(scr); if (pipe(in_fd) < 0) { wsyserror("could not create pipe for log shell\n"); return; } if (pipe(out_fd) < 0) { wsyserror("could not create pipe for log shell\n"); close(in_fd[0]); close(in_fd[1]); return; } if (pipe(err_fd) < 0) { wsyserror("could not create pipe for log shell\n"); close(out_fd[0]); close(out_fd[1]); close(in_fd[0]); close(in_fd[1]); return; } pid = fork(); if (pid < 0) { wsyserror("could not fork a new process for log shell\n"); return; } else if (pid == 0) { close(in_fd[0]); close(out_fd[1]); close(err_fd[1]); close(0); close(1); close(2); if (dup2(in_fd[1], 0) < 0) { wsyserror("could not redirect stdin for log shell\n"); exit(1); } if (dup2(out_fd[1], 1) < 0) { wsyserror("could not redirect stdout for log shell\n"); exit(1); } if (dup2(err_fd[1], 2) < 0) { wsyserror("could not redirect stderr for log shell\n"); exit(1); } close(in_fd[1]); close(out_fd[1]); close(err_fd[1]); execl("/bin/sh", "/bin/sh", "-c", wPreferences.logger_shell, NULL); wsyserror("could not execute %s\n", wPreferences.logger_shell); exit(1); } else { close(in_fd[1]); close(out_fd[0]); close(err_fd[0]); LogStdIn = in_fd[1]; LogStdOut = out_fd[0]; LogStdErr = err_fd[0]; } } /* *--------------------------------------------------------------------- * wAbort-- * Do a major cleanup and exit the program * *---------------------------------------------------------------------- */ void wAbort(Bool dumpCore) { int i; WScreen *scr; for (i=0; i1) { for (i=1; i=argc) { wwarning(_("too few arguments for %s"), argv[i-1]); exit(0); } Locale = argv[i]; } else if (strcmp(argv[i], "-display")==0 || strcmp(argv[i], "--display")==0) { i++; if (i>=argc) { wwarning(_("too few arguments for %s"), argv[i-1]); exit(0); } DisplayName = argv[i]; } else if (strcmp(argv[i], "-visualid")==0 || strcmp(argv[i], "--visual-id")==0) { i++; if (i>=argc) { wwarning(_("too few arguments for %s"), argv[i-1]); exit(0); } if (sscanf(argv[i], "%i", &wVisualID)!=1) { wwarning(_("bad value for visualid: \"%s\""), argv[i]); exit(0); } } else if (strcmp(argv[i], "-static")==0 || strcmp(argv[i], "--static")==0) { wPreferences.flags.noupdates = 1; } else if (strcmp(argv[i], "-nopolling")==0 || strcmp(argv[i], "--no-polling")==0) { wPreferences.flags.nopolling = 1; #ifdef XSMP_ENABLED } else if (strcmp(argv[i], "-clientid")==0 || strcmp(argv[i], "-restore")==0) { i++; if (i>=argc) { wwarning(_("too few arguments for %s"), argv[i-1]); exit(0); } #endif } else if (strcmp(argv[i], "--help")==0) { print_help(); exit(0); } else { printf(_("%s: invalid argument '%s'\n"), argv[0], argv[i]); printf(_("Try '%s --help' for more information\n"), argv[0]); exit(1); } } } if (!wPreferences.flags.noupdates) { /* check existence of Defaults DB directory */ check_defaults(); } if (!Locale) { Locale = getenv("LC_ALL"); } if (!Locale) { Locale = getenv("LANG"); } setlocale(LC_ALL, ""); if (!Locale || strcmp(Locale, "C")==0 || strcmp(Locale, "POSIX")==0) Locale = NULL; #ifdef I18N if (getenv("NLSPATH")) bindtextdomain("WindowMaker", getenv("NLSPATH")); else bindtextdomain("WindowMaker", LOCALEDIR); textdomain("WindowMaker"); if (!XSupportsLocale()) { wwarning(_("X server does not support locale")); } if (XSetLocaleModifiers("") == NULL) { wwarning(_("cannot set locale modifiers")); } #endif if (Locale) { char *ptr; Locale = wstrdup(Locale); ptr = strchr(Locale, '.'); if (ptr) *ptr = 0; } /* open display */ dpy = XOpenDisplay(DisplayName); if (dpy == NULL) { wfatal(_("could not open display \"%s\""), XDisplayName(DisplayName)); exit(1); } if (fcntl(ConnectionNumber(dpy), F_SETFD, FD_CLOEXEC) < 0) { wsyserror("error setting close-on-exec flag for X connection"); exit(1); } /* check if the user specified a complete display name (with screen). * If so, only manage the specified screen */ if (DisplayName) str = strchr(DisplayName, ':'); else str = NULL; if (str && sscanf(str, ":%i.%i", &d, &s)==2) multiHead = False; DisplayName = XDisplayName(DisplayName); { int len = strlen(DisplayName)+64; str = wmalloc(len); snprintf(str, len, "DISPLAY=%s", DisplayName); } putenv(str); #ifdef DEBUG if (doSync) XSynchronize(dpy, True); #endif wXModifierInitialize(); #ifdef XSMP_ENABLED wSessionConnectManager(argv, argc); #endif StartUp(!multiHead); if (wScreenCount==1) multiHead = False; execInitScript(); EventLoop(); return -1; }