NEWS/Changelog for previous commit.
[fvwm.git] / fvwm / fvwm.c
blob710f5ecb4a4293bb5138c1cb0bfcff8668ea6e79
1 /* -*-c-*- */
2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * This module is all original code
19 * by Rob Nation
20 * Copyright 1993, Robert Nation
21 * You may use this code for any purpose, as long as the original
22 * copyright remains in the source code and all documentation
25 /* ---------------------------- included header files ---------------------- */
27 #include "config.h"
29 #include <stdio.h>
30 #include <signal.h>
31 #include <errno.h>
32 #include <sys/stat.h>
33 #ifdef HAVE_FCNTL_H
34 #include <fcntl.h>
35 #endif
36 #ifdef HAVE_GETPWUID
37 # include <pwd.h>
38 #endif
39 #if HAVE_SYS_SYSTEMINFO_H
40 /* Solaris has sysinfo instead of gethostname. */
41 #include <sys/systeminfo.h>
42 #endif
44 #include <X11/Xproto.h>
45 #include <X11/Xatom.h>
47 #include "libs/fvwmlib.h"
48 #include "libs/envvar.h"
49 #include "libs/Strings.h"
50 #include "libs/System.h"
51 #include "libs/Grab.h"
52 #include "libs/ColorUtils.h"
53 #include "libs/Graphics.h"
54 #include "libs/FScreen.h"
55 #include "libs/FShape.h"
56 #include "libs/PictureBase.h"
57 #include "libs/PictureUtils.h"
58 #include "libs/Fsvg.h"
59 #include "libs/FRenderInit.h"
60 #include "libs/charmap.h"
61 #include "libs/wcontext.h"
62 #include "fvwm.h"
63 #include "externs.h"
64 #include "cursor.h"
65 #include "functions.h"
66 #include "misc.h"
67 #include "screen.h"
68 #include "builtins.h"
69 #include "module_list.h"
70 #include "colorset.h"
71 #include "events.h"
72 #include "eventhandler.h"
73 #include "eventmask.h"
74 #include "icccm2.h"
75 #include "gnome.h"
76 #include "ewmh.h"
77 #include "add_window.h"
78 #include "libs/fvwmsignal.h"
79 #include "stack.h"
80 #include "virtual.h"
81 #include "session.h"
82 #include "read.h"
83 #include "focus.h"
84 #include "update.h"
85 #include "move_resize.h"
86 #include "frame.h"
87 #include "menus.h"
88 #include "menubindings.h"
89 #include "libs/FGettext.h"
91 /* ---------------------------- local definitions -------------------------- */
93 #define MAXHOSTNAME 255
94 #define MAX_CFG_CMDS 10
95 #define MAX_ARG_SIZE 25
97 #define g_width 2
98 #define g_height 2
99 #define l_g_width 4
100 #define l_g_height 2
101 #define s_g_width 4
102 #define s_g_height 4
104 /* ---------------------------- local macros ------------------------------- */
106 /* ---------------------------- imports ------------------------------------ */
108 extern int last_event_type;
110 /* ---------------------------- included code files ------------------------ */
112 /* ---------------------------- local types -------------------------------- */
114 typedef enum
116 FVWM_RUNNING = 0,
117 FVWM_DONE,
118 FVWM_RESTART
119 } fvwm_run_state_t;
121 /* ---------------------------- forward declarations ----------------------- */
123 /* ---------------------------- local variables ---------------------------- */
125 static char *config_commands[MAX_CFG_CMDS];
126 static int num_config_commands=0;
128 /* assorted gray bitmaps for decorative borders */
129 static char g_bits[] =
130 {0x02, 0x01};
131 static char l_g_bits[] =
132 {0x08, 0x02};
133 static char s_g_bits[] =
134 {0x01, 0x02, 0x04, 0x08};
136 static char *home_dir;
138 static volatile sig_atomic_t fvwmRunState = FVWM_RUNNING;
140 static const char *init_function_names[4] =
142 "InitFunction",
143 "RestartFunction",
144 "ExitFunction",
145 "Nop"
148 /* ---------------------------- exported variables (globals) --------------- */
150 int master_pid; /* process number of 1st fvwm process */
152 ScreenInfo Scr; /* structures for the screen */
153 Display *dpy = NULL; /* which display are we talking to */
155 Bool fFvwmInStartup = True; /* Set to False when startup has finished */
156 Bool DoingCommandLine = False; /* Set True before each cmd line arg */
158 XContext FvwmContext; /* context for fvwm windows */
159 XContext MenuContext; /* context for fvwm menus */
161 int JunkX = 0, JunkY = 0;
162 Window JunkRoot, JunkChild; /* junk window */
163 int JunkWidth, JunkHeight, JunkBW, JunkDepth;
164 unsigned int JunkMask;
166 Bool debugging = False;
167 Bool debugging_stack_ring = False;
169 Window bad_window = None;
171 char **g_argv;
172 int g_argc;
174 char *state_filename = NULL;
175 char *restart_state_filename = NULL; /* $HOME/.fs-restart */
177 Bool Restarting = False;
178 int x_fd;
179 char *display_name = NULL;
180 char *fvwm_userdir;
181 char const *Fvwm_VersionInfo;
182 char const *Fvwm_LicenseInfo;
183 char const *Fvwm_SupportInfo;
185 Atom _XA_MIT_PRIORITY_COLORS;
186 Atom _XA_WM_CHANGE_STATE;
187 Atom _XA_WM_STATE;
188 Atom _XA_WM_COLORMAP_WINDOWS;
189 Atom _XA_WM_TAKE_FOCUS;
190 Atom _XA_WM_DELETE_WINDOW;
191 Atom _XA_WM_DESKTOP;
192 Atom _XA_MwmAtom;
193 Atom _XA_MOTIF_WM;
195 Atom _XA_OL_WIN_ATTR;
196 Atom _XA_OL_WT_BASE;
197 Atom _XA_OL_WT_CMD;
198 Atom _XA_OL_WT_HELP;
199 Atom _XA_OL_WT_NOTICE;
200 Atom _XA_OL_WT_OTHER;
201 Atom _XA_OL_DECOR_ADD;
202 Atom _XA_OL_DECOR_DEL;
203 Atom _XA_OL_DECOR_CLOSE;
204 Atom _XA_OL_DECOR_RESIZE;
205 Atom _XA_OL_DECOR_HEADER;
206 Atom _XA_OL_DECOR_ICON_NAME;
208 Atom _XA_WM_WINDOW_ROLE;
209 Atom _XA_WINDOW_ROLE;
210 Atom _XA_WM_CLIENT_LEADER;
211 Atom _XA_SM_CLIENT_ID;
213 Atom _XA_XROOTPMAP_ID;
214 Atom _XA_XSETROOT_ID;
216 /* ---------------------------- local functions ---------------------------- */
218 static void SaveDesktopState(void)
220 FvwmWindow *t;
221 unsigned long data[1];
223 for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
225 data[0] = (unsigned long) t->Desk;
226 XChangeProperty(
227 dpy, FW_W(t), _XA_WM_DESKTOP, _XA_WM_DESKTOP, 32,
228 PropModeReplace, (unsigned char *)data, 1);
230 data[0] = (unsigned long) Scr.CurrentDesk;
231 XChangeProperty(
232 dpy, Scr.Root, _XA_WM_DESKTOP, _XA_WM_DESKTOP, 32,
233 PropModeReplace, (unsigned char *) data, 1);
234 XFlush(dpy);
236 return;
239 static void InternUsefulAtoms (void)
241 /* Create priority colors if necessary. */
242 _XA_MIT_PRIORITY_COLORS = XInternAtom(
243 dpy, "_MIT_PRIORITY_COLORS", False);
244 _XA_WM_CHANGE_STATE = XInternAtom(dpy, "WM_CHANGE_STATE", False);
245 _XA_WM_STATE = XInternAtom(dpy, "WM_STATE", False);
246 _XA_WM_COLORMAP_WINDOWS = XInternAtom(
247 dpy, "WM_COLORMAP_WINDOWS", False);
248 _XA_WM_PROTOCOLS = XInternAtom(dpy, "WM_PROTOCOLS", False);
249 _XA_WM_TAKE_FOCUS = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
250 _XA_WM_DELETE_WINDOW = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
251 _XA_WM_DESKTOP = XInternAtom(dpy, "WM_DESKTOP", False);
252 _XA_MwmAtom=XInternAtom(dpy, "_MOTIF_WM_HINTS",False);
253 _XA_MOTIF_WM=XInternAtom(dpy, "_MOTIF_WM_INFO",False);
254 _XA_OL_WIN_ATTR=XInternAtom(dpy, "_OL_WIN_ATTR",False);
255 _XA_OL_WT_BASE=XInternAtom(dpy, "_OL_WT_BASE",False);
256 _XA_OL_WT_CMD=XInternAtom(dpy, "_OL_WT_CMD",False);
257 _XA_OL_WT_HELP=XInternAtom(dpy, "_OL_WT_HELP",False);
258 _XA_OL_WT_NOTICE=XInternAtom(dpy, "_OL_WT_NOTICE",False);
259 _XA_OL_WT_OTHER=XInternAtom(dpy, "_OL_WT_OTHER",False);
260 _XA_OL_DECOR_ADD=XInternAtom(dpy, "_OL_DECOR_ADD",False);
261 _XA_OL_DECOR_DEL=XInternAtom(dpy, "_OL_DECOR_DEL",False);
262 _XA_OL_DECOR_CLOSE=XInternAtom(dpy, "_OL_DECOR_CLOSE",False);
263 _XA_OL_DECOR_RESIZE=XInternAtom(dpy, "_OL_DECOR_RESIZE",False);
264 _XA_OL_DECOR_HEADER=XInternAtom(dpy, "_OL_DECOR_HEADER",False);
265 _XA_OL_DECOR_ICON_NAME=XInternAtom(dpy, "_OL_DECOR_ICON_NAME",False);
266 _XA_WM_WINDOW_ROLE=XInternAtom(dpy, "WM_WINDOW_ROLE",False);
267 _XA_WINDOW_ROLE=XInternAtom(dpy, "WINDOW_ROLE",False);
268 _XA_WM_CLIENT_LEADER=XInternAtom(dpy, "WM_CLIENT_LEADER",False);
269 _XA_SM_CLIENT_ID=XInternAtom(dpy, "SM_CLIENT_ID",False);
270 _XA_XROOTPMAP_ID=XInternAtom(dpy, "_XROOTPMAP_ID",False);
271 _XA_XSETROOT_ID=XInternAtom(dpy, "_XSETROOT_ID",False);
273 return;
276 /* exit handler that will try to release any grabs */
277 static void catch_exit(void)
279 if (dpy != NULL)
281 /* Don't care if this is called from an X error handler. We
282 * *have* to try this, whatever happens. XFree 4.0 may freeze
283 * if we don't do this. */
284 XUngrabServer(dpy);
285 XUngrabPointer(dpy, CurrentTime);
286 XUngrabKeyboard(dpy, CurrentTime);
289 return;
293 * Restart on a signal
295 static RETSIGTYPE
296 Restart(int sig)
298 fvwmRunState = FVWM_RESTART;
300 /* This function might not return - it could "long-jump"
301 * right out, so we need to do everything we need to do
302 * BEFORE we call it ... */
303 fvwmSetTerminate(sig);
305 SIGNAL_RETURN;
308 static RETSIGTYPE
309 SigDone(int sig)
311 fvwmRunState = FVWM_DONE;
313 /* This function might not return - it could "long-jump"
314 * right out, so we need to do everything we need to do
315 * BEFORE we call it ... */
316 fvwmSetTerminate(sig);
318 SIGNAL_RETURN;
322 * parse_command_args - parses a given command string into a given limited
323 * argument array suitable for execv*. The parsing is similar to shell's.
324 * Returns:
325 * positive number of parsed arguments - on success,
326 * 0 - on empty command (only spaces),
327 * negative - on no command or parsing error.
329 * Any character can be quoted with a backslash (even inside single quotes).
330 * Every command argument is separated by a space/tab/new-line from both sizes
331 * or is at the start/end of the command. Sequential spaces are ignored.
332 * An argument can be enclosed into single quotes (no further expanding)
333 * or double quotes (expending environmental variables $VAR or ${VAR}).
334 * The character '~' is expanded into user home directory (if not in quotes).
336 * In the current implementation, parsed arguments are stored in one
337 * large static string pointed by returned argv[0], so they will be lost
338 * on the next function call. This can be changed using dynamic allocation,
339 * in this case the caller must free the string pointed by argv[0].
341 static int parse_command_args(
342 const char *command, char **argv, int max_argc, const char **error_msg)
344 /* It is impossible to guess the exact length because of expanding */
345 #define MAX_TOTAL_ARG_LEN 256
346 /* char *arg_string = safemalloc(MAX_TOTAL_ARG_LEN); */
347 static char arg_string[MAX_TOTAL_ARG_LEN];
348 int total_arg_len = 0;
349 int error_code = 0;
350 int argc;
351 char *aptr = arg_string;
352 const char *cptr = command;
354 #define the_char (*cptr)
355 #define adv_char (cptr++)
356 #define top_char (*cptr == '\\' ? *(cptr + 1) : *cptr)
357 #define pop_char (*(cptr++) == '\\' ? *(cptr++) : *(cptr - 1))
358 #define can_add_arg_char (total_arg_len < MAX_TOTAL_ARG_LEN-1)
359 #define add_arg_char(ch) (++total_arg_len, *(aptr++) = ch)
360 #define can_add_arg_str(str) (total_arg_len < MAX_TOTAL_ARG_LEN - strlen(str))
361 #define add_arg_str(str) \
363 const char *tmp = str;\
364 while (*tmp)\
366 add_arg_char(*(tmp++));\
370 *error_msg = "";
371 if (!command)
373 *error_msg = "No command";
374 return -1;
376 for (argc = 0; argc < max_argc - 1; argc++)
378 int s_quote = 0;
379 argv[argc] = aptr;
380 while (isspace(the_char))
382 adv_char;
384 if (the_char == '\0')
386 break;
388 while ((s_quote || !isspace(the_char)) &&
389 the_char != '\0' && can_add_arg_char)
391 if (the_char == '"')
393 if (s_quote)
395 s_quote = 0;
397 else
399 s_quote = 1;
401 adv_char;
403 else if (!s_quote && the_char == '\'')
405 adv_char;
406 while (the_char != '\'' && the_char != '\0' &&
407 can_add_arg_char)
409 add_arg_char(pop_char);
411 if (the_char == '\'')
413 adv_char;
415 else if (!can_add_arg_char)
417 break;
419 else
421 *error_msg = "No closing single quote";
422 error_code = -3;
423 break;
426 else if (!s_quote && the_char == '~')
428 if (!can_add_arg_str(home_dir))
430 break;
432 add_arg_str(home_dir);
433 adv_char;
435 else if (the_char == '$')
437 int beg, len;
438 const char *str = getFirstEnv(cptr, &beg, &len);
440 if (!str || beg)
442 add_arg_char(the_char);
443 adv_char;
444 continue;
446 if (!can_add_arg_str(str))
448 break;
450 add_arg_str(str);
451 cptr += len;
453 else
455 if (add_arg_char(pop_char) == '\0')
457 break;
461 if (*(aptr-1) == '\0')
463 *error_msg = "Unexpected last backslash";
464 error_code = -2;
465 break;
467 if (error_code)
469 break;
471 if (the_char == '~' || the_char == '$' || !can_add_arg_char)
473 *error_msg = "The command is too long";
474 error_code = -argc - 100;
475 break;
477 if (s_quote)
479 *error_msg = "No closing double quote";
480 error_code = -4;
481 break;
483 add_arg_char('\0');
485 #undef the_char
486 #undef adv_char
487 #undef top_char
488 #undef pop_char
489 #undef can_add_arg_char
490 #undef add_arg_char
491 #undef can_add_arg_str
492 #undef add_arg_str
493 argv[argc] = NULL;
494 if (argc == 0 && !error_code)
496 *error_msg = "Void command";
499 return error_code ? error_code : argc;
505 static
506 char *get_display_name(char *display_name, int screen_num)
508 char *msg;
509 char *new_dn;
510 char *cp;
511 char string_screen_num[32];
513 CopyString(&msg, display_name);
514 cp = strchr(msg, ':');
515 if (cp != NULL)
517 cp = strchr(cp, '.');
518 if (cp != NULL)
520 /* truncate at display part */
521 *cp = '\0';
524 sprintf(string_screen_num, ".%d", screen_num);
525 new_dn = safemalloc(
526 strlen(msg) + strlen(string_screen_num) + 1);
527 new_dn[0] = '\0';
528 strcat(new_dn, msg);
529 strcat(new_dn, string_screen_num);
530 free(msg);
532 return new_dn;
537 * Procedure:
538 * Done - tells fvwm to clean up and exit
541 /* if restart is true, command must not be NULL... */
542 void Done(int restart, char *command)
544 const char *exit_func_name;
546 if (!restart)
548 MoveViewport(0,0,False);
550 /* migo (03/Jul/1999): execute [Session]ExitFunction */
551 exit_func_name = get_init_function_name(2);
552 if (functions_is_complex_function(exit_func_name))
554 const exec_context_t *exc;
555 exec_context_changes_t ecc;
557 char *action = safestrdup(
558 CatString2("Function ", exit_func_name));
559 ecc.type = restart ? EXCT_TORESTART : EXCT_QUIT;
560 ecc.w.wcontext = C_ROOT;
561 exc = exc_create_context(&ecc, ECC_TYPE | ECC_WCONTEXT);
562 execute_function(NULL, exc, action, 0);
563 exc_destroy_context(exc);
564 free(action);
566 /* XFree freeze hack */
567 XUngrabPointer(dpy, CurrentTime);
568 XUngrabKeyboard(dpy, CurrentTime);
569 XUngrabServer(dpy);
570 if (!restart)
572 Reborder();
574 EWMH_ExitStuff();
575 if (restart)
577 Bool do_preserve_state = True;
578 SaveDesktopState();
580 if (command)
582 while (isspace(command[0]))
584 command++;
586 if (strncmp(command, "--dont-preserve-state", 21) == 0)
588 do_preserve_state = False;
589 command += 21;
590 while (isspace(command[0])) command++;
593 if (command[0] == '\0')
595 command = NULL; /* native restart */
598 /* won't return under SM on Restart without parameters */
599 RestartInSession(
600 restart_state_filename, command == NULL,
601 do_preserve_state);
603 /* RBW - 06/08/1999 - without this, windows will wander to
604 * other pages on a Restart/Recapture because Restart gets the
605 * window position information out of sync. There may be a
606 * better way to do this (i.e., adjust the Restart code), but
607 * this works for now. */
608 MoveViewport(0,0,False);
609 Reborder();
611 /* Really make sure that the connection is closed and cleared!
613 CloseICCCM2();
614 catch_exit();
615 XCloseDisplay(dpy);
616 dpy = NULL;
618 /* really need to destroy all windows, explicitly, not sleep,
619 * but this is adequate for now */
620 sleep(1);
622 if (command)
624 char *my_argv[MAX_ARG_SIZE];
625 const char *error_msg;
626 int n = parse_command_args(
627 command, my_argv, MAX_ARG_SIZE, &error_msg);
629 if (n <= 0)
631 fvwm_msg(
632 ERR, "Done",
633 "Restart command parsing error in"
634 " (%s): [%s]", command, error_msg);
636 else if (strcmp(my_argv[0], "--pass-args") == 0)
638 if (n != 2)
640 fvwm_msg(
641 ERR, "Done",
642 "Restart --pass-args: single"
643 " name expected. (restarting"
644 " '%s' instead)", g_argv[0]);
647 else
649 int i;
650 my_argv[0] = my_argv[1];
651 for (i = 1; i < g_argc &&
652 i < MAX_ARG_SIZE - 1; i++)
654 my_argv[i] = g_argv[i];
656 my_argv[i] = NULL;
658 execvp(my_argv[0], my_argv);
659 fvwm_msg(
660 ERR, "Done",
661 "Call of '%s' failed!"
662 " (restarting '%s' instead)",
663 my_argv[0], g_argv[0]);
664 perror(" system error description");
668 else
670 char *str = NULL;
672 /* Warn against an old 'Restart fvwm2' usage */
673 if (n == 1 && strcmp(my_argv[0], "fvwm2") == 0)
675 str = "fvwm2";
677 /* If we are at it, warn against a 'Restart
678 * fvwm' usage as well */
679 else if (n == 1 &&
680 strcmp(my_argv[0], "fvwm") == 0)
682 str = "fvwm";
684 if (str)
686 fvwm_msg(
687 WARN, "Done",
688 "`Restart %s' might not do"
689 " what you want, see the man"
690 " page.\n\tUse Restart without"
691 " parameters if you mean to"
692 " restart the same WM.", str);
694 execvp(my_argv[0], my_argv);
695 fvwm_msg(
696 ERR, "Done", "Call of '%s' failed!"
697 " (restarting '%s' instead)",
698 my_argv[0], g_argv[0]);
699 perror(" system error description");
703 execvp(g_argv[0], g_argv); /* that _should_ work */
704 fvwm_msg(ERR, "Done", "Call of '%s' failed!", g_argv[0]);
705 perror(" system error description");
707 else
709 CloseICCCM2();
710 catch_exit();
711 XCloseDisplay(dpy);
712 dpy = NULL;
715 /* dv (15-Jan-2000): This must be done after calling CloseICCCM2()!
716 * Otherwise fvwm ignores map requests while it still has
717 * SubstructureRedirect selected on the root window ==> windows end up
718 * in nirvana. This explicitly happened with windows unswallowed by
719 * FvwmButtons. */
720 module_kill_all();
722 exit(0);
725 /***********************************************************************
727 * Procedure:
728 * InstallSignals: install the signal handlers, using whatever
729 * means we have at our disposal. The more POSIXy, the better
731 ************************************************************************/
732 static void
733 InstallSignals(void)
735 #ifdef HAVE_SIGACTION
736 struct sigaction sigact;
739 * All signals whose handlers call fvwmSetTerminate()
740 * must be mutually exclusive - we mustn't receive one
741 * while processing any of the others ...
743 sigemptyset(&sigact.sa_mask);
744 sigaddset(&sigact.sa_mask, SIGINT);
745 sigaddset(&sigact.sa_mask, SIGHUP);
746 sigaddset(&sigact.sa_mask, SIGQUIT);
747 sigaddset(&sigact.sa_mask, SIGTERM);
748 sigaddset(&sigact.sa_mask, SIGUSR1);
750 #ifdef SA_RESTART
751 sigact.sa_flags = SA_RESTART;
752 #else
753 sigact.sa_flags = 0;
754 #endif
755 sigact.sa_handler = DeadPipe;
756 sigaction(SIGPIPE, &sigact, NULL);
758 sigact.sa_handler = Restart;
759 sigaction(SIGUSR1, &sigact, NULL);
761 sigact.sa_handler = SigDone;
762 sigaction(SIGINT, &sigact, NULL);
763 sigaction(SIGHUP, &sigact, NULL);
764 sigaction(SIGQUIT, &sigact, NULL);
765 sigaction(SIGTERM, &sigact, NULL);
767 /* Reap all zombies automatically! This signal handler will only be
768 * called if a child process dies, not if someone sends a child a STOP
769 * signal. Note that none of our "terminate" signals can be delivered
770 * until the SIGCHLD handler completes, and this is a Good Thing
771 * because the terminate handlers might exit abruptly via "siglongjmp".
772 * This could potentially leave SIGCHLD handler with unfinished
773 * business ...
775 * NOTE: We could still receive SIGPIPE signals within the SIGCHLD
776 * handler, but the SIGPIPE handler has the SA_RESTART flag set and so
777 * should not affect our "wait" system call. */
778 sigact.sa_flags |= SA_NOCLDSTOP;
779 sigact.sa_handler = fvwmReapChildren;
780 sigaction(SIGCHLD, &sigact, NULL);
781 #else
782 #ifdef USE_BSD_SIGNALS
783 fvwmSetSignalMask(
784 sigmask(SIGUSR1) | sigmask(SIGINT) | sigmask(SIGHUP) |
785 sigmask(SIGQUIT) | sigmask(SIGTERM) );
786 #endif
789 * We don't have sigaction(), so fall back on
790 * less reliable methods ...
792 signal(SIGPIPE, DeadPipe);
793 signal(SIGUSR1, Restart);
794 #ifdef HAVE_SIGINTERRUPT
795 siginterrupt(SIGUSR1, 0);
796 #endif
798 signal(SIGINT, SigDone);
799 #ifdef HAVE_SIGINTERRUPT
800 siginterrupt(SIGINT, 0);
801 #endif
802 signal(SIGHUP, SigDone);
803 #ifdef HAVE_SIGINTERRUPT
804 siginterrupt(SIGHUP, 0);
805 #endif
806 signal(SIGQUIT, SigDone);
807 #ifdef HAVE_SIGINTERRUPT
808 siginterrupt(SIGQUIT, 0);
809 #endif
810 signal(SIGTERM, SigDone);
811 #ifdef HAVE_SIGINTERRUPT
812 siginterrupt(SIGTERM, 0);
813 #endif
814 signal(SIGCHLD, fvwmReapChildren);
815 #ifdef HAVE_SIGINTERRUPT
816 siginterrupt(SIGCHLD, 0);
817 #endif
818 #endif
820 /* When fvwm restarts, the SIGCHLD handler is automatically reset
821 * to the default handler. This means that Zombies left over from
822 * the previous instance of fvwm could still be roaming the process
823 * table if they exited while the default handler was in place.
824 * We fix this by invoking the SIGCHLD handler NOW, so that they
825 * may finally rest in peace. */
826 fvwmReapChildren(0);
828 return;
831 void fvmm_deinstall_signals(void)
833 signal(SIGCHLD, SIG_DFL);
834 signal(SIGHUP, SIG_DFL);
835 signal(SIGINT, SIG_DFL);
836 signal(SIGPIPE, SIG_DFL);
837 signal(SIGQUIT, SIG_DFL);
838 signal(SIGTERM, SIG_DFL);
839 signal(SIGUSR1, SIG_DFL);
841 return;
844 /***********************************************************************
846 * LoadDefaultLeftButton -- loads default left button # into
847 * assumes associated button memory is already free
849 ************************************************************************/
850 static void LoadDefaultLeftButton(DecorFace *df, int i)
852 struct vector_coords *v = &df->u.vector;
853 int j = 0;
855 memset(&df->style, 0, sizeof(df->style));
856 DFS_FACE_TYPE(df->style) = DefaultVectorButton;
857 switch (i % 5)
859 case 0:
860 case 4:
861 v->num = 5;
862 v->x = (signed char*)safemalloc(sizeof(char) * v->num);
863 v->y = (signed char*)safemalloc(sizeof(char) * v->num);
864 v->xoff = (signed char*)safemalloc(sizeof(char) * v->num);
865 v->yoff = (signed char*)safemalloc(sizeof(char) * v->num);
866 v->c = (signed char*)safecalloc(v->num, sizeof(char));
867 v->x[0] = 22;
868 v->y[0] = 39;
869 v->c[0] = 1;
870 v->x[1] = 78;
871 v->y[1] = 39;
872 v->c[1] = 1;
873 v->x[2] = 78;
874 v->y[2] = 61;
875 v->x[3] = 22;
876 v->y[3] = 61;
877 v->x[4] = 22;
878 v->y[4] = 39;
879 v->c[4] = 1;
880 break;
881 case 1:
882 v->num = 5;
883 v->x = (signed char*)safemalloc(sizeof(char) * v->num);
884 v->y = (signed char*)safemalloc(sizeof(char) * v->num);
885 v->xoff = (signed char*)safemalloc(sizeof(char) * v->num);
886 v->yoff = (signed char*)safemalloc(sizeof(char) * v->num);
887 v->c = (signed char*)safecalloc(v->num, sizeof(char));
888 v->x[0] = 32;
889 v->y[0] = 45;
890 v->x[1] = 68;
891 v->y[1] = 45;
892 v->x[2] = 68;
893 v->y[2] = 55;
894 v->c[2] = 1;
895 v->x[3] = 32;
896 v->y[3] = 55;
897 v->c[3] = 1;
898 v->x[4] = 32;
899 v->y[4] = 45;
900 break;
901 case 2:
902 v->num = 5;
903 v->x = (signed char*)safemalloc(sizeof(char) * v->num);
904 v->y = (signed char*)safemalloc(sizeof(char) * v->num);
905 v->xoff = (signed char*)safemalloc(sizeof(char) * v->num);
906 v->yoff = (signed char*)safemalloc(sizeof(char) * v->num);
907 v->c = (signed char*)safecalloc(v->num, sizeof(char));
908 v->x[0] = 49;
909 v->y[0] = 49;
910 v->c[0] = 1;
911 v->x[1] = 51;
912 v->y[1] = 49;
913 v->c[1] = 1;
914 v->x[2] = 51;
915 v->y[2] = 51;
916 v->x[3] = 49;
917 v->y[3] = 51;
918 v->x[4] = 49;
919 v->y[4] = 49;
920 v->c[4] = 1;
921 break;
922 case 3:
923 v->num = 5;
924 v->x = (signed char*)safemalloc(sizeof(char) * v->num);
925 v->y = (signed char*)safemalloc(sizeof(char) * v->num);
926 v->xoff = (signed char*)safemalloc(sizeof(char) * v->num);
927 v->yoff = (signed char*)safemalloc(sizeof(char) * v->num);
928 v->c = (signed char*)safecalloc(v->num, sizeof(char));
929 v->x[0] = 32;
930 v->y[0] = 45;
931 v->c[0] = 1;
932 v->x[1] = 68;
933 v->y[1] = 45;
934 v->c[1] = 1;
935 v->x[2] = 68;
936 v->y[2] = 55;
937 v->x[3] = 32;
938 v->y[3] = 55;
939 v->x[4] = 32;
940 v->y[4] = 45;
941 v->c[4] = 1;
942 break;
944 /* set offsets to 0, for all buttons */
945 for(j = 0 ; j < v->num ; j++)
947 v->xoff[j] = 0;
948 v->yoff[j] = 0;
951 return;
954 /***********************************************************************
956 * LoadDefaultRightButton -- loads default left button # into
957 * assumes associated button memory is already free
959 ************************************************************************/
960 static void LoadDefaultRightButton(DecorFace *df, int i)
962 struct vector_coords *v = &df->u.vector;
963 int j = 0;
965 memset(&df->style, 0, sizeof(df->style));
966 DFS_FACE_TYPE(df->style) = DefaultVectorButton;
967 switch (i % 5)
969 case 0:
970 case 3:
971 v->num = 5;
972 v->x = (signed char*)safemalloc(sizeof(char) * v->num);
973 v->y = (signed char*)safemalloc(sizeof(char) * v->num);
974 v->xoff = (signed char*)safemalloc(sizeof(char) * v->num);
975 v->yoff = (signed char*)safemalloc(sizeof(char) * v->num);
976 v->c = (signed char*)safecalloc(v->num, sizeof(char));
977 v->x[0] = 25;
978 v->y[0] = 25;
979 v->c[0] = 1;
980 v->x[1] = 75;
981 v->y[1] = 25;
982 v->c[1] = 1;
983 v->x[2] = 75;
984 v->y[2] = 75;
985 v->x[3] = 25;
986 v->y[3] = 75;
987 v->x[4] = 25;
988 v->y[4] = 25;
989 v->c[4] = 1;
990 break;
991 case 1:
992 v->num = 5;
993 v->x = (signed char*)safemalloc(sizeof(char) * v->num);
994 v->y = (signed char*)safemalloc(sizeof(char) * v->num);
995 v->xoff = (signed char*)safemalloc(sizeof(char) * v->num);
996 v->yoff = (signed char*)safemalloc(sizeof(char) * v->num);
997 v->c = (signed char*)safecalloc(v->num, sizeof(char));
998 v->x[0] = 39;
999 v->y[0] = 39;
1000 v->c[0] = 1;
1001 v->x[1] = 61;
1002 v->y[1] = 39;
1003 v->c[1] = 1;
1004 v->x[2] = 61;
1005 v->y[2] = 61;
1006 v->x[3] = 39;
1007 v->y[3] = 61;
1008 v->x[4] = 39;
1009 v->y[4] = 39;
1010 v->c[4] = 1;
1011 break;
1012 case 2:
1013 v->num = 5;
1014 v->x = (signed char*)safemalloc(sizeof(char) * v->num);
1015 v->y = (signed char*)safemalloc(sizeof(char) * v->num);
1016 v->xoff = (signed char*)safemalloc(sizeof(char) * v->num);
1017 v->yoff = (signed char*)safemalloc(sizeof(char) * v->num);
1018 v->c = (signed char*)safecalloc(v->num, sizeof(char));
1019 v->x[0] = 49;
1020 v->y[0] = 49;
1021 v->c[0] = 1;
1022 v->x[1] = 51;
1023 v->y[1] = 49;
1024 v->c[1] = 1;
1025 v->x[2] = 51;
1026 v->y[2] = 51;
1027 v->x[3] = 49;
1028 v->y[3] = 51;
1029 v->x[4] = 49;
1030 v->y[4] = 49;
1031 v->c[4] = 1;
1032 break;
1033 case 4:
1034 v->num = 5;
1035 v->x = (signed char*)safemalloc(sizeof(char) * v->num);
1036 v->y = (signed char*)safemalloc(sizeof(char) * v->num);
1037 v->xoff = (signed char*)safemalloc(sizeof(char) * v->num);
1038 v->yoff = (signed char*)safemalloc(sizeof(char) * v->num);
1039 v->c = (signed char*)safecalloc(v->num, sizeof(char));
1040 v->x[0] = 36;
1041 v->y[0] = 36;
1042 v->c[0] = 1;
1043 v->x[1] = 64;
1044 v->y[1] = 36;
1045 v->c[1] = 1;
1046 v->x[2] = 64;
1047 v->y[2] = 64;
1048 v->x[3] = 36;
1049 v->y[3] = 64;
1050 v->x[4] = 36;
1051 v->y[4] = 36;
1052 v->c[4] = 1;
1053 break;
1055 /* set offsets to 0, for all buttons */
1056 for(j = 0 ; j < v->num ; j++)
1058 v->xoff[j] = 0;
1059 v->yoff[j] = 0;
1062 return;
1065 /***********************************************************************
1067 * Procedure:
1068 * CreateGCs - open fonts and create all the needed GC's. I only
1069 * want to do this once, hence the first_time flag.
1071 ***********************************************************************/
1072 static void CreateGCs(void)
1074 XGCValues gcv;
1075 unsigned long gcm;
1076 XColor c;
1078 /* create scratch GC's */
1079 gcm = GCFunction|GCLineWidth;
1080 gcv.function = GXcopy;
1081 gcv.line_width = 0;
1083 Scr.ScratchGC1 = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
1084 Scr.ScratchGC2 = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
1085 Scr.ScratchGC3 = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
1086 Scr.ScratchGC4 = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
1087 Scr.TitleGC = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
1088 Scr.BordersGC = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
1089 Scr.TransMaskGC = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
1090 c.pixel = GetColor(DEFAULT_FORE_COLOR);
1091 Scr.ScratchMonoPixmap = XCreatePixmap(dpy, Scr.Root, 1, 1, 1);
1092 Scr.MonoGC = fvwmlib_XCreateGC(dpy, Scr.ScratchMonoPixmap, gcm, &gcv);
1093 Scr.ScratchAlphaPixmap = XCreatePixmap(
1094 dpy, Scr.Root, 1, 1, FRenderGetAlphaDepth());
1095 Scr.AlphaGC = fvwmlib_XCreateGC(dpy, Scr.ScratchAlphaPixmap, gcm, &gcv);
1096 return;
1099 /***********************************************************************
1101 * Procedure:
1102 * InitVariables - initialize fvwm variables
1104 ************************************************************************/
1105 static void InitVariables(void)
1107 FvwmContext = XUniqueContext();
1108 MenuContext = XUniqueContext();
1110 /* initialize some lists */
1111 Scr.AllBindings = NULL;
1112 Scr.functions = NULL;
1113 menus_init();
1114 Scr.last_added_item.type = ADDED_NONE;
1115 Scr.DefaultIcon = NULL;
1116 Scr.DefaultColorset = -1;
1117 Scr.StdGC = 0;
1118 Scr.StdReliefGC = 0;
1119 Scr.StdShadowGC = 0;
1120 Scr.XorGC = 0;
1121 /* zero all flags */
1122 memset(&Scr.flags, 0, sizeof(Scr.flags));
1123 /* create graphics contexts */
1124 CreateGCs();
1126 FW_W(&Scr.FvwmRoot) = Scr.Root;
1127 Scr.FvwmRoot.next = 0;
1128 init_stack_and_layers();
1129 Scr.root_pushes = 0;
1130 Scr.fvwm_pushes = 0;
1131 Scr.pushed_window = &Scr.FvwmRoot;
1132 Scr.FvwmRoot.number_cmap_windows = 0;
1133 Scr.FvwmRoot.attr_backup.colormap = Pcmap;
1135 Scr.MyDisplayWidth = DisplayWidth(dpy, Scr.screen);
1136 Scr.MyDisplayHeight = DisplayHeight(dpy, Scr.screen);
1137 Scr.BusyCursor = BUSY_NONE;
1138 Scr.Hilite = NULL;
1139 Scr.DefaultFont = NULL;
1140 Scr.VxMax = 2*Scr.MyDisplayWidth;
1141 Scr.VyMax = 2*Scr.MyDisplayHeight;
1142 Scr.Vx = 0;
1143 Scr.Vy = 0;
1144 Scr.SizeWindow = None;
1146 /* Sets the current desktop number to zero */
1147 /* Multiple desks are available even in non-virtual
1148 * compilations */
1149 Scr.CurrentDesk = 0;
1150 Scr.EdgeScrollX = DEFAULT_EDGE_SCROLL * Scr.MyDisplayWidth / 100;
1151 Scr.EdgeScrollY = DEFAULT_EDGE_SCROLL * Scr.MyDisplayHeight / 100;
1152 Scr.ScrollDelay = DEFAULT_SCROLL_DELAY;
1153 Scr.OpaqueSize = DEFAULT_OPAQUE_MOVE_SIZE;
1154 Scr.MoveThreshold = DEFAULT_MOVE_THRESHOLD;
1155 /* ClickTime is set to the positive value upon entering the
1156 * event loop. */
1157 Scr.ClickTime = -DEFAULT_CLICKTIME;
1158 Scr.ColormapFocus = COLORMAP_FOLLOWS_MOUSE;
1160 /* set major operating modes */
1161 Scr.NumBoxes = 0;
1162 Scr.cascade_x = 0;
1163 Scr.cascade_y = 0;
1164 /* the last Cascade placed window or NULL, we don't want NULL
1165 * initially */
1166 Scr.cascade_window = &Scr.FvwmRoot;
1167 Scr.buttons2grab = 0;
1168 /* initialisation of the head of the desktops info */
1169 Scr.Desktops = (DesktopsInfo *)safemalloc(sizeof(DesktopsInfo));
1170 Scr.Desktops->name = NULL;
1171 Scr.Desktops->desk = 0; /* not desk 0 */
1172 Scr.Desktops->ewmh_dyn_working_area.x =
1173 Scr.Desktops->ewmh_working_area.x = 0;
1174 Scr.Desktops->ewmh_dyn_working_area.y =
1175 Scr.Desktops->ewmh_working_area.y = 0;
1176 Scr.Desktops->ewmh_dyn_working_area.width =
1177 Scr.Desktops->ewmh_working_area.width = Scr.MyDisplayWidth;
1178 Scr.Desktops->ewmh_dyn_working_area.height =
1179 Scr.Desktops->ewmh_working_area.height = Scr.MyDisplayHeight;
1180 Scr.Desktops->next = NULL;
1181 /* ewmh desktop */
1182 Scr.EwmhDesktop = NULL;
1183 InitFvwmDecor(&Scr.DefaultDecor);
1184 #ifdef USEDECOR
1185 Scr.DefaultDecor.tag = "Default";
1186 #endif
1187 /* Initialize RaiseHackNeeded by identifying X servers
1188 possibly running under NT. This is probably not an
1189 ideal solution, since eg NCD also produces X servers
1190 which do not run under NT.
1192 "Hummingbird Communications Ltd."
1193 is the ServerVendor string of the Exceed X server under NT,
1195 "Network Computing Devices Inc."
1196 is the ServerVendor string of the PCXware X server under Windows.
1198 "WRQ, Inc."
1199 is the ServerVendor string of the Reflection X server under Windows.
1201 Scr.bo.is_raise_hack_needed =
1202 (strcmp (
1203 ServerVendor (dpy),
1204 "Hummingbird Communications Ltd.") == 0) ||
1205 (strcmp (
1206 ServerVendor (dpy),
1207 "Network Computing Devices Inc.") == 0) ||
1208 (strcmp (ServerVendor (dpy), "WRQ, Inc.") == 0);
1210 Scr.bo.is_modality_evil = 0;
1211 Scr.bo.do_disable_configure_notify = 0;
1212 Scr.bo.do_install_root_cmap = 0;
1213 Scr.bo.do_enable_flickering_qt_dialogs_workaround = 1;
1214 Scr.bo.do_enable_qt_drag_n_drop_workaround = 0;
1215 Scr.bo.do_enable_ewmh_iconic_state_workaround = 0;
1217 Scr.gs.do_emulate_mwm = DEFAULT_EMULATE_MWM;
1218 Scr.gs.do_emulate_win = DEFAULT_EMULATE_WIN;
1219 Scr.gs.use_active_down_buttons = DEFAULT_USE_ACTIVE_DOWN_BUTTONS;
1220 Scr.gs.use_inactive_buttons = DEFAULT_USE_INACTIVE_BUTTONS;
1221 Scr.gs.use_inactive_down_buttons = DEFAULT_USE_INACTIVE_DOWN_BUTTONS;
1222 /* Not the right place for this, should only be called once
1223 * somewhere .. */
1225 /* EdgeCommands - no edge commands by default */
1226 Scr.PanFrameTop.command = NULL;
1227 Scr.PanFrameBottom.command = NULL;
1228 Scr.PanFrameRight.command = NULL;
1229 Scr.PanFrameLeft.command = NULL;
1230 /* EdgeLeaveCommands - no edge leave commands by default */
1231 Scr.PanFrameTop.command_leave = NULL;
1232 Scr.PanFrameBottom.command_leave = NULL;
1233 Scr.PanFrameRight.command_leave = NULL;
1234 Scr.PanFrameLeft.command_leave = NULL;
1235 Scr.flags.is_pointer_on_this_screen = !!FQueryPointer(
1236 dpy, Scr.Root, &JunkRoot, &JunkChild, &JunkX, &JunkY, &JunkX,
1237 &JunkY, &JunkMask);
1239 /* make sure colorset 0 exists */
1240 alloc_colorset(0);
1242 return;
1245 static void usage(int is_verbose)
1247 fprintf(stderr, "usage: %s", g_argv[0]);
1248 fprintf(stderr,
1249 " [-d display]"
1250 " [-f cfgfile]"
1251 " [-c cmd]"
1252 " [-s [screen_num]]"
1253 " [-I vis-id | -C vis-class]"
1254 " [-l colors"
1255 " [-L|A|S|P] ...]"
1256 " [-r]"
1257 " [OTHER OPTIONS] ..."
1258 "\n");
1259 if (!is_verbose)
1261 fprintf(
1262 stderr, "Try '%s --help' for more information.\n",
1263 g_argv[0]);
1264 return;
1266 fprintf(stderr,
1267 " -A: allocate palette\n"
1268 " -c cmd: preprocess configuration file with <cmd>\n"
1269 " -C vis-class: use visual class <vis-class>\n"
1270 " -d display: run fvwm on <display>\n"
1271 " -D: enable debug oputput\n"
1272 " -f cfgfile: read configuration from <cfgfile>\n"
1273 " -F file: used internally for session management\n"
1274 " -h, -?: print this help message\n"
1275 " -i client-id: used internally for session management\n"
1276 " -I vis-id: use visual <vis-id>\n"
1277 " -l colors: try to use no more than <colors> colors\n"
1278 " -L: strict color limit\n"
1279 " -P: visual palette\n"
1280 " -r: replace running window manager\n"
1281 " -s [screen]: manage a single screen\n"
1282 " -S: static palette\n"
1283 " -V: print version information\n"
1285 fprintf(
1286 stderr, "Try 'man %s' for more information.\n",
1287 PACKAGE);
1289 return;
1292 static void setVersionInfo(void)
1294 char version_str[256];
1295 char license_str[512];
1296 char support_str[512] = "";
1297 int support_len;
1299 /* Set version information string */
1300 sprintf(version_str, "fvwm %s%s compiled on %s at %s",
1301 VERSION, VERSIONINFO, __DATE__, __TIME__);
1302 Fvwm_VersionInfo = safestrdup(version_str);
1304 sprintf(license_str,
1305 "fvwm comes with NO WARRANTY, to the extent permitted by law. "
1306 "You may\nredistribute copies of fvwm under "
1307 "the terms of the GNU General Public License.\n"
1308 "For more information about these matters, see the file "
1309 "named COPYING.");
1310 Fvwm_LicenseInfo = safestrdup(license_str);
1312 #ifdef HAVE_READLINE
1313 strcat(support_str, " ReadLine,");
1314 #endif
1315 #ifdef HAVE_RPLAY
1316 strcat(support_str, " RPlay,");
1317 #endif
1318 #ifdef HAVE_STROKE
1319 strcat(support_str, " Stroke,");
1320 #endif
1321 #ifdef XPM
1322 strcat(support_str, " XPM,");
1323 #endif
1324 #ifdef HAVE_PNG
1325 strcat(support_str, " PNG,");
1326 #endif
1327 #ifdef HAVE_RSVG
1328 strcat(support_str, " SVG,");
1329 #endif
1330 if (FHaveShapeExtension)
1331 strcat(support_str, " Shape,");
1332 #ifdef HAVE_XSHM
1333 strcat(support_str, " XShm,");
1334 #endif
1335 #ifdef SESSION
1336 strcat(support_str, " SM,");
1337 #endif
1338 #ifdef HAVE_BIDI
1339 strcat(support_str, " Bidi text,");
1340 #endif
1341 #ifdef HAVE_XINERAMA
1342 strcat(support_str, " Xinerama,");
1343 #endif
1344 #ifdef HAVE_XRENDER
1345 strcat(support_str, " XRender,");
1346 #endif
1347 #ifdef HAVE_XCURSOR
1348 strcat(support_str, " XCursor,");
1349 #endif
1350 #ifdef HAVE_XFT
1351 strcat(support_str, " XFT,");
1352 #endif
1353 #ifdef HAVE_NLS
1354 strcat(support_str, " NLS,");
1355 #endif
1357 support_len = strlen(support_str);
1358 if (support_len > 0)
1360 /* strip last comma */
1361 support_str[support_len - 1] = '\0';
1362 Fvwm_SupportInfo = safestrdup(
1363 CatString2("with support for:", support_str));
1365 else
1367 Fvwm_SupportInfo = "with no optional feature support";
1370 return;
1373 /* Sets some initial style values & such */
1374 static void SetRCDefaults(void)
1376 #define RC_DEFAULTS_COMPLETE ((char *)-1)
1377 int i;
1378 /* set up default colors, fonts, etc */
1379 const char *defaults[][3] = {
1380 { "XORValue 0", "", "" },
1381 { "DefaultFont", "", "" },
1382 { "DefaultColors black grey", "", "" },
1383 { DEFAULT_MENU_STYLE, "", "" },
1384 { "TitleStyle Centered -- Raised", "", "" },
1385 { "Style * Color lightgrey/dimgrey", "", "" },
1386 { "Style * HilightFore black, HilightBack grey", "", "" },
1388 "AddToMenu MenuFvwmRoot \"",
1389 _("Builtin Menu"),
1390 "\" Title"
1392 { "+ \"&1. XTerm\" Exec xterm", "", ""},
1394 "+ \"&2. ",
1395 _("Setup Form"),
1396 "\" Module FvwmForm FvwmForm-Setup"
1399 "+ \"&3. ",
1400 _("Setup 95 Script"),
1401 "\" Module FvwmScript FvwmScript-Setup95"
1404 "+ \"&4. ",
1405 _("Issue fvwm commands"),
1406 "\" Module FvwmConsole"
1409 "+ \"&R. ",
1410 _("Restart fvwm"),
1411 "\" Restart"
1414 "+ \"&X. ",
1415 _("Exit fvwm"),
1416 "\" Quit"
1418 { "Mouse 1 R A Menu MenuFvwmRoot", "", "" },
1419 /* default menu navigation */
1420 { "Key Escape M A MenuClose", "", "" },
1421 { "Key Return M A MenuSelectItem", "", "" },
1422 { "Key Left M A MenuCursorLeft", "", "" },
1423 { "Key Right M A MenuCursorRight", "", "" },
1424 { "Key Up M A MenuMoveCursor -1", "", "" },
1425 { "Key Down M A MenuMoveCursor 1", "", "" },
1426 { "Mouse 1 MI A MenuSelectItem", "", "" },
1427 /* don't add anything below */
1428 { RC_DEFAULTS_COMPLETE, "", "" },
1429 { "Read "FVWM_DATADIR"/ConfigFvwmDefaults", "", "" },
1430 { NULL, NULL, NULL }
1433 for (i = 0; defaults[i][0] != NULL; i++)
1435 const exec_context_t *exc;
1436 exec_context_changes_t ecc;
1437 char *cmd;
1439 if (defaults[i][0] == RC_DEFAULTS_COMPLETE)
1441 menu_bindings_startup_complete();
1442 continue;
1444 ecc.type = Restarting ? EXCT_RESTART : EXCT_INIT;
1445 ecc.w.wcontext = C_ROOT;
1446 exc = exc_create_context(&ecc, ECC_TYPE | ECC_WCONTEXT);
1447 cmd = CatString3(
1448 defaults[i][0], defaults[i][1], defaults[i][2]);
1449 execute_function(NULL, exc, cmd, 0);
1450 exc_destroy_context(exc);
1452 #undef RC_DEFAULTS_COMPLETE
1454 return;
1457 static int CatchRedirectError(Display *dpy, XErrorEvent *event)
1459 fvwm_msg(ERR, "CatchRedirectError", "another WM is running");
1460 exit(1);
1462 /* to make insure happy */
1463 return 0;
1466 /* CatchFatal - Shuts down if the server connection is lost */
1467 static int CatchFatal(Display *dpy)
1469 /* No action is taken because usually this action is caused by someone
1470 using "xlogout" to be able to switch between multiple window managers
1472 module_kill_all();
1473 exit(1);
1475 /* to make insure happy */
1476 return 0;
1479 /* FvwmErrorHandler - displays info on internal errors */
1480 static int FvwmErrorHandler(Display *dpy, XErrorEvent *event)
1482 if (event->error_code == BadWindow)
1484 bad_window = event->resourceid;
1485 return 0;
1487 /* some errors are acceptable, mostly they're caused by
1488 * trying to update a lost window or free'ing another modules colors */
1489 if (event->error_code == BadWindow ||
1490 event->request_code == X_GetGeometry ||
1491 event->error_code == BadDrawable ||
1492 event->request_code == X_ConfigureWindow ||
1493 event->request_code == X_SetInputFocus||
1494 event->request_code == X_GrabButton ||
1495 event->request_code == X_ChangeWindowAttributes ||
1496 event->request_code == X_InstallColormap ||
1497 event->request_code == X_FreePixmap ||
1498 event->request_code == X_FreeColors)
1500 return 0;
1502 fvwm_msg(ERR, "FvwmErrorHandler", "*** internal error ***");
1503 fvwm_msg(ERR, "FvwmErrorHandler", "Request %d, Error %d, EventType: %d",
1504 event->request_code,
1505 event->error_code,
1506 last_event_type);
1508 return 0;
1511 /* ---------------------------- interface functions ------------------------ */
1513 /* Does initial window captures and runs init/restart function */
1514 void StartupStuff(void)
1516 #define start_func_name "StartFunction"
1517 const char *init_func_name;
1518 const exec_context_t *exc;
1519 exec_context_changes_t ecc;
1521 ecc.type = Restarting ? EXCT_RESTART : EXCT_INIT;
1522 ecc.w.wcontext = C_ROOT;
1523 exc = exc_create_context(&ecc, ECC_TYPE | ECC_WCONTEXT);
1524 CaptureAllWindows(exc, False);
1525 /* Turn off the SM stuff after the initial capture so that new windows
1526 * will not be matched by accident. */
1527 if (Restarting)
1529 DisableRestoringState();
1531 /* Have to do this here too because preprocessor modules have not run
1532 * to the end when HandleEvents is entered from the main loop. */
1533 checkPanFrames();
1535 fFvwmInStartup = False;
1537 /* Make sure the geometry window uses the current font */
1538 resize_geometry_window();
1540 /* Make sure we have the correct click time now. */
1541 if (Scr.ClickTime < 0)
1543 Scr.ClickTime = -Scr.ClickTime;
1546 # if 0
1547 /* It is safe to ungrab here: if not, and one of the init functions
1548 * does not finish, we've got a complete freeze! */
1549 /* DV (15-Jul-2004): No, it is not safe to ungrab. If another
1550 * application grabs the pointer before execute_function gets it, the
1551 * start functions are not executed. And the pointer is grabbed
1552 * during function execution anyway, so releasing it here buys us
1553 * nothing. */
1554 UngrabEm(GRAB_STARTUP);
1555 XUngrabPointer(dpy, CurrentTime);
1556 #endif
1558 /* migo (04-Sep-1999): execute StartFunction */
1559 if (functions_is_complex_function(start_func_name))
1561 char *action = "Function " start_func_name;
1563 execute_function(NULL, exc, action, 0);
1566 /* migo (03-Jul-1999): execute [Session]{Init|Restart}Function */
1567 init_func_name = get_init_function_name(Restarting == True);
1568 if (functions_is_complex_function(init_func_name))
1570 char *action = safestrdup(
1571 CatString2("Function ", init_func_name));
1573 execute_function(NULL, exc, action, 0);
1574 free(action);
1576 /* see comment above */
1577 UngrabEm(GRAB_STARTUP);
1578 XUngrabPointer(dpy, CurrentTime);
1580 /* This should be done after the initialization is finished, since
1581 * it directly changes the global state. */
1582 LoadGlobalState(state_filename);
1585 ** migo (20-Jun-1999): Remove state file after usage.
1586 ** migo (09-Jul-1999): but only on restart, otherwise it can be reused.
1588 if (Restarting)
1590 unlink(state_filename);
1592 exc_destroy_context(exc);
1594 /* TA: 20091212: If we get here, we're done restarting, so reset the
1595 * flag back to False!
1597 Restarting = False;
1599 return;
1602 /***********************************************************************
1604 * LoadDefaultButton -- loads default button # into button structure
1605 * assumes associated button memory is already free
1607 ************************************************************************/
1608 void LoadDefaultButton(DecorFace *df, int i)
1610 if (i & 1)
1612 LoadDefaultRightButton(df, i / 2);
1614 else
1616 LoadDefaultLeftButton(df, i / 2);
1619 return;
1622 /***********************************************************************
1624 * ResetOrDestroyAllButtons -- resets all buttons to defaults
1625 * destroys existing buttons
1627 ************************************************************************/
1628 void DestroyAllButtons(FvwmDecor *decor)
1630 TitleButton *tbp;
1631 DecorFace *face;
1632 int i;
1633 int j;
1635 for (tbp = decor->buttons, i = 0; i < NUMBER_OF_TITLE_BUTTONS;
1636 i++, tbp++)
1638 for (j = 0, face = TB_STATE(*tbp); j < BS_MaxButtonState;
1639 j++, face++)
1641 FreeDecorFace(dpy, face);
1645 return;
1648 void ResetAllButtons(FvwmDecor *decor)
1650 TitleButton *tbp;
1651 DecorFace *face;
1652 int i;
1653 int j;
1655 DestroyAllButtons(decor);
1656 for (tbp = decor->buttons, i = 0; i < NUMBER_OF_TITLE_BUTTONS;
1657 i++, tbp++)
1659 memset(&TB_FLAGS(*tbp), 0, sizeof(TB_FLAGS(*tbp)));
1660 TB_JUSTIFICATION(*tbp) = JUST_CENTER;
1661 for (face = TB_STATE(*tbp), j = 0; j < BS_MaxButtonState;
1662 j++, face++)
1664 LoadDefaultButton(face, i);
1668 /* standard MWM decoration hint assignments (veliaa@rpi.edu)
1669 [Menu] - Title Bar - [Minimize] [Maximize] */
1670 TB_MWM_DECOR_FLAGS(decor->buttons[0]) |= MWM_DECOR_MENU;
1671 TB_MWM_DECOR_FLAGS(decor->buttons[1]) |= MWM_DECOR_MAXIMIZE;
1672 TB_MWM_DECOR_FLAGS(decor->buttons[3]) |= MWM_DECOR_MINIMIZE;
1674 return;
1677 void SetMWM_INFO(Window window)
1679 struct mwminfo
1681 long props[2];
1682 /* prop[0]: flags */
1683 /* prop[1]: win */
1684 } motif_wm_info;
1685 static char set_yorn='n';
1687 if (set_yorn=='y')
1689 return;
1692 if (Scr.bo.is_modality_evil)
1694 /* Set Motif WM_INFO atom to make motif relinquish
1695 * broken handling of modal dialogs */
1696 motif_wm_info.props[0] = 2;
1697 motif_wm_info.props[1] = window;
1698 XChangeProperty(
1699 dpy,Scr.Root, _XA_MOTIF_WM, _XA_MOTIF_WM,32,
1700 PropModeReplace, (unsigned char *)&motif_wm_info, 2);
1701 set_yorn='y';
1704 return;
1708 * set_init_function_name - sets one of the init, restart or exit function names
1709 * get_init_function_name - gets one of the init, restart or exit function names
1711 * First parameter defines a function type: 0 - init, 1 - restart, 2 - exit.
1713 void set_init_function_name(int n, const char *name)
1715 init_function_names[n >= 0 && n < 3? n: 3] = name;
1717 return;
1720 const char *get_init_function_name(int n)
1722 return init_function_names[n >= 0 && n < 3? n: 3];
1725 #ifndef _PATH_DEVNULL
1726 # define _PATH_DEVNULL "/dev/null"
1727 #endif
1728 static void reopen_fd(int fd, char* mode, FILE *of)
1730 struct stat sbuf;
1731 FILE *f;
1732 int rc;
1734 errno = 0;
1735 rc = fstat(fd, &sbuf);
1736 if (rc == 0)
1738 return;
1740 else if (errno != EBADF)
1742 exit(77);
1744 f = freopen(_PATH_DEVNULL, mode, of);
1745 if (f == 0 || fileno(f) != fd)
1747 exit(88);
1750 return;
1753 /***********************************************************************
1755 * Procedure:
1756 * main - start of fvwm
1758 ***********************************************************************/
1760 int main(int argc, char **argv)
1762 unsigned long valuemask;
1763 XSetWindowAttributes attributes;
1764 int i;
1765 int len;
1766 char *display_string;
1767 Bool do_force_single_screen = False;
1768 int single_screen_num = -1;
1769 Bool replace_wm = False;
1770 int visualClass = -1;
1771 int visualId = -1;
1772 PictureColorLimitOption colorLimitop = {-1, -1, -1, -1, -1};
1773 const exec_context_t *exc;
1774 exec_context_changes_t ecc;
1776 DBUG("main", "Entered, about to parse args");
1778 fvwmlib_init_max_fd();
1779 /* close open fds */
1780 for (i = 3; i < fvwmlib_max_fd; i++)
1782 close(i);
1784 /* reopen stdin, stdout and stderr if necessary */
1785 reopen_fd(0, "rb", stdin);
1786 reopen_fd(1, "wb", stdout);
1787 reopen_fd(2, "wb", stderr);
1789 memset(&Scr, 0, sizeof(Scr));
1790 /* for use on restart */
1791 g_argv = (char **)safemalloc((argc + 4) * sizeof(char *));
1792 g_argc = argc;
1793 for (i = 0; i < argc; i++)
1795 g_argv[i] = argv[i];
1797 g_argv[g_argc] = NULL;
1799 FlocaleInit(LC_CTYPE, "", "", "fvwm");
1800 FGettextInit("fvwm", LOCALEDIR, "fvwm");
1802 setVersionInfo();
1803 /* Put the default module directory into the environment so it can be
1804 * used later by the config file, etc. */
1805 flib_putenv("FVWM_MODULEDIR", "FVWM_MODULEDIR=" FVWM_MODULEDIR);
1807 /* Figure out user's home directory */
1808 home_dir = getenv("HOME");
1809 #ifdef HAVE_GETPWUID
1810 if (home_dir == NULL)
1812 struct passwd* pw = getpwuid(getuid());
1813 if (pw != NULL)
1815 home_dir = safestrdup(pw->pw_dir);
1818 #endif
1819 if (home_dir == NULL)
1821 home_dir = "/"; /* give up and use root dir */
1824 /* Figure out where to read and write user's data files. */
1825 fvwm_userdir = getenv("FVWM_USERDIR");
1826 if (fvwm_userdir == NULL)
1828 char *s;
1830 fvwm_userdir = safestrdup(CatString2(home_dir, "/.fvwm"));
1831 /* Put the user directory into the environment so it can be used
1832 * later everywhere. */
1833 s = safestrdup(CatString2("FVWM_USERDIR=", fvwm_userdir));
1834 flib_putenv("FVWM_USERDIR", s);
1835 free(s);
1838 /* Create FVWM_USERDIR directory if needed */
1839 if (access(fvwm_userdir, F_OK) != 0)
1841 mkdir(fvwm_userdir, 0777);
1843 if (access(fvwm_userdir, W_OK) != 0)
1845 fvwm_msg(
1846 ERR, "main", "No write permissions in `%s/'.\n",
1847 fvwm_userdir);
1850 for (i = 1; i < argc; i++)
1852 if (strcmp(argv[i], "-debug_stack_ring") == 0 ||
1853 strcmp(argv[i], "--debug-stack-ring") == 0)
1855 debugging_stack_ring = True;
1857 else if (strcmp(argv[i], "-D") == 0 ||
1858 strcmp(argv[i], "-debug") == 0 ||
1859 strcmp(argv[i], "--debug") == 0)
1861 debugging = True;
1863 else if (strcmp(argv[i], "-i") == 0 ||
1864 strcmp(argv[i], "-clientid") == 0 ||
1865 strcmp(argv[i], "--clientid") == 0 ||
1866 strcmp(argv[i], "-clientId") == 0 ||
1867 strcmp(argv[i], "--clientId") == 0)
1869 if (++i >= argc)
1871 usage(0);
1872 exit(1);
1874 SetClientID(argv[i]);
1876 else if (strcmp(argv[i], "-F") == 0 ||
1877 strcmp(argv[i], "-restore") == 0 ||
1878 strcmp(argv[i], "--restore") == 0)
1880 if (++i >= argc)
1882 usage(0);
1883 exit(1);
1885 state_filename = argv[i];
1887 else if (strcmp(argv[i], "-s") == 0 ||
1888 strcmp(argv[i], "-single-screen") == 0 ||
1889 strcmp(argv[i], "--single-screen") == 0)
1891 do_force_single_screen = True;
1892 if (i+1 < argc && argv[i+1][0] != '-')
1894 i++;
1895 if (sscanf(argv[i], "%d", &single_screen_num) ==
1898 usage(0);
1899 exit(1);
1903 else if (strcmp(argv[i], "-d") == 0 ||
1904 strcmp(argv[i], "-display") == 0 ||
1905 strcmp(argv[i], "--display") == 0)
1907 if (++i >= argc)
1909 usage(0);
1910 exit(1);
1912 display_name = argv[i];
1914 else if (strcmp(argv[i], "-f") == 0)
1916 if (++i >= argc)
1918 usage(0);
1919 exit(1);
1921 if (num_config_commands < MAX_CFG_CMDS)
1923 config_commands[num_config_commands] =
1924 (char *)malloc(6+strlen(argv[i]));
1925 strcpy(config_commands[num_config_commands],
1926 "Read ");
1927 strcat(config_commands[num_config_commands],
1928 argv[i]);
1929 num_config_commands++;
1931 else
1933 fvwm_msg(
1934 ERR, "main",
1935 "only %d -f and -cmd parms allowed!",
1936 MAX_CFG_CMDS);
1939 else if (strcmp(argv[i], "-c") == 0 ||
1940 strcmp(argv[i], "-cmd") == 0 ||
1941 strcmp(argv[i], "--cmd") == 0)
1943 if (++i >= argc)
1945 usage(0);
1946 exit(1);
1948 if (num_config_commands < MAX_CFG_CMDS)
1950 config_commands[num_config_commands] =
1951 safestrdup(argv[i]);
1952 num_config_commands++;
1954 else
1956 fvwm_msg(
1957 ERR, "main",
1958 "only %d -f and -cmd parms allowed!",
1959 MAX_CFG_CMDS);
1962 else if (strcmp(argv[i], "-h") == 0 ||
1963 strcmp(argv[i], "-?") == 0 ||
1964 strcmp(argv[i], "--help") == 0)
1966 usage(1);
1967 exit(0);
1969 else if (strcmp(argv[i], "-blackout") == 0)
1971 /* obsolete option */
1972 fvwm_msg(
1973 WARN, "main",
1974 "The -blackout option is obsolete, it will be "
1975 "removed in 3.0.");
1977 else if (strcmp(argv[i], "-r") == 0 ||
1978 strcmp(argv[i], "-replace") == 0 ||
1979 strcmp(argv[i], "--replace") == 0)
1981 replace_wm = True;
1983 /* check for visualId before visual to remove ambiguity */
1984 else if (strcmp(argv[i], "-I") == 0 ||
1985 strcmp(argv[i], "-visualid") == 0 ||
1986 strcmp(argv[i], "--visualid") == 0 ||
1987 strcmp(argv[i], "-visualId") == 0 ||
1988 strcmp(argv[i], "--visualId") == 0)
1990 visualClass = -1;
1991 if (++i >= argc)
1993 usage(0);
1994 exit(1);
1996 if (sscanf(argv[i], "0x%x", &visualId) == 0)
1998 if (sscanf(argv[i], "%d", &visualId) == 0)
2000 usage(0);
2001 exit(1);
2005 else if (strcmp(argv[i], "-C") == 0 ||
2006 strcmp(argv[i], "-visual") == 0 ||
2007 strcmp(argv[i], "--visual") == 0)
2009 visualId = None;
2010 if (++i >= argc)
2012 usage(0);
2013 exit(1);
2015 if (strncasecmp(argv[i], "staticg", 7) == 0)
2017 visualClass = StaticGray;
2019 else if (strncasecmp(argv[i], "g", 1) == 0)
2021 visualClass = GrayScale;
2023 else if (strncasecmp(argv[i], "staticc", 7) == 0)
2025 visualClass = StaticColor;
2027 else if (strncasecmp(argv[i], "p", 1) == 0)
2029 visualClass = PseudoColor;
2031 else if (strncasecmp(argv[i], "t", 1) == 0)
2033 visualClass = TrueColor;
2035 else if (strncasecmp(argv[i], "d", 1) == 0)
2037 visualClass = DirectColor;
2039 else
2041 usage(0);
2042 exit(1);
2045 else if (strcmp(argv[i], "-l") == 0 ||
2046 strcmp(argv[i], "-color-limit") == 0 ||
2047 strcmp(argv[i], "--color-limit") == 0)
2049 if (++i >= argc)
2051 usage(0);
2052 exit(1);
2054 colorLimitop.color_limit = atoi(argv[i]);
2056 else if (strcmp(argv[i], "-L") == 0 ||
2057 strcmp(argv[i], "-strict-color-limit") == 0 ||
2058 strcmp(argv[i], "--strict-color-limit") == 0)
2060 colorLimitop.strict = True;
2062 else if (strcmp(argv[i], "-A") == 0 ||
2063 strcmp(argv[i], "-allocate-palette") == 0 ||
2064 strcmp(argv[i], "--allocate-palette") == 0)
2066 colorLimitop.allocate = True;
2068 else if (strcmp(argv[i], "-S") == 0 ||
2069 strcmp(argv[i], "-static-palette") == 0 ||
2070 strcmp(argv[i], "--static-palette") == 0)
2072 colorLimitop.not_dynamic = True;
2074 else if (strcmp(argv[i], "-P") == 0 ||
2075 strcmp(argv[i], "-visual-palette") == 0 ||
2076 strcmp(argv[i], "--visual-palette") == 0)
2078 colorLimitop.use_named_table = True;
2080 else if (strcmp(argv[i], "-V") == 0 ||
2081 strcmp(argv[i], "-version") == 0 ||
2082 strcmp(argv[i], "--version") == 0)
2084 printf("%s\n%s\n\n%s\n", Fvwm_VersionInfo,
2085 Fvwm_SupportInfo, Fvwm_LicenseInfo);
2086 exit(0);
2088 else
2090 usage(0);
2091 fprintf(stderr, "invalid option -- %s\n", argv[i]);
2092 exit(1);
2096 DBUG("main", "Done parsing args");
2098 DBUG("main", "Installing signal handlers");
2099 InstallSignals();
2101 if (single_screen_num >= 0)
2103 char *dn = NULL;
2105 if (display_name)
2107 dn = display_name;
2109 if (!dn)
2111 dn = getenv("DISPLAY");
2113 if (!dn)
2115 /* should never happen ? */
2116 if (!(dpy = XOpenDisplay(dn)))
2118 fvwm_msg(
2119 ERR, "main", "can't open display %s"
2120 "to get the default display",
2121 XDisplayName(dn));
2123 else
2125 dn = XDisplayString(dpy);
2128 if (dn == NULL)
2130 fvwm_msg(
2131 ERR,
2132 "main", "couldn't find default display (%s)",
2133 XDisplayName(dn));
2135 else
2137 char *new_dn;
2139 new_dn = get_display_name(dn, single_screen_num);
2140 if (dpy && strcmp(new_dn, dn) == 0)
2142 /* allready opened */
2143 Pdpy = dpy;
2145 else if (dpy)
2147 XCloseDisplay(dpy);
2148 dpy = NULL;
2150 if (!dpy && !(Pdpy = dpy = XOpenDisplay(new_dn)))
2152 fvwm_msg(
2153 ERR, "main",
2154 "can't open display %s, single screen "
2155 "number %d maybe not correct",
2156 new_dn, single_screen_num);
2158 Scr.screen = single_screen_num;
2159 Scr.NumberOfScreens = ScreenCount(dpy);
2160 free(new_dn);
2164 if (!dpy)
2166 if(!(Pdpy = dpy = XOpenDisplay(display_name)))
2168 fvwm_msg(
2169 ERR, "main", "can't open display %s",
2170 XDisplayName(display_name));
2171 exit (1);
2173 Scr.screen= DefaultScreen(dpy);
2174 Scr.NumberOfScreens = ScreenCount(dpy);
2177 atexit(catch_exit);
2178 master_pid = getpid();
2180 if (!do_force_single_screen)
2182 int myscreen = 0;
2183 char *new_dn;
2184 char *dn;
2186 dn = XDisplayString(dpy);
2187 for (i=0;i<Scr.NumberOfScreens;i++)
2189 if (i != Scr.screen && fork() == 0)
2191 myscreen = i;
2192 new_dn = get_display_name(dn, myscreen);
2193 Pdpy = dpy = XOpenDisplay(new_dn);
2194 Scr.screen = myscreen;
2195 Scr.NumberOfScreens = ScreenCount(dpy);
2196 free(new_dn);
2198 break;
2202 g_argv[argc++] = "-s";
2203 g_argv[argc] = NULL;
2205 FScreenInit(dpy);
2206 x_fd = XConnectionNumber(dpy);
2208 #ifdef HAVE_X11_FD
2209 if (fcntl(x_fd, F_SETFD, 1) == -1)
2211 fvwm_msg(ERR, "main", "close-on-exec failed");
2212 exit (1);
2214 #endif
2216 /* Add a DISPLAY entry to the environment, incase we were started
2217 * with fvwm -display term:0.0 */
2218 len = strlen(XDisplayString(dpy));
2219 display_string = safemalloc(len+10);
2220 sprintf(display_string, "DISPLAY=%s",XDisplayString(dpy));
2221 flib_putenv("DISPLAY", display_string);
2222 /* Add a HOSTDISPLAY environment variable, which is the same as
2223 * DISPLAY, unless display = :0.0 or unix:0.0, in which case the full
2224 * host name will be used for ease in networking.
2226 if (strncmp(display_string, "DISPLAY=:",9)==0)
2228 char client[MAXHOSTNAME], *rdisplay_string;
2229 gethostname(client,MAXHOSTNAME);
2230 rdisplay_string = safemalloc(len+14 + strlen(client));
2231 sprintf(rdisplay_string, "HOSTDISPLAY=%s:%s", client,
2232 &display_string[9]);
2233 flib_putenv("HOSTDISPLAY", rdisplay_string);
2234 free(rdisplay_string);
2236 else if (strncmp(display_string, "DISPLAY=unix:",13)==0)
2238 char client[MAXHOSTNAME], *rdisplay_string;
2239 gethostname(client,MAXHOSTNAME);
2240 rdisplay_string = safemalloc(len+14 + strlen(client));
2241 sprintf(rdisplay_string, "HOSTDISPLAY=%s:%s", client,
2242 &display_string[13]);
2243 flib_putenv("HOSTDISPLAY", rdisplay_string);
2244 free(rdisplay_string);
2246 else
2248 char *rdisplay_string;
2249 rdisplay_string = safemalloc(len+14);
2250 sprintf(rdisplay_string, "HOSTDISPLAY=%s",XDisplayString(dpy));
2251 flib_putenv("HOSTDISPLAY", rdisplay_string);
2252 free(rdisplay_string);
2254 free(display_string);
2256 Scr.Root = RootWindow(dpy, Scr.screen);
2257 if (Scr.Root == None)
2259 fvwm_msg(
2260 ERR, "main", "Screen %d is not a valid screen",
2261 (int)Scr.screen);
2262 exit(1);
2266 XVisualInfo template, *vinfo = NULL;
2267 int total, i;
2269 Pdepth = 0;
2270 Pdefault = False;
2271 total = 0;
2272 template.screen = Scr.screen;
2273 if (visualClass != -1)
2275 template.class = visualClass;
2276 vinfo = XGetVisualInfo(dpy,
2277 VisualScreenMask|VisualClassMask,
2278 &template, &total);
2279 if (!total)
2281 fvwm_msg(ERR, "main",
2282 "Cannot find visual class %d",
2283 visualClass);
2286 else if (visualId != -1)
2288 template.visualid = visualId;
2289 vinfo = XGetVisualInfo(dpy,
2290 VisualScreenMask|VisualIDMask,
2291 &template, &total);
2292 if (!total)
2294 fvwm_msg(ERR, "main",
2295 "VisualId 0x%x is not valid ",
2296 visualId);
2300 /* visualID's are unique so there will only be one.
2301 Select the visualClass with the biggest depth */
2302 for (i = 0; i < total; i++)
2304 if (vinfo[i].depth > Pdepth)
2306 Pvisual = vinfo[i].visual;
2307 Pdepth = vinfo[i].depth;
2310 if (vinfo)
2312 XFree(vinfo);
2315 /* Detection of a card with 2 hardware colormaps (8+24) which
2316 * use depth 8 for the default. We can use our own depth 24
2317 * cmap without affecting other applications. */
2318 if (Pdepth == 0 && DefaultDepth(dpy, Scr.screen) <= 8)
2320 template.class = TrueColor;
2321 vinfo = XGetVisualInfo(
2322 dpy, VisualScreenMask|VisualClassMask,
2323 &template, &total);
2325 for(i = 0; i<total; i++)
2327 if (Pdepth < vinfo[i].depth &&
2328 vinfo[i].depth > 8)
2330 Pvisual = vinfo[i].visual;
2331 Pdepth = vinfo[i].depth;
2334 if (vinfo)
2336 XFree(vinfo);
2340 /* have to have a colormap for non-default visual windows */
2341 if (Pdepth > 0)
2343 if (Pvisual->class == DirectColor)
2345 Pcmap = XCreateColormap(
2346 dpy, Scr.Root, Pvisual, AllocAll);
2348 else
2350 Pcmap = XCreateColormap(
2351 dpy, Scr.Root, Pvisual, AllocNone);
2354 /* use default visuals if none found so far */
2355 else
2357 Pvisual = DefaultVisual(dpy, Scr.screen);
2358 Pdepth = DefaultDepth(dpy, Scr.screen);
2359 Pcmap = DefaultColormap(dpy, Scr.screen);
2360 Pdefault = True;
2364 PictureSetupWhiteAndBlack();
2366 /* make a copy of the visual stuff so that XorPixmap can swap with root
2368 PictureSaveFvwmVisual();
2370 Scr.ColorLimit = 0;
2371 PUseDynamicColors = 0;
2372 Scr.ColorLimit = PictureInitColors(
2373 PICTURE_CALLED_BY_FVWM, True, &colorLimitop, True, True);
2375 Frsvg_init();
2376 FShapeInit(dpy);
2377 FRenderInit(dpy);
2378 Scr.pscreen = XScreenOfDisplay(dpy, Scr.screen);
2379 Scr.use_backing_store = DoesBackingStore(Scr.pscreen);
2380 Scr.flags.do_save_under = DoesSaveUnders(Scr.pscreen);
2382 InternUsefulAtoms();
2384 /* Make sure property priority colors is empty */
2385 XChangeProperty(dpy, Scr.Root, _XA_MIT_PRIORITY_COLORS,
2386 XA_CARDINAL, 32, PropModeReplace, NULL, 0);
2388 Scr.FvwmCursors = CreateCursors(dpy);
2389 XDefineCursor(dpy, Scr.Root, Scr.FvwmCursors[CRS_ROOT]);
2390 /* create a window which will accept the keyboard focus when no other
2391 * windows have it */
2392 /* do this before any RC parsing as some GC's are created from this
2393 * window rather than the root window */
2394 attributes.event_mask = XEVMASK_NOFOCUSW;
2395 attributes.override_redirect = True;
2396 attributes.colormap = Pcmap;
2397 attributes.cursor = Scr.FvwmCursors[CRS_DEFAULT];
2398 attributes.background_pixmap = None;
2399 attributes.border_pixel = 0;
2400 Scr.NoFocusWin=XCreateWindow(
2401 dpy, Scr.Root, -10, -10, 10, 10, 0, Pdepth, InputOutput,
2402 Pvisual, CWEventMask | CWOverrideRedirect | CWColormap |
2403 CWBackPixmap | CWBorderPixel | CWCursor, &attributes);
2404 XMapWindow(dpy, Scr.NoFocusWin);
2405 SetMWM_INFO(Scr.NoFocusWin);
2406 FOCUS_SET(Scr.NoFocusWin);
2408 frame_init();
2409 XFlush(dpy);
2410 if (debugging)
2412 sync_server(1);
2415 SetupICCCM2(replace_wm);
2416 XSetIOErrorHandler(CatchFatal);
2418 /* We need to catch any errors of XSelectInput on the root
2419 * window here. The event mask contains
2420 * SubstructureRedirectMask which can be acquired by exactly
2421 * one client (window manager). Synchronizing is necessary
2422 * here because Neither XSetErrorHandler nor XSelectInput
2423 * generate any protocol requests.
2425 XSync(dpy, 0);
2426 XSetErrorHandler(CatchRedirectError);
2427 XSelectInput(dpy, Scr.Root, XEVMASK_ROOTW);
2428 XSync(dpy, 0);
2429 XSetErrorHandler(FvwmErrorHandler);
2432 /* do not grab the pointer earlier because if fvwm exits with
2433 * the pointer grabbed while a different display is visible,
2434 * XFree 4.0 freezes. */
2435 Cursor cursor = XCreateFontCursor(dpy, XC_watch);
2436 XGrabPointer(
2437 dpy, Scr.Root, 0, 0, GrabModeAsync, GrabModeAsync,
2438 None, cursor, CurrentTime);
2441 Atom atype;
2442 int aformat;
2443 unsigned long nitems, bytes_remain;
2444 unsigned char *prop;
2446 if (XGetWindowProperty(
2447 dpy, Scr.Root, _XA_WM_DESKTOP, 0L, 1L, True,
2448 _XA_WM_DESKTOP, &atype, &aformat, &nitems,
2449 &bytes_remain, &prop) == Success)
2451 if (prop != NULL)
2453 Restarting = True;
2454 /* do_force_single_screen = True; */
2458 restart_state_filename = safestrdup(
2459 CatString3(fvwm_userdir, "/.fs-restart-",
2460 getenv("HOSTDISPLAY")));
2461 if (!state_filename && Restarting)
2463 state_filename = restart_state_filename;
2466 /* This should be done early enough to have the window states loaded
2467 * before the first call to AddWindow. */
2468 LoadWindowStates(state_filename);
2470 InitVariables();
2471 if (visualClass != -1 || visualId != -1)
2473 /* this is so that menus use the (non-default) fvwm colormap */
2474 FW_W(&Scr.FvwmRoot) = Scr.NoFocusWin;
2475 Scr.FvwmRoot.number_cmap_windows = 1;
2476 Scr.FvwmRoot.cmap_windows = &Scr.NoFocusWin;
2478 InitEventHandlerJumpTable();
2480 Scr.gray_bitmap =
2481 XCreateBitmapFromData(dpy,Scr.Root,g_bits, g_width,g_height);
2483 EWMH_Init();
2485 DBUG("main", "Setting up rc file defaults...");
2486 SetRCDefaults();
2487 flush_window_updates();
2488 simplify_style_list();
2490 DBUG("main", "Running config_commands...");
2491 ecc.type = Restarting ? EXCT_RESTART : EXCT_INIT;
2492 ecc.w.wcontext = C_ROOT;
2493 exc = exc_create_context(&ecc, ECC_TYPE | ECC_WCONTEXT);
2494 if (num_config_commands > 0)
2496 int i;
2497 for (i = 0; i < num_config_commands; i++)
2499 DoingCommandLine = True;
2500 execute_function(NULL, exc, config_commands[i], 0);
2501 free(config_commands[i]);
2503 DoingCommandLine = False;
2505 else
2507 /* Run startup command file in these places (default prefix):
2508 * ~/.fvwm/config
2509 * /usr/local/share/fvwm/config
2510 * and for compatibility:
2511 * ~/.fvwm/.fvwm2rc
2512 * /usr/local/share/fvwm/system.fvwm2rc
2513 * and for compatibility to be discontinued:
2514 * ~/.fvwm2rc,
2515 * /usr/local/share/fvwm/.fvwm2rc
2516 * /usr/local/etc/system.fvwm2rc
2518 if (
2519 !run_command_file(CatString3(
2520 fvwm_userdir, "/", FVWM_CONFIG), exc) &&
2521 !run_command_file(CatString3(
2522 FVWM_DATADIR, "/", FVWM_CONFIG), exc) &&
2523 !run_command_file(CatString3(
2524 fvwm_userdir, "/", FVWM2RC), exc) &&
2525 !run_command_file(CatString3(
2526 home_dir, "/", FVWM2RC), exc) &&
2527 !run_command_file(CatString3(
2528 FVWM_DATADIR, "/", FVWM2RC), exc) &&
2529 !run_command_file(CatString3(
2530 FVWM_DATADIR, "/system", FVWM2RC), exc) &&
2531 !run_command_file(CatString3(
2532 FVWM_CONFDIR, "/system", FVWM2RC), exc))
2534 fvwm_msg(
2535 ERR, "main", "Cannot read startup config file,"
2536 " tried: \n\t%s/%s\n\t%s/%s\n\t%s/%s\n\t"
2537 "%s/%s\n\t%s/%s\n\t%s/system%s\n\t%s/system%s",
2538 fvwm_userdir, FVWM_CONFIG,
2539 FVWM_DATADIR, FVWM_CONFIG,
2540 fvwm_userdir, FVWM2RC,
2541 home_dir, FVWM2RC,
2542 FVWM_DATADIR, FVWM2RC,
2543 FVWM_DATADIR, FVWM2RC,
2544 FVWM_CONFDIR, FVWM2RC);
2547 exc_destroy_context(exc);
2549 DBUG("main", "Done running config_commands");
2551 if (Pdepth<2)
2553 Scr.gray_pixmap = XCreatePixmapFromBitmapData(
2554 dpy, Scr.NoFocusWin, g_bits, g_width, g_height,
2555 PictureBlackPixel(), PictureWhitePixel(), Pdepth);
2556 Scr.light_gray_pixmap = XCreatePixmapFromBitmapData(
2557 dpy, Scr.NoFocusWin, l_g_bits, l_g_width, l_g_height,
2558 PictureBlackPixel(), PictureWhitePixel(), Pdepth);
2559 Scr.sticky_gray_pixmap = XCreatePixmapFromBitmapData(
2560 dpy, Scr.NoFocusWin, s_g_bits, s_g_width, s_g_height,
2561 PictureBlackPixel(), PictureWhitePixel(), Pdepth);
2564 attributes.background_pixel = Scr.StdBack;
2565 attributes.colormap = Pcmap;
2566 attributes.border_pixel = 0;
2567 valuemask = CWBackPixel | CWColormap | CWBorderPixel;
2569 Scr.SizeWindow = XCreateWindow(
2570 dpy, Scr.Root, 0, 0, 1, 1, 0, Pdepth,
2571 InputOutput, Pvisual, valuemask, &attributes);
2572 resize_geometry_window();
2573 initPanFrames();
2574 MyXGrabServer(dpy);
2575 checkPanFrames();
2576 MyXUngrabServer(dpy);
2577 CoerceEnterNotifyOnCurrentWindow();
2578 SessionInit();
2579 GNOME_Init();
2580 DBUG("main", "Entering HandleEvents loop...");
2582 HandleEvents();
2583 switch (fvwmRunState)
2585 case FVWM_DONE:
2586 Done(0, NULL); /* does not return */
2588 case FVWM_RESTART:
2589 Done(1, ""); /* does not return */
2591 default:
2592 DBUG("main", "Unknown fvwm run-state");
2595 exit(0);