1 /****************************************************************************
2 * This module is based on Twm, but has been siginificantly modified
3 * by Rob Nation
4 *
5 * later modified for BowMan
6 * by Bo Yang
7 *
8 * modified slightly for AfterStep
9 * by Frank Fejes
10 *
11 * small modifications for textured backgrounds
12 * by Alfredo Kojima
13 ****************************************************************************/
14 /*****************************************************************************/
15 /** Copyright 1988 by Evans & Sutherland Computer Corporation, **/
16 /** Salt Lake City, Utah **/
17 /** Portions Copyright 1989 by the Massachusetts Institute of Technology **/
18 /** Cambridge, Massachusetts **/
19 /** **/
20 /** All Rights Reserved **/
21 /** **/
22 /** Permission to use, copy, modify, and distribute this software and **/
23 /** its documentation for any purpose and without fee is hereby **/
24 /** granted, provided that the above copyright notice appear in all **/
25 /** copies and that both that copyright notice and this permis- **/
26 /** sion notice appear in supporting documentation, and that the **/
27 /** names of Evans & Sutherland and M.I.T. not be used in advertising **/
28 /** in publicity pertaining to distribution of the software without **/
29 /** specific, written prior permission. **/
30 /** **/
31 /** EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD **/
32 /** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/
33 /** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND OR **/
34 /** M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/
35 /** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/
36 /** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/
37 /** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/
38 /** OR PERFORMANCE OF THIS SOFTWARE. **/
39 /*****************************************************************************/
40
41
42 /***********************************************************************
43 * AfterStep: WM with NEXTSTEP look and feel
44 ***********************************************************************/
45
46 #include "../configure.h"
47
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <signal.h>
51 #include <fcntl.h>
52 #include <string.h>
53 #include <unistd.h>
54 #include "afterstep.h"
55 #include "menus.h"
56 #include "misc.h"
57 #include "screen.h"
58 #include "parse.h"
59 #include <X11/Xproto.h>
60 #include <X11/Xatom.h>
61 /* need to get prototype for XrmUniqueQuark for XUniqueContext call */
62 #include <X11/Xresource.h>
63 #include <X11/Xutil.h>
64
65 #ifdef SHAPE
66 #include <X11/extensions/shape.h>
67 #endif /* SHAPE */
68
69 #if defined (sparc) && defined (SVR4)
70 /* Solaris has sysinfo instead of gethostname. */
71 #include <sys/systeminfo.h>
72 #endif
73
74 #define MAXHOSTNAME 255
75
76 #include "../version.h"
77
78 #ifdef ENABLE_TEXTURE
79 TextureInfo Textures; /* texture information */
80 #endif
81
82 ScreenInfo Scr; /* structures for the screen */
83 Display *dpy; /* which display are we talking to */
84 extern char *config_file;
85
86 XErrorHandler CatchRedirectError(Display *, XErrorEvent *);
87 XErrorHandler ASErrorHandler(Display *, XErrorEvent *);
88 void newhandler(int sig);
89 void InitModifiers(void);
90 void CreateCursors(void);
91 void NoisyExit(int);
92 void ChildDied(int nonsense);
93 void SaveDesktopState(void);
94
95 XContext ASContext; /* context for afterstep windows */
96 XContext MenuContext; /* context for afterstep menus */
97
98 XClassHint NoClass; /* for applications with no class */
99
100 int JunkX = 0, JunkY = 0;
101 Window JunkRoot, JunkChild; /* junk window */
102 unsigned int JunkWidth, JunkHeight, JunkBW, JunkDepth, JunkMask;
103
104 /* assorted gray bitmaps for decorative borders */
105 #define g_width 2
106 #define g_height 2
107 static char g_bits[] = {0x02, 0x01};
108
109 #define l_g_width 4
110 #define l_g_height 2
111 static char l_g_bits[] = {0x08, 0x02};
112 Bool debugging = False,PPosOverride;
113
114 #define s_g_width 4
115 #define s_g_height 4
116 static char s_g_bits[] = {0x01, 0x02, 0x04, 0x08};
117 char **g_argv;
118
119 #ifdef M4
120 int m4_enable; /* use m4? */
121 int m4_prefix; /* Do GNU m4 prefixing (-P) */
122 char m4_options[BUFSIZ]; /* Command line options to m4 */
123 char m4_prog[BUFSIZ]; /* Name of the m4 program */
124 int m4_default_quotes; /* Use default m4 quotes */
125 char m4_startquote[16]; /* Left quote characters for m4 */
126 char m4_endquote[16]; /* Right quote characters for m4 */
127 #endif
128
129 #ifndef NO_PAGER
130 extern Pixel PagerForeColor;
131 #endif
132
133 #ifdef SHAPE
134 int ShapeEventBase, ShapeErrorBase;
135 #endif
136
137 long isIconicState = 0;
138 extern XEvent Event;
139 Bool Restarting = False;
140 int fd_width, x_fd;
141 char *display_name = NULL;
142
143 /***********************************************************************
144 *
145 * Procedure:
146 * main - start of afterstep
147 *
148 ***********************************************************************
149 */
main(int argc,char ** argv)150 int main(int argc, char **argv)
151 {
152 unsigned long valuemask; /* mask for create windows */
153 XSetWindowAttributes attributes; /* attributes for create windows */
154 void InternUsefulAtoms (void);
155 void InitVariables(void);
156 void enterAlarm(int);
157 int i;
158 extern int x_fd;
159 int len;
160 char *display_string;
161 char message[255];
162 char num[10];
163
164 Bool single = False;
165 Bool option_error = FALSE;
166
167 #ifdef M4
168 /* Set the defaults for m4 processing */
169
170 m4_enable = TRUE;
171 m4_prefix = FALSE;
172 strcpy(m4_prog, "m4");
173 *m4_options = '\0';
174 m4_default_quotes = 1;
175 strcpy(m4_startquote, "`");
176 strcpy(m4_endquote, "'");
177 #endif
178
179 for (i = 1; i < argc; i++)
180 {
181 if (mystrncasecmp(argv[i],"-debug",6)==0)
182 debugging = True;
183 else if (mystrncasecmp(argv[i],"-s",2)==0)
184 {
185 single = True;
186 }
187 else if (mystrncasecmp(argv[i],"-d",2)==0)
188 {
189 if (++i >= argc)
190 usage();
191 display_name = argv[i];
192 }
193 else if (mystrncasecmp(argv[i],"-f",2)==0)
194 {
195 if (++i >= argc)
196 usage();
197 config_file = argv[i];
198 }
199 #ifdef M4
200 else if (mystrncasecmp(argv[i], "-no-m4", 6) == 0)
201 {
202 m4_enable = FALSE;
203 }
204 else if (mystrncasecmp(argv[i], "-m4-prefix", 10) == 0)
205 {
206 m4_prefix = TRUE;
207 }
208 else if (mystrncasecmp(argv[i],"-m4opt", 6) == 0)
209 {
210 if (++i < argc)
211 {
212 strcat(m4_options, argv[i]);
213 strcat(m4_options, " ");
214 }
215 }
216 else if (mystrncasecmp(argv[i], "-m4-squote", 6) == 0)
217 {
218 if (++i < argc)
219 {
220 strcpy(m4_startquote, argv[i]);
221 m4_default_quotes = 0;
222 }
223 }
224 else if (mystrncasecmp(argv[i], "-m4-equote", 6) == 0)
225 {
226 if (++i < argc)
227 {
228 strcpy(m4_endquote, argv[i]);
229 m4_default_quotes = 0;
230 }
231 }
232 else if (mystrncasecmp(argv[i], "-m4prog", 7) == 0)
233 {
234 if (++i < argc)
235 {
236 strcpy(m4_prog, argv[i]);
237 }
238 }
239 #endif
240 else if (mystrncasecmp(argv[i], "-version", 8) == 0)
241 {
242 fprintf(stderr, "AfterStep Version %s\n", VERSION);
243 }
244 else
245 {
246 fprintf(stderr, "afterstep: Unknown option: `%s'\n", argv[i]);
247 option_error = TRUE;
248 }
249 }
250
251 if (option_error)
252 {
253 usage();
254 }
255
256 g_argv = argv;
257
258 newhandler (SIGINT);
259 newhandler (SIGHUP);
260 newhandler (SIGQUIT);
261 newhandler (SIGTERM);
262 signal (SIGUSR1, Restart);
263
264 signal (SIGPIPE, DeadPipe);
265 signal(SIGALRM,enterAlarm);
266
267 ReapChildren();
268
269 if (!(dpy = XOpenDisplay(display_name)))
270 {
271 afterstep_err("can't open display %s", XDisplayName(display_name),
272 NULL,NULL);
273 exit (1);
274 }
275 x_fd = XConnectionNumber(dpy);
276
277 if (fcntl(x_fd, F_SETFD, 1) == -1)
278 {
279 afterstep_err("close-on-exec failed",NULL,NULL,NULL);
280 exit (1);
281 }
282 Scr.screen= DefaultScreen(dpy);
283 Scr.NumberOfScreens = ScreenCount(dpy);
284
285 if(!single)
286 {
287 for(i=0;i<Scr.NumberOfScreens;i++)
288 {
289 if(i!= Scr.screen)
290 {
291 sprintf(message,"%s -d %s",argv[0],XDisplayString(dpy));
292 len = strlen(message);
293 message[len-1] = 0;
294 sprintf(num,"%d",i);
295 strcat(message,num);
296 strcat(message," -s ");
297 if(debugging)
298 strcat(message," -debug");
299 strcat(message," -f ");
300 strcat(message,config_file);
301 strcat(message," &\n");
302 system(message);
303 }
304 }
305 }
306
307
308 /* Add a DISPLAY entry to the environment, incase we were started
309 * with afterstep -display term:0.0
310 */
311 len = strlen(XDisplayString(dpy));
312 display_string = safemalloc(len+10);
313 sprintf(display_string,"DISPLAY=%s",XDisplayString(dpy));
314 putenv(display_string);
315 /* Add a HOSTDISPLAY environment variable, which is the same as
316 * DISPLAY, unless display = :0.0 or unix:0.0, in which case the full
317 * host name will be used for ease in networking . */
318 if(strncmp(display_string,"DISPLAY=:",9)==0)
319 {
320 char client[MAXHOSTNAME], *rdisplay_string;
321 mygethostname(client,MAXHOSTNAME);
322 rdisplay_string = safemalloc(len+14 + strlen(client));
323 sprintf(rdisplay_string,"HOSTDISPLAY=%s:%s",client,&display_string[9]);
324 putenv(rdisplay_string);
325 }
326 else if(strncmp(display_string,"DISPLAY=unix:",13)==0)
327 {
328 char client[MAXHOSTNAME], *rdisplay_string;
329 mygethostname(client,MAXHOSTNAME);
330 rdisplay_string = safemalloc(len+14 + strlen(client));
331 sprintf(rdisplay_string,"HOSTDISPLAY=%s:%s",client,
332 &display_string[13]);
333 putenv(rdisplay_string);
334 }
335 else
336 {
337 char *rdisplay_string;
338 rdisplay_string = safemalloc(len+14);
339 sprintf(rdisplay_string,"HOSTDISPLAY=%s",XDisplayString(dpy));
340 putenv(rdisplay_string);
341 }
342
343 Scr.Root = RootWindow(dpy, Scr.screen);
344 if(Scr.Root == None)
345 {
346 afterstep_err("Screen %d is not a valid screen",(char *)Scr.screen,
347 NULL,NULL);
348 exit(1);
349 }
350
351 #ifdef SHAPE
352 XShapeQueryExtension(dpy, &ShapeEventBase, &ShapeErrorBase);
353 #endif /* SHAPE */
354
355 InternUsefulAtoms ();
356
357 /* Make sure property priority colors is empty */
358 XChangeProperty (dpy, Scr.Root, _XA_MIT_PRIORITY_COLORS,
359 XA_CARDINAL, 32, PropModeReplace, NULL, 0);
360
361 XSetErrorHandler((XErrorHandler)CatchRedirectError);
362 XSelectInput(dpy, Scr.Root,
363 LeaveWindowMask| EnterWindowMask | PropertyChangeMask |
364 SubstructureRedirectMask | /* SubstructureNotifyMask | */
365 KeyPressMask | ButtonPressMask | ButtonReleaseMask );
366 XSync(dpy, 0);
367
368 XSetErrorHandler((XErrorHandler)ASErrorHandler);
369
370 CreateCursors();
371 InitVariables();
372 initModules();
373 XGrabServer(dpy);
374
375 Scr.gray_bitmap =
376 XCreateBitmapFromData(dpy,Scr.Root,g_bits, g_width,g_height);
377
378 /* read config file, set up menus, colors, fonts */
379 #ifdef M4
380 MakeMenus(display_name, m4_options);
381 #else
382 MakeMenus(display_name, NULL);
383 #endif
384 if(Scr.d_depth<2)
385 {
386 Scr.gray_pixmap =
387 XCreatePixmapFromBitmapData(dpy,Scr.Root,g_bits, g_width,g_height,
388 Scr.StdColors.fore,Scr.StdColors.back,
389 Scr.d_depth);
390 Scr.light_gray_pixmap =
391 XCreatePixmapFromBitmapData(dpy,Scr.Root,l_g_bits,l_g_width,l_g_height,
392 Scr.StdColors.fore,Scr.StdColors.back,
393 Scr.d_depth);
394 Scr.sticky_gray_pixmap =
395 XCreatePixmapFromBitmapData(dpy,Scr.Root,s_g_bits,s_g_width,s_g_height,
396 Scr.StickyColors.fore,Scr.StickyColors.back,
397 Scr.d_depth);
398 }
399
400 /* create a window which will accept the keyboard focus when no other
401 windows have it */
402 attributes.event_mask = KeyPressMask|FocusChangeMask;
403 attributes.override_redirect = True;
404 Scr.NoFocusWin=XCreateWindow(dpy,Scr.Root,-10, -10, 10, 10, 0, 0,
405 InputOnly,CopyFromParent,
406 CWEventMask|CWOverrideRedirect,
407 &attributes);
408 XMapWindow(dpy, Scr.NoFocusWin);
409
410 XSetInputFocus (dpy, Scr.NoFocusWin, RevertToParent, CurrentTime);
411 Scr.TitleHeight=NS_TITLE_HEIGHT;
412
413 XSync(dpy, 0);
414 if(debugging)
415 XSynchronize(dpy,1);
416
417 Scr.SizeStringWidth = XTextWidth (Scr.StdFont.font,
418 " +8888 x +8888 ", 15);
419 attributes.border_pixel = Scr.StdColors.fore;
420 attributes.background_pixel = Scr.StdColors.back;
421 attributes.bit_gravity = NorthWestGravity;
422 valuemask = (CWBorderPixel | CWBackPixel | CWBitGravity);
423 Scr.SizeWindow = XCreateWindow (dpy, Scr.Root,
424 (DisplayWidth(dpy, Scr.screen) -
425 (unsigned int)(Scr.SizeStringWidth +
426 SIZE_HINDENT*2))/2,
427 (DisplayHeight(dpy, Scr.screen) -
428 (unsigned int) (Scr.StdFont.height +
429 SIZE_VINDENT*2))/2,
430 (unsigned int)(Scr.SizeStringWidth +
431 SIZE_HINDENT*2),
432 (unsigned int) (Scr.StdFont.height +
433 SIZE_VINDENT*2),
434 (unsigned int) 0, 0,
435 (unsigned int) CopyFromParent,
436 (Visual *) CopyFromParent,
437 valuemask, &attributes);
438
439 #ifndef NON_VIRTUAL
440 initPanFrames();
441 #endif
442 CaptureAllWindows();
443 #ifndef NON_VIRTUAL
444 checkPanFrames();
445 #endif
446 XUngrabServer(dpy);
447 MoveResizeViewPortIndicator();
448 fd_width = GetFdWidth();
449
450
451 if(Restarting)
452 {
453 if(Scr.RestartFunction != NULL)
454 ExecuteFunction(F_FUNCTION,NULL,None,NULL,&Event,C_ROOT,0,0,
455 0,0,Scr.RestartFunction,-1);
456 }
457 else
458 {
459 if(Scr.InitFunction != NULL)
460 ExecuteFunction(F_FUNCTION,NULL,None,NULL,&Event,C_ROOT,0,0,
461 0,0,Scr.InitFunction,-1);
462 }
463
464 XDefineCursor(dpy, Scr.Root, Scr.ASCursors[DEFAULT]);
465 HandleEvents();
466 return 0;
467 }
468
469 /***********************************************************************
470 *
471 * Procedure:
472 * CaptureAllWindows
473 *
474 * Decorates all windows at start-up
475 *
476 ***********************************************************************/
477
CaptureAllWindows(void)478 void CaptureAllWindows(void)
479 {
480 int i,j;
481 unsigned int nchildren;
482 Window root, parent, *children;
483
484 PPosOverride = TRUE;
485
486 if(!XQueryTree(dpy, Scr.Root, &root, &parent, &children, &nchildren))
487 return;
488
489 /*
490 * weed out icon windows
491 */
492 for (i = 0; i < nchildren; i++)
493 {
494 if (children[i])
495 {
496 XWMHints *wmhintsp = XGetWMHints (dpy, children[i]);
497 if (wmhintsp)
498 {
499 if (wmhintsp->flags & IconWindowHint)
500 {
501 for (j = 0; j < nchildren; j++)
502 {
503 if (children[j] == wmhintsp->icon_window)
504 {
505 children[j] = None;
506 break;
507 }
508 }
509 }
510 XFree ((char *) wmhintsp);
511 }
512 }
513 }
514 /*
515 * map all of the non-override windows
516 */
517
518 for (i = 0; i < nchildren; i++)
519 {
520 if (children[i] && MappedNotOverride(children[i]))
521 {
522 XUnmapWindow(dpy, children[i]);
523 Event.xmaprequest.window = children[i];
524 HandleMapRequest ();
525 }
526 }
527
528 isIconicState = DontCareState;
529
530 if(nchildren > 0)
531 XFree((char *)children);
532
533 /* after the windows already on the screen are in place,
534 * don't use PPosition */
535 PPosOverride = FALSE;
536 }
537
538 /***********************************************************************
539 *
540 * Procedure:
541 * MappedNotOverride - checks to see if we should really
542 * put a afterstep frame on the window
543 *
544 * Returned Value:
545 * TRUE - go ahead and frame the window
546 * FALSE - don't frame the window
547 *
548 * Inputs:
549 * w - the window to check
550 *
551 ***********************************************************************/
552
MappedNotOverride(Window w)553 int MappedNotOverride(Window w)
554 {
555 XWindowAttributes wa;
556 Atom atype;
557 int aformat;
558 unsigned long nitems, bytes_remain;
559 unsigned char *prop;
560
561 isIconicState = DontCareState;
562
563 if(!XGetWindowAttributes(dpy, w, &wa))
564 return False;
565
566 if(XGetWindowProperty(dpy,w,_XA_WM_STATE,0L,3L,False,_XA_WM_STATE,
567 &atype,&aformat,&nitems,&bytes_remain,&prop)==Success)
568 {
569 if(prop != NULL)
570 {
571 isIconicState = *(long *)prop;
572 XFree(prop);
573 }
574 }
575 #ifndef NO_PAGER
576 if(w == Scr.Pager_w)
577 return True;
578 #endif
579 return (((isIconicState == IconicState)||(wa.map_state != IsUnmapped)) &&
580 (wa.override_redirect != True));
581 }
582
583
584 /***********************************************************************
585 *
586 * Procedure:
587 * InternUsefulAtoms:
588 * Dont really know what it does
589 *
590 ***********************************************************************
591 */
592 Atom _XA_MIT_PRIORITY_COLORS;
593 Atom _XA_WM_CHANGE_STATE;
594 Atom _XA_WM_STATE;
595 Atom _XA_WM_COLORMAP_WINDOWS;
596 Atom _XA_WM_PROTOCOLS;
597 Atom _XA_WM_TAKE_FOCUS;
598 Atom _XA_WM_DELETE_WINDOW;
599 Atom _XA_WM_DESKTOP;
600 Atom _XA_MwmAtom;
601
InternUsefulAtoms(void)602 void InternUsefulAtoms (void)
603 {
604 /*
605 * Create priority colors if necessary.
606 */
607 _XA_MIT_PRIORITY_COLORS = XInternAtom(dpy, "_MIT_PRIORITY_COLORS", False);
608 _XA_WM_CHANGE_STATE = XInternAtom (dpy, "WM_CHANGE_STATE", False);
609 _XA_WM_STATE = XInternAtom (dpy, "WM_STATE", False);
610 _XA_WM_COLORMAP_WINDOWS = XInternAtom (dpy, "WM_COLORMAP_WINDOWS", False);
611 _XA_WM_PROTOCOLS = XInternAtom (dpy, "WM_PROTOCOLS", False);
612 _XA_WM_TAKE_FOCUS = XInternAtom (dpy, "WM_TAKE_FOCUS", False);
613 _XA_WM_DELETE_WINDOW = XInternAtom (dpy, "WM_DELETE_WINDOW", False);
614 _XA_WM_DESKTOP = XInternAtom (dpy, "WM_DESKTOP", False);
615 _XA_MwmAtom=XInternAtom(dpy,"_MOTIF_WM_HINTS",False);
616 return;
617 }
618
619 /***********************************************************************
620 *
621 * Procedure:
622 * newhandler: Installs new signal handler
623 *
624 ************************************************************************/
newhandler(int sig)625 void newhandler(int sig)
626 {
627 if (signal (sig, SIG_IGN) != SIG_IGN)
628 signal (sig, SigDone);
629 }
630
631
632 /*************************************************************************
633 * Restart on a signal
634 ************************************************************************/
Restart(int nonsense)635 void Restart(int nonsense)
636 {
637 Done(1, *g_argv);
638 SIGNAL_RETURN;
639 }
640
641 /***********************************************************************
642 *
643 * Procedure:
644 * CreateCursors - Loads afterstep cursors
645 *
646 ***********************************************************************
647 */
CreateCursors(void)648 void CreateCursors(void)
649 {
650 /* define cursors */
651 Scr.ASCursors[POSITION] = XCreateFontCursor(dpy,XC_left_ptr);
652 /* Scr.ASCursors[DEFAULT] = XCreateFontCursor(dpy, XC_top_left_arrow); */
653 Scr.ASCursors[DEFAULT] = XCreateFontCursor(dpy,XC_left_ptr);
654 Scr.ASCursors[SYS] = XCreateFontCursor(dpy, XC_left_ptr);
655 Scr.ASCursors[TITLE_CURSOR] = XCreateFontCursor(dpy, XC_left_ptr);
656 Scr.ASCursors[MOVE] = XCreateFontCursor(dpy, XC_fleur);
657 Scr.ASCursors[MENU] = XCreateFontCursor(dpy, XC_left_ptr);
658 Scr.ASCursors[WAIT] = XCreateFontCursor(dpy, XC_watch);
659 Scr.ASCursors[SELECT] = XCreateFontCursor(dpy, XC_dot);
660 Scr.ASCursors[DESTROY] = XCreateFontCursor(dpy, XC_pirate);
661 Scr.ASCursors[LEFT] = XCreateFontCursor(dpy, XC_left_side);
662 Scr.ASCursors[RIGHT] = XCreateFontCursor(dpy, XC_right_side);
663 Scr.ASCursors[TOP] = XCreateFontCursor(dpy, XC_top_side);
664 Scr.ASCursors[BOTTOM] = XCreateFontCursor(dpy, XC_bottom_side);
665 Scr.ASCursors[TOP_LEFT] = XCreateFontCursor(dpy,XC_top_left_corner);
666 Scr.ASCursors[TOP_RIGHT] = XCreateFontCursor(dpy,XC_top_right_corner);
667 Scr.ASCursors[BOTTOM_LEFT] = XCreateFontCursor(dpy,XC_bottom_left_corner);
668 Scr.ASCursors[BOTTOM_RIGHT] =XCreateFontCursor(dpy,XC_bottom_right_corner);
669 }
670
671 /***********************************************************************
672 *
673 * Procedure:
674 * InitVariables - initialize afterstep variables
675 *
676 ************************************************************************/
InitVariables(void)677 void InitVariables(void)
678 {
679 ASContext = XUniqueContext();
680 MenuContext = XUniqueContext();
681 NoClass.res_name = NoName;
682 NoClass.res_class = NoName;
683
684 Scr.d_depth = DefaultDepth(dpy, Scr.screen);
685 Scr.ASRoot.w = Scr.Root;
686 Scr.ASRoot.next = 0;
687 XGetWindowAttributes(dpy,Scr.Root,&(Scr.ASRoot.attr));
688 Scr.root_pushes = 0;
689 Scr.pushed_window = &Scr.ASRoot;
690 Scr.ASRoot.number_cmap_windows = 0;
691
692
693 Scr.MyDisplayWidth = DisplayWidth(dpy, Scr.screen);
694 Scr.MyDisplayHeight = DisplayHeight(dpy, Scr.screen);
695
696 Scr.NoBoundaryWidth = 1;
697 Scr.BoundaryWidth = BOUNDARY_WIDTH;
698 Scr.CornerWidth = CORNER_WIDTH;
699 Scr.Hilite = NULL;
700 Scr.Focus = NULL;
701 Scr.Ungrabbed = NULL;
702
703 Scr.StdFont.font = NULL;
704 Scr.StdFont.name = "fixed";
705 Scr.WindowFont.name = "fixed";
706
707 Scr.VScale = 32;
708 #ifndef NON_VIRTUAL
709 Scr.VxMax = 3;
710 Scr.VyMax = 3;
711 #else
712 Scr.VxMax = 1;
713 Scr.VyMax = 1;
714 #endif
715 Scr.Vx = Scr.Vy = 0;
716
717 /* Sets the current desktop number to zero */
718 /* Multiple desks are available even in non-virtual
719 * compilations */
720 {
721 Atom atype;
722 int aformat;
723 unsigned long nitems, bytes_remain;
724 unsigned char *prop;
725
726 Scr.CurrentDesk = 0;
727 if ((XGetWindowProperty(dpy, Scr.Root, _XA_WM_DESKTOP, 0L, 1L, True,
728 _XA_WM_DESKTOP, &atype, &aformat, &nitems,
729 &bytes_remain, &prop))==Success)
730 {
731 if(prop != NULL)
732 {
733 Restarting = True;
734 Scr.CurrentDesk = *(unsigned long *)prop;
735 }
736 }
737 }
738
739 Scr.EdgeScrollX = Scr.EdgeScrollY = -100000;
740 Scr.ScrollResistance = Scr.MoveResistance = 0;
741 Scr.OpaqueSize = 5;
742 Scr.ClickTime = 150;
743 Scr.AutoRaiseDelay = 0;
744 Scr.RaiseButtons = 0;
745
746 /* set major operating modes */
747 Scr.flags = 0;
748 Scr.NumBoxes = 0;
749
750 Scr.randomx = Scr.randomy = 0;
751 Scr.buttons2grab = 7;
752
753 Scr.next_focus_sequence = 0;
754
755 #ifndef NO_PAGER
756 Scr.PagerFont.name = NULL;
757 Scr.PagerFont.height = 0;
758 Scr.PagerFont.y = 0;
759 Scr.ASPager = (ASWindow *)0;
760 Scr.Pager_w = None;
761 Scr.CPagerWin = None;
762 #endif
763 Scr.InitFunction = NULL;
764 Scr.RestartFunction = NULL;
765
766 InitModifiers();
767
768 return;
769 }
770
771 /* Read the server modifier mapping */
772
InitModifiers(void)773 void InitModifiers(void)
774 {
775 int m, i, knl;
776 char* kn;
777 KeySym ks;
778 KeyCode kc, *kp;
779 unsigned lockmask, *mp;
780 XModifierKeymap* mm = XGetModifierMapping(dpy);
781 lockmask = LockMask;
782 if (mm)
783 {
784 kp = mm->modifiermap;
785 for (m = 0; m < 8; m++)
786 {
787 for (i = 0; i < mm->max_keypermod; i++)
788 {
789 if ((kc = *kp++) &&
790 ((ks = XkbKeycodeToKeysym(dpy, kc, 0, 0)) != NoSymbol))
791 {
792 kn = XKeysymToString(ks);
793 knl = strlen(kn);
794 if ((knl > 6) && (strcasecmp(kn + knl - 4, "lock") == 0))
795 lockmask |= (1 << m);
796 }
797 }
798 }
799 XFreeModifiermap(mm);
800 }
801 lockmask &= ~(ShiftMask | ControlMask); /* forget shift & control locks */
802 Scr.nonlock_mods = ((ShiftMask | ControlMask | Mod1Mask | Mod2Mask
803 | Mod3Mask| Mod4Mask| Mod5Mask) & ~lockmask);
804
805 if (Scr.lock_mods == NULL)
806 Scr.lock_mods = (unsigned*) safemalloc(256 * sizeof(unsigned));
807 mp = Scr.lock_mods;
808 for (m = 0, i = 1; i < 256; i++)
809 {
810 if ((i & lockmask) > m)
811 m = *mp++ = (i & lockmask);
812 }
813 *mp = 0;
814 }
815
816
817 /***********************************************************************
818 *
819 * Procedure:
820 * Reborder - Removes afterstep border windows
821 *
822 ************************************************************************/
823
Reborder_unmap(ASWindow * t)824 void Reborder_unmap(ASWindow* t)
825 {
826 if (t->next) Reborder_unmap(t->next);
827 XUnmapWindow(dpy, t->frame);
828 RestoreWithdrawnLocation(t, True);
829 XDestroyWindow(dpy, t->frame);
830 }
831
Reborder(void)832 void Reborder(void)
833 {
834 ASWindow *tmp; /* temp afterstep window structure */
835 int i;
836 extern unsigned PopupCount;
837 extern MenuRoot *PopupTable[MAXPOPUPS];
838
839 /* put a border back around all windows */
840 XGrabServer (dpy);
841 #ifndef NO_PAGER
842 if(Scr.Pager_w != None)
843 XDestroyWindow(dpy,Scr.Pager_w);
844 #endif
845
846 InstallWindowColormaps (&Scr.ASRoot); /* force reinstall */
847 Reborder_unmap(Scr.ASRoot.next);
848
849 for(i=0;i<PopupCount;i++)
850 if(PopupTable[i]->w != None)
851 XDestroyWindow(dpy,PopupTable[i]->w);
852 XUngrabServer (dpy);
853 XSetInputFocus (dpy, PointerRoot, RevertToPointerRoot,CurrentTime);
854 XSync(dpy,0);
855
856 }
857
858 /***********************************************************************
859 *
860 * Procedure: NoisyExit
861 * Print error messages and die. (segmentation violation)
862 *
863 **********************************************************************/
NoisyExit(int nonsense)864 void NoisyExit(int nonsense)
865 {
866 XErrorEvent event;
867
868 afterstep_err("Seg Fault",NULL,NULL,NULL);
869 event.error_code = 0;
870 event.request_code = 0;
871 ASErrorHandler(dpy, &event);
872
873 /* Attempt to do a re-start of afterstep */
874 Done(0,NULL);
875 }
876
877
878
879
880
881 /***********************************************************************
882 *
883 * Procedure:
884 * Done - cleanup and exit afterstep
885 *
886 ***********************************************************************
887 */
SigDone(int nonsense)888 void SigDone(int nonsense)
889 {
890 Done(0, NULL);
891 SIGNAL_RETURN;
892 }
893
Done(int restart,char * command)894 void Done(int restart, char *command)
895 {
896 #ifndef NON_VIRTUAL
897 MoveViewport(0,0,False);
898 #endif
899
900 /* Close all my pipes */
901 ClosePipes();
902
903 Reborder ();
904
905 #ifdef M4
906 if (m4_enable)
907 {
908 extern char *afterstep_file;
909
910 /* With m4 processing, a temporary file was created to hold the
911 processed file. Delete the file now because we don't need it
912 any more. It will be created again during restart. */
913 unlink(afterstep_file);
914 }
915 #endif
916
917 if(restart)
918 {
919 SaveDesktopState(); /* I wonder why ... */
920
921 /* Really make sure that the connection is closed and cleared! */
922 XSelectInput(dpy, Scr.Root, 0 );
923 XSync(dpy, 0);
924 XCloseDisplay(dpy);
925
926 {
927 char *my_argv[10];
928 int i,done,j;
929
930 i=0;
931 j=0;
932 done = 0;
933 while((g_argv[j] != NULL)&&(i<8))
934 {
935 if(strcmp(g_argv[j],"-s")!=0)
936 {
937 my_argv[i] = g_argv[j];
938 i++;
939 j++;
940 }
941 else
942 j++;
943 }
944 if(strstr(command,"afterstep")!= NULL)
945 my_argv[i++] = "-s";
946 while(i<10)
947 my_argv[i++] = NULL;
948
949 /* really need to destroy all windows, explicitly,
950 * not sleep, but this is adequate for now */
951 sleep(1);
952 ReapChildren();
953 execvp(command,my_argv);
954 }
955 fprintf(stderr, "AfterStep: Call of '%s' failed!!!!\n",command);
956 execvp(g_argv[0], g_argv); /* that _should_ work */
957 fprintf(stderr, "AfterStep: Call of '%s' failed!!!!\n", g_argv[0]);
958 }
959 else
960 {
961 XCloseDisplay(dpy);
962 exit(0);
963 }
964 }
965
966 /***********************************************************************
967 *
968 * Procedure:
969 * CatchRedirectError - Figures out if there's another WM running
970 *
971 ************************************************************************/
CatchRedirectError(Display * dpy,XErrorEvent * event)972 XErrorHandler CatchRedirectError(Display *dpy, XErrorEvent *event)
973 {
974 afterstep_err("another WM is running",NULL,NULL,NULL);
975 exit(1);
976 }
977
978
979 /***********************************************************************
980 *
981 * Procedure:
982 * ASErrorHandler - displays info on internal errors
983 *
984 ************************************************************************/
ASErrorHandler(Display * dpy,XErrorEvent * event)985 XErrorHandler ASErrorHandler(Display *dpy, XErrorEvent *event)
986 {
987 extern int last_event_type;
988
989 /* some errors are acceptable, mostly they're caused by
990 * trying to update a lost window */
991 if((event->error_code == BadWindow)||(event->request_code == X_GetGeometry)||
992 (event->error_code==BadDrawable)||(event->request_code==X_SetInputFocus)||
993 (event->request_code==X_GrabButton)||
994 (event->request_code==X_ChangeWindowAttributes)||
995 (event->request_code == X_InstallColormap))
996 return 0 ;
997
998
999 afterstep_err("internal error",NULL,NULL,NULL);
1000 fprintf(stderr," Request %d, Error %d\n", event->request_code,
1001 event->error_code);
1002 fprintf(stderr," EventType: %d",last_event_type);
1003 fprintf(stderr,"\n");
1004 return 0;
1005 }
1006
afterstep_err(char * message,char * arg1,char * arg2,char * arg3)1007 void afterstep_err(char *message, char *arg1, char *arg2, char *arg3)
1008 {
1009 fprintf(stderr,"AfterStep: ");
1010 fprintf(stderr,message,arg1,arg2,arg3);
1011 fprintf(stderr,"\n");
1012 }
1013
usage(void)1014 void usage(void)
1015 {
1016 #ifdef M4
1017 #define USAGE "AfterStep Ver %s\n\nusage: afterstep [-d dpy] [-debug] [-f config_file] [-s] [-no-m4] [-m4-prefix] [-m4opt option] [-m4-squote squote] [-m4-equote equote] [-m4prog m4prog]\n"
1018 #else
1019 #define USAGE "AfterStep Ver %s\n\nusage: afterstep [-d dpy] [-debug] [-f config_file] [-s]\n"
1020 #endif
1021
1022 fprintf(stderr,USAGE,VERSION);
1023
1024 }
1025
1026
1027
1028
1029 #ifndef NON_VIRTUAL
1030 /* the root window is surrounded by four window slices, which are InputOnly.
1031 * So you can see 'through' them, but they eat the input. An EnterEvent in
1032 * one of these windows causes a Paging. The windows have the according cursor
1033 * pointing in the pan direction or are hidden if there is no more panning
1034 * in that direction. This is mostly intended to get a panning even atop
1035 * of Motif applictions, which does not work yet. It seems Motif windows
1036 * eat all mouse events.
1037 *
1038 * Hermann Dunkel, HEDU, dunkel@cul-ipn.uni-kiel.de 1/94
1039 */
1040
1041 /***************************************************************************
1042 * checkPanFrames hides PanFrames if they are on the very border of the
1043 * VIRTUELL screen and EdgeWrap for that direction is off.
1044 * (A special cursor for the EdgeWrap border could be nice) HEDU
1045 ****************************************************************************/
checkPanFrames(void)1046 void checkPanFrames(void)
1047 {
1048 extern Bool DoHandlePageing;
1049 int wrapX = (Scr.flags & EdgeWrapX);
1050 int wrapY = (Scr.flags & EdgeWrapY);
1051
1052 /* Remove Pan frames if paging by edge-scroll is permanently or
1053 * temporarily disabled */
1054 if((Scr.EdgeScrollY == 0)||(!DoHandlePageing))
1055 {
1056 XUnmapWindow(dpy,Scr.PanFrameTop.win);
1057 Scr.PanFrameTop.isMapped=False;
1058 XUnmapWindow (dpy,Scr.PanFrameBottom.win);
1059 Scr.PanFrameBottom.isMapped=False;
1060 }
1061 if((Scr.EdgeScrollX == 0)||(!DoHandlePageing))
1062 {
1063 XUnmapWindow(dpy,Scr.PanFrameLeft.win);
1064 Scr.PanFrameLeft.isMapped=False;
1065 XUnmapWindow (dpy,Scr.PanFrameRight.win);
1066 Scr.PanFrameRight.isMapped=False;
1067 }
1068 if(((Scr.EdgeScrollX == 0)&&(Scr.EdgeScrollY == 0))||(!DoHandlePageing))
1069 return;
1070
1071 /* LEFT, hide only if EdgeWrap is off */
1072 if (Scr.Vx==0 && Scr.PanFrameLeft.isMapped && (!wrapX))
1073 {
1074 XUnmapWindow(dpy,Scr.PanFrameLeft.win);
1075 Scr.PanFrameLeft.isMapped=False;
1076 }
1077 else if (Scr.Vx > 0 && Scr.PanFrameLeft.isMapped==False)
1078 {
1079 XMapRaised(dpy,Scr.PanFrameLeft.win);
1080 Scr.PanFrameLeft.isMapped=True;
1081 }
1082 /* RIGHT, hide only if EdgeWrap is off */
1083 if (Scr.Vx == Scr.VxMax && Scr.PanFrameRight.isMapped && (!wrapX))
1084 {
1085 XUnmapWindow (dpy,Scr.PanFrameRight.win);
1086 Scr.PanFrameRight.isMapped=False;
1087 }
1088 else if (Scr.Vx < Scr.VxMax && Scr.PanFrameRight.isMapped==False)
1089 {
1090 XMapRaised(dpy,Scr.PanFrameRight.win);
1091 Scr.PanFrameRight.isMapped=True;
1092 }
1093 /* TOP, hide only if EdgeWrap is off */
1094 if (Scr.Vy==0 && Scr.PanFrameTop.isMapped && (!wrapY))
1095 {
1096 XUnmapWindow(dpy,Scr.PanFrameTop.win);
1097 Scr.PanFrameTop.isMapped=False;
1098 }
1099 else if (Scr.Vy > 0 && Scr.PanFrameTop.isMapped==False)
1100 {
1101 XMapRaised(dpy,Scr.PanFrameTop.win);
1102 Scr.PanFrameTop.isMapped=True;
1103 }
1104 /* BOTTOM, hide only if EdgeWrap is off */
1105 if (Scr.Vy == Scr.VyMax && Scr.PanFrameBottom.isMapped && (!wrapY))
1106 {
1107 XUnmapWindow (dpy,Scr.PanFrameBottom.win);
1108 Scr.PanFrameBottom.isMapped=False;
1109 }
1110 else if (Scr.Vy < Scr.VyMax && Scr.PanFrameBottom.isMapped==False)
1111 {
1112 XMapRaised(dpy,Scr.PanFrameBottom.win);
1113 Scr.PanFrameBottom.isMapped=True;
1114 }
1115 }
1116
1117 /****************************************************************************
1118 *
1119 * Gotta make sure these things are on top of everything else, or they
1120 * don't work!
1121 *
1122 ***************************************************************************/
raisePanFrames(void)1123 void raisePanFrames(void)
1124 {
1125 if (Scr.PanFrameTop.isMapped) XRaiseWindow(dpy,Scr.PanFrameTop.win);
1126 if (Scr.PanFrameLeft.isMapped) XRaiseWindow(dpy,Scr.PanFrameLeft.win);
1127 if (Scr.PanFrameRight.isMapped) XRaiseWindow(dpy,Scr.PanFrameRight.win);
1128 if (Scr.PanFrameBottom.isMapped) XRaiseWindow(dpy,Scr.PanFrameBottom.win);
1129 }
1130
1131 /****************************************************************************
1132 *
1133 * Creates the windows for edge-scrolling
1134 *
1135 ****************************************************************************/
initPanFrames()1136 void initPanFrames()
1137 {
1138 XSetWindowAttributes attributes; /* attributes for create */
1139 unsigned long valuemask;
1140
1141 attributes.event_mask = (EnterWindowMask | LeaveWindowMask |
1142 VisibilityChangeMask);
1143 valuemask= (CWEventMask | CWCursor );
1144
1145 attributes.cursor = Scr.ASCursors[TOP];
1146 Scr.PanFrameTop.win =
1147 XCreateWindow (dpy, Scr.Root,
1148 0,0,
1149 Scr.MyDisplayWidth,PAN_FRAME_THICKNESS,
1150 0, /* no border */
1151 CopyFromParent, InputOnly,
1152 CopyFromParent,
1153 valuemask, &attributes);
1154 attributes.cursor = Scr.ASCursors[LEFT];
1155 Scr.PanFrameLeft.win =
1156 XCreateWindow (dpy, Scr.Root,
1157 0,PAN_FRAME_THICKNESS,
1158 PAN_FRAME_THICKNESS,
1159 Scr.MyDisplayHeight-2*PAN_FRAME_THICKNESS,
1160 0, /* no border */
1161 CopyFromParent, InputOnly, CopyFromParent,
1162 valuemask, &attributes);
1163 attributes.cursor = Scr.ASCursors[RIGHT];
1164 Scr.PanFrameRight.win =
1165 XCreateWindow (dpy, Scr.Root,
1166 Scr.MyDisplayWidth-PAN_FRAME_THICKNESS,PAN_FRAME_THICKNESS,
1167 PAN_FRAME_THICKNESS,
1168 Scr.MyDisplayHeight-2*PAN_FRAME_THICKNESS,
1169 0, /* no border */
1170 CopyFromParent, InputOnly, CopyFromParent,
1171 valuemask, &attributes);
1172 attributes.cursor = Scr.ASCursors[BOTTOM];
1173 Scr.PanFrameBottom.win =
1174 XCreateWindow (dpy, Scr.Root,
1175 0,Scr.MyDisplayHeight-PAN_FRAME_THICKNESS,
1176 Scr.MyDisplayWidth,PAN_FRAME_THICKNESS,
1177 0, /* no border */
1178 CopyFromParent, InputOnly, CopyFromParent,
1179 valuemask, &attributes);
1180 Scr.PanFrameTop.isMapped=Scr.PanFrameLeft.isMapped=
1181 Scr.PanFrameRight.isMapped= Scr.PanFrameBottom.isMapped=False;
1182
1183 Scr.usePanFrames=True;
1184
1185 }
1186 #endif /* NON_VIRTUAL */
1187
1188 /****************************************************************************
1189 *
1190 * Save Desktop State
1191 *
1192 ****************************************************************************/
SaveDesktopState()1193 void SaveDesktopState()
1194 {
1195 ASWindow *t;
1196 unsigned long data[1];
1197
1198 for (t = Scr.ASRoot.next; t != NULL; t = t->next)
1199 {
1200 data[0] = (unsigned long) t->Desk;
1201 XChangeProperty (dpy, t->w, _XA_WM_DESKTOP, _XA_WM_DESKTOP, 32,
1202 PropModeReplace, (unsigned char *) data, 1);
1203 }
1204
1205 data[0] = (unsigned long) Scr.CurrentDesk;
1206 XChangeProperty (dpy, Scr.Root, _XA_WM_DESKTOP, _XA_WM_DESKTOP, 32,
1207 PropModeReplace, (unsigned char *) data, 1);
1208
1209 XSync(dpy, 0);
1210 }
1211
1212
1213