/*
* window.cc
*
* Copyright (C) 1995, 1996, 1997, 1997, 1998, 1999, 2000, 2001, 2002 Kenichi Kourai
* Copyright (C) 1999, 2000, 2001, 2002 Luiz Blanes
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with blwm; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>
#if defined(sun) && !defined(__SVR4)
#include <sys/resource.h>
#endif
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/shape.h>
#include "main.h"
#include "blwm.h"
#include "misc.h"
#include "util.h"
#include "fbutton.h"
#include "tbutton.h"
#include "menu.h"
#include "blwmrc.h"
#include "pager.h"
#include "mini.h"
#include "timer.h"
#include "list.h"
#include "focus_mgr.h"
#include "desktop.h"
#include "callback.h"
#include "gnome.h"
#include "paging.h"
Blwm* Blwm::activeBlwm = NULL;
/*
* MapWindows --
* Map this window and the transient windows that should be mapped.
*/
void Blwm::MapWindows(Bool mapTransient)
{
if (CheckMapped())
return;
if (isFirstMapped) {
RaiseWindow(True);
isFirstMapped = False;
}
MapWindow(mapTransient);
trMapped = True;
RaiseWindow(True);
if (!CheckFlags(NO_FOCUS) && !CheckFlags(TRANSIENT)) {
focusMgr.RemoveUnmapList(this);
focusMgr.Push(this);
}
}
/*
* MapWindow --
* Map window.
*/
void Blwm::MapWindow(Bool mapTransient)
{
mapped = True;
if (CheckFlags(BORDER)) {
for (int i = 0; i < 4; i++) {
XMapWindow(display, side[i]);
XMapWindow(display, corner[i]);
}
}
else {
for (int i = 0; i < 4; i++) {
XUnmapWindow(display, side[i]);
XUnmapWindow(display, corner[i]);
}
}
if (CheckFlags(BORDER_EDGE)) {
for (int i = 0; i < 4; i++)
XMapWindow(display, edge[i]);
}
else {
for (int i = 0; i < 4; i++)
XUnmapWindow(display, edge[i]);
}
if (CheckFlags(TITLE)) {
XMapRaised(display, title);
if (CheckFlags(CTRL_MENU))
XMapWindow(display, ctrl);
else
XUnmapWindow(display, ctrl);
if (CheckFlags(BUTTON1))
fButton[0]->MapButton();
else
fButton[0]->UnmapButton();
if (CheckFlags(BUTTON2))
fButton[1]->MapButton();
else
fButton[1]->UnmapButton();
if (CheckFlags(BUTTON3)) {
SetFlags(BUTTON3);
fButton[2]->MapButton();
}
else
fButton[2]->UnmapButton();
}
else
XUnmapWindow(display, title);
XMapRaised(display, parent);
/*
* Don't notify MapNotify to blwm.
*/
XWindowAttributes attr;
long tmpMask;
XGetWindowAttributes(display, wOrig, &attr);
tmpMask = attr.your_event_mask &
~(StructureNotifyMask | SubstructureNotifyMask);
XSelectInput(display, wOrig, tmpMask);
XMapWindow(display, wOrig);
XSelectInput(display, wOrig, attr.your_event_mask);
if (GradWindowMapStyle != Normal)
XResizeWindow(display, frame, 1, 1);
XMapWindow(display, frame);
if (GradWindowMapStyle != Normal)
AnimateWindow(True);
SetStateProperty(NormalState);
if (UsePager) {
ASSERT(mini);
mini->MapMiniature();
}
if (mapTransient) {
/*
* When this is a main window, mapping unmapped transient windows due to
* unmapping this window.
*/
List<Blwm>::Iterator li(&trList);
Blwm* blWm = li.GetHead();
while (blWm) {
if (blWm->trMapped) {
blWm->MapWindow(mapTransient);
Gnome::ResetState(blWm, WIN_STATE_HID_TRANSIENT);
}
blWm = li.GetNext();
}
}
}
/*
* UnmapWindows --
* Unmap this window and the transient windows that are mapped.
*/
void Blwm::UnmapWindows(Bool unmapTransient)
{
if (!CheckMapped())
return;
/*
* Unmap all menus.
*/
if (CheckMenuMapped())
UnmapMenu();
if (GradWindowMapStyle != Normal)
AnimateWindow(False);
UnmapWindow(unmapTransient);
trMapped = False;
if (!CheckFlags(TRANSIENT)) {
focusMgr.Remove(this);
focusMgr.InsertUnmapList(this);
}
}
void Blwm::UnmapWindow(Bool unmapTransient)
{
mapped = False;
/*
* Don't notify UnmapNotify to blwm.
*/
XWindowAttributes attr;
long tmpMask;
XGetWindowAttributes(display, wOrig, &attr);
tmpMask = attr.your_event_mask &
~(StructureNotifyMask | SubstructureNotifyMask);
XSelectInput(display, wOrig, tmpMask);
XUnmapWindow(display, wOrig);
XSelectInput(display, wOrig, attr.your_event_mask);
XUnmapWindow(display, frame);
if (UsePager) {
ASSERT(mini);
mini->UnmapMiniature();
}
if (unmapTransient) {
/*
* When this is a main window, unmapping all transient windows.
*/
List<Blwm>::Iterator li(&trList);
Blwm* blWm = li.GetHead();
while (blWm) {
if (blWm->trMapped) {
blWm->UnmapWindow(unmapTransient);
Gnome::SetState(blWm, WIN_STATE_HID_TRANSIENT);
}
blWm = li.GetNext();
}
}
}
/*
* RaiseWindow --
* Raise this window on top, but keep transient windows to be on the top.
* If soon is False, called this routine later again.
*/
void Blwm::RaiseWindow(Bool soon)
{
if (this == rootBlwm)
return;
if (!soon && AutoRaise && AutoRaiseDelay > 0)
timer->SetTimeout(AutoRaiseDelay,
new Callback<Blwm>(this, &Blwm::RaiseSoon));
else if (CheckMapped()) {
Window* wins;
Miniature** minis;
int nwindows = 0;
int maxNum;
Bool already = False;
maxNum = desktop.GetBlwmList().GetSize();
wins = new Window[maxNum + 1];
minis = new Miniature*[maxNum];
wins[0] = desktop.GetTopWindow();
if (CheckFlags(ONTOP))
StackWindows(wins, minis, &nwindows);
else {
/*
* In the most top, ONTOP windows is located.
*/
List<Blwm>::Iterator li(&desktop.GetOnTopList());
Blwm* blWm = li.GetTail();
while (blWm) {
if (blWm->CheckMapped())
blWm->StackWindows(wins, minis, &nwindows);
if (blWm == this)
already = True;
blWm = li.GetPrev();
}
/*
* If this window is not included in ontop window list, locate it.
*/
if (!already)
StackWindows(wins, minis, &nwindows);
}
XRestackWindows(display, wins, nwindows + 1);
if (UsePager) {
ASSERT(minis[0]);
minis[0]->RaiseMiniature();
Miniature::RestackMiniatures(minis, nwindows);
}
delete [] wins;
delete [] minis;
if (UseTaskbar && OnTopTaskbar)
taskBar->RaiseTaskbar();
if (UsePager && OnTopPager)
pager->RaisePager();
if (this != activeBlwm)
activeBlwm = this;
}
}
void Blwm::StackWindows(Window* wins, Miniature** minis, int *nwindows)
{
/*
* First locate the transient windows of this window.
*/
List<Blwm>::Iterator li(&trList);
Blwm* blWm = li.GetHead();
while (blWm) {
if (blWm->CheckMapped())
blWm->StackWindows(wins, minis, nwindows);
blWm = li.GetNext();
}
/*
* Next locate this window.
*/
ASSERT(*nwindows < desktop.GetBlwmList().GetSize())
wins[*nwindows + 1] = frame;
if (UsePager)
minis[*nwindows] = mini;
(*nwindows)++;
}
/*
* RaiseSoon --
* Raise soon if the window is raisable.
*/
void Blwm::RaiseSoon()
{
if (focusBlwm == this && CheckMapped() && !CheckMenuMapped())
RaiseWindow(True);
}
/*
* LowerWindow --
* Lower this window, but keep it above the icons.
* This is achieved by searching the lowest "real" window and putting this
* just below it.
*/
void Blwm::LowerWindow()
{
if (this == rootBlwm)
return;
if (CheckFlags(ONTOP))
return;
if (CheckMapped()) {
Window junkRoot, junkParent, *children;
unsigned int nChildren;
// XQueryTree returns windows in correct stacking order, lowest first
XQueryTree(display, root, &junkRoot, &junkParent, &children, &nChildren);
Blwm* blWm;
int j;
for (j = 0; j < (int)nChildren; j++) {
if (XFindContext(display, children[j], context, (caddr_t*)&blWm)
== XCSUCCESS) {
if (blWm == this) // this is already lowest window
return;
break; // found a "real" window
}
}
if (nChildren)
XFree(children);
// not found
if (j == (int)nChildren)
return;
Window wins[2];
wins[0] = blWm->GetFrameWin();
wins[1] = frame;
XRestackWindows(display, wins, 2);
if (UsePager) {
// find lowest pager mini window to place this mini window below it
XQueryTree(display, pager->GetPagesWin(), &junkRoot, &junkParent,
&children, &nChildren);
ASSERT(nChildren >= 2);
ASSERT(children[0] == pager->GetVisualWin()); // lowest should be visual
wins[0] = children[1];
wins[1] = mini->GetWin();
XRestackWindows(display, wins, 2);
XFree(children);
}
}
}
/*
* SetShape --
* Transparentize the shaped window.
*/
void Blwm::SetShape()
{
int borderWidth, topBorder, titleHeight, titleEdge;
GetBorderAndTitle(borderWidth, topBorder, titleHeight, titleEdge);
/*
* Transparentize the original window.
*/
XShapeCombineShape(display, frame, ShapeBounding,
borderWidth, topBorder + titleHeight + titleEdge,
wOrig, ShapeBounding, ShapeSet);
if (CheckFlags(TITLE)) {
XRectangle rect;
rect.x = topBorder;
rect.y = topBorder;
rect.width = rc.width - topBorder * 2;
rect.height = titleHeight;
XShapeCombineRectangles(display, frame, ShapeBounding, 0, 0, &rect, 1,
ShapeUnion, Unsorted);
}
if (CheckFlags(BORDER)) {
XRectangle rect[4];
rect[0].x = 0;
rect[0].y = 0;
rect[0].width = rc.width;
rect[0].height = topBorder + titleHeight + titleEdge;
rect[1].x = 0;
rect[1].y = topBorder + titleHeight + titleEdge;
rect[1].width = borderWidth;
rect[1].height = rc.height - (borderWidth + topBorder + titleHeight
+ titleEdge);
rect[2].x = 0;
rect[2].y = rc.height - borderWidth;
rect[2].width = rc.width;
rect[2].height = borderWidth;
rect[3].x = rc.width - borderWidth;
rect[3].y = topBorder + titleHeight + titleEdge;
rect[3].width = borderWidth;
rect[3].height = rc.height - (borderWidth + topBorder + titleHeight +
titleEdge);
XShapeCombineRectangles(display, frame, ShapeBounding, 0, 0, rect, 4,
ShapeUnion, Unsorted);
}
}
void Blwm::AnimateWindow(Bool map)
{
int i;
int width, height;
switch (GradWindowMapStyle) {
case TopToBottom:
for (i = 1; i <= GradWindowMapSpeed; i++) {
if (map)
height = rc.height * i / GradWindowMapSpeed;
else
height = rc.height * (GradWindowMapSpeed - i + 1) / GradWindowMapSpeed;
if (height == 0)
height = 1;
XResizeWindow(display, frame, rc.width, height);
XFlush(display);
usleep(10000);
}
break;
case LeftToRight:
for (i = 1; i <= GradWindowMapSpeed; i++) {
if (map)
width = rc.width * i / GradWindowMapSpeed;
else
width = rc.width * (GradWindowMapSpeed - i + 1) / GradWindowMapSpeed;
if (width == 0)
width = 1;
XResizeWindow(display, frame, width, rc.height);
XFlush(display);
usleep(10000);
}
break;
case CenterToTopBottom:
for (i = 1; i <= GradWindowMapSpeed; i++) {
if (map)
height = rc.height * i / GradWindowMapSpeed;
else
height = rc.height * (GradWindowMapSpeed - i + 1) / GradWindowMapSpeed;
if (height == 0)
height = 1;
int y = rc.y + (rc.height - height) / 2;
XMoveResizeWindow(display, frame,
rc.x - paging->origin.x, y - paging->origin.y,
rc.width, height);
XFlush(display);
usleep(10000);
}
break;
case CenterToLeftRight:
for (i = 1; i <= GradWindowMapSpeed; i++) {
if (map)
width = rc.width * i / GradWindowMapSpeed;
else
width = rc.width * (GradWindowMapSpeed - i + 1) / GradWindowMapSpeed;
if (width == 0)
width = 1;
int x = rc.x + (rc.width - width) / 2;
XMoveResizeWindow(display, frame,
x - paging->origin.x, rc.y - paging->origin.y,
width, rc.height);
XFlush(display);
usleep(10000);
}
break;
case CenterToAll:
for (i = 1; i <= GradWindowMapSpeed; i++) {
if (map) {
width = rc.width * i / GradWindowMapSpeed;
height = rc.height * i / GradWindowMapSpeed;
}
else {
width = rc.width * (GradWindowMapSpeed - i + 1) / GradWindowMapSpeed;
height = rc.height * (GradWindowMapSpeed - i + 1) / GradWindowMapSpeed;
}
int x = rc.x + (rc.width - width) / 2;
int y = rc.y + (rc.height - height) / 2;
XMoveResizeWindow(display, frame,
x - paging->origin.x, y - paging->origin.y,
width, height);
XFlush(display);
usleep(10000);
}
case Normal:
break;
}
}
syntax highlighted by Code2HTML, v. 0.9.1