todo-2.6 -- add note for fvwm-menu-desktop (2.6.X release)
[fvwm.git] / modules / FvwmM4 / FvwmM4.c
blob5ca7cb188cb979944afe1c837fdc064b5683c220
1 /* -*-c-*- */
2 /* This module, and the entire FvwmM4 program, and the concept for
3 * interfacing this module to the Window Manager, are all original work
4 * by Robert Nation
6 * Copyright 1994, Robert Nation
7 * No guarantees or warantees or anything
8 * are provided or implied in any way whatsoever. Use this program at your
9 * own risk. Permission to use this program for any purpose is given,
10 * as long as the copyright is kept intact. */
12 /* This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "config.h"
29 #include <stdio.h>
30 #include <signal.h>
31 #include <fcntl.h>
32 #include <sys/wait.h>
33 #include "libs/ftime.h"
34 #include <unistd.h>
35 #include <ctype.h>
36 #include <pwd.h>
37 #include <sys/param.h>
38 #include <sys/types.h>
39 #include <netdb.h>
41 #include <X11/Xlib.h>
42 #include <X11/Xutil.h>
43 #include <X11/Xproto.h>
44 #include <X11/Xatom.h>
45 #include <X11/Intrinsic.h>
47 #include "libs/Module.h"
48 #include "libs/Strings.h"
49 #include "libs/System.h"
50 #include "libs/fvwm_sys_stat.h"
52 #include "FvwmM4.h"
53 #include "libs/fvwmlib.h"
54 #include "libs/FShape.h"
55 #include "libs/PictureBase.h"
56 #include "libs/FSMlib.h"
57 #include <X11/StringDefs.h>
58 #include <X11/Shell.h>
59 #define Resolution(pixels, mm) ((((pixels) * 2000 / (mm)) + 1) / 2)
61 char *MyName;
62 int fd[2];
64 long Vx, Vy;
65 static char *MkDef(char *name, char *def);
66 static char *MkNum(char *name,int def);
67 static char *m4_defs(Display *display, const char *host, char *m4_options, char *config_file);
68 #define MAXHOSTNAME 255
69 #define EXTRA 56
71 int m4_enable; /* use m4? */
72 int m4_prefix; /* Do GNU m4 prefixing (-P) */
73 int m4_prefix_defines; /* Add "m4_" to the names of the defines */
74 char m4_options[BUFSIZ]; /* Command line options to m4 */
75 char m4_outfile[BUFSIZ] = ""; /* The output filename for m4 */
76 char *m4_prog = "m4"; /* Name of the m4 program */
77 int m4_default_quotes; /* Use default m4 quotes */
78 char *m4_startquote = "`"; /* Left quote characters for m4 */
79 char *m4_endquote = "'"; /* Right quote characters for m4 */
84 * Procedure:
85 * main - start of module
88 int main(int argc, char **argv)
90 Display *dpy; /* which display are we talking to */
91 char *temp, *s;
92 char *display_name = NULL;
93 char *filename = NULL;
94 char *tmp_file;
95 int i;
96 int debug = 0;
97 int lock = 0;
98 int noread = 0;
99 char *user_dir;
100 char *m4path;
102 /* Figure out the working directory and go to it */
103 user_dir = getenv("FVWM_USERDIR");
104 if (user_dir != NULL)
106 if (chdir(user_dir) < 0)
107 fprintf(stderr, "%s: <<Warning>> chdir to %s failed in m4_defs",
108 MyName, user_dir);
111 m4_enable = True;
112 m4_prefix = False;
113 m4_prefix_defines = False;
114 sprintf(m4_options, " ");
115 m4_default_quotes = 1;
116 /* add FVWM_DATADIR to the include path. Can't use the -I option here because
117 * it is incompatible with the System V version of m4. Instead, append it to
118 * the front of the M4PATH environment variable. */
119 m4path = getenv("M4PATH");
120 if (m4path == NULL)
122 m4path = safemalloc(sizeof("M4PATH=") + strlen(FVWM_DATADIR) + 1);
123 sprintf(m4path, "M4PATH=%s", FVWM_DATADIR);
125 else
127 char *s;
129 s = safemalloc(
130 sizeof("M4PATH=") + strlen(FVWM_DATADIR) + strlen(m4path) + 2);
131 sprintf(s, "M4PATH=%s:%s", FVWM_DATADIR, m4path);
132 m4path = s;
134 putenv(m4path);
136 /* Record the program name for error messages */
137 temp = argv[0];
139 s=strrchr(argv[0], '/');
140 if (s != NULL)
141 temp = s + 1;
143 MyName = safemalloc(strlen(temp)+2);
144 strcpy(MyName,"*");
145 strcat(MyName, temp);
147 if(argc < 6)
149 fprintf(stderr,"%s Version %s should only be executed by fvwm!\n",MyName,
150 VERSION);
151 exit(1);
154 /* We should exit if our fvwm pipes die */
155 signal (SIGPIPE, DeadPipe);
157 fd[0] = atoi(argv[1]);
158 fd[1] = atoi(argv[2]);
160 for(i=6;i<argc;i++)
162 if(strcasecmp(argv[i],"-m4-prefix") == 0)
164 m4_prefix = True;
166 else if(strcasecmp(argv[i],"-m4-prefix-defines") == 0)
168 m4_prefix_defines = True;
170 else if(strcasecmp(argv[i],"-m4opt") == 0)
172 /* leaving this in just in case-- any option starting with '-'
173 will get passed on to m4 anyway */
174 strcat(m4_options, argv[++i]);
175 strcat(m4_options, " ");
177 else if(strcasecmp(argv[i],"-m4-squote") == 0)
179 m4_startquote = argv[++i];
180 m4_default_quotes = 0;
182 else if(strcasecmp(argv[i],"-m4-equote") == 0)
184 m4_endquote = argv[++i];
185 m4_default_quotes = 0;
187 else if (strcasecmp(argv[i], "-m4prog") == 0)
189 m4_prog = argv[++i];
191 else if(strcasecmp(argv[i], "-outfile") == 0)
193 strcpy(m4_outfile,argv[++i]);
195 else if(strcasecmp(argv[i], "-debug") == 0)
197 debug = 1;
199 else if(strcasecmp(argv[i], "-lock") == 0)
201 lock = 1;
203 else if(strcasecmp(argv[i], "-noread") == 0)
205 noread = 1;
207 else if (strncasecmp(argv[i],"-",1) == 0)
209 /* pass on any other arguments starting with '-' to m4 */
210 strcat(m4_options, argv[i]);
211 strcat(m4_options, " ");
213 else
214 filename = argv[i];
217 if (!filename)
219 fprintf(stderr, "%s: no file specified.\n", MyName);
220 exit(1);
222 for(i=0;i<strlen(filename);i++)
223 if((filename[i] == '\n')||(filename[i] == '\r'))
225 filename[i] = 0;
228 if (!(dpy = XOpenDisplay(display_name)))
230 fprintf(stderr,"FvwmM4: can't open display %s",
231 XDisplayName(display_name));
232 exit (1);
235 /* set up G */
236 PictureInitCMap(dpy);
238 /* tell fvwm we're running if -lock is not used */
239 if (!lock)
240 SendFinishedStartupNotification(fd);
242 tmp_file = m4_defs(dpy, display_name,m4_options, filename);
244 if (!noread)
246 char *read_string = CatString3("Read '", tmp_file, "'");
247 SendText(fd, read_string, 0);
250 /* tell fvwm to continue if -lock is used */
251 if (lock)
252 SendFinishedStartupNotification(fd);
254 /* For a debugging version, we may wish to omit this part. */
255 /* I'll let some m4 advocates clean this up */
256 if (!debug)
258 char *delete_string;
259 char *delete_file = tmp_file;
260 if (tmp_file[0] != '/' && user_dir != NULL)
262 delete_file = safestrdup(CatString3(user_dir, "/", tmp_file));
264 delete_string = CatString3("Exec exec /bin/rm '", delete_file, "'");
265 SendText(fd, delete_string, 0);
268 return 0;
273 static char *m4_defs(
274 Display *display, const char *host, char *m4_options, char *config_file)
276 Screen *screen;
277 Visual *visual;
278 char client[MAXHOSTNAME], server[MAXHOSTNAME], *colon;
279 char ostype[BUFSIZ];
280 char options[BUFSIZ];
281 static char tmp_name[BUFSIZ];
282 struct hostent *hostname;
283 char *vc; /* Visual Class */
284 FILE *tmpf;
285 struct passwd *pwent;
286 int fd;
287 int ScreenWidth, ScreenHeight;
288 int Mscreen;
290 /* Generate a temporary filename. Honor the TMPDIR environment variable,
291 if set. Hope nobody deletes this file! */
293 if (strlen(m4_outfile) == 0)
295 if ((vc = getenv("TMPDIR")))
297 strcpy(tmp_name, vc);
299 else
301 strcpy(tmp_name, "/tmp");
303 strcat(tmp_name, "/fvwmrcXXXXXX");
304 fd = fvwm_mkstemp(tmp_name);
305 if (fd == -1)
307 fprintf(
308 stderr,
309 "[FvwmM4][m4_def] fvwm_mkstemp failed %s\n",
310 tmp_name);
311 exit(0377);
314 else
316 strcpy(tmp_name, m4_outfile);
318 * check to make sure it doesn't exist already, to prevent
319 * security hole
321 /* first try to unlink it */
322 unlink(tmp_name);
323 fd = open(
324 tmp_name, O_WRONLY|O_EXCL|O_CREAT,
325 FVWM_S_IRUSR | FVWM_S_IWUSR);
326 if (fd < 0)
328 fprintf(
329 stderr,
330 "[FvwmM4][m4_defs] error opening file %s\n",
331 tmp_name);
332 exit(0377);
336 close(fd);
339 * Create the appropriate command line to run m4, and
340 * open a pipe to the command.
343 if(m4_prefix)
345 sprintf(
346 options, "%s --prefix-builtins %s > %s\n",
347 m4_prog,
348 m4_options, tmp_name);
350 else
352 sprintf(options, "%s %s > %s\n",
353 m4_prog,
354 m4_options, tmp_name);
356 tmpf = popen(options, "w");
357 if (tmpf == NULL)
359 fprintf(
360 stderr,
361 "[FvwmM4][m4_defs] Cannot open pipe to m4\n");
362 exit(0377);
365 gethostname(client,MAXHOSTNAME);
366 getostype (ostype, sizeof ostype);
368 /* Change the quoting characters, if specified */
370 if (!m4_default_quotes)
372 fprintf(
373 tmpf, "%schangequote(%s, %s)%sdnl\n",
374 (m4_prefix) ? "m4_" : "",
375 m4_startquote, m4_endquote,
376 (m4_prefix) ? "m4_" : "");
379 hostname = gethostbyname(client);
380 strcpy(server, XDisplayName(host));
381 colon = strchr(server, ':');
382 if (colon != NULL) *colon = '\0';
383 if ((server[0] == '\0') || (!strcmp(server, "unix")))
384 strcpy(server, client); /* must be connected to :0 or unix:0 */
386 /* TWM_TYPE is fvwm, for completeness */
388 fputs(MkDef("TWM_TYPE", "fvwm"), tmpf);
390 /* The machine running the X server */
391 fputs(MkDef("SERVERHOST", server), tmpf);
392 /* The machine running the window manager process */
393 fputs(MkDef("CLIENTHOST", client), tmpf);
394 if (hostname)
395 fputs(MkDef("HOSTNAME", (char *)hostname->h_name), tmpf);
396 else
397 fputs(MkDef("HOSTNAME", (char *)client), tmpf);
399 fputs(MkDef("OSTYPE", ostype), tmpf);
401 pwent=getpwuid(geteuid());
402 fputs(MkDef("USER", pwent->pw_name), tmpf);
404 fputs(MkDef("HOME", getenv("HOME")), tmpf);
405 fputs(MkNum("VERSION", ProtocolVersion(display)), tmpf);
406 fputs(MkNum("REVISION", ProtocolRevision(display)), tmpf);
407 fputs(MkDef("VENDOR", ServerVendor(display)), tmpf);
408 fputs(MkNum("RELEASE", VendorRelease(display)), tmpf);
410 Mscreen= DefaultScreen(display);
411 fputs(MkNum("SCREEN", Mscreen), tmpf);
413 ScreenWidth = DisplayWidth(display,Mscreen);
414 ScreenHeight = DisplayHeight(display,Mscreen);
415 fputs(MkNum("WIDTH", DisplayWidth(display,Mscreen)), tmpf);
416 fputs(MkNum("HEIGHT", DisplayHeight(display,Mscreen)), tmpf);
418 screen = ScreenOfDisplay(display, Mscreen);
419 fputs(MkNum(
420 "X_RESOLUTION",Resolution(screen->width,screen->mwidth)),
421 tmpf);
422 fputs(MkNum(
423 "Y_RESOLUTION",Resolution(screen->height,screen->mheight)),
424 tmpf);
425 fputs(MkNum("PLANES",DisplayPlanes(display, Mscreen)), tmpf);
427 visual = DefaultVisualOfScreen(screen);
428 fputs(MkNum("BITS_PER_RGB", visual->bits_per_rgb), tmpf);
430 switch(visual->class)
432 case(StaticGray):
433 vc = "StaticGray";
434 break;
435 case(GrayScale):
436 vc = "GrayScale";
437 break;
438 case(StaticColor):
439 vc = "StaticColor";
440 break;
441 case(PseudoColor):
442 vc = "PseudoColor";
443 break;
444 case(TrueColor):
445 vc = "TrueColor";
446 break;
447 case(DirectColor):
448 vc = "DirectColor";
449 break;
450 default:
451 vc = "NonStandard";
452 break;
454 fputs(MkDef("CLASS", vc), tmpf);
456 switch(Pvisual->class)
458 case(StaticGray):
459 vc = "StaticGray";
460 break;
461 case(GrayScale):
462 vc = "GrayScale";
463 break;
464 case(StaticColor):
465 vc = "StaticColor";
466 break;
467 case(PseudoColor):
468 vc = "PseudoColor";
469 break;
470 case(TrueColor):
471 vc = "TrueColor";
472 break;
473 case(DirectColor):
474 vc = "DirectColor";
475 break;
476 default:
477 vc = "NonStandard";
478 break;
480 fputs(MkDef("FVWM_CLASS", vc), tmpf);
482 if (visual->class != StaticGray && visual->class != GrayScale)
483 fputs(MkDef("COLOR", "Yes"), tmpf);
484 else
485 fputs(MkDef("COLOR", "No"), tmpf);
487 if (Pvisual->class != StaticGray && Pvisual->class != GrayScale)
488 fputs(MkDef("FVWM_COLOR", "Yes"), tmpf);
489 else
490 fputs(MkDef("FVWM_COLOR", "No"), tmpf);
492 fputs(MkDef("FVWM_VERSION", VERSION), tmpf);
494 /* Add options together */
495 *options = '\0';
496 if (FHaveShapeExtension)
497 strcat(options, "SHAPE ");
499 if (XpmSupport)
500 strcat(options, "XPM ");
502 strcat(options, "M4 ");
504 fputs(MkDef("OPTIONS", options), tmpf);
506 fputs(MkDef("FVWM_MODULEDIR", FVWM_MODULEDIR), tmpf);
507 fputs(MkDef("FVWM_DATADIR", FVWM_DATADIR), tmpf);
509 if ((vc = getenv("FVWM_USERDIR")))
510 fputs(MkDef("FVWM_USERDIR", vc), tmpf);
512 if (SessionSupport && (vc = getenv("SESSION_MANAGER")))
513 fputs(MkDef("SESSION_MANAGER", vc), tmpf);
516 * At this point, we've sent the definitions to m4. Just include
517 * the fvwmrc file now.
520 fprintf(tmpf, "%sinclude(%s%s%s)\n",
521 (m4_prefix) ? "m4_": "",
522 m4_startquote,
523 config_file,
524 m4_endquote);
526 pclose(tmpf);
527 return(tmp_name);
533 * Procedure:
534 * SIGPIPE handler - SIGPIPE means fvwm is dying
537 RETSIGTYPE DeadPipe(int nonsense)
539 exit(0);
540 SIGNAL_RETURN;
543 static char *MkDef(char *name, char *def)
545 char *cp = NULL;
546 int n;
548 /* Get space to hold everything, if needed */
550 n = EXTRA + strlen(name) + strlen(def);
551 cp = safemalloc(n);
553 if (m4_prefix)
554 strcpy(cp, "m4_define(");
555 else
556 strcpy(cp, "define(");
558 if (m4_prefix_defines)
559 strcat(cp, "m4_");
560 strcat(cp, name);
562 /* Tack on "," and 2 sets of starting quotes */
563 strcat(cp, ",");
564 strcat(cp, m4_startquote);
565 strcat(cp, m4_startquote);
567 /* The definition itself */
568 strcat(cp, def);
570 /* Add 2 sets of closing quotes */
571 strcat(cp, m4_endquote);
572 strcat(cp, m4_endquote);
574 /* End the definition, appropriately */
575 strcat(cp, ")");
576 if (m4_prefix)
577 strcat(cp, "m4_");
579 strcat(cp, "dnl\n");
581 return(cp);
584 static char *MkNum(char *name,int def)
586 char num[20];
588 sprintf(num, "%d", def);
590 return(MkDef(name, num));