Files
cdesktop/cde/programs/dtwm/WmWinState.c
Liang Chang 8fa32b3db5 dtwm: Trigger fullscreen in an "edge trigger" manner to avoid wrong
behaviors caused by some unusual operations. E.g., after entered
fullscreen, applications change windows to other states instead of
leaving fullscreen.
2021-11-05 14:21:32 +08:00

1478 lines
34 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these libraries and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/*
* (c) Copyright 1989, 1990, 1991, 1992 OPEN SOFTWARE FOUNDATION, INC.
* ALL RIGHTS RESERVED
*/
/*
* Motif Release 1.2.1
*/
/*
* (c) Copyright 1987, 1988, 1989, 1990 HEWLETT-PACKARD COMPANY */
/*
* Included Files:
*/
#include "WmGlobal.h"
#include "WmICCC.h"
#include "WmProtocol.h"
#include "WmIPC.h"
/*
* include extern functions
*/
#include "WmCDecor.h"
#include "WmCDInfo.h"
#include "WmFunction.h"
#include "WmIDecor.h"
#include "WmIPlace.h"
#include "WmIconBox.h"
#include "WmKeyFocus.h"
#include "WmPanelP.h" /* for typedef in WmManage.h */
#include "WmManage.h"
#include "WmProperty.h"
#include "WmWinInfo.h"
#include "WmWinList.h"
#include "WmWrkspace.h"
/*
* Function Declarations:
*/
#include "WmMultiHead.h"
#include "WmWinState.h"
static void SlideWindowOut (ClientData *pCD);
static void UnmapClients (ClientData *pCD, unsigned int event_mask);
static void SetupWindowStateWithEventMask (ClientData *pCD, int newState, Time setTime, unsigned int event_mask);
/*
* Global Variables:
*/
extern int firstTime;
/******************************<->*************************************
*
* SetClientState (pCD, newState, setTime)
*
*
* Description:
* -----------
* This function is used to change the state of a client window (between
* withdrawn, normal, minimized, maximized).
*
*
* Inputs:
* ------
* pCD = This is a pointer to the window data for the window that
* is to have its state changed. The fields that are used
* are clientState, ...
*
* newState = This is the state that the client window is to be changed to.
*
* setTime = timestamp for state setting operations
*
*
* Outputs:
* -------
* pCD.clientState = new client state
*
******************************<->***********************************/
void SetClientState (ClientData *pCD, int newState, Time setTime)
{
SetClientStateWithEventMask(pCD, newState, setTime, (unsigned int)0);
} /* END OF FUNCTION SetClientState */
void SetClientStateWithEventMask (ClientData *pCD, int newState, Time setTime, unsigned int event_mask)
{
ClientData *pcdLeader;
int currentState;
WmScreenData *pSD = PSD_FOR_CLIENT(pCD);
Boolean notShowing = (newState & UNSEEN_STATE);
currentState = pCD->clientState;
if (currentState == newState)
{
/* no change in state */
return;
}
/*
* Undo the old state and setup the new state. If this is a transient
* window then insure that it is put in a state that is compatible
* with its transient leader (e.g., it cannot be minimized separately).
*/
pcdLeader = (pCD->transientLeader) ? FindTransientTreeLeader (pCD) : pCD;
SetClientWsIndex (pCD);
if (pCD->transientLeader)
{
if ((pcdLeader->clientState == MINIMIZED_STATE) &&
(newState != WITHDRAWN_STATE))
{
newState = MINIMIZED_STATE;
if (notShowing)
{
newState |= UNSEEN_STATE;
}
}
else if ((newState == MINIMIZED_STATE) &&
(pcdLeader->clientState != MINIMIZED_STATE))
{
if (currentState == WITHDRAWN_STATE)
{
newState = NORMAL_STATE;
if (notShowing)
{
newState |= UNSEEN_STATE;
}
}
else
{
newState = currentState;
if (notShowing)
{
newState |= UNSEEN_STATE;
}
}
}
if (newState == currentState)
{
return;
}
}
switch (newState)
{
case UNSEEN_STATE | WITHDRAWN_STATE:
{
/*
* Free window manager resources (frame and icon). The
* WM_STATE property is set in WithdrawWindow.
*/
UnManageWindow (pCD);
break;
}
case NORMAL_STATE:
case MAXIMIZED_STATE:
{
SetupWindowStateWithEventMask (pCD, newState, setTime, event_mask);
XMapWindow (DISPLAY, pCD->client);
XMapWindow (DISPLAY, pCD->clientFrameWin);
WmStopWaiting(); /* in WmIPC.c */
break;
}
case MINIMIZED_STATE:
{
Boolean clientHasFocus;
/*
* Transient windows are minimized with the rest of the transient
* tree, including the transient leader.
*/
if ((pCD->clientState == NORMAL_STATE) ||
(pCD->clientState == MAXIMIZED_STATE))
{
if ((wmGD.keyboardFocus == pCD) ||
(pCD->transientChildren && wmGD.keyboardFocus &&
(pCD == FindTransientTreeLeader (wmGD.keyboardFocus))))
{
clientHasFocus = True;
}
else
{
clientHasFocus = False;
}
if (clientHasFocus ||
((wmGD.nextKeyboardFocus == pCD) ||
(pCD->transientChildren && wmGD.keyboardFocus &&
(pCD == FindTransientTreeLeader (wmGD.nextKeyboardFocus)))))
{
/*
* Give up the keyboard focus when minimized (including
* the case in which an associated transient window has
* the focus). Immediately remove the focus indication
* from the window being minimized.
*/
if (wmGD.autoKeyFocus &&
(wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT))
{
AutoResetKeyFocus (pcdLeader, setTime);
}
else
{
Do_Focus_Key (NULL, setTime,
ALWAYS_SET_FOCUS | WORKSPACE_IF_NULL);
}
if (clientHasFocus)
{
SetKeyboardFocus (NULL, 0);
}
}
/* unmap main client and all transients */
UnmapClients (pCD, event_mask);
}
/*
* Display the icon for the minimized client.
*/
if (ICON_FRAME_WIN(pCD))
{
if (pCD->clientState & UNSEEN_STATE)
{
if (pCD->iconWindow)
{
XMapWindow (DISPLAY, pCD->iconWindow);
}
XMapWindow (DISPLAY, ICON_FRAME_WIN(pCD));
}
ShowAllIconsForMinimizedClient (pCD);
}
SetClientWMState (pCD, IconicState, MINIMIZED_STATE);
if ((pSD->useIconBox) && P_ICON_BOX(pCD))
{
if ((pCD->clientFlags & ICON_BOX) && ACTIVE_ICON_TEXT_WIN)
{
/*
* Hide active icon text window and reparent it to
* root
*/
HideActiveIconText((WmScreenData *)NULL);
pSD->activeLabelParent = ACTIVE_ROOT;
XReparentWindow(DISPLAY, ACTIVE_ICON_TEXT_WIN ,
ACTIVE_ROOT, 0, 0 );
}
if (ICON_FRAME_WIN(pCD))
{
/*
* force icon appearance in icon box to change
*/
IconExposureProc (pCD, True);
}
}
break;
}
case UNSEEN_STATE | NORMAL_STATE:
case UNSEEN_STATE | MAXIMIZED_STATE:
case UNSEEN_STATE | MINIMIZED_STATE:
{
if (wmGD.keyboardFocus == pCD)
{
/*
* Give up the keyboard focus
*/
Do_Focus_Key ((ClientData *)NULL,
CurrentTime, ALWAYS_SET_FOCUS);
SetKeyboardFocus (NULL, 0);
}
if (!(pCD->clientState & UNSEEN_STATE) &&
(((pCD->clientState & ~UNSEEN_STATE) == NORMAL_STATE) ||
((pCD->clientState & ~UNSEEN_STATE) == MAXIMIZED_STATE)))
{
/* unmap main client and all transients */
UnmapClients (pcdLeader, event_mask);
}
if (pCD->clientFrameWin)
{
if (!P_ICON_BOX(pCD))
{
if (ICON_FRAME_WIN(pCD))
{
XUnmapWindow (DISPLAY, ICON_FRAME_WIN(pCD));
}
if (pCD->iconWindow)
XUnmapWindow (DISPLAY, pCD->iconWindow);
}
}
switch (newState & ~UNSEEN_STATE)
{
case MINIMIZED_STATE:
SetClientWMState (pCD, IconicState, newState);
break;
case NORMAL_STATE:
case MAXIMIZED_STATE:
default:
SetClientWMState (pCD, NormalState, newState);
break;
}
}
break;
}
} /* END OF FUNCTION SetClientStateWithEventMask */
/*************************************<->*************************************
*
* SetupWindowStateWithEventMask (pCD, newState, setTime, event_mask)
*
*
* Description:
* -----------
* This function is used to setup a client window in the Normal or Maximized
* state.
*
*
* Inputs:
* ------
* pCD = This is a pointer to the window data for the window that
* is to have its state changed.
*
* newState = This is the state that the client window is to be changed to.
*
* setTime = timestamp for state setting operations
*
* event_mask = what to grab to prevent stray events going somewhere
*
* Outputs:
* -------
* pCD.clientState = new client state
*
*************************************<->***********************************/
static void SetupWindowStateWithEventMask (ClientData *pCD, int newState,
Time setTime, unsigned int event_mask)
{
int currentState;
int wsI, iplace;
WmWorkspaceData *pWS_i;
WmScreenData *pSD = PSD_FOR_CLIENT(pCD);
currentState = pCD->clientState;
/*
* A transient window is not restored or maximized if the transient leader
* is minimized.
*/
if (newState == NORMAL_STATE)
{
if (pCD->maxConfig == True)
{
/*
* The configuration function uses maxConfig to determine
* what the current configuration is (and then resets
* maxConfig) and uses the state paramenter to determine
* what the new configuration is.
*/
ConfigureNewState (pCD);
}
}
else /* MAXIMIZED_STATE */
{
if (pCD->maxConfig == False)
{
ConfigureNewState (pCD);
}
}
if (currentState == MINIMIZED_STATE)
{
Boolean clearIconFocus;
/*
* give up keyboard focus
*/
if ((wmGD.keyboardFocus == pCD) ||
(wmGD.nextKeyboardFocus == pCD))
{
Do_Focus_Key (NULL, setTime, ALWAYS_SET_FOCUS | WORKSPACE_IF_NULL);
}
if (wmGD.keyboardFocus == pCD)
{
clearIconFocus = True;
}
else
{
clearIconFocus = False;
}
/*
* The wm icon frame window and the client icon window
* (if it is being used) are mapped and the client window and
* client frame are unmapped.
*/
if (ICON_FRAME_WIN(pCD))
{
if (pSD->useIconBox && P_ICON_BOX(pCD) &&
!(pCD->clientFlags & ICON_BOX))
{
ShowClientIconState(pCD, newState);
}
else
{
Boolean doGrab = False;
if (event_mask)
doGrab = (Success == XGrabPointer
(DISPLAY, DefaultRootWindow(DISPLAY),
False, event_mask, GrabModeAsync, GrabModeAsync,
None, None, CurrentTime));
XUnmapWindow (DISPLAY, ICON_FRAME_WIN(pCD));
if (pCD->iconWindow)
{
XUnmapWindow (DISPLAY, pCD->iconWindow);
}
if (event_mask && doGrab)
{
XEvent event;
XMaskEvent(DISPLAY, event_mask, &event);
XUngrabPointer(DISPLAY,CurrentTime);
}
if (wmGD.iconAutoPlace)
{
for (wsI = 0; wsI < pCD->numInhabited; wsI++)
{
iplace = pCD->pWsList[wsI].iconPlace;
if (iplace != NO_ICON_PLACE)
{
pWS_i = GetWorkspaceData (pCD->pSD,
pCD->pWsList[wsI].wsID);
pWS_i->IPData.placeList[iplace].pCD =
NULL;
}
}
}
}
if (clearIconFocus)
{
ClearFocusIndication (pCD, False /*no refresh*/);
wmGD.keyboardFocus = NULL;
}
}
}
if ((currentState != NORMAL_STATE) && (currentState != MAXIMIZED_STATE))
{
/*
* Note that maximized state is considered a NormalState in
* the ICCC. SetClientWMState also sets the state in the
* client data.
*/
if (currentState == MINIMIZED_STATE)
{
/*
* Raise the window(s) when they are deiconified.
*/
pCD->clientState = newState;
wmGD.bSuspendSecondaryRestack = True;
F_Raise (NULL, pCD, NULL);
wmGD.bSuspendSecondaryRestack = False;
}
if ( (!(pCD->clientFlags & ICON_BOX)) ||
((pCD->clientFlags & ICON_BOX) && (!(firstTime))) )
{
if ((currentState == WITHDRAWN_STATE) &&
(pCD->dtwmBehaviors & DtWM_BEHAVIOR_SUBPANEL) &&
!(pCD->transientChildren))
{
if (pCD->dtwmBehaviors & DtWM_BEHAVIOR_SUB_RESTORED)
{
pCD->dtwmBehaviors &= ~DtWM_BEHAVIOR_SUB_RESTORED;
pCD->dtwmBehaviors &= ~DtWM_BEHAVIOR_SUBPANEL;
XMapWindow (DISPLAY, pCD->client);
XMapWindow (DISPLAY, pCD->clientFrameWin);
}
else
{
SlideWindowOut (pCD);
}
}
else
MapClientWindows (pCD);
}
/*
* Set the WM_STATE property of the window and any associated
* transients, along with the clientState value. The call
* is made with an indication of NORMAL_STATE to insure
* that transient window clientState values are setup
* correctly. The top-level window clientState is set later.
*/
SetClientWMState (pCD, NormalState, NORMAL_STATE);
}
pCD->clientState = newState;
if ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT) &&
(currentState == MINIMIZED_STATE) && wmGD.deiconifyKeyFocus)
{
ClientData *pcdFocus;
pcdFocus = FindTransientFocus (pCD);
if (pcdFocus)
{
Do_Focus_Key (pcdFocus, setTime, ALWAYS_SET_FOCUS);
}
}
if ( pSD->useIconBox && P_ICON_BOX(pCD) &&
(!(pCD->clientFlags & ICON_BOX)) && (ICON_FRAME_WIN(pCD)))
{
/*
* force icon appearance in icon box to change
*/
IconExposureProc (pCD, True);
}
} /* END OF FUNCTION SetupWindowStateWithEventMask */
/*************************************<->*************************************
*
* ConfigureNewState (pcd)
*
*
* Description:
* -----------
* Configure the window to a new state
*
*
* Inputs:
* ------
* pcd - pointer to client data
*
* Outputs:
* -------
*
*
* Comments:
* --------
* o This is only good for going between NORMAL and MAXIMIZED state.
*
*************************************<->***********************************/
void ConfigureNewState (ClientData *pcd)
{
WmHeadInfo_t *WmHI = NULL;
if (pcd->maxConfig)
{
pcd->maxConfig = FALSE;
RegenerateClientFrame(pcd);
XResizeWindow (DISPLAY, pcd->client,
(unsigned int) pcd->clientWidth,
(unsigned int) pcd->clientHeight);
XDeleteProperty (DISPLAY, pcd->client, wmGD.xa_NET_WM_STATE);
}
else
{
if (pcd->enterFullscreen && pcd->monitorSizeIsSet)
{
pcd->maxX = pcd->monitorX;
pcd->maxY = pcd->monitorY;
pcd->maxWidth = pcd->monitorWidth;
pcd->maxHeight = pcd->monitorHeight;
FrameToClient(pcd, &pcd->maxX, &pcd->maxY, &pcd->maxWidth,
&pcd->maxHeight);
}
else if (WmHI = GetHeadInfo(pcd)) {
/*
* Update client config to reflect underlying head, if MultiHead is
* active
*/
FrameToClient(pcd, &WmHI->x_org, &WmHI->y_org,
&WmHI->width, &WmHI->height);
pcd->maxX = WmHI->x_org;
pcd->maxY = WmHI->y_org;
pcd->maxWidth = WmHI->width;
pcd->maxHeight = WmHI->height;
free(WmHI);
}
XResizeWindow (DISPLAY, pcd->client,
(unsigned int) pcd->maxWidth,
(unsigned int) pcd->maxHeight);
pcd->maxConfig = TRUE;
RegenerateClientFrame(pcd);
if (pcd->enterFullscreen)
XChangeProperty (DISPLAY, pcd->client, wmGD.xa_NET_WM_STATE,
XA_ATOM, 32, PropModeReplace,
(unsigned char *) &wmGD.xa_NET_WM_STATE_FULLSCREEN,
1);
}
pcd->enterFullscreen = False;
SendConfigureNotify (pcd);
/*
* Force repaint if size doesn't change to update frame appearance.
*/
if ((pcd->clientWidth == pcd->maxWidth) &&
(pcd->clientHeight == pcd->maxHeight))
{
FrameExposureProc (pcd);
}
} /* END OF FUNCTION ConfigureNewState */
/*************************************<->*************************************
*
* UnmapClients (pCD, event_mask)
*
*
* Description:
* -----------
* Unmap the window(s). The indicated client may be the head of a transient
* tree - if it is unmap all windows in the transient tree.
*
*
* Inputs:
* ------
* pCD = pointer to client data of window(s) to be unmapped
* event_mask = what to grab to prevent stray events going somewhere. Our
* passive grab has just been activated -- but it is dropped when the
* window is unmapped and the ButtonRelease event can go to the window
* now exposed. Avoid this by grabbing the ButtonRelease before the unmap
* and swallowing it.
* Also done for icon being unmapped.
*
*************************************<->***********************************/
static void UnmapClients (ClientData *pCD, unsigned int event_mask)
{
ClientData *pNext;
Boolean doGrab = False;
pNext = pCD->transientChildren;
while (pNext)
{
/* unmap all children first */
if (pNext->transientChildren)
UnmapClients (pNext, (unsigned int) 0);
/* then unmap all siblings at this level */
XUnmapWindow (DISPLAY, pNext->clientFrameWin);
XUnmapWindow (DISPLAY, pNext->client);
pNext->wmUnmapCount++;
pNext = pNext->transientSiblings;
}
if (event_mask)
doGrab = (Success == XGrabPointer (DISPLAY, DefaultRootWindow(DISPLAY),
False, event_mask, GrabModeAsync, GrabModeAsync,
None, None, CurrentTime));
/* unmap this primary window */
XUnmapWindow (DISPLAY, pCD->clientFrameWin);
XUnmapWindow (DISPLAY, pCD->client);
if (event_mask && doGrab)
{
XEvent event;
XMaskEvent(DISPLAY, event_mask, &event);
XUngrabPointer(DISPLAY,CurrentTime);
}
pCD->wmUnmapCount++;
} /* END OF FUNCTION UnmapClients */
/*************************************<->*************************************
*
* SetClientWMState (pCD, wmState, mwmState)
*
*
* Description:
* -----------
* Set a new window manage state for a client window or a tree of transient
* client windows.
*
* Inputs:
* ------
* pCD = pointer to client data
*
* wmState = new state for WM_STATE property
*
* mwmState = mwm client state
*
*************************************<->***********************************/
void SetClientWMState (ClientData *pCD, int wmState, int mwmState)
{
ClientData *pNext;
Boolean bToUnseen;
bToUnseen = (mwmState & UNSEEN_STATE) != 0;
mwmState &= ~UNSEEN_STATE;
SetClientWsIndex (pCD);
pNext = pCD->transientChildren;
while (pNext)
{
if (pNext->transientChildren)
{
SetClientWMState (pNext, wmState, mwmState);
}
SetClientWsIndex (pNext);
SetWMState (pNext->client, wmState, ICON_FRAME_WIN(pNext));
if (pNext->maxConfig && mwmState == NORMAL_STATE)
{
pNext->clientState = MAXIMIZED_STATE;
}
else if (!pNext->maxConfig && mwmState == MAXIMIZED_STATE)
{
pNext->clientState = NORMAL_STATE;
}
else
{
pNext->clientState = mwmState;
}
if (bToUnseen)
pNext->clientState |= UNSEEN_STATE;
pNext = pNext->transientSiblings;
}
SetWMState (pCD->client, wmState, ICON_FRAME_WIN(pCD));
pCD->clientState = mwmState;
if (bToUnseen)
pCD->clientState |= UNSEEN_STATE;
} /* END OF FUNCTION SetClientWMState */
#define SLIDE_UP_PERCENTAGE 5
#define SLIDE_UP_DIVISOR (100/SLIDE_UP_PERCENTAGE)
#define SLIDE_UP_INTERVAL 15
/******************************<->*************************************
*
* void SlideOutTimerProc (client_data, id)
*
* Description:
* -----------
* An XtTimerCallbackProc to process slide up mapping of a panel
*
* Inputs:
* ------
* client_data = pointer to a SlideOutRec
*
* Outputs:
* -------
*
*
* Comments:
* --------
******************************<->***********************************/
void
SlideOutTimerProc ( XtPointer client_data, XtIntervalId *id)
{
SlideOutRec *pSOR = (SlideOutRec *) client_data;
Boolean bDone = False;
if (pSOR)
{
/*
* compute next increment;
*/
switch (pSOR->direction)
{
case SLIDE_NORTH:
if (pSOR->mapping)
{
pSOR->currY -= pSOR->incHeight;
pSOR->currHeight += pSOR->incHeight;
if ((pSOR->currY < pSOR->pCD->frameInfo.y) ||
(pSOR->currHeight > pSOR->pCD->frameInfo.height))
{
pSOR->currY = pSOR->pCD->frameInfo.y;
pSOR->currHeight = pSOR->pCD->frameInfo.height;
}
bDone = (pSOR->currY == pSOR->pCD->frameInfo.y);
}
else
{
pSOR->currY += pSOR->incHeight;
if (pSOR->incHeight >= pSOR->currHeight)
{
pSOR->currHeight = 0;
bDone = True;
}
else
{
pSOR->currHeight -= pSOR->incHeight;
}
}
break;
case SLIDE_SOUTH:
if (pSOR->mapping)
{
pSOR->currHeight += pSOR->incHeight;
if (pSOR->currHeight > pSOR->pCD->frameInfo.height)
{
pSOR->currHeight = pSOR->pCD->frameInfo.height;
}
bDone =
(pSOR->currHeight == pSOR->pCD->frameInfo.height);
}
else
{
if (pSOR->incHeight >= pSOR->currHeight)
{
pSOR->currHeight = 0;
bDone = True;
}
else
{
pSOR->currHeight -= pSOR->incHeight;
}
}
break;
}
/*
* do next slide-up
*/
if (pSOR->currHeight > 0)
{
XMoveResizeWindow (DISPLAY, pSOR->coverWin,
pSOR->currX, pSOR->currY,
pSOR->currWidth, pSOR->currHeight);
XMoveResizeWindow (DISPLAY, pSOR->pCD->clientFrameWin,
pSOR->currX, pSOR->currY,
pSOR->currWidth, pSOR->currHeight);
}
/*
* See if we need to continue
*/
if (bDone)
{
if (!pSOR->mapping)
{
/* Time to really unmanage the slide-up */
XtUnmanageChild (pSOR->wSubpanel);
}
else
{
WmSubpanelPosted (DISPLAY1, pSOR->pCD->client);
SendConfigureNotify(pSOR->pCD);
}
/* done! clean up */
XDestroyWindow (DISPLAY, pSOR->coverWin);
pSOR->pCD->pSOR = NULL;
XtFree ((char *)pSOR);
wmGD.iSlideUpsInProgress -= 1;
}
else
{
/* re-arm the timer */
XtAppAddTimeOut(wmGD.mwmAppContext, pSOR->interval,
SlideOutTimerProc, (XtPointer)pSOR);
XSync (DISPLAY, False);
}
}
} /* END OF FUNCTION SlideOutTimerProc */
/*************************************<->*************************************
*
* SlideWindowOut (pCD)
*
*
* Description:
* -----------
* Maps a window with a slide-out effect.
*
*
* Inputs:
* ------
* pCD = pointer to client data
*
* Comment:
* -------
* Only supports slide-up or slide-down
*
*************************************<->***********************************/
static void
SlideWindowOut (ClientData *pCD)
{
SlideOutRec *pSOR;
if (pCD->pSOR)
{
pSOR = pCD->pSOR;
/*
* Hmmm. We're already sliding this window.
* If we're supposed to go in the other direction,
* then turn it around.
*/
if (pSOR->mapping == True)
{
/*
* We're already mapping this guy, ignore this
* and finish what we've already got going.
*/
return;
}
else
{
/*
* We're not mapping this guy. Reverse course!!
*/
pSOR->mapping = True;
/* insure the client window is mapped */
XMapWindow (DISPLAY, pCD->client);
/* handle the rest on the next timeout */
return;
}
}
/* map the primary window */
XMapWindow (DISPLAY, pCD->client);
pSOR = (SlideOutRec *) XtMalloc (sizeof(SlideOutRec));
if (pSOR)
{
/*
* Compute this ahead of time so we can check against
* the window size. If the window is short, we'll
* just map it, avoiding a lot of processing.
*/
pSOR->incHeight = (Dimension) (DisplayHeight(DISPLAY,
SCREEN_FOR_CLIENT(pCD))/SLIDE_UP_DIVISOR);
}
if ((pCD->slideDirection != SLIDE_NOT) && pSOR &&
(pSOR->incHeight < pCD->frameInfo.height))
{
XSetWindowAttributes window_attribs;
XWindowChanges window_changes;
unsigned long mask;
/*
* Set up data for processing slide up
*/
pSOR->pCD = pCD;
pSOR->interval = SLIDE_UP_INTERVAL;
pSOR->direction = pCD->slideDirection;
pSOR->mapping = True;
pSOR->wSubpanel = NULL;
pSOR->pCD->pSOR = pSOR;
switch (pSOR->direction)
{
case SLIDE_NORTH:
pSOR->incWidth = 0;
pSOR->currWidth = pCD->frameInfo.width;
pSOR->currHeight = pSOR->incHeight;
pSOR->currX = pCD->frameInfo.x;
pSOR->currY = pCD->frameInfo.y +
(pCD->frameInfo.height - pSOR->currHeight);
break;
case SLIDE_SOUTH:
pSOR->incWidth = 0;
pSOR->currWidth = pCD->frameInfo.width;
pSOR->currHeight = pSOR->incHeight;
pSOR->currX = pCD->frameInfo.x;
pSOR->currY = pCD->frameInfo.y;
break;
}
/*
* Create screening window to hide the slide-up from button
* events until it is all the way up.
*/
mask = CWOverrideRedirect;
window_attribs.override_redirect = True;
pSOR->coverWin = XCreateWindow(DISPLAY,
RootWindow (DISPLAY, SCREEN_FOR_CLIENT(pCD)),
pSOR->currX, pSOR->currY,
pSOR->currWidth, pSOR->currHeight, 0,
CopyFromParent,InputOnly,CopyFromParent,
mask, &window_attribs);
/*
* Put screen window above the slide-up client
*/
mask = CWStackMode | CWSibling;
window_changes.stack_mode = Above;
window_changes.sibling = pCD->clientFrameWin;
XConfigureWindow (DISPLAY, pSOR->coverWin, mask, &window_changes);
/*
* Start slide-up processing
*/
XMoveResizeWindow (DISPLAY, pSOR->coverWin, pSOR->currX, pSOR->currY,
pSOR->currWidth, pSOR->currHeight);
XMoveResizeWindow (DISPLAY, pCD->clientFrameWin,
pSOR->currX, pSOR->currY, pSOR->currWidth, pSOR->currHeight);
XMapWindow (DISPLAY, pSOR->coverWin);
XMapWindow (DISPLAY, pCD->clientFrameWin);
XSync (DISPLAY, False);
XtAppAddTimeOut(wmGD.mwmAppContext, pSOR->interval,
SlideOutTimerProc, (XtPointer)pSOR);
wmGD.iSlideUpsInProgress += 1;
}
else
{
/*
* Not sliding because no direction specified or our window
* is just a little guy.
*/
XMapWindow (DISPLAY, pCD->clientFrameWin);
if (pSOR)
{
XtFree ((char *) pSOR);
pCD->pSOR = NULL;
}
}
} /* END OF FUNCTION SlideOutWindow */
/*************************************<->*************************************
*
* SlideSubpanelBackIn (pCD, wSubpanel)
*
*
* Description:
* -----------
* Slides a subpanel back in
*
*
* Inputs:
* ------
* pCD = pointer to client data
* wSubpanel = subpanel widget to unmanage
*
* Comment:
* -------
*
*************************************<->***********************************/
void
SlideSubpanelBackIn (ClientData *pCD, Widget wSubpanel)
{
SlideOutRec *pSOR;
if (pCD->pSOR)
{
pSOR = pCD->pSOR;
/*
* Hmmm. We're already sliding this window.
* If we're supposed to go in the other direction,
* then turn it around.
*/
if (pSOR->mapping == False)
{
/*
* We're already unmapping this guy, ignore this
* and finish what we've already got going.
*/
return;
}
else
{
/*
* We're mapping this guy. Reverse course!!
*/
pSOR->mapping = False;
pSOR->wSubpanel = wSubpanel;
/* handle the rest on the next timeout */
return;
}
}
pSOR = (SlideOutRec *) XtMalloc (sizeof(SlideOutRec));
if (pSOR)
{
/*
* Compute this ahead of time to check if our window
* is short. If it is, we'll just unmap it, avoiding
* a lot of extra work.
*/
pSOR->incHeight = (Dimension) (DisplayHeight(DISPLAY,
SCREEN_FOR_CLIENT(pCD))/SLIDE_UP_DIVISOR);
}
if ((pCD->slideDirection != SLIDE_NOT) && pSOR &&
(pSOR->incHeight < pCD->frameInfo.height))
{
XSetWindowAttributes window_attribs;
XWindowChanges window_changes;
unsigned long mask;
/*
* Set up data for processing slide up
*/
pSOR->pCD = pCD;
pSOR->interval = SLIDE_UP_INTERVAL;
pSOR->direction = pCD->slideDirection;
pSOR->mapping = False;
pSOR->wSubpanel = wSubpanel;
pSOR->pCD->pSOR = pSOR;
pSOR->incWidth = 0;
pSOR->currWidth = pCD->frameInfo.width;
pSOR->currHeight = pCD->frameInfo.height;
pSOR->currX = pCD->frameInfo.x;
pSOR->currY = pCD->frameInfo.y;
switch (pSOR->direction)
{
case SLIDE_NORTH:
pSOR->currHeight -= pSOR->incHeight;
pSOR->currY += pSOR->incHeight;
break;
case SLIDE_SOUTH:
pSOR->currHeight -= pSOR->incHeight;
break;
}
/*
* Create screening window to hide the slide-up from button
* events until it is all the way up.
*/
mask = CWOverrideRedirect;
window_attribs.override_redirect = True;
pSOR->coverWin = XCreateWindow(DISPLAY,
RootWindow (DISPLAY, SCREEN_FOR_CLIENT(pCD)),
pSOR->currX, pSOR->currY,
pSOR->currWidth, pSOR->currHeight, 0,
CopyFromParent,InputOnly,CopyFromParent,
mask, &window_attribs);
/*
* Put screen window above the slide-up client
*/
mask = CWStackMode | CWSibling;
window_changes.stack_mode = Above;
window_changes.sibling = pCD->clientFrameWin;
XConfigureWindow (DISPLAY, pSOR->coverWin, mask, &window_changes);
/*
* Start slide-up processing
*/
XMapWindow (DISPLAY, pSOR->coverWin);
if (pSOR->currHeight > 0)
{
XMoveResizeWindow (DISPLAY, pCD->clientFrameWin,
pSOR->currX, pSOR->currY,
pSOR->currWidth, pSOR->currHeight);
XMoveResizeWindow (DISPLAY, pSOR->coverWin,
pSOR->currX, pSOR->currY,
pSOR->currWidth, pSOR->currHeight);
XSync (DISPLAY, False);
}
XtAppAddTimeOut(wmGD.mwmAppContext, pSOR->interval,
SlideOutTimerProc, (XtPointer)pSOR);
wmGD.iSlideUpsInProgress += 1;
}
else
{
/*
* Not sliding because no direction specified or our window
* is just a little guy.
*/
/* Just unmanage the slide-up */
XtUnmanageChild (wSubpanel);
if (pSOR)
{
XtFree ((char *) pSOR);
pCD->pSOR = NULL;
}
}
} /* END OF FUNCTION SlideOutWindow */
/*************************************<->*************************************
*
* MapClientWindows (pCD)
*
*
* Description:
* -----------
* Maps the window. If this is a transient tree then all the windows in
* the transient tree are mapped.
*
*
* Inputs:
* ------
* pCD = pointer to client data
*
*************************************<->***********************************/
void MapClientWindows (ClientData *pCD)
{
ClientData *pNext;
pNext = pCD->transientChildren;
while (pNext)
{
/* map all transient children first */
if (pNext->transientChildren)
{
MapClientWindows (pNext);
}
/* then map all siblings at this level */
XMapWindow (DISPLAY, pNext->client);
XMapWindow (DISPLAY, pNext->clientFrameWin);
pNext = pNext->transientSiblings;
}
/* map the primary window */
XMapWindow (DISPLAY, pCD->client);
XMapWindow (DISPLAY, pCD->clientFrameWin);
} /* END OF FUNCTION MapClientWindows */
/*************************************<->*************************************
*
* ShowIconForMinimizedClient (pWS, pCD)
*
*
* Description:
* -----------
* This function shows the icon for the specified client. If the icon
* is in an icon box then the "minimized" icon is displayed. If the icon
* is on the root window it is mapped.
*
*
* Inputs:
* ------
* pWS = pointer to workspace data
* pCD = pointer to client data
*
*************************************<->***********************************/
void ShowIconForMinimizedClient (WmWorkspaceData *pWS, ClientData *pCD)
{
WmScreenData *pSD = PSD_FOR_CLIENT(pCD);
/*
* Handle auto-placement for root icons (icons not in an icon
* box).
*/
if (wmGD.iconAutoPlace && !P_ICON_BOX(pCD))
{
if ((ICON_PLACE(pCD) == NO_ICON_PLACE) ||
((pWS->IPData.placeList[ICON_PLACE(pCD)].pCD) &&
(pWS->IPData.placeList[ICON_PLACE(pCD)].pCD != pCD)))
{
/*
* Icon place not defined or occupied by another client,
* find a free place to put the icon.
*/
if ((ICON_PLACE(pCD) = GetNextIconPlace (&pWS->IPData))
== NO_ICON_PLACE)
{
ICON_PLACE(pCD) =
CvtIconPositionToPlace (&pWS->IPData,
pCD->clientX,
pCD->clientY);
}
CvtIconPlaceToPosition (&pWS->IPData, ICON_PLACE(pCD),
&ICON_X(pCD), &ICON_Y(pCD));
}
pWS->IPData.placeList[ICON_PLACE(pCD)].pCD = pCD;
}
/*
* If icon on root window and this workspace is active, the
* make sure it's in the right place.
*/
if ((pWS == pSD->pActiveWS) && !P_ICON_BOX(pCD))
{
XMoveWindow (DISPLAY, ICON_FRAME_WIN(pCD),
ICON_X(pCD), ICON_Y(pCD));
}
if (pCD->iconWindow)
{
XMapWindow (DISPLAY, pCD->iconWindow);
}
if ((pSD->useIconBox) && P_ICON_BOX(pCD))
{
ShowClientIconState (pCD, MINIMIZED_STATE );
}
else
{
XWindowChanges windowChanges;
/*
* Map the icon on the screen at the appropriate place in the
* window stack.
*/
if (wmGD.lowerOnIconify)
{
if ((&pCD->iconEntry != pSD->lastClient) &&
(pSD->lastClient))
{
if (pSD->lastClient->type == MINIMIZED_STATE)
{
windowChanges.sibling =
ICON_FRAME_WIN(pSD->lastClient->pCD);
}
else
{
windowChanges.sibling =
pSD->lastClient->pCD->clientFrameWin;
}
windowChanges.stack_mode = Below;
XConfigureWindow (DISPLAY, ICON_FRAME_WIN(pCD),
(CWSibling | CWStackMode), &windowChanges);
MoveEntryInList (pWS, &pCD->iconEntry,
False /*on bottom*/, NULL);
}
}
else
{
windowChanges.sibling = pCD->clientFrameWin;
windowChanges.stack_mode = Below;
XConfigureWindow (DISPLAY, ICON_FRAME_WIN(pCD),
(CWSibling | CWStackMode), &windowChanges);
MoveEntryInList (pWS, &pCD->iconEntry, False /*below*/,
&pCD->clientEntry);
}
if (pWS == pSD->pActiveWS)
{
XMapWindow (DISPLAY, ICON_FRAME_WIN(pCD));
}
}
} /* END OF FUNCTION ShowIconForMinimizedClient */
/*************************************<->*************************************
*
* ShowAllIconsForMinimizedClient (pCD)
*
*
* Description:
* -----------
* This function places icons in all the workspaces for the minimized
* client. Since there is only one clientState per client (not per
* workspace), this loops over all workspace in which the client
* resides and places an icon in each.
*
*
* Inputs:
* ------
* pCD = pointer to client data
*
* Comments:
* ---------
* This operates by setting up the currentWsc index for each workspace
* and calling ShowIconForMinimizedClient, which makes heavy use of
* the macros that use the currentWsc index.
*
*************************************<->***********************************/
void ShowAllIconsForMinimizedClient (ClientData *pCD)
{
int saveWsc = pCD->currentWsc;
int tmpWsc;
WmWorkspaceData *pWS;
for (tmpWsc = 0; tmpWsc < pCD->numInhabited; tmpWsc++)
{
pCD->currentWsc = tmpWsc;
pWS = GetWorkspaceData (PSD_FOR_CLIENT(pCD),
pCD->pWsList[tmpWsc].wsID);
ShowIconForMinimizedClient(pWS, pCD);
}
pCD->currentWsc = saveWsc;
} /* END OF FUNCTION ShowAllIconsForMinimizedClient */