1 /* evilwm - Minimalist Window Manager for X
2  * Copyright (C) 1999-2002 Ciaran Anscomb <evilwm@6809.org.uk>
3  * see README for license and other details. */
4 
5 #include "yeahwm.h"
6 #include <stdlib.h>
7 #include <stdio.h>
8 #ifdef SHAPE
9 #include <X11/extensions/shape.h>
10 #endif
11 
12 static int send_xmessage(Window w, Atom a, long x);
13 
14 /* used all over the place.  return the client that has specified window as
15  * either window or parent */
16 
find_client(Window w)17 Client *find_client(Window w)
18 {
19     Client *c;
20 
21     for (c = head_client; c; c = c->next)
22         if (w == c->parent || w == c->window || w == c->tab)
23             return c;
24     return NULL;
25 }
26 
__set_wm_state(const Window win,const Atom a,int state,long vis)27 static void __set_wm_state(const Window win, const Atom a, int state, long vis)
28 {
29     long data[2];
30 
31     data[0] = (long) state;
32     data[1] = vis;
33 
34     XChangeProperty(dpy, win, a, a, 32, PropModeReplace, (unsigned char *) data, 2);
35 }
36 
set_wm_state(Client * c,int state)37 void set_wm_state(Client * c, int state)
38 {
39     /* iconify window and set state */
40     __set_wm_state(c->window, xa_wm_state, state, None);
41 }
42 
_g_wm_state(const Window win,const Atom where)43 static long *_g_wm_state(const Window win, const Atom where)
44 {
45     Atom real_type;
46     int real_format;
47     unsigned long n, extra;
48     unsigned char *data;
49 
50     if ((XGetWindowProperty(dpy, win, where, 0L, 2L, False,
51                             AnyPropertyType, &real_type, &real_format, &n, &extra, &data) == Success) && n) {
52         return (long *) data;
53     }
54     return NULL;
55 }
__wm_state(const Window win,const Atom where)56 static int __wm_state(const Window win, const Atom where)
57 {
58     long *data, state = WithdrawnState;
59 
60     data = _g_wm_state(win, where);
61     if (data) {
62         state = *data;
63         XFree(data);
64     }
65     return state;
66 }
67 
wm_state(Client * c)68 int wm_state(Client * c)
69 {
70     return __wm_state(c->window, xa_wm_state);
71 }
72 
send_config(Client * c)73 void send_config(Client * c)
74 {
75     XConfigureEvent ce;
76     ce.type = ConfigureNotify;
77     ce.event = c->window;
78     ce.window = c->window;
79     ce.x = c->x;
80     ce.y = c->y;
81     ce.width = c->width;
82     ce.height = c->height;
83     ce.border_width = 0;
84     ce.above = None;
85     ce.override_redirect = 0;
86     XSendEvent(dpy, c->window, False, StructureNotifyMask, (XEvent *) & ce);
87 }
88 
remove_client(Client * c)89 void remove_client(Client * c)
90 {
91     Client *p;
92 #ifdef DEBUG
93     fprintf(stderr, "remove_client() : Removing...\n");
94 #endif
95     XGrabServer(dpy);
96     XSetErrorHandler(ignore_xerror);
97     if (!quitting) {
98 #ifdef DEBUG
99         fprintf(stderr, "\tremove_client() : setting WithdrawnState\n");
100 #endif
101         set_wm_state(c, WithdrawnState);
102         XRemoveFromSaveSet(dpy, c->window);
103     }
104     ungravitate(c);
105     XSetWindowBorderWidth(dpy, c->window, 1);
106     XReparentWindow(dpy, c->window, root, c->x, c->y);
107     if (c->parent)
108         XDestroyWindow(dpy, c->parent);;
109     if (c->tab)
110         XDestroyWindow(dpy, c->tab);
111     if (head_client == c)
112         head_client = c->next;
113     else
114         for (p = head_client; p && p->next; p = p->next)
115             if (p->next == c)
116                 p->next = c->next;
117     if (c->size)
118         XFree(c->size);
119     if (c->name)
120         XFree(c->name);
121     if (current == c)
122         current = NULL;         /* an enter event should set this up again */
123     free(c);
124 #ifdef DEBUG
125     {
126         Client *p;
127         int i = 0;
128         for (p = head_client; p; p = p->next)
129             i++;
130         fprintf(stderr, "\tremove_client() : free(), window count now %d\n", i);
131     }
132 #endif
133     XSync(dpy, False);
134     XSetErrorHandler(handle_xerror);
135     XUngrabServer(dpy);
136 }
137 
change_gravity(Client * c,int multiplier)138 void change_gravity(Client * c, int multiplier)
139 {
140     int dx = 0, dy = 0;
141     int gravity = (c->size->flags & PWinGravity) ? c->size->win_gravity : NorthWestGravity;
142     switch (gravity) {
143     case NorthWestGravity:
144     case SouthWestGravity:
145     case NorthEastGravity:
146     case StaticGravity:
147         dx = c->border;
148     case NorthGravity:
149         dy = c->border;
150         break;
151     }
152     c->x += multiplier * dx;
153     c->y += multiplier * dy;
154 #ifdef DEBUG
155     if (dx || dy) {
156         fprintf(stderr, "change_gravity() : window adjustment of %d,%d for ", multiplier * dx, multiplier * dy);
157         switch (gravity) {
158         case NorthWestGravity:
159             fprintf(stderr, "NorthWestGravity\n");
160             break;
161         case SouthWestGravity:
162             fprintf(stderr, "SouthWestGravity\n");
163             break;
164         case NorthEastGravity:
165             fprintf(stderr, "NorthEastGravity\n");
166             break;
167         case NorthGravity:
168             fprintf(stderr, "NorthGravity\n");
169             break;
170         case StaticGravity:
171             fprintf(stderr, "StaticGravity\n");
172             break;
173         default:
174             fprintf(stderr, "unhandled gravity %d\n", gravity);
175             break;
176         }
177     }
178 #endif
179 }
180 
send_wm_delete(Client * c)181 void send_wm_delete(Client * c)
182 {
183     int i, n, found = 0;
184     Atom *protocols;
185     if (c) {
186         if (XGetWMProtocols(dpy, c->window, &protocols, &n)) {
187             for (i = 0; i < n; i++)
188                 if (protocols[i] == xa_wm_delete)
189                     found++;
190             XFree(protocols);
191         }
192         if (found)
193             send_xmessage(c->window, xa_wm_protos, xa_wm_delete);
194         else
195             XKillClient(dpy, c->window);
196     }
197 }
198 
send_xmessage(Window w,Atom a,long x)199 static int send_xmessage(Window w, Atom a, long x)
200 {
201     XEvent ev;
202     ev.type = ClientMessage;
203     ev.xclient.window = w;
204     ev.xclient.message_type = a;
205     ev.xclient.format = 32;
206     ev.xclient.data.l[0] = x;
207     ev.xclient.data.l[1] = CurrentTime;
208     return XSendEvent(dpy, w, False, NoEventMask, &ev);
209 }
210 
211 #ifdef SHAPE
set_shape(Client * c)212 void set_shape(Client * c)
213 {
214     int n, order;
215     XRectangle *rect;
216     rect = XShapeGetRectangles(dpy, c->window, ShapeBounding, &n, &order);
217     if (n > 1)
218         XShapeCombineShape(dpy, c->parent, ShapeBounding, c->border, c->border, c->window, ShapeBounding, ShapeSet);
219     XFree((void *) rect);
220 }
221 #endif
client_update_current(Client * c)222 void client_update_current(Client * c)
223 {
224 
225     if (c) {
226         if (c->vdesk == STICKY) {
227             XSetWindowBackground(dpy, c->parent, fc.pixel);
228             XSetWindowBackground(dpy, c->tab, fc.pixel);
229         } else {
230 
231             XSetWindowBackground(dpy, c->parent, abg.pixel);
232             XSetWindowBackground(dpy, c->tab, abg.pixel);
233         }
234         XClearWindow(dpy, c->parent);
235         XClearWindow(dpy, c->tab);
236         if (c->title)
237             show_info(c);
238         if (c == current)
239             return;
240     }
241     if (current) {
242         XSetWindowBackground(dpy, current->parent, bg.pixel);
243         XSetWindowBackground(dpy, current->tab, bg.pixel);
244         XClearWindow(dpy, current->parent);
245         XClearWindow(dpy, current->tab);
246         if (current->title)
247             show_info(current);
248     }
249     current = c;
250 }
251