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