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