add_window.c revision 6d8e82c3
1/*****************************************************************************/
2/*
3
4Copyright 1989,1998  The Open Group
5
6Permission to use, copy, modify, distribute, and sell this software and its
7documentation for any purpose is hereby granted without fee, provided that
8the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation.
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall not be
23used in advertising or otherwise to promote the sale, use or other dealings
24in this Software without prior written authorization from The Open Group.
25
26*/
27/**       Copyright 1988 by Evans & Sutherland Computer Corporation,        **/
28/**                          Salt Lake City, Utah                           **/
29/**                        Cambridge, Massachusetts                         **/
30/**                                                                         **/
31/**                           All Rights Reserved                           **/
32/**                                                                         **/
33/**    Permission to use, copy, modify, and distribute this software and    **/
34/**    its documentation  for  any  purpose  and  without  fee is hereby    **/
35/**    granted, provided that the above copyright notice appear  in  all    **/
36/**    copies and that both  that  copyright  notice  and  this  permis-    **/
37/**    sion  notice appear in supporting  documentation,  and  that  the    **/
38/**    name of Evans & Sutherland not be used in advertising    **/
39/**    in publicity pertaining to distribution of the  software  without    **/
40/**    specific, written prior permission.                                  **/
41/**                                                                         **/
42/**    EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD    **/
43/**    TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES  OF  MERCHANT-    **/
44/**    ABILITY  AND  FITNESS,  IN  NO  EVENT SHALL EVANS & SUTHERLAND    **/
45/**    BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL  DAM-    **/
46/**    AGES OR  ANY DAMAGES WHATSOEVER  RESULTING FROM LOSS OF USE, DATA    **/
47/**    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER    **/
48/**    TORTIOUS ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE    **/
49/**    OR PERFORMANCE OF THIS SOFTWARE.                                     **/
50/*****************************************************************************/
51
52/**********************************************************************
53 *
54 * Add a new window, put the titlebar and other stuff around
55 * the window
56 *
57 * 31-Mar-88 Tom LaStrange        Initial Version.
58 *
59 **********************************************************************/
60
61#include <stdio.h>
62#include "twm.h"
63#include <X11/Xatom.h>
64#include "util.h"
65#include "resize.h"
66#include "parse.h"
67#include "list.h"
68#include "events.h"
69#include "menus.h"
70#include "screen.h"
71#include "iconmgr.h"
72#include "session.h"
73#include "add_window.h"
74
75#define short_lookup (short)(long)(void*)
76
77#define gray_width 2
78#define gray_height 2
79static char gray_bits[] = {
80    0x02, 0x01
81};
82
83int AddingX;
84int AddingY;
85int AddingW;
86int AddingH;
87
88static int PlaceX = 50;
89static int PlaceY = 50;
90
91static void do_add_binding(int button, int context, int modifier, int func);
92static Window CreateHighlightWindow(TwmWindow *tmp_win);
93static void CreateWindowTitlebarButtons(TwmWindow *tmp_win);
94
95char NoName[] = "Untitled";     /* name if no name is specified */
96
97/**
98 * map gravity to (x,y) offset signs for adding to x and y when window is
99 * mapped to get proper placement.
100 *
101 *  \param tmp    window from which to get gravity
102 *  \param xp,yp  return values
103 *
104 */
105void
106GetGravityOffsets(TwmWindow *tmp, int *xp, int *yp)
107{
108    /* *INDENT-OFF* */
109    static struct _gravity_offset {
110        int x, y;
111    } gravity_offsets[11] = {
112        {  0,  0 },                     /* ForgetGravity */
113        { -1, -1 },                     /* NorthWestGravity */
114        {  0, -1 },                     /* NorthGravity */
115        {  1, -1 },                     /* NorthEastGravity */
116        { -1,  0 },                     /* WestGravity */
117        {  0,  0 },                     /* CenterGravity */
118        {  1,  0 },                     /* EastGravity */
119        { -1,  1 },                     /* SouthWestGravity */
120        {  0,  1 },                     /* SouthGravity */
121        {  1,  1 },                     /* SouthEastGravity */
122        {  0,  0 },                     /* StaticGravity */
123    };
124    /* *INDENT-ON* */
125    int g = ((tmp->hints.flags & PWinGravity)
126                      ? tmp->hints.win_gravity : NorthWestGravity);
127
128    if (g < ForgetGravity || g > StaticGravity) {
129        *xp = *yp = 0;
130    }
131    else {
132        *xp = gravity_offsets[g].x;
133        *yp = gravity_offsets[g].y;
134    }
135}
136
137/**
138 * add a new window to the twm list.
139 *
140 *  \return  pointer to the TwmWindow structure
141 *
142 *      \param w      the window id of the window to add
143 *      \param iconm  flag to tell if this is an icon manager window
144 *      \param iconp  pointer to icon manager struct
145 */
146TwmWindow *
147AddWindow(Window w, int iconm, IconMgr *iconp)
148{
149    TwmWindow *tmp_win;         /* new twm window structure */
150    XEvent event;
151    unsigned long valuemask;    /* mask for create windows */
152    XSetWindowAttributes attributes;    /* attributes for create windows */
153    int ask_user;               /* don't know where to put the window */
154    int gravx, gravy;           /* gravity signs for positioning */
155    int namelen;
156    int bw2;
157    short saved_x, saved_y, restore_icon_x, restore_icon_y;
158    unsigned short saved_width, saved_height;
159    Bool restore_iconified = 0;
160    Bool restore_icon_info_present = 0;
161    int restoredFromPrevSession;
162    Bool width_ever_changed_by_user;
163    Bool height_ever_changed_by_user;
164    char *name;
165    int dummy = 0;
166    unsigned udummy = 0;
167    Window wdummy = None;
168
169#ifdef DEBUG
170    fprintf(stderr, "AddWindow: w = 0x%lx\n", (unsigned long) w);
171#endif
172
173    /* allocate space for the twm window */
174    tmp_win = (TwmWindow *) calloc(1, sizeof(TwmWindow));
175    if (tmp_win == NULL) {
176        twmWarning("Unable to allocate memory to manage window ID %lx.", w);
177        return NULL;
178    }
179    tmp_win->w = w;
180    tmp_win->zoomed = ZOOM_NONE;
181    tmp_win->iconmgr = (short) iconm;
182    tmp_win->iconmgrp = iconp;
183    tmp_win->cmaps.number_cwins = 0;
184
185    XSelectInput(dpy, tmp_win->w, PropertyChangeMask);
186
187    XGetWindowAttributes(dpy, tmp_win->w, &tmp_win->attr);
188
189    if (!I18N_FetchName(dpy, tmp_win->w, &name))
190        name = NULL;
191    tmp_win->xclass = NoClass;
192    XGetClassHint(dpy, tmp_win->w, &tmp_win->xclass);
193    FetchWmProtocols(tmp_win);
194    FetchWmColormapWindows(tmp_win);
195
196    if (name == NULL)
197        tmp_win->name = strdup(NoName);
198    else {
199        tmp_win->name = strdup(name);
200        free(name);
201    }
202
203    if (GetWindowConfig(tmp_win,
204                        &saved_x, &saved_y, &saved_width, &saved_height,
205                        &restore_iconified, &restore_icon_info_present,
206                        &restore_icon_x, &restore_icon_y,
207                        &width_ever_changed_by_user,
208                        &height_ever_changed_by_user)) {
209        tmp_win->attr.x = saved_x;
210        tmp_win->attr.y = saved_y;
211
212        tmp_win->widthEverChangedByUser = width_ever_changed_by_user;
213        tmp_win->heightEverChangedByUser = height_ever_changed_by_user;
214
215        if (width_ever_changed_by_user)
216            tmp_win->attr.width = saved_width;
217
218        if (height_ever_changed_by_user)
219            tmp_win->attr.height = saved_height;
220
221        restoredFromPrevSession = 1;
222    }
223    else {
224        tmp_win->widthEverChangedByUser = False;
225        tmp_win->heightEverChangedByUser = False;
226
227        restoredFromPrevSession = 0;
228    }
229
230    /*
231     * do initial clip; should look at window gravity
232     */
233    if (tmp_win->attr.width > Scr->MaxWindowWidth)
234        tmp_win->attr.width = Scr->MaxWindowWidth;
235    if (tmp_win->attr.height > Scr->MaxWindowHeight)
236        tmp_win->attr.height = Scr->MaxWindowHeight;
237
238    tmp_win->wmhints = XGetWMHints(dpy, tmp_win->w);
239
240    if (tmp_win->wmhints) {
241        if (restore_iconified) {
242            tmp_win->wmhints->initial_state = IconicState;
243            tmp_win->wmhints->flags |= StateHint;
244        }
245
246        if (restore_icon_info_present) {
247            tmp_win->wmhints->icon_x = restore_icon_x;
248            tmp_win->wmhints->icon_y = restore_icon_y;
249            tmp_win->wmhints->flags |= IconPositionHint;
250        }
251    }
252
253    if (tmp_win->wmhints && (tmp_win->wmhints->flags & WindowGroupHint))
254        tmp_win->group = tmp_win->wmhints->window_group;
255    else
256        tmp_win->group = tmp_win->w /* NULL */ ;
257
258    /*
259     * The July 27, 1988 draft of the ICCCM ignores the size and position
260     * fields in the WM_NORMAL_HINTS property.
261     */
262
263    tmp_win->transient = (short) Transient(tmp_win->w, &tmp_win->transientfor);
264
265    tmp_win->nameChanged = 0;
266    if (tmp_win->xclass.res_name == NULL)
267        tmp_win->xclass.res_name = NoName;
268    if (tmp_win->xclass.res_class == NULL)
269        tmp_win->xclass.res_class = NoName;
270
271    tmp_win->full_name = strdup(tmp_win->name);
272    namelen = (int) strlen(tmp_win->name);
273
274    tmp_win->highlight = Scr->Highlight &&
275        (!short_lookup LookInList(Scr->NoHighlight, tmp_win->full_name,
276                                  &tmp_win->xclass));
277
278    tmp_win->stackmode = Scr->StackMode &&
279        (!short_lookup LookInList(Scr->NoStackModeL, tmp_win->full_name,
280                                  &tmp_win->xclass));
281
282    tmp_win->titlehighlight = Scr->TitleHighlight &&
283        (!short_lookup LookInList(Scr->NoTitleHighlight, tmp_win->full_name,
284                                  &tmp_win->xclass));
285
286    tmp_win->auto_raise = short_lookup LookInList(Scr->AutoRaise,
287                                                  tmp_win->full_name,
288                                                  &tmp_win->xclass);
289    if (tmp_win->auto_raise)
290        Scr->NumAutoRaises++;
291    if (Scr->IconifyByUnmapping) {
292        tmp_win->iconify_by_unmapping = iconm ? FALSE :
293            !short_lookup LookInList(Scr->DontIconify, tmp_win->full_name,
294                                     &tmp_win->xclass);
295    }
296    else {
297        tmp_win->iconify_by_unmapping = Scr->IconifyByUnmapping;
298    }
299    tmp_win->iconify_by_unmapping |=
300        short_lookup LookInList(Scr->IconifyByUn, tmp_win->full_name,
301                                &tmp_win->xclass);
302
303    if (LookInList(Scr->WindowRingL, tmp_win->full_name, &tmp_win->xclass)) {
304        if (Scr->Ring) {
305            tmp_win->ring.next = Scr->Ring->ring.next;
306            if (Scr->Ring->ring.next->ring.prev)
307                Scr->Ring->ring.next->ring.prev = tmp_win;
308            Scr->Ring->ring.next = tmp_win;
309            tmp_win->ring.prev = Scr->Ring;
310        }
311        else {
312            tmp_win->ring.next = tmp_win->ring.prev = Scr->Ring = tmp_win;
313        }
314    }
315    else
316        tmp_win->ring.next = tmp_win->ring.prev = NULL;
317    tmp_win->ring.cursor_valid = False;
318
319    tmp_win->squeeze_info = NULL;
320    /*
321     * get the squeeze information; note that this does not have to be freed
322     * since it is coming from the screen list
323     */
324    if (HasShape) {
325        if (!LookInList(Scr->DontSqueezeTitleL, tmp_win->full_name,
326                        &tmp_win->xclass)) {
327            tmp_win->squeeze_info = (SqueezeInfo *)
328                LookInList(Scr->SqueezeTitleL, tmp_win->full_name,
329                           &tmp_win->xclass);
330            if (!tmp_win->squeeze_info) {
331                static SqueezeInfo default_squeeze = { J_LEFT, 0, 0 };
332                if (Scr->SqueezeTitle)
333                    tmp_win->squeeze_info = &default_squeeze;
334            }
335        }
336    }
337
338    tmp_win->old_bw = tmp_win->attr.border_width;
339
340    if (Scr->ClientBorderWidth) {
341        tmp_win->frame_bw = tmp_win->old_bw;
342    }
343    else {
344        tmp_win->frame_bw = Scr->BorderWidth;
345    }
346    bw2 = tmp_win->frame_bw * 2;
347
348    tmp_win->title_height = Scr->TitleHeight + tmp_win->frame_bw;
349    if (Scr->NoTitlebar)
350        tmp_win->title_height = 0;
351    if (LookInList(Scr->MakeTitle, tmp_win->full_name, &tmp_win->xclass))
352        tmp_win->title_height = Scr->TitleHeight + tmp_win->frame_bw;
353    if (LookInList(Scr->NoTitle, tmp_win->full_name, &tmp_win->xclass))
354        tmp_win->title_height = 0;
355
356    /* if it is a transient window, don't put a title on it */
357    if (tmp_win->transient && !Scr->DecorateTransients)
358        tmp_win->title_height = 0;
359
360    if (LookInList(Scr->StartIconified, tmp_win->full_name, &tmp_win->xclass)) {
361        if (!tmp_win->wmhints) {
362            tmp_win->wmhints = (XWMHints *) malloc(sizeof(XWMHints));
363            tmp_win->wmhints->flags = 0;
364        }
365        tmp_win->wmhints->initial_state = IconicState;
366        tmp_win->wmhints->flags |= StateHint;
367    }
368
369    GetWindowSizeHints(tmp_win);
370
371    if (restoredFromPrevSession) {
372        /*
373         * When restoring window positions from the previous session,
374         * we always use NorthWest gravity.
375         */
376
377        gravx = gravy = -1;
378    }
379    else {
380        GetGravityOffsets(tmp_win, &gravx, &gravy);
381    }
382
383    /*
384     * Don't bother user if:
385     *
386     *     o  the window is a transient, or
387     *
388     *     o  a USPosition was requested, or
389     *
390     *     o  a PPosition was requested and UsePPosition is ON or
391     *        NON_ZERO if the window is at other than (0,0)
392     */
393    ask_user = TRUE;
394    if (tmp_win->transient ||
395        (tmp_win->hints.flags & USPosition) ||
396        ((tmp_win->hints.flags & PPosition) && Scr->UsePPosition &&
397         (Scr->UsePPosition == PPOS_ON ||
398          tmp_win->attr.x != 0 || tmp_win->attr.y != 0)))
399        ask_user = FALSE;
400
401    /*
402     * do any prompting for position
403     */
404    if (HandlingEvents && ask_user && !restoredFromPrevSession) {
405        if (Scr->RandomPlacement) {     /* just stick it somewhere */
406            /* Avoid putting the new window off-screen */
407            if ((PlaceX + tmp_win->attr.width) > Scr->MyDisplayWidth) {
408                PlaceX = Scr->MyDisplayWidth - tmp_win->attr.width;
409                if (PlaceX < 0)
410                    PlaceX = 0;
411                if (PlaceX > 50)
412                    PlaceX = 50;
413            }
414            if ((PlaceY + tmp_win->attr.height) > Scr->MyDisplayHeight) {
415                PlaceY = Scr->MyDisplayHeight - tmp_win->attr.height;
416                if (PlaceY < 0)
417                    PlaceY = 0;
418                if (PlaceY > 50)
419                    PlaceY = 50;
420            }
421
422            tmp_win->attr.x = PlaceX;
423            tmp_win->attr.y = PlaceY;
424            PlaceX += 30;
425            PlaceY += 30;
426        }
427        else {                  /* else prompt */
428            if (!(tmp_win->wmhints && tmp_win->wmhints->flags & StateHint &&
429                  tmp_win->wmhints->initial_state == IconicState)) {
430                Bool firsttime = True;
431                int height, width;
432
433                /* better wait until all the mouse buttons have been
434                 * released.
435                 */
436                while (TRUE) {
437                    int stat;
438                    Window root = None;
439                    unsigned mask = 0;
440
441                    XUngrabServer(dpy);
442                    XSync(dpy, 0);
443                    XGrabServer(dpy);
444
445                    if (!XQueryPointer(dpy, Scr->Root, &root,
446                                       &wdummy, &dummy, &dummy,
447                                       &AddingX, &AddingY, &mask))
448                        mask = 0;
449
450                    mask &= (Button1Mask | Button2Mask | Button3Mask |
451                                 Button4Mask | Button5Mask);
452
453                    /*
454                     * watch out for changing screens
455                     */
456                    if (firsttime) {
457                        if (root != Scr->Root) {
458                            int scrnum;
459
460                            for (scrnum = 0; scrnum < NumScreens; scrnum++) {
461                                if (root == RootWindow(dpy, scrnum))
462                                    break;
463                            }
464
465                            if (scrnum != NumScreens)
466                                PreviousScreen = scrnum;
467                        }
468                        firsttime = False;
469                    }
470
471                    /*
472                     * wait for buttons to come up; yuck
473                     */
474                    if (mask != 0)
475                        continue;
476
477                    /*
478                     * this will cause a warp to the indicated root
479                     */
480                    stat = XGrabPointer(dpy, Scr->Root, False,
481                                        ButtonPressMask | ButtonReleaseMask |
482                                        PointerMotionMask |
483                                        PointerMotionHintMask, GrabModeAsync,
484                                        GrabModeAsync, Scr->Root,
485                                        UpperLeftCursor, CurrentTime);
486
487                    if (stat == GrabSuccess)
488                        break;
489                }
490
491                width = (SIZE_HINDENT + MyFont_TextWidth(&Scr->SizeFont,
492                                                         tmp_win->name,
493                                                         namelen));
494                height = Scr->SizeFont.height + SIZE_VINDENT * 2;
495
496                XResizeWindow(dpy, Scr->SizeWindow,
497                              (unsigned) (width + SIZE_HINDENT),
498                              (unsigned) height);
499                XMapRaised(dpy, Scr->SizeWindow);
500                InstallRootColormap();
501
502                MyFont_ChangeGC(Scr->DefaultC.fore, Scr->DefaultC.back,
503                                &Scr->SizeFont);
504                MyFont_DrawImageString(dpy, Scr->SizeWindow, &Scr->SizeFont,
505                                       Scr->NormalGC,
506                                       SIZE_HINDENT,
507                                       SIZE_VINDENT + Scr->SizeFont.ascent,
508                                       tmp_win->name, namelen);
509
510                AddingW = tmp_win->attr.width + bw2;
511                AddingH = tmp_win->attr.height + tmp_win->title_height + bw2;
512
513                if (Scr->DontMoveOff) {
514                    /*
515                     * Make sure the initial outline comes up on the screen.
516                     */
517                    if (AddingX < 0)
518                        AddingX = 0;
519                    if (AddingX > Scr->MyDisplayWidth - AddingW)
520                        AddingX = Scr->MyDisplayWidth - AddingW;
521
522                    if (AddingY < 0)
523                        AddingY = 0;
524                    if (AddingY > Scr->MyDisplayHeight - AddingH)
525                        AddingY = Scr->MyDisplayHeight - AddingH;
526                }
527
528                MoveOutline(Scr->Root, AddingX, AddingY, AddingW, AddingH,
529                            tmp_win->frame_bw, tmp_win->title_height);
530
531                while (TRUE) {
532                    XMaskEvent(dpy, ButtonPressMask | PointerMotionMask,
533                               &event);
534
535                    if (Event.type == MotionNotify) {
536                        /* discard any extra motion events before a release */
537                        while (XCheckMaskEvent(dpy,
538                                               ButtonMotionMask |
539                                               ButtonPressMask, &Event))
540                            if (Event.type == ButtonPress)
541                                break;
542                    }
543
544                    if (event.type == ButtonPress) {
545                        AddingX = event.xbutton.x_root;
546                        AddingY = event.xbutton.y_root;
547
548                        /* DontMoveOff prohibits user form off-screen placement */
549                        if (Scr->DontMoveOff) {
550                            int AddingR, AddingB;
551
552                            AddingR = AddingX + AddingW;
553                            AddingB = AddingY + AddingH;
554
555                            if (AddingX < 0)
556                                AddingX = 0;
557                            if (AddingR > Scr->MyDisplayWidth)
558                                AddingX = Scr->MyDisplayWidth - AddingW;
559
560                            if (AddingY < 0)
561                                AddingY = 0;
562                            if (AddingB > Scr->MyDisplayHeight)
563                                AddingY = Scr->MyDisplayHeight - AddingH;
564
565                        }
566                        break;
567                    }
568
569                    if (event.type != MotionNotify) {
570                        continue;
571                    }
572
573                    XQueryPointer(dpy, Scr->Root, &wdummy, &wdummy,
574                                  &dummy, &dummy, &AddingX, &AddingY,
575                                  &udummy);
576
577                    if (Scr->DontMoveOff) {
578                        int AddingR, AddingB;
579
580                        AddingR = AddingX + AddingW;
581                        AddingB = AddingY + AddingH;
582
583                        if (AddingX < 0)
584                            AddingX = 0;
585                        if (AddingR > Scr->MyDisplayWidth)
586                            AddingX = Scr->MyDisplayWidth - AddingW;
587
588                        if (AddingY < 0)
589                            AddingY = 0;
590                        if (AddingB > Scr->MyDisplayHeight)
591                            AddingY = Scr->MyDisplayHeight - AddingH;
592                    }
593
594                    MoveOutline(Scr->Root, AddingX, AddingY, AddingW, AddingH,
595                                tmp_win->frame_bw, tmp_win->title_height);
596
597                }
598
599                if (event.xbutton.button == Button2) {
600                    int lastx, lasty;
601
602                    Scr->SizeStringOffset = width +
603                        MyFont_TextWidth(&Scr->SizeFont, ": ", 2);
604                    XResizeWindow(dpy, Scr->SizeWindow,
605                                  (unsigned) (Scr->SizeStringOffset +
606                                              Scr->SizeStringWidth),
607                                  (unsigned) height);
608                    MyFont_DrawImageString(dpy, Scr->SizeWindow, &Scr->SizeFont,
609                                           Scr->NormalGC, width,
610                                           SIZE_VINDENT + Scr->SizeFont.ascent,
611                                           ": ", 2);
612                    if (0 /*Scr->AutoRelativeResize */ ) {
613                        int dx = (tmp_win->attr.width / 4);
614                        int dy = (tmp_win->attr.height / 4);
615
616#define HALF_AVE_CURSOR_SIZE 8  /* so that it is visible */
617                        if (dx < HALF_AVE_CURSOR_SIZE)
618                            dx = HALF_AVE_CURSOR_SIZE;
619                        if (dy < HALF_AVE_CURSOR_SIZE)
620                            dy = HALF_AVE_CURSOR_SIZE;
621#undef HALF_AVE_CURSOR_SIZE
622                        dx += (tmp_win->frame_bw + 1);
623                        dy += (bw2 + tmp_win->title_height + 1);
624                        if (AddingX + dx >= Scr->MyDisplayWidth)
625                            dx = Scr->MyDisplayWidth - AddingX - 1;
626                        if (AddingY + dy >= Scr->MyDisplayHeight)
627                            dy = Scr->MyDisplayHeight - AddingY - 1;
628                        if (dx > 0 && dy > 0)
629                            XWarpPointer(dpy, None, None, 0, 0, 0, 0, dx, dy);
630                    }
631                    else {
632                        XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0,
633                                     AddingX + AddingW / 2,
634                                     AddingY + AddingH / 2);
635                    }
636                    AddStartResize(tmp_win, AddingX, AddingY, AddingW, AddingH);
637
638                    lastx = -10000;
639                    lasty = -10000;
640                    while (TRUE) {
641                        XMaskEvent(dpy,
642                                   ButtonReleaseMask | ButtonMotionMask,
643                                   &event);
644
645                        if (Event.type == MotionNotify) {
646                            /* discard any extra motion events before a release */
647                            while (XCheckMaskEvent(dpy,
648                                                   ButtonMotionMask |
649                                                   ButtonReleaseMask, &Event))
650                                if (Event.type == ButtonRelease)
651                                    break;
652                        }
653
654                        if (event.type == ButtonRelease) {
655                            AddEndResize(tmp_win);
656                            break;
657                        }
658
659                        if (event.type != MotionNotify) {
660                            continue;
661                        }
662
663                        /*
664                         * XXX - if we are going to do a loop, we ought to consider
665                         * using multiple GXxor lines so that we don't need to
666                         * grab the server.
667                         */
668                        XQueryPointer(dpy, Scr->Root, &wdummy, &wdummy,
669                                      &dummy, &dummy, &AddingX, &AddingY,
670                                      &udummy);
671
672                        if (lastx != AddingX || lasty != AddingY) {
673                            DoResize(AddingX, AddingY, tmp_win);
674
675                            lastx = AddingX;
676                            lasty = AddingY;
677                        }
678
679                    }
680                }
681                else if (event.xbutton.button == Button3) {
682                    int maxw = Scr->MyDisplayWidth - AddingX;
683                    int maxh = Scr->MyDisplayHeight - AddingY;
684
685                    /*
686                     * Make window go to bottom of screen, and clip to right edge.
687                     * This is useful when popping up large windows and fixed
688                     * column text windows.
689                     */
690                    if (AddingW > maxw)
691                        AddingW = maxw;
692                    AddingH = maxh;
693
694                    AddingW -= bw2;
695                    AddingH -= bw2;
696                    ConstrainSize(tmp_win, &AddingW, &AddingH); /* w/o borders */
697                    AddingW += bw2;
698                    AddingH += bw2;
699                }
700                else {
701                    XMaskEvent(dpy, ButtonReleaseMask, &event);
702                }
703
704                MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
705                XUnmapWindow(dpy, Scr->SizeWindow);
706                UninstallRootColormap();
707                XUngrabPointer(dpy, CurrentTime);
708
709                tmp_win->attr.x = AddingX;
710                tmp_win->attr.y = AddingY + tmp_win->title_height;
711                tmp_win->attr.width = AddingW - bw2;
712                tmp_win->attr.height = AddingH - tmp_win->title_height - bw2;
713
714                XUngrabServer(dpy);
715            }
716        }
717    }
718    else {                      /* put it where asked, mod title bar */
719        /* if the gravity is towards the top, move it by the title height */
720        if (gravy < 0)
721            tmp_win->attr.y -= gravy * tmp_win->title_height;
722    }
723
724#ifdef DEBUG
725    fprintf(stderr, "  position window  %d, %d  %dx%d\n",
726            tmp_win->attr.x,
727            tmp_win->attr.y, tmp_win->attr.width, tmp_win->attr.height);
728#endif
729
730    if (!Scr->ClientBorderWidth) {      /* need to adjust for twm borders */
731        int delta = tmp_win->attr.border_width - tmp_win->frame_bw;
732
733        tmp_win->attr.x += gravx * delta;
734        tmp_win->attr.y += gravy * delta;
735    }
736
737    tmp_win->title_width = tmp_win->attr.width;
738
739    if (tmp_win->old_bw)
740        XSetWindowBorderWidth(dpy, tmp_win->w, 0);
741
742    tmp_win->name_width = MyFont_TextWidth(&Scr->TitleBarFont, tmp_win->name,
743                                           namelen);
744
745    if (!I18N_GetIconName(dpy, tmp_win->w, &name)) {
746        tmp_win->icon_name = strdup(tmp_win->name);
747    }
748    else {
749        if (name == NULL) {
750            tmp_win->icon_name = strdup(tmp_win->name);
751        }
752        else {
753            tmp_win->icon_name = strdup(name);
754            free(name);
755        }
756    }
757
758    tmp_win->iconified = FALSE;
759    tmp_win->icon = FALSE;
760    tmp_win->icon_on = FALSE;
761
762    XGrabServer(dpy);
763
764    /*
765     * Make sure the client window still exists.  We don't want to leave an
766     * orphan frame window if it doesn't.  Since we now have the server
767     * grabbed, the window can't disappear later without having been
768     * reparented, so we'll get a DestroyNotify for it.  We won't have
769     * gotten one for anything up to here, however.
770     */
771    if (XGetGeometry(dpy, tmp_win->w, &wdummy, &dummy, &dummy,
772                     &udummy, &udummy, &udummy, &udummy) == 0) {
773        free(tmp_win);
774        XUngrabServer(dpy);
775        return (NULL);
776    }
777
778    /* add the window into the twm list */
779    tmp_win->next = Scr->TwmRoot.next;
780    if (Scr->TwmRoot.next != NULL)
781        Scr->TwmRoot.next->prev = tmp_win;
782    tmp_win->prev = &Scr->TwmRoot;
783    Scr->TwmRoot.next = tmp_win;
784
785    /* get all the colors for the window */
786
787    tmp_win->border = Scr->BorderColor;
788    tmp_win->icon_border = Scr->IconBorderColor;
789    tmp_win->border_tile.fore = Scr->BorderTileC.fore;
790    tmp_win->border_tile.back = Scr->BorderTileC.back;
791    tmp_win->title.fore = Scr->TitleC.fore;
792    tmp_win->title.back = Scr->TitleC.back;
793    tmp_win->iconc.fore = Scr->IconC.fore;
794    tmp_win->iconc.back = Scr->IconC.back;
795
796    GetColorFromList(Scr->BorderColorL, tmp_win->full_name,
797                     &tmp_win->xclass, &tmp_win->border);
798    GetColorFromList(Scr->IconBorderColorL, tmp_win->full_name,
799                     &tmp_win->xclass, &tmp_win->icon_border);
800    GetColorFromList(Scr->BorderTileForegroundL, tmp_win->full_name,
801                     &tmp_win->xclass, &tmp_win->border_tile.fore);
802    GetColorFromList(Scr->BorderTileBackgroundL, tmp_win->full_name,
803                     &tmp_win->xclass, &tmp_win->border_tile.back);
804    GetColorFromList(Scr->TitleForegroundL, tmp_win->full_name,
805                     &tmp_win->xclass, &tmp_win->title.fore);
806    GetColorFromList(Scr->TitleBackgroundL, tmp_win->full_name,
807                     &tmp_win->xclass, &tmp_win->title.back);
808    GetColorFromList(Scr->IconForegroundL, tmp_win->full_name,
809                     &tmp_win->xclass, &tmp_win->iconc.fore);
810    GetColorFromList(Scr->IconBackgroundL, tmp_win->full_name,
811                     &tmp_win->xclass, &tmp_win->iconc.back);
812
813    /* create windows */
814
815    tmp_win->frame_x = tmp_win->attr.x + tmp_win->old_bw - tmp_win->frame_bw;
816    tmp_win->frame_y = tmp_win->attr.y - tmp_win->title_height +
817        tmp_win->old_bw - tmp_win->frame_bw;
818    tmp_win->frame_width = tmp_win->attr.width;
819    tmp_win->frame_height = tmp_win->attr.height + tmp_win->title_height;
820
821    valuemask = CWBackPixmap | CWBorderPixel | CWCursor | CWEventMask;
822    attributes.background_pixmap = None;
823    attributes.border_pixel = tmp_win->border;
824    attributes.cursor = Scr->FrameCursor;
825    attributes.event_mask = (SubstructureRedirectMask |
826                             ButtonPressMask | ButtonReleaseMask |
827                             EnterWindowMask | LeaveWindowMask);
828    if (tmp_win->attr.save_under) {
829        attributes.save_under = True;
830        valuemask |= CWSaveUnder;
831    }
832
833    tmp_win->frame = XCreateWindow(dpy, Scr->Root, tmp_win->frame_x,
834                                   tmp_win->frame_y,
835                                   (unsigned int) tmp_win->frame_width,
836                                   (unsigned int) tmp_win->frame_height,
837                                   (unsigned int) tmp_win->frame_bw,
838                                   Scr->d_depth,
839                                   (unsigned int) CopyFromParent,
840                                   Scr->d_visual, valuemask, &attributes);
841
842    if (tmp_win->title_height) {
843        valuemask = (CWEventMask | CWBorderPixel | CWBackPixel);
844        attributes.event_mask = (KeyPressMask | ButtonPressMask |
845                                 ButtonReleaseMask | ExposureMask);
846        attributes.border_pixel = tmp_win->border;
847        attributes.background_pixel = tmp_win->title.back;
848        tmp_win->title_w = XCreateWindow(dpy, tmp_win->frame,
849                                         -tmp_win->frame_bw,
850                                         -tmp_win->frame_bw,
851                                         (unsigned int) tmp_win->attr.width,
852                                         (unsigned int) Scr->TitleHeight,
853                                         (unsigned int) tmp_win->frame_bw,
854                                         Scr->d_depth,
855                                         (unsigned int) CopyFromParent,
856                                         Scr->d_visual, valuemask, &attributes);
857    }
858    else {
859        tmp_win->title_w = 0;
860        tmp_win->squeeze_info = NULL;
861    }
862
863    if (tmp_win->highlight) {
864        tmp_win->gray = XCreatePixmapFromBitmapData(dpy, Scr->Root,
865                                                    gray_bits, gray_width,
866                                                    gray_height,
867                                                    tmp_win->border_tile.fore,
868                                                    tmp_win->border_tile.back,
869                                                    (unsigned) Scr->d_depth);
870
871        SetBorder(tmp_win, False);
872    }
873    else
874        tmp_win->gray = None;
875
876    if (tmp_win->title_w) {
877        CreateWindowTitlebarButtons(tmp_win);
878        ComputeTitleLocation(tmp_win);
879        XMoveWindow(dpy, tmp_win->title_w, tmp_win->title_x, tmp_win->title_y);
880        XDefineCursor(dpy, tmp_win->title_w, Scr->TitleCursor);
881    }
882
883    valuemask = (CWEventMask | CWDontPropagate);
884    attributes.event_mask = (StructureNotifyMask | PropertyChangeMask |
885                             ColormapChangeMask | VisibilityChangeMask |
886                             EnterWindowMask | LeaveWindowMask);
887    attributes.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask;
888    XChangeWindowAttributes(dpy, tmp_win->w, valuemask, &attributes);
889
890    if (HasShape)
891        XShapeSelectInput(dpy, tmp_win->w, ShapeNotifyMask);
892
893    if (tmp_win->title_w) {
894        XMapWindow(dpy, tmp_win->title_w);
895    }
896
897    if (HasShape) {
898        int xws, yws, xbs, ybs;
899        unsigned wws, hws, wbs, hbs;
900        int boundingShaped, clipShaped;
901
902        XShapeSelectInput(dpy, tmp_win->w, ShapeNotifyMask);
903        XShapeQueryExtents(dpy, tmp_win->w,
904                           &boundingShaped, &xws, &yws, &wws, &hws,
905                           &clipShaped, &xbs, &ybs, &wbs, &hbs);
906        tmp_win->wShaped = (short) boundingShaped;
907    }
908
909    if (!tmp_win->iconmgr)
910        XAddToSaveSet(dpy, tmp_win->w);
911
912    XReparentWindow(dpy, tmp_win->w, tmp_win->frame, 0, tmp_win->title_height);
913    /*
914     * Reparenting generates an UnmapNotify event, followed by a MapNotify.
915     * Set the map state to FALSE to prevent a transition back to
916     * WithdrawnState in HandleUnmapNotify.  Map state gets set correctly
917     * again in HandleMapNotify.
918     */
919    tmp_win->mapped = FALSE;
920
921    SetupFrame(tmp_win, tmp_win->frame_x, tmp_win->frame_y,
922               tmp_win->frame_width, tmp_win->frame_height, -1, True);
923
924    /* wait until the window is iconified and the icon window is mapped
925     * before creating the icon window
926     */
927    tmp_win->icon_w = (Window) 0;
928
929    if (!tmp_win->iconmgr) {
930        GrabButtons(tmp_win);
931        GrabKeys(tmp_win);
932    }
933
934    (void) AddIconManager(tmp_win);
935
936    XSaveContext(dpy, tmp_win->w, TwmContext, (XPointer) tmp_win);
937    XSaveContext(dpy, tmp_win->w, ScreenContext, (XPointer) Scr);
938    XSaveContext(dpy, tmp_win->frame, TwmContext, (XPointer) tmp_win);
939    XSaveContext(dpy, tmp_win->frame, ScreenContext, (XPointer) Scr);
940    if (tmp_win->title_height) {
941        int i;
942        int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
943
944        XSaveContext(dpy, tmp_win->title_w, TwmContext, (XPointer) tmp_win);
945        XSaveContext(dpy, tmp_win->title_w, ScreenContext, (XPointer) Scr);
946        for (i = 0; i < nb; i++) {
947            XSaveContext(dpy, tmp_win->titlebuttons[i].window, TwmContext,
948                         (XPointer) tmp_win);
949            XSaveContext(dpy, tmp_win->titlebuttons[i].window, ScreenContext,
950                         (XPointer) Scr);
951        }
952        if (tmp_win->hilite_w) {
953            XSaveContext(dpy, tmp_win->hilite_w, TwmContext,
954                         (XPointer) tmp_win);
955            XSaveContext(dpy, tmp_win->hilite_w, ScreenContext, (XPointer) Scr);
956        }
957    }
958
959    XUngrabServer(dpy);
960
961    /* if we were in the middle of a menu activated function, regrab
962     * the pointer
963     */
964    if (RootFunction)
965        ReGrab();
966
967    return (tmp_win);
968}
969
970/**
971 * checks to see if we should really put a twm frame on the window
972 *
973 *  \return TRUE  - go ahead and place the window
974 *  \return FALSE - don't frame the window
975 *      \param w the window to check
976 */
977int
978MappedNotOverride(Window w)
979{
980    XWindowAttributes wa;
981
982    XGetWindowAttributes(dpy, w, &wa);
983    return ((wa.map_state != IsUnmapped) && (wa.override_redirect != True));
984}
985
986/**
987 * attach default bindings so that naive users don't get messed up if they
988 * provide a minimal twmrc.
989 */
990static void
991do_add_binding(int button, int context, int modifier, int func)
992{
993    MouseButton *mb = &Scr->Mouse[button][context][modifier];
994
995    if (mb->func)
996        return;                 /* already defined */
997
998    mb->func = func;
999    mb->item = NULL;
1000}
1001
1002void
1003AddDefaultBindings(void)
1004{
1005    /*
1006     * The bindings are stored in Scr->Mouse, indexed by
1007     * Mouse[button_number][C_context][modifier].
1008     */
1009
1010#define NoModifierMask 0
1011
1012    do_add_binding(Button1, C_TITLE, NoModifierMask, F_MOVE);
1013    do_add_binding(Button1, C_ICON, NoModifierMask, F_ICONIFY);
1014    do_add_binding(Button1, C_ICONMGR, NoModifierMask, F_ICONIFY);
1015
1016    do_add_binding(Button2, C_TITLE, NoModifierMask, F_RAISELOWER);
1017    do_add_binding(Button2, C_ICON, NoModifierMask, F_ICONIFY);
1018    do_add_binding(Button2, C_ICONMGR, NoModifierMask, F_ICONIFY);
1019
1020#undef NoModifierMask
1021}
1022
1023/**
1024 * grab needed buttons for the window
1025 *
1026 *  \param[in] tmp_win the twm window structure to use
1027 */
1028void
1029GrabButtons(TwmWindow *tmp_win)
1030{
1031    int i, j;
1032
1033    for (i = 0; i < MAX_BUTTONS + 1; i++) {
1034        for (j = 0; j < MOD_SIZE; j++) {
1035            if (Scr->Mouse[i][C_WINDOW][j].func != 0) {
1036                /* twm used to do this grab on the application main window,
1037                 * tmp_win->w . This was not ICCCM compliant and was changed.
1038                 */
1039                XGrabButton(dpy, (unsigned) i, (unsigned) j, tmp_win->frame,
1040                            True, ButtonPressMask | ButtonReleaseMask,
1041                            GrabModeAsync, GrabModeAsync, None,
1042                            Scr->FrameCursor);
1043            }
1044        }
1045    }
1046}
1047
1048/**
1049 * grab needed keys for the window
1050 *
1051 *  \param[in] tmp_win the twm window structure to use
1052 */
1053void
1054GrabKeys(TwmWindow *tmp_win)
1055{
1056    FuncKey *tmp;
1057    IconMgr *p;
1058
1059    for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next) {
1060        switch (tmp->cont) {
1061        case C_WINDOW:
1062            XGrabKey(dpy, tmp->keycode, (unsigned) tmp->mods, tmp_win->w, True,
1063                     GrabModeAsync, GrabModeAsync);
1064            break;
1065
1066        case C_ICON:
1067            if (tmp_win->icon_w)
1068                XGrabKey(dpy, tmp->keycode, (unsigned) tmp->mods,
1069                         tmp_win->icon_w, True, GrabModeAsync, GrabModeAsync);
1070            /* FALLTHRU */
1071
1072        case C_TITLE:
1073            if (tmp_win->title_w)
1074                XGrabKey(dpy, tmp->keycode, (unsigned) tmp->mods,
1075                         tmp_win->title_w, True, GrabModeAsync, GrabModeAsync);
1076            break;
1077
1078        case C_NAME:
1079            XGrabKey(dpy, tmp->keycode, (unsigned) tmp->mods, tmp_win->w, True,
1080                     GrabModeAsync, GrabModeAsync);
1081            if (tmp_win->icon_w)
1082                XGrabKey(dpy, tmp->keycode, (unsigned) tmp->mods,
1083                         tmp_win->icon_w, True, GrabModeAsync, GrabModeAsync);
1084            if (tmp_win->title_w)
1085                XGrabKey(dpy, tmp->keycode, (unsigned) tmp->mods,
1086                         tmp_win->title_w, True, GrabModeAsync, GrabModeAsync);
1087            break;
1088            /*
1089               case C_ROOT:
1090               XGrabKey(dpy, tmp->keycode, tmp->mods, Scr->Root, True,
1091               GrabModeAsync, GrabModeAsync);
1092               break;
1093             */
1094        }
1095    }
1096    for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next) {
1097        if (tmp->cont == C_ICONMGR && !Scr->NoIconManagers) {
1098            for (p = &Scr->iconmgr; p != NULL; p = p->next) {
1099                XUngrabKey(dpy, tmp->keycode, (unsigned) tmp->mods,
1100                           p->twm_win->w);
1101            }
1102        }
1103    }
1104}
1105
1106static Window
1107CreateHighlightWindow(TwmWindow *tmp_win)
1108{
1109    XSetWindowAttributes attributes;    /* attributes for create windows */
1110    Pixmap pm = None;
1111    GC gc;
1112    XGCValues gcv;
1113    unsigned long valuemask;
1114    int h = (Scr->TitleHeight - 2 * Scr->FramePadding);
1115    Window w;
1116
1117    /*
1118     * If a special highlight pixmap was given, use that.  Otherwise,
1119     * use a nice, even gray pattern.  The old horizontal lines look really
1120     * awful on interlaced monitors (as well as resembling other looks a
1121     * little bit too closely), but can be used by putting
1122     *
1123     *                 Pixmaps { TitleHighlight "hline2" }
1124     *
1125     * (or whatever the horizontal line bitmap is named) in the startup
1126     * file.  If all else fails, use the foreground color to look like a
1127     * solid line.
1128     */
1129    if (!Scr->hilitePm) {
1130        Scr->hilitePm = XCreateBitmapFromData(dpy, tmp_win->title_w,
1131                                              gray_bits, gray_width,
1132                                              gray_height);
1133        Scr->hilite_pm_width = gray_width;
1134        Scr->hilite_pm_height = gray_height;
1135    }
1136    if (Scr->hilitePm) {
1137        pm = XCreatePixmap(dpy, tmp_win->title_w,
1138                           (unsigned) Scr->hilite_pm_width,
1139                           (unsigned) Scr->hilite_pm_height,
1140                           (unsigned) Scr->d_depth);
1141        gcv.foreground = tmp_win->title.fore;
1142        gcv.background = tmp_win->title.back;
1143        gcv.graphics_exposures = False;
1144        gc = XCreateGC(dpy, pm,
1145                       (GCForeground | GCBackground | GCGraphicsExposures),
1146                       &gcv);
1147        if (gc) {
1148            XCopyPlane(dpy, Scr->hilitePm, pm, gc, 0, 0,
1149                       (unsigned) Scr->hilite_pm_width,
1150                       (unsigned) Scr->hilite_pm_height, 0, 0, 1);
1151            XFreeGC(dpy, gc);
1152        }
1153        else {
1154            XFreePixmap(dpy, pm);
1155            pm = None;
1156        }
1157    }
1158    if (pm) {
1159        valuemask = CWBackPixmap;
1160        attributes.background_pixmap = pm;
1161    }
1162    else {
1163        valuemask = CWBackPixel;
1164        attributes.background_pixel = tmp_win->title.fore;
1165    }
1166
1167    w = XCreateWindow(dpy, tmp_win->title_w, 0, Scr->FramePadding,
1168                      (unsigned int) Scr->TBInfo.width, (unsigned int) h,
1169                      (unsigned int) 0,
1170                      Scr->d_depth, (unsigned int) CopyFromParent,
1171                      Scr->d_visual, valuemask, &attributes);
1172    if (pm)
1173        XFreePixmap(dpy, pm);
1174    return w;
1175}
1176
1177void
1178ComputeCommonTitleOffsets(void)
1179{
1180    int buttonwidth = (Scr->TBInfo.width + Scr->TBInfo.pad);
1181
1182    Scr->TBInfo.leftx = Scr->TBInfo.rightoff = Scr->FramePadding;
1183    if (Scr->TBInfo.nleft > 0)
1184        Scr->TBInfo.leftx += Scr->ButtonIndent;
1185    Scr->TBInfo.titlex = (Scr->TBInfo.leftx +
1186                          (Scr->TBInfo.nleft * buttonwidth) -
1187                          Scr->TBInfo.pad + Scr->TitlePadding);
1188    if (Scr->TBInfo.nright > 0)
1189        Scr->TBInfo.rightoff += (Scr->ButtonIndent +
1190                                 ((Scr->TBInfo.nright * buttonwidth) -
1191                                  Scr->TBInfo.pad));
1192    return;
1193}
1194
1195void
1196ComputeWindowTitleOffsets(TwmWindow *tmp_win, int width, Bool squeeze)
1197{
1198    tmp_win->highlightx = (Scr->TBInfo.titlex + tmp_win->name_width);
1199    if (tmp_win->hilite_w || Scr->TBInfo.nright > 0)
1200        tmp_win->highlightx += Scr->TitlePadding;
1201    tmp_win->rightx = width - Scr->TBInfo.rightoff;
1202    if (squeeze && tmp_win->squeeze_info) {
1203        int rx = (tmp_win->highlightx +
1204                  (tmp_win->hilite_w
1205                   ? Scr->TBInfo.width * 2 : 0) +
1206                  (Scr->TBInfo.nright > 0 ? Scr->TitlePadding : 0) +
1207                  Scr->FramePadding);
1208        if (rx < tmp_win->rightx)
1209            tmp_win->rightx = rx;
1210    }
1211    return;
1212}
1213
1214/**
1215 * calculate the position of the title window.  We need to take the frame_bw
1216 * into account since we want (0,0) of the title window to line up with (0,0)
1217 * of the frame window.
1218 */
1219void
1220ComputeTitleLocation(TwmWindow *tmp)
1221{
1222    tmp->title_x = -tmp->frame_bw;
1223    tmp->title_y = -tmp->frame_bw;
1224
1225    if (tmp->squeeze_info) {
1226        SqueezeInfo *si = tmp->squeeze_info;
1227        int basex;
1228        int maxwidth = tmp->frame_width;
1229        int tw = tmp->title_width;
1230
1231        /*
1232         * figure label base from squeeze info (justification fraction)
1233         */
1234        if (si->denom == 0) {   /* num is pixel based */
1235            if ((basex = si->num) == 0) {       /* look for special cases */
1236                switch (si->justify) {
1237                case J_RIGHT:
1238                    basex = maxwidth;
1239                    break;
1240                case J_CENTER:
1241                    basex = maxwidth / 2;
1242                    break;
1243                }
1244            }
1245        }
1246        else {                  /* num/denom is fraction */
1247            basex = ((si->num * maxwidth) / si->denom);
1248            if (si->num < 0)
1249                basex += maxwidth;
1250        }
1251
1252        /*
1253         * adjust for left (nop), center, right justify and clip
1254         */
1255        switch (si->justify) {
1256        case J_CENTER:
1257            basex -= tw / 2;
1258            break;
1259        case J_RIGHT:
1260            basex -= tw - 1;
1261            break;
1262        }
1263        if (basex > maxwidth - tw + 1)
1264            basex = maxwidth - tw + 1;
1265        if (basex < 0)
1266            basex = 0;
1267
1268        tmp->title_x = basex - tmp->frame_bw;
1269    }
1270}
1271
1272static void
1273CreateWindowTitlebarButtons(TwmWindow *tmp_win)
1274{
1275    unsigned long valuemask;    /* mask for create windows */
1276    XSetWindowAttributes attributes;    /* attributes for create windows */
1277    int leftx, rightx, y;
1278    TitleButton *tb;
1279    int nb;
1280
1281    if (tmp_win->title_height == 0) {
1282        tmp_win->hilite_w = 0;
1283        return;
1284    }
1285
1286    /*
1287     * create the title bar windows; let the event handler deal with painting
1288     * so that we don't have to spend two pixmaps (or deal with hashing)
1289     */
1290    ComputeWindowTitleOffsets(tmp_win, tmp_win->attr.width, False);
1291
1292    leftx = y = Scr->TBInfo.leftx;
1293    rightx = tmp_win->rightx;
1294
1295    attributes.win_gravity = NorthWestGravity;
1296    attributes.background_pixel = tmp_win->title.back;
1297    attributes.border_pixel = tmp_win->title.fore;
1298    attributes.event_mask = (ButtonPressMask | ButtonReleaseMask |
1299                             ExposureMask);
1300    attributes.cursor = Scr->ButtonCursor;
1301    valuemask = (CWWinGravity | CWBackPixel | CWBorderPixel | CWEventMask |
1302                 CWCursor);
1303
1304    tmp_win->titlebuttons = NULL;
1305    nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
1306    if (nb > 0) {
1307        tmp_win->titlebuttons = (TBWindow *)
1308            malloc((size_t) nb * sizeof(TBWindow));
1309        if (!tmp_win->titlebuttons) {
1310            twmWarning("unable to allocate %d titlebuttons", nb);
1311        }
1312        else {
1313            TBWindow *tbw;
1314            int boxwidth = (Scr->TBInfo.width + Scr->TBInfo.pad);
1315            unsigned h =
1316                (unsigned) (Scr->TBInfo.width - Scr->TBInfo.border * 2);
1317
1318            for (tb = Scr->TBInfo.head, tbw = tmp_win->titlebuttons; tb;
1319                 tb = tb->next, tbw++) {
1320                int x;
1321
1322                if (tb->rightside) {
1323                    x = rightx;
1324                    rightx += boxwidth;
1325                    attributes.win_gravity = NorthEastGravity;
1326                }
1327                else {
1328                    x = leftx;
1329                    leftx += boxwidth;
1330                    attributes.win_gravity = NorthWestGravity;
1331                }
1332                tbw->window = XCreateWindow(dpy, tmp_win->title_w, x, y, h, h,
1333                                            (unsigned int) Scr->TBInfo.border,
1334                                            0, (unsigned int) CopyFromParent,
1335                                            (Visual *) CopyFromParent,
1336                                            valuemask, &attributes);
1337                tbw->info = tb;
1338            }
1339        }
1340    }
1341
1342    tmp_win->hilite_w = (tmp_win->titlehighlight
1343                         ? CreateHighlightWindow(tmp_win) : None);
1344
1345    XMapSubwindows(dpy, tmp_win->title_w);
1346    if (tmp_win->hilite_w)
1347        XUnmapWindow(dpy, tmp_win->hilite_w);
1348    return;
1349}
1350
1351void
1352SetHighlightPixmap(char *filename)
1353{
1354    unsigned width = 0;
1355    unsigned height = 0;
1356
1357    Pixmap pm = FindBitmap(filename, &width, &height);
1358
1359    if (pm) {
1360        if (Scr->hilitePm) {
1361            XFreePixmap(dpy, Scr->hilitePm);
1362        }
1363        Scr->hilitePm = pm;
1364        Scr->hilite_pm_width = (int) width;
1365        Scr->hilite_pm_height = (int) height;
1366    }
1367}
1368
1369void
1370FetchWmProtocols(TwmWindow *tmp)
1371{
1372    unsigned long flags = 0L;
1373    Atom *protocols = NULL;
1374    int n;
1375
1376    if (XGetWMProtocols(dpy, tmp->w, &protocols, &n)) {
1377        int i;
1378        Atom *ap;
1379
1380        for (i = 0, ap = protocols; i < n; i++, ap++) {
1381            if (*ap == _XA_WM_TAKE_FOCUS)
1382                flags |= DoesWmTakeFocus;
1383            if (*ap == _XA_WM_SAVE_YOURSELF)
1384                flags |= DoesWmSaveYourself;
1385            if (*ap == _XA_WM_DELETE_WINDOW)
1386                flags |= DoesWmDeleteWindow;
1387        }
1388        if (protocols)
1389            XFree(protocols);
1390    }
1391    tmp->protocols = flags;
1392}
1393
1394TwmColormap *
1395CreateTwmColormap(Colormap c)
1396{
1397    TwmColormap *cmap;
1398
1399    cmap = (TwmColormap *) calloc(1, sizeof(TwmColormap));
1400    if (!cmap || XSaveContext(dpy, c, ColormapContext, (XPointer) cmap)) {
1401        if (cmap)
1402            free(cmap);
1403        return (NULL);
1404    }
1405    cmap->c = c;
1406    cmap->state = 0;
1407    cmap->install_req = 0;
1408    cmap->w = None;
1409    cmap->refcnt = 1;
1410    return (cmap);
1411}
1412
1413ColormapWindow *
1414CreateColormapWindow(Window w, Bool creating_parent, Bool property_window)
1415{
1416    ColormapWindow *cwin;
1417    TwmColormap *cmap;
1418    XWindowAttributes attributes;
1419
1420    cwin = (ColormapWindow *) malloc(sizeof(ColormapWindow));
1421    if (cwin) {
1422        if (!XGetWindowAttributes(dpy, w, &attributes) ||
1423            XSaveContext(dpy, w, ColormapContext, (XPointer) cwin)) {
1424            free(cwin);
1425            return (NULL);
1426        }
1427
1428        if (XFindContext(dpy, attributes.colormap, ColormapContext,
1429                         (XPointer *) &cwin->colormap) == XCNOENT) {
1430            cwin->colormap = cmap = CreateTwmColormap(attributes.colormap);
1431            if (!cmap) {
1432                XDeleteContext(dpy, w, ColormapContext);
1433                free(cwin);
1434                return (NULL);
1435            }
1436        }
1437        else {
1438            cwin->colormap->refcnt++;
1439        }
1440
1441        cwin->w = w;
1442        /*
1443         * Assume that windows in colormap list are
1444         * obscured if we are creating the parent window.
1445         * Otherwise, we assume they are unobscured.
1446         */
1447        cwin->visibility = creating_parent ?
1448            VisibilityPartiallyObscured : VisibilityUnobscured;
1449        cwin->refcnt = 1;
1450
1451        /*
1452         * If this is a ColormapWindow property window and we
1453         * are not monitoring ColormapNotify or VisibilityNotify
1454         * events, we need to.
1455         */
1456        if (property_window &&
1457            (attributes.your_event_mask &
1458             (ColormapChangeMask | VisibilityChangeMask)) !=
1459            (ColormapChangeMask | VisibilityChangeMask)) {
1460            XSelectInput(dpy, w, attributes.your_event_mask |
1461                         (ColormapChangeMask | VisibilityChangeMask));
1462        }
1463    }
1464
1465    return (cwin);
1466}
1467
1468void
1469FetchWmColormapWindows(TwmWindow *tmp)
1470{
1471    int i, j;
1472    Window *cmap_windows = NULL;
1473    Bool can_free_cmap_windows = False;
1474    int number_cmap_windows = 0;
1475    ColormapWindow **cwins = NULL;
1476    int previously_installed;
1477
1478    number_cmap_windows = 0;
1479
1480    /* SUPPRESS 560 */
1481    if ((previously_installed =
1482         (Scr->cmapInfo.cmaps == &tmp->cmaps && tmp->cmaps.number_cwins))) {
1483        cwins = tmp->cmaps.cwins;
1484        for (i = 0; i < tmp->cmaps.number_cwins; i++)
1485            cwins[i]->colormap->state = 0;
1486    }
1487
1488    if (XGetWMColormapWindows(dpy, tmp->w, &cmap_windows,
1489                              &number_cmap_windows) &&
1490        number_cmap_windows > 0) {
1491
1492        can_free_cmap_windows = False;
1493        /*
1494         * check if the top level is in the list, add to front if not
1495         */
1496        for (i = 0; i < number_cmap_windows; i++) {
1497            if (cmap_windows[i] == tmp->w)
1498                break;
1499        }
1500        if (i == number_cmap_windows) { /* not in list */
1501            Window *new_cmap_windows = (Window *)
1502                malloc(sizeof(Window) * (size_t) (number_cmap_windows + 1));
1503
1504            if (!new_cmap_windows) {
1505                twmWarning
1506                    ("unable to allocate %d element colormap window array",
1507                     number_cmap_windows + 1);
1508                goto done;
1509            }
1510            new_cmap_windows[0] = tmp->w;       /* add to front */
1511            for (i = 0; i < number_cmap_windows; i++) { /* append rest */
1512                new_cmap_windows[i + 1] = cmap_windows[i];
1513            }
1514            XFree(cmap_windows);
1515            can_free_cmap_windows = True;       /* do not use XFree any more */
1516            cmap_windows = new_cmap_windows;
1517            number_cmap_windows++;
1518        }
1519
1520        cwins = (ColormapWindow **)
1521            malloc(sizeof(ColormapWindow *) * (size_t) number_cmap_windows);
1522        if (cwins) {
1523            for (i = 0; i < number_cmap_windows; i++) {
1524
1525                /*
1526                 * Copy any existing entries into new list.
1527                 */
1528                for (j = 0; j < tmp->cmaps.number_cwins; j++) {
1529                    if (tmp->cmaps.cwins[j]->w == cmap_windows[i]) {
1530                        cwins[i] = tmp->cmaps.cwins[j];
1531                        cwins[i]->refcnt++;
1532                        break;
1533                    }
1534                }
1535
1536                /*
1537                 * If the colormap window is not being pointed by
1538                 * some other applications colormap window list,
1539                 * create a new entry.
1540                 */
1541                if (j == tmp->cmaps.number_cwins) {
1542                    if (XFindContext(dpy, cmap_windows[i], ColormapContext,
1543                                     (XPointer *) &cwins[i]) == XCNOENT) {
1544                        if ((cwins[i] =
1545                             CreateColormapWindow(cmap_windows[i],
1546                                                  (tmp->cmaps.number_cwins == 0
1547                                                   ? True
1548                                                   : False), True)) == NULL) {
1549                            int k;
1550
1551                            for (k = i + 1; k < number_cmap_windows; k++)
1552                                cmap_windows[k - 1] = cmap_windows[k];
1553                            i--;
1554                            number_cmap_windows--;
1555                        }
1556                    }
1557                    else
1558                        cwins[i]->refcnt++;
1559                }
1560            }
1561        }
1562    }
1563
1564    /* No else here, in case we bailed out of clause above.
1565     */
1566    if (number_cmap_windows == 0) {
1567
1568        number_cmap_windows = 1;
1569
1570        cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *));
1571        if (XFindContext(dpy, tmp->w, ColormapContext, (XPointer *) &cwins[0])
1572            == XCNOENT) {
1573            cwins[0] =
1574                CreateColormapWindow(tmp->w,
1575                                     (Bool) tmp->cmaps.number_cwins == 0,
1576                                     False);
1577            if (cwins[0] == NULL)
1578                number_cmap_windows = 0;
1579        }
1580        else
1581            cwins[0]->refcnt++;
1582    }
1583
1584    if (tmp->cmaps.number_cwins)
1585        free_cwins(tmp);
1586
1587    tmp->cmaps.cwins = cwins;
1588    tmp->cmaps.number_cwins = number_cmap_windows;
1589    if (number_cmap_windows > 1)
1590        tmp->cmaps.scoreboard = (char *)
1591            calloc(1, ColormapsScoreboardLength(&tmp->cmaps));
1592
1593    if (previously_installed)
1594        InstallWindowColormaps(PropertyNotify, (TwmWindow *) NULL);
1595
1596 done:
1597    if (cmap_windows) {
1598        if (can_free_cmap_windows)
1599            free(cmap_windows);
1600        else
1601            XFree(cmap_windows);
1602    }
1603
1604    return;
1605}
1606
1607void
1608GetWindowSizeHints(TwmWindow *tmp)
1609{
1610    long supplied = 0;
1611
1612    if (!XGetWMNormalHints(dpy, tmp->w, &tmp->hints, &supplied))
1613        tmp->hints.flags = 0;
1614
1615    if (tmp->hints.flags & PResizeInc) {
1616        if (tmp->hints.width_inc == 0)
1617            tmp->hints.width_inc = 1;
1618        if (tmp->hints.height_inc == 0)
1619            tmp->hints.height_inc = 1;
1620    }
1621
1622    if (!(supplied & PWinGravity) && (tmp->hints.flags & USPosition)) {
1623        static int gravs[] = { SouthEastGravity, SouthWestGravity,
1624            NorthEastGravity, NorthWestGravity
1625        };
1626        int right = tmp->attr.x + tmp->attr.width + 2 * tmp->old_bw;
1627        int bottom = tmp->attr.y + tmp->attr.height + 2 * tmp->old_bw;
1628
1629        tmp->hints.win_gravity =
1630            gravs[((Scr->MyDisplayHeight - bottom <
1631                    tmp->title_height) ? 0 : 2) | ((Scr->MyDisplayWidth -
1632                                                    right <
1633                                                    tmp->title_height) ? 0 :
1634                                                   1)];
1635        tmp->hints.flags |= PWinGravity;
1636    }
1637}
1638