/* -*-c-*- */ /* 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 */ /* ---------------------------- included header files ---------------------- */ #include "config.h" #include #include #include #include #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_GETPWUID # include #endif #if HAVE_SYS_SYSTEMINFO_H /* Solaris has sysinfo instead of gethostname. */ #include #endif #include #include #include "libs/fvwmlib.h" #include "libs/envvar.h" #include "libs/Strings.h" #include "libs/System.h" #include "libs/Grab.h" #include "libs/ColorUtils.h" #include "libs/Graphics.h" #include "libs/FScreen.h" #include "libs/FShape.h" #include "libs/PictureBase.h" #include "libs/PictureUtils.h" #include "libs/Fsvg.h" #include "libs/FRenderInit.h" #include "libs/charmap.h" #include "libs/wcontext.h" #include "fvwm.h" #include "externs.h" #include "cursor.h" #include "functions.h" #include "misc.h" #include "screen.h" #include "builtins.h" #include "module_list.h" #include "colorset.h" #include "events.h" #include "eventhandler.h" #include "eventmask.h" #include "icccm2.h" #include "gnome.h" #include "ewmh.h" #include "add_window.h" #include "libs/fvwmsignal.h" #include "stack.h" #include "virtual.h" #include "session.h" #include "read.h" #include "focus.h" #include "update.h" #include "move_resize.h" #include "frame.h" #include "menus.h" #include "menubindings.h" #include "libs/FGettext.h" /* ---------------------------- local definitions -------------------------- */ #define MAXHOSTNAME 255 #define MAX_CFG_CMDS 10 #define MAX_ARG_SIZE 25 #define g_width 2 #define g_height 2 #define l_g_width 4 #define l_g_height 2 #define s_g_width 4 #define s_g_height 4 /* ---------------------------- local macros ------------------------------- */ /* ---------------------------- imports ------------------------------------ */ extern int last_event_type; /* ---------------------------- included code files ------------------------ */ /* ---------------------------- local types -------------------------------- */ typedef enum { FVWM_RUNNING = 0, FVWM_DONE, FVWM_RESTART } fvwm_run_state_t; /* ---------------------------- forward declarations ----------------------- */ /* ---------------------------- local variables ---------------------------- */ static char *config_commands[MAX_CFG_CMDS]; static int num_config_commands=0; /* assorted gray bitmaps for decorative borders */ static char g_bits[] = {0x02, 0x01}; static char l_g_bits[] = {0x08, 0x02}; static char s_g_bits[] = {0x01, 0x02, 0x04, 0x08}; static char *home_dir; static volatile sig_atomic_t fvwmRunState = FVWM_RUNNING; static const char *init_function_names[4] = { "InitFunction", "RestartFunction", "ExitFunction", "Nop" }; /* ---------------------------- exported variables (globals) --------------- */ int master_pid; /* process number of 1st fvwm process */ ScreenInfo Scr; /* structures for the screen */ 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 */ XContext FvwmContext; /* context for fvwm windows */ XContext MenuContext; /* context for fvwm menus */ int JunkX = 0, JunkY = 0; Window JunkRoot, JunkChild; /* junk window */ int JunkWidth, JunkHeight, JunkBW, JunkDepth; unsigned int 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 */ Bool Restarting = False; int x_fd; char *display_name = NULL; char *fvwm_userdir; char const *Fvwm_VersionInfo; char const *Fvwm_LicenseInfo; char const *Fvwm_SupportInfo; Atom _XA_MIT_PRIORITY_COLORS; Atom _XA_WM_CHANGE_STATE; Atom _XA_WM_STATE; Atom _XA_WM_COLORMAP_WINDOWS; 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_WINDOW_ROLE; Atom _XA_WM_CLIENT_LEADER; Atom _XA_SM_CLIENT_ID; Atom _XA_XROOTPMAP_ID; Atom _XA_XSETROOT_ID; /* ---------------------------- local functions ---------------------------- */ static void SaveDesktopState(void) { FvwmWindow *t; unsigned long data[1]; for (t = Scr.FvwmRoot.next; t != NULL; t = t->next) { data[0] = (unsigned long) t->Desk; XChangeProperty( dpy, FW_W(t), _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); XFlush(dpy); return; } 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_WINDOW_ROLE=XInternAtom(dpy, "WINDOW_ROLE",False); _XA_WM_CLIENT_LEADER=XInternAtom(dpy, "WM_CLIENT_LEADER",False); _XA_SM_CLIENT_ID=XInternAtom(dpy, "SM_CLIENT_ID",False); _XA_XROOTPMAP_ID=XInternAtom(dpy, "_XROOTPMAP_ID",False); _XA_XSETROOT_ID=XInternAtom(dpy, "_XSETROOT_ID",False); return; } /* 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; } /* * 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); SIGNAL_RETURN; } 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); SIGNAL_RETURN; } /* * parse_command_args - 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 parse_command_args( const char *command, char **argv, int max_argc, const char **error_msg) { /* It is impossible to guess the exact length because of expanding */ #define MAX_TOTAL_ARG_LEN 256 /* char *arg_string = safemalloc(MAX_TOTAL_ARG_LEN); */ static char arg_string[MAX_TOTAL_ARG_LEN]; int total_arg_len = 0; int error_code = 0; int argc; char *aptr = arg_string; const char *cptr = command; #define the_char (*cptr) #define adv_char (cptr++) #define top_char (*cptr == '\\' ? *(cptr + 1) : *cptr) #define pop_char (*(cptr++) == '\\' ? *(cptr++) : *(cptr - 1)) #define can_add_arg_char (total_arg_len < MAX_TOTAL_ARG_LEN-1) #define add_arg_char(ch) (++total_arg_len, *(aptr++) = ch) #define can_add_arg_str(str) (total_arg_len < MAX_TOTAL_ARG_LEN - strlen(str)) #define add_arg_str(str) \ {\ const char *tmp = str;\ while (*tmp)\ {\ add_arg_char(*(tmp++));\ }\ } *error_msg = ""; if (!command) { *error_msg = "No command"; return -1; } for (argc = 0; argc < max_argc - 1; argc++) { int s_quote = 0; argv[argc] = aptr; while (isspace(the_char)) { adv_char; } if (the_char == '\0') { break; } while ((s_quote || !isspace(the_char)) && the_char != '\0' && can_add_arg_char) { if (the_char == '"') { if (s_quote) { s_quote = 0; } else { s_quote = 1; } adv_char; } else if (!s_quote && the_char == '\'') { adv_char; while (the_char != '\'' && the_char != '\0' && can_add_arg_char) { add_arg_char(pop_char); } if (the_char == '\'') { adv_char; } else if (!can_add_arg_char) { break; } else { *error_msg = "No closing single quote"; error_code = -3; break; } } else if (!s_quote && the_char == '~') { if (!can_add_arg_str(home_dir)) { break; } add_arg_str(home_dir); adv_char; } else if (the_char == '$') { int beg, len; const char *str = getFirstEnv(cptr, &beg, &len); if (!str || beg) { add_arg_char(the_char); adv_char; continue; } if (!can_add_arg_str(str)) { break; } add_arg_str(str); cptr += len; } else { if (add_arg_char(pop_char) == '\0') { break; } } } if (*(aptr-1) == '\0') { *error_msg = "Unexpected last backslash"; error_code = -2; break; } if (error_code) { break; } if (the_char == '~' || the_char == '$' || !can_add_arg_char) { *error_msg = "The command is too long"; error_code = -argc - 100; break; } if (s_quote) { *error_msg = "No closing double quote"; error_code = -4; break; } add_arg_char('\0'); } #undef the_char #undef adv_char #undef top_char #undef pop_char #undef can_add_arg_char #undef add_arg_char #undef can_add_arg_str #undef add_arg_str argv[argc] = NULL; if (argc == 0 && !error_code) { *error_msg = "Void command"; } return error_code ? error_code : argc; } /* * */ static char *get_display_name(char *display_name, int screen_num) { char *msg; char *new_dn; char *cp; char string_screen_num[32]; CopyString(&msg, display_name); cp = strchr(msg, ':'); if (cp != NULL) { cp = strchr(cp, '.'); if (cp != NULL) { /* truncate at display part */ *cp = '\0'; } } sprintf(string_screen_num, ".%d", screen_num); new_dn = safemalloc( strlen(msg) + strlen(string_screen_num) + 1); new_dn[0] = '\0'; strcat(new_dn, msg); strcat(new_dn, string_screen_num); free(msg); return new_dn; } /* * * Procedure: * Done - tells fvwm to clean up and exit * */ /* if restart is true, command must not be NULL... */ void Done(int restart, char *command) { const char *exit_func_name; if (!restart) { MoveViewport(0,0,False); } /* migo (03/Jul/1999): execute [Session]ExitFunction */ exit_func_name = get_init_function_name(2); if (functions_is_complex_function(exit_func_name)) { const exec_context_t *exc; exec_context_changes_t ecc; char *action = safestrdup( CatString2("Function ", exit_func_name)); ecc.type = restart ? EXCT_TORESTART : EXCT_QUIT; ecc.w.wcontext = C_ROOT; exc = exc_create_context(&ecc, ECC_TYPE | ECC_WCONTEXT); execute_function(NULL, exc, action, 0); exc_destroy_context(exc); free(action); } /* XFree freeze hack */ XUngrabPointer(dpy, CurrentTime); XUngrabKeyboard(dpy, CurrentTime); XUngrabServer(dpy); if (!restart) { Reborder(); } EWMH_ExitStuff(); if (restart) { Bool do_preserve_state = True; SaveDesktopState(); if (command) { while (isspace(command[0])) { command++; } if (strncmp(command, "--dont-preserve-state", 21) == 0) { do_preserve_state = 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, do_preserve_state); /* 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) { char *my_argv[MAX_ARG_SIZE]; const char *error_msg; int n = parse_command_args( command, my_argv, MAX_ARG_SIZE, &error_msg); if (n <= 0) { fvwm_msg( ERR, "Done", "Restart command parsing error in" " (%s): [%s]", command, error_msg); } else if (strcmp(my_argv[0], "--pass-args") == 0) { 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 { char *str = NULL; /* Warn against an old 'Restart fvwm2' usage */ if (n == 1 && strcmp(my_argv[0], "fvwm2") == 0) { str = "fvwm2"; } /* If we are at it, warn against a 'Restart * fvwm' usage as well */ else if (n == 1 && strcmp(my_argv[0], "fvwm") == 0) { str = "fvwm"; } if (str) { fvwm_msg( WARN, "Done", "`Restart %s' might not do" " what you want, see the man" " page.\n\tUse Restart without" " parameters if you mean to" " restart the same WM.", str); } 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; } /* dv (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. */ module_kill_all(); exit(0); } /*********************************************************************** * * Procedure: * InstallSignals: install the signal handlers, using whatever * means we have at our disposal. The more POSIXy, the better * ************************************************************************/ static 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 = fvwmReapChildren; 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, fvwmReapChildren); #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. */ fvwmReapChildren(0); return; } void fvmm_deinstall_signals(void) { signal(SIGCHLD, SIG_DFL); signal(SIGHUP, SIG_DFL); signal(SIGINT, SIG_DFL); signal(SIGPIPE, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGTERM, SIG_DFL); signal(SIGUSR1, SIG_DFL); return; } /*********************************************************************** * * 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; int j = 0; memset(&df->style, 0, sizeof(df->style)); DFS_FACE_TYPE(df->style) = DefaultVectorButton; switch (i % 5) { case 0: case 4: v->num = 5; v->x = (signed char*)safemalloc(sizeof(char) * v->num); v->y = (signed char*)safemalloc(sizeof(char) * v->num); v->xoff = (signed char*)safemalloc(sizeof(char) * v->num); v->yoff = (signed char*)safemalloc(sizeof(char) * v->num); v->c = (signed char*)safecalloc(v->num, sizeof(char)); v->x[0] = 22; v->y[0] = 39; v->c[0] = 1; v->x[1] = 78; v->y[1] = 39; v->c[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->c[4] = 1; break; case 1: v->num = 5; v->x = (signed char*)safemalloc(sizeof(char) * v->num); v->y = (signed char*)safemalloc(sizeof(char) * v->num); v->xoff = (signed char*)safemalloc(sizeof(char) * v->num); v->yoff = (signed char*)safemalloc(sizeof(char) * v->num); v->c = (signed char*)safecalloc(v->num, sizeof(char)); 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->c[2] = 1; v->x[3] = 32; v->y[3] = 55; v->c[3] = 1; v->x[4] = 32; v->y[4] = 45; break; case 2: v->num = 5; v->x = (signed char*)safemalloc(sizeof(char) * v->num); v->y = (signed char*)safemalloc(sizeof(char) * v->num); v->xoff = (signed char*)safemalloc(sizeof(char) * v->num); v->yoff = (signed char*)safemalloc(sizeof(char) * v->num); v->c = (signed char*)safecalloc(v->num, sizeof(char)); v->x[0] = 49; v->y[0] = 49; v->c[0] = 1; v->x[1] = 51; v->y[1] = 49; v->c[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->c[4] = 1; break; case 3: v->num = 5; v->x = (signed char*)safemalloc(sizeof(char) * v->num); v->y = (signed char*)safemalloc(sizeof(char) * v->num); v->xoff = (signed char*)safemalloc(sizeof(char) * v->num); v->yoff = (signed char*)safemalloc(sizeof(char) * v->num); v->c = (signed char*)safecalloc(v->num, sizeof(char)); v->x[0] = 32; v->y[0] = 45; v->c[0] = 1; v->x[1] = 68; v->y[1] = 45; v->c[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->c[4] = 1; break; } /* set offsets to 0, for all buttons */ for(j = 0 ; j < v->num ; j++) { v->xoff[j] = 0; v->yoff[j] = 0; } return; } /*********************************************************************** * * 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; int j = 0; memset(&df->style, 0, sizeof(df->style)); DFS_FACE_TYPE(df->style) = DefaultVectorButton; switch (i % 5) { case 0: case 3: v->num = 5; v->x = (signed char*)safemalloc(sizeof(char) * v->num); v->y = (signed char*)safemalloc(sizeof(char) * v->num); v->xoff = (signed char*)safemalloc(sizeof(char) * v->num); v->yoff = (signed char*)safemalloc(sizeof(char) * v->num); v->c = (signed char*)safecalloc(v->num, sizeof(char)); v->x[0] = 25; v->y[0] = 25; v->c[0] = 1; v->x[1] = 75; v->y[1] = 25; v->c[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->c[4] = 1; break; case 1: v->num = 5; v->x = (signed char*)safemalloc(sizeof(char) * v->num); v->y = (signed char*)safemalloc(sizeof(char) * v->num); v->xoff = (signed char*)safemalloc(sizeof(char) * v->num); v->yoff = (signed char*)safemalloc(sizeof(char) * v->num); v->c = (signed char*)safecalloc(v->num, sizeof(char)); v->x[0] = 39; v->y[0] = 39; v->c[0] = 1; v->x[1] = 61; v->y[1] = 39; v->c[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->c[4] = 1; break; case 2: v->num = 5; v->x = (signed char*)safemalloc(sizeof(char) * v->num); v->y = (signed char*)safemalloc(sizeof(char) * v->num); v->xoff = (signed char*)safemalloc(sizeof(char) * v->num); v->yoff = (signed char*)safemalloc(sizeof(char) * v->num); v->c = (signed char*)safecalloc(v->num, sizeof(char)); v->x[0] = 49; v->y[0] = 49; v->c[0] = 1; v->x[1] = 51; v->y[1] = 49; v->c[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->c[4] = 1; break; case 4: v->num = 5; v->x = (signed char*)safemalloc(sizeof(char) * v->num); v->y = (signed char*)safemalloc(sizeof(char) * v->num); v->xoff = (signed char*)safemalloc(sizeof(char) * v->num); v->yoff = (signed char*)safemalloc(sizeof(char) * v->num); v->c = (signed char*)safecalloc(v->num, sizeof(char)); v->x[0] = 36; v->y[0] = 36; v->c[0] = 1; v->x[1] = 64; v->y[1] = 36; v->c[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->c[4] = 1; break; } /* set offsets to 0, for all buttons */ for(j = 0 ; j < v->num ; j++) { v->xoff[j] = 0; v->yoff[j] = 0; } return; } /*********************************************************************** * * 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.BordersGC = 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); Scr.ScratchAlphaPixmap = XCreatePixmap( dpy, Scr.Root, 1, 1, FRenderGetAlphaDepth()); Scr.AlphaGC = fvwmlib_XCreateGC(dpy, Scr.ScratchAlphaPixmap, gcm, &gcv); return; } /*********************************************************************** * * Procedure: * InitVariables - initialize fvwm variables * ************************************************************************/ static void InitVariables(void) { FvwmContext = XUniqueContext(); MenuContext = XUniqueContext(); /* initialize some lists */ Scr.AllBindings = NULL; Scr.functions = NULL; menus_init(); Scr.last_added_item.type = ADDED_NONE; Scr.DefaultIcon = NULL; Scr.DefaultColorset = -1; 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(); FW_W(&Scr.FvwmRoot) = Scr.Root; Scr.FvwmRoot.next = 0; init_stack_and_layers(); Scr.root_pushes = 0; Scr.fvwm_pushes = 0; Scr.pushed_window = &Scr.FvwmRoot; Scr.FvwmRoot.number_cmap_windows = 0; Scr.FvwmRoot.attr_backup.colormap = Pcmap; Scr.MyDisplayWidth = DisplayWidth(dpy, Scr.screen); Scr.MyDisplayHeight = DisplayHeight(dpy, Scr.screen); Scr.BusyCursor = BUSY_NONE; Scr.Hilite = NULL; Scr.DefaultFont = NULL; Scr.VxMax = 2*Scr.MyDisplayWidth; Scr.VyMax = 2*Scr.MyDisplayHeight; Scr.Vx = 0; 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.ScrollDelay = DEFAULT_SCROLL_DELAY; 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.cascade_x = 0; Scr.cascade_y = 0; /* the last Cascade placed window or NULL, we don't want NULL * initially */ Scr.cascade_window = &Scr.FvwmRoot; Scr.buttons2grab = 0; /* initialisation of the head of the desktops info */ Scr.Desktops = (DesktopsInfo *)safemalloc(sizeof(DesktopsInfo)); Scr.Desktops->name = NULL; Scr.Desktops->desk = 0; /* not desk 0 */ Scr.Desktops->ewmh_dyn_working_area.x = Scr.Desktops->ewmh_working_area.x = 0; Scr.Desktops->ewmh_dyn_working_area.y = Scr.Desktops->ewmh_working_area.y = 0; Scr.Desktops->ewmh_dyn_working_area.width = Scr.Desktops->ewmh_working_area.width = Scr.MyDisplayWidth; Scr.Desktops->ewmh_dyn_working_area.height = Scr.Desktops->ewmh_working_area.height = Scr.MyDisplayHeight; Scr.Desktops->next = NULL; /* ewmh desktop */ Scr.EwmhDesktop = NULL; 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.is_raise_hack_needed = (strcmp ( ServerVendor (dpy), "Hummingbird Communications Ltd.") == 0) || (strcmp ( ServerVendor (dpy), "Network Computing Devices Inc.") == 0) || (strcmp (ServerVendor (dpy), "WRQ, Inc.") == 0); Scr.bo.is_modality_evil = 0; Scr.bo.do_disable_configure_notify = 0; Scr.bo.do_install_root_cmap = 0; Scr.bo.do_enable_flickering_qt_dialogs_workaround = 1; Scr.bo.do_enable_qt_drag_n_drop_workaround = 0; Scr.bo.do_enable_ewmh_iconic_state_workaround = 0; Scr.gs.do_emulate_mwm = DEFAULT_EMULATE_MWM; Scr.gs.do_emulate_win = DEFAULT_EMULATE_WIN; Scr.gs.use_active_down_buttons = DEFAULT_USE_ACTIVE_DOWN_BUTTONS; Scr.gs.use_inactive_buttons = DEFAULT_USE_INACTIVE_BUTTONS; Scr.gs.use_inactive_down_buttons = DEFAULT_USE_INACTIVE_DOWN_BUTTONS; /* Not the right place for this, should only be called once * somewhere .. */ /* EdgeCommands - no edge commands by default */ Scr.PanFrameTop.command = NULL; Scr.PanFrameBottom.command = NULL; Scr.PanFrameRight.command = NULL; Scr.PanFrameLeft.command = NULL; /* EdgeLeaveCommands - no edge leave commands by default */ Scr.PanFrameTop.command_leave = NULL; Scr.PanFrameBottom.command_leave = NULL; Scr.PanFrameRight.command_leave = NULL; Scr.PanFrameLeft.command_leave = NULL; Scr.flags.is_pointer_on_this_screen = !!FQueryPointer( dpy, Scr.Root, &JunkRoot, &JunkChild, &JunkX, &JunkY, &JunkX, &JunkY, &JunkMask); /* make sure colorset 0 exists */ alloc_colorset(0); return; } static void usage(int is_verbose) { fprintf(stderr, "usage: %s", g_argv[0]); fprintf(stderr, " [-d display]" " [-f cfgfile]" " [-c cmd]" " [-s [screen_num]]" " [-I vis-id | -C vis-class]" " [-l colors" " [-L|A|S|P] ...]" " [-r]" " [OTHER OPTIONS] ..." "\n"); if (!is_verbose) { fprintf( stderr, "Try '%s --help' for more information.\n", g_argv[0]); return; } fprintf(stderr, " -A: allocate palette\n" " -c cmd: preprocess configuration file with \n" " -C vis-class: use visual class \n" " -d display: run fvwm on \n" " -D: enable debug oputput\n" " -f cfgfile: read configuration from \n" " -F file: used internally for session management\n" " -h, -?: print this help message\n" " -i client-id: used internally for session management\n" " -I vis-id: use visual \n" " -l colors: try to use no more than colors\n" " -L: strict color limit\n" " -P: visual palette\n" " -r: replace running window manager\n" " -s [screen]: manage a single screen\n" " -S: static palette\n" " -V: print version information\n" ); fprintf( stderr, "Try 'man %s' for more information.\n", PACKAGE); return; } static void setVersionInfo(void) { char version_str[256]; char license_str[512]; char support_str[512] = ""; int support_len; /* Set version information string */ sprintf(version_str, "fvwm %s%s compiled on %s at %s", VERSION, VERSIONINFO, __DATE__, __TIME__); Fvwm_VersionInfo = safestrdup(version_str); sprintf(license_str, "fvwm comes with NO WARRANTY, to the extent permitted by law. " "You may\nredistribute copies of fvwm under " "the terms of the GNU General Public License.\n" "For more information about these matters, see the file " "named COPYING."); Fvwm_LicenseInfo = safestrdup(license_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 HAVE_PNG strcat(support_str, " PNG,"); #endif #ifdef HAVE_RSVG strcat(support_str, " SVG,"); #endif if (FHaveShapeExtension) strcat(support_str, " Shape,"); #ifdef HAVE_XSHM strcat(support_str, " XShm,"); #endif #ifdef SESSION strcat(support_str, " SM,"); #endif #ifdef HAVE_BIDI strcat(support_str, " Bidi text,"); #endif #ifdef HAVE_XINERAMA strcat(support_str, " Xinerama,"); #endif #ifdef HAVE_XRENDER strcat(support_str, " XRender,"); #endif #ifdef HAVE_XCURSOR strcat(support_str, " XCursor,"); #endif #ifdef HAVE_XFT strcat(support_str, " XFT,"); #endif #ifdef HAVE_NLS strcat(support_str, " NLS,"); #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"; } return; } /* Sets some initial style values & such */ static void SetRCDefaults(void) { #define RC_DEFAULTS_COMPLETE ((char *)-1) int i; /* set up default colors, fonts, etc */ const char *defaults[][3] = { { "XORValue 0", "", "" }, { "DefaultFont", "", "" }, { "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" }, { "+ \"&D. ", _("Desktop Menu"), "\" Popup FvwmMenu" }, { "+ \"&R. ", _("Restart fvwm"), "\" Restart" }, { "+ \"&X. ", _("Exit fvwm"), "\" Quit" }, { "Mouse 1 R A Menu MenuFvwmRoot", "", "" }, /* default menu navigation */ { "Key Escape M A MenuClose", "", "" }, { "Key Return M A MenuSelectItem", "", "" }, { "Key Left M A MenuCursorLeft", "", "" }, { "Key Right M A MenuCursorRight", "", "" }, { "Key Up M A MenuMoveCursor -1", "", "" }, { "Key Down M A MenuMoveCursor 1", "", "" }, { "Mouse 1 MI A MenuSelectItem", "", "" }, { "PipeRead 'fvwm-menu-desktop --enable-mini-icons --fvwm-icons'", "", "" }, /* don't add anything below */ { RC_DEFAULTS_COMPLETE, "", "" }, { "Read "FVWM_DATADIR"/ConfigFvwmDefaults", "", "" }, { NULL, NULL, NULL } }; for (i = 0; defaults[i][0] != NULL; i++) { const exec_context_t *exc; exec_context_changes_t ecc; char *cmd; if (defaults[i][0] == RC_DEFAULTS_COMPLETE) { menu_bindings_startup_complete(); continue; } ecc.type = Restarting ? EXCT_RESTART : EXCT_INIT; ecc.w.wcontext = C_ROOT; exc = exc_create_context(&ecc, ECC_TYPE | ECC_WCONTEXT); cmd = CatString3( defaults[i][0], defaults[i][1], defaults[i][2]); execute_function(NULL, exc, cmd, 0); exc_destroy_context(exc); } #undef RC_DEFAULTS_COMPLETE return; } static int CatchRedirectError(Display *dpy, XErrorEvent *event) { fvwm_msg(ERR, "CatchRedirectError", "another WM is running"); exit(1); /* to make insure happy */ return 0; } /* CatchFatal - Shuts down if the server connection is lost */ static 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 */ module_kill_all(); exit(1); /* to make insure happy */ return 0; } /* FvwmErrorHandler - displays info on internal errors */ static int FvwmErrorHandler(Display *dpy, XErrorEvent *event) { 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; } /* ---------------------------- interface functions ------------------------ */ /* Does initial window captures and runs init/restart function */ void StartupStuff(void) { #define start_func_name "StartFunction" const char *init_func_name; const exec_context_t *exc; exec_context_changes_t ecc; ecc.type = Restarting ? EXCT_RESTART : EXCT_INIT; ecc.w.wcontext = C_ROOT; exc = exc_create_context(&ecc, ECC_TYPE | ECC_WCONTEXT); CaptureAllWindows(exc, 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 the geometry window uses the current font */ resize_geometry_window(); /* 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 (functions_is_complex_function(start_func_name)) { char *action = "Function " start_func_name; execute_function(NULL, exc, action, 0); } /* migo (03-Jul-1999): execute [Session]{Init|Restart}Function */ init_func_name = get_init_function_name(Restarting == True); if (functions_is_complex_function(init_func_name)) { char *action = safestrdup( CatString2("Function ", init_func_name)); execute_function(NULL, exc, action, 0); 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); } exc_destroy_context(exc); /* TA: 20091212: If we get here, we're done restarting, so reset the * flag back to False! */ Restarting = False; return; } /*********************************************************************** * * 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); } return; } /*********************************************************************** * * 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_TITLE_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; DestroyAllButtons(decor); for (tbp = decor->buttons, i = 0; i < NUMBER_OF_TITLE_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; return; } void SetMWM_INFO(Window window) { struct mwminfo { long props[2]; /* prop[0]: flags */ /* prop[1]: win */ } motif_wm_info; static char set_yorn='n'; if (set_yorn=='y') { return; } if (Scr.bo.is_modality_evil) { /* Set Motif WM_INFO atom to make motif relinquish * broken handling of modal dialogs */ motif_wm_info.props[0] = 2; motif_wm_info.props[1] = window; XChangeProperty( dpy,Scr.Root, _XA_MOTIF_WM, _XA_MOTIF_WM,32, PropModeReplace, (unsigned char *)&motif_wm_info, 2); set_yorn='y'; } return; } /* * set_init_function_name - sets one of the init, restart or exit function names * get_init_function_name - gets one of the init, restart or exit function names * * First parameter defines a function type: 0 - init, 1 - restart, 2 - exit. */ void set_init_function_name(int n, const char *name) { init_function_names[n >= 0 && n < 3? n: 3] = name; return; } const char *get_init_function_name(int n) { return init_function_names[n >= 0 && n < 3? n: 3]; } #ifndef _PATH_DEVNULL # define _PATH_DEVNULL "/dev/null" #endif static void reopen_fd(int fd, char* mode, FILE *of) { struct stat sbuf; FILE *f; int rc; errno = 0; rc = fstat(fd, &sbuf); if (rc == 0) { return; } else if (errno != EBADF) { exit(77); } f = freopen(_PATH_DEVNULL, mode, of); if (f == 0 || fileno(f) != fd) { exit(88); } return; } /*********************************************************************** * * Procedure: * main - start of fvwm * ***********************************************************************/ int main(int argc, char **argv) { unsigned long valuemask; XSetWindowAttributes attributes; int i; int len; char *display_string; Bool do_force_single_screen = False; int single_screen_num = -1; Bool replace_wm = False; int visualClass = -1; int visualId = -1; PictureColorLimitOption colorLimitop = {-1, -1, -1, -1, -1}; const exec_context_t *exc; exec_context_changes_t ecc; DBUG("main", "Entered, about to parse args"); fvwmlib_init_max_fd(); /* close open fds */ for (i = 3; i < fvwmlib_max_fd; i++) { close(i); } /* reopen stdin, stdout and stderr if necessary */ reopen_fd(0, "rb", stdin); reopen_fd(1, "wb", stdout); reopen_fd(2, "wb", stderr); memset(&Scr, 0, sizeof(Scr)); /* 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; FlocaleInit(LC_CTYPE, "", "", "fvwm"); FGettextInit("fvwm", LOCALEDIR, "fvwm"); setVersionInfo(); /* Put the default module directory into the environment so it can be * used later by the config file, etc. */ flib_putenv("FVWM_MODULEDIR", "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) { char *s; fvwm_userdir = safestrdup(CatString2(home_dir, "/.fvwm")); /* Put the user directory into the environment so it can be used * later everywhere. */ s = safestrdup(CatString2("FVWM_USERDIR=", fvwm_userdir)); flib_putenv("FVWM_USERDIR", s); free(s); } /* 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 (strcmp(argv[i], "-debug_stack_ring") == 0 || strcmp(argv[i], "--debug-stack-ring") == 0) { debugging_stack_ring = True; } else if (strcmp(argv[i], "-D") == 0 || strcmp(argv[i], "-debug") == 0 || strcmp(argv[i], "--debug") == 0) { debugging = True; } else if (strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "-clientid") == 0 || strcmp(argv[i], "--clientid") == 0 || strcmp(argv[i], "-clientId") == 0 || strcmp(argv[i], "--clientId") == 0) { if (++i >= argc) { usage(0); exit(1); } SetClientID(argv[i]); } else if (strcmp(argv[i], "-F") == 0 || strcmp(argv[i], "-restore") == 0 || strcmp(argv[i], "--restore") == 0) { if (++i >= argc) { usage(0); exit(1); } state_filename = argv[i]; } else if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "-single-screen") == 0 || strcmp(argv[i], "--single-screen") == 0) { do_force_single_screen = True; if (i+1 < argc && argv[i+1][0] != '-') { i++; if (sscanf(argv[i], "%d", &single_screen_num) == 0) { usage(0); exit(1); } } } else if (strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "-display") == 0 || strcmp(argv[i], "--display") == 0) { if (++i >= argc) { usage(0); exit(1); } display_name = argv[i]; } else if (strcmp(argv[i], "-f") == 0) { if (++i >= argc) { usage(0); exit(1); } 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 (strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "-cmd") == 0 || strcmp(argv[i], "--cmd") == 0) { if (++i >= argc) { usage(0); exit(1); } 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 (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-?") == 0 || strcmp(argv[i], "--help") == 0) { usage(1); exit(0); } else if (strcmp(argv[i], "-blackout") == 0) { /* obsolete option */ fvwm_msg( WARN, "main", "The -blackout option is obsolete, it will be " "removed in 3.0."); } else if (strcmp(argv[i], "-r") == 0 || strcmp(argv[i], "-replace") == 0 || strcmp(argv[i], "--replace") == 0) { replace_wm = True; } /* check for visualId before visual to remove ambiguity */ else if (strcmp(argv[i], "-I") == 0 || strcmp(argv[i], "-visualid") == 0 || strcmp(argv[i], "--visualid") == 0 || strcmp(argv[i], "-visualId") == 0 || strcmp(argv[i], "--visualId") == 0) { visualClass = -1; if (++i >= argc) { usage(0); exit(1); } if (sscanf(argv[i], "0x%x", &visualId) == 0) { if (sscanf(argv[i], "%d", &visualId) == 0) { usage(0); exit(1); } } } else if (strcmp(argv[i], "-C") == 0 || strcmp(argv[i], "-visual") == 0 || strcmp(argv[i], "--visual") == 0) { visualId = None; if (++i >= argc) { usage(0); exit(1); } 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(0); exit(1); } } else if (strcmp(argv[i], "-l") == 0 || strcmp(argv[i], "-color-limit") == 0 || strcmp(argv[i], "--color-limit") == 0) { if (++i >= argc) { usage(0); exit(1); } colorLimitop.color_limit = atoi(argv[i]); } else if (strcmp(argv[i], "-L") == 0 || strcmp(argv[i], "-strict-color-limit") == 0 || strcmp(argv[i], "--strict-color-limit") == 0) { colorLimitop.strict = True; } else if (strcmp(argv[i], "-A") == 0 || strcmp(argv[i], "-allocate-palette") == 0 || strcmp(argv[i], "--allocate-palette") == 0) { colorLimitop.allocate = True; } else if (strcmp(argv[i], "-S") == 0 || strcmp(argv[i], "-static-palette") == 0 || strcmp(argv[i], "--static-palette") == 0) { colorLimitop.not_dynamic = True; } else if (strcmp(argv[i], "-P") == 0 || strcmp(argv[i], "-visual-palette") == 0 || strcmp(argv[i], "--visual-palette") == 0) { colorLimitop.use_named_table = True; } else if (strcmp(argv[i], "-V") == 0 || strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "--version") == 0) { printf("%s\n%s\n\n%s\n", Fvwm_VersionInfo, Fvwm_SupportInfo, Fvwm_LicenseInfo); exit(0); } else { usage(0); fprintf(stderr, "invalid option -- %s\n", argv[i]); exit(1); } } DBUG("main", "Done parsing args"); DBUG("main", "Installing signal handlers"); InstallSignals(); if (single_screen_num >= 0) { char *dn = NULL; if (display_name) { dn = display_name; } if (!dn) { dn = getenv("DISPLAY"); } if (!dn) { /* should never happen ? */ if (!(dpy = XOpenDisplay(dn))) { fvwm_msg( ERR, "main", "can't open display %s" "to get the default display", XDisplayName(dn)); } else { dn = XDisplayString(dpy); } } if (dn == NULL) { fvwm_msg( ERR, "main", "couldn't find default display (%s)", XDisplayName(dn)); } else { char *new_dn; new_dn = get_display_name(dn, single_screen_num); if (dpy && strcmp(new_dn, dn) == 0) { /* allready opened */ Pdpy = dpy; } else if (dpy) { XCloseDisplay(dpy); dpy = NULL; } if (!dpy && !(Pdpy = dpy = XOpenDisplay(new_dn))) { fvwm_msg( ERR, "main", "can't open display %s, single screen " "number %d maybe not correct", new_dn, single_screen_num); } Scr.screen = single_screen_num; Scr.NumberOfScreens = ScreenCount(dpy); free(new_dn); } } if (!dpy) { if(!(Pdpy = dpy = XOpenDisplay(display_name))) { fvwm_msg( ERR, "main", "can't open display %s", XDisplayName(display_name)); exit (1); } Scr.screen= DefaultScreen(dpy); Scr.NumberOfScreens = ScreenCount(dpy); } atexit(catch_exit); master_pid = getpid(); if (!do_force_single_screen) { int myscreen = 0; char *new_dn; char *dn; dn = XDisplayString(dpy); for (i=0;i Pdepth) { Pvisual = vinfo[i].visual; Pdepth = vinfo[i].depth; } } if (vinfo) { XFree(vinfo); } /* Detection of a card with 2 hardware colormaps (8+24) which * use depth 8 for the default. We can use our own depth 24 * cmap without affecting other applications. */ if (Pdepth == 0 && DefaultDepth(dpy, Scr.screen) <= 8) { template.class = TrueColor; vinfo = XGetVisualInfo( dpy, VisualScreenMask|VisualClassMask, &template, &total); for(i = 0; i 8) { Pvisual = vinfo[i].visual; Pdepth = vinfo[i].depth; } } if (vinfo) { XFree(vinfo); } } /* have to have a colormap for non-default visual windows */ if (Pdepth > 0) { if (Pvisual->class == DirectColor) { Pcmap = XCreateColormap( dpy, Scr.Root, Pvisual, AllocAll); } else { Pcmap = XCreateColormap( dpy, Scr.Root, Pvisual, AllocNone); } } /* use default visuals if none found so far */ else { Pvisual = DefaultVisual(dpy, Scr.screen); Pdepth = DefaultDepth(dpy, Scr.screen); Pcmap = DefaultColormap(dpy, Scr.screen); Pdefault = True; } } PictureSetupWhiteAndBlack(); /* make a copy of the visual stuff so that XorPixmap can swap with root */ PictureSaveFvwmVisual(); Scr.ColorLimit = 0; PUseDynamicColors = 0; Scr.ColorLimit = PictureInitColors( PICTURE_CALLED_BY_FVWM, True, &colorLimitop, True, True); Frsvg_init(); FShapeInit(dpy); FRenderInit(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); Scr.FvwmCursors = CreateCursors(dpy); XDefineCursor(dpy, Scr.Root, Scr.FvwmCursors[CRS_ROOT]); /* 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.cursor = Scr.FvwmCursors[CRS_DEFAULT]; 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 | CWCursor, &attributes); XMapWindow(dpy, Scr.NoFocusWin); SetMWM_INFO(Scr.NoFocusWin); FOCUS_SET(Scr.NoFocusWin); frame_init(); XFlush(dpy); if (debugging) { sync_server(1); } SetupICCCM2(replace_wm); XSetIOErrorHandler(CatchFatal); { /* We need to catch any errors of XSelectInput on the root * window here. The event mask contains * SubstructureRedirectMask which can be acquired by exactly * one client (window manager). Synchronizing is necessary * here because Neither XSetErrorHandler nor XSelectInput * generate any protocol requests. */ XSync(dpy, 0); XSetErrorHandler(CatchRedirectError); 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); InitVariables(); if (visualClass != -1 || visualId != -1) { /* this is so that menus use the (non-default) fvwm colormap */ FW_W(&Scr.FvwmRoot) = Scr.NoFocusWin; Scr.FvwmRoot.number_cmap_windows = 1; Scr.FvwmRoot.cmap_windows = &Scr.NoFocusWin; } InitEventHandlerJumpTable(); Scr.gray_bitmap = XCreateBitmapFromData(dpy,Scr.Root,g_bits, g_width,g_height); EWMH_Init(); DBUG("main", "Setting up rc file defaults..."); SetRCDefaults(); flush_window_updates(); simplify_style_list(); DBUG("main", "Running config_commands..."); ecc.type = Restarting ? EXCT_RESTART : EXCT_INIT; ecc.w.wcontext = C_ROOT; exc = exc_create_context(&ecc, ECC_TYPE | ECC_WCONTEXT); if (num_config_commands > 0) { int i; for (i = 0; i < num_config_commands; i++) { DoingCommandLine = True; execute_function(NULL, exc, config_commands[i], 0); free(config_commands[i]); } DoingCommandLine = False; } else { /* Run startup command file in these places (default prefix): * ~/.fvwm/config * /usr/local/share/fvwm/config * and for compatibility: * ~/.fvwm/.fvwm2rc * /usr/local/share/fvwm/system.fvwm2rc * and for compatibility to be discontinued: * ~/.fvwm2rc, * /usr/local/share/fvwm/.fvwm2rc * /usr/local/etc/system.fvwm2rc */ if ( !run_command_file(CatString3( fvwm_userdir, "/", FVWM_CONFIG), exc) && !run_command_file(CatString3( FVWM_DATADIR, "/", FVWM_CONFIG), exc) && !run_command_file(CatString3( fvwm_userdir, "/", FVWM2RC), exc) && !run_command_file(CatString3( home_dir, "/", FVWM2RC), exc) && !run_command_file(CatString3( FVWM_DATADIR, "/", FVWM2RC), exc) && !run_command_file(CatString3( FVWM_DATADIR, "/system", FVWM2RC), exc) && !run_command_file(CatString3( FVWM_CONFDIR, "/system", FVWM2RC), exc)) { fvwm_msg( ERR, "main", "Cannot read startup config file," " tried: \n\t%s/%s\n\t%s/%s\n\t%s/%s\n\t" "%s/%s\n\t%s/%s\n\t%s/system%s\n\t%s/system%s", fvwm_userdir, FVWM_CONFIG, FVWM_DATADIR, FVWM_CONFIG, fvwm_userdir, FVWM2RC, home_dir, FVWM2RC, FVWM_DATADIR, FVWM2RC, FVWM_DATADIR, FVWM2RC, FVWM_CONFDIR, FVWM2RC); } } exc_destroy_context(exc); DBUG("main", "Done running config_commands"); if (Pdepth<2) { Scr.gray_pixmap = XCreatePixmapFromBitmapData( dpy, Scr.NoFocusWin, g_bits, g_width, g_height, PictureBlackPixel(), PictureWhitePixel(), Pdepth); Scr.light_gray_pixmap = XCreatePixmapFromBitmapData( dpy, Scr.NoFocusWin, l_g_bits, l_g_width, l_g_height, PictureBlackPixel(), PictureWhitePixel(), Pdepth); Scr.sticky_gray_pixmap = XCreatePixmapFromBitmapData( dpy, Scr.NoFocusWin, s_g_bits, s_g_width, s_g_height, PictureBlackPixel(), PictureWhitePixel(), 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, 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); }