root/client.c

Revision 1, 5.4 KB (checked in by root, 3 years ago)

Initial commit

Line 
1/* evilwm - Minimalist Window Manager for X
2 * Copyright (C) 1999-2006 Ciaran Anscomb <evilwm@6809.org.uk>
3 * see README for license and other details. */
4
5#include <stdio.h>
6#include <stdlib.h>
7#include "evilwm.h"
8#include "log.h"
9
10static int send_xmessage(Window w, Atom a, long x);
11
12/* used all over the place.  return the client that has specified window as
13 * either window or parent */
14
15Client *find_client(Window w) {
16        Client *c;
17
18        for (c = head_client; c; c = c->next)
19                if (w == c->parent || w == c->window)
20                        return c;
21        return NULL;
22}
23
24void set_wm_state(Client *c, int state) {
25        /* Using "long" for the type of "data" looks wrong, but the
26         * fine people in the X Consortium defined it this way
27         * (even on 64-bit machines).
28         */
29        long data[2];
30        data[0] = state;
31        data[1] = None;
32        XChangeProperty(dpy, c->window, xa_wm_state, xa_wm_state, 32,
33                        PropModeReplace, (unsigned char *)data, 2);
34}
35
36void send_config(Client *c) {
37        XConfigureEvent ce;
38
39        ce.type = ConfigureNotify;
40        ce.event = c->window;
41        ce.window = c->window;
42        ce.x = c->x;
43        ce.y = c->y;
44        ce.width = c->width;
45        ce.height = c->height;
46        ce.border_width = 0;
47        ce.above = None;
48        ce.override_redirect = False;
49
50        XSendEvent(dpy, c->window, False, StructureNotifyMask, (XEvent *)&ce);
51        //puts("config");
52        //todo: config -- hook
53}
54
55/* Support for 'gravitating' clients based on their original
56 * border width and configured window manager frame width. */
57void gravitate_client(Client *c, int sign) {
58        int d0 = sign * c->border;
59        int d1 = sign * c->old_border;
60        int d2 = sign * (2*c->old_border - c->border);
61        switch (c->win_gravity) {
62                case NorthGravity:
63                        c->x += d1;
64                        c->y += d0;
65                        break;
66                case NorthEastGravity:
67                        c->x += d2;
68                        c->y += d0;
69                        break;
70                case EastGravity:
71                        c->x += d2;
72                        c->y += d1;
73                        break;
74                case SouthEastGravity:
75                        c->x += d2;
76                        c->y += d2;
77                        break;
78                case SouthGravity:
79                        c->x += d1;
80                        c->y += d2;
81                        break;
82                case SouthWestGravity:
83                        c->x += d0;
84                        c->y += d2;
85                        break;
86                case WestGravity:
87                        c->x += d0;
88                        c->y += d1;
89                        break;
90                case NorthWestGravity:
91                default:
92                        c->x += d0;
93                        c->y += d0;
94                        break;
95        }
96}
97
98void select_client(Client *c) {
99        if (current)
100                XSetWindowBorder(dpy, current->parent, current->screen->bg.pixel);
101        if (c) {
102                unsigned long bpixel;
103#ifdef VWM
104                if (is_sticky(c))
105                        bpixel = c->screen->fc.pixel;
106                else
107#endif
108                        bpixel = c->screen->fg.pixel;
109                XSetWindowBorder(dpy, c->parent, bpixel);
110#ifdef COLOURMAP
111                XInstallColormap(dpy, c->cmap);
112#endif
113                XSetInputFocus(dpy, c->window, RevertToPointerRoot, CurrentTime);
114        }
115        current = c;
116}
117
118#ifdef VWM
119void fix_client(Client *c) {
120        toggle_sticky(c);
121        select_client(c);
122        update_net_wm_state(c);
123}
124#endif
125
126void remove_client(Client *c) {
127        Client *p;
128
129        LOG_DEBUG("remove_client() : Removing...\n");
130
131        XGrabServer(dpy);
132        ignore_xerror = 1;
133
134        /* ICCCM 4.1.3.1
135         * "When the window is withdrawn, the window manager will either
136         *  change the state field's value to WithdrawnState or it will
137         *  remove the WM_STATE property entirely."
138         * EWMH 1.3
139         * "The Window Manager should remove the property whenever a
140         *  window is withdrawn but it should leave the property in
141         *  place when it is shutting down." (both _NET_WM_DESKTOP and
142         *  _NET_WM_STATE) */
143        if (c->remove) {
144                LOG_DEBUG("\tremove_client() : setting WithdrawnState\n");
145                set_wm_state(c, WithdrawnState);
146#ifdef VWM
147                XDeleteProperty(dpy, c->window, xa_net_wm_desktop);
148                XDeleteProperty(dpy, c->window, xa_net_wm_state);
149#endif
150        }
151
152        ungravitate(c);
153        XReparentWindow(dpy, c->window, c->screen->root, c->x, c->y);
154        XSetWindowBorderWidth(dpy, c->window, c->old_border);
155        XRemoveFromSaveSet(dpy, c->window);
156        if (c->parent)
157                XDestroyWindow(dpy, c->parent);
158
159        if (head_client == c) head_client = c->next;
160        else for (p = head_client; p && p->next; p = p->next)
161                if (p->next == c) p->next = c->next;
162
163        if (current == c)
164                current = NULL;  /* an enter event should set this up again */
165        Py_DECREF(c->dict);
166        free(c);
167#ifdef DEBUG
168        {
169                Client *pp;
170                int i = 0;
171                for (pp = head_client; pp; pp = pp->next)
172                        i++;
173                LOG_DEBUG("\tremove_client() : free(), window count now %d\n", i);
174        }
175#endif
176
177        XUngrabServer(dpy);
178        XSync(dpy, False);
179        ignore_xerror = 0;
180        LOG_DEBUG("remove_client() returning\n");
181}
182
183void send_wm_delete(Client *c, int kill_client) {
184        int i, n, found = 0;
185        Atom *protocols;
186
187        if (!kill_client && XGetWMProtocols(dpy, c->window, &protocols, &n)) {
188                for (i = 0; i < n; i++)
189                        if (protocols[i] == xa_wm_delete)
190                                found++;
191                XFree(protocols);
192        }
193        if (found)
194                send_xmessage(c->window, xa_wm_protos, xa_wm_delete);
195        else
196                XKillClient(dpy, c->window);
197}
198
199static int send_xmessage(Window w, Atom a, long x) {
200        XEvent ev;
201
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
209        return XSendEvent(dpy, w, False, NoEventMask, &ev);
210}
211
212#ifdef SHAPE
213void set_shape(Client *c) {
214        int bounding_shaped;
215        int i, b;  unsigned int u;  /* dummies */
216
217        if (!have_shape) return;
218        /* Logic to decide if we have a shaped window cribbed from fvwm-2.5.10.
219         * Previous method (more than one rectangle returned from
220         * XShapeGetRectangles) worked _most_ of the time. */
221        if (XShapeQueryExtents(dpy, c->window, &bounding_shaped, &i, &i,
222                                &u, &u, &b, &i, &i, &u, &u) && bounding_shaped) {
223                LOG_DEBUG("%d shape extents\n", bounding_shaped);
224                XShapeCombineShape(dpy, c->parent, ShapeBounding, 0, 0,
225                                c->window, ShapeBounding, ShapeSet);
226        }
227}
228#endif
Note: See TracBrowser for help on using the browser.