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.
6 *
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.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, see: <http://www.gnu.org/licenses/>
14 */
15
16 /* ---------------------------- included header files ---------------------- */
17
18 #include "config.h"
19
20 #include <stdio.h>
21 #include <signal.h>
22 #include <errno.h>
23 #include <sys/stat.h>
24 #ifdef HAVE_FCNTL_H
25 #include <fcntl.h>
26 #endif
27 #if HAVE_SYS_SYSTEMINFO_H
28 /* Solaris has sysinfo instead of gethostname. */
29 #include <sys/systeminfo.h>
30 #endif
31
32 #include "libs/fvwm_x11.h"
33 #include "libs/fvwmlib.h"
34 #include "libs/envvar.h"
35 #include "libs/Strings.h"
36 #include "libs/System.h"
37 #include "libs/Grab.h"
38 #include "libs/ColorUtils.h"
39 #include "libs/Graphics.h"
40 #include "libs/FShape.h"
41 #include "libs/FEvent.h"
42 #include "libs/PictureBase.h"
43 #include "libs/PictureUtils.h"
44 #include "libs/Fsvg.h"
45 #include "libs/FRenderInit.h"
46 #include "libs/charmap.h"
47 #include "libs/wcontext.h"
48 #include "libs/getpwuid.h"
49 #include "fvwm.h"
50 #include "externs.h"
51 #include "cursor.h"
52 #include "functions.h"
53 #include "misc.h"
54 #include "screen.h"
55 #include "builtins.h"
56 #include "module_list.h"
57 #include "colorset.h"
58 #include "events.h"
59 #include "eventhandler.h"
60 #include "eventmask.h"
61 #include "icccm2.h"
62 #include "ewmh.h"
63 #include "add_window.h"
64 #include "libs/fvwmsignal.h"
65 #include "stack.h"
66 #include "virtual.h"
67 #include "session.h"
68 #include "read.h"
69 #include "focus.h"
70 #include "update.h"
71 #include "move_resize.h"
72 #include "frame.h"
73 #include "menus.h"
74 #include "menubindings.h"
75 #include "libs/FGettext.h"
76
77 /* ---------------------------- local definitions -------------------------- */
78
79 #define MAXHOSTNAME 255
80 #define MAX_CFG_CMDS 10
81 #define MAX_ARG_SIZE 25
82
83 #define g_width 2
84 #define g_height 2
85 #define l_g_width 4
86 #define l_g_height 2
87 #define s_g_width 4
88 #define s_g_height 4
89
90 /* ---------------------------- local macros ------------------------------- */
91
92 /* ---------------------------- imports ------------------------------------ */
93
94 extern int last_event_type;
95
96 /* ---------------------------- included code files ------------------------ */
97
98 /* ---------------------------- local types -------------------------------- */
99
100 typedef enum
101 {
102 FVWM_RUNNING = 0,
103 FVWM_DONE,
104 FVWM_RESTART
105 } fvwm_run_state_t;
106
107 /* ---------------------------- forward declarations ----------------------- */
108
109 /* ---------------------------- local variables ---------------------------- */
110
111 static char *config_commands[MAX_CFG_CMDS];
112 static int num_config_commands=0;
113
114 /* assorted gray bitmaps for decorative borders */
115 static char g_bits[] =
116 {0x02, 0x01};
117 static char l_g_bits[] =
118 {0x08, 0x02};
119 static char s_g_bits[] =
120 {0x01, 0x02, 0x04, 0x08};
121
122 static const char *home_dir;
123
124 static volatile sig_atomic_t fvwmRunState = FVWM_RUNNING;
125
126 static const char *init_function_names[4] =
127 {
128 "InitFunction",
129 "RestartFunction",
130 "ExitFunction",
131 "Nop"
132 };
133
134 /* ---------------------------- exported variables (globals) --------------- */
135
136 int master_pid; /* process number of 1st fvwm process */
137
138 ScreenInfo Scr; /* structures for the screen */
139 Display *dpy = NULL; /* which display are we talking to */
140
141 Bool fFvwmInStartup = True; /* Set to False when startup has finished */
142 Bool DoingCommandLine = False; /* Set True before each cmd line arg */
143
144 XContext FvwmContext; /* context for fvwm windows */
145 XContext MenuContext; /* context for fvwm menus */
146
147 int JunkX = 0, JunkY = 0;
148 Window JunkRoot, JunkChild; /* junk window */
149 int JunkWidth, JunkHeight, JunkBW, JunkDepth;
150 unsigned int JunkMask;
151
152 Bool debugging = False;
153 Bool debugging_stack_ring = False;
154
155 Window bad_window = None;
156
157 char **g_argv;
158 int g_argc;
159
160 char *state_filename = NULL;
161 char *restart_state_filename = NULL; /* $HOME/.fs-restart */
162
163 Bool Restarting = False;
164 int x_fd;
165 char *display_name = NULL;
166 char *fvwm_userdir;
167 char const *Fvwm_VersionInfo;
168 char const *Fvwm_LicenseInfo;
169 char *Fvwm_SupportInfo;
170
171 Atom _XA_MIT_PRIORITY_COLORS;
172 Atom _XA_WM_CHANGE_STATE;
173 Atom _XA_WM_STATE;
174 Atom _XA_WM_COLORMAP_WINDOWS;
175 Atom _XA_WM_TAKE_FOCUS;
176 Atom _XA_WM_DELETE_WINDOW;
177 Atom _XA_WM_DESKTOP;
178 Atom _XA_MwmAtom;
179 Atom _XA_MOTIF_WM;
180
181 Atom _XA_OL_WIN_ATTR;
182 Atom _XA_OL_WT_BASE;
183 Atom _XA_OL_WT_CMD;
184 Atom _XA_OL_WT_HELP;
185 Atom _XA_OL_WT_NOTICE;
186 Atom _XA_OL_WT_OTHER;
187 Atom _XA_OL_DECOR_ADD;
188 Atom _XA_OL_DECOR_DEL;
189 Atom _XA_OL_DECOR_CLOSE;
190 Atom _XA_OL_DECOR_RESIZE;
191 Atom _XA_OL_DECOR_HEADER;
192 Atom _XA_OL_DECOR_ICON_NAME;
193
194 Atom _XA_WM_WINDOW_ROLE;
195 Atom _XA_WINDOW_ROLE;
196 Atom _XA_WM_CLIENT_LEADER;
197 Atom _XA_SM_CLIENT_ID;
198
199 Atom _XA_XROOTPMAP_ID;
200 Atom _XA_XSETROOT_ID;
201
202 /* ---------------------------- local functions ---------------------------- */
203
SaveDesktopState(void)204 static void SaveDesktopState(void)
205 {
206 FvwmWindow *t;
207 unsigned long data[1];
208
209 for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
210 {
211 data[0] = (unsigned long) t->Desk;
212 XChangeProperty(
213 dpy, FW_W(t), _XA_WM_DESKTOP, _XA_WM_DESKTOP, 32,
214 PropModeReplace, (unsigned char *)data, 1);
215 }
216 data[0] = (unsigned long) monitor_get_current()->virtual_scr.CurrentDesk;
217 XChangeProperty(
218 dpy, Scr.Root, _XA_WM_DESKTOP, _XA_WM_DESKTOP, 32,
219 PropModeReplace, (unsigned char *) data, 1);
220 XFlush(dpy);
221
222 return;
223 }
224
InternUsefulAtoms(void)225 static void InternUsefulAtoms (void)
226 {
227 /* Create priority colors if necessary. */
228 _XA_MIT_PRIORITY_COLORS = XInternAtom(
229 dpy, "_MIT_PRIORITY_COLORS", False);
230 _XA_WM_CHANGE_STATE = XInternAtom(dpy, "WM_CHANGE_STATE", False);
231 _XA_WM_STATE = XInternAtom(dpy, "WM_STATE", False);
232 _XA_WM_COLORMAP_WINDOWS = XInternAtom(
233 dpy, "WM_COLORMAP_WINDOWS", False);
234 _XA_WM_PROTOCOLS = XInternAtom(dpy, "WM_PROTOCOLS", False);
235 _XA_WM_TAKE_FOCUS = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
236 _XA_WM_DELETE_WINDOW = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
237 _XA_WM_DESKTOP = XInternAtom(dpy, "WM_DESKTOP", False);
238 _XA_MwmAtom=XInternAtom(dpy, "_MOTIF_WM_HINTS",False);
239 _XA_MOTIF_WM=XInternAtom(dpy, "_MOTIF_WM_INFO",False);
240 _XA_OL_WIN_ATTR=XInternAtom(dpy, "_OL_WIN_ATTR",False);
241 _XA_OL_WT_BASE=XInternAtom(dpy, "_OL_WT_BASE",False);
242 _XA_OL_WT_CMD=XInternAtom(dpy, "_OL_WT_CMD",False);
243 _XA_OL_WT_HELP=XInternAtom(dpy, "_OL_WT_HELP",False);
244 _XA_OL_WT_NOTICE=XInternAtom(dpy, "_OL_WT_NOTICE",False);
245 _XA_OL_WT_OTHER=XInternAtom(dpy, "_OL_WT_OTHER",False);
246 _XA_OL_DECOR_ADD=XInternAtom(dpy, "_OL_DECOR_ADD",False);
247 _XA_OL_DECOR_DEL=XInternAtom(dpy, "_OL_DECOR_DEL",False);
248 _XA_OL_DECOR_CLOSE=XInternAtom(dpy, "_OL_DECOR_CLOSE",False);
249 _XA_OL_DECOR_RESIZE=XInternAtom(dpy, "_OL_DECOR_RESIZE",False);
250 _XA_OL_DECOR_HEADER=XInternAtom(dpy, "_OL_DECOR_HEADER",False);
251 _XA_OL_DECOR_ICON_NAME=XInternAtom(dpy, "_OL_DECOR_ICON_NAME",False);
252 _XA_WM_WINDOW_ROLE=XInternAtom(dpy, "WM_WINDOW_ROLE",False);
253 _XA_WINDOW_ROLE=XInternAtom(dpy, "WINDOW_ROLE",False);
254 _XA_WM_CLIENT_LEADER=XInternAtom(dpy, "WM_CLIENT_LEADER",False);
255 _XA_SM_CLIENT_ID=XInternAtom(dpy, "SM_CLIENT_ID",False);
256 _XA_XROOTPMAP_ID=XInternAtom(dpy, "_XROOTPMAP_ID",False);
257 _XA_XSETROOT_ID=XInternAtom(dpy, "_XSETROOT_ID",False);
258
259 return;
260 }
261
262 /* exit handler that will try to release any grabs */
catch_exit(void)263 static void catch_exit(void)
264 {
265 if (dpy != NULL)
266 {
267 /* Don't care if this is called from an X error handler. We
268 * *have* to try this, whatever happens. XFree 4.0 may freeze
269 * if we don't do this. */
270 XUngrabServer(dpy);
271 XUngrabPointer(dpy, CurrentTime);
272 XUngrabKeyboard(dpy, CurrentTime);
273 }
274
275 return;
276 }
277
278 /*
279 * Restart on a signal
280 */
281 static RETSIGTYPE
Restart(int sig)282 Restart(int sig)
283 {
284 fvwmRunState = FVWM_RESTART;
285
286 /* This function might not return - it could "long-jump"
287 * right out, so we need to do everything we need to do
288 * BEFORE we call it ... */
289 fvwmSetTerminate(sig);
290
291 SIGNAL_RETURN;
292 }
293
294 static RETSIGTYPE
ToggleLogging(int sig)295 ToggleLogging(int sig)
296 {
297 log_toggle(fvwm_userdir);
298
299 SIGNAL_RETURN;
300 }
301
302 static RETSIGTYPE
SigDone(int sig)303 SigDone(int sig)
304 {
305 fvwmRunState = FVWM_DONE;
306
307 /* This function might not return - it could "long-jump"
308 * right out, so we need to do everything we need to do
309 * BEFORE we call it ... */
310 fvwmSetTerminate(sig);
311
312 SIGNAL_RETURN;
313 }
314
315 /*
316 * parse_command_args - parses a given command string into a given limited
317 * argument array suitable for execv*. The parsing is similar to shell's.
318 * Returns:
319 * positive number of parsed arguments - on success,
320 * 0 - on empty command (only spaces),
321 * negative - on no command or parsing error.
322 *
323 * Any character can be quoted with a backslash (even inside single quotes).
324 * Every command argument is separated by a space/tab/new-line from both sizes
325 * or is at the start/end of the command. Sequential spaces are ignored.
326 * An argument can be enclosed into single quotes (no further expanding)
327 * or double quotes (expending environmental variables $VAR or ${VAR}).
328 * The character '~' is expanded into user home directory (if not in quotes).
329 *
330 * In the current implementation, parsed arguments are stored in one
331 * large static string pointed by returned argv[0], so they will be lost
332 * on the next function call. This can be changed using dynamic allocation,
333 * in this case the caller must free the string pointed by argv[0].
334 */
parse_command_args(const char * command,char ** argv,int max_argc,const char ** error_msg)335 static int parse_command_args(
336 const char *command, char **argv, int max_argc, const char **error_msg)
337 {
338 /* It is impossible to guess the exact length because of expanding */
339 #define MAX_TOTAL_ARG_LEN 256
340 /* char *arg_string = fxmalloc(MAX_TOTAL_ARG_LEN); */
341 static char arg_string[MAX_TOTAL_ARG_LEN];
342 int total_arg_len = 0;
343 int error_code = 0;
344 int argc;
345 char *aptr = arg_string;
346 const char *cptr = command;
347
348 #define the_char (*cptr)
349 #define adv_char (cptr++)
350 #define top_char (*cptr == '\\' ? *(cptr + 1) : *cptr)
351 #define pop_char (*(cptr++) == '\\' ? *(cptr++) : *(cptr - 1))
352 #define can_add_arg_char (total_arg_len < MAX_TOTAL_ARG_LEN-1)
353 #define add_arg_char(ch) (++total_arg_len, *(aptr++) = ch)
354 #define can_add_arg_str(str) (total_arg_len < MAX_TOTAL_ARG_LEN - strlen(str))
355 #define add_arg_str(str) \
356 {\
357 const char *tmp = str;\
358 while (*tmp)\
359 {\
360 add_arg_char(*(tmp++));\
361 }\
362 }
363
364 *error_msg = "";
365 if (!command)
366 {
367 *error_msg = "No command";
368 return -1;
369 }
370 for (argc = 0; argc < max_argc - 1; argc++)
371 {
372 int s_quote = 0;
373 argv[argc] = aptr;
374 while (isspace(the_char))
375 {
376 adv_char;
377 }
378 if (the_char == '\0')
379 {
380 break;
381 }
382 while ((s_quote || !isspace(the_char)) &&
383 the_char != '\0' && can_add_arg_char)
384 {
385 if (the_char == '"')
386 {
387 if (s_quote)
388 {
389 s_quote = 0;
390 }
391 else
392 {
393 s_quote = 1;
394 }
395 adv_char;
396 }
397 else if (!s_quote && the_char == '\'')
398 {
399 adv_char;
400 while (the_char != '\'' && the_char != '\0' &&
401 can_add_arg_char)
402 {
403 add_arg_char(pop_char);
404 }
405 if (the_char == '\'')
406 {
407 adv_char;
408 }
409 else if (!can_add_arg_char)
410 {
411 break;
412 }
413 else
414 {
415 *error_msg = "No closing single quote";
416 error_code = -3;
417 break;
418 }
419 }
420 else if (!s_quote && the_char == '~')
421 {
422 if (!can_add_arg_str(home_dir))
423 {
424 break;
425 }
426 add_arg_str(home_dir);
427 adv_char;
428 }
429 else if (the_char == '$')
430 {
431 int beg, len;
432 const char *str = getFirstEnv(cptr, &beg, &len);
433
434 if (!str || beg)
435 {
436 add_arg_char(the_char);
437 adv_char;
438 continue;
439 }
440 if (!can_add_arg_str(str))
441 {
442 break;
443 }
444 add_arg_str(str);
445 cptr += len;
446 }
447 else
448 {
449 if (add_arg_char(pop_char) == '\0')
450 {
451 break;
452 }
453 }
454 }
455 if (*(aptr-1) == '\0')
456 {
457 *error_msg = "Unexpected last backslash";
458 error_code = -2;
459 break;
460 }
461 if (error_code)
462 {
463 break;
464 }
465 if (the_char == '~' || the_char == '$' || !can_add_arg_char)
466 {
467 *error_msg = "The command is too long";
468 error_code = -argc - 100;
469 break;
470 }
471 if (s_quote)
472 {
473 *error_msg = "No closing double quote";
474 error_code = -4;
475 break;
476 }
477 add_arg_char('\0');
478 }
479 #undef the_char
480 #undef adv_char
481 #undef top_char
482 #undef pop_char
483 #undef can_add_arg_char
484 #undef add_arg_char
485 #undef can_add_arg_str
486 #undef add_arg_str
487 argv[argc] = NULL;
488 if (argc == 0 && !error_code)
489 {
490 *error_msg = "Void command";
491 }
492
493 return error_code ? error_code : argc;
494 }
495
496 /*
497 *
498 */
499 static
get_display_name(char * display_name,int screen_num)500 char *get_display_name(char *display_name, int screen_num)
501 {
502 char *msg;
503 char *new_dn;
504 char *cp;
505 char string_screen_num[32];
506
507 CopyString(&msg, display_name);
508 cp = strchr(msg, ':');
509 if (cp != NULL)
510 {
511 cp = strchr(cp, '.');
512 if (cp != NULL)
513 {
514 /* truncate at display part */
515 *cp = '\0';
516 }
517 }
518 sprintf(string_screen_num, ".%d", screen_num);
519 /* TA: FIXME! Use asprintF() */
520 new_dn = fxmalloc(strlen(msg) + strlen(string_screen_num) + 1);
521 *new_dn = '\0';
522 strcat(new_dn, msg);
523 strcat(new_dn, string_screen_num);
524 free(msg);
525
526 return new_dn;
527 }
528
529 /*
530 *
531 * Procedure:
532 * Done - tells fvwm to clean up and exit
533 *
534 */
535 /* if restart is true, command must not be NULL... */
Done(int restart,char * command)536 void Done(int restart, char *command)
537 {
538 const char *exit_func_name;
539 struct monitor *m = monitor_get_current();
540
541 if (!restart)
542 {
543 MoveViewport(m, 0,0,False);
544 }
545 /* migo (03/Jul/1999): execute [Session]ExitFunction */
546 exit_func_name = get_init_function_name(2);
547 if (functions_is_complex_function(exit_func_name))
548 {
549 const exec_context_t *exc;
550 exec_context_changes_t ecc;
551
552 char *action;
553
554 xasprintf(&action, "Function ", exit_func_name);
555
556 ecc.type = restart ? EXCT_TORESTART : EXCT_QUIT;
557 ecc.w.wcontext = C_ROOT;
558 exc = exc_create_context(&ecc, ECC_TYPE | ECC_WCONTEXT);
559 execute_function(NULL, exc, action, 0);
560 exc_destroy_context(exc);
561 free(action);
562 }
563 /* XFree freeze hack */
564 XUngrabPointer(dpy, CurrentTime);
565 XUngrabKeyboard(dpy, CurrentTime);
566 XUngrabServer(dpy);
567 if (!restart)
568 {
569 Reborder();
570 }
571 EWMH_ExitStuff();
572 if (restart)
573 {
574 Bool do_preserve_state = True;
575 SaveDesktopState();
576
577 if (command)
578 {
579 while (isspace(command[0]))
580 {
581 command++;
582 }
583 if (strncmp(command, "--dont-preserve-state", 21) == 0)
584 {
585 do_preserve_state = False;
586 command += 21;
587 while (isspace(command[0])) command++;
588 }
589 }
590 if (command[0] == '\0')
591 {
592 command = NULL; /* native restart */
593 }
594
595 /* won't return under SM on Restart without parameters */
596 RestartInSession(
597 restart_state_filename, command == NULL,
598 do_preserve_state);
599
600 /* RBW - 06/08/1999 - without this, windows will wander to
601 * other pages on a Restart/Recapture because Restart gets the
602 * window position information out of sync. There may be a
603 * better way to do this (i.e., adjust the Restart code), but
604 * this works for now. */
605 MoveViewport(m, 0,0,False);
606 Reborder();
607
608 /* Really make sure that the connection is closed and cleared!
609 */
610 CloseICCCM2();
611 catch_exit();
612 XCloseDisplay(dpy);
613 dpy = NULL;
614
615 /* really need to destroy all windows, explicitly, not sleep,
616 * but this is adequate for now */
617 sleep(1);
618
619 if (command)
620 {
621 char *my_argv[MAX_ARG_SIZE];
622 const char *error_msg;
623 int n = parse_command_args(
624 command, my_argv, MAX_ARG_SIZE, &error_msg);
625
626 if (n <= 0)
627 {
628 fvwm_debug(__func__,
629 "Restart command parsing error in"
630 " (%s): [%s]", command, error_msg);
631 }
632 else if (strcmp(my_argv[0], "--pass-args") == 0)
633 {
634 if (n != 2)
635 {
636 fvwm_debug(__func__,
637 "Restart --pass-args: single"
638 " name expected. (restarting"
639 " '%s' instead)",
640 g_argv[0]);
641
642 }
643 else
644 {
645 int i;
646 my_argv[0] = my_argv[1];
647 for (i = 1; i < g_argc &&
648 i < MAX_ARG_SIZE - 1; i++)
649 {
650 my_argv[i] = g_argv[i];
651 }
652 my_argv[i] = NULL;
653
654 execvp(my_argv[0], my_argv);
655 fvwm_debug(__func__,
656 "Call of '%s' failed!"
657 " (restarting '%s' instead)",
658 my_argv[0], g_argv[0]);
659 perror(" system error description");
660 }
661
662 }
663 else
664 {
665 char *str = NULL;
666
667 /* Warn against an old 'Restart fvwm2' usage */
668 if (n == 1 && strcmp(my_argv[0], "fvwm2") == 0)
669 {
670 str = "fvwm2";
671 }
672 /* If we are at it, warn against a 'Restart
673 * fvwm' usage as well */
674 else if (n == 1 &&
675 strcmp(my_argv[0], "fvwm") == 0)
676 {
677 str = "fvwm";
678 }
679 if (str)
680 {
681 fvwm_debug(__func__,
682 "`Restart %s' might not do"
683 " what you want, see the man"
684 " page.\n\tUse Restart without"
685 " parameters if you mean to"
686 " restart the same WM.",
687 str);
688 }
689 execvp(my_argv[0], my_argv);
690 fvwm_debug(__func__, "Call of '%s' failed!"
691 " (restarting '%s' instead)",
692 my_argv[0], g_argv[0]);
693 perror(" system error description");
694 }
695 }
696
697 execvp(g_argv[0], g_argv); /* that _should_ work */
698 fvwm_debug(__func__, "Call of '%s' failed!", g_argv[0]);
699 perror(" system error description");
700 }
701 else
702 {
703 CloseICCCM2();
704 catch_exit();
705 XCloseDisplay(dpy);
706 dpy = NULL;
707 }
708
709 /* dv (15-Jan-2000): This must be done after calling CloseICCCM2()!
710 * Otherwise fvwm ignores map requests while it still has
711 * SubstructureRedirect selected on the root window ==> windows end up
712 * in nirvana. This explicitly happened with windows unswallowed by
713 * FvwmButtons. */
714 module_kill_all();
715
716 exit(0);
717 }
718
719 /***********************************************************************
720 *
721 * Procedure:
722 * InstallSignals: install the signal handlers, using whatever
723 * means we have at our disposal. The more POSIXy, the better
724 *
725 ************************************************************************/
726 static void
InstallSignals(void)727 InstallSignals(void)
728 {
729 #ifdef HAVE_SIGACTION
730 struct sigaction sigact;
731
732 /*
733 * All signals whose handlers call fvwmSetTerminate()
734 * must be mutually exclusive - we mustn't receive one
735 * while processing any of the others ...
736 */
737 sigemptyset(&sigact.sa_mask);
738 sigaddset(&sigact.sa_mask, SIGINT);
739 sigaddset(&sigact.sa_mask, SIGHUP);
740 sigaddset(&sigact.sa_mask, SIGQUIT);
741 sigaddset(&sigact.sa_mask, SIGTERM);
742 sigaddset(&sigact.sa_mask, SIGUSR1);
743 sigaddset(&sigact.sa_mask, SIGUSR2);
744
745 #ifdef SA_RESTART
746 sigact.sa_flags = SA_RESTART;
747 #else
748 sigact.sa_flags = 0;
749 #endif
750 sigact.sa_handler = DeadPipe;
751 sigaction(SIGPIPE, &sigact, NULL);
752
753 sigact.sa_handler = Restart;
754 sigaction(SIGUSR1, &sigact, NULL);
755
756 sigact.sa_handler = ToggleLogging;
757 sigaction(SIGUSR2, &sigact, NULL);
758
759 sigact.sa_handler = SigDone;
760 sigaction(SIGINT, &sigact, NULL);
761 sigaction(SIGHUP, &sigact, NULL);
762 sigaction(SIGQUIT, &sigact, NULL);
763 sigaction(SIGTERM, &sigact, NULL);
764
765 /* Unblock these signals so that we can process them again. */
766 sigprocmask(SIG_UNBLOCK, &sigact.sa_mask, NULL);
767
768 /* Reap all zombies automatically! This signal handler will only be
769 * called if a child process dies, not if someone sends a child a STOP
770 * signal. Note that none of our "terminate" signals can be delivered
771 * until the SIGCHLD handler completes, and this is a Good Thing
772 * because the terminate handlers might exit abruptly via "siglongjmp".
773 * This could potentially leave SIGCHLD handler with unfinished
774 * business ...
775 *
776 * NOTE: We could still receive SIGPIPE signals within the SIGCHLD
777 * handler, but the SIGPIPE handler has the SA_RESTART flag set and so
778 * should not affect our "wait" system call. */
779 sigact.sa_flags |= SA_NOCLDSTOP;
780 sigact.sa_handler = fvwmReapChildren;
781 sigaction(SIGCHLD, &sigact, NULL);
782 #else
783 #ifdef USE_BSD_SIGNALS
784 fvwmSetSignalMask(
785 sigmask(SIGUSR1) | sigmask(SIGUSR2) | sigmask(SIGINT) |
786 sigmask(SIGHUP) | sigmask(SIGQUIT) | sigmask(SIGTERM) );
787 #endif
788
789 /*
790 * We don't have sigaction(), so fall back on
791 * less reliable methods ...
792 */
793 signal(SIGPIPE, DeadPipe);
794 signal(SIGUSR1, Restart);
795 signal(SIGUSR2, ToggleLogging);
796 #ifdef HAVE_SIGINTERRUPT
797 siginterrupt(SIGUSR1, 0);
798 #endif
799
800 signal(SIGINT, SigDone);
801 #ifdef HAVE_SIGINTERRUPT
802 siginterrupt(SIGINT, 0);
803 #endif
804 signal(SIGHUP, SigDone);
805 #ifdef HAVE_SIGINTERRUPT
806 siginterrupt(SIGHUP, 0);
807 #endif
808 signal(SIGQUIT, SigDone);
809 #ifdef HAVE_SIGINTERRUPT
810 siginterrupt(SIGQUIT, 0);
811 #endif
812 signal(SIGTERM, SigDone);
813 #ifdef HAVE_SIGINTERRUPT
814 siginterrupt(SIGTERM, 0);
815 #endif
816 signal(SIGCHLD, fvwmReapChildren);
817 #ifdef HAVE_SIGINTERRUPT
818 siginterrupt(SIGCHLD, 0);
819 #endif
820 #endif
821
822 /* When fvwm restarts, the SIGCHLD handler is automatically reset
823 * to the default handler. This means that Zombies left over from
824 * the previous instance of fvwm could still be roaming the process
825 * table if they exited while the default handler was in place.
826 * We fix this by invoking the SIGCHLD handler NOW, so that they
827 * may finally rest in peace. */
828 fvwmReapChildren(0);
829
830 return;
831 }
832
fvmm_deinstall_signals(void)833 void fvmm_deinstall_signals(void)
834 {
835 signal(SIGCHLD, SIG_DFL);
836 signal(SIGHUP, SIG_DFL);
837 signal(SIGINT, SIG_DFL);
838 signal(SIGPIPE, SIG_DFL);
839 signal(SIGQUIT, SIG_DFL);
840 signal(SIGTERM, SIG_DFL);
841 signal(SIGUSR1, SIG_DFL);
842 signal(SIGUSR2, SIG_DFL);
843
844 return;
845 }
846
847 /***********************************************************************
848 *
849 * LoadDefaultLeftButton -- loads default left button # into
850 * assumes associated button memory is already free
851 *
852 ************************************************************************/
LoadDefaultLeftButton(DecorFace * df,int i)853 static void LoadDefaultLeftButton(DecorFace *df, int i)
854 {
855 struct vector_coords *v = &df->u.vector;
856 int j = 0;
857
858 memset(&df->style, 0, sizeof(df->style));
859 DFS_FACE_TYPE(df->style) = DefaultVectorButton;
860 switch (i % 5)
861 {
862 case 0:
863 case 4:
864 v->num = 5;
865 v->x = fxmalloc(sizeof(char) * v->num);
866 v->y = fxmalloc(sizeof(char) * v->num);
867 v->xoff = fxmalloc(sizeof(char) * v->num);
868 v->yoff = fxmalloc(sizeof(char) * v->num);
869 v->c = fxcalloc(v->num, sizeof(char));
870 v->x[0] = 22;
871 v->y[0] = 39;
872 v->c[0] = 1;
873 v->x[1] = 78;
874 v->y[1] = 39;
875 v->c[1] = 1;
876 v->x[2] = 78;
877 v->y[2] = 61;
878 v->x[3] = 22;
879 v->y[3] = 61;
880 v->x[4] = 22;
881 v->y[4] = 39;
882 v->c[4] = 1;
883 break;
884 case 1:
885 v->num = 5;
886 v->x = fxmalloc(sizeof(char) * v->num);
887 v->y = fxmalloc(sizeof(char) * v->num);
888 v->xoff = fxmalloc(sizeof(char) * v->num);
889 v->yoff = fxmalloc(sizeof(char) * v->num);
890 v->c = fxcalloc(v->num, sizeof(char));
891 v->x[0] = 32;
892 v->y[0] = 45;
893 v->x[1] = 68;
894 v->y[1] = 45;
895 v->x[2] = 68;
896 v->y[2] = 55;
897 v->c[2] = 1;
898 v->x[3] = 32;
899 v->y[3] = 55;
900 v->c[3] = 1;
901 v->x[4] = 32;
902 v->y[4] = 45;
903 break;
904 case 2:
905 v->num = 5;
906 v->x = fxmalloc(sizeof(char) * v->num);
907 v->y = fxmalloc(sizeof(char) * v->num);
908 v->xoff = fxmalloc(sizeof(char) * v->num);
909 v->yoff = fxmalloc(sizeof(char) * v->num);
910 v->c = fxcalloc(v->num, sizeof(char));
911 v->x[0] = 49;
912 v->y[0] = 49;
913 v->c[0] = 1;
914 v->x[1] = 51;
915 v->y[1] = 49;
916 v->c[1] = 1;
917 v->x[2] = 51;
918 v->y[2] = 51;
919 v->x[3] = 49;
920 v->y[3] = 51;
921 v->x[4] = 49;
922 v->y[4] = 49;
923 v->c[4] = 1;
924 break;
925 case 3:
926 v->num = 5;
927 v->x = fxmalloc(sizeof(char) * v->num);
928 v->y = fxmalloc(sizeof(char) * v->num);
929 v->xoff = fxmalloc(sizeof(char) * v->num);
930 v->yoff = fxmalloc(sizeof(char) * v->num);
931 v->c = fxcalloc(v->num, sizeof(char));
932 v->x[0] = 32;
933 v->y[0] = 45;
934 v->c[0] = 1;
935 v->x[1] = 68;
936 v->y[1] = 45;
937 v->c[1] = 1;
938 v->x[2] = 68;
939 v->y[2] = 55;
940 v->x[3] = 32;
941 v->y[3] = 55;
942 v->x[4] = 32;
943 v->y[4] = 45;
944 v->c[4] = 1;
945 break;
946 }
947 /* set offsets to 0, for all buttons */
948 for(j = 0 ; j < v->num ; j++)
949 {
950 v->xoff[j] = 0;
951 v->yoff[j] = 0;
952 }
953
954 return;
955 }
956
957 /***********************************************************************
958 *
959 * LoadDefaultRightButton -- loads default left button # into
960 * assumes associated button memory is already free
961 *
962 ************************************************************************/
LoadDefaultRightButton(DecorFace * df,int i)963 static void LoadDefaultRightButton(DecorFace *df, int i)
964 {
965 struct vector_coords *v = &df->u.vector;
966 int j = 0;
967
968 memset(&df->style, 0, sizeof(df->style));
969 DFS_FACE_TYPE(df->style) = DefaultVectorButton;
970 switch (i % 5)
971 {
972 case 0:
973 case 3:
974 v->num = 5;
975 v->x = fxmalloc(sizeof(char) * v->num);
976 v->y = fxmalloc(sizeof(char) * v->num);
977 v->xoff = fxmalloc(sizeof(char) * v->num);
978 v->yoff = fxmalloc(sizeof(char) * v->num);
979 v->c = fxcalloc(v->num, sizeof(char));
980 v->x[0] = 25;
981 v->y[0] = 25;
982 v->c[0] = 1;
983 v->x[1] = 75;
984 v->y[1] = 25;
985 v->c[1] = 1;
986 v->x[2] = 75;
987 v->y[2] = 75;
988 v->x[3] = 25;
989 v->y[3] = 75;
990 v->x[4] = 25;
991 v->y[4] = 25;
992 v->c[4] = 1;
993 break;
994 case 1:
995 v->num = 5;
996 v->x = fxmalloc(sizeof(char) * v->num);
997 v->y = fxmalloc(sizeof(char) * v->num);
998 v->xoff = fxmalloc(sizeof(char) * v->num);
999 v->yoff = fxmalloc(sizeof(char) * v->num);
1000 v->c = fxcalloc(v->num, sizeof(char));
1001 v->x[0] = 39;
1002 v->y[0] = 39;
1003 v->c[0] = 1;
1004 v->x[1] = 61;
1005 v->y[1] = 39;
1006 v->c[1] = 1;
1007 v->x[2] = 61;
1008 v->y[2] = 61;
1009 v->x[3] = 39;
1010 v->y[3] = 61;
1011 v->x[4] = 39;
1012 v->y[4] = 39;
1013 v->c[4] = 1;
1014 break;
1015 case 2:
1016 v->num = 5;
1017 v->x = fxmalloc(sizeof(char) * v->num);
1018 v->y = fxmalloc(sizeof(char) * v->num);
1019 v->xoff = fxmalloc(sizeof(char) * v->num);
1020 v->yoff = fxmalloc(sizeof(char) * v->num);
1021 v->c = fxcalloc(v->num, sizeof(char));
1022 v->x[0] = 49;
1023 v->y[0] = 49;
1024 v->c[0] = 1;
1025 v->x[1] = 51;
1026 v->y[1] = 49;
1027 v->c[1] = 1;
1028 v->x[2] = 51;
1029 v->y[2] = 51;
1030 v->x[3] = 49;
1031 v->y[3] = 51;
1032 v->x[4] = 49;
1033 v->y[4] = 49;
1034 v->c[4] = 1;
1035 break;
1036 case 4:
1037 v->num = 5;
1038 v->x = fxmalloc(sizeof(char) * v->num);
1039 v->y = fxmalloc(sizeof(char) * v->num);
1040 v->xoff = fxmalloc(sizeof(char) * v->num);
1041 v->yoff = fxmalloc(sizeof(char) * v->num);
1042 v->c = fxcalloc(v->num, sizeof(char));
1043 v->x[0] = 36;
1044 v->y[0] = 36;
1045 v->c[0] = 1;
1046 v->x[1] = 64;
1047 v->y[1] = 36;
1048 v->c[1] = 1;
1049 v->x[2] = 64;
1050 v->y[2] = 64;
1051 v->x[3] = 36;
1052 v->y[3] = 64;
1053 v->x[4] = 36;
1054 v->y[4] = 36;
1055 v->c[4] = 1;
1056 break;
1057 }
1058 /* set offsets to 0, for all buttons */
1059 for(j = 0 ; j < v->num ; j++)
1060 {
1061 v->xoff[j] = 0;
1062 v->yoff[j] = 0;
1063 }
1064
1065 return;
1066 }
1067
1068 /***********************************************************************
1069 *
1070 * Procedure:
1071 * CreateGCs - open fonts and create all the needed GC's. I only
1072 * want to do this once, hence the first_time flag.
1073 *
1074 ***********************************************************************/
CreateGCs(void)1075 static void CreateGCs(void)
1076 {
1077 XGCValues gcv;
1078 unsigned long gcm;
1079
1080 /* create scratch GC's */
1081 gcm = GCFunction|GCLineWidth;
1082 gcv.function = GXcopy;
1083 gcv.line_width = 0;
1084
1085 Scr.ScratchGC1 = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
1086 Scr.ScratchGC2 = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
1087 Scr.ScratchGC3 = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
1088 Scr.ScratchGC4 = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
1089 Scr.TitleGC = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
1090 Scr.BordersGC = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
1091 Scr.TransMaskGC = fvwmlib_XCreateGC(dpy, Scr.NoFocusWin, gcm, &gcv);
1092 Scr.ScratchMonoPixmap = XCreatePixmap(dpy, Scr.Root, 1, 1, 1);
1093 Scr.MonoGC = fvwmlib_XCreateGC(dpy, Scr.ScratchMonoPixmap, gcm, &gcv);
1094 Scr.ScratchAlphaPixmap = XCreatePixmap(
1095 dpy, Scr.Root, 1, 1, FRenderGetAlphaDepth());
1096 Scr.AlphaGC = fvwmlib_XCreateGC(dpy, Scr.ScratchAlphaPixmap, gcm, &gcv);
1097 return;
1098 }
1099
1100 /***********************************************************************
1101 *
1102 * Procedure:
1103 * InitVariables - initialize fvwm variables
1104 *
1105 ************************************************************************/
InitVariables(void)1106 static void InitVariables(void)
1107 {
1108 FvwmContext = XUniqueContext();
1109 MenuContext = XUniqueContext();
1110
1111 /* initialize some lists */
1112 Scr.AllBindings = NULL;
1113 Scr.functions = NULL;
1114 menus_init();
1115 Scr.last_added_item.type = ADDED_NONE;
1116 Scr.DefaultIcon = NULL;
1117 Scr.DefaultColorset = -1;
1118 Scr.StdGC = 0;
1119 Scr.StdReliefGC = 0;
1120 Scr.StdShadowGC = 0;
1121 Scr.XorGC = 0;
1122 /* zero all flags */
1123 memset(&Scr.flags, 0, sizeof(Scr.flags));
1124 /* create graphics contexts */
1125 CreateGCs();
1126
1127 FW_W(&Scr.FvwmRoot) = Scr.Root;
1128 Scr.FvwmRoot.next = 0;
1129 init_stack_and_layers();
1130 Scr.root_pushes = 0;
1131 Scr.fvwm_pushes = 0;
1132 Scr.pushed_window = &Scr.FvwmRoot;
1133 Scr.FvwmRoot.number_cmap_windows = 0;
1134 Scr.FvwmRoot.attr_backup.colormap = Pcmap;
1135
1136 Scr.BusyCursor = BUSY_NONE;
1137 Scr.Hilite = NULL;
1138 Scr.DefaultFont = NULL;
1139
1140 memset(&Scr.SizeWindow, 0, sizeof Scr.SizeWindow);
1141 Scr.SizeWindow.m = NULL;
1142 Scr.SizeWindow.cset = -1;
1143
1144 Scr.ScrollDelay = DEFAULT_SCROLL_DELAY;
1145 Scr.OpaqueSize = DEFAULT_OPAQUE_MOVE_SIZE;
1146 Scr.MoveThreshold = DEFAULT_MOVE_THRESHOLD;
1147 /* ClickTime is set to the positive value upon entering the
1148 * event loop. */
1149 Scr.ClickTime = -DEFAULT_CLICKTIME;
1150 Scr.ColormapFocus = COLORMAP_FOLLOWS_MOUSE;
1151
1152 /* set major operating modes */
1153 Scr.NumBoxes = 0;
1154 Scr.cascade_x = 0;
1155 Scr.cascade_y = 0;
1156 /* the last Cascade placed window or NULL, we don't want NULL
1157 * initially */
1158 Scr.cascade_window = &Scr.FvwmRoot;
1159 Scr.buttons2grab = 0;
1160 /* ewmh desktop */
1161 InitFvwmDecor(&Scr.DefaultDecor);
1162 Scr.DefaultDecor.tag = "Default";
1163 /* Initialize RaiseHackNeeded by identifying X servers
1164 possibly running under NT. This is probably not an
1165 ideal solution, since eg NCD also produces X servers
1166 which do not run under NT.
1167
1168 "Hummingbird Communications Ltd."
1169 is the ServerVendor string of the Exceed X server under NT,
1170
1171 "Network Computing Devices Inc."
1172 is the ServerVendor string of the PCXware X server under Windows.
1173
1174 "WRQ, Inc."
1175 is the ServerVendor string of the Reflection X server under Windows.
1176 */
1177 Scr.bo.is_raise_hack_needed =
1178 (strcmp (
1179 ServerVendor (dpy),
1180 "Hummingbird Communications Ltd.") == 0) ||
1181 (strcmp (
1182 ServerVendor (dpy),
1183 "Network Computing Devices Inc.") == 0) ||
1184 (strcmp (ServerVendor (dpy), "WRQ, Inc.") == 0);
1185
1186 Scr.bo.is_modality_evil = 0;
1187 Scr.bo.do_disable_configure_notify = 0;
1188 Scr.bo.do_install_root_cmap = 0;
1189 Scr.bo.do_enable_flickering_qt_dialogs_workaround = 1;
1190 Scr.bo.do_enable_qt_drag_n_drop_workaround = 0;
1191 Scr.bo.do_enable_ewmh_iconic_state_workaround = 0;
1192
1193 Scr.gs.do_emulate_mwm = DEFAULT_EMULATE_MWM;
1194 Scr.gs.do_emulate_win = DEFAULT_EMULATE_WIN;
1195 Scr.gs.use_active_down_buttons = DEFAULT_USE_ACTIVE_DOWN_BUTTONS;
1196 Scr.gs.use_inactive_buttons = DEFAULT_USE_INACTIVE_BUTTONS;
1197 Scr.gs.use_inactive_down_buttons = DEFAULT_USE_INACTIVE_DOWN_BUTTONS;
1198 /* Not the right place for this, should only be called once
1199 * somewhere .. */
1200
1201 Scr.flags.is_pointer_on_this_screen = !!FQueryPointer(
1202 dpy, Scr.Root, &JunkRoot, &JunkChild, &JunkX, &JunkY, &JunkX,
1203 &JunkY, &JunkMask);
1204
1205 /* make sure colorset 0 exists */
1206 alloc_colorset(0);
1207
1208 return;
1209 }
1210
usage(int is_verbose)1211 static void usage(int is_verbose)
1212 {
1213 fprintf(stderr, "usage: %s", g_argv[0]);
1214 fprintf(stderr,
1215 " [-d display]"
1216 " [-f cfgfile]"
1217 " [-c cmd]"
1218 " [-s [screen_num]]"
1219 " [-I vis-id | -C vis-class]"
1220 " [-l colors"
1221 " [-L|A|S|P] ...]"
1222 " [-r]"
1223 " [OTHER OPTIONS] ..."
1224 "\n");
1225 if (!is_verbose)
1226 {
1227 fprintf(stderr,
1228 "Try '%s --help' for more information.\n",
1229 g_argv[0]);
1230 return;
1231 }
1232 fprintf(stderr,
1233 " -A: allocate palette\n"
1234 " -c cmd: preprocess configuration file with <cmd>\n"
1235 " -C vis-class: use visual class <vis-class>\n"
1236 " -d display: run fvwm on <display>\n"
1237 " -D: enable debug oputput\n"
1238 " -f cfgfile: read configuration from <cfgfile>\n"
1239 " -F file: used internally for session management\n"
1240 " -h, -?: print this help message\n"
1241 " -i client-id: used internally for session management\n"
1242 " -I vis-id: use visual <vis-id>\n"
1243 " -l colors: try to use no more than <colors> colors\n"
1244 " -L: strict color limit\n"
1245 " -P: visual palette\n"
1246 " -r: replace running window manager\n"
1247 " -s [screen]: manage a single screen\n"
1248 " -S: static palette\n"
1249 " -V: print version information\n"
1250 );
1251 fprintf(stderr, "Try 'man %s' for more information.\n",
1252 PACKAGE);
1253
1254 return;
1255 }
1256
setVersionInfo(void)1257 static void setVersionInfo(void)
1258 {
1259 char version_str[256];
1260 char license_str[512];
1261 char support_str[512] = "";
1262 int support_len;
1263
1264 /* Set version information string */
1265 sprintf(version_str, "fvwm3 %s (%s)", VERSION, VERSIONINFO);
1266 Fvwm_VersionInfo = fxstrdup(version_str);
1267
1268 sprintf(license_str,
1269 "fvwm3 comes with NO WARRANTY, to the extent permitted by law. "
1270 "You may\nredistribute copies of fvwm under "
1271 "the terms of the GNU General Public License.\n"
1272 "For more information about these matters, see the file "
1273 "named COPYING.");
1274 Fvwm_LicenseInfo = fxstrdup(license_str);
1275
1276 #ifdef HAVE_READLINE
1277 strcat(support_str, " ReadLine,");
1278 #endif
1279 #ifdef XPM
1280 strcat(support_str, " XPM,");
1281 #endif
1282 #if PngSupport
1283 strcat(support_str, " PNG,");
1284 #endif
1285 #ifdef HAVE_RSVG
1286 strcat(support_str, " SVG,");
1287 #endif
1288 if (FHaveShapeExtension)
1289 strcat(support_str, " Shape,");
1290 #ifdef HAVE_XSHM
1291 strcat(support_str, " XShm,");
1292 #endif
1293 #ifdef SESSION
1294 strcat(support_str, " SM,");
1295 #endif
1296 #ifdef HAVE_BIDI
1297 strcat(support_str, " Bidi text,");
1298 #endif
1299 strcat(support_str, " XRandR,");
1300 #ifdef HAVE_XRENDER
1301 strcat(support_str, " XRender,");
1302 #endif
1303 #ifdef HAVE_XCURSOR
1304 strcat(support_str, " XCursor,");
1305 #endif
1306 #ifdef HAVE_XFT
1307 strcat(support_str, " XFT,");
1308 #endif
1309 #ifdef HAVE_NLS
1310 strcat(support_str, " NLS,");
1311 #endif
1312
1313 support_len = strlen(support_str);
1314 if (support_len > 0)
1315 {
1316 /* strip last comma */
1317 support_str[support_len - 1] = '\0';
1318 xasprintf(&Fvwm_SupportInfo, "with support for: %s", support_str);
1319 }
1320 else
1321 {
1322 Fvwm_SupportInfo = fxstrdup("with no optional feature support");
1323 }
1324
1325 return;
1326 }
1327
1328 /* Sets some initial style values & such */
SetRCDefaults(void)1329 static void SetRCDefaults(void)
1330 {
1331 #define RC_DEFAULTS_COMPLETE ((char *)-1)
1332 int i;
1333 /* set up default colors, fonts, etc */
1334 const char *defaults[][3] = {
1335 { "XORValue 0", "", "" },
1336 { "ImagePath "FVWM_DATADIR"/default-config/images", "", "" },
1337 { "SetEnv FVWM_DATADIR "FVWM_DATADIR"", "", "" },
1338 { "SetEnv FVWM_IS_FVWM3 1", "", "" },
1339 /* The below is historical -- before we had a default
1340 * configuration which defines these and more.
1341 */
1342 { "DefaultFont", "", "" },
1343 { "DefaultColors black grey", "", "" },
1344 { DEFAULT_MENU_STYLE, "", "" },
1345 { "TitleStyle Centered -- Raised", "", "" },
1346 { "Style * Color lightgrey/dimgrey", "", "" },
1347 { "Style * HilightFore black, HilightBack grey", "", "" },
1348 { "AddToFunc LoadDefaultConfig", "", "" },
1349 { "+ I Read "FVWM_DATADIR"/default-config/config", "", "" },
1350 { "+ I StartFunction", "", "" },
1351 {
1352 "AddToMenu MenuFvwmRoot \"",
1353 _("Builtin Menu"),
1354 "\" Title"
1355 },
1356 { "+ \"&1. XTerm\" Exec xterm", "", "" },
1357 { "+ \"&2. FvwmConsole\" Module FvwmConsole", "", "" },
1358 {
1359 "+ \"&3. ",
1360 _("Load Default Config"),
1361 "\" LoadDefaultConfig"
1362 },
1363 {
1364 "+ \"&4. ",
1365 _("Restart"),
1366 " Fvwm\" Restart"
1367 },
1368 {
1369 "+ \"&5. ",
1370 _("Quit"),
1371 " Fvwm\" Quit"
1372 },
1373 { "Mouse 1 R A Menu MenuFvwmRoot", "", "" },
1374 /* default menu navigation */
1375 { "Key Escape M A MenuClose", "", "" },
1376 { "Key Return M A MenuSelectItem", "", "" },
1377 { "Key Left M A MenuCursorLeft", "", "" },
1378 { "Key Right M A MenuCursorRight", "", "" },
1379 { "Key Up M A MenuMoveCursor -1", "", "" },
1380 { "Key Down M A MenuMoveCursor 1", "", "" },
1381 { "Mouse 1 MI A MenuSelectItem", "", "" },
1382 /* don't add anything below */
1383 { RC_DEFAULTS_COMPLETE, "", "" },
1384 { "Read "FVWM_DATADIR"/ConfigFvwmDefaults", "", "" },
1385 { NULL, NULL, NULL }
1386 };
1387
1388 for (i = 0; defaults[i][0] != NULL; i++)
1389 {
1390 const exec_context_t *exc;
1391 exec_context_changes_t ecc;
1392 char *cmd;
1393
1394 if (defaults[i][0] == RC_DEFAULTS_COMPLETE)
1395 {
1396 menu_bindings_startup_complete();
1397 continue;
1398 }
1399 ecc.type = Restarting ? EXCT_RESTART : EXCT_INIT;
1400 ecc.w.wcontext = C_ROOT;
1401 exc = exc_create_context(&ecc, ECC_TYPE | ECC_WCONTEXT);
1402 xasprintf(&cmd, "%s%s%s", defaults[i][0], defaults[i][1],
1403 defaults[i][2]);
1404 execute_function(NULL, exc, cmd, 0);
1405 free(cmd);
1406 exc_destroy_context(exc);
1407 }
1408 #undef RC_DEFAULTS_COMPLETE
1409
1410 return;
1411 }
1412
CatchRedirectError(Display * dpy,XErrorEvent * event)1413 static int CatchRedirectError(Display *dpy, XErrorEvent *event)
1414 {
1415 fvwm_debug(__func__, "another WM is running");
1416 exit(1);
1417
1418 /* to make insure happy */
1419 return 0;
1420 }
1421
1422 /* CatchFatal - Shuts down if the server connection is lost */
CatchFatal(Display * dpy)1423 static int CatchFatal(Display *dpy)
1424 {
1425 /* No action is taken because usually this action is caused by someone
1426 using "xlogout" to be able to switch between multiple window managers
1427 */
1428 module_kill_all();
1429 exit(1);
1430
1431 /* to make insure happy */
1432 return 0;
1433 }
1434
1435 /* FvwmErrorHandler - displays info on internal errors */
FvwmErrorHandler(Display * dpy,XErrorEvent * event)1436 static int FvwmErrorHandler(Display *dpy, XErrorEvent *event)
1437 {
1438 char errtext[512];
1439
1440 if (event->error_code == BadWindow)
1441 {
1442 bad_window = event->resourceid;
1443 return 0;
1444 }
1445 /* some errors are acceptable, mostly they're caused by
1446 * trying to update a lost window or free'ing another modules colors */
1447 if (event->error_code == BadWindow ||
1448 event->request_code == X_GetGeometry ||
1449 event->error_code == BadDrawable ||
1450 event->request_code == X_ConfigureWindow ||
1451 event->request_code == X_SetInputFocus||
1452 event->request_code == X_GrabButton ||
1453 event->request_code == X_ChangeWindowAttributes ||
1454 event->request_code == X_InstallColormap ||
1455 event->request_code == X_FreePixmap ||
1456 event->request_code == X_FreeColors)
1457 {
1458 return 0;
1459 }
1460
1461 XGetErrorText(dpy, event->error_code, errtext, 512);
1462
1463 fvwm_debug(__func__, "*** internal error ***");
1464 fvwm_debug(__func__, "Request %d, Error %d, Text %s, "
1465 "EventType: %d",
1466 event->request_code,
1467 event->error_code,
1468 errtext,
1469 last_event_type);
1470
1471 return 0;
1472 }
1473
1474 /* ---------------------------- interface functions ------------------------ */
1475
1476 /* Does initial window captures and runs init/restart function */
StartupStuff(void)1477 void StartupStuff(void)
1478 {
1479 #define start_func_name "StartFunction"
1480 const char *init_func_name;
1481 const exec_context_t *exc;
1482 exec_context_changes_t ecc;
1483
1484 ecc.type = Restarting ? EXCT_RESTART : EXCT_INIT;
1485 ecc.w.wcontext = C_ROOT;
1486 exc = exc_create_context(&ecc, ECC_TYPE | ECC_WCONTEXT);
1487 CaptureAllWindows(exc, False);
1488 /* Turn off the SM stuff after the initial capture so that new windows
1489 * will not be matched by accident. */
1490 if (Restarting)
1491 {
1492 DisableRestoringState();
1493 }
1494 /* Have to do this here too because preprocessor modules have not run
1495 * to the end when HandleEvents is entered from the main loop. */
1496 struct monitor *m;
1497 TAILQ_FOREACH(m, &monitor_q, entry)
1498 checkPanFrames(m);
1499
1500 fFvwmInStartup = False;
1501
1502 /* Make sure the geometry window uses the current font */
1503 resize_geometry_window();
1504
1505 /* Make sure we have the correct click time now. */
1506 if (Scr.ClickTime < 0)
1507 {
1508 Scr.ClickTime = -Scr.ClickTime;
1509 }
1510
1511 # if 0
1512 /* It is safe to ungrab here: if not, and one of the init functions
1513 * does not finish, we've got a complete freeze! */
1514 /* DV (15-Jul-2004): No, it is not safe to ungrab. If another
1515 * application grabs the pointer before execute_function gets it, the
1516 * start functions are not executed. And the pointer is grabbed
1517 * during function execution anyway, so releasing it here buys us
1518 * nothing. */
1519 UngrabEm(GRAB_STARTUP);
1520 XUngrabPointer(dpy, CurrentTime);
1521 #endif
1522
1523 /* migo (04-Sep-1999): execute StartFunction */
1524 if (functions_is_complex_function(start_func_name))
1525 {
1526 char *action = "Function " start_func_name;
1527
1528 execute_function(NULL, exc, action, 0);
1529 }
1530
1531 /* migo (03-Jul-1999): execute [Session]{Init|Restart}Function */
1532 init_func_name = get_init_function_name(Restarting == True);
1533 if (functions_is_complex_function(init_func_name))
1534 {
1535 char *action;
1536
1537 xasprintf(&action, "Function %s", init_func_name);
1538 execute_function(NULL, exc, action, 0);
1539 free(action);
1540 }
1541 /* see comment above */
1542 UngrabEm(GRAB_STARTUP);
1543 XUngrabPointer(dpy, CurrentTime);
1544
1545 /* This should be done after the initialization is finished, since
1546 * it directly changes the global state. */
1547 LoadGlobalState(state_filename);
1548
1549 /*
1550 ** migo (20-Jun-1999): Remove state file after usage.
1551 ** migo (09-Jul-1999): but only on restart, otherwise it can be reused.
1552 */
1553 if (Restarting)
1554 {
1555 unlink(state_filename);
1556 }
1557 exc_destroy_context(exc);
1558
1559 /* TA: 20091212: If we get here, we're done restarting, so reset the
1560 * flag back to False!
1561 */
1562 Restarting = False;
1563
1564 return;
1565 }
1566
1567 /***********************************************************************
1568 *
1569 * LoadDefaultButton -- loads default button # into button structure
1570 * assumes associated button memory is already free
1571 *
1572 ************************************************************************/
LoadDefaultButton(DecorFace * df,int i)1573 void LoadDefaultButton(DecorFace *df, int i)
1574 {
1575 if (i & 1)
1576 {
1577 LoadDefaultRightButton(df, i / 2);
1578 }
1579 else
1580 {
1581 LoadDefaultLeftButton(df, i / 2);
1582 }
1583
1584 return;
1585 }
1586
1587 /***********************************************************************
1588 *
1589 * ResetOrDestroyAllButtons -- resets all buttons to defaults
1590 * destroys existing buttons
1591 *
1592 ************************************************************************/
DestroyAllButtons(FvwmDecor * decor)1593 void DestroyAllButtons(FvwmDecor *decor)
1594 {
1595 TitleButton *tbp;
1596 DecorFace *face;
1597 int i;
1598 int j;
1599
1600 for (tbp = decor->buttons, i = 0; i < NUMBER_OF_TITLE_BUTTONS;
1601 i++, tbp++)
1602 {
1603 for (j = 0, face = TB_STATE(*tbp); j < BS_MaxButtonState;
1604 j++, face++)
1605 {
1606 FreeDecorFace(dpy, face);
1607 }
1608 }
1609
1610 return;
1611 }
1612
ResetAllButtons(FvwmDecor * decor)1613 void ResetAllButtons(FvwmDecor *decor)
1614 {
1615 TitleButton *tbp;
1616 DecorFace *face;
1617 int i;
1618 int j;
1619
1620 DestroyAllButtons(decor);
1621 for (tbp = decor->buttons, i = 0; i < NUMBER_OF_TITLE_BUTTONS;
1622 i++, tbp++)
1623 {
1624 memset(&TB_FLAGS(*tbp), 0, sizeof(TB_FLAGS(*tbp)));
1625 TB_JUSTIFICATION(*tbp) = JUST_CENTER;
1626 for (face = TB_STATE(*tbp), j = 0; j < BS_MaxButtonState;
1627 j++, face++)
1628 {
1629 LoadDefaultButton(face, i);
1630 }
1631 }
1632
1633 /* standard MWM decoration hint assignments (veliaa@rpi.edu)
1634 [Menu] - Title Bar - [Minimize] [Maximize] */
1635 TB_MWM_DECOR_FLAGS(decor->buttons[0]) |= MWM_DECOR_MENU;
1636 TB_MWM_DECOR_FLAGS(decor->buttons[1]) |= MWM_DECOR_MAXIMIZE;
1637 TB_MWM_DECOR_FLAGS(decor->buttons[3]) |= MWM_DECOR_MINIMIZE;
1638
1639 return;
1640 }
1641
SetMWM_INFO(Window window)1642 void SetMWM_INFO(Window window)
1643 {
1644 struct mwminfo
1645 {
1646 long props[2];
1647 /* prop[0]: flags */
1648 /* prop[1]: win */
1649 } motif_wm_info;
1650 static char set_yorn='n';
1651
1652 if (set_yorn=='y')
1653 {
1654 return;
1655 }
1656
1657 if (Scr.bo.is_modality_evil)
1658 {
1659 /* Set Motif WM_INFO atom to make motif relinquish
1660 * broken handling of modal dialogs */
1661 motif_wm_info.props[0] = 2;
1662 motif_wm_info.props[1] = window;
1663 XChangeProperty(
1664 dpy,Scr.Root, _XA_MOTIF_WM, _XA_MOTIF_WM,32,
1665 PropModeReplace, (unsigned char *)&motif_wm_info, 2);
1666 set_yorn='y';
1667 }
1668
1669 return;
1670 }
1671
1672 /*
1673 * set_init_function_name - sets one of the init, restart or exit function names
1674 * get_init_function_name - gets one of the init, restart or exit function names
1675 *
1676 * First parameter defines a function type: 0 - init, 1 - restart, 2 - exit.
1677 */
set_init_function_name(int n,const char * name)1678 void set_init_function_name(int n, const char *name)
1679 {
1680 init_function_names[n >= 0 && n < 3? n: 3] = name;
1681
1682 return;
1683 }
1684
get_init_function_name(int n)1685 const char *get_init_function_name(int n)
1686 {
1687 return init_function_names[n >= 0 && n < 3? n: 3];
1688 }
1689
1690 #ifndef _PATH_DEVNULL
1691 # define _PATH_DEVNULL "/dev/null"
1692 #endif
reopen_fd(int fd,char * mode,FILE * of)1693 static void reopen_fd(int fd, char* mode, FILE *of)
1694 {
1695 struct stat sbuf;
1696 FILE *f;
1697 int rc;
1698
1699 errno = 0;
1700 rc = fstat(fd, &sbuf);
1701 if (rc == 0)
1702 {
1703 return;
1704 }
1705 else if (errno != EBADF)
1706 {
1707 exit(77);
1708 }
1709 f = freopen(_PATH_DEVNULL, mode, of);
1710 if (f == 0 || fileno(f) != fd)
1711 {
1712 exit(88);
1713 }
1714
1715 return;
1716 }
1717
1718 /***********************************************************************
1719 *
1720 * Procedure:
1721 * main - start of fvwm
1722 *
1723 ***********************************************************************/
1724
main(int argc,char ** argv)1725 int main(int argc, char **argv)
1726 {
1727 unsigned long valuemask;
1728 XSetWindowAttributes attributes;
1729 int i;
1730 char *display_string;
1731 Bool do_force_single_screen = False;
1732 int single_screen_num = -1;
1733 Bool replace_wm = False;
1734 int visualClass = -1;
1735 int visualId = -1;
1736 PictureColorLimitOption colorLimitop = {-1, -1, -1, -1, -1};
1737 const exec_context_t *exc;
1738 exec_context_changes_t ecc;
1739 struct monitor *m = NULL;
1740
1741 fvwmlib_init_max_fd();
1742 /* Tell the FEvent module an event type that is not used by fvwm. */
1743 fev_init_invalid_event_type(KeymapNotify);
1744
1745 /* close open fds */
1746 for (i = 3; i < fvwmlib_max_fd; i++)
1747 {
1748 close(i);
1749 }
1750 /* reopen stdin, stdout and stderr if necessary */
1751 reopen_fd(0, "rb", stdin);
1752 reopen_fd(1, "wb", stdout);
1753 reopen_fd(2, "wb", stderr);
1754
1755 memset(&Scr, 0, sizeof(Scr));
1756 /* for use on restart */
1757 g_argv = fxmalloc((argc + 4) * sizeof(char *));
1758 g_argc = argc;
1759 for (i = 0; i < argc; i++)
1760 {
1761 g_argv[i] = argv[i];
1762 }
1763 g_argv[g_argc] = NULL;
1764
1765 FlocaleInit(LC_CTYPE, "", "", "fvwm");
1766 FGettextInit("fvwm", LOCALEDIR, "fvwm");
1767
1768 setVersionInfo();
1769 /* Put the default module directory into the environment so it can be
1770 * used later by the config file, etc. */
1771 flib_putenv("FVWM_MODULEDIR", "FVWM_MODULEDIR=" FVWM_MODULEDIR);
1772
1773 /* Figure out user's home directory */
1774 home_dir = find_home_dir();
1775 if (home_dir == NULL)
1776 {
1777 home_dir = "/"; /* give up and use root dir */
1778 }
1779
1780 /* Figure out where to read and write user's data files. */
1781 fvwm_userdir = getenv("FVWM_USERDIR");
1782 if (fvwm_userdir == NULL)
1783 {
1784 char *s;
1785
1786 xasprintf(&fvwm_userdir, "%s/.fvwm", home_dir);
1787 /* Put the user directory into the environment so it can be used
1788 * later everywhere. */
1789 xasprintf(&s, "FVWM_USERDIR=%s", fvwm_userdir);
1790 flib_putenv("FVWM_USERDIR", s);
1791 free(s);
1792 }
1793
1794 /* Create FVWM_USERDIR directory if needed */
1795 if (access(fvwm_userdir, F_OK) != 0)
1796 {
1797 mkdir(fvwm_userdir, 0777);
1798 }
1799 if (access(fvwm_userdir, W_OK) != 0)
1800 {
1801 fvwm_debug(__func__, "No write permissions in `%s/'.\n",
1802 fvwm_userdir);
1803 }
1804
1805 for (i = 1; i < argc; i++)
1806 {
1807 if (strcmp(argv[i], "-debug_stack_ring") == 0 ||
1808 strcmp(argv[i], "--debug-stack-ring") == 0)
1809 {
1810 debugging_stack_ring = True;
1811 }
1812 else if (strcmp(argv[i], "-D") == 0 ||
1813 strcmp(argv[i], "-debug") == 0 ||
1814 strcmp(argv[i], "--debug") == 0)
1815 {
1816 debugging = True;
1817 }
1818 else if (strcmp(argv[i], "-i") == 0 ||
1819 strcmp(argv[i], "-clientid") == 0 ||
1820 strcmp(argv[i], "--clientid") == 0 ||
1821 strcmp(argv[i], "-clientId") == 0 ||
1822 strcmp(argv[i], "--clientId") == 0)
1823 {
1824 if (++i >= argc)
1825 {
1826 usage(0);
1827 exit(1);
1828 }
1829 SetClientID(argv[i]);
1830 }
1831 else if (strcmp(argv[i], "-F") == 0 ||
1832 strcmp(argv[i], "-restore") == 0 ||
1833 strcmp(argv[i], "--restore") == 0)
1834 {
1835 if (++i >= argc)
1836 {
1837 usage(0);
1838 exit(1);
1839 }
1840 state_filename = argv[i];
1841 }
1842 else if (strcmp(argv[i], "-s") == 0 ||
1843 strcmp(argv[i], "-single-screen") == 0 ||
1844 strcmp(argv[i], "--single-screen") == 0)
1845 {
1846 do_force_single_screen = True;
1847 if (i+1 < argc && argv[i+1][0] != '-')
1848 {
1849 i++;
1850 if (sscanf(argv[i], "%d", &single_screen_num) ==
1851 0)
1852 {
1853 usage(0);
1854 exit(1);
1855 }
1856 }
1857 }
1858 else if (strcmp(argv[i], "-d") == 0 ||
1859 strcmp(argv[i], "-display") == 0 ||
1860 strcmp(argv[i], "--display") == 0)
1861 {
1862 if (++i >= argc)
1863 {
1864 usage(0);
1865 exit(1);
1866 }
1867 display_name = argv[i];
1868 }
1869 else if (strcmp(argv[i], "-f") == 0)
1870 {
1871 if (++i >= argc)
1872 {
1873 usage(0);
1874 exit(1);
1875 }
1876 if (num_config_commands < MAX_CFG_CMDS)
1877 {
1878 config_commands[num_config_commands] =
1879 (char *)malloc(6+strlen(argv[i]));
1880 strcpy(config_commands[num_config_commands],
1881 "Read ");
1882 strcat(config_commands[num_config_commands],
1883 argv[i]);
1884
1885 /* Check to see if the file requested exists.
1886 * If it doesn't, use the default config
1887 * instead.
1888 */
1889
1890 if (access(argv[i], F_OK) != 0) {
1891 free(config_commands[num_config_commands]);
1892 config_commands[num_config_commands] =
1893 fxstrdup("Read " FVWM_DATADIR
1894 "/default-config/config");
1895 }
1896 num_config_commands++;
1897 }
1898 else
1899 {
1900 fvwm_debug(__func__,
1901 "only %d -f and -cmd parms allowed!",
1902 MAX_CFG_CMDS);
1903 }
1904 }
1905 else if (strcmp(argv[i], "-c") == 0 ||
1906 strcmp(argv[i], "-cmd") == 0 ||
1907 strcmp(argv[i], "--cmd") == 0)
1908 {
1909 if (++i >= argc)
1910 {
1911 usage(0);
1912 exit(1);
1913 }
1914 if (num_config_commands < MAX_CFG_CMDS)
1915 {
1916 config_commands[num_config_commands] =
1917 fxstrdup(argv[i]);
1918 num_config_commands++;
1919 }
1920 else
1921 {
1922 fvwm_debug(__func__,
1923 "only %d -f and -cmd parms allowed!",
1924 MAX_CFG_CMDS);
1925 }
1926 }
1927 else if (strcmp(argv[i], "-h") == 0 ||
1928 strcmp(argv[i], "-?") == 0 ||
1929 strcmp(argv[i], "--help") == 0)
1930 {
1931 usage(1);
1932 exit(0);
1933 }
1934 else if (strcmp(argv[i], "-blackout") == 0)
1935 {
1936 /* obsolete option */
1937 fvwm_debug(__func__,
1938 "The -blackout option is obsolete, it will be "
1939 "removed in 3.0.");
1940 }
1941 else if (strcmp(argv[i], "-r") == 0 ||
1942 strcmp(argv[i], "-replace") == 0 ||
1943 strcmp(argv[i], "--replace") == 0)
1944 {
1945 replace_wm = True;
1946 }
1947 /* check for visualId before visual to remove ambiguity */
1948 else if (strcmp(argv[i], "-I") == 0 ||
1949 strcmp(argv[i], "-visualid") == 0 ||
1950 strcmp(argv[i], "--visualid") == 0 ||
1951 strcmp(argv[i], "-visualId") == 0 ||
1952 strcmp(argv[i], "--visualId") == 0)
1953 {
1954 visualClass = -1;
1955 if (++i >= argc)
1956 {
1957 usage(0);
1958 exit(1);
1959 }
1960 if (sscanf(argv[i], "0x%x", &visualId) == 0)
1961 {
1962 if (sscanf(argv[i], "%d", &visualId) == 0)
1963 {
1964 usage(0);
1965 exit(1);
1966 }
1967 }
1968 }
1969 else if (strcmp(argv[i], "-C") == 0 ||
1970 strcmp(argv[i], "-visual") == 0 ||
1971 strcmp(argv[i], "--visual") == 0)
1972 {
1973 visualId = None;
1974 if (++i >= argc)
1975 {
1976 usage(0);
1977 exit(1);
1978 }
1979 if (strncasecmp(argv[i], "staticg", 7) == 0)
1980 {
1981 visualClass = StaticGray;
1982 }
1983 else if (strncasecmp(argv[i], "g", 1) == 0)
1984 {
1985 visualClass = GrayScale;
1986 }
1987 else if (strncasecmp(argv[i], "staticc", 7) == 0)
1988 {
1989 visualClass = StaticColor;
1990 }
1991 else if (strncasecmp(argv[i], "p", 1) == 0)
1992 {
1993 visualClass = PseudoColor;
1994 }
1995 else if (strncasecmp(argv[i], "t", 1) == 0)
1996 {
1997 visualClass = TrueColor;
1998 }
1999 else if (strncasecmp(argv[i], "d", 1) == 0)
2000 {
2001 visualClass = DirectColor;
2002 }
2003 else
2004 {
2005 usage(0);
2006 exit(1);
2007 }
2008 }
2009 else if (strcmp(argv[i], "-l") == 0 ||
2010 strcmp(argv[i], "-color-limit") == 0 ||
2011 strcmp(argv[i], "--color-limit") == 0)
2012 {
2013 if (++i >= argc)
2014 {
2015 usage(0);
2016 exit(1);
2017 }
2018 colorLimitop.color_limit = atoi(argv[i]);
2019 }
2020 else if (strcmp(argv[i], "-L") == 0 ||
2021 strcmp(argv[i], "-strict-color-limit") == 0 ||
2022 strcmp(argv[i], "--strict-color-limit") == 0)
2023 {
2024 colorLimitop.strict = True;
2025 }
2026 else if (strcmp(argv[i], "-A") == 0 ||
2027 strcmp(argv[i], "-allocate-palette") == 0 ||
2028 strcmp(argv[i], "--allocate-palette") == 0)
2029 {
2030 colorLimitop.allocate = True;
2031 }
2032 else if (strcmp(argv[i], "-S") == 0 ||
2033 strcmp(argv[i], "-static-palette") == 0 ||
2034 strcmp(argv[i], "--static-palette") == 0)
2035 {
2036 colorLimitop.not_dynamic = True;
2037 }
2038 else if (strcmp(argv[i], "-P") == 0 ||
2039 strcmp(argv[i], "-visual-palette") == 0 ||
2040 strcmp(argv[i], "--visual-palette") == 0)
2041 {
2042 colorLimitop.use_named_table = True;
2043 }
2044 else if (strcmp(argv[i], "-V") == 0 ||
2045 strcmp(argv[i], "-version") == 0 ||
2046 strcmp(argv[i], "--version") == 0)
2047 {
2048 printf("%s\n%s\n\n%s\n", Fvwm_VersionInfo,
2049 Fvwm_SupportInfo, Fvwm_LicenseInfo);
2050 free(Fvwm_SupportInfo);
2051 exit(0);
2052 }
2053 else if (strcmp(argv[i], "-v") == 0)
2054 {
2055 log_set_level(1);
2056 log_open(fvwm_userdir);
2057 }
2058 else
2059 {
2060 usage(0);
2061 fprintf(stderr, "invalid option -- %s\n",
2062 argv[i]);
2063 exit(1);
2064 }
2065 }
2066
2067 InstallSignals();
2068
2069 if (single_screen_num >= 0)
2070 {
2071 char *dn = NULL;
2072
2073 if (display_name)
2074 {
2075 dn = display_name;
2076 }
2077 if (!dn)
2078 {
2079 dn = getenv("DISPLAY");
2080 }
2081 if (!dn)
2082 {
2083 /* should never happen ? */
2084 if (!(dpy = XOpenDisplay(dn)))
2085 {
2086 fvwm_debug(__func__, "can't open display %s"
2087 "to get the default display",
2088 XDisplayName(dn));
2089 }
2090 else
2091 {
2092 dn = XDisplayString(dpy);
2093 }
2094 }
2095 if (dn == NULL)
2096 {
2097 fvwm_debug(__func__,
2098 "couldn't find default display (%s)",
2099 XDisplayName(dn));
2100 }
2101 else
2102 {
2103 char *new_dn;
2104
2105 new_dn = get_display_name(dn, single_screen_num);
2106 if (dpy && strcmp(new_dn, dn) == 0)
2107 {
2108 /* allready opened */
2109 Pdpy = dpy;
2110 }
2111 else if (dpy)
2112 {
2113 XCloseDisplay(dpy);
2114 dpy = NULL;
2115 }
2116 if (!dpy && !(Pdpy = dpy = XOpenDisplay(new_dn)))
2117 {
2118 fvwm_debug(__func__,
2119 "can't open display %s, single screen "
2120 "number %d maybe not correct",
2121 new_dn, single_screen_num);
2122 }
2123 Scr.screen = single_screen_num;
2124 Scr.NumberOfScreens = ScreenCount(dpy);
2125 free(new_dn);
2126 }
2127 }
2128
2129 if (!dpy)
2130 {
2131 if(!(Pdpy = dpy = XOpenDisplay(display_name)))
2132 {
2133 fvwm_debug(__func__, "can't open display %s",
2134 XDisplayName(display_name));
2135 exit (1);
2136 }
2137 Scr.screen= DefaultScreen(dpy);
2138 Scr.NumberOfScreens = ScreenCount(dpy);
2139 }
2140
2141 atexit(catch_exit);
2142 master_pid = getpid();
2143
2144 if (!do_force_single_screen)
2145 {
2146 int myscreen = 0;
2147 char *new_dn;
2148 char *dn;
2149
2150 dn = XDisplayString(dpy);
2151 for (i=0;i<Scr.NumberOfScreens;i++)
2152 {
2153 if (i != Scr.screen && fork() == 0)
2154 {
2155 myscreen = i;
2156 new_dn = get_display_name(dn, myscreen);
2157 Pdpy = dpy = XOpenDisplay(new_dn);
2158 Scr.screen = myscreen;
2159 Scr.NumberOfScreens = ScreenCount(dpy);
2160 free(new_dn);
2161
2162 break;
2163 }
2164 }
2165
2166 g_argv[argc++] = "-s";
2167 g_argv[argc] = NULL;
2168 }
2169
2170 monitor_mode = MONITOR_TRACKING_G;
2171 FScreenInit(dpy);
2172 FScreenSelect(dpy);
2173 x_fd = XConnectionNumber(dpy);
2174
2175 #ifdef HAVE_X11_FD
2176 if (fcntl(x_fd, F_SETFD, 1) == -1)
2177 {
2178 fvwm_debug(__func__, "close-on-exec failed");
2179 exit (1);
2180 }
2181 #endif
2182
2183 /* Add a DISPLAY entry to the environment, incase we were started
2184 * with fvwm -display term:0.0 */
2185 xasprintf(&display_string, "DISPLAY=%s",XDisplayString(dpy));
2186 flib_putenv("DISPLAY", display_string);
2187 /* Add a HOSTDISPLAY environment variable, which is the same as
2188 * DISPLAY, unless display = :0.0 or unix:0.0, in which case the full
2189 * host name will be used for ease in networking.
2190 */
2191 if (strncmp(display_string, "DISPLAY=:",9)==0)
2192 {
2193 char client[MAXHOSTNAME], *rdisplay_string;
2194 gethostname(client,MAXHOSTNAME);
2195 xasprintf(&rdisplay_string, "HOSTDISPLAY=%s:%s", client,
2196 &display_string[9]);
2197 flib_putenv("HOSTDISPLAY", rdisplay_string);
2198 free(rdisplay_string);
2199 }
2200 else if (strncmp(display_string, "DISPLAY=unix:",13)==0)
2201 {
2202 char client[MAXHOSTNAME], *rdisplay_string;
2203 gethostname(client,MAXHOSTNAME);
2204 xasprintf(&rdisplay_string, "HOSTDISPLAY=%s:%s", client,
2205 &display_string[13]);
2206 flib_putenv("HOSTDISPLAY", rdisplay_string);
2207 free(rdisplay_string);
2208 }
2209 else
2210 {
2211 char *rdisplay_string;
2212 xasprintf(&rdisplay_string, "HOSTDISPLAY=%s",
2213 XDisplayString(dpy));
2214 flib_putenv("HOSTDISPLAY", rdisplay_string);
2215 free(rdisplay_string);
2216 }
2217 free(display_string);
2218
2219 Scr.Root = RootWindow(dpy, Scr.screen);
2220 if (Scr.Root == None)
2221 {
2222 fvwm_debug(__func__, "Screen %d is not a valid screen",
2223 (int)Scr.screen);
2224 exit(1);
2225 }
2226
2227 {
2228 XVisualInfo template, *vinfo = NULL;
2229 int total, i;
2230
2231 Pdepth = 0;
2232 Pdefault = False;
2233 total = 0;
2234 template.screen = Scr.screen;
2235 if (visualClass != -1)
2236 {
2237 template.class = visualClass;
2238 vinfo = XGetVisualInfo(dpy,
2239 VisualScreenMask|VisualClassMask,
2240 &template, &total);
2241 if (!total)
2242 {
2243 fvwm_debug(__func__,
2244 "Cannot find visual class %d",
2245 visualClass);
2246 }
2247 }
2248 else if (visualId != -1)
2249 {
2250 template.visualid = visualId;
2251 vinfo = XGetVisualInfo(dpy,
2252 VisualScreenMask|VisualIDMask,
2253 &template, &total);
2254 if (!total)
2255 {
2256 fvwm_debug(__func__,
2257 "VisualId 0x%x is not valid ",
2258 visualId);
2259 }
2260 }
2261
2262 /* visualID's are unique so there will only be one.
2263 Select the visualClass with the biggest depth */
2264 for (i = 0; i < total; i++)
2265 {
2266 if (vinfo[i].depth > Pdepth)
2267 {
2268 Pvisual = vinfo[i].visual;
2269 Pdepth = vinfo[i].depth;
2270 }
2271 }
2272 if (vinfo)
2273 {
2274 XFree(vinfo);
2275 }
2276
2277 /* Detection of a card with 2 hardware colormaps (8+24) which
2278 * use depth 8 for the default. We can use our own depth 24
2279 * cmap without affecting other applications. */
2280 if (Pdepth == 0 && DefaultDepth(dpy, Scr.screen) <= 8)
2281 {
2282 template.class = TrueColor;
2283 vinfo = XGetVisualInfo(
2284 dpy, VisualScreenMask|VisualClassMask,
2285 &template, &total);
2286
2287 for(i = 0; i<total; i++)
2288 {
2289 if (Pdepth < vinfo[i].depth &&
2290 vinfo[i].depth > 8)
2291 {
2292 Pvisual = vinfo[i].visual;
2293 Pdepth = vinfo[i].depth;
2294 }
2295 }
2296 if (vinfo)
2297 {
2298 XFree(vinfo);
2299 }
2300 }
2301
2302 /* have to have a colormap for non-default visual windows */
2303 if (Pdepth > 0)
2304 {
2305 if (Pvisual->class == DirectColor)
2306 {
2307 Pcmap = XCreateColormap(
2308 dpy, Scr.Root, Pvisual, AllocAll);
2309 }
2310 else
2311 {
2312 Pcmap = XCreateColormap(
2313 dpy, Scr.Root, Pvisual, AllocNone);
2314 }
2315 }
2316 /* use default visuals if none found so far */
2317 else
2318 {
2319 Pvisual = DefaultVisual(dpy, Scr.screen);
2320 Pdepth = DefaultDepth(dpy, Scr.screen);
2321 Pcmap = DefaultColormap(dpy, Scr.screen);
2322 Pdefault = True;
2323 }
2324 }
2325
2326 PictureSetupWhiteAndBlack();
2327
2328 /* make a copy of the visual stuff so that XorPixmap can swap with root
2329 */
2330 PictureSaveFvwmVisual();
2331
2332 Scr.ColorLimit = 0;
2333 PUseDynamicColors = 0;
2334 Scr.ColorLimit = PictureInitColors(
2335 PICTURE_CALLED_BY_FVWM, True, &colorLimitop, True, True);
2336
2337 #ifdef Frsvg_init
2338 Frsvg_init();
2339 #endif
2340 FShapeInit(dpy);
2341 FRenderInit(dpy);
2342
2343 Scr.pscreen = XScreenOfDisplay(dpy, Scr.screen);
2344 Scr.use_backing_store = DoesBackingStore(Scr.pscreen);
2345 Scr.flags.do_save_under = DoesSaveUnders(Scr.pscreen);
2346
2347 InternUsefulAtoms();
2348
2349 /* Make sure property priority colors is empty */
2350 XChangeProperty(dpy, Scr.Root, _XA_MIT_PRIORITY_COLORS,
2351 XA_CARDINAL, 32, PropModeReplace, NULL, 0);
2352
2353 Scr.FvwmCursors = CreateCursors(dpy);
2354 XDefineCursor(dpy, Scr.Root, Scr.FvwmCursors[CRS_ROOT]);
2355 /* create a window which will accept the keyboard focus when no other
2356 * windows have it */
2357 /* do this before any RC parsing as some GC's are created from this
2358 * window rather than the root window */
2359 attributes.event_mask = XEVMASK_NOFOCUSW;
2360 attributes.override_redirect = True;
2361 attributes.colormap = Pcmap;
2362 attributes.cursor = Scr.FvwmCursors[CRS_DEFAULT];
2363 attributes.background_pixmap = None;
2364 attributes.border_pixel = 0;
2365 Scr.NoFocusWin=XCreateWindow(
2366 dpy, Scr.Root, -10, -10, 10, 10, 0, Pdepth, InputOutput,
2367 Pvisual, CWEventMask | CWOverrideRedirect | CWColormap |
2368 CWBackPixmap | CWBorderPixel | CWCursor, &attributes);
2369 XMapWindow(dpy, Scr.NoFocusWin);
2370 SetMWM_INFO(Scr.NoFocusWin);
2371 FOCUS_SET(Scr.NoFocusWin, NULL);
2372
2373 frame_init();
2374 XFlush(dpy);
2375 if (debugging)
2376 {
2377 sync_server(1);
2378 }
2379
2380 SetupICCCM2(replace_wm);
2381 XSetIOErrorHandler(CatchFatal);
2382 {
2383 /* We need to catch any errors of XSelectInput on the root
2384 * window here. The event mask contains
2385 * SubstructureRedirectMask which can be acquired by exactly
2386 * one client (window manager). Synchronizing is necessary
2387 * here because Neither XSetErrorHandler nor XSelectInput
2388 * generate any protocol requests.
2389 */
2390 XSync(dpy, 0);
2391 XSetErrorHandler(CatchRedirectError);
2392 XSelectInput(dpy, Scr.Root, XEVMASK_ROOTW);
2393 XSync(dpy, 0);
2394 XSetErrorHandler(FvwmErrorHandler);
2395 }
2396 {
2397 /* do not grab the pointer earlier because if fvwm exits with
2398 * the pointer grabbed while a different display is visible,
2399 * XFree 4.0 freezes. */
2400 Cursor cursor = XCreateFontCursor(dpy, XC_watch);
2401 XGrabPointer(
2402 dpy, Scr.Root, 0, 0, GrabModeAsync, GrabModeAsync,
2403 None, cursor, CurrentTime);
2404 }
2405 {
2406 Atom atype;
2407 int aformat;
2408 unsigned long nitems, bytes_remain;
2409 unsigned char *prop;
2410
2411 if (XGetWindowProperty(
2412 dpy, Scr.Root, _XA_WM_DESKTOP, 0L, 1L, True,
2413 _XA_WM_DESKTOP, &atype, &aformat, &nitems,
2414 &bytes_remain, &prop) == Success)
2415 {
2416 if (prop != NULL)
2417 {
2418 Restarting = True;
2419 /* do_force_single_screen = True; */
2420 }
2421 }
2422 }
2423 xasprintf(&restart_state_filename, "%s/.fs-restart-%s", fvwm_userdir,
2424 getenv("HOSTDISPLAY"));
2425 if (!state_filename && Restarting)
2426 {
2427 state_filename = restart_state_filename;
2428 }
2429
2430 InitVariables();
2431 if (visualClass != -1 || visualId != -1)
2432 {
2433 /* this is so that menus use the (non-default) fvwm colormap */
2434 FW_W(&Scr.FvwmRoot) = Scr.NoFocusWin;
2435 Scr.FvwmRoot.number_cmap_windows = 1;
2436 Scr.FvwmRoot.cmap_windows = &Scr.NoFocusWin;
2437 }
2438 InitEventHandlerJumpTable();
2439
2440 Scr.gray_bitmap =
2441 XCreateBitmapFromData(dpy,Scr.Root,g_bits, g_width,g_height);
2442
2443 /* This should be done early enough to have the window states loaded
2444 * before the first call to AddWindow. */
2445 fvwm_debug(__func__, "Loading window states via %s", state_filename);
2446 LoadWindowStates(state_filename);
2447
2448 is_tracking_shared = false;
2449 TAILQ_FOREACH(m, &monitor_q, entry)
2450 EWMH_Init(m);
2451
2452 SetRCDefaults();
2453 flush_window_updates();
2454 simplify_style_list();
2455
2456 ecc.type = Restarting ? EXCT_RESTART : EXCT_INIT;
2457 ecc.w.wcontext = C_ROOT;
2458 exc = exc_create_context(&ecc, ECC_TYPE | ECC_WCONTEXT);
2459 if (num_config_commands > 0)
2460 {
2461 int i;
2462 for (i = 0; i < num_config_commands; i++)
2463 {
2464 DoingCommandLine = True;
2465 execute_function(NULL, exc, config_commands[i], 0);
2466 free(config_commands[i]);
2467 }
2468 DoingCommandLine = False;
2469 }
2470 else
2471 {
2472 /* Run startup command file in these places (default prefix):
2473 * ~/.fvwm/config
2474 * /usr/local/share/fvwm/config
2475 * and for compatibility:
2476 * ~/.fvwm/.fvwm2rc
2477 * /usr/local/share/fvwm/system.fvwm2rc
2478 * and for compatibility to be discontinued:
2479 * ~/.fvwm2rc,
2480 * /usr/local/share/fvwm/.fvwm2rc
2481 * /usr/local/etc/system.fvwm2rc
2482 */
2483 int upper = 8;
2484 int nl = -1, tries = 0;
2485 char *cfg_loc[upper];
2486
2487 xasprintf(&cfg_loc[++nl], "%s/%s", fvwm_userdir, FVWM_CONFIG);
2488 xasprintf(&cfg_loc[++nl], "%s/%s", FVWM_DATADIR, FVWM_CONFIG);
2489 xasprintf(&cfg_loc[++nl], "%s/%s", fvwm_userdir, FVWM2RC);
2490 xasprintf(&cfg_loc[++nl], "%s/%s", home_dir, FVWM2RC);
2491 xasprintf(&cfg_loc[++nl], "%s/%s", FVWM_DATADIR, FVWM2RC);
2492 xasprintf(&cfg_loc[++nl], "%s/system%s", FVWM_DATADIR, FVWM2RC);
2493 xasprintf(&cfg_loc[++nl], "%s/system%s", FVWM_CONFDIR, FVWM2RC);
2494 xasprintf(&cfg_loc[++nl], "%s/default-config/config", FVWM_DATADIR);
2495
2496 for (nl = 0; nl < upper; nl++) {
2497 if (!run_command_file(cfg_loc[nl], exc)) {
2498 fvwm_debug(__func__,
2499 "couldn't find/load [%d]: %s\n", nl, cfg_loc[nl]);
2500 tries++;
2501 } else {
2502 fprintf(stderr, "loaded [%d]: %s\n", nl, cfg_loc[nl]);
2503 break;
2504 }
2505 }
2506
2507 if (tries == upper) {
2508 fvwm_debug(__func__,
2509 "Cannot read startup config file,"
2510 " tried: \n\t%s/%s\n\t%s/%s\n\t%s/%s\n\t"
2511 "%s/%s\n\t%s/%s\n\t%s/system%s\n\t%s/system%s",
2512 fvwm_userdir, FVWM_CONFIG,
2513 FVWM_DATADIR, FVWM_CONFIG,
2514 fvwm_userdir, FVWM2RC,
2515 home_dir, FVWM2RC,
2516 FVWM_DATADIR, FVWM2RC,
2517 FVWM_DATADIR, FVWM2RC,
2518 FVWM_CONFDIR, FVWM2RC);
2519 }
2520 for (nl = 0; nl < upper; nl++)
2521 free(cfg_loc[nl]);
2522 }
2523 exc_destroy_context(exc);
2524
2525 if (Pdepth<2)
2526 {
2527 Scr.gray_pixmap = XCreatePixmapFromBitmapData(
2528 dpy, Scr.NoFocusWin, g_bits, g_width, g_height,
2529 PictureBlackPixel(), PictureWhitePixel(), Pdepth);
2530 Scr.light_gray_pixmap = XCreatePixmapFromBitmapData(
2531 dpy, Scr.NoFocusWin, l_g_bits, l_g_width, l_g_height,
2532 PictureBlackPixel(), PictureWhitePixel(), Pdepth);
2533 Scr.sticky_gray_pixmap = XCreatePixmapFromBitmapData(
2534 dpy, Scr.NoFocusWin, s_g_bits, s_g_width, s_g_height,
2535 PictureBlackPixel(), PictureWhitePixel(), Pdepth);
2536 }
2537
2538 attributes.background_pixel = Scr.StdBack;
2539 attributes.colormap = Pcmap;
2540 attributes.border_pixel = 0;
2541 valuemask = CWBackPixel | CWColormap | CWBorderPixel;
2542
2543 Scr.SizeWindow.win = XCreateWindow(
2544 dpy, Scr.Root, 0, 0, 1, 1, 0, Pdepth,
2545 InputOutput, Pvisual, valuemask, &attributes);
2546 resize_geometry_window();
2547 CoerceEnterNotifyOnCurrentWindow();
2548 SessionInit();
2549
2550 HandleEvents();
2551 switch (fvwmRunState)
2552 {
2553 case FVWM_DONE:
2554 Done(0, NULL); /* does not return */
2555
2556 case FVWM_RESTART:
2557 Done(1, ""); /* does not return */
2558
2559 default:
2560 break;
2561 }
2562
2563 exit(0);
2564 }
2565