root/new.c

Revision 1, 10.9 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 <stdlib.h>
6#include <string.h>
7#include <stdio.h>
8#include "evilwm.h"
9#include "log.h"
10
11#define MAXIMUM_PROPERTY_LENGTH 4096
12
13static void init_geometry(Client *c);
14static void reparent(Client *c);
15static void *get_property(Window w, Atom property, Atom req_type,
16                unsigned long *nitems_return);
17#ifdef XDEBUG
18static const char *map_state_string(int map_state);
19static const char *gravity_string(int gravity);
20static void debug_wm_normal_hints(XSizeHints *size);
21#else
22# define debug_wm_normal_hints(s)
23#endif
24
25void make_new_client(Window w, ScreenInfo *s) {
26        Client *c;
27        char *name;
28        XClassHint *class;
29
30        XGrabServer(dpy);
31
32        /* First a bit of interaction with the error handler due to X's
33         * tendency to batch event notifications.  We set a global variable to
34         * the id of the window we're initialising then do simple X call on
35         * that window.  If an error is raised by this (and nothing else should
36         * do so as we've grabbed the server), the error handler resets the
37         * variable indicating the window has already disappeared, so we stop
38         * trying to manage it. */
39        initialising = w;
40        XFetchName(dpy, w, &name);
41        XSync(dpy, False);
42        /* If 'initialising' is now set to None, that means doing the
43         * XFetchName raised BadWindow - the window has been removed before
44         * we got a chance to grab the server. */
45        if (initialising == None) {
46                LOG_DEBUG("make_new_client() : XError occurred for initialising window - aborting...\n");
47                XUngrabServer(dpy);
48                return;
49        }
50        initialising = None;
51        LOG_DEBUG("make_new_client(): %s\n", name ? name : "Untitled");
52        if (name)
53                XFree(name);
54
55        c = malloc(sizeof(Client));
56        /* Don't crash the window manager, just fail the operation. */
57        if (!c) {
58                LOG_ERROR("out of memory in new_client; limping onward\n");
59                return;
60        }
61        c->next = head_client;
62        c->dict = PyDict_New();
63        head_client = c;
64
65        c->screen = s;
66        c->window = w;
67        c->ignore_unmap = 0;
68        c->remove = 0;
69
70        /* Ungrab the X server as soon as possible. Now that the client is
71         * malloc()ed and attached to the list, it is safe for any subsequent
72         * X calls to raise an X error and thus flag it for removal. */
73        XUngrabServer(dpy);
74
75        c->border = opt_bw;
76
77        init_geometry(c);
78
79#ifdef DEBUG
80        {
81                Client *p;
82                int i = 0;
83                for (p = head_client; p; p = p->next)
84                        i++;
85                LOG_DEBUG("make_new_client() : new window %dx%d+%d+%d, wincount=%d\n", c->width, c->height, c->x, c->y, i);
86        }
87#endif
88
89#ifdef COLOURMAP
90        XSelectInput(dpy, c->window, ColormapChangeMask | EnterWindowMask | PropertyChangeMask);
91#else
92        XSelectInput(dpy, c->window, EnterWindowMask | PropertyChangeMask);
93#endif
94
95        reparent(c);
96
97#ifdef SHAPE
98        if (have_shape) {
99            XShapeSelectInput(dpy, c->window, ShapeNotifyMask);
100            set_shape(c);
101        }
102#endif
103
104        /* Read instance/class information for client and check against list
105         * built with -app options */
106        class = XAllocClassHint();
107        if (class) {
108                Application *a = head_app;
109                XGetClassHint(dpy, w, class);
110                while (a) {
111                        if ((!a->res_name || (class->res_name && !strcmp(class->res_name, a->res_name)))
112                                        && (!a->res_class || (class->res_class && !strcmp(class->res_class, a->res_class)))) {
113                                if (a->geometry_mask & WidthValue)
114                                        c->width = a->width * c->width_inc;
115                                if (a->geometry_mask & HeightValue)
116                                        c->height = a->height * c->height_inc;
117                                if (a->geometry_mask & XValue) {
118                                        if (a->geometry_mask & XNegative)
119                                                c->x = a->x + DisplayWidth(dpy, s->screen)-c->width-c->border;
120                                        else
121                                                c->x = a->x + c->border;
122                                }
123                                if (a->geometry_mask & YValue) {
124                                        if (a->geometry_mask & YNegative)
125                                                c->y = a->y + DisplayHeight(dpy, s->screen)-c->height-c->border;
126                                        else
127                                                c->y = a->y + c->border;
128                                }
129                                moveresize(c);
130#ifdef VWM
131                                if (a->vdesk != -1) c->vdesk = a->vdesk;
132                                c->sticky = a->sticky;
133#endif
134                        }
135                        a = a->next;
136                }
137                XFree(class->res_name);
138                XFree(class->res_class);
139                XFree(class);
140        }
141
142        /* Only map the window frame (and thus the window) if it's supposed
143         * to be visible on this virtual desktop. */
144#ifdef VWM
145        if (s->vdesk == c->vdesk)
146#endif
147        {
148                unhide(c, RAISE);
149#ifndef MOUSE
150                select_client(c);
151                setmouse(c->window, c->width + c->border - 1,
152                                c->height + c->border - 1);
153                discard_enter_events();
154#endif
155        }
156#ifdef VWM
157        else {
158                set_wm_state(c, IconicState);
159        }
160        update_net_wm_desktop(c);
161#endif
162}
163
164/* Calls XGetWindowAttributes, XGetWMHints and XGetWMNormalHints to determine
165 * window's initial geometry.
166 *
167 * XGetWindowAttributes
168 */
169static void init_geometry(Client *c) {
170        long size_flags;
171        XWindowAttributes attr;
172        unsigned long nitems;
173        PropMwmHints *mprop;
174#ifdef VWM
175        unsigned long i;
176        unsigned long *lprop;
177        Atom *aprop;
178#endif
179
180        if ( (mprop = get_property(c->window, mwm_hints, mwm_hints, &nitems)) ) {
181                if (nitems >= PROP_MWM_HINTS_ELEMENTS
182                                && (mprop->flags & MWM_HINTS_DECORATIONS)
183                                && !(mprop->decorations & MWM_DECOR_ALL)
184                                && !(mprop->decorations & MWM_DECOR_BORDER)) {
185                        c->border = 0;
186                }
187                XFree(mprop);
188        }
189
190#ifdef VWM
191        c->vdesk = c->screen->vdesk;
192        if ( (lprop = get_property(c->window, xa_net_wm_desktop, XA_CARDINAL, &nitems)) ) {
193                if (nitems && valid_vdesk(lprop[0]))
194                        c->vdesk = lprop[0];
195                XFree(lprop);
196        }
197        remove_sticky(c);
198        if ( (aprop = get_property(c->window, xa_net_wm_state, XA_ATOM, &nitems)) ) {
199                for (i = 0; i < nitems; i++) {
200                        if (aprop[i] == xa_net_wm_state_sticky)
201                                add_sticky(c);
202                }
203                XFree(aprop);
204        }
205#endif
206
207        /* Get current window attributes */
208        LOG_XDEBUG("XGetWindowAttributes()\n");
209        XGetWindowAttributes(dpy, c->window, &attr);
210        LOG_XDEBUG("\t(%s) %dx%d+%d+%d, bw = %d\n", map_state_string(attr.map_state), attr.width, attr.height, attr.x, attr.y, attr.border_width);
211        c->old_border = attr.border_width;
212        c->oldw = c->oldh = 0;
213#ifdef COLOURMAP
214        c->cmap = attr.colormap;
215#endif
216
217        size_flags = get_wm_normal_hints(c);
218
219        if ((attr.width >= c->min_width) && (attr.height >= c->min_height)) {
220        /* if (attr.map_state == IsViewable || (size_flags & (PSize | USSize))) { */
221                c->width = attr.width;
222                c->height = attr.height;
223        } else {
224                c->width = c->min_width;
225                c->height = c->min_height;
226                send_config(c);
227        }
228        if ((attr.map_state == IsViewable)
229                        || (size_flags & (/*PPosition |*/ USPosition))) {
230                c->x = attr.x;
231                c->y = attr.y;
232        } else {
233#ifdef MOUSE
234                int xmax = DisplayWidth(dpy, c->screen->screen);
235                int ymax = DisplayHeight(dpy, c->screen->screen);
236                int x, y;
237                get_mouse_position(&x, &y, c->screen->root);
238                c->x = (x * (xmax - c->border - c->width)) / xmax;
239                c->y = (y * (ymax - c->border - c->height)) / ymax;
240#else
241                c->x = c->y = c->border;
242#endif
243                send_config(c);
244        }
245
246        LOG_DEBUG("\twindow started as %dx%d +%d+%d\n", c->width, c->height, c->x, c->y);
247        if (attr.map_state == IsViewable) {
248                /* The reparent that is to come would trigger an unmap event */
249                c->ignore_unmap++;
250        }
251        gravitate(c);
252        run_geometry_hook(c);
253}
254
255static void reparent(Client *c) {
256        XSetWindowAttributes p_attr;
257
258        p_attr.border_pixel = c->screen->bg.pixel;
259        p_attr.override_redirect = True;
260        p_attr.event_mask = ChildMask | ButtonPressMask | EnterWindowMask;
261        c->parent = XCreateWindow(dpy, c->screen->root, c->x-c->border, c->y-c->border,
262                c->width, c->height, c->border,
263                DefaultDepth(dpy, c->screen->screen), CopyFromParent,
264                DefaultVisual(dpy, c->screen->screen),
265                CWOverrideRedirect | CWBorderPixel | CWEventMask, &p_attr);
266
267        XAddToSaveSet(dpy, c->window);
268        XSetWindowBorderWidth(dpy, c->window, 0);
269        XReparentWindow(dpy, c->window, c->parent, 0, 0);
270        XMapWindow(dpy, c->window);
271#ifdef MOUSE
272        grab_button(c->parent, grabmask2, AnyButton);
273#endif
274}
275
276/* Get WM_NORMAL_HINTS property */
277long get_wm_normal_hints(Client *c) {
278        XSizeHints *size;
279        long flags;
280        long dummy;
281        size = XAllocSizeHints();
282        LOG_XDEBUG("XGetWMNormalHints()\n");
283        XGetWMNormalHints(dpy, c->window, size, &dummy);
284        debug_wm_normal_hints(size);
285        flags = size->flags;
286        if (flags & PMinSize) {
287                c->min_width = size->min_width;
288                c->min_height = size->min_height;
289        } else {
290                c->min_width = c->min_height = 0;
291        }
292        if (flags & PMaxSize) {
293                c->max_width = size->max_width;
294                c->max_height = size->max_height;
295        } else {
296                c->max_width = c->max_height = 0;
297        }
298        if (flags & PBaseSize) {
299                c->base_width = size->base_width;
300                c->base_height = size->base_height;
301        } else {
302                c->base_width = c->min_width;
303                c->base_height = c->min_height;
304        }
305        c->width_inc = c->height_inc = 1;
306        if (flags & PResizeInc) {
307                c->width_inc = size->width_inc ? size->width_inc : 1;
308                c->height_inc = size->height_inc ? size->height_inc : 1;
309        }
310        if (!(flags & PMinSize)) {
311                c->min_width = c->base_width + c->width_inc;
312                c->min_height = c->base_height + c->height_inc;
313        }
314        if (flags & PWinGravity) {
315                c->win_gravity = size->win_gravity;
316        } else {
317                c->win_gravity = NorthWestGravity;
318        }
319        XFree(size);
320        return flags;
321}
322
323static void *get_property(Window w, Atom property, Atom req_type,
324                unsigned long *nitems_return) {
325        Atom actual_type;
326        int actual_format;
327        unsigned long bytes_after;
328        unsigned char *prop;
329        if (XGetWindowProperty(dpy, w, property,
330                                0L, MAXIMUM_PROPERTY_LENGTH / 4, False,
331                                req_type, &actual_type, &actual_format,
332                                nitems_return, &bytes_after, &prop)
333                        == Success) {
334                if (actual_type == req_type)
335                        return (void *)prop;
336                XFree(prop);
337        }
338        return NULL;
339}
340
341#ifdef XDEBUG
342static const char *map_state_string(int map_state) {
343        const char *map_states[4] = {
344                "IsUnmapped",
345                "IsUnviewable",
346                "IsViewable",
347                "Unknown"
348        };
349        return ((unsigned int)map_state < 3)
350                ? map_states[map_state]
351                : map_states[3];
352}
353
354static const char *gravity_string(int gravity) {
355        const char *gravities[12] = {
356                "ForgetGravity",
357                "NorthWestGravity",
358                "NorthGravity",
359                "NorthEastGravity",
360                "WestGravity",
361                "CenterGravity",
362                "EastGravity",
363                "SouthWestGravity",
364                "SouthGravity",
365                "SouthEastGravity",
366                "StaticGravity",
367                "Unknown"
368        };
369        return ((unsigned int)gravity < 11) ? gravities[gravity] : gravities[11];
370}
371
372static void debug_wm_normal_hints(XSizeHints *size) {
373        if (size->flags & 15) {
374                LOG_XDEBUG("\t");
375                if (size->flags & USPosition) {
376                        LOG_XDEBUG("USPosition ");
377                }
378                if (size->flags & USSize) {
379                        LOG_XDEBUG("USSize ");
380                }
381                if (size->flags & PPosition) {
382                        LOG_XDEBUG("PPosition ");
383                }
384                if (size->flags & PSize) {
385                        LOG_XDEBUG("PSize");
386                }
387                LOG_XDEBUG("\n");
388        }
389        if (size->flags & PMinSize) {
390                LOG_XDEBUG("\tPMinSize: min_width = %d, min_height = %d\n", size->min_width, size->min_height);
391        }
392        if (size->flags & PMaxSize) {
393                LOG_XDEBUG("\tPMaxSize: max_width = %d, max_height = %d\n", size->max_width, size->max_height);
394        }
395        if (size->flags & PResizeInc) {
396                LOG_XDEBUG("\tPResizeInc: width_inc = %d, height_inc = %d\n",
397                                size->width_inc, size->height_inc);
398        }
399        if (size->flags & PAspect) {
400                LOG_XDEBUG("\tPAspect: min_aspect = %d/%d, max_aspect = %d/%d\n",
401                                size->min_aspect.x, size->min_aspect.y,
402                                size->max_aspect.x, size->max_aspect.y);
403        }
404        if (size->flags & PBaseSize) {
405                LOG_XDEBUG("\tPBaseSize: base_width = %d, base_height = %d\n",
406                                size->base_width, size->base_height);
407        }
408        if (size->flags & PWinGravity) {
409                LOG_XDEBUG("\tPWinGravity: %s\n", gravity_string(size->win_gravity));
410        }
411}
412#endif
Note: See TracBrowser for help on using the browser.