//$Id: mdi.cpp,v 1.7 1997/12/01 05:49:48 parallax Exp $

#include "mdi.h"
#include <iostream.h>
#include <qpainter.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <unistd.h>

const int STARTING_OFFSET = 30; // how much further away from the previous window
const int CAPTION_OFFSET = 2;
//const int MENU_HEIGHT = 25;
const int DEFAULT_WINDOW_WIDTH = 600; // in case they don't set it explicitly with SetDefaultWindowSize()
const int DEFAULT_WINDOW_HEIGHT = 300;
const int DEFAULT_WINDOW_POSX = 0;
const int DEFAULT_WINDOW_POSY = 0;
const int MIN_EDGE = 40; // minimum amount of window showing.
const int TASKBAR_HEIGHT = 30;
const int BORDER = 2; // border so we have somewhere to grab
const int RESIZE_BORDER = 10;
const int MINIMUM_X = 100;
const int MINIMUM_Y = 100;
const int MIN_TITLE_HEIGHT = 18;
const int TITLE_BUTTON_WIDTH = 20;

const int UPPER_LEFT = 1;
const int LOWER_LEFT = 2;
const int UPPER_RIGHT = 3;
const int LOWER_RIGHT = 4;

const int DETACH_BUTTON = 0;
const int MINIMIZE_BUTTON = 1;
const int MAXIMIZE_BUTTON = 2;
const int CLOSE_BUTTON = 3;
#define RESIZE_TIMES 10
#define SLEEP_TIME 100
#define FANCY_RECT 0

QString MDIManager::detachPic;
QString MDIManager::attachPic;
QString MDIManager::minimizePic;
QString MDIManager::maximizePic;
QString MDIManager::closePic;


void MDILabel::mousePressEvent ( QMouseEvent *e)
{
    if (e->button() == RightButton)
        emit PopupMenu(e->pos());
    else
        emit Moving();
}

MDILabel::~MDILabel()
{

}

MDIWindow::MDIWindow ( QWidget *p, const char *name)
        : QWidget(p, name)
{
    moving = false;
    resizeMode = 0;
    eraseResizeRect = false;

    outerFrame = new QFrame(this, "outer frame");
    outerFrame->setFrameStyle( QFrame::Panel | QFrame::Sunken);
    outerFrame->setLineWidth(2);
    outerFrame->setMouseTracking(TRUE);
    outerFrame->installEventFilter(this);
    
    clientArea = new QWidget(outerFrame, "client area");
    clientArea->installEventFilter(this);
    menu = new QMenuBar(outerFrame);
    menu->setFrameStyle( QFrame::Panel | QFrame::Raised);
    menu->setLineWidth( 1 );
    menu->installEventFilter (this);
    adjustSize();
    menu->setStyle ( MotifStyle );
    menu->setMouseTracking(TRUE);

    detachPic = new QPixmap();
    attachPic = new QPixmap();
    QPixmap pixmap;
    if (!MDIManager::detachPic.isEmpty())
    {
        detachPic->load(MDIManager::detachPic);
        menu->insertItem (*detachPic, DETACH_BUTTON);
        menu->connectItem(DETACH_BUTTON, this, SLOT(Detach()) );
    }
    if (!MDIManager::attachPic.isEmpty())
    {
        attachPic->load( MDIManager::attachPic);
    }
    
    menu->insertSeparator();
    if (!MDIManager::minimizePic.isEmpty())
    {
        pixmap.load( MDIManager::minimizePic );
        menu->insertItem (pixmap, MINIMIZE_BUTTON);
        menu->connectItem(MINIMIZE_BUTTON,  this, SLOT(Minimize()));
    }
    if (!MDIManager::maximizePic.isEmpty())
    {
        pixmap.load( MDIManager::maximizePic );
        menu->insertItem(pixmap, MAXIMIZE_BUTTON);
        menu->connectItem(MAXIMIZE_BUTTON, this, SLOT(Maximize()));
    }
    if (!MDIManager::closePic.isEmpty())
    {
        pixmap.load(MDIManager::closePic);
        menu->insertItem(pixmap, CLOSE_BUTTON);
        menu->connectItem(CLOSE_BUTTON, this, SLOT(Close()));
    }
    //  captionFrame = new QFrame ( menu, "caption frame" );
    // captionFrame->installEventFilter(this);
  
    // captionFrame->setStyle(WindowsStyle);

    caption = new MDILabel ( menu, "caption" );
    caption->installEventFilter(this);
    caption->setFrameStyle( QFrame::Panel | QFrame::Sunken);
    caption->setLineWidth( 1 );
    connect (caption, SIGNAL(Moving()), SLOT(Moving()) );
    // caption->setStyle(WindowsStyle);
//    caption->setFrameStyle( QFrame::Panel | QFrame::Sunken );

    isMinimized = false;
    isMaximized = false;
    isAttached = true;
    child = NULL;
}

QWidget *MDIWindow::Child()
{
    return child;
}

MDIWindow::~MDIWindow()
{  
}

QLabel *MDIWindow::Caption()
{
    return caption;
}

void MDIWindow::DrawResizeAnimation(QRect &start, QRect &finish)
{
    int times = RESIZE_TIMES;
    QRect r;
    int cX = start.x();
    int cY = start.y();
    int cW = start.width();
    int cH = start.height();
    XGrabServer(qt_xdisplay());
    for (int i=0; i<times; i++)
    {
        r = QRect(cX, cY, cW, cH);
        DrawRect(r);
        XFlush(qt_xdisplay());
        XSync(qt_xdisplay(), False);
        usleep(SLEEP_TIME);
        DrawRect(r);
        cX += (finish.x()-start.x())/(times);
        cY +=  (finish.y()-start.y())/(times);
        cW += (finish.width()-start.width())/times;
        cH += (finish.height()-start.height())/times;
    }
    XUngrabServer(qt_xdisplay());
}

void MDIWindow::SetChild(QWidget *widget)
{
    widget->recreate(clientArea, 0, QPoint(0,0), true);
    child = widget;
    // now recurse the child list, and install event filters
    LinkChildren(widget);
}

// this is a PHAT recursive function, it will search through the widget's children, and it's
// children's children....and install the appropriate event filters.
void MDIWindow::LinkChildren(QWidget *widget)
{
    QList<QObject> *list = (QList<QObject> *)(widget->children());
    if (list)
    {
        for (unsigned int i=0; i< list->count(); i++)
        {
            QWidget *w = (QWidget *)list->at(i);
            LinkChildren(w);
        }
    }
    widget->installEventFilter(this);
    widget->setMouseTracking(true);
}
void MDIWindow::Moving()
{
    if (isAttached)
    {
        moving = true;
//        resizeRect.setRect(0,0,0,0); // will make isNULL() true
    }
}

void MDIWindow::SetCaption ( const char *txt )
{
    caption->setText( txt );
    // caption->setAlignment ( AlignLeft | AlignVCenter );
    setCaption(txt);
    caption->update();
    emit CaptionChanged ( this, txt );
}

void MDIWindow::Select(bool restoreIfMinimized)
{
    if (restoreIfMinimized)
    {
        if(isMinimized)
            Restore();
    }
    setFocus();
 }

void MDIWindow::Minimize ()
{
    isMinimized = true;
    restoreX = x();
    restoreY = y();
    restoreWidth = width();
    restoreHeight = height();
    // now do a cool animation
    if (isVisible())
    {
        hide();
        QRect b(x(), y(), width(), height());
        QRect e(x() + width()/2,y() + height()/2,0,0);
        DrawResizeAnimation(b, e);
    }
    else
        hide();
   emit Minimized (this);
}

void MDIWindow::Maximize ()
{
    if (isMaximized)
    {
        Restore();
    }
    else
    {
        isMaximized = true;
        QWidget *p = (QWidget *)parent();
        restoreX = x();
        restoreY = y();
        restoreWidth = width();
        restoreHeight = height();
        hide();
         // now do a cool animation
        QRect b(x(), y(), width(), height());
        QRect e(0,0, p->width(), p->height());
        DrawResizeAnimation(b, e);
        show();
        setGeometry (0, 0, p->width(), p->height());
        emit Maximized (this);
    }
}


void MDIWindow::Restore ()
{
    if (isMinimized)
    {
        isMinimized = false;
        QRect b(restoreX + restoreWidth/2, restoreY + restoreHeight/2, 0, 0);
        QRect e(restoreX, restoreY, restoreWidth, restoreHeight);
        DrawResizeAnimation(b, e);
        move (restoreX, restoreY);
        show();
        resize (restoreWidth, restoreHeight);
    }

    if (isMaximized)
    {
        isMaximized = false;
        // bust that animation
        QRect b(x(), y(), width(), height());
        QRect e(restoreX, restoreY, restoreWidth, restoreHeight);
        DrawResizeAnimation(b, e);
        move (restoreX, restoreY);
        resize (restoreWidth, restoreHeight);
    }
    
    Select();
    emit Restored(this);
}

void MDIWindow::MoveTo( int dx, int dy)
{
    QPoint movePoint = ClipPoint(QPoint(dx, dy));
    move (movePoint.x(), movePoint.y());
    emit Moved (this, movePoint.x(), movePoint.y());
}

void MDIWindow::Close()
{
    if (child)
    {
        if (child->close())
        {
            emit Closed(this); // we need to tell people its closed before it really is, so they don't get a null pointer
            //     delete this;
            recreate(0, 0, QPoint(0,0)); // hack hack hack
            close(true);
        }
    }
    else
    {
        if (close())
        {
            emit Closed(this); // we need to tell people its closed before it really is, so they don't get a null pointer
            //     delete this;
            recreate(0, 0, QPoint(0,0)); // hack hack hack
            close(true);
        }
    }
}

bool MDIWindow::eventFilter ( QObject *, QEvent *e )
{
    if (e->type() == Event_MouseMove)
    {
        mouseMoveEvent ( (QMouseEvent *)e );
    }
    
    if (e->type() == Event_MouseButtonPress)
    {
        mousePressEvent( (QMouseEvent *)e );
    }
   
    if (e->type() == Event_MouseButtonRelease)
    {
        mouseReleaseEvent ( (QMouseEvent *)e );
    }
    return false; // allow the children to see the event too    
}

void MDIWindow::DoResizing()
{
    QRect resizeRect(x(), y(), width(), height());
    XGrabServer(qt_xdisplay());
    DrawRect(resizeRect, FANCY_RECT);
    XEvent ev;
    QPoint oldMousePos = QCursor::pos();
    while (!XCheckMaskEvent(qt_xdisplay(),  (ButtonPressMask|ButtonReleaseMask), &ev))
    {
        Window dw1, dw2;
        int t1, t2;
        unsigned int t3;
        int newX, newY;
        XQueryPointer(qt_xdisplay(), qt_xrootwin(), &dw1, &dw2, &newX, &newY, &t1, &t2, &t3);
        QPoint mousePos = QPoint(newX, newY);
        if (oldMousePos != mousePos)
        {
            DrawRect(resizeRect, FANCY_RECT);
            int rX = resizeRect.x();
            int rY = resizeRect.y();
            int rW = resizeRect.width();
            int rH = resizeRect.height();
            int dX = mousePos.x() - oldMousePos.x();
            int dY = mousePos.y()-oldMousePos.y();
            switch (resizeMode)
            {
                case LOWER_RIGHT:
                    rW += dX;
                    rH += dY;
                    break;
                case UPPER_RIGHT:
                    rY += dY;
                    rW += dX;
                    rH -= dY;
                    break;
                case LOWER_LEFT:
                    rX += dX;
                    rW -= dX;
                    rH += dY;
                    break;
                case UPPER_LEFT:
                    rX += dX;
                    rY += dY;
                    rW -= dX;
                    rH -= dY;
                    break;
            }
            resizeRect = QRect(QMIN(rX, x() + width()-MINIMUM_X), \
                               QMIN(rY, y() + height()-MINIMUM_Y), \
                               QMAX(rW, MINIMUM_X), QMAX(rH, MINIMUM_Y));
            DrawRect(resizeRect, FANCY_RECT);
            oldMousePos = mousePos;
        }
    }
    DrawRect(resizeRect, FANCY_RECT);
    XUngrabServer(qt_xdisplay());
    setGeometry(resizeRect.x(), resizeRect.y(), resizeRect.width(), resizeRect.height());
    resizeMode = 0;
    setCursor (arrowCursor);
}

void MDIWindow::DoMove()
{
    Window dw1, dw2;
    int t1, t2;
    unsigned int t3;
    int newX, newY;
   
    QRect moveRect(x(), y(), width(), height());
    XGrabServer(qt_xdisplay());
    DrawRect(moveRect, FANCY_RECT);
    XEvent ev;
    QPoint oldMousePos = QCursor::pos();
    while (!XCheckMaskEvent(qt_xdisplay(),  (ButtonPressMask|ButtonReleaseMask), &ev))
    {
        XQueryPointer(qt_xdisplay(), qt_xrootwin(), &dw1, &dw2, &newX, &newY, &t1, &t2, &t3);
        QPoint mousePos = QPoint(newX, newY);
        if (oldMousePos != mousePos)
        {
            DrawRect(moveRect, FANCY_RECT);
            int nX = moveRect.x() + (mousePos.x()-oldMousePos.x());
            nX = QMAX(nX, MIN_EDGE-width());
            nX = QMIN(nX, parentWidget()->width()-MIN_EDGE);
            int nY = moveRect.y() + (mousePos.y()-oldMousePos.y());
            nY = QMAX(nY, 0);
            nY = QMIN(nY, parentWidget()->height()-MIN_EDGE);
            moveRect = QRect(nX, nY,  moveRect.width(), moveRect.height());
            DrawRect(moveRect, FANCY_RECT);
            oldMousePos = mousePos;
        }
    }
    DrawRect(moveRect, FANCY_RECT);
    XUngrabServer(qt_xdisplay());
    move(moveRect.x(), moveRect.y());

    moving = false;
}
    
void MDIWindow::focusInEvent(QFocusEvent *)
{
    if (!isVisible())
        show();
    raise();
//    HandleSelect();
    emit Selected(this);
}

void MDIWindow::focusOutEvent(QFocusEvent *)
{

}
void MDIWindow::mouseMoveEvent ( QMouseEvent *e )
{
    if (isAttached) // we don't do any of this stuff if we are detached
    {
        if (e->state() & LeftButton)
        {
            if (resizeMode)
            {
                DoResizing();
                return;
            }
            
            if (moving)
            {
                DoMove();
                return;
            }
        }
        QPoint currentPoint = e->pos();
        int r = isInResizeArea(currentPoint.x(), currentPoint.y());
        if (r)
        {
            if (r == UPPER_LEFT || r == LOWER_RIGHT)
                setCursor ( sizeFDiagCursor);
            else
                setCursor ( sizeBDiagCursor);
        }
        else
            setCursor (arrowCursor);
    }
}

void MDIWindow::mouseReleaseEvent (QMouseEvent *)
{
    resizeMode = 0;
    moving = 0;
}


void MDIWindow::mousePressEvent ( QMouseEvent *e )
{
    isMinimized = false; // no way we can click on a minimized window
    Select(true);
    anchorPoint = e->pos();
    corner = isInResizeArea (anchorPoint.x(), anchorPoint.y());
    if (corner)
        resizeMode = corner;
}

void MDIWindow::resizeEvent ( QResizeEvent *)
{
    outerFrame->setGeometry(0,0,width(), height());
    QRect r = outerFrame->contentsRect();
    menu->setGeometry(0,0,width(), menu->height());
    clientArea->setGeometry(r.x() + BORDER, menu->height(), r.width()-2*BORDER, r.height() - menu->height() - BORDER);
    caption->setGeometry(2*BORDER + TITLE_BUTTON_WIDTH, BORDER, menu->width()-4*BORDER-4*TITLE_BUTTON_WIDTH, menu->height()-2*BORDER);
//  setGeometry(rect.right() - 3*ICON_WIDTH, rect.top(), ICON_WIDTH, ICON_HEIGHT);
    // r = captionFrame->contentsRect();
    // caption->setGeometry(r.left()+CAPTION_OFFSET,r.top(),(r.right()- 2*CAPTION_OFFSET), r.bottom() );
    caption->raise();
    if (child)
        child->setGeometry(0,0, clientArea->width(), clientArea->height());
}

int MDIWindow::isInResizeArea ( int x, int y)
{
    if (x > (width() - RESIZE_BORDER))
    {
        if (y > (height() - RESIZE_BORDER)) // lower right corner
            return LOWER_RIGHT;
        if (y < RESIZE_BORDER) // upper right corner
            return UPPER_RIGHT;
    }

    if (x < RESIZE_BORDER)
    {
        if (y > (height() - RESIZE_BORDER)) // lower left corner
            return LOWER_LEFT;
        if (y < RESIZE_BORDER) // upper left corner
            return UPPER_LEFT;
    }     
    return 0;
}


void MDIWindow::Detach()
{
    if (isAttached && parentWidget())
    {
        restoreX = x();
        restoreY = y();
        restoreWidth = width();
        restoreHeight = height();
        oldParent = parentWidget();
        oldWFlags = getWFlags();
        QPoint pt = (parentWidget())->mapToGlobal(pos());
        recreate(NULL, 0, pt, TRUE);
        caption->hide();
        setIconText(QWidget::caption());
        menu->setItemEnabled(MINIMIZE_BUTTON, false);
        menu->setItemEnabled(MAXIMIZE_BUTTON, false);
        menu->setItemEnabled(CLOSE_BUTTON, false);
        menu->changeItem(*attachPic, DETACH_BUTTON);
        menu->disconnectItem(DETACH_BUTTON, this, SLOT(Detach()) );
        menu->connectItem(DETACH_BUTTON, this, SLOT(Attach()) );
        isAttached = false;
    }
}

void MDIWindow::Attach()
{
    if (!isAttached)
    {
        recreate(oldParent, 0, QPoint(restoreX, restoreY), TRUE);
        caption->show();
        setGeometry(restoreX, restoreY, restoreWidth, restoreHeight);
        menu->setItemEnabled(MINIMIZE_BUTTON, true);
        menu->setItemEnabled(MAXIMIZE_BUTTON, true);
        menu->setItemEnabled(CLOSE_BUTTON, true);
        QPixmap pixmap;
        menu->changeItem(*detachPic, DETACH_BUTTON);
        menu->disconnectItem(DETACH_BUTTON, this, SLOT(Attach()) );
        menu->connectItem(DETACH_BUTTON, this, SLOT(Detach()) );
        isAttached = true;
    }
}

void MDIWindow::DrawRect ( QRect &r, bool fancy )
{
    if (!r.isNull())
    {
        QWidget* pr=parentWidget();
        XGCValues gcvals;
        gcvals.foreground=black.pixel();
        gcvals.subwindow_mode=IncludeInferiors;
        gcvals.function=GXinvert;
        int valmask=GCForeground|GCSubwindowMode|GCFunction;
        GC gc=XCreateGC(x11Display(),pr->handle(),valmask,&gcvals);
        XDrawRectangle(x11Display(),pr->handle(),gc,r.x(),r.y(),r.width(),r.height());
        if (fancy)
        {
            int dY = r.y() + r.height()/3;
            XDrawLine(x11Display(), pr->handle(), gc, r.x(), dY, r.x() + r.width(), dY);
            dY = r.y() + 2*(r.height())/3;
            XDrawLine(x11Display(), pr->handle(), gc, r.x(), dY, r.x() + r.width(), dY);
            int dX = r.x() + r.width()/3;
            XDrawLine(x11Display(), pr->handle(), gc, dX, r.y(), dX, r.y() + r.height());
            dX = r.x() + 2*(r.width())/3;
            XDrawLine(x11Display(), pr->handle(), gc, dX, r.y(), dX, r.y() + r.height());
        }
        XFreeGC(x11Display(),gc);
    }
}

QPoint MDIWindow::ClipPoint (QPoint pt)
{
    QWidget *p = parentWidget();
    int rx = pt.x();
    int ry = pt.y();
    if (rx < (MIN_EDGE - width()))
        rx = MIN_EDGE - width();
    if (ry < 0) // this is a cheap hack to get around titlebar problems
        ry = 0;
    if (rx > (p->width() - MIN_EDGE))
        rx = p->width() - MIN_EDGE;
    if (ry > (p->height() - MIN_EDGE))
        ry = p->height() - MIN_EDGE;
    return (QPoint(rx, ry));
}

MDIManager::MDIManager ( QWidget *p, const char *name, const char *detachButton, \
                       const char *attachButton, const char *minimizeButton, \
                       const char *maximizeButton, const char *closeButton )
        : QWidget ( p, name )
{
    detachPic = detachButton;
    attachPic = attachButton;
    minimizePic = minimizeButton;
    maximizePic = maximizeButton;
    closePic = closeButton;
    
    selectedWin = NULL;
    windowList = new QList<MDIWindow>();
//    windowList->setAutoDelete(true);
    numWindows = 0;
    SetDefaultWindowSize ( DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT );
    SetDefaultWindowPos ( DEFAULT_WINDOW_POSX, DEFAULT_WINDOW_POSY );
    smartPlacement = FALSE;
}

MDIManager::~MDIManager()
{
}

void MDIManager::SetSmartPlacement(bool yn)
{
    smartPlacement = yn;
}

void MDIManager::SetDefaultWindowSize ( int w, int h)
{
    defaultWindowWidth = w;
    defaultWindowHeight = h;
}

void MDIManager::SetDefaultWindowPos ( int x, int y )
{
    defaultWindowPosX = x;
    defaultWindowPosY = y;
}
   
void MDIManager::HandleWindowSelect(MDIWindow *win)
{

    for (MDIWindow *w=windowList->first(); w!=0; w=windowList->next())
   {
       if (w == win)
           selectedWin = w;
       else
       {   
           if (w->IsMinimized())
               w->hide();
           else
           {
               if (!w->isVisible())
                   w->show();
           }
       }
   }
}

void MDIManager::NextWindow ()
{
    //  focusNextPrevChild(true);
    
    windowList->find(selectedWin);
    MDIWindow *w = windowList->next();
    if (!w)
        w = windowList->first();
    if (w)
        w->Select();
        
}

void MDIManager::PrevWindow ()
{
    //focusNextPrevChild(false);
    
    windowList->find(selectedWin);
    MDIWindow *w = windowList->prev();
    if (!w)
        w = windowList->last();
    if (w)
        w->Select();
      
}

void MDIManager::AddWindow(QWidget *widget, bool showIt)
{
    MDIWindow *w = new MDIWindow(this, widget->name());
    if (!showIt)
        w->hide();
    w->SetChild(widget);
    AddWindow(w);
}

void MDIManager::AddWindow( MDIWindow *w )
{
    CHECK_PTR(w);
    if (w->parentWidget() != this)
        w->recreate(this, 0, QPoint(0,0));
    windowList->append(w);

    // now we place and resize the new window
    int x, y;
    if (smartPlacement)
    {
        x = (width() / 2) - (defaultWindowWidth / 2);
        y = (height() / 2) - (defaultWindowHeight / 2);
    }
    else
    {
        x = defaultWindowPosX;
        y = defaultWindowPosY;
    }
    
    while (IsPointTaken(x, y))
    {
       x += STARTING_OFFSET;
       y += STARTING_OFFSET;
    }
    w->move(x, y);
    w->resize(defaultWindowWidth, defaultWindowHeight);
    connect(w, SIGNAL(Selected(MDIWindow *)), SLOT(HandleWindowSelect( MDIWindow *)) );
    connect(w, SIGNAL(Closed(MDIWindow *)), SLOT(RemoveWindow(MDIWindow *)) );
// make sure the window gets deleted when we are done
    numWindows++;

    //  win->Select();
    emit WindowAdded(w);
//    PrintWindowList();
}

void MDIManager::RemoveWindow ( MDIWindow *win )
{
    if (win == selectedWin)
        selectedWin = NULL;
    
    int i = windowList->find(win);
    if ( i > -1)
    {
        windowList->remove();
        numWindows --;
        emit WindowRemoved(win);
        //   SetWindowFocus();
    }
    else
        warning("MDIManager::RemoveWindow: window not found.");
}
        
void MDIManager::Cascade()
{
    int posX = 0;
    int posY = 0;
    int i = 0;
    while (windowList->at(i))
    {
        MDIWindow *w = windowList->at(i);
        if (w->isVisible()) // we act on visible windows, not necessarily restored ones
        {
            w->setGeometry(posX, posY, defaultWindowWidth, defaultWindowHeight);
            w->Select(true);
            posX += STARTING_OFFSET;
            posY += STARTING_OFFSET;
        }
        i++;
    }
}
       
void MDIManager::Tile()
{
    bool isOdd; // is there an odd number of windows?
    // tiles the windows
    int startX = 0;
    int startY = 0;// menu->height()+tool->height();
    
    int totalWidth = width()-startX;
    int totalHeight = height()-startY;

    int eachHeight=0;
    int eachWidth=0;

    int columns = 0;
    int rows = 0;

    int numVisible = 0;
    
    MDIWindow *w = windowList->first();
    while (w)
    {
        if (w->isVisible())
            numVisible++;
        
        w = windowList->next();
    }
    
    if (numVisible == 0)
        return;

    if (numVisible%2)
        isOdd = true;
    else
        isOdd = false;

    if (numVisible >= 5)
        columns = 3;
    if (numVisible < 5) 
        columns = 2;
    if (numVisible < 3) 
        columns = 1;

    if (numVisible == 1)
        rows = 1;
    else
    {
        
        if (isOdd)
            rows = (numVisible +1) / columns;  // treat 3 like 4, 5 like 6, etc
        else
            rows = numVisible / columns;
    }
   
    eachHeight = int(totalHeight / rows);
    eachWidth = int(totalWidth / columns);
    
      
    // now call setGeometry() on each window accordingly
    int thisX = startX;
    int thisY = startY;

    int i = 0;
    for (int c=0;c<columns;c++)
    {                
        for (int r=0;r<rows;r++)
        {
            w=windowList->at(i);
            i++;
            if (w)
            {
                while (!(w->isVisible()))
                {
                    w = windowList->at(i); // skip hidden windows
                    i++;
                }
                if (r+1 == rows && c+2 == columns && isOdd && columns >1) // if the last window and odd, we must double it
                    //     cout << "last window\n";
                    w->setGeometry(thisX, thisY, 2*eachWidth, eachHeight);
                else
                        w->setGeometry(thisX, thisY, eachWidth, eachHeight);
                w->Select(true);
            }
            thisY += eachHeight;
        } // end for rows
            
        thisX += eachWidth;
        thisY = startY;
        
    } // end for columns

          
}

MDIWindow *MDIManager::GetWindowByName ( const char *name, bool caseSensitive )
{
    MDIWindow *w = windowList->first();
    QString name1 (name);
    if (!caseSensitive)
        name1 = name1.lower();
    QString name2;
    while ( w )
    {
        name2 = w->name();
        if (!caseSensitive)
           name2 = name2.lower();
        if (name1 == name2)
        {
            return ( w );
        }
        
        w = windowList->next();
    }

    return NULL; // didn't find it
}
 
MDIWindow *MDIManager::GetWindowByIndex ( int index )
{
    MDIWindow *w = windowList->at(index);
    if (w)
        return(w);
    else
        return NULL;
}
    

bool MDIManager::IsPointTaken ( int x, int y)
{
    MDIWindow *w;
    for (int i=0; i< numWindows; i++)
    {
        
        w = GetWindowByIndex(i);
        if (w)
        {
            if ((w->x() == x) && (w->y() == y))
                return true;
        }
    }

    return false;
}

bool MDIManager::SetWindowFocus()
{
    // this is such a hack, but it works goddamn it
    QList<QObject> *childrenList = (QList<QObject> *)(children());
    if (childrenList)
    {
        MDIWindow *w = (MDIWindow *)(childrenList->last());
        while (w)
        {
            if (w->IsMinimized())
                w = (MDIWindow *)(childrenList->prev()); 
            else
            {
                w->Select();
                return true;
            }
        }
    }
    return false; // we couldn't find a window
}
void MDIManager::PrintWindowList ( )	// FOR DEBUG
{
    cout << "****Window List:\n";
    
    if (!windowList)
    {
        cout << "No windows in list.\n";
        return;
    }
    
    MDIWindow *w = windowList->first();
    do
    {
        cout <<(char *) (w->name()) << endl;
        w = windowList->next();
    } while ( w );
    
    cout << "****End of window list.\n";
}

#include "mdi.moc"




