sdo@soliado.East.Sun.COM (Scott Oaks - Sun Consulting NYC) (04/29/91)
Submitted-by: sdo@soliado.East.Sun.COM (Scott Oaks - Sun Consulting NYC) Posting-number: Volume 12, Issue 72 Archive-name: olvwm/part16 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 16 (of 16)." # Contents: winframe.c # Wrapped by sdo@piccolo on Fri Apr 26 17:31:11 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'winframe.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'winframe.c'\" else echo shar: Extracting \"'winframe.c'\" \(51092 characters\) sed "s/^X//" >'winframe.c' <<'END_OF_FILE' X/* X * (c) Copyright 1989, 1990 Sun Microsystems, Inc. Sun design patents X * pending in the U.S. and foreign countries. See LEGAL_NOTICE X * file for terms of the license. X * X * Written for Sun Microsystems by Crucible, Santa Cruz, CA. X */ X static char sccsid[] = "@(#)winframe.c 1.3 olvwm version 4/17/91"; X X/* X * Based on static char sccsid[] = "@(#) winframe.c 25.29 90/06/01 Crucible"; X * X */ X X#include <errno.h> X#include <stdio.h> X#include <string.h> X#include <X11/Xos.h> X#include <X11/Xlib.h> X#include <X11/Xutil.h> X#include <X11/Xatom.h> X#include <olgx/olgx.h> X#include "mem.h" X#include "olwm.h" X#include "win.h" X#include "menu.h" X#include "globals.h" X X/*************************************************************************** X* global data X***************************************************************************/ X extern Menu FrameFullMenuSticky, FrameFullMenuUnsticky; extern Menu FrameLimMenu; extern Menu FrameNormMenuSticky, FrameNormMenuUnsticky; extern Atom AtomLeftFooter; extern Atom AtomRightFooter; extern Atom AtomTakeFocus; extern Atom AtomDfltBtn; extern Window NoFocusWin; extern Graphics_info *olgx_gisnormal; extern int Resize_height, Resize_width; X extern GC DrawBackgroundGC; extern GC DrawNormalGC; extern GC DrawReverseGC; extern GC DrawBlackGC; extern GC DrawBusyGC; X X/*************************************************************************** X* private data X***************************************************************************/ X X/* Events in the adornment window that are interesting. */ X#define FRAME_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | \ X ExposureMask | Button1MotionMask | \ X EnterWindowMask | LeaveWindowMask | \ X SubstructureRedirectMask | \ X FocusChangeMask | PropertyChangeMask) X X/* REMIND rework this stuff so it can handle different point sizes */ X#define FRAME_OUTLINE_WIDTH 2 X#define FRAME_SELECTED_WIDTH 3 X static ClassPaneFrame classPaneFrame; X X/*************************************************************************** X* forward-declared functions X***************************************************************************/ X static void setTitleText(); static void setFooterText(); X X/*************************************************************************** X* sizing and decoration positioning functions X***************************************************************************/ X X/* decoration positioning */ X/* ptSize - determine the point size we're working with. X * REMIND this function is a hack which should be replaced with a X * glyph font property. X */ static int ptSize(gis) Graphics_info *gis; X{ X#ifdef OBSOLETE X switch (Resize_height) X { X case 10: X return 10; X case 11: X return 12; X case 12: X return 14; X case 14: X return 19; X default: X return 10+((int)(0.5 * Resize_height)); X } X#endif X return Pointsize_Glyph(gis); X} X static int xposCloseButton(gis) Graphics_info *gis; X{ X return ptSize(gis)+FRAME_OUTLINE_WIDTH; X} X static int yposCloseButton(cli,gis) Client *cli; Graphics_info *gis; X{ X if (Abbrev_MenuButton_Height(gis) < headerHeight(cli,gis)) X return(ResizeArm_Height(gis)+(headerHeight(cli,gis)-Abbrev_MenuButton_Height(gis))/2); X else X return ResizeArm_Height(gis)+(ptSize(gis)>>4+2); X} X static int xposPushPin(gis) Graphics_info *gis; X{ X return xposCloseButton(gis); X} X static int yposPushPin(cli,gis) Client *cli; Graphics_info *gis; X{ X if (PushPinOut_Height(gis) < headerHeight(cli,gis)) X return(ResizeArm_Height(gis)+(headerHeight(cli,gis)-PushPinOut_Height(gis))/2); X else X return ResizeArm_Height(gis)+(ptSize(gis)>>4); X} X static int decoToTitle(gis) Graphics_info *gis; X{ X#ifdef NOTDEF X return (2*xposCloseButton(gis))/3; X#endif X return (ptSize(gis)>>2); X} X X/* REMIND change this function to use olgx macros to extract X * font size X */ static int headerHeight(cli,gis) Client *cli; Graphics_info *gis; X{ X int fontht = GRV.TitleFontInfo->ascent X + GRV.TitleFontInfo->descent; X return MAX(Abbrev_MenuButton_Height(gis),fontht+3); X} X X/* REMIND this function should also be changed to use olgx macros */ static int footerHeight(cli,gis) Client *cli; Graphics_info *gis; X{ X return GRV.TitleFontInfo->ascent + GRV.TitleFontInfo->descent X + ResizeArm_Height(gis); X} X X X/* height/width functions */ int heightTopFrame(win) WinPaneFrame *win; X{ X Client *cli = win->core.client; X X if (cli->wmDecors->flags & WMDecorationHeader) X return headerHeight(cli,olgx_gisnormal)+2*ResizeArm_Height(olgx_gisnormal); X else X return ResizeArm_Height(olgx_gisnormal); X} X int heightBottomFrame(win) WinPaneFrame *win; X{ X Client *cli = win->core.client; X X if (cli->wmDecors->flags & WMDecorationFooter) X return footerHeight(cli,olgx_gisnormal)+ResizeArm_Height(olgx_gisnormal); X else X return ResizeArm_Height(olgx_gisnormal); X} X int widthRightFrame(win) WinPaneFrame *win; X{ X return ResizeArm_Width(olgx_gisnormal); X} X int widthLeftFrame(win) WinPaneFrame *win; X{ X return ResizeArm_Width(olgx_gisnormal); X} X X/*************************************************************************** X* event-handling functions X***************************************************************************/ X X/* X * handle events for the frame X * X * The reader should be aware of the fact that both the titlebar X * window and the frame window are affected when the window's X * focus and select state is changed. The window manager was X * being written before the OpenLook spec. was completed so it is X * not the most efficient design and is rather awkward in places. X * X * The way focusing is handled deserves some attention. For a X * detailed description of how focusing should be handled see X * the Inter-Client Communication Conventions Manual. I'll give X * a rough overview below. X * X * A client can use one of four input models: No Input, Passive, X * Locally Active, Globally Active. When OLWM is in focus-follows- X * mouse mode, focus is handled in a fairly straightforward manner. X * When the cursor enters a window, signaled by the frame getting X * an EnterNotify event, OLWM sets the focus like this: X * X * No Input - Do nothing. X * Passive - Set the focus using XSetInputFocus. X * Locally Active - Set the focus using XSetInputFocus. X * Globally Active - Set the focus by sending a message X * to the client. X * X * When OLWM is in click-to-focus mode, focus is a bit more complicated. X * This is due to the fact that the user can press down in the decoration X * around the client window and drag the window, and NOT set the focus. X * If the user just clicks, without moving, in the decoration then we X * set the focus. So, we don't know whether to set the focus until X * the button release event. But, if the user presses down in the X * client window we must set the focus immediately. This is so the user X * can go to an xterm which does not have the focus, press down, (which X * sets the focus), move the cursor, and release the button to select X * some text, for example. If the client is Passive or Locally Active, X * we have a passive grab on the SELECT button. This is how we handle X * setting the focus upon button press and release for the four input X * modes: X * X * ButtonPress X * No Input - Do Nothing. X * Passive - If the press was in the client, X * set the focus X * Locally Active - If the press was in the client, X * set the focus X * Globally Active - Do Nothing. X * X * ButtonRelease X * No Input - Do Nothing. X * Passive - Set the focus. We only get here X * if the button press was NOT in X * the client. X * Locally Active - Set the focus. We only get here X * if the button press was NOT in X * the client. X * Globally Active - Send a message to the client. X */ X X/* X * eventMapRequest -- the pane is go from iconic to normal states X */ static int eventMapRequest(dpy, event, frameInfo) Display *dpy; XXEvent *event; WinPaneFrame *frameInfo; X{ X Client *cli = frameInfo->core.client; X X /* transition from Iconic or Withdrawn */ X if (cli->wmState == IconicState ) { X StateIconNorm(cli); X } else { X#ifdef DEBUG X ErrorWarning("withdrawn window giving map request?"); X#endif /* DEBUG */ X } X} X X/* X * eventConfigureRequest -- the pane is trying to change configuration X */ static int eventConfigureRequest(dpy, event, frameInfo) Display *dpy; XXEvent *event; WinPaneFrame *frameInfo; X{ X Client *cli = frameInfo->core.client; X WinPane *winPane = (WinPane*)frameInfo->fcore.panewin; X X ClientConfigure(cli,winPane,event); X} X X/* X * selectClickFrame -- the select button has been clicked X */ static int selectClickFrame(dpy, event, frameInfo) Display *dpy; XXEvent *event; WinPaneFrame *frameInfo; X{ X WinPane *winPane = (WinPane*)frameInfo->fcore.panewin; X Client *cli = frameInfo->core.client; X X if (!GRV.FocusFollowsMouse) X { X ClientSetFocus(cli,True,event->xbutton.time); X } X} X X/* X * selectDoubleClickFrame -- the select button has been double-clicked X */ static int selectDoubleClickFrame(dpy, event, frameInfo) Display *dpy; XXEvent *event; WinPaneFrame *frameInfo; X{ X if (frameInfo->core.client->wmDecors->flags & WMDecorationResizeable) X { X if (frameInfo->normfullsizefunc != NULL) X (frameInfo->normfullsizefunc)(frameInfo); X } X} X X/* X * selectDragFrame -- the select button has been pressed and moved enough X * to trigger a drag. X */ static int selectDragFrame(dpy, event, frameInfo, lastpress) Display *dpy; XXEvent *event; WinPaneFrame *frameInfo; XXButtonEvent *lastpress; X{ X UserMoveWindows(dpy, lastpress, frameInfo); X} X X/* X * menuPressFrame -- the menu button has been pressed X */ static int menuPressFrame(dpy,event,frameInfo) Display *dpy; XXEvent *event; WinPaneFrame *frameInfo; X{ X if (frameInfo->fcore.menu) X MenuShow(dpy, frameInfo, frameInfo->fcore.menu, event ); X} X X/* X * selectPressFrame -- the select or adjust button has been pressed X */ static int selectAdjustPressFrame(dpy, event, frameInfo) Display *dpy; XXEvent *event; WinPaneFrame *frameInfo; X{ X Client *cli = frameInfo->core.client; X X /* If the button press was in the X * client, set the input focus. X */ X ClientSetFocus(cli,False,event->xbutton.time); X} X X X/* X * adjustClickFrame -- the adjust button has been pressed X */ static int adjustClickFrame(dpy, event, frameInfo) Display *dpy; XXEvent *event; WinPaneFrame *frameInfo; X{ X Client *cli = frameInfo->core.client; X X ToggleSelection(cli, event->xbutton.time); X if (!GRV.FocusFollowsMouse) X { X ClientSetFocus(cli,True,event->xbutton.time); X } X} X X/* X * eventEnterNotify -- if in follow-mouse and pointer enters this tree of windows, X * set the focus X */ static int eventEnterNotify(dpy, event, frameInfo) Display *dpy; XXEvent *event; WinPaneFrame *frameInfo; X{ X Client *cli = frameInfo->core.client; X WinRoot *root; X X if (GRV.FocusFollowsMouse && (event->xcrossing.detail != NotifyInferior)) X { X ClientSetFocus(cli,True,event->xcrossing.time); X } X X switch (event->xcrossing.detail) { X case NotifyInferior: X case NotifyNonlinear: X /* X * REMIND - it's sort of bogus that we must look up the client's X * root window X */ X root = WIGetInfo(RootWindow(cli->dpy, cli->screen)); X ColorWindowCrossing(dpy, event, root); X break; X } X X /* REMIND: does this imply and exit from the pane? If so, the X * pointer warping information is no longer valid and the X * pointerIsWarped flag should be set to False. On the other hand X * how will we distinguish the initial warp generated enterNotify X * from the enterFromPane enterNotify? X */ X} X X/* X * eventLeaveNotify -- if in follow-mouse and pointer left this tree of windows, X * set the focus to the NoFocus window X */ static int eventLeaveNotify(dpy, event, frameInfo) Display *dpy; XXEvent *event; WinPaneFrame *frameInfo; X{ X if (GRV.FocusFollowsMouse && (event->xcrossing.detail != NotifyInferior)) X { X NoFocusTakeFocus(dpy,event->xcrossing.time); X } X X /* if pointer had been warped to pane, this leave notify X * indicates that the user has shifted their attention away X * from the "warp-to" location, and it is no longer necessary X * to worry about warping the pointer back. X */ X if (frameInfo->pointerIsWarped) X frameInfo->pointerIsWarped = False; X} X X static int eventFocus(dpy, event, frameInfo) X Display *dpy; X XEvent *event; X WinPaneFrame *frameInfo; X{ X if (event->xfocus.detail != NotifyInferior) X WinCallFocus(frameInfo, (event->type == FocusIn)); X} X X X/* X * drawHeaderBusy3D X * draw the header in the busy state in 3D look X */ static void drawHeaderBusy3D(dpy, win, cli, sel) X Display *dpy; X WinPaneFrame *win; X Client *cli; X Bool sel; X{ X Window self = win->core.self; X int w = win->core.width; X int armh = ResizeArm_Height(olgx_gisnormal); X int armw = ResizeArm_Width(olgx_gisnormal); X X XFillRectangle(dpy, self, DrawBackgroundGC, armw, armh, X w-2*armw, heightTopFrame(win)-armh); X XFillRectangle(dpy, self, DrawBusyGC, armw, armh, X w-2*armw, heightTopFrame(win)-armh); X olgx_draw_text(olgx_gisnormal, self, win->fcore.name, win->titlex, X win->titley, 0, OLGX_NORMAL); X} X X X/* X * drawHeaderBusy2D X * draw the header in the busy state in 2D look X */ static void drawHeaderBusy2D(dpy, win, cli, sel) X Display *dpy; X WinPaneFrame *win; X Client *cli; X Bool sel; X{ X Window self = win->core.self; X int w = win->core.width; X int armh = ResizeArm_Height(olgx_gisnormal); X int armw = ResizeArm_Width(olgx_gisnormal); X X /* fill in frame-colored area below titlebar */ X XFillRectangle(dpy, self, DrawBackgroundGC, armw, armh, X w-2*armw, heightTopFrame(win)-armh); X XFillRectangle(dpy, self, DrawBusyGC, armw, armh, X w-2*armw, heightTopFrame(win)-armh); X X /* fill in window name in titlebar */ X XDrawString(dpy, self, DrawNormalGC, win->titlex, win->titley, X win->fcore.name, win->nameLength); X} X X X/* drawHeaderFocusClick3D - draw the header, with focus, in X * click-to-focus mode (3D) X */ static void drawHeaderFocusClick3D(dpy, win, cli, sel) Display *dpy; WinPaneFrame *win; Client *cli; Bool sel; X{ X Window self = win->core.self; X int w = win->core.width; X int armh = ResizeArm_Height(olgx_gisnormal); X X XFillRectangle(dpy, self, DrawBackgroundGC, widthLeftFrame(win), X heightTopFrame(win)-armh, w-widthLeftFrame(win)-widthRightFrame(win), armh); X X olgx_draw_box(olgx_gisnormal, self, widthLeftFrame(win), armh, X w-widthLeftFrame(win)-widthRightFrame(win), heightTopFrame(win)-(2*armh), X OLGX_INVOKED, True); X X olgx_draw_text(olgx_gisnormal, self, win->fcore.name, win->titlex, X win->titley, 0, OLGX_INVOKED); X} X X/* drawHeaderFocusFollow3D - draw the header, with focus, in X * focus-follow-mouse (3D mode) X */ static void drawHeaderFocusFollow3D(dpy, win, cli, sel) Display *dpy; WinPaneFrame *win; Client *cli; Bool sel; X{ X Window self = win->core.self; X int outlinewidth = sel?FRAME_SELECTED_WIDTH:FRAME_OUTLINE_WIDTH; X int w = win->core.width; X int armh = ResizeArm_Height(olgx_gisnormal); X int armw = ResizeArm_Width(olgx_gisnormal); X X XFillRectangle(dpy, self, DrawBackgroundGC, armw, armh, X w-2*armw, heightTopFrame(win)-armh); X X olgx_draw_text(olgx_gisnormal, self, win->fcore.name, win->titlex, X win->titley, 0, OLGX_NORMAL); X X if (cli->wmDecors->flags & WMDecorationResizeable) X olgx_draw_text_ledge(olgx_gisnormal, self, Resize_width+1, X outlinewidth+1, w-(2*Resize_width)-2); X else X olgx_draw_text_ledge(olgx_gisnormal, self, widthLeftFrame(win), X outlinewidth+1, w-widthLeftFrame(win)-widthRightFrame(win)); X X olgx_draw_text_ledge(olgx_gisnormal, self, widthLeftFrame(win), X heightTopFrame(win)-3, w-widthLeftFrame(win)-widthRightFrame(win)); X} X X/* drawHeaderNoFocus3D - draw the header, without focus (3D mode) X */ static void drawHeaderNoFocus3D(dpy, win, cli, sel) Display *dpy; WinPaneFrame *win; Client *cli; Bool sel; X{ X Window self = win->core.self; X int w = win->core.width; X int armh = ResizeArm_Height(olgx_gisnormal); X int armw = ResizeArm_Width(olgx_gisnormal); X X XFillRectangle(dpy, self, DrawBackgroundGC, armw, armh, X w-2*armw, heightTopFrame(win)-armh); X X olgx_draw_text(olgx_gisnormal, self, win->fcore.name, win->titlex, X win->titley, 0, OLGX_NORMAL); X} X X/* drawHeaderFocusClick2D - draw the header, with focus, in X * click-to-focus mode (2D) X */ static void drawHeaderFocusClick2D(dpy, win, cli, sel) Display *dpy; WinPaneFrame *win; Client *cli; Bool sel; X{ X Window self = win->core.self; X int w = win->core.width; X int armh = ResizeArm_Height(olgx_gisnormal); X X /* draw frame-colored rectangle below titlebar box */ X XFillRectangle(dpy, self, DrawBackgroundGC, widthLeftFrame(win), X heightTopFrame(win)-armh, w-widthLeftFrame(win)-widthRightFrame(win), armh); X X /* draw black titlebar to indicate 2d focus (XFillRectangle uses X * foreground color for fill) X */ X XFillRectangle(dpy, self, DrawBlackGC, widthLeftFrame(win), armh-1, X w-widthLeftFrame(win)-widthRightFrame(win), heightTopFrame(win)-(2*armh)+1); X X /* fill in window name */ X XDrawString(dpy, self, DrawReverseGC, win->titlex, win->titley, X win->fcore.name, win->nameLength); X} X X/* drawHeaderFocusFollow2D - draw the header, with focus, in X * focus-follow-mouse (2D mode) X */ static void drawHeaderFocusFollow2D(dpy, win, cli, sel) Display *dpy; WinPaneFrame *win; Client *cli; Bool sel; X{ X Window self = win->core.self; X int outlinewidth = sel?FRAME_SELECTED_WIDTH:FRAME_OUTLINE_WIDTH; X int w = win->core.width; X int armh = ResizeArm_Height(olgx_gisnormal); X int armw = ResizeArm_Width(olgx_gisnormal); X X /* fill in frame-colored area below titlebar area */ X XFillRectangle(dpy, self, DrawBackgroundGC, armw, armh, X w-2*armw, heightTopFrame(win)-armh); X X /* fill in window name */ X XDrawString(dpy, self, DrawNormalGC, win->titlex, win->titley, X win->fcore.name, win->nameLength); X X /* draw 2 pixel tall black focus indicator line above titlebar area X * (without overwriting the resize corners) X */ X if (cli->wmDecors->flags & WMDecorationResizeable) X XFillRectangle(dpy, self, DrawBlackGC, Resize_width+1, X outlinewidth+1, w-(2*Resize_width)-2, 2); X else X XFillRectangle(dpy, self, DrawBlackGC, widthLeftFrame(win), X outlinewidth+1, w-widthLeftFrame(win)-widthRightFrame(win), 2); X X /* draw 2 pixel tall black focus indicator line below titlebar area */ X XFillRectangle(dpy, self, DrawBlackGC, widthLeftFrame(win), heightTopFrame(win)-3, X w-widthLeftFrame(win)-widthRightFrame(win), 2); X} X X/* drawHeaderNoFocus2D - draw the header, without focus (2D mode) X */ static void drawHeaderNoFocus2D(dpy, win, cli, sel) Display *dpy; WinPaneFrame *win; Client *cli; Bool sel; X{ X Window self = win->core.self; X int w = win->core.width; X int armh = ResizeArm_Height(olgx_gisnormal); X int armw = ResizeArm_Width(olgx_gisnormal); X X /* fill in frame-colored area below titlebar */ X XFillRectangle(dpy, self, DrawBackgroundGC, armw, armh, X w-2*armw, heightTopFrame(win)-armh); X X /* fill in window name in titlebar */ X XDrawString(dpy, self, DrawNormalGC, win->titlex, win->titley, X win->fcore.name, win->nameLength); X} X X X/* drawFooter - draw the footer X */ static void drawFooter(dpy, win, cli) Display *dpy; WinPaneFrame *win; Client *cli; X{ X Window self = win->core.self; X int w = win->core.width; X int h = win->core.height; X int fy = h-heightBottomFrame(win); X int baseline = fy + GRV.TitleFontInfo->ascent + X ResizeArm_Height(olgx_gisnormal); X int margin = FRAME_OUTLINE_WIDTH + ptSize(olgx_gisnormal); X int footwidth = w - 2*margin; X int qfootwidth = footwidth / 4; X int gutter = ptSize(olgx_gisnormal); X int rstart, lmaxwidth, rmaxwidth; X X /* fill in frame-colored area above footer */ X XFillRectangle(dpy, self, DrawBackgroundGC, widthLeftFrame(win), fy, X w - widthLeftFrame(win) - widthRightFrame(win), X footerHeight(cli, olgx_gisnormal)); X X /* REMIND we don't paint the "more arrow" if text is truncated */ X X if ((win->leftfooterWidth + win->rightfooterWidth + gutter) X <= footwidth) { X /* room for both: no clipping */ X lmaxwidth = win->leftfooterWidth; X rmaxwidth = win->rightfooterWidth; X } else if (win->rightfooterWidth < qfootwidth) { X /* right footer takes less than 1/4 of the footer */ X rmaxwidth = win->rightfooterWidth; X lmaxwidth = footwidth - rmaxwidth - gutter; X } else if X ((win->leftfooterWidth) < (footwidth - qfootwidth - gutter)) { X /* left footer takes less than 3/4 of the footer */ X lmaxwidth = win->leftfooterWidth; X rmaxwidth = footwidth - lmaxwidth - gutter; X } else { X /* must truncate both */ X rmaxwidth = qfootwidth; X lmaxwidth = footwidth - qfootwidth - gutter; X } X rstart = w - margin - rmaxwidth; X X if (win->leftfooter) X olgx_draw_text(olgx_gisnormal, self, win->leftfooter, X margin, baseline, lmaxwidth, OLGX_NORMAL); X X if (win->rightfooter) X olgx_draw_text(olgx_gisnormal, self, win->rightfooter, X rstart, baseline, rmaxwidth, OLGX_NORMAL); X} X X/* drawBase2D - draw the outer border of the window (2D mode) X */ static void drawBase2D(dpy, win, cli, sel) Display *dpy; WinPaneFrame *win; Client *cli; Bool sel; X{ X Window self = win->core.self; X int outlinewidth = sel?FRAME_SELECTED_WIDTH:FRAME_OUTLINE_WIDTH; X int w = win->core.width; X int h = win->core.height; X int armh = ResizeArm_Height(olgx_gisnormal); X int armw = ResizeArm_Width(olgx_gisnormal); X X /* top base area */ X XFillRectangle(dpy, self, DrawBackgroundGC, outlinewidth, X outlinewidth, w-(2*outlinewidth), armh-outlinewidth); X XFillRectangle(dpy, self, DrawBlackGC, 0, 0, X w, outlinewidth); X X /* bottom base area */ X XFillRectangle(dpy, self, DrawBackgroundGC, outlinewidth, h-armh, X w-(2*outlinewidth), armh-outlinewidth); X XFillRectangle(dpy, self, DrawBlackGC, 0, h-outlinewidth, X w, outlinewidth); X X /* left base area */ X XFillRectangle(dpy, self, DrawBackgroundGC, outlinewidth, armh, X armw-outlinewidth, h-(2*armh)); X XFillRectangle(dpy, self, DrawBlackGC, 0, outlinewidth, X outlinewidth, h-(2*outlinewidth)); X X /* right base area */ X XFillRectangle(dpy, self, DrawBackgroundGC, w-armw, armh, X armw-outlinewidth, h-(2*armh)); X XFillRectangle(dpy, self, DrawBlackGC, w-outlinewidth, outlinewidth, X outlinewidth, h-(2*outlinewidth)); X} X X/* drawBase3D - draw the outer border of the window (3D mode) X */ static void drawBase3D(dpy, win, cli, sel) Display *dpy; WinPaneFrame *win; Client *cli; Bool sel; X{ X olgx_draw_box(olgx_gisnormal, win->core.self, 0, 0, win->core.width, X win->core.height, OLGX_NORMAL, True); X if (sel) { X olgx_draw_box(olgx_gisnormal, win->core.self, 1, 1, X win->core.width-2, win->core.height-2, X OLGX_NORMAL, False, 0); X } X} X X/* X * drawFrame -- draw the frame window X */ X/*ARGSUSED*/ /* dpy arg will be used when multiple Displays supported */ static int drawFrame(dpy, winInfo) Display *dpy; WinPaneFrame *winInfo; X{ X Client *cli = winInfo->core.client; X X if (GRV.F3dUsed && GRV.F3dFrames) X drawBase3D(dpy, winInfo, cli, cli->isSelected); X else X drawBase2D(dpy, winInfo, cli, cli->isSelected); X X if (cli->wmDecors->flags & WMDecorationHeader) X { X if (cli->isBusy) { X if (GRV.F3dUsed) X drawHeaderBusy3D(dpy, winInfo, cli, cli->isSelected); X else X drawHeaderBusy2D(dpy, winInfo, cli, cli->isSelected); X } X else if (cli->isFocus) X if (GRV.FocusFollowsMouse) X if (GRV.F3dUsed) X drawHeaderFocusFollow3D(dpy, winInfo, cli, cli->isSelected); X else X drawHeaderFocusFollow2D(dpy, winInfo, cli, cli->isSelected); X else X if (GRV.F3dUsed) X drawHeaderFocusClick3D(dpy, winInfo, cli, cli->isSelected); X else X drawHeaderFocusClick2D(dpy, winInfo, cli, cli->isSelected); X else X if (GRV.F3dUsed) X drawHeaderNoFocus3D(dpy, winInfo, cli); X else X drawHeaderNoFocus2D(dpy, winInfo, cli); X } X X if (cli->wmDecors->flags & WMDecorationFooter) X { X drawFooter(dpy, winInfo, cli); /* no difference between 2D and 3D */ X } X} X X X/* X * DestroyFrame -- destroy the frame window resources and free any allocated X * data. X */ static int destroyFrame(dpy, winInfo) Display *dpy; WinPaneFrame *winInfo; X{ Client *cli = winInfo->core.client; X X /* free our data and throw away window */ X ListDestroy(winInfo->core.children); X XFree(winInfo->fcore.name); X XFree(winInfo->leftfooter); X XFree(winInfo->rightfooter); X XUndefineCursor(dpy, winInfo->core.self); X XDestroyWindow(dpy,winInfo->core.self); X WIUninstallInfo(winInfo->core.self); X MemFree(winInfo); X if (cli->virtualWindow) X VirtualDestroy(dpy, cli); X} X X/* X * newconfigFrame -- compute a new configuration of frame window X */ static int newconfigFrame(winInfo, pxcre) WinPaneFrame *winInfo; XXConfigureRequestEvent *pxcre; X{ X Client *cli = winInfo->core.client; X Display *dpy = cli->dpy; X WinPane *winPane = (WinPane *)winInfo->fcore.panewin; X int neww; X int newh; X WinGeneric *winDeco; X X neww = winInfo->fcore.panewin->core.width + widthLeftFrame(winInfo) + X widthRightFrame(winInfo); X newh = winInfo->fcore.panewin->core.height + heightTopFrame(winInfo) + X heightBottomFrame(winInfo); X X if (neww != winInfo->core.width) X { X winInfo->core.width = neww; X winInfo->core.dirtyconfig |= CWWidth; X setTitleText(cli,dpy,winInfo,winPane->core.self); X setFooterText(cli,dpy,winInfo,winPane->core.self); X } X X if (newh != winInfo->core.height) X { X winInfo->core.height = newh; X winInfo->core.dirtyconfig |= CWHeight; X } X X if (winInfo->core.dirtyconfig) X { X (WinFunc(winPane,core.newposfunc))(winPane, widthLeftFrame(winInfo), X heightTopFrame(winInfo)); X winDeco = winInfo->winDeco; X if (cli->wmDecors->flags & WMDecorationPushPin) X { X (WinFunc(winDeco,core.newposfunc))(winDeco, X xposPushPin(olgx_gisnormal), X yposPushPin(cli,olgx_gisnormal)); X } X if (cli->wmDecors->flags & WMDecorationCloseButton) X { X (WinFunc(winDeco,core.newposfunc))(winDeco, X xposCloseButton(olgx_gisnormal), X yposCloseButton(cli,olgx_gisnormal)); X } X if (cli->isBusy && winInfo->winBusy != NULL) X (WinFunc(winInfo->winBusy,core.newposfunc))(winInfo->winBusy, X widthLeftFrame(winInfo), heightTopFrame(winInfo)); X } X X return winInfo->core.dirtyconfig; X} X X/* X * makeSpecials -- make any special mark windows (pushpin, close button) X */ static void makeSpecials(cli,dpy,wf,panewin,wid,high) Client *cli; Display *dpy; WinPaneFrame *wf; Window panewin; int wid,high; X{ X NewXSizeHints *hints; X int decorWidth; X X /* Make resize children */ X if (cli->wmDecors->flags & WMDecorationResizeable) X { X MakeResize(dpy, wf, upleft, 0, 0); X MakeResize(dpy, wf, upright, wid-Resize_width, 0); X MakeResize(dpy, wf, lowleft, 0, high-Resize_height); X MakeResize(dpy, wf, lowright, wid-Resize_width, high-Resize_height); X } X X /* Here we figure out, among other things, how much space X * the decorations will take up in the title bar. Also, we X * set the leftmost point at which the title string can be X * drawn without interfering with the decoration, if any, X * on the left hand side of the title bar. 'frame->titleOff' X * X * A window cannot have both a close button and a pushpin. So, if X * they ask for both, they only get the pushpin. This mutual X * exclusion was taken care of in GetOLWinDecors in states.c X */ X if (cli->wmDecors->flags & WMDecorationPushPin) X { X (WinPushPin *)(wf->winDeco) = X MakePushPin(dpy,wf,panewin,xposPushPin(olgx_gisnormal), X yposPushPin(cli,olgx_gisnormal)); X decorWidth = xposPushPin(olgx_gisnormal) + X PushPinOut_Width(olgx_gisnormal); X } X X if (cli->wmDecors->flags & WMDecorationCloseButton) X { X (WinButton *)(wf->winDeco) = X MakeButton(dpy,wf,xposCloseButton(olgx_gisnormal), X yposCloseButton(cli,olgx_gisnormal)); X decorWidth = xposCloseButton(olgx_gisnormal) + X Abbrev_MenuButton_Width(olgx_gisnormal) ; X } X X wf->titleOff = decorWidth + decoToTitle(olgx_gisnormal); X X /* Add decoration's size to minimum width of window. */ X hints = cli->normHints; X hints->min_width = MAX(decorWidth, hints->min_width); X} X X/* setvTitleText - extract the name of the window only for the use of the X * virtual window X */ static void setVTitleText(cli,dpy,w,panewin) Client *cli; Display *dpy; WinPaneFrame *w; Window panewin; X{ X char *tmp; X X /* Get window name */ X if (w->fcore.name) X MemFree(w->fcore.name); X X if (XFetchName(dpy, panewin, &tmp) == 0 || tmp == NULL) { X w->fcore.name = MemNewString(GRV.DefaultWinName); X } else { X /* X * Somewhat nitpicky. We copy the string with MemNewString to X * ensure that we can free it with MemFree (above), because the X * string returned by XFetchName must be freed with XFree. X */ X w->fcore.name = MemNewString(tmp); X XFree(tmp); X } X X w->nameLength = strlen(w->fcore.name); X w->nameWidth = XTextWidth(GRV.TitleFontInfo, w->fcore.name, w->nameLength); X} X X/* setTitleText - extract the name of the window and set up the titlebar X * area X */ static void setTitleText(cli,dpy,w,panewin) Client *cli; Display *dpy; WinPaneFrame *w; Window panewin; X{ X int availwidth; X char *ptr, *tmp; X X /* Get window name */ X if (w->fcore.name) X MemFree(w->fcore.name); X X if (XFetchName(dpy, panewin, &tmp) == 0 || tmp == NULL) { X w->fcore.name = MemNewString(GRV.DefaultWinName); X } else { X /* X * Somewhat nitpicky. We copy the string with MemNewString to X * ensure that we can free it with MemFree (above), because the X * string returned by XFetchName must be freed with XFree. X */ X w->fcore.name = MemNewString(tmp); X XFree(tmp); X } X X w->nameLength = strlen(w->fcore.name); X w->nameWidth = XTextWidth(GRV.TitleFontInfo, w->fcore.name, w->nameLength); X X#ifdef NOTDEF X availwidth = w->core.width - widthLeftFrame(w) - widthRightFrame(w) - X w->titleOff; X#endif X availwidth = w->core.width - widthRightFrame(w) - w->titleOff; X availwidth = MAX(0,availwidth); X X if (availwidth < w->nameWidth) X { X /* Must truncate the title. X * First we see if there is a colon and truncate X * all the chars up to the colon. X */ X if (ptr = strchr(w->fcore.name, ':')) X { X ptr++; /* after ':' */ X w->nameLength -= ptr - w->fcore.name; X tmp = w->fcore.name; X w->fcore.name = MemNewString(ptr); X MemFree(tmp); X w->nameWidth = XTextWidth( GRV.TitleFontInfo, w->fcore.name, X w->nameLength); X } X } X X while (availwidth < w->nameWidth) X { X /* Truncate the title from the right. */ X w->fcore.name[strlen(w->fcore.name) - 1] = '\0'; X w->nameLength--; X w->nameWidth = XTextWidth( GRV.TitleFontInfo, w->fcore.name, X w->nameLength); X } X X X /* Center that title. */ X w->titlex = w->titleOff + (availwidth - w->nameWidth)/2; X w->titley = GRV.TitleFontInfo->max_bounds.ascent + 2 + ResizeArm_Height(olgx_gisnormal); X} X X/* setFooterText - extract the footer texts and determine where to draw them X */ static void setFooterText(cli,dpy,w,panewin) Client *cli; Display *dpy; WinPaneFrame *w; Window panewin; X{ X unsigned long nItems, remain; X X /* REMIND add in truncation later */ X X /* Read the left footer, if any. */ X if (w->leftfooter != NULL) X XFree(w->leftfooter); X w->leftfooter = GetWindowProperty(dpy, panewin, AtomLeftFooter, 0L, X FOOTLEN, XA_STRING, 0, &nItems, &remain); X if (w->leftfooter == NULL) X w->leftfooterWidth = w->leftfooterLength = 0; X else X { X w->leftfooterLength = strlen(w->leftfooter); X w->leftfooterWidth = XTextWidth(GRV.TitleFontInfo, X w->leftfooter, w->leftfooterLength); X } X X /* Read the right footer, if any. */ X if (w->rightfooter != NULL) X XFree(w->rightfooter); X w->rightfooter = GetWindowProperty(dpy, panewin, AtomRightFooter, 0L, X FOOTLEN, XA_STRING, 0, &nItems, &remain); X if (w->rightfooter == NULL) X w->rightfooterWidth = w->rightfooterLength = 0; X else X { X w->rightfooterLength = strlen(w->rightfooter); X w->rightfooterWidth = XTextWidth(GRV.TitleFontInfo, X w->rightfooter, w->rightfooterLength); X } X X} X X X/* X * setupGrabs X * X * Set up any pointer grabs for this window, as appropriate for the focus mode X * (follow-mouse or click) and for the focus model (Passive, Globally Active, X * etc.) of this window. This is important for ClickFocus mode for Passive X * and Locally Active clients. If the user clicks over the pane window, we X * get the event, set the focus, and replay the event, thus passing the event X * through. X * X * SDO: We seem to get the event anyway. And grabbing the button seemed X * to cause lots of problems anyway, due perhaps to the grab bugs X * in xnews, but whatever; if the button press was destined for the X * VDM, we never got the button up (or anything else . . .). And X * X * REMIND we need to remove explicit reference to Buttons 1 and 2. X */ void XFrameSetupGrabs(cli, win, activate) X Client *cli; X Window win; X Bool activate; X{ X#ifdef NOTDEF X if (!GRV.FocusFollowsMouse) { X switch (cli->focusMode) { X case Passive: X case LocallyActive: X if (activate) { X XGrabButton(cli->dpy, Button1, 0, win, True, X ButtonPressMask | ButtonReleaseMask | Button1MotionMask, X GrabModeSync, GrabModeSync, None, None); X XGrabButton(cli->dpy, Button2, 0, win, True, X ButtonPressMask | ButtonReleaseMask | Button1MotionMask, X GrabModeSync, GrabModeSync, None, None); X } else { X XUngrabButton(cli->dpy, Button1, 0, win); X XUngrabButton(cli->dpy, Button2, 0, win); X } X break; X } X } X#endif X} X X X/*************************************************************************** X* global functions X***************************************************************************/ X X/* X * MakeFrame -- create the frame window. Return a WinPaneFrame structure. X * Note that unlike most Make functions, frames are not mapped right X * away. X */ WinPaneFrame * MakeFrame(cli,panewin,paneattrs) Client *cli; Window panewin; XXWindowAttributes *paneattrs; X{ X Display *dpy = cli->dpy; X int screen = cli->screen; X WinPaneFrame *w; X Window win; X XSetWindowAttributes attributes; X unsigned long valuemask; X int wid, high; X X /* create the frame window */ X valuemask = CWEventMask | CWSaveUnder | CWBackPixmap | CWCursor; X attributes.event_mask = FRAME_EVENT_MASK; X attributes.save_under = paneattrs->save_under; X attributes.background_pixmap = None; X attributes.cursor = GRV.TargetPointer; X X win = XCreateWindow(dpy, DefaultRootWindow(dpy), X 0, 0, 1, 1, X 0, X DefaultDepth(dpy, screen), X InputOutput, X DefaultVisual(dpy, screen), X valuemask, X &attributes); X X /* create the associated structure */ X w = MemNew(WinPaneFrame); X w->class = &classPaneFrame; X w->core.self = win; X w->core.kind = WIN_FRAME; X w->core.parent = NULL; X w->core.children = NULL; X w->core.client = cli; X /* x and y set later */ X X /* compute size of frame from pane */ X wid = paneattrs->width + widthLeftFrame(w) + widthRightFrame(w); X high = paneattrs->height + heightTopFrame(w) + heightBottomFrame(w); X X w->core.width = wid; /* these get fixed up at config time */ X w->core.height = high; X w->core.stack_mode = Above; X w->core.dirtyconfig = CWX | CWY | CWHeight | CWWidth | CWStackMode; X w->core.colormap = None; X w->core.exposures = NULL; X X /* REMIND this call appears to be redundant */ X FrameSetPosFromPane(w, paneattrs->x, paneattrs->y); X X cli->framewin = w; X X /* register the window */ X WIInstallInfo(w); X X /* if there's any special marks, make them */ X makeSpecials(cli,dpy,w,panewin,wid,high); X X /* set up the titlebar */ X if (cli->wmDecors->flags & WMDecorationHeader) X setTitleText(cli,dpy,w,panewin); X else X setVTitleText(cli, dpy, w, panewin); X X /* set up the footer */ X if (cli->wmDecors->flags & WMDecorationFooter) X setFooterText(cli,dpy,w,panewin); X X /* Determine which menu should come up when menus are requested X * for this frame. */ X switch(cli->wmDecors->menu_type) X { X case MENU_FULL: X if (cli->sticky) X w->fcore.menu = &FrameFullMenuSticky; X else w->fcore.menu = &FrameFullMenuUnsticky; X break; X X case MENU_LIMITED: X w->fcore.menu = &FrameLimMenu; X break; X X case MENU_NONE: X w->fcore.menu = NULL; X break; X } X X FrameSetupGrabs(cli, win, True); X X /* set the full/normal size to transition to full size X * on first activation */ X w->normfullsizefunc = FrameFullSize; X w->restoreSet = False; X X return w; X} X void XFrameInit(dpy) Display *dpy; X{ X classPaneFrame.core.kind = WIN_FRAME; X X classPaneFrame.core.xevents[MapRequest] = eventMapRequest; X classPaneFrame.core.xevents[ConfigureRequest] = eventConfigureRequest; X classPaneFrame.core.xevents[Expose] = WinEventExpose; X classPaneFrame.core.xevents[ButtonRelease] = GFrameEventButtonRelease; X classPaneFrame.core.xevents[MotionNotify] = GFrameEventMotionNotify; X classPaneFrame.core.xevents[ButtonPress] = GFrameEventButtonPress; X classPaneFrame.core.xevents[EnterNotify] = eventEnterNotify; X classPaneFrame.core.xevents[LeaveNotify] = eventLeaveNotify; X classPaneFrame.core.xevents[FocusIn] = eventFocus; X classPaneFrame.core.xevents[FocusOut] = eventFocus; X X classPaneFrame.core.focusfunc = GFrameFocus; X classPaneFrame.core.drawfunc = drawFrame; X classPaneFrame.core.destroyfunc = destroyFrame; X classPaneFrame.core.selectfunc = GFrameSelect; X classPaneFrame.core.newconfigfunc = newconfigFrame; X classPaneFrame.core.newposfunc = WinNewPosFunc; X classPaneFrame.core.setconfigfunc = GFrameSetConfigFunc; X classPaneFrame.core.createcallback = NULL; X classPaneFrame.core.heightfunc = NULL; X classPaneFrame.core.widthfunc = NULL; X classPaneFrame.fcore.heighttop = heightTopFrame; X classPaneFrame.fcore.heightbottom = heightBottomFrame; X classPaneFrame.fcore.widthleft = widthRightFrame; X classPaneFrame.fcore.widthright = widthLeftFrame; X classPaneFrame.fcore.menuPress = menuPressFrame; X classPaneFrame.fcore.adjustPress = selectAdjustPressFrame; X classPaneFrame.fcore.adjustClick = adjustClickFrame; X classPaneFrame.fcore.selectPress = selectAdjustPressFrame; X classPaneFrame.fcore.selectClick = selectClickFrame; X classPaneFrame.fcore.selectDoubleClick = selectDoubleClickFrame; X classPaneFrame.fcore.selectDrag = selectDragFrame; X} X X#ifdef NOTDEF X/* FrameSetStack -- set the frame's stacking position. Does not initiate X * a configuration change. X */ void XFrameSetStack(win, mask, mode, sib) WinPaneFrame *win; int mask; int mode; Window sib; X{ X WinGeneric *wsib; X X if ((mask & CWSibling) && (mask & CWStackMode)) X { X wsib = WIGetInfo(sib); X if (wsib != NULL) X { X win->core.stack_sib = wsib->core.client->framewin->core.self; X win->core.dirtyconfig |= CWSibling; X } X } X if (mask & CWStackMode) X { X win->core.stack_mode = mode; X win->core.dirtyconfig |= CWStackMode; X } X} X#endif /* NOTDEF */ X X X/* FrameMoveRelative X * Moves a frame by a delta in x and y X */ void XFrameMoveRelative(win,dx,dy) WinPaneFrame *win; int dx,dy; X{ X (WinFunc(win,core.newposfunc))(win,win->core.x+dx,win->core.y+dy); X} X X X/* X * FrameSetPosAbsolute X * The client is moving the pane to an absolute location on the screen, so we X * must move the frame accordingly. X */ void XFrameSetPosAbsolute(win, x, y) X WinPaneFrame *win; X int x, y; X{ X int fx, fy; X WinGenericPane *pane = win->fcore.panewin; X int panebord = (pane == NULL)?(0):(pane->pcore.oldBorderWidth); X X fx = x - widthLeftFrame(win)+panebord; X fy = y - heightTopFrame(win)+panebord; X (WinFunc(win,core.newposfunc))(win, fx, fy); X} X X X/* FrameSetPosFromPane -- the client has specified a position for the pane. X * Using the window gravity, the frame's position should be adjusted X * so that the point on the frame named by the window gravity is at the X * corresponding point in the requested pane. X * REMIND we aren't accounting for the window's border width here X */ void XFrameSetPosFromPane(win,x,y) WinPaneFrame *win; int x,y; X{ X int bw = widthLeftFrame(win)+widthRightFrame(win); X int bh = heightTopFrame(win)+heightBottomFrame(win); X WinGenericPane *pane = win->fcore.panewin; X int panebord = (pane == NULL)?(0):(pane->pcore.oldBorderWidth); X X switch (win->core.client->normHints->win_gravity) X { X case NorthWestGravity: X break; X X case NorthGravity: X x -= bw/2-panebord; X break; X X case NorthEastGravity: X x -= bw-2*panebord; X break; X X case WestGravity: X y -= bh/2-panebord; X break; X X case CenterGravity: X y -= bh/2-panebord; X x -= bw/2-panebord; X break; X X case EastGravity: X y -= bh/2-panebord; X x -= bw-2*panebord; X break; X X case SouthWestGravity: X y -= bh-2*panebord; X break; X X case SouthGravity: X y -= bh-2*panebord; X x -= bw/2-panebord; X break; X X case SouthEastGravity: X y -= bh-2*panebord; X x -= bw-2*panebord; X break; X X } X (WinFunc(win,core.newposfunc))(win, x, y); X} X X/* FrameUnparentPane -- Reparent the pane back to the root, moving the pane's X * position according to the window gravity X * REMIND we aren't accounting for the window's border width yet X */ void XFrameUnparentPane(cli, winFrame, winPane) Client *cli; WinPaneFrame *winFrame; WinPane *winPane; X{ X int x = winFrame->core.x; X int y = winFrame->core.y; X int bw = widthLeftFrame(winFrame)+widthRightFrame(winFrame); X int bh = heightTopFrame(winFrame)+heightBottomFrame(winFrame); X int panebord = winPane->pcore.oldBorderWidth; X X switch (winFrame->core.client->normHints->win_gravity) X { X case NorthWestGravity: X break; X X case NorthGravity: X x += bw/2-panebord; X break; X X case NorthEastGravity: X x += bw-2*panebord; X break; X X case WestGravity: X y += bh/2-panebord; X break; X X case CenterGravity: X y += bh/2-panebord; X x += bw/2-panebord; X break; X X case EastGravity: X y += bh/2-panebord; X x += bw-2*panebord; X break; X X case SouthWestGravity: X y += bh-2*panebord; X break; X X case SouthGravity: X y += bh-2*panebord; X x += bw/2-panebord; X break; X X case SouthEastGravity: X y += bh-2*panebord; X x += bw-2*panebord; X break; X } X X XSetWindowBorderWidth(cli->dpy,winPane->core.self,winPane->pcore.oldBorderWidth); X if (winPane->pcore.oldSaveUnder) X { X XSetWindowAttributes xwa; X xwa.save_under = True; X XChangeWindowAttributes(cli->dpy,winPane->core.self,CWSaveUnder,&xwa); X } X X if (winPane->core.kind != WIN_MENU) { X XReparentWindow(cli->dpy, winPane->core.self, X DefaultRootWindow(cli->dpy), x, y); X XChangeSaveSet(cli->dpy, winPane->core.self, SetModeDelete); X } X} X X X/* X * FrameFullSize -- make the frame full size X */ void XFrameFullSize(frameInfo) WinPaneFrame *frameInfo; X{ X Client *cli = frameInfo->core.client; X WinPane *paneInfo = (WinPane *)frameInfo->fcore.panewin; X int maxheight; X X /* substite "normal size" menu for "full size" menu */ X if (cli->wmDecors->menu_type == MENU_FULL) { X if (cli->sticky) X frameInfo->fcore.menu = &FrameNormMenuSticky; X else frameInfo->fcore.menu = &FrameNormMenuUnsticky; X } X X /* save restore size attributes */ X if (!frameInfo->restoreSet) X { X frameInfo->restoreWidth = paneInfo->core.width; X frameInfo->restoreHeight = paneInfo->core.height; X frameInfo->restoreY = frameInfo->core.y; X frameInfo->restoreSet = True; X } X X /* if there is a program specified max size */ X if ((cli->normHints) && X (cli->normHints->flags & PMaxSize)) X { X (WinFunc(paneInfo,pcore.setsizefunc))(paneInfo, X cli->normHints->max_width, X cli->normHints->max_height); X WinCallConfig(cli->dpy, paneInfo, NULL); X } X else X { X /* move window to top of screen and change the X * height to Display Height */ X frameInfo->core.y = 0; X frameInfo->core.dirtyconfig |= CWY; X maxheight = DisplayHeight(cli->dpy, cli->screen) - X heightTopFrame(frameInfo) - heightBottomFrame(frameInfo); X (WinFunc(paneInfo,pcore.setsizefunc))(paneInfo, paneInfo->core.width, X maxheight); X WinCallConfig(cli->dpy, paneInfo, NULL); X } X frameInfo->normfullsizefunc = FrameNormSize; X} X X/* X * FrameNormSize -- restore the frame to normal size X */ void XFrameNormSize(winInfo) WinPaneFrame *winInfo; X{ X Client *cli = winInfo->core.client; X WinPane *paneInfo = (WinPane *)winInfo->fcore.panewin; X X /* substite "full size" menu for "normal size" menu */ X if (cli->wmDecors->menu_type == MENU_FULL) { X if (cli->sticky) X winInfo->fcore.menu = &FrameFullMenuSticky; X else winInfo->fcore.menu = &FrameFullMenuUnsticky; X } X X /* restore from saved values */ X winInfo->core.y = winInfo->restoreY; X winInfo->core.dirtyconfig |= CWY; X winInfo->restoreSet = False; X X /* call the pane's config func to register new size */ X (WinFunc(paneInfo,pcore.setsizefunc))(paneInfo, winInfo->restoreWidth, X winInfo->restoreHeight); X WinCallConfig(cli->dpy, paneInfo, NULL); X winInfo->normfullsizefunc = FrameFullSize; X} X X/* FrameNewFooter -- the footer text has changed; update as appropriate */ void XFrameNewFooter(cli) Client *cli; X{ X setFooterText(cli,cli->dpy,cli->framewin,PANEWINOFCLIENT(cli)); X (WinFunc(cli->framewin,core.drawfunc))(cli->dpy, cli->framewin); X} X X/* FrameNewHeader -- the header text has changed; update as appropriate */ void XFrameNewHeader(cli) Client *cli; X{ X setTitleText(cli,cli->dpy,cli->framewin,PANEWINOFCLIENT(cli)); X (WinFunc(cli->framewin,core.drawfunc))(cli->dpy, cli->framewin); X} X X/* FrameFlashTitleBar -- flash the title bar X */ void XFrameFlashTitleBar(winInfo) WinPaneFrame *winInfo; X{ X Client *cli = winInfo->core.client; X Display *dpy = cli->dpy; X int ii; X void (*drawdiff)(), (*drawsame)(); X X if (GRV.F3dUsed) X { X if (cli->isFocus) X { X drawsame = (GRV.FocusFollowsMouse) ? X (drawHeaderFocusFollow3D):(drawHeaderFocusClick3D); X drawdiff = drawHeaderNoFocus3D; X } X else X { X drawdiff = (GRV.FocusFollowsMouse) ? X (drawHeaderFocusFollow3D):(drawHeaderFocusClick3D); X drawsame = drawHeaderNoFocus3D; X } X } X else X { X if (cli->isFocus) X { X drawsame = (GRV.FocusFollowsMouse) ? X (drawHeaderFocusFollow2D):(drawHeaderFocusClick2D); X drawdiff = drawHeaderNoFocus2D; X } X else X { X drawdiff = (GRV.FocusFollowsMouse) ? X (drawHeaderFocusFollow2D):(drawHeaderFocusClick2D); X drawsame = drawHeaderNoFocus2D; X } X } X X for (ii=0; ii<6; ii++) X { X drawdiff(dpy, winInfo, cli, cli->isSelected); X XFlush(dpy); X olwm_usleep((unsigned)(GRV.FlashTime)); X drawsame(dpy, winInfo, cli, cli->isSelected); X XFlush(dpy); X olwm_usleep((unsigned)(GRV.FlashTime)); X } X} X X/* FrameSetBusy - change the frame's busy state. The client's overall X * indication has already been set; create a busy window and manipulate X * the focus (if necessary). X */ void XFrameSetBusy(win, newBusy) WinPaneFrame *win; Bool newBusy; X{ X if (newBusy) X { X win->winBusy = MakeBusy(win->core.client->dpy, win); X } X else X { X (WinFunc(win->winBusy,core.destroyfunc))(win->core.client->dpy, win->winBusy); X } X WinCallDraw(win); X} X X/* FrameWarpPointer - warp to pane windows default button position (if necessary) X * This function can only be called AFTER the frame & pane are mapped. X */ X#define WARPINFO_LEN 6 void XFrameWarpPointer(cli) Client *cli; X{ X WinPaneFrame *frameInfo; X WinPane *paneInfo; X int *warpParam; X Bool sameScreen; /* pointer is on same screen as client */ X unsigned long nItems, remain; X Window root, child; X int root_x, root_y, win_x; X unsigned int keys_buttons; X X frameInfo = cli->framewin; X paneInfo = (WinPane*)(frameInfo->fcore.panewin); X X /* if user has turned off pointer warping, just invalidate the warpinfo */ X if (!GRV.PopupJumpCursor) X { X frameInfo->pointerIsWarped = False; X return; X } X X /* see if window pane has any warp info */ X /* REMIND: could this property be tracked automatically? */ X warpParam = GetWindowProperty(cli->dpy, paneInfo->core.self, AtomDfltBtn, X 0L, WARPINFO_LEN, XA_INTEGER, 0, &nItems, &remain); X X if (warpParam == NULL) X { X frameInfo->pointerIsWarped = False; X } X else if (nItems != WARPINFO_LEN) X { X frameInfo->pointerIsWarped = False; X XFree(warpParam); X } X else X { X /* save warp destination information */ X cli->warpInfo.warpToX = warpParam[0]; X cli->warpInfo.warpToY = warpParam[1]; X cli->warpInfo.dflButtonX = warpParam[2]; X cli->warpInfo.dflButtonY = warpParam[3]; X cli->warpInfo.dflButtonW = warpParam[4]; X cli->warpInfo.dflButtonH = warpParam[5]; X X /* save warp return information */ X sameScreen = XQueryPointer(cli->dpy, paneInfo->core.self, X &root, &child, &root_x, &root_y, X &win_x, &win_x, &keys_buttons); X cli->warpInfo.warpBackWin = root; X cli->warpInfo.warpBackX = root_x; X cli->warpInfo.warpBackY = root_y; X X /* warp the pointer */ X XWarpPointer(cli->dpy, X None, paneInfo->core.self, X 0, 0, 0, 0, X cli->warpInfo.warpToX, X cli->warpInfo.warpToY); X X frameInfo->pointerIsWarped = True; X XFree(warpParam); X } X X} X X/* FrameUnwarpPointer - called when a pane is unmapping, and the pointer X * needs to be restored to its original position (if it was warped when the X * window was initially mapped). X */ void XFrameUnwarpPointer(cli) Client *cli; X{ X WinPaneFrame *frameInfo; X WinPane *paneInfo; X int warpx, warpy; X Window root, child; int rootx, rooty, winx, winy, state; Bool result; X X frameInfo = cli->framewin; X paneInfo = (WinPane*)(frameInfo->fcore.panewin); X X result = XQueryPointer(cli->dpy, DefaultRootWindow(cli->dpy), X &root, &child, &rootx, &rooty, &winx, &winy, X &state); X X /* X * The pane window may already be unmapped at this point, so we must X * translate the origin of the warp rectangle into root coordinates. X */ X WinRootPos(paneInfo, &warpx, &warpy); X warpx += cli->warpInfo.dflButtonX; X warpy += cli->warpInfo.dflButtonY; X X if (frameInfo->pointerIsWarped) { X XWarpPointer(cli->dpy, DefaultRootWindow(cli->dpy), X cli->warpInfo.warpBackWin, X warpx, warpy, X cli->warpInfo.dflButtonW, cli->warpInfo.dflButtonH, X cli->warpInfo.warpBackX, cli->warpInfo.warpBackY); X /* invalidate the pointer warp info */ X frameInfo->pointerIsWarped = False; X } X} END_OF_FILE if test 51092 -ne `wc -c <'winframe.c'`; then echo shar: \"'winframe.c'\" unpacked with wrong size! fi # end of 'winframe.c' fi echo shar: End of archive 16 \(of 16\). cp /dev/null ark16isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 16 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Dan Heller O'Reilly && Associates Z-Code Software Comp-sources-x: Senior Writer President comp-sources.x@uunet.uu.net argv@ora.com argv@zipcode.com