v12i072: olvwm - Open Look Virtual Window Manager, Part16/16

Scott Oaks - Sun Consulting NYC sdo at soliado.East.Sun.COM
Mon Apr 29 03:31:44 AEST 1991


Submitted-by: sdo at 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 at 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 at uunet.uu.net
argv at ora.com                 argv at zipcode.com



More information about the Comp.sources.x mailing list