1 /* Copyright (c) 1994-1996 David Hogan, see README for licence details */
2 
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <errno.h>
6 
7 #include <X11/X.h>
8 #include <X11/Xos.h>
9 #include <X11/Xlib.h>
10 #include <X11/Xutil.h>
11 #include <X11/Xatom.h>
12 #include <X11/extensions/shape.h>
13 #include <X11/cursorfont.h>
14 
15 #include "dat.h"
16 #include "fns.h"
17 
18 Display *dpy;
19 ScreenInfo *screens;
20 int initting;
21 XFontStruct *font;
22 char **myargv;
23 char *shell;
24 Bool shape;
25 int num_screens;
26 
27 Atom exit_larswm;
28 Atom restart_larswm;
29 Atom bartext_larswm;
30 
31 Atom wm_state;
32 Atom wm_change_state;
33 Atom wm_protocols;
34 Atom wm_delete;
35 Atom wm_colormaps;
36 
37 void
usage(void)38 usage (void)
39 {
40   fprintf (stderr, "%s\n", VERSION);
41   fprintf (stderr,
42 	   "usage: larswm [-display display] [-f file] [-defaults] [-v]\n");
43   exit (1);
44 }
45 
46 int
main(int argc,char ** argv)47 main (int argc, char **argv)
48 {
49   int i;
50   int shape_event, dummy;
51   char rcname[512];
52   char *display_string = "";
53   char *rc_file;
54 
55   rc_file = getenv ("HOME");
56 
57   if (rc_file)
58     {
59       strncpy (rcname, rc_file, sizeof (rcname) - 11);
60       strcat (rcname, "/.larswmrc");
61       rc_file = rcname;
62     }
63 
64   myargv = argv;
65   font = 0;
66 
67   for (i = 1; i < argc; i++)
68     {
69       if (strcmp (argv[i], "-f") == 0 && i + 1 < argc)
70 	{
71 	  rc_file = argv[++i];
72 	}
73       else if (strcmp (argv[i], "-display") == 0 && i + 1 < argc)
74 	{
75 	  display_string = argv[++i];
76 	}
77       else if (strcmp (argv[i], "-defaults") == 0)
78 	{
79 	  set_defaults ();
80 	  dump_prefs ();
81 	  exit (0);
82 	}
83       else if (strcmp (argv[i], "-v") == 0)
84 	{
85 	  fprintf (stderr, "%s\n", VERSION);
86 	  exit (0);
87 	}
88       else
89 	{
90 	  usage ();
91 	}
92     }
93 
94   shell = (char *) getenv ("SHELL");
95 
96   if (shell == NULL)
97     shell = DEFSHELL;
98 
99   dpy = XOpenDisplay (display_string);
100 
101   if (dpy == 0)
102     fatal ("can not open display");
103 
104   initting = 1;
105 
106   XSetErrorHandler (handler);
107 
108   exit_larswm = XInternAtom (dpy, "LARSWM_EXIT", False);
109   restart_larswm = XInternAtom (dpy, "LARSWM_RESTART", False);
110   bartext_larswm = XInternAtom (dpy, "LARSWM_BARTEXT", False);
111 
112   wm_state = XInternAtom (dpy, "WM_STATE", False);
113   wm_change_state = XInternAtom (dpy, "WM_CHANGE_STATE", False);
114   wm_protocols = XInternAtom (dpy, "WM_PROTOCOLS", False);
115   wm_delete = XInternAtom (dpy, "WM_DELETE_WINDOW", False);
116   wm_colormaps = XInternAtom (dpy, "WM_COLORMAP_WINDOWS", False);
117 
118   XrmInitialize ();
119   load_prefs (rc_file);
120 
121   if (prefs.fname != 0)
122     {
123       if ((font = XLoadQueryFont (dpy, prefs.fname)) == 0)
124 	fprintf (stderr, "larswm: warning: can't load font %s\n",
125 		 prefs.fname);
126     }
127 
128   if (font == 0)
129     {
130       prefs.fname = "fixed";
131 
132       if ((font = XLoadQueryFont (dpy, prefs.fname)) == 0)
133 	fatal ("can not find fixed font");
134     }
135 
136   shape = XShapeQueryExtension (dpy, &shape_event, &dummy);
137   num_screens = ScreenCount (dpy);
138 
139   if (num_screens > MAXSCREENS)
140     {
141       fprintf (stderr, "larswm was compiled with support for %d screens.\n",
142 	       MAXSCREENS);
143       fprintf (stderr,
144 	       "please recompile with MAXSCREENS set to at least %d screens.\n",
145 	       num_screens);
146       exit (1);
147     }
148 
149   screens = (ScreenInfo *) malloc (sizeof (ScreenInfo) * num_screens);
150 
151   for (i = 0; i < num_screens; i++)
152     initscreen (&screens[i], i);
153 
154   XSync (dpy, False);
155   initting = 0;
156 
157   nofocus ();
158 
159   for (i = 0; i < num_screens; i++)
160     scanwins (&screens[i]);
161 
162   initkeys (0);
163 
164   XSync (dpy, False);
165   mainloop (shape_event);
166 
167   exit (0);
168 }
169 
170 void
initscreen(ScreenInfo * s,int i)171 initscreen (ScreenInfo * s, int i)
172 {
173   char *ds, *colon, *dot1;
174   unsigned long mask;
175   XGCValues gv;
176   int t;
177 
178   s->num = i;
179   s->root = RootWindow (dpy, i);
180   s->def_cmap = DefaultColormap (dpy, i);
181   s->min_cmaps = MinCmapsOfScreen (ScreenOfDisplay (dpy, i));
182   s->tile_height = s->res_height = DisplayHeight (dpy, s->num);
183 
184   ds = DisplayString (dpy);
185 
186   strcpy (s->display, "DISPLAY=");
187   strcat (s->display, ds);
188 
189   colon = rindex (ds, ':');
190 
191   if (colon && num_screens > 1)
192     {
193       colon = s->display + 8 + (colon - ds);
194       dot1 = index (colon, '.');
195 
196       if (!dot1)
197 	dot1 = colon + strlen (colon);
198 
199       sprintf (dot1, ".%d", i);
200     }
201 
202   /* hey, this is experimental software, it doesn't have to look pretty just yet. :) */
203   if (prefs.fgstr)
204     {
205       XColor color;
206 
207       if (XAllocNamedColor
208 	  (dpy, DefaultColormap (dpy, s->num), prefs.fgstr, &color,
209 	   &color) == 0)
210 	{
211 	  fprintf (stderr,
212 		   "XAllocNamedColor - allocation of fg color failed.\n");
213 	  s->black = BlackPixel (dpy, i);
214 	}
215       else
216 	{
217 	  s->black = color.pixel;
218 	}
219     }
220   else
221     {
222       s->black = BlackPixel (dpy, i);
223     }
224 
225   if (prefs.bgstr)
226     {
227       XColor color;
228 
229       if (XAllocNamedColor
230 	  (dpy, DefaultColormap (dpy, s->num), prefs.bgstr, &color,
231 	   &color) == 0)
232 	{
233 	  fprintf (stderr,
234 		   "XAllocNamedColor - allocation of bg color failed.\n");
235 	  s->white = WhitePixel (dpy, i);
236 	}
237       else
238 	{
239 	  s->white = color.pixel;
240 	}
241     }
242   else
243     {
244       s->white = WhitePixel (dpy, i);
245     }
246 
247 #ifdef THREE_D
248   {
249     XColor topcolor;
250     XColor botcolor;
251     XColor get_c;
252 
253     get_c.pixel = s->white;
254 
255     if ((get_c.pixel == WhitePixel (dpy, s->num)) ||
256 	(get_c.pixel == BlackPixel (dpy, s->num)))
257       {
258         topcolor.red = L_TOP (L_OFF_R);
259         topcolor.green = L_TOP (L_OFF_G);
260         topcolor.blue = L_TOP (L_OFF_B);
261 
262         botcolor.red = L_BOT (L_OFF_R);
263         botcolor.green = L_BOT (L_OFF_G);
264         botcolor.blue = L_BOT (L_OFF_B);
265       }
266     else
267       {
268 	XQueryColor (dpy, s->def_cmap, &get_c);
269 
270 	topcolor.red = L_TOP (get_c.red);
271 	topcolor.green = L_TOP (get_c.green);
272 	topcolor.blue = L_TOP (get_c.blue);
273 
274 	botcolor.red = L_BOT (get_c.red);
275 	botcolor.green = L_BOT (get_c.green);
276 	botcolor.blue = L_BOT (get_c.blue);
277       }
278 
279     XAllocColor (dpy, s->def_cmap, &topcolor);
280     XAllocColor (dpy, s->def_cmap, &botcolor);
281 
282     s->topwhite = topcolor.pixel;
283     s->botwhite = botcolor.pixel;
284 
285     gv.foreground = s->topwhite;
286     gv.line_width = 0;
287     mask = GCForeground | GCLineWidth;
288     s->topwhitegc = XCreateGC (dpy, s->root, mask, &gv);
289 
290     gv.foreground = s->botwhite;
291     gv.line_width = 0;
292     mask = GCForeground | GCLineWidth;
293     s->botwhitegc = XCreateGC (dpy, s->root, mask, &gv);
294 
295     get_c.pixel = s->black;
296 
297     if ((get_c.pixel == WhitePixel (dpy, s->num)) ||
298 	(get_c.pixel == BlackPixel (dpy, s->num)))
299       {
300         topcolor.red = L_TOP (L_ON_R);
301         topcolor.green = L_TOP (L_ON_G);
302         topcolor.blue = L_TOP (L_ON_B);
303 
304 	botcolor.red = L_BOT (L_ON_R);
305         botcolor.green = L_BOT (L_ON_G);
306         botcolor.blue = L_BOT (L_ON_B);
307       }
308     else
309       {
310 	XQueryColor (dpy, s->def_cmap, &get_c);
311 
312 	topcolor.red = L_TOP (get_c.red);
313 	topcolor.green = L_TOP (get_c.green);
314 	topcolor.blue = L_TOP (get_c.blue);
315 
316 	botcolor.red = L_BOT (get_c.red);
317 	botcolor.green = L_BOT (get_c.green);
318 	botcolor.blue = L_BOT (get_c.blue);
319       }
320 
321     XAllocColor (dpy, s->def_cmap, &topcolor);
322     XAllocColor (dpy, s->def_cmap, &botcolor);
323 
324     s->topblack = topcolor.pixel;
325     s->botblack = botcolor.pixel;
326 
327     gv.foreground = s->topblack;
328     gv.line_width = 0;
329     mask = GCForeground | GCLineWidth;
330     s->topblackgc = XCreateGC (dpy, s->root, mask, &gv);
331 
332     gv.foreground = s->botblack;
333     gv.line_width = 0;
334     mask = GCForeground | GCLineWidth;
335     s->botblackgc = XCreateGC (dpy, s->root, mask, &gv);
336   }
337 #endif
338 
339   gv.foreground = s->black ^ s->white;
340   gv.background = s->white;
341   gv.function = GXxor;
342   gv.line_width = 0;
343   gv.subwindow_mode = IncludeInferiors;
344   mask = GCForeground | GCBackground | GCFunction | GCLineWidth
345     | GCSubwindowMode;
346 
347   if (font != 0)
348     {
349       gv.font = font->fid;
350       mask |= GCFont;
351     }
352 
353   s->gc = XCreateGC (dpy, s->root, mask, &gv);
354   s->place = XCreateFontCursor (dpy, XC_top_left_corner);
355   s->sweep = XCreateFontCursor (dpy, XC_bottom_right_corner);
356 
357   XSelectInput (dpy, s->root,
358 		SubstructureRedirectMask | SubstructureNotifyMask |
359 		ColormapChangeMask | PropertyChangeMask | ButtonPressMask |
360 		ButtonReleaseMask);
361 
362   XSync (dpy, False);
363 
364   /* lars stuff */
365   s->desktop = 0;
366   for (t = 0; t < prefs.desktops; t++)
367     {
368       s->clickthru[t] = prefs.clickthru[s->num][t];
369       s->tile_resize[t] = prefs.tile_resize[s->num][t];
370       s->skip_focus[t] = prefs.skip_focus[s->num][t];
371       s->left_track_width[t] = prefs.left_track_width[s->num][t];
372       s->bigmr[t] = 1;
373       s->focused[t] = 0;
374       s->notilefocused[t] = 0;
375       s->notile_raised[t] = 0;
376     }
377 
378   s->barwin =
379     XCreateSimpleWindow (dpy, s->root, BAR_X (s), BAR_Y (s), BAR_WIDTH (s),
380 			 BAR_HEIGHT, 0, s->black, s->white);
381   XSelectInput (dpy, s->barwin,
382 		ExposureMask | ButtonPressMask | ButtonReleaseMask);
383   raise_tbar (s);
384   s->tile_height = BAR_Y (s);
385   s->res_height = BAR_Y (s);
386 }
387 
388 ScreenInfo *
getscreen(Window w)389 getscreen (Window w)
390 {
391   int i;
392 
393   for (i = 0; i < num_screens; i++)
394     if (screens[i].root == w)
395       return &screens[i];
396 
397   return 0;
398 }
399 
400 void
sendcmessage(Window w,Atom a,long x,int isroot)401 sendcmessage (Window w, Atom a, long x, int isroot)
402 {
403   XEvent ev;
404   long mask;
405 
406   memset (&ev, 0, sizeof (ev));
407   ev.xclient.type = ClientMessage;
408   ev.xclient.window = w;
409   ev.xclient.message_type = a;
410   ev.xclient.format = 32;
411   ev.xclient.data.l[0] = x;
412   ev.xclient.data.l[1] = CurrentTime;
413   mask = 0L;
414 
415   if (isroot)
416     mask = SubstructureRedirectMask;	/* magic! */
417 
418   XSendEvent (dpy, w, False, mask, &ev);
419 }
420 
421 void
sendconfig(Client * c)422 sendconfig (Client * c)
423 {
424   XConfigureEvent ce;
425 
426   ce.type = ConfigureNotify;
427   ce.event = c->window;
428   ce.window = c->window;
429   ce.x = c->x;
430   ce.y = c->y;
431   ce.width = c->dx;
432   ce.height = c->dy;
433   ce.border_width = c->border;
434   ce.above = None;
435   ce.override_redirect = 0;
436 
437   XSendEvent (dpy, c->window, False, StructureNotifyMask, (XEvent *) & ce);
438 }
439 
440 void
cleanup(void)441 cleanup (void)
442 {
443   Client *c, *cc[2], *next;
444   XWindowChanges wc;
445   int i;
446 
447   /* order of un-reparenting determines final stacking order... */
448   cc[0] = cc[1] = 0;
449 
450   for (c = clients; c; c = next)
451     {
452       next = c->next;
453       i = normal (c);
454       c->next = cc[i];
455       cc[i] = c;
456     }
457 
458   for (i = 0; i < 2; i++)
459     {
460       for (c = cc[i]; c; c = c->next)
461 	{
462 	  if (!withdrawn (c))
463 	    {
464 	      gravitate (c, 1);
465 	      XReparentWindow (dpy, c->window, c->screen->root, c->x, c->y);
466 	    }
467 
468 	  wc.border_width = c->border;
469 
470 	  XConfigureWindow (dpy, c->window, CWBorderWidth, &wc);
471 	}
472     }
473 
474   XSetInputFocus (dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
475 
476   for (i = 0; i < num_screens; i++)
477     cmapnofocus (&screens[i]);
478 
479   XCloseDisplay (dpy);
480 }
481