/*****************************************************************************/ /** Copyright 1988 by Evans & Sutherland Computer Corporation, **/ /** Salt Lake City, Utah **/ /** Portions Copyright 1989 by the Massachusetts Institute of Technology **/ /** Cambridge, Massachusetts **/ /** **/ /** All Rights Reserved **/ /** **/ /** Permission to use, copy, modify, and distribute this software and **/ /** its documentation for any purpose and without fee is hereby **/ /** granted, provided that the above copyright notice appear in all **/ /** copies and that both that copyright notice and this permis- **/ /** sion notice appear in supporting documentation, and that the **/ /** names of Evans & Sutherland and M.I.T. not be used in advertising **/ /** in publicity pertaining to distribution of the software without **/ /** specific, written prior permission. **/ /** **/ /** EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD **/ /** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/ /** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND OR **/ /** M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/ /** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/ /** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/ /** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/ /** OR PERFORMANCE OF THIS SOFTWARE. **/ /*****************************************************************************/ /* * [ ctwm ] * * Copyright 1992 Claude Lecommandeur. * * Permission to use, copy, modify and distribute this software [ctwm] and * its documentation for any purpose is hereby granted without fee, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting documen- * tation, and that the name of Claude Lecommandeur not be used in adverti- * sing or publicity pertaining to distribution of the software without * specific, written prior permission. Claude Lecommandeur make no represen- * tations about the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty. * * Claude Lecommandeur DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO * EVENT SHALL Claude Lecommandeur BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * * Author: Claude Lecommandeur [ lecom@sic.epfl.ch ][ April 1992 ] */ /********************************************************************** * * $XConsortium: add_window.c,v 1.153 91/07/10 13:17:26 dave Exp $ * * Add a new window, put the titlbar and other stuff around * the window * * 31-Mar-88 Tom LaStrange Initial Version. * * Do the necessary modification to be integrated in ctwm. * Can no longer be used for the standard twm. * * 22-April-92 Claude Lecommandeur. * **********************************************************************/ #include #include #ifndef VMS #include #else #include #endif #if defined(AIXV3) || defined(_SYSTYPE_SVR4) || defined(ibm) || defined __QNX__ #include #endif #include "twm.h" #ifdef VMS #include #else #include #endif #include "add_window.h" #include "windowbox.h" #include "util.h" #include "resize.h" #include "parse.h" #include "list.h" #include "events.h" #include "menus.h" #include "screen.h" #include "icons.h" #include "iconmgr.h" #include "session.h" #include "mwmhints.h" #define gray_width 2 #define gray_height 2 static unsigned char gray_bits[] = { 0x02, 0x01}; static unsigned char black_bits[] = { 0xFF, 0xFF}; int AddingX; int AddingY; unsigned int AddingW; unsigned int AddingH; static int PlaceX = -1; static int PlaceY = -1; static void CreateWindowTitlebarButtons(TwmWindow *tmp_win); void DealWithNonSensicalGeometries(Display *dpy, Window vroot, TwmWindow *tmp_win); static void splitWindowRegionEntry (WindowEntry *we, int grav1, int grav2, int w, int h); static WindowEntry *findWindowEntry (WorkSpace *wl, TwmWindow *tmp_win, WindowRegion **wrp); static WindowEntry *prevWindowEntry (WindowEntry *we, WindowRegion *wr); static void mergeWindowEntries (WindowEntry *old, WindowEntry *we); char NoName[] = "Untitled"; /* name if no name is specified */ int resizeWhenAdd; extern Atom _OL_WIN_ATTR; #if defined(__hpux) && !defined(_XPG4_EXTENDED) # define FDSET int* #else # define FDSET fd_set* #endif /************************************************************************ * * Procedure: * GetGravityOffsets - map gravity to (x,y) offset signs for adding * to x and y when window is mapped to get proper placement. * ************************************************************************ */ void GetGravityOffsets (TwmWindow *tmp, /* window from which to get gravity */ int *xp, int *yp) /* return values */ { static struct _gravity_offset { int x, y; } gravity_offsets[11] = { { 0, 0 }, /* ForgetGravity */ { -1, -1 }, /* NorthWestGravity */ { 0, -1 }, /* NorthGravity */ { 1, -1 }, /* NorthEastGravity */ { -1, 0 }, /* WestGravity */ { 0, 0 }, /* CenterGravity */ { 1, 0 }, /* EastGravity */ { -1, 1 }, /* SouthWestGravity */ { 0, 1 }, /* SouthGravity */ { 1, 1 }, /* SouthEastGravity */ { 0, 0 }, /* StaticGravity */ }; register int g = ((tmp->hints.flags & PWinGravity) ? tmp->hints.win_gravity : NorthWestGravity); if (g < ForgetGravity || g > StaticGravity) { *xp = *yp = 0; } else { *xp = gravity_offsets[g].x; *yp = gravity_offsets[g].y; } } /*********************************************************************** * * Procedure: * AddWindow - add a new window to the twm list * * Returned Value: * (TwmWindow *) - pointer to the TwmWindow structure * * Inputs: * w - the window id of the window to add * iconm - flag to tell if this is an icon manager window * 0 --> normal window. * 1 --> icon manager. * 2 --> window box; * else --> iconmgr; * * iconp - pointer to icon manager struct * *********************************************************************** */ TwmWindow *AddWindow(Window w, int iconm, IconMgr *iconp) { virtualScreen *vs; TwmWindow *tmp_win; /* new twm window structure */ int stat; XEvent event; unsigned long valuemask; /* mask for create windows */ XSetWindowAttributes attributes; /* attributes for create windows */ int width, height; /* tmp variable */ int ask_user; /* don't know where to put the window */ int gravx, gravy; /* gravity signs for positioning */ int namelen; int bw2; short saved_x, saved_y, restore_icon_x, restore_icon_y; unsigned short saved_width, saved_height; Bool restore_iconified = 0; Bool restore_icon_info_present = 0; int restoredFromPrevSession; Bool width_ever_changed_by_user; Bool height_ever_changed_by_user; int saved_occupation; /* <== [ Matthew McNeill Feb 1997 ] == */ Bool random_placed = False; int found = 0; #ifndef VMS fd_set mask; int fd; struct timeval timeout; #endif XRectangle ink_rect; XRectangle logical_rect; WindowBox *winbox; int iswinbox = 0; int iswman = 0; Window vroot; #ifdef DEBUG fprintf(stderr, "AddWindow: w = 0x%x\n", w); #endif if (!captive && RedirectToCaptive (w)) return (NULL); /* allocate space for the twm window */ tmp_win = (TwmWindow *)calloc(1, sizeof(TwmWindow)); if (tmp_win == 0) { fprintf (stderr, "%s: Unable to allocate memory to manage window ID %lx.\n", ProgramName, w); return NULL; } switch (iconm) { case 0 : iswinbox = 0; break; case 1 : iswinbox = 0; break; case 2 : iswinbox = 1; iconm = 0; break; case 3 : iswman = 1; iconm = 0; break; default : iswinbox = 0; iswman = 0; iconm = 1; break; } tmp_win->w = w; tmp_win->zoomed = ZOOM_NONE; tmp_win->iconmgr = iconm; tmp_win->iconmgrp = iconp; tmp_win->wspmgr = iswman; tmp_win->iswinbox = iswinbox; tmp_win->vs = NULL; tmp_win->old_parent_vs = NULL; tmp_win->savevs = NULL; tmp_win->cmaps.number_cwins = 0; tmp_win->savegeometry.width = -1; XSelectInput(dpy, tmp_win->w, PropertyChangeMask); XGetWindowAttributes(dpy, tmp_win->w, &tmp_win->attr); tmp_win->name = (char*) GetWMPropertyString(tmp_win->w, XA_WM_NAME); tmp_win->class = NoClass; XGetClassHint(dpy, tmp_win->w, &tmp_win->class); FetchWmProtocols (tmp_win); FetchWmColormapWindows (tmp_win); if (GetWindowConfig (tmp_win, &saved_x, &saved_y, &saved_width, &saved_height, &restore_iconified, &restore_icon_info_present, &restore_icon_x, &restore_icon_y, &width_ever_changed_by_user, &height_ever_changed_by_user, &saved_occupation)) /* <== [ Matthew McNeill Feb 1997 ] == */ { tmp_win->attr.x = saved_x; tmp_win->attr.y = saved_y; tmp_win->widthEverChangedByUser = width_ever_changed_by_user; tmp_win->heightEverChangedByUser = height_ever_changed_by_user; if (width_ever_changed_by_user) tmp_win->attr.width = saved_width; if (height_ever_changed_by_user) tmp_win->attr.height = saved_height; restoredFromPrevSession = 1; } else { tmp_win->widthEverChangedByUser = False; tmp_win->heightEverChangedByUser = False; restoredFromPrevSession = 0; } /* * do initial clip; should look at window gravity */ if (tmp_win->attr.width > Scr->MaxWindowWidth) tmp_win->attr.width = Scr->MaxWindowWidth; if (tmp_win->attr.height > Scr->MaxWindowHeight) tmp_win->attr.height = Scr->MaxWindowHeight; tmp_win->wmhints = XGetWMHints(dpy, tmp_win->w); if (tmp_win->wmhints) { if (restore_iconified) { tmp_win->wmhints->initial_state = IconicState; tmp_win->wmhints->flags |= StateHint; } if (restore_icon_info_present) { tmp_win->wmhints->icon_x = restore_icon_x; tmp_win->wmhints->icon_y = restore_icon_y; tmp_win->wmhints->flags |= IconPositionHint; } } if (tmp_win->wmhints) tmp_win->wmhints->input = True; /* CL: Having with not willing focus cause problems with AutoSqueeze and a few others things. So I suppress it. And the whole focus thing is buggy anyway */ if (tmp_win->wmhints && !(tmp_win->wmhints->flags & InputHint)) tmp_win->wmhints->input = True; if (tmp_win->wmhints && (tmp_win->wmhints->flags & WindowGroupHint)) { tmp_win->group = tmp_win->wmhints->window_group; if (tmp_win->group) { /* * GTK windows often have a spurious "group leader" window which is * never reported to us and therefore does not really exist. This * is annoying because we treat group members a lot like transient * windows. Look for that here. It is in fact a duplicate of the * WM_CLIENT_LEADER property. */ if (tmp_win->group != w && !GetTwmWindow(tmp_win->group)) { tmp_win->group = 0; } } } else tmp_win->group = 0; /* * The July 27, 1988 draft of the ICCCM ignores the size and position * fields in the WM_NORMAL_HINTS property. */ tmp_win->transient = Transient(tmp_win->w, &tmp_win->transientfor); tmp_win->nameChanged = 0; if (tmp_win->name == NULL) tmp_win->name = NoName; if (tmp_win->class.res_name == NULL) tmp_win->class.res_name = NoName; if (tmp_win->class.res_class == NULL) tmp_win->class.res_class = NoName; /* * full_name seems to exist only because in the conditional code below, * name is sometimes changed. In all other cases, name and full_name * seem to be identical. Is that worth it? */ tmp_win->full_name = tmp_win->name; #ifdef CLAUDE if (strstr (tmp_win->name, " - Mozilla")) { char *moz = strstr (tmp_win->name, " - Mozilla"); *moz = '\0'; } #endif namelen = strlen (tmp_win->name); if (LookInList(Scr->IgnoreTransientL, tmp_win->full_name, &tmp_win->class)) tmp_win->transient = 0; tmp_win->highlight = Scr->Highlight && (!LookInList(Scr->NoHighlight, tmp_win->full_name, &tmp_win->class)); tmp_win->stackmode = Scr->StackMode && (!LookInList(Scr->NoStackModeL, tmp_win->full_name, &tmp_win->class)); tmp_win->ontoppriority = (LookInList(Scr->AlwaysOnTopL, tmp_win->full_name, &tmp_win->class)) ? ONTOP_MAX : ONTOP_DEFAULT; tmp_win->titlehighlight = Scr->TitleHighlight && (!LookInList(Scr->NoTitleHighlight, tmp_win->full_name, &tmp_win->class)); tmp_win->auto_raise = Scr->AutoRaiseDefault || LookInList(Scr->AutoRaise, tmp_win->full_name, &tmp_win->class); if (tmp_win->auto_raise) Scr->NumAutoRaises++; tmp_win->auto_lower = Scr->AutoLowerDefault || LookInList(Scr->AutoLower, tmp_win->full_name, &tmp_win->class); if (tmp_win->auto_lower) Scr->NumAutoLowers++; tmp_win->iconify_by_unmapping = Scr->IconifyByUnmapping; if (Scr->IconifyByUnmapping) { tmp_win->iconify_by_unmapping = iconm ? FALSE : !LookInList(Scr->DontIconify, tmp_win->full_name, &tmp_win->class); } tmp_win->iconify_by_unmapping = tmp_win->iconify_by_unmapping || LookInList(Scr->IconifyByUn, tmp_win->full_name, &tmp_win->class); if (LookInList (Scr->UnmapByMovingFarAway, tmp_win->full_name, &tmp_win->class)) tmp_win->UnmapByMovingFarAway = True; else tmp_win->UnmapByMovingFarAway = False; if (LookInList (Scr->DontSetInactive, tmp_win->full_name, &tmp_win->class)) tmp_win->DontSetInactive = True; else tmp_win->DontSetInactive = False; if (LookInList (Scr->AutoSqueeze, tmp_win->full_name, &tmp_win->class)) tmp_win->AutoSqueeze = True; else tmp_win->AutoSqueeze = False; if (LookInList (Scr->StartSqueezed, tmp_win->full_name, &tmp_win->class)) tmp_win->StartSqueezed = True; else tmp_win->StartSqueezed = False; if (Scr->AlwaysSqueezeToGravity || LookInList (Scr->AlwaysSqueezeToGravityL, tmp_win->full_name, &tmp_win->class)) tmp_win->AlwaysSqueezeToGravity = True; else tmp_win->AlwaysSqueezeToGravity = False; if (tmp_win->transient || tmp_win->group) { TwmWindow *t = NULL; if (tmp_win->transient) t = GetTwmWindow(tmp_win->transientfor); if (!t && tmp_win->group) t = GetTwmWindow(tmp_win->group); if (t) tmp_win->UnmapByMovingFarAway = t->UnmapByMovingFarAway; } if ((Scr->WindowRingAll && !iswman && !LookInList(Scr->WindowRingExcludeL, tmp_win->full_name, &tmp_win->class)) || LookInList(Scr->WindowRingL, tmp_win->full_name, &tmp_win->class)) { if (Scr->Ring) { tmp_win->ring.next = Scr->Ring->ring.next; if (Scr->Ring->ring.next->ring.prev) Scr->Ring->ring.next->ring.prev = tmp_win; Scr->Ring->ring.next = tmp_win; tmp_win->ring.prev = Scr->Ring; } else { tmp_win->ring.next = tmp_win->ring.prev = Scr->Ring = tmp_win; } } else tmp_win->ring.next = tmp_win->ring.prev = NULL; tmp_win->ring.cursor_valid = False; tmp_win->squeeze_info = NULL; tmp_win->squeeze_info_copied = 0; /* * get the squeeze information; note that this does not have to be freed * since it is coming from the screen list */ if (HasShape) { if (!LookInList (Scr->DontSqueezeTitleL, tmp_win->full_name, &tmp_win->class)) { tmp_win->squeeze_info = (SqueezeInfo *) LookInList (Scr->SqueezeTitleL, tmp_win->full_name, &tmp_win->class); if (!tmp_win->squeeze_info) { static SqueezeInfo default_squeeze = { J_LEFT, 0, 0 }; if (Scr->SqueezeTitle) tmp_win->squeeze_info = &default_squeeze; } } } tmp_win->old_bw = tmp_win->attr.border_width; { MotifWmHints mwmHints; Boolean have_title; GetMWMHints(tmp_win->w, &mwmHints); tmp_win->frame_bw3D = Scr->ThreeDBorderWidth; if (((mwmHints.flags & MWM_HINTS_DECORATIONS) && (mwmHints.decorations & MWM_DECOR_BORDER) == 0) || LookInList(Scr->NoBorder, tmp_win->full_name, &tmp_win->class)) { tmp_win->frame_bw = 0; tmp_win->frame_bw3D = 0; } else if (tmp_win->frame_bw3D != 0) { tmp_win->frame_bw = 0; Scr->ClientBorderWidth = FALSE; } else if (Scr->ClientBorderWidth) { tmp_win->frame_bw = tmp_win->old_bw; } else { tmp_win->frame_bw = Scr->BorderWidth; } bw2 = tmp_win->frame_bw * 2; have_title = True; if (mwmHints.flags & MWM_HINTS_DECORATIONS) have_title = (mwmHints.decorations & MWM_DECOR_TITLE) != 0; if (Scr->NoTitlebar) have_title = False; if (LookInList(Scr->MakeTitle, tmp_win->full_name, &tmp_win->class)) have_title = True; if (LookInList(Scr->NoTitle, tmp_win->full_name, &tmp_win->class)) have_title = False; if (have_title) { tmp_win->title_height = Scr->TitleHeight + tmp_win->frame_bw; } else { tmp_win->title_height = 0; } } tmp_win->OpaqueMove = Scr->DoOpaqueMove; if (LookInList(Scr->OpaqueMoveList, tmp_win->full_name, &tmp_win->class)) tmp_win->OpaqueMove = TRUE; else if (LookInList(Scr->NoOpaqueMoveList, tmp_win->full_name, &tmp_win->class)) tmp_win->OpaqueMove = FALSE; tmp_win->OpaqueResize = Scr->DoOpaqueResize; if (LookInList(Scr->OpaqueResizeList, tmp_win->full_name, &tmp_win->class)) tmp_win->OpaqueResize = TRUE; else if (LookInList(Scr->NoOpaqueResizeList, tmp_win->full_name, &tmp_win->class)) tmp_win->OpaqueResize = FALSE; /* if it is a transient window, don't put a title on it */ if (tmp_win->transient && !Scr->DecorateTransients) tmp_win->title_height = 0; if (LookInList(Scr->StartIconified, tmp_win->full_name, &tmp_win->class)) { if (!tmp_win->wmhints) { tmp_win->wmhints = (XWMHints *)malloc(sizeof(XWMHints)); tmp_win->wmhints->flags = 0; } tmp_win->wmhints->initial_state = IconicState; tmp_win->wmhints->flags |= StateHint; } GetWindowSizeHints (tmp_win); if (restoredFromPrevSession) { /* * When restoring window positions from the previous session, * we always use NorthWest gravity. */ gravx = gravy = -1; } else { GetGravityOffsets (tmp_win, &gravx, &gravy); } /* * Don't bother user if: * * o the window is a transient, or * * o a USPosition was requested, or * * o a PPosition was requested and UsePPosition is ON or * NON_ZERO if the window is at other than (0,0) */ ask_user = TRUE; if (tmp_win->transient || (tmp_win->hints.flags & USPosition) || ((tmp_win->hints.flags & PPosition) && Scr->UsePPosition && (Scr->UsePPosition == PPOS_ON || tmp_win->attr.x != 0 || tmp_win->attr.y != 0))) ask_user = FALSE; /*===============[ Matthew McNeill 1997 ]==========================* * added the occupation parameter to this function call so that the * occupation can be set up in a specific state if desired * (restore session for example) */ /* note, this is where tmp_win->vs get setup, among other things */ if (restoredFromPrevSession) { SetupOccupation (tmp_win, saved_occupation); } else SetupOccupation (tmp_win, 0); /*=================================================================*/ tmp_win->frame_width = tmp_win->attr.width + 2 * tmp_win->frame_bw3D; tmp_win->frame_height = tmp_win->attr.height + 2 * tmp_win->frame_bw3D + tmp_win->title_height; ConstrainSize (tmp_win, &tmp_win->frame_width, &tmp_win->frame_height); winbox = findWindowBox (tmp_win); if (PlaceWindowInRegion (tmp_win, &(tmp_win->attr.x), &(tmp_win->attr.y))) { ask_user = False; } if (LookInList (Scr->WindowGeometries, tmp_win->full_name, &tmp_win->class)) { char *geom; int mask_; geom = LookInList (Scr->WindowGeometries, tmp_win->full_name, &tmp_win->class); mask_ = XParseGeometry (geom, &tmp_win->attr.x, &tmp_win->attr.y, (unsigned int*) &tmp_win->attr.width, (unsigned int*) &tmp_win->attr.height); if (mask_ & XNegative) tmp_win->attr.x += Scr->rootw - tmp_win->attr.width; if (mask_ & YNegative) tmp_win->attr.y += Scr->rooth - tmp_win->attr.height; ask_user = False; } if (XFindContext (dpy, w, VirtScreenContext, (XPointer *)&vs) == XCSUCCESS) vroot = vs->window; else if (tmp_win->vs) vroot = tmp_win->vs->window; else vroot = Scr->Root; if (winbox) vroot = winbox->window; /* * do any prompting for position */ if (HandlingEvents && ask_user && !restoredFromPrevSession) { if ((Scr->RandomPlacement == RP_ALL) || ((Scr->RandomPlacement == RP_UNMAPPED) && ((tmp_win->wmhints && (tmp_win->wmhints->initial_state == IconicState)) || (! visible (tmp_win))))) { /* just stick it somewhere */ #ifdef DEBUG fprintf(stderr, "DEBUG[RandomPlacement]: win: %dx%d+%d+%d, screen: %dx%d, title height: %d, random: +%d+%d\n", tmp_win->attr.width, tmp_win->attr.height, tmp_win->attr.x, tmp_win->attr.y, Scr->rootw, Scr->rooth, tmp_win->title_height, PlaceX, PlaceY); #endif /* Initiallise PlaceX and PlaceY */ if (PlaceX < 0 && PlaceY < 0) { if (Scr->RandomDisplacementX >= 0) PlaceX = Scr->BorderLeft + 5; else PlaceX = Scr->rootw - tmp_win->attr.width - Scr->BorderRight - 5; if (Scr->RandomDisplacementY >= 0) PlaceY = Scr->BorderTop + 5; else PlaceY = Scr->rooth - tmp_win->attr.height - tmp_win->title_height - Scr->BorderBottom - 5; } /* For a positive horizontal displacement, if the right edge of the window would fall outside of the screen, start over by placing the left edge of the window 5 pixels inside the left edge of the screen.*/ if (Scr->RandomDisplacementX >= 0 && (PlaceX + tmp_win->attr.width > Scr->rootw - Scr->BorderRight - 5)) PlaceX = Scr->BorderLeft + 5; /* For a negative horizontal displacement, if the left edge of the window would fall outside of the screen, start over by placing the right edge of the window 5 pixels inside the right edge of the screen.*/ if (Scr->RandomDisplacementX < 0 && PlaceX < Scr->BorderLeft + 5) PlaceX = Scr->rootw - tmp_win->attr.width - Scr->BorderRight - 5; /* For a positive vertical displacement, if the bottom edge of the window would fall outside of the screen, start over by placing the top edge of the window 5 pixels inside the top edge of the screen. Because we add the title height further down, we need to count with it here as well. */ if (Scr->RandomDisplacementY >= 0 && (PlaceY + tmp_win->attr.height + tmp_win->title_height > Scr->rooth - Scr->BorderBottom - 5)) PlaceY = Scr->BorderTop + 5; /* For a negative vertical displacement, if the top edge of the window would fall outside of the screen, start over by placing the bottom edge of the window 5 pixels inside the bottom edge of the screen. Because we add the title height further down, we need to count with it here as well. */ if (Scr->RandomDisplacementY < 0 && PlaceY < Scr->BorderTop + 5) PlaceY = Scr->rooth - tmp_win->attr.height - tmp_win->title_height - Scr->BorderBottom - 5; /* Assign the current random placement to the new window, as a preliminary measure. Add the title height so things will look right. */ tmp_win->attr.x = PlaceX; tmp_win->attr.y = PlaceY + tmp_win->title_height; /* If the window is not supposed to move off the screen, check that it's still within the screen, and if not, attempt to correct the situation. */ if (Scr->DontMoveOff) { int available; #ifdef DEBUG fprintf(stderr, "DEBUG[DontMoveOff]: win: %dx%d+%d+%d, screen: %dx%d, bw2: %d, bw3D: %d\n", tmp_win->attr.width, tmp_win->attr.height, tmp_win->attr.x, tmp_win->attr.y, Scr->rootw, Scr->rooth, bw2, tmp_win->frame_bw3D); #endif /* If the right edge of the window is outside the right edge of the screen, we need to move the window left. Note that this can only happen with windows that are less than 50 pixels less wide than the screen. */ if ((tmp_win->attr.x + tmp_win->attr.width) > Scr->rootw) { available = Scr->rootw - tmp_win->attr.width - 2 * (bw2 + tmp_win->frame_bw3D); #ifdef DEBUG fprintf(stderr, "DEBUG[DontMoveOff]: availableX: %d\n", available); #endif /* If the window is wider than the screen or exactly the width of the screen, the availability is exactly 0. The result will be to have the window placed as much to the left as possible. */ if (available <= 0) available = 0; /* Place the window exactly between the left and right edge of the screen when possible. If available was originally less than zero, it means the window's left edge will be against the screen's left edge, and the window's right edge will be outside the screen. */ tmp_win->attr.x = available / 2; } /* If the bottom edge of the window is outside the bottom edge of the screen, we need to move the window up. Note that this can only happen with windows that are less than 50 pixels less tall than the screen. Don't forget to count with the title height and the frame widths. */ if ((tmp_win->attr.y + tmp_win->attr.height) > Scr->rooth) { available = Scr->rooth - tmp_win->attr.height - tmp_win->title_height - 2 * (bw2 + tmp_win->frame_bw3D); #ifdef DEBUG fprintf(stderr, "DEBUG[DontMoveOff]: availableY: %d\n", available); #endif /* If the window is taller than the screen or exactly the height of the screen, the availability is exactly 0. The result will be to have the window placed as much to the top as possible. */ if (available <= 0) available = 0; /* Place the window exactly between the top and bottom edge of the screen when possible. If available was originally less than zero, it means the window's top edge will be against the screen's top edge, and the window's bottom edge will be outside the screen. Again, don't forget to add the title height. */ tmp_win->attr.y = available / 2 + tmp_win->title_height; } #ifdef DEBUG fprintf(stderr, "DEBUG[DontMoveOff]: win: %dx%d+%d+%d, screen: %dx%d\n", tmp_win->attr.width, tmp_win->attr.height, tmp_win->attr.x, tmp_win->attr.y, Scr->rootw, Scr->rooth); #endif } /* We know that if the window's left edge has moved compared to PlaceX, it will have moved to the left. If it was moved less than 15 pixel either way, change the next "random position" 30 pixels down and right. */ if (PlaceX - tmp_win->attr.x < 15 || PlaceY - (tmp_win->attr.y - tmp_win->title_height) < 15) { PlaceX += Scr->RandomDisplacementX; PlaceY += Scr->RandomDisplacementY; } random_placed = True; } else { /* else prompt */ if (!(tmp_win->wmhints && tmp_win->wmhints->flags & StateHint && tmp_win->wmhints->initial_state == IconicState)) { Bool firsttime = True; /* better wait until all the mouse buttons have been * released. */ while (TRUE) { XUngrabServer(dpy); XSync(dpy, 0); XGrabServer(dpy); JunkMask = 0; if (!XQueryPointer (dpy, Scr->Root, &JunkRoot, &JunkChild, &JunkX, &JunkY, &AddingX, &AddingY, &JunkMask)) JunkMask = 0; JunkMask &= (Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask); /* * watch out for changing screens */ if (firsttime) { if (JunkRoot != Scr->Root) { register int scrnum; for (scrnum = 0; scrnum < NumScreens; scrnum++) { if (JunkRoot == RootWindow (dpy, scrnum)) break; } if (scrnum != NumScreens) PreviousScreen = scrnum; } if (Scr->currentvs) { vroot = Scr->currentvs->window; } firsttime = False; } if (winbox) vroot = winbox->window; /* * wait for buttons to come up; yuck */ if (JunkMask != 0) continue; /* * this will cause a warp to the indicated root */ stat = XGrabPointer(dpy, vroot, False, ButtonPressMask | ButtonReleaseMask | PointerMotionMask | PointerMotionHintMask, GrabModeAsync, GrabModeAsync, vroot, UpperLeftCursor, CurrentTime); if (stat == GrabSuccess) break; } XmbTextExtents(Scr->SizeFont.font_set, tmp_win->name, namelen, &ink_rect, &logical_rect); width = SIZE_HINDENT + ink_rect.width; height = logical_rect.height + SIZE_VINDENT * 2; XmbTextExtents(Scr->SizeFont.font_set, ": ", 2, &logical_rect, &logical_rect); Scr->SizeStringOffset = width + logical_rect.width; XResizeWindow (dpy, Scr->SizeWindow, Scr->SizeStringOffset + Scr->SizeStringWidth + SIZE_HINDENT, height); XMapRaised(dpy, Scr->SizeWindow); InstallRootColormap(); FB(Scr->DefaultC.fore, Scr->DefaultC.back); XmbDrawImageString (dpy, Scr->SizeWindow, Scr->SizeFont.font_set, Scr->NormalGC, SIZE_HINDENT, SIZE_VINDENT + Scr->SizeFont.ascent, tmp_win->name, namelen); if (winbox) ConstrainedToWinBox (tmp_win, AddingX, AddingY, &AddingX, &AddingY); AddingW = tmp_win->attr.width + bw2 + 2 * tmp_win->frame_bw3D; AddingH = tmp_win->attr.height + tmp_win->title_height + bw2 + 2 * tmp_win->frame_bw3D; MoveOutline(vroot,AddingX, AddingY, AddingW, AddingH, tmp_win->frame_bw, tmp_win->title_height + tmp_win->frame_bw3D); XmbDrawImageString (dpy, Scr->SizeWindow, Scr->SizeFont.font_set, Scr->NormalGC, width, SIZE_VINDENT + Scr->SizeFont.ascent, ": ", 2); DisplayPosition (tmp_win, AddingX, AddingY); tmp_win->frame_width = AddingW; tmp_win->frame_height = AddingH; /*SetFocus ((TwmWindow *) NULL, CurrentTime);*/ while (TRUE) { #ifndef VMS /* I'll try to implement this later. RL */ if (Scr->OpenWindowTimeout) { fd = ConnectionNumber (dpy); while (!XCheckMaskEvent (dpy, ButtonMotionMask | ButtonPressMask, &event)) { FD_ZERO (&mask); FD_SET (fd, &mask); timeout.tv_sec = Scr->OpenWindowTimeout; timeout.tv_usec = 0; found = select (fd + 1, (FDSET)&mask, (FDSET)0, (FDSET)0, &timeout); if (found == 0) break; } if (found == 0) break; } else { #else { #endif found = 1; XMaskEvent(dpy, ButtonPressMask | PointerMotionMask, &event); } if (event.type == MotionNotify) { /* discard any extra motion events before a release */ while(XCheckMaskEvent(dpy, ButtonMotionMask | ButtonPressMask, &event)) if (event.type == ButtonPress) break; } FixRootEvent (&event); if (event.type == ButtonPress) { AddingX = event.xbutton.x_root; AddingY = event.xbutton.y_root; TryToGrid (tmp_win, &AddingX, &AddingY); if (Scr->PackNewWindows) TryToPack (tmp_win, &AddingX, &AddingY); /* DontMoveOff prohibits user form off-screen placement */ if (Scr->DontMoveOff) { ConstrainByBorders (tmp_win, &AddingX, AddingW, &AddingY, AddingH); } break; } if (event.type != MotionNotify) { continue; } XQueryPointer(dpy, vroot, &JunkRoot, &JunkChild, &JunkX, &JunkY, &AddingX, &AddingY, &JunkMask); TryToGrid (tmp_win, &AddingX, &AddingY); if (Scr->PackNewWindows) TryToPack (tmp_win, &AddingX, &AddingY); if (Scr->DontMoveOff) { ConstrainByBorders (tmp_win, &AddingX, AddingW, &AddingY, AddingH); } MoveOutline(vroot, AddingX, AddingY, AddingW, AddingH, tmp_win->frame_bw, tmp_win->title_height + tmp_win->frame_bw3D); DisplayPosition (tmp_win, AddingX, AddingY); } if (found) { if (event.xbutton.button == Button2) { int lastx, lasty; XmbTextExtents(Scr->SizeFont.font_set, ": ", 2, &logical_rect, &logical_rect); Scr->SizeStringOffset = width + logical_rect.width; XResizeWindow (dpy, Scr->SizeWindow, Scr->SizeStringOffset + Scr->SizeStringWidth + SIZE_HINDENT, height); XmbDrawImageString(dpy, Scr->SizeWindow, Scr->SizeFont.font_set, Scr->NormalGC, width, SIZE_VINDENT + Scr->SizeFont.ascent, ": ", 2); if (0/*Scr->AutoRelativeResize*/) { int dx = (tmp_win->attr.width / 4); int dy = (tmp_win->attr.height / 4); #define HALF_AVE_CURSOR_SIZE 8 /* so that it is visible */ if (dx < HALF_AVE_CURSOR_SIZE + Scr->BorderLeft) dx = HALF_AVE_CURSOR_SIZE + Scr->BorderLeft; if (dy < HALF_AVE_CURSOR_SIZE + Scr->BorderTop) dy = HALF_AVE_CURSOR_SIZE + Scr->BorderTop; #undef HALF_AVE_CURSOR_SIZE dx += (tmp_win->frame_bw + 1); dy += (bw2 + tmp_win->title_height + 1); if (AddingX + dx >= Scr->rootw - Scr->BorderRight) dx = Scr->rootw - Scr->BorderRight - AddingX - 1; if (AddingY + dy >= Scr->rooth - Scr->BorderBottom) dy = Scr->rooth - Scr->BorderBottom - AddingY - 1; if (dx > 0 && dy > 0) XWarpPointer (dpy, None, None, 0, 0, 0, 0, dx, dy); } else { XWarpPointer (dpy, None, vroot, 0, 0, 0, 0, AddingX + AddingW/2, AddingY + AddingH/2); } AddStartResize(tmp_win, AddingX, AddingY, AddingW, AddingH); lastx = -10000; lasty = -10000; while (TRUE) { XMaskEvent(dpy, ButtonReleaseMask | ButtonMotionMask, &event); if (event.type == MotionNotify) { /* discard any extra motion events before a release */ while(XCheckMaskEvent(dpy, ButtonMotionMask | ButtonReleaseMask, &event)) if (event.type == ButtonRelease) break; } FixRootEvent (&event); if (event.type == ButtonRelease) { AddEndResize(tmp_win); break; } if (event.type != MotionNotify) { continue; } /* * XXX - if we are going to do a loop, we ought to consider * using multiple GXxor lines so that we don't need to * grab the server. */ XQueryPointer(dpy, vroot, &JunkRoot, &JunkChild, &JunkX, &JunkY, &AddingX, &AddingY, &JunkMask); if (lastx != AddingX || lasty != AddingY) { resizeWhenAdd = TRUE; DoResize(AddingX, AddingY, tmp_win); resizeWhenAdd = FALSE; lastx = AddingX; lasty = AddingY; } } } else if (event.xbutton.button == Button3) { int maxw = Scr->rootw - Scr->BorderRight - AddingX - bw2; int maxh = Scr->rooth - Scr->BorderBottom - AddingY - bw2; /* * Make window go to bottom of screen, and clip to right edge. * This is useful when popping up large windows and fixed * column text windows. */ if (AddingW > maxw) AddingW = maxw; AddingH = maxh; ConstrainSize (tmp_win, &AddingW, &AddingH); /* w/o borders */ AddingW += bw2; AddingH += bw2; XMaskEvent(dpy, ButtonReleaseMask, &event); } else { XMaskEvent(dpy, ButtonReleaseMask, &event); } } MoveOutline(vroot, 0, 0, 0, 0, 0, 0); XUnmapWindow(dpy, Scr->SizeWindow); UninstallRootColormap(); XUngrabPointer(dpy, CurrentTime); tmp_win->attr.x = AddingX; tmp_win->attr.y = AddingY + tmp_win->title_height; tmp_win->attr.width = AddingW - bw2 - 2 * tmp_win->frame_bw3D; tmp_win->attr.height = AddingH - tmp_win->title_height - bw2 - 2 * tmp_win->frame_bw3D; XUngrabServer(dpy); } } } else { /* put it where asked, mod title bar */ /* if the gravity is towards the top, move it by the title height */ if (gravy < 0) tmp_win->attr.y -= gravy * tmp_win->title_height; } #ifdef DEBUG fprintf(stderr, " position window %d, %d %dx%d\n", tmp_win->attr.x, tmp_win->attr.y, tmp_win->attr.width, tmp_win->attr.height); #endif if (!Scr->ClientBorderWidth) { /* need to adjust for twm borders */ int delta = tmp_win->attr.border_width - tmp_win->frame_bw - tmp_win->frame_bw3D; tmp_win->attr.x += gravx * delta; tmp_win->attr.y += gravy * delta; } tmp_win->title_width = tmp_win->attr.width; tmp_win->icon_name = (char*) GetWMPropertyString(tmp_win->w, XA_WM_ICON_NAME); if (!tmp_win->icon_name) tmp_win->icon_name = tmp_win->name; #ifdef CLAUDE if (strstr (tmp_win->icon_name, " - Mozilla")) { char *moz = strstr (tmp_win->icon_name, " - Mozilla"); *moz = '\0'; } #endif XmbTextExtents (Scr->TitleBarFont.font_set, tmp_win->name, namelen, &ink_rect, &logical_rect); tmp_win->name_width = logical_rect.width; if (tmp_win->old_bw) XSetWindowBorderWidth (dpy, tmp_win->w, 0); tmp_win->squeezed = FALSE; tmp_win->iconified = FALSE; tmp_win->isicon = FALSE; tmp_win->icon_on = FALSE; XGrabServer(dpy); /* * Make sure the client window still exists. We don't want to leave an * orphan frame window if it doesn't. Since we now have the server * grabbed, the window can't disappear later without having been * reparented, so we'll get a DestroyNotify for it. We won't have * gotten one for anything up to here, however. */ if (XGetGeometry(dpy, tmp_win->w, &JunkRoot, &JunkX, &JunkY, &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth) == 0) { TwmWindow *prev = tmp_win->ring.prev, *next = tmp_win->ring.next; if (prev) prev->ring.next = next; if (next) next->ring.prev = prev; if (Scr->Ring == tmp_win) Scr->Ring = (next != tmp_win ? next : (TwmWindow *) NULL); if (!Scr->Ring || Scr->RingLeader == tmp_win) Scr->RingLeader = Scr->Ring; free((char *)tmp_win); XUngrabServer(dpy); return(NULL); } /* add the window into the twm list */ tmp_win->next = Scr->FirstWindow; if (Scr->FirstWindow != NULL) Scr->FirstWindow->prev = tmp_win; tmp_win->prev = NULL; Scr->FirstWindow = tmp_win; /* get all the colors for the window */ tmp_win->borderC.fore = Scr->BorderColorC.fore; tmp_win->borderC.back = Scr->BorderColorC.back; tmp_win->border_tile.fore = Scr->BorderTileC.fore; tmp_win->border_tile.back = Scr->BorderTileC.back; tmp_win->title.fore = Scr->TitleC.fore; tmp_win->title.back = Scr->TitleC.back; GetColorFromList(Scr->BorderColorL, tmp_win->full_name, &tmp_win->class, &tmp_win->borderC.fore); GetColorFromList(Scr->BorderColorL, tmp_win->full_name, &tmp_win->class, &tmp_win->borderC.back); GetColorFromList(Scr->BorderTileForegroundL, tmp_win->full_name, &tmp_win->class, &tmp_win->border_tile.fore); GetColorFromList(Scr->BorderTileBackgroundL, tmp_win->full_name, &tmp_win->class, &tmp_win->border_tile.back); GetColorFromList(Scr->TitleForegroundL, tmp_win->full_name, &tmp_win->class, &tmp_win->title.fore); GetColorFromList(Scr->TitleBackgroundL, tmp_win->full_name, &tmp_win->class, &tmp_win->title.back); if (Scr->use3Dtitles && !Scr->BeNiceToColormap) GetShadeColors (&tmp_win->title); if (Scr->use3Dborders && !Scr->BeNiceToColormap) { GetShadeColors (&tmp_win->borderC); GetShadeColors (&tmp_win->border_tile); } /* create windows */ tmp_win->frame_x = tmp_win->attr.x + tmp_win->old_bw - tmp_win->frame_bw - tmp_win->frame_bw3D; tmp_win->frame_y = tmp_win->attr.y - tmp_win->title_height + tmp_win->old_bw - tmp_win->frame_bw - tmp_win->frame_bw3D; tmp_win->frame_width = tmp_win->attr.width + 2 * tmp_win->frame_bw3D; tmp_win->frame_height = tmp_win->attr.height + tmp_win->title_height + 2 * tmp_win->frame_bw3D; ConstrainSize (tmp_win, &tmp_win->frame_width, &tmp_win->frame_height); if (random_placed) ConstrainByBorders (tmp_win, &tmp_win->frame_x, tmp_win->frame_width, &tmp_win->frame_y, tmp_win->frame_height); valuemask = CWBackPixmap | CWBorderPixel | CWCursor | CWEventMask | CWBackPixel; attributes.background_pixmap = None; attributes.border_pixel = tmp_win->border_tile.back; attributes.background_pixel = tmp_win->border_tile.back; attributes.cursor = Scr->FrameCursor; attributes.event_mask = (SubstructureRedirectMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | ExposureMask); if (Scr->BorderCursors) attributes.event_mask |= PointerMotionMask; if (tmp_win->attr.save_under) { attributes.save_under = True; valuemask |= CWSaveUnder; } if (tmp_win->hints.flags & PWinGravity) { attributes.win_gravity = tmp_win->hints.win_gravity; valuemask |= CWWinGravity; } if ((tmp_win->frame_x > Scr->rootw) || (tmp_win->frame_y > Scr->rooth) || ((int)(tmp_win->frame_x + tmp_win->frame_width) < 0) || ((int)(tmp_win->frame_y + tmp_win->frame_height) < 0)) { tmp_win->frame_x = 0; tmp_win->frame_y = 0; } DealWithNonSensicalGeometries(dpy, vroot, tmp_win); tmp_win->frame = XCreateWindow (dpy, vroot, tmp_win->frame_x, tmp_win->frame_y, (unsigned int) tmp_win->frame_width, (unsigned int) tmp_win->frame_height, (unsigned int) tmp_win->frame_bw, Scr->d_depth, (unsigned int) CopyFromParent, Scr->d_visual, valuemask, &attributes); if (tmp_win->title_height) { valuemask = (CWEventMask | CWDontPropagate | CWBorderPixel | CWBackPixel); attributes.event_mask = (KeyPressMask | ButtonPressMask | ButtonReleaseMask | ExposureMask); attributes.do_not_propagate_mask = PointerMotionMask; attributes.border_pixel = tmp_win->borderC.back; attributes.background_pixel = tmp_win->title.back; tmp_win->title_w = XCreateWindow (dpy, tmp_win->frame, tmp_win->frame_bw3D - tmp_win->frame_bw, tmp_win->frame_bw3D - tmp_win->frame_bw, (unsigned int) tmp_win->attr.width, (unsigned int) Scr->TitleHeight, (unsigned int) tmp_win->frame_bw, Scr->d_depth, (unsigned int) CopyFromParent, Scr->d_visual, valuemask, &attributes); } else { tmp_win->title_w = 0; tmp_win->squeeze_info = NULL; } if (tmp_win->highlight) { if (Scr->use3Dtitles && (Scr->Monochrome != COLOR)) tmp_win->gray = XCreatePixmapFromBitmapData(dpy, vroot, (char*)black_bits, gray_width, gray_height, tmp_win->border_tile.fore, tmp_win->border_tile.back, Scr->d_depth); else tmp_win->gray = XCreatePixmapFromBitmapData(dpy, vroot, (char*)gray_bits, gray_width, gray_height, tmp_win->border_tile.fore, tmp_win->border_tile.back, Scr->d_depth); tmp_win->hasfocusvisible = True; SetFocusVisualAttributes (tmp_win, False); } else tmp_win->gray = None; RaiseWindow(tmp_win); if (tmp_win->title_w) { ComputeTitleLocation (tmp_win); CreateWindowTitlebarButtons (tmp_win); XMoveWindow (dpy, tmp_win->title_w, tmp_win->title_x, tmp_win->title_y); XDefineCursor(dpy, tmp_win->title_w, Scr->TitleCursor); } else { tmp_win->title_x = tmp_win->frame_bw3D - tmp_win->frame_bw; tmp_win->title_y = tmp_win->frame_bw3D - tmp_win->frame_bw; } valuemask = (CWEventMask | CWDontPropagate); attributes.event_mask = (StructureNotifyMask | PropertyChangeMask | ColormapChangeMask | VisibilityChangeMask | FocusChangeMask | EnterWindowMask | LeaveWindowMask); attributes.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask; XChangeWindowAttributes (dpy, tmp_win->w, valuemask, &attributes); if (HasShape) XShapeSelectInput (dpy, tmp_win->w, ShapeNotifyMask); if (tmp_win->title_w) { XMapWindow (dpy, tmp_win->title_w); } if (HasShape) { int xws, yws, xbs, ybs; unsigned wws, hws, wbs, hbs; int boundingShaped, clipShaped; XShapeSelectInput (dpy, tmp_win->w, ShapeNotifyMask); XShapeQueryExtents (dpy, tmp_win->w, &boundingShaped, &xws, &yws, &wws, &hws, &clipShaped, &xbs, &ybs, &wbs, &hbs); tmp_win->wShaped = boundingShaped; } if (!tmp_win->iconmgr &&! iswman && (tmp_win->w != Scr->workSpaceMgr.occupyWindow->w)) XAddToSaveSet(dpy, tmp_win->w); XReparentWindow(dpy, tmp_win->w, tmp_win->frame, tmp_win->frame_bw3D, tmp_win->title_height + tmp_win->frame_bw3D); /* * Reparenting generates an UnmapNotify event, followed by a MapNotify. * Set the map state to FALSE to prevent a transition back to * WithdrawnState in HandleUnmapNotify. Map state gets set correctly * again in HandleMapNotify. */ tmp_win->mapped = FALSE; SetupFrame (tmp_win, tmp_win->frame_x, tmp_win->frame_y, tmp_win->frame_width, tmp_win->frame_height, -1, True); /* wait until the window is iconified and the icon window is mapped * before creating the icon window */ tmp_win->icon = (Icon*) 0; tmp_win->iconslist = (name_list*) 0; if (!tmp_win->iconmgr) { GrabButtons(tmp_win); GrabKeys(tmp_win); } (void) AddIconManager(tmp_win); XSaveContext(dpy, tmp_win->w, TwmContext, (XPointer) tmp_win); XSaveContext(dpy, tmp_win->w, ScreenContext, (XPointer) Scr); XSaveContext(dpy, tmp_win->frame, TwmContext, (XPointer) tmp_win); XSaveContext(dpy, tmp_win->frame, ScreenContext, (XPointer) Scr); if (tmp_win->title_height) { int i; int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright; XSaveContext(dpy, tmp_win->title_w, TwmContext, (XPointer) tmp_win); XSaveContext(dpy, tmp_win->title_w, ScreenContext, (XPointer) Scr); for (i = 0; i < nb; i++) { XSaveContext(dpy, tmp_win->titlebuttons[i].window, TwmContext, (XPointer) tmp_win); XSaveContext(dpy, tmp_win->titlebuttons[i].window, ScreenContext, (XPointer) Scr); } if (tmp_win->hilite_wl) { XSaveContext(dpy, tmp_win->hilite_wl, TwmContext, (XPointer)tmp_win); XSaveContext(dpy, tmp_win->hilite_wl, ScreenContext, (XPointer)Scr); } if (tmp_win->hilite_wr) { XSaveContext(dpy, tmp_win->hilite_wr, TwmContext, (XPointer)tmp_win); XSaveContext(dpy, tmp_win->hilite_wr, ScreenContext, (XPointer)Scr); } if (tmp_win->lolite_wl) { XSaveContext(dpy, tmp_win->lolite_wl, TwmContext, (XPointer)tmp_win); XSaveContext(dpy, tmp_win->lolite_wl, ScreenContext, (XPointer)Scr); } if (tmp_win->lolite_wr) { XSaveContext(dpy, tmp_win->lolite_wr, TwmContext, (XPointer)tmp_win); XSaveContext(dpy, tmp_win->lolite_wr, ScreenContext, (XPointer)Scr); } } XUngrabServer(dpy); /* if we were in the middle of a menu activated function, regrab * the pointer */ if (RootFunction) ReGrab(); if (!iswman) WMapAddWindow (tmp_win); SetPropsIfCaptiveCtwm (tmp_win); savegeometry (tmp_win); return (tmp_win); } /*********************************************************************** * * Procedure: * GetTwmWindow - finds the TwmWindow structure associated with * a Window (if any), or NULL. * * Returned Value: * NULL - it is not a Window we know about * otherwise- the TwmWindow * * * Inputs: * w - the window to check * * Note: * This is a relatively cheap function since it does not involve * communication with the server. Probably faster than walking * the list of TwmWindows, since the lookup is by a hash table. * *********************************************************************** */ TwmWindow *GetTwmWindow(Window w) { TwmWindow *twmwin; int stat; stat = XFindContext(dpy, w, TwmContext, (XPointer *)&twmwin); if (stat == XCNOENT) twmwin = NULL; return twmwin; } /*********************************************************************** * * Procedure: * MappedNotOverride - checks to see if we should really * put a twm frame on the window * * Returned Value: * TRUE - go ahead and frame the window * FALSE - don't frame the window * * Inputs: * w - the window to check * *********************************************************************** */ int MappedNotOverride(Window w) { XWindowAttributes wa; XGetWindowAttributes(dpy, w, &wa); return ((wa.map_state != IsUnmapped) && (wa.override_redirect != True)); } /*********************************************************************** * * Procedure: * AddDefaultBindings - attach default bindings so that naive users * don't get messed up if they provide a minimal twmrc. */ static void do_add_binding (int button, int context, int modifier, int func) { AddFuncButton (button, context, modifier, func, NULL, NULL); } void AddDefaultBindings (void) { #define NoModifierMask 0 do_add_binding (Button1, C_TITLE, NoModifierMask, F_MOVE); do_add_binding (Button1, C_ICON, NoModifierMask, F_ICONIFY); do_add_binding (Button1, C_ICONMGR, NoModifierMask, F_ICONIFY); do_add_binding (Button2, C_TITLE, NoModifierMask, F_RAISELOWER); do_add_binding (Button2, C_ICON, NoModifierMask, F_ICONIFY); do_add_binding (Button2, C_ICONMGR, NoModifierMask, F_ICONIFY); #undef NoModifierMask } /*********************************************************************** * * Procedure: * GrabButtons - grab needed buttons for the window * * Inputs: * tmp_win - the twm window structure to use * *********************************************************************** */ #define AltMask (Alt1Mask | Alt2Mask | Alt3Mask | Alt4Mask | Alt5Mask) #define grabbutton(button, modifier, window, pointer_mode) \ XGrabButton (dpy, button, modifier, window, \ True, ButtonPressMask | ButtonReleaseMask, \ pointer_mode, GrabModeAsync, None, \ Scr->FrameCursor); void GrabButtons(TwmWindow *tmp_win) { FuncButton *tmp; int i; unsigned int ModifierMask[8] = { ShiftMask, ControlMask, LockMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask }; for (tmp = Scr->FuncButtonRoot.next; tmp != NULL; tmp = tmp->next) { if ((tmp->cont != C_WINDOW) || (tmp->func == 0)) continue; grabbutton (tmp->num, tmp->mods, tmp_win->frame, GrabModeAsync); if (Scr->IgnoreLockModifier && !(tmp->mods & LockMask)) { grabbutton (tmp->num, tmp->mods | LockMask, tmp_win->frame, GrabModeAsync); } for (i = 0 ; i < 8 ; i++) { if ((Scr->IgnoreModifier & ModifierMask [i]) && !(tmp->mods & ModifierMask [i])) grabbutton (tmp->num, tmp->mods | ModifierMask [i], tmp_win->frame, GrabModeAsync); } } if (Scr->ClickToFocus) { grabbutton (AnyButton, None, tmp_win->w, GrabModeSync); for (i = 0 ; i < 8 ; i++) { grabbutton (AnyButton, ModifierMask [i], tmp_win->w, GrabModeSync); } } else if (Scr->RaiseOnClick) { grabbutton (Scr->RaiseOnClickButton, None, tmp_win->w, GrabModeSync); for (i = 0 ; i < 8 ; i++) { grabbutton (Scr->RaiseOnClickButton, ModifierMask [i], tmp_win->w, GrabModeSync); } } } /*********************************************************************** * * Procedure: * GrabKeys - grab needed keys for the window * * Inputs: * tmp_win - the twm window structure to use * *********************************************************************** */ #define MAX_KEYCODE 256 #define grabkey(funckey, modifier, window) \ XGrabKey(dpy, funckey->keycode, funckey->mods | modifier, window, True, \ GrabModeAsync, GrabModeAsync); #define ungrabkey(funckey, modifier, window) \ XUngrabKey (dpy, funckey->keycode, funckey->mods | modifier, window); void GrabKeys(TwmWindow *tmp_win) { FuncKey *tmp; IconMgr *p; int i; unsigned int ModifierMask[8] = { ShiftMask, ControlMask, LockMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask }; for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next) { switch (tmp->cont) { case C_WINDOW: /* case C_WORKSPACE: */ if (tmp->mods & AltMask) break; grabkey (tmp, 0, tmp_win->w); if (Scr->IgnoreLockModifier && !(tmp->mods & LockMask)) grabkey (tmp, LockMask, tmp_win->w); for (i = 0 ; i < 8 ; i++) { if ((Scr->IgnoreModifier & ModifierMask [i]) && !(tmp->mods & ModifierMask [i])) grabkey (tmp, ModifierMask [i], tmp_win->w); } break; case C_ICON: if (!tmp_win->icon || tmp_win->icon->w) break; grabkey (tmp, 0, tmp_win->icon->w); if (Scr->IgnoreLockModifier && !(tmp->mods & LockMask)) grabkey (tmp, LockMask, tmp_win->icon->w); for (i = 0 ; i < 8 ; i++) { if ((Scr->IgnoreModifier & ModifierMask [i]) && !(tmp->mods & ModifierMask [i])) grabkey (tmp, ModifierMask [i], tmp_win->icon->w); } break; case C_TITLE: if (!tmp_win->title_w) break; grabkey (tmp, 0, tmp_win->title_w); if (Scr->IgnoreLockModifier && !(tmp->mods & LockMask)) grabkey (tmp, LockMask, tmp_win->title_w); for (i = 0 ; i < 8 ; i++) { if ((Scr->IgnoreModifier & ModifierMask [i]) && !(tmp->mods & ModifierMask [i])) grabkey (tmp, ModifierMask [i], tmp_win->title_w); } break; case C_NAME: grabkey (tmp, 0, tmp_win->w); if (Scr->IgnoreLockModifier && !(tmp->mods & LockMask)) { grabkey (tmp, LockMask, tmp_win->w); } for (i = 0 ; i < 8 ; i++) { if ((Scr->IgnoreModifier & ModifierMask [i]) && !(tmp->mods & ModifierMask [i])) grabkey (tmp, ModifierMask [i], tmp_win->w); } if (tmp_win->icon && tmp_win->icon->w) { grabkey (tmp, 0, tmp_win->icon->w); if (Scr->IgnoreLockModifier && !(tmp->mods & LockMask)) grabkey (tmp, LockMask, tmp_win->icon->w); for (i = 0 ; i < 8 ; i++) { if ((Scr->IgnoreModifier & ModifierMask [i]) && !(tmp->mods & ModifierMask [i])) grabkey (tmp, ModifierMask [i], tmp_win->icon->w); } } if (tmp_win->title_w) { grabkey (tmp, 0, tmp_win->title_w); if (Scr->IgnoreLockModifier && !(tmp->mods & LockMask)) grabkey (tmp, LockMask, tmp_win->title_w); for (i = 0 ; i < 8 ; i++) { if ((Scr->IgnoreModifier & ModifierMask [i]) && !(tmp->mods & ModifierMask [i])) grabkey (tmp, ModifierMask [i], tmp_win->title_w); } } break; /* case C_ROOT: XGrabKey(dpy, tmp->keycode, tmp->mods, Scr->Root, True, GrabModeAsync, GrabModeAsync); break; */ } } for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next) { if (tmp->cont == C_ICONMGR && !Scr->NoIconManagers) { for (p = Scr->iconmgr; p != NULL; p = p->next) { ungrabkey (tmp, 0, p->twm_win->w); if (Scr->IgnoreLockModifier && !(tmp->mods & LockMask)) ungrabkey (tmp, LockMask, p->twm_win->w); for (i = 0 ; i < 8 ; i++) { if ((Scr->IgnoreModifier & ModifierMask [i]) && !(tmp->mods & ModifierMask [i])) ungrabkey (tmp, ModifierMask [i], p->twm_win->w); } } } } } void ComputeCommonTitleOffsets (void) { int buttonwidth = (Scr->TBInfo.width + Scr->TBInfo.pad); Scr->TBInfo.leftx = Scr->TBInfo.rightoff = Scr->FramePadding; if (Scr->TBInfo.nleft > 0) Scr->TBInfo.leftx += Scr->ButtonIndent; if (Scr->TBInfo.nright > 0) Scr->TBInfo.rightoff += (Scr->ButtonIndent + (Scr->TBInfo.nright * buttonwidth) - Scr->TBInfo.pad); Scr->TBInfo.titlex = (Scr->TBInfo.leftx + (Scr->TBInfo.nleft * buttonwidth) - Scr->TBInfo.pad + Scr->TitlePadding); } static void CreateHighlightWindows (TwmWindow *tmp_win) { XSetWindowAttributes attributes; /* attributes for create windows */ GC gc; XGCValues gcv; unsigned long valuemask; int h = (Scr->TitleHeight - 2 * Scr->FramePadding); int y = Scr->FramePadding; if (! tmp_win->titlehighlight) { tmp_win->hilite_wl = (Window) 0; tmp_win->hilite_wr = (Window) 0; return; } /* * If a special highlight pixmap was given, use that. Otherwise, * use a nice, even gray pattern. The old horizontal lines look really * awful on interlaced monitors (as well as resembling other looks a * little bit too closely), but can be used by putting * * Pixmaps { TitleHighlight "hline2" } * * (or whatever the horizontal line bitmap is named) in the startup * file. If all else fails, use the foreground color to look like a * solid line. */ if (! tmp_win->HiliteImage) { if (Scr->HighlightPixmapName) { tmp_win->HiliteImage = GetImage (Scr->HighlightPixmapName, tmp_win->title); } } if (! tmp_win->HiliteImage) { Pixmap pm = None; Pixmap bm = None; if (Scr->use3Dtitles && (Scr->Monochrome != COLOR)) bm = XCreateBitmapFromData (dpy, tmp_win->title_w, (char*)black_bits, gray_width, gray_height); else bm = XCreateBitmapFromData (dpy, tmp_win->title_w, (char*)gray_bits, gray_width, gray_height); pm = XCreatePixmap (dpy, tmp_win->title_w, gray_width, gray_height, Scr->d_depth); gcv.foreground = tmp_win->title.fore; gcv.background = tmp_win->title.back; gcv.graphics_exposures = False; gc = XCreateGC (dpy, pm, (GCForeground|GCBackground|GCGraphicsExposures), &gcv); if (gc) { XCopyPlane (dpy, bm, pm, gc, 0, 0, gray_width, gray_height, 0, 0, 1); tmp_win->HiliteImage = (Image*) malloc (sizeof (struct _Image)); tmp_win->HiliteImage->pixmap = pm; tmp_win->HiliteImage->width = gray_width; tmp_win->HiliteImage->height = gray_height; tmp_win->HiliteImage->mask = None; tmp_win->HiliteImage->next = None; XFreeGC (dpy, gc); } else { XFreePixmap (dpy, pm); pm = None; } XFreePixmap (dpy, bm); } if (tmp_win->HiliteImage) { valuemask = CWBackPixmap; attributes.background_pixmap = tmp_win->HiliteImage->pixmap; } else { valuemask = CWBackPixel; attributes.background_pixel = tmp_win->title.fore; } if (Scr->use3Dtitles) { y += Scr->TitleShadowDepth; h -= 2 * Scr->TitleShadowDepth; } if (Scr->TitleJustification == J_LEFT) tmp_win->hilite_wl = (Window) 0; else tmp_win->hilite_wl = XCreateWindow (dpy, tmp_win->title_w, 0, y, (unsigned int) Scr->TBInfo.width, (unsigned int) h, (unsigned int) 0, Scr->d_depth, (unsigned int) CopyFromParent, Scr->d_visual, valuemask, &attributes); if (Scr->TitleJustification == J_RIGHT) tmp_win->hilite_wr = (Window) 0; else tmp_win->hilite_wr = XCreateWindow (dpy, tmp_win->title_w, 0, y, (unsigned int) Scr->TBInfo.width, (unsigned int) h, (unsigned int) 0, Scr->d_depth, (unsigned int) CopyFromParent, Scr->d_visual, valuemask, &attributes); } void DeleteHighlightWindows(TwmWindow *tmp_win) { if (tmp_win->HiliteImage) { if (Scr->HighlightPixmapName) { /* * Image obtained from GetImage(): it is in a cache * so we don't need to free it. There will not be multiple * copies if the same xpm:foo image is requested again. */ } else { XFreePixmap (dpy, tmp_win->HiliteImage->pixmap); free(tmp_win->HiliteImage); } tmp_win->HiliteImage = NULL; } } static void CreateLowlightWindows (TwmWindow *tmp_win) { XSetWindowAttributes attributes; /* attributes for create windows */ unsigned long valuemask; int h = (Scr->TitleHeight - 2 * Scr->FramePadding); int y = Scr->FramePadding; ColorPair cp; if (!Scr->UseSunkTitlePixmap || ! tmp_win->titlehighlight) { tmp_win->lolite_wl = (Window) 0; tmp_win->lolite_wr = (Window) 0; return; } /* * If a special highlight pixmap was given, use that. Otherwise, * use a nice, even gray pattern. The old horizontal lines look really * awful on interlaced monitors (as well as resembling other looks a * little bit too closely), but can be used by putting * * Pixmaps { TitleHighlight "hline2" } * * (or whatever the horizontal line bitmap is named) in the startup * file. If all else fails, use the foreground color to look like a * solid line. */ if (! tmp_win->LoliteImage) { if (Scr->HighlightPixmapName) { cp = tmp_win->title; cp.shadc = tmp_win->title.shadd; cp.shadd = tmp_win->title.shadc; tmp_win->LoliteImage = GetImage (Scr->HighlightPixmapName, cp); } } if (tmp_win->LoliteImage) { valuemask = CWBackPixmap; attributes.background_pixmap = tmp_win->LoliteImage->pixmap; } else { valuemask = CWBackPixel; attributes.background_pixel = tmp_win->title.fore; } if (Scr->use3Dtitles) { y += 2; h -= 4; } if (Scr->TitleJustification == J_LEFT) tmp_win->lolite_wl = (Window) 0; else tmp_win->lolite_wl = XCreateWindow (dpy, tmp_win->title_w, 0, y, (unsigned int) Scr->TBInfo.width, (unsigned int) h, (unsigned int) 0, Scr->d_depth, (unsigned int) CopyFromParent, Scr->d_visual, valuemask, &attributes); if (Scr->TitleJustification == J_RIGHT) tmp_win->lolite_wr = (Window) 0; else tmp_win->lolite_wr = XCreateWindow (dpy, tmp_win->title_w, 0, y, (unsigned int) Scr->TBInfo.width, (unsigned int) h, (unsigned int) 0, Scr->d_depth, (unsigned int) CopyFromParent, Scr->d_visual, valuemask, &attributes); } void ComputeWindowTitleOffsets (TwmWindow *tmp_win, unsigned int width, Bool squeeze) { int titlew = width - Scr->TBInfo.titlex - Scr->TBInfo.rightoff; switch (Scr->TitleJustification) { case J_LEFT : tmp_win->name_x = Scr->TBInfo.titlex; if (Scr->use3Dtitles) tmp_win->name_x += Scr->TitleShadowDepth + 2; break; case J_CENTER : tmp_win->name_x = Scr->TBInfo.titlex + (titlew - tmp_win->name_width) / 2; break; case J_RIGHT : tmp_win->name_x = Scr->TBInfo.titlex + titlew - tmp_win->name_width; if (Scr->use3Dtitles) tmp_win->name_x -= Scr->TitleShadowDepth - 2; break; } if (Scr->use3Dtitles) { if (tmp_win->name_x < (Scr->TBInfo.titlex + 2 * Scr->TitleShadowDepth)) tmp_win->name_x = Scr->TBInfo.titlex + 2 * Scr->TitleShadowDepth; } else if (tmp_win->name_x < Scr->TBInfo.titlex) { tmp_win->name_x = Scr->TBInfo.titlex; } tmp_win->highlightxl = Scr->TBInfo.titlex; tmp_win->highlightxr = tmp_win->name_x + tmp_win->name_width + 2; if (Scr->use3Dtitles) { tmp_win->highlightxl += Scr->TitleShadowDepth; } if (tmp_win->hilite_wr || Scr->TBInfo.nright > 0) tmp_win->highlightxr += Scr->TitlePadding; tmp_win->rightx = width - Scr->TBInfo.rightoff; if (squeeze && tmp_win->squeeze_info && !tmp_win->squeezed) { int rx = (tmp_win->highlightxr + (tmp_win->hilite_wr ? Scr->TBInfo.width * 2 : 0) + (Scr->TBInfo.nright > 0 ? Scr->TitlePadding : 0) + Scr->FramePadding); if (rx < tmp_win->rightx) tmp_win->rightx = rx; } return; } /* * ComputeTitleLocation - calculate the position of the title window; we need * to take the frame_bw into account since we want (0,0) of the title window * to line up with (0,0) of the frame window. */ void ComputeTitleLocation (register TwmWindow *tmp) { tmp->title_x = tmp->frame_bw3D - tmp->frame_bw; tmp->title_y = tmp->frame_bw3D - tmp->frame_bw; if (tmp->squeeze_info && !tmp->squeezed) { register SqueezeInfo *si = tmp->squeeze_info; int basex; int maxwidth = tmp->frame_width; int tw = tmp->title_width + 2 * tmp->frame_bw3D; /* * figure label base from squeeze info (justification fraction) */ if (si->denom == 0) { /* num is pixel based */ basex = si->num; } else { /* num/denom is fraction */ basex = ((si->num * maxwidth) / si->denom); } if (si->num < 0) basex += maxwidth; /* * adjust for left (nop), center, right justify and clip */ switch (si->justify) { case J_CENTER: basex -= tw / 2; break; case J_RIGHT: basex -= tw - 1; break; } if (basex > maxwidth - tw) basex = maxwidth - tw; if (basex < 0) basex = 0; tmp->title_x = basex - tmp->frame_bw + tmp->frame_bw3D; } } static void CreateWindowTitlebarButtons (TwmWindow *tmp_win) { unsigned long valuemask; /* mask for create windows */ XSetWindowAttributes attributes; /* attributes for create windows */ int leftx, rightx, y; TitleButton *tb; int nb; if (tmp_win->title_height == 0) { tmp_win->hilite_wl = (Window) 0; tmp_win->hilite_wr = (Window) 0; tmp_win->lolite_wl = (Window) 0; tmp_win->lolite_wr = (Window) 0; return; } /* * create the title bar windows; let the event handler deal with painting * so that we don't have to spend two pixmaps (or deal with hashing) */ ComputeWindowTitleOffsets (tmp_win, tmp_win->attr.width, False); leftx = y = Scr->TBInfo.leftx; rightx = tmp_win->rightx; attributes.win_gravity = NorthWestGravity; attributes.background_pixel = tmp_win->title.back; attributes.border_pixel = tmp_win->title.fore; attributes.event_mask = (ButtonPressMask | ButtonReleaseMask | ExposureMask); attributes.cursor = Scr->ButtonCursor; valuemask = (CWWinGravity | CWBackPixel | CWBorderPixel | CWEventMask | CWCursor); tmp_win->titlebuttons = NULL; nb = Scr->TBInfo.nleft + Scr->TBInfo.nright; if (nb > 0) { tmp_win->titlebuttons = (TBWindow *) malloc (nb * sizeof(TBWindow)); if (!tmp_win->titlebuttons) { fprintf (stderr, "%s: unable to allocate %d titlebuttons\n", ProgramName, nb); } else { TBWindow *tbw; int boxwidth = (Scr->TBInfo.width + Scr->TBInfo.pad); unsigned int h = (Scr->TBInfo.width - Scr->TBInfo.border * 2); for (tb = Scr->TBInfo.head, tbw = tmp_win->titlebuttons; tb; tb = tb->next, tbw++) { int x; if (tb->rightside) { x = rightx; rightx += boxwidth; attributes.win_gravity = NorthEastGravity; } else { x = leftx; leftx += boxwidth; attributes.win_gravity = NorthWestGravity; } tbw->window = XCreateWindow (dpy, tmp_win->title_w, x, y, h, h, (unsigned int) Scr->TBInfo.border, 0, (unsigned int) CopyFromParent, (Visual *) CopyFromParent, valuemask, &attributes); tbw->image = GetImage (tb->name, tmp_win->title); if (! tbw->image) { tbw->image = GetImage (TBPM_QUESTION, tmp_win->title); if (! tbw->image) { /* cannot happen (see util.c) */ fprintf (stderr, "%s: unable to add titlebar button \"%s\"\n", ProgramName, tb->name); } } tbw->info = tb; } } } CreateHighlightWindows (tmp_win); CreateLowlightWindows (tmp_win); XMapSubwindows(dpy, tmp_win->title_w); if (tmp_win->hilite_wl) XUnmapWindow(dpy, tmp_win->hilite_wl); if (tmp_win->hilite_wr) XUnmapWindow(dpy, tmp_win->hilite_wr); if (tmp_win->lolite_wl) XMapWindow(dpy, tmp_win->lolite_wl); if (tmp_win->lolite_wr) XMapWindow(dpy, tmp_win->lolite_wr); return; } void SetHighlightPixmap (char *filename) { #ifdef VMS char *ftemp; ftemp = (char *) malloc((strlen(filename)+1)*sizeof(char)); Scr->HighlightPixmapName = strcpy (ftemp,filename); #else Scr->HighlightPixmapName = (char*) strdup (filename); #endif } void FetchWmProtocols (TwmWindow *tmp) { unsigned long flags = 0L; Atom *protocols = NULL; int n; if (XGetWMProtocols (dpy, tmp->w, &protocols, &n)) { register int i; register Atom *ap; for (i = 0, ap = protocols; i < n; i++, ap++) { if (*ap == _XA_WM_TAKE_FOCUS) flags |= DoesWmTakeFocus; if (*ap == _XA_WM_SAVE_YOURSELF) flags |= DoesWmSaveYourself; if (*ap == _XA_WM_DELETE_WINDOW) flags |= DoesWmDeleteWindow; } if (protocols) XFree ((char *) protocols); } tmp->protocols = flags; } TwmColormap *CreateTwmColormap(Colormap c) { TwmColormap *cmap; cmap = (TwmColormap *) malloc(sizeof(TwmColormap)); if (!cmap || XSaveContext(dpy, c, ColormapContext, (XPointer) cmap)) { if (cmap) free((char *) cmap); return (NULL); } cmap->c = c; cmap->state = 0; cmap->install_req = 0; cmap->w = None; cmap->refcnt = 1; return (cmap); } ColormapWindow *CreateColormapWindow(Window w, Bool creating_parent, Bool property_window) { ColormapWindow *cwin; TwmColormap *cmap; XWindowAttributes attributes; cwin = (ColormapWindow *) malloc(sizeof(ColormapWindow)); if (cwin) { if (!XGetWindowAttributes(dpy, w, &attributes) || XSaveContext(dpy, w, ColormapContext, (XPointer) cwin)) { free((char *) cwin); return (NULL); } if (XFindContext(dpy, attributes.colormap, ColormapContext, (XPointer *)&cwin->colormap) == XCNOENT) { cwin->colormap = cmap = CreateTwmColormap(attributes.colormap); if (!cmap) { XDeleteContext(dpy, w, ColormapContext); free((char *) cwin); return (NULL); } } else { cwin->colormap->refcnt++; } cwin->w = w; /* * Assume that windows in colormap list are * obscured if we are creating the parent window. * Otherwise, we assume they are unobscured. */ cwin->visibility = creating_parent ? VisibilityPartiallyObscured : VisibilityUnobscured; cwin->refcnt = 1; /* * If this is a ColormapWindow property window and we * are not monitoring ColormapNotify or VisibilityNotify * events, we need to. */ if (property_window && (attributes.your_event_mask & (ColormapChangeMask|VisibilityChangeMask)) != (ColormapChangeMask|VisibilityChangeMask)) { XSelectInput(dpy, w, attributes.your_event_mask | (ColormapChangeMask|VisibilityChangeMask)); } } return (cwin); } int FetchWmColormapWindows (TwmWindow *tmp) { register int i, j; Window *cmap_windows = NULL; Bool can_free_cmap_windows = False; int number_cmap_windows = 0; ColormapWindow **cwins = NULL; int previously_installed; number_cmap_windows = 0; if (/* SUPPRESS 560 */ (previously_installed = (Scr->cmapInfo.cmaps == &tmp->cmaps && tmp->cmaps.number_cwins))) { cwins = tmp->cmaps.cwins; for (i = 0; i < tmp->cmaps.number_cwins; i++) cwins[i]->colormap->state = 0; } if (XGetWMColormapWindows (dpy, tmp->w, &cmap_windows, &number_cmap_windows) && number_cmap_windows > 0) { can_free_cmap_windows = False; /* * check if the top level is in the list, add to front if not */ for (i = 0; i < number_cmap_windows; i++) { if (cmap_windows[i] == tmp->w) break; } if (i == number_cmap_windows) { /* not in list */ Window *new_cmap_windows = (Window *) malloc (sizeof(Window) * (number_cmap_windows + 1)); if (!new_cmap_windows) { fprintf (stderr, "%s: unable to allocate %d element colormap window array\n", ProgramName, number_cmap_windows+1); goto done; } new_cmap_windows[0] = tmp->w; /* add to front */ for (i = 0; i < number_cmap_windows; i++) { /* append rest */ new_cmap_windows[i+1] = cmap_windows[i]; } XFree ((char *) cmap_windows); can_free_cmap_windows = True; /* do not use XFree any more */ cmap_windows = new_cmap_windows; number_cmap_windows++; } cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *) * number_cmap_windows); if (cwins) { for (i = 0; i < number_cmap_windows; i++) { /* * Copy any existing entries into new list. */ for (j = 0; j < tmp->cmaps.number_cwins; j++) { if (tmp->cmaps.cwins[j]->w == cmap_windows[i]) { cwins[i] = tmp->cmaps.cwins[j]; cwins[i]->refcnt++; break; } } /* * If the colormap window is not being pointed by * some other applications colormap window list, * create a new entry. */ if (j == tmp->cmaps.number_cwins) { if (XFindContext(dpy, cmap_windows[i], ColormapContext, (XPointer *)&cwins[i]) == XCNOENT) { if ((cwins[i] = CreateColormapWindow(cmap_windows[i], (Bool) tmp->cmaps.number_cwins == 0, True)) == NULL) { int k; for (k = i + 1; k < number_cmap_windows; k++) cmap_windows[k-1] = cmap_windows[k]; i--; number_cmap_windows--; } } else cwins[i]->refcnt++; } } } } /* No else here, in case we bailed out of clause above. */ if (number_cmap_windows == 0) { number_cmap_windows = 1; cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *)); if (XFindContext(dpy, tmp->w, ColormapContext, (XPointer *)&cwins[0]) == XCNOENT) cwins[0] = CreateColormapWindow(tmp->w, (Bool) tmp->cmaps.number_cwins == 0, False); else cwins[0]->refcnt++; } if (tmp->cmaps.number_cwins) free_cwins(tmp); tmp->cmaps.cwins = cwins; tmp->cmaps.number_cwins = number_cmap_windows; if (number_cmap_windows > 1) tmp->cmaps.scoreboard = (char *) calloc(1, ColormapsScoreboardLength(&tmp->cmaps)); if (previously_installed) { InstallColormaps(PropertyNotify, NULL); } done: if (cmap_windows) { if (can_free_cmap_windows) free ((char *) cmap_windows); else XFree ((char *) cmap_windows); } return (0); } void GetWindowSizeHints (TwmWindow *tmp) { long supplied = 0; XSizeHints *hints = &tmp->hints; if (!XGetWMNormalHints (dpy, tmp->w, hints, &supplied)) hints->flags = 0; if (hints->flags & PResizeInc) { if (hints->width_inc == 0) hints->width_inc = 1; if (hints->height_inc == 0) hints->height_inc = 1; } if (!(supplied & PWinGravity) && (hints->flags & USPosition)) { static int gravs[] = { SouthEastGravity, SouthWestGravity, NorthEastGravity, NorthWestGravity }; int right = tmp->attr.x + tmp->attr.width + 2 * tmp->old_bw; int bottom = tmp->attr.y + tmp->attr.height + 2 * tmp->old_bw; hints->win_gravity = gravs[((Scr->rooth - bottom < tmp->title_height + 2 * tmp->frame_bw3D) ? 0 : 2) | ((Scr->rootw - right < tmp->title_height + 2 * tmp->frame_bw3D) ? 0 : 1)]; hints->flags |= PWinGravity; } /* Check for min size < max size */ if ((hints->flags & (PMinSize|PMaxSize)) == (PMinSize|PMaxSize)) { if (hints->max_width < hints->min_width) { if (hints->max_width > 0) { hints->min_width = hints->max_width; } else if (hints->min_width > 0) { hints->max_width = hints->min_width; } else { hints->max_width = hints->min_width = 1; } } if (hints->max_height < hints->min_height) { if (hints->max_height > 0) { hints->min_height = hints->max_height; } else if (hints->min_height > 0) { hints->max_height = hints->min_height; } else { hints->max_height = hints->min_height = 1; } } } } void AnimateButton (TBWindow *tbw) { Image *image; XSetWindowAttributes attr; image = tbw->image; attr.background_pixmap = image->pixmap; XChangeWindowAttributes (dpy, tbw->window, CWBackPixmap, &attr); XClearWindow (dpy, tbw->window); tbw->image = image->next; } void AnimateHighlight (TwmWindow *t) { Image *image; XSetWindowAttributes attr; image = t->HiliteImage; attr.background_pixmap = image->pixmap; if (t->hilite_wl) { XChangeWindowAttributes (dpy, t->hilite_wl, CWBackPixmap, &attr); XClearWindow (dpy, t->hilite_wl); } if (t->hilite_wr) { XChangeWindowAttributes (dpy, t->hilite_wr, CWBackPixmap, &attr); XClearWindow (dpy, t->hilite_wr); } t->HiliteImage = image->next; } name_list **AddWindowRegion (char *geom, int grav1, int grav2) { WindowRegion *wr; int mask; wr = (WindowRegion*) malloc (sizeof (WindowRegion)); wr->next = NULL; if (!Scr->FirstWindowRegion) Scr->FirstWindowRegion = wr; wr->entries = NULL; wr->clientlist = NULL; wr->grav1 = grav1; wr->grav2 = grav2; wr->x = wr->y = wr->w = wr->h = 0; mask = XParseGeometry (geom, &wr->x, &wr->y, (unsigned int*) &wr->w, (unsigned int*) &wr->h); if (mask & XNegative) wr->x += Scr->rootw - wr->w; if (mask & YNegative) wr->y += Scr->rooth - wr->h; return (&(wr->clientlist)); } void CreateWindowRegions (void) { WindowRegion *wr, *wr1 = NULL, *wr2 = NULL; WorkSpace *wl; for (wl = Scr->workSpaceMgr.workSpaceList; wl != NULL; wl = wl->next) { wl->FirstWindowRegion = NULL; wr2 = NULL; for (wr = Scr->FirstWindowRegion; wr != NULL; wr = wr->next) { wr1 = (WindowRegion*) malloc (sizeof (WindowRegion)); *wr1 = *wr; wr1->entries = (WindowEntry*) malloc (sizeof (WindowEntry)); wr1->entries->next = 0; wr1->entries->x = wr1->x; wr1->entries->y = wr1->y; wr1->entries->w = wr1->w; wr1->entries->h = wr1->h; wr1->entries->twm_win = (TwmWindow*) 0; wr1->entries->used = 0; if (wr2) wr2->next = wr1; else wl->FirstWindowRegion = wr1; wr2 = wr1; } if (wr1) wr1->next = NULL; } } Bool PlaceWindowInRegion (TwmWindow *tmp_win, int *final_x, int *final_y) { WindowRegion *wr; WindowEntry *we; int w, h; WorkSpace *wl; if (!Scr->FirstWindowRegion) return (False); for (wl = Scr->workSpaceMgr.workSpaceList; wl != NULL; wl = wl->next) { if (OCCUPY (tmp_win, wl)) break; } if (!wl) return (False); w = tmp_win->frame_width; h = tmp_win->frame_height; we = (WindowEntry*) 0; for (wr = wl->FirstWindowRegion; wr; wr = wr->next) { if (LookInList (wr->clientlist, tmp_win->full_name, &tmp_win->class)) { for (we = wr->entries; we; we=we->next) { if (we->used) continue; if (we->w >= w && we->h >= h) break; } if (we) break; } } tmp_win->wr = (WindowRegion*) 0; if (!we) return (False); splitWindowRegionEntry (we, wr->grav1, wr->grav2, w, h); we->used = 1; we->twm_win = tmp_win; *final_x = we->x; *final_y = we->y; tmp_win->wr = wr; return (True); } static void splitWindowRegionEntry (WindowEntry *we, int grav1, int grav2, int w, int h) { WindowEntry *new; switch (grav1) { case D_NORTH: case D_SOUTH: if (w != we->w) splitWindowRegionEntry (we, grav2, grav1, w, we->h); if (h != we->h) { new = (WindowEntry *) malloc (sizeof (WindowEntry)); new->twm_win = 0; new->used = 0; new->next = we->next; we->next = new; new->x = we->x; new->h = (we->h - h); new->w = we->w; we->h = h; if (grav1 == D_SOUTH) { new->y = we->y; we->y = new->y + new->h; } else new->y = we->y + we->h; } break; case D_EAST: case D_WEST: if (h != we->h) splitWindowRegionEntry (we, grav2, grav1, we->w, h); if (w != we->w) { new = (WindowEntry *) malloc (sizeof (WindowEntry)); new->twm_win = 0; new->used = 0; new->next = we->next; we->next = new; new->y = we->y; new->w = (we->w - w); new->h = we->h; we->w = w; if (grav1 == D_EAST) { new->x = we->x; we->x = new->x + new->w; } else new->x = we->x + we->w; } break; } } static WindowEntry *findWindowEntry (WorkSpace *wl, TwmWindow *tmp_win, WindowRegion **wrp) { WindowRegion *wr; WindowEntry *we; for (wr = wl->FirstWindowRegion; wr; wr = wr->next) { for (we = wr->entries; we; we=we->next) { if (we->twm_win == tmp_win) { if (wrp) *wrp = wr; return we; } } } return (WindowEntry*) 0; } static WindowEntry *prevWindowEntry (WindowEntry *we, WindowRegion *wr) { WindowEntry *wp; if (we == wr->entries) return 0; for (wp = wr->entries; wp->next != we; wp=wp->next); return wp; } static void mergeWindowEntries (WindowEntry *old, WindowEntry *we) { if (old->y == we->y) { we->w = old->w + we->w; if (old->x < we->x) we->x = old->x; } else { we->h = old->h + we->h; if (old->y < we->y) we->y = old->y; } } void RemoveWindowFromRegion (TwmWindow *tmp_win) { WindowEntry *we, *wp, *wn; WindowRegion *wr; WorkSpace *wl; if (!Scr->FirstWindowRegion) return; we = (WindowEntry*) 0; for (wl = Scr->workSpaceMgr.workSpaceList; wl != NULL; wl = wl->next) { we = findWindowEntry (wl, tmp_win, &wr); if (we) break; } if (!we) return; we->twm_win = 0; we->used = 0; wp = prevWindowEntry (we, wr); wn = we->next; for (;;) { if (wp && wp->used == 0 && ((wp->x == we->x && wp->w == we->w) || (wp->y == we->y && wp->h == we->h))) { wp->next = we->next; mergeWindowEntries (we, wp); free ((char *) we); we = wp; wp = prevWindowEntry (wp, wr); } else if (wn && wn->used == 0 && ((wn->x == we->x && wn->w == we->w) || (wn->y == we->y && wn->h == we->h))) { we->next = wn->next; mergeWindowEntries (wn, we); free ((char *) wn); wn = we->next; } else break; } } /* * This is largely for Xinerama support with VirtualScreens. * In this case, windows may be on something other then the main screen * on startup, or the mapping may be relative to the right side of the * screen, which is on a different monitor, which will cause issues with * the virtual screens. * * It probably needs to be congnizant of windows that are actually owned by * other workspaces, and ignore them (this needs to be revisited), or perhaps * that functionality is appropriate in AddWindow(). This needs to be dug into * more deply. * * this approach assumes screens that are next to each other horizontally, * Other possibilities need to be investigated and accounted for. */ void DealWithNonSensicalGeometries(Display *mydpy, Window vroot, TwmWindow *tmp_win) { Window vvroot; int x,y; unsigned int w,h; unsigned int j; virtualScreen *myvs, *vs; int dropx = 0; if(! vroot) return; if(!(XGetGeometry(mydpy, vroot, &vvroot, &x, &y, &w, &h, &j, &j))) return; myvs = findIfVScreenOf(x, y); /* * probably need to rethink this for unmapped vs's. ugh. */ if(!myvs) return; for(vs = myvs->next; vs; vs = vs->next) { dropx += vs->w; } for(vs = Scr->vScreenList; vs && vs != myvs; vs = vs->next) { dropx -= vs->w; } if(tmp_win->frame_x > 0 && tmp_win->frame_x >= w) { tmp_win->frame_x -= abs(dropx); } else { } }