/****************************************************************************
** $Id: qwidget_pm.cpp 8 2005-11-16 19:36:46Z dmik $
**
** Implementation of QWidget and QWindow classes for OS/2
**
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
** Copyright (C) 2004 Norman ASA.  Initial OS/2 Port.
** Copyright (C) 2005 netlabs.org.  Further OS/2 Development.
**
** This file is part of the kernel module of the Qt GUI Toolkit.
**
** This file may be distributed under the terms of the Q Public License
** as defined by Trolltech AS of Norway and appearing in the file
** LICENSE.QPL included in the packaging of this file.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
** licenses may use this file in accordance with the Qt Commercial License
** Agreement provided with the Software.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
**   information about Qt Commercial License Agreements.
** See http://www.trolltech.com/qpl/ for QPL licensing information.
** See http://www.trolltech.com/gpl/ for GPL licensing information.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/

#include "qapplication.h"
#include "qapplication_p.h"
#include "qpainter.h"
#include "qbitmap.h"
#include "qwidgetlist.h"
#include "qwidgetintdict.h"
#include "qobjectlist.h"
#include "qaccel.h"
#include "qimage.h"
#include "qfocusdata.h"
#include "qlayout.h"
#include "qt_os2.h"
#include "qpaintdevicemetrics.h"
#include "qcursor.h"
#include <private/qapplication_p.h>
//@@TODO (dmik): remove
//#include <private/qinputcontext_p.h>

//@@TODO (dmik): need this?
//#if defined(QT_NON_COMMERCIAL)
//#include "qnc_win.h"
//#endif

//@@TODO (dmik): remove
//#if !defined(WS_EX_TOOLWINDOW)
//#define WS_EX_TOOLWINDOW 0x00000080
//#endif
//
//#if !defined(GWLP_WNDPROC)
//#define GWLP_WNDPROC GWL_WNDPROC
//#endif

const QString qt_reg_winclass( int );		// defined in qapplication_pm.cpp
//@@TODO (dmik): later?
//void	    qt_olednd_unregister( QWidget* widget, QOleDropTarget *dst ); // dnd_win
//QOleDropTarget* qt_olednd_register( QWidget* widget );


extern bool qt_nograb();
//@@TODO (dmik): later (qregion_pm.cpp)
//extern HRGN qt_win_bitmapToRegion(const QBitmap& bitmap);

// defined in qapplication_pm.cpp
extern void qt_sendBlocked( QObject *obj, QWidget *modal, QEvent *e, bool override );

static QWidget *mouseGrb    = 0;
static QCursor *mouseGrbCur = 0;
static QWidget *keyboardGrb = 0;

extern "C" MRESULT EXPENTRY QtWndProc( HWND, ULONG, MPARAM, MPARAM );
extern PFNWP QtOldFrameProc;
extern "C" MRESULT EXPENTRY QtFrameProc( HWND, ULONG, MPARAM, MPARAM );

PFNWP QtOldSysMenuProc;
extern "C" MRESULT EXPENTRY QtSysMenuProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
{
    if ( msg == WM_MENUEND ) {
        // the pull-down menu is closed, always dismiss the system menu itself
        WinPostMsg( hwnd, MM_ENDMENUMODE, MPFROMSHORT(TRUE), 0 );
    }
    return QtOldSysMenuProc( hwnd, msg, mp1, mp2 );
}

static void removeSysMenuAccels( HWND frame )
{
    HWND sysMenu = WinWindowFromID( frame, FID_SYSMENU );
    if ( !sysMenu )
        return;

    SHORT subId = SHORT1FROMMR( WinSendMsg( sysMenu, MM_ITEMIDFROMPOSITION, 0, 0 ) );
    if ( subId != MIT_ERROR ) {
        MENUITEM item;
        WinSendMsg( sysMenu, MM_QUERYITEM, MPFROM2SHORT(subId, FALSE), MPFROMP(&item) );
        HWND subMenu = item.hwndSubMenu;
        if ( subMenu ) {
            USHORT cnt = SHORT1FROMMR( WinSendMsg( subMenu, MM_QUERYITEMCOUNT, 0, 0 ) );
            for ( int i = 0; i < cnt; i++ ) {
                USHORT id = SHORT1FROMMR(
                    WinSendMsg( subMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(i), 0 ) );
                if ( id == SC_TASKMANAGER || id == SC_CLOSE ) {
                    // accels for these entries always work in Qt, skip them
                    continue;
                }
                USHORT len = SHORT1FROMMR(
                    WinSendMsg( subMenu, MM_QUERYITEMTEXTLENGTH, MPFROMSHORT(id), 0 ) );
                if ( len++ ) {
                    char *text = new char[len];
                    WinSendMsg( subMenu, MM_QUERYITEMTEXT,
                        MPFROM2SHORT(id, len), MPFROMP(text) );
                    char *tab = strrchr( text, '\t' );
                    if ( tab ) {
                        *tab = 0;
                        WinSendMsg( subMenu, MM_SETITEMTEXT,
                            MPFROMSHORT(id), MPFROMP(text) );
                    }
                    delete[] text;
                }
            }
            // sublclass the system menu to leave the menu mode completely
            // when the user presses the ESC key. by default, pressing ESC
            // while the pull-down menu is showing brings us to the menu bar,
            // which is confusing in the case of the system menu, because
            // there is only one item on the menu bar, and we cannot see
            // that it is active when the frame window has an icon.
            PFNWP oldProc = WinSubclassWindow( sysMenu, QtSysMenuProc );
            // set QtOldSysMenuProc only once: it must be the same for
            // all FID_SYSMENU windows.
            if ( !QtOldSysMenuProc )
                QtOldSysMenuProc = oldProc;
        }
    }
}

/*****************************************************************************
  QWidget member functions
 *****************************************************************************/

//#define QT_DEBUGWINCREATEDESTROY

void QWidget::create( WId window, bool initializeWindow, bool destroyOldWindow)
{
    if ( testWState(WState_Created) && window == 0 )
	return;
    setWState( WState_Created );			// set created flag

    if ( !parentWidget() || parentWidget()->isDesktop() )
	setWFlags( WType_TopLevel );		// top-level widget

    static int sw = -1, sh = -1;

    bool topLevel = testWFlags(WType_TopLevel);
    bool popup = testWFlags(WType_Popup);
    bool dialog = testWFlags(WType_Dialog);
    bool desktop  = testWFlags(WType_Desktop);
//@@TODO (dmik): guess this is for embedded windows. remove?
//    HWND destroyw = 0;
    WId	 id = 0;

    if ( !window )				// always initialize
	initializeWindow = TRUE;

    if ( popup ) {
//@@TODO (dmik): ignored for now?
	setWFlags(WStyle_StaysOnTop); // a popup stays on top
    }

    if ( sw < 0 ) {				// get the screen size
        sw = WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN );
        sh = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN );
    }

//@@TODO (dmik): guess this is for embedded windows. remove?
//    if ( window ) {
//	// There's no way we can know the background color of the
//	// other window because it could be cleared using the WM_ERASEBKND
//	// message.  Therefore we assume white.
//	bg_col = white;
//    }

    if ( dialog || popup || desktop ) {		// these are top-level, too
	topLevel = TRUE;
	setWFlags( WType_TopLevel );
    }

    if ( desktop ) {				// desktop widget
	popup = FALSE;				// force this flags off
        //@@TODO (dmik): use WinGetMaxPosition () to take into account such
        //  things as XCenter?
        crect.setRect( 0, 0, sw, sh );
    }

    PCSZ title = NULL;
    ULONG style = 0;
    ULONG fId = 0, fStyle = 0, fcFlags = 0;

//@@TODO (dmik): guess this is for embedded windows. remove?
//    if ( window ) {
//	style = GetWindowLongA( window, GWL_STYLE );
//#ifndef QT_NO_DEBUG
//	if ( !style )
//	    qSystemWarning( "QWidget: GetWindowLong failed" );
//#endif
//	topLevel = FALSE; // #### needed for some IE plugins??
//    } else if ( popup ) {
    if ( popup ) {
        style |= WS_SAVEBITS;
    } else if ( !topLevel ) {
//@@TODO (dmik): why should we set these flags for non-toplevel (child) windows?
//	if ( !testWFlags(WStyle_Customize) )
//	    setWFlags( WStyle_NormalBorder | WStyle_Title | WStyle_MinMax | WStyle_SysMenu  );
	if ( !testWFlags(WStyle_Customize) )
	    setWFlags( WStyle_Title );
    } else if (!desktop ) {
	if ( !testWFlags(WStyle_Customize) ) {
            if ( testWFlags(WStyle_Tool) ) {
                // a special case for WStyle_Tool w/o WStyle_Customize.
                // it violates the Qt docs but it is used by QPopupMenu
                // to create torn-off menus.
                setWFlags( WStyle_Title );
            } else {
                if ( dialog )
                    setWFlags( WStyle_NormalBorder | WStyle_Title | WStyle_SysMenu );
                else
                    setWFlags( WStyle_NormalBorder | WStyle_Title | WStyle_MinMax | WStyle_SysMenu  );
            }
	}
    }
    if ( !desktop ) {
//@@TODO (dmik): this is temporarily commented out because QSplitter sets
//  WPaintUnclipped which causes terrible flicker in QFileDialog's list
//  box and list view. this needs to be investigated. Qt/Win32 does also
//  comment this out...
//	if ( !testWFlags( WPaintUnclipped ) )
	    style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
        // for all top-level windows except popups we create a WC_FRAME
        // as a parent and owner.
	if ( topLevel && !popup ) {
            if ( !testWFlags(WStyle_NoBorder) ) {
                if ( testWFlags(WStyle_NormalBorder) ) {
                    fcFlags |= FCF_SIZEBORDER;
                } else if ( testWFlags(WStyle_DialogBorder) ) {
                    fcFlags |= FCF_DLGBORDER;
                } else if ( testWFlags(WStyle_Tool)  ) {
                    fcFlags |= FCF_BORDER;
                }
            }
            if ( testWFlags(WStyle_Title) )
                fcFlags |= FCF_TITLEBAR;
            if ( testWFlags(WStyle_SysMenu) )
                fcFlags |= FCF_SYSMENU | FCF_CLOSEBUTTON;
            if ( testWFlags(WStyle_Minimize) )
                fcFlags |= FCF_MINBUTTON;
            if ( testWFlags(WStyle_Maximize) )
                fcFlags |= FCF_MAXBUTTON;
            fStyle |= FS_NOMOVEWITHOWNER | FS_NOBYTEALIGN;
            fStyle |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
	}
    }
    if ( testWFlags(WStyle_Title) ) {
        title = topLevel ? qAppName() : name();
    }

    // The WState_Created flag is checked by translateConfigEvent() in
    // qapplication_pm.cpp. We switch it off temporarily to avoid move
    // and resize events during creation
    clearWState( WState_Created );

    QString className = qt_reg_winclass( getWFlags() );
    PCSZ pszClassName = className.latin1();

//@@TODO (dmik): guess this is for embedded windows. remove?
//    if ( window ) {				// override the old window
//	if ( destroyOldWindow )
//	    destroyw = winid;
//	id = window;
//	setWinId( window );
//	LONG res = SetWindowLongA( window, GWL_STYLE, style );
//#ifndef QT_NO_DEBUG
//	if ( !res )
//	    qSystemWarning( "QWidget: Failed to set window style" );
//#endif
//	res = SetWindowLongA( window, GWLP_WNDPROC, (LONG)QtWndProc );
//#ifndef QT_NO_DEBUG
//	if ( !res )
//	    qSystemWarning( "QWidget: Failed to set window procedure" );
//#endif
//    } else if ( desktop ) {			// desktop widget
    if ( desktop ) {                            // desktop widget
	id = WinQueryDesktopWindow( 0, 0 );
	QWidget *otherDesktop = find( id );	// is there another desktop?
	if ( otherDesktop && otherDesktop->testWFlags(WPaintDesktop) ) {
	    otherDesktop->setWinId( 0 );	// remove id from widget mapper
	    setWinId( id );			// make sure otherDesktop is
	    otherDesktop->setWinId( id );	//   found first
	} else {
	    setWinId( id );
	}
    } else if ( topLevel ) {
        // create top-level widget
        HWND ownerw = 0;
	if ( !popup ) {
            QWidget *p = parentWidget();
            if ( p && !p->isDesktop() )
                ownerw = p->topLevelWidget()->winFId();
        }

        if ( !popup ) {
            // create WC_FRAME
            FRAMECDATA fcData;
            fcData.cb = sizeof(FRAMECDATA);
            fcData.flCreateFlags = fcFlags;
            fcData.hmodResources = NULL;
            fcData.idResources = 0;
#if !defined(QT_NO_DEBUG) && defined(QT_DEBUGWINCREATEDESTROY)
            qDebug(
                "|Creating top level window [%s] (frame):\n"
                "|  owner = %08lX\n"
                "|  title = '%s'\n"
                "|  style = %08lX\n"
                "|  fcFlags = %08lX",
                name(), ownerw, title, fStyle, fcFlags
            );
#endif
            fId = WinCreateWindow(
                    HWND_DESKTOP, WC_FRAME, title, fStyle, 0, 0, 0, 0,
                    ownerw, HWND_TOP, 0, &fcData, NULL
            );
#ifndef QT_NO_DEBUG
#ifdef QT_DEBUGWINCREATEDESTROY
            qDebug( "|  hwnd = %08lX", fId );
#endif
            if ( fId == 0 )
                qSystemWarning( "QWidget: Failed to create frame window" );
#endif
            PFNWP oldProc = WinSubclassWindow( fId, QtFrameProc );
            // set QtOldFrameProc only once: it must be the same for
            // all WC_FRAME windows.
            if ( !QtOldFrameProc )
                QtOldFrameProc = oldProc;

            removeSysMenuAccels( fId );

            // create client
#if !defined(QT_NO_DEBUG) && defined(QT_DEBUGWINCREATEDESTROY)
            qDebug(
                "|Creating top level window [%s] (client):\n"
                "|  owner & parent = %08lX\n"
                "|  class = '%s'\n"
                "|  title = '%s'\n"
                "|  style = %08lX",
                name(), fId, pszClassName, title, style
            );
#endif
            id = WinCreateWindow(
                    fId, pszClassName, title, style, 0, 0, 0, 0,
                    fId, HWND_BOTTOM, FID_CLIENT, NULL, NULL
            );
        } else {
#if !defined(QT_NO_DEBUG) && defined(QT_DEBUGWINCREATEDESTROY)
            qDebug(
                "|Creating top level window [%s]:\n"
                "|  owner = %08lX\n"
                "|  class = '%s'\n"
                "|  title = '%s'\n"
                "|  style = %08lX",
                name(), ownerw, pszClassName, title, style
            );
#endif
            id = WinCreateWindow(
                    HWND_DESKTOP, pszClassName, title, style, 0, 0, 0, 0,
                    ownerw, HWND_TOP, 0, NULL, NULL
            );
        }
#ifndef QT_NO_DEBUG
#ifdef QT_DEBUGWINCREATEDESTROY
        qDebug( "|  hwnd = %08lX", id );
#endif
	if ( id == 0 )
	    qSystemWarning( "QWidget: Failed to create window" );
#endif
	setWinId( id );
//@@TODO (dmik): remove?
//	if ( testWFlags( WStyle_StaysOnTop) )
//	    SetWindowPos( id, HWND_TOPMOST, 0, 0, 100, 100, SWP_NOACTIVATE );

        // When the FS_SHELLPOSITION flag is specified during WC_FRAME window
        // creation its size and position remains zero until it is shown
        // for the first time. So, we don't use FS_SHELLPOSITION but emulate
        // its functionality here.
        SWP swp;
        WinQueryTaskSizePos( 0, 0, &swp );
        WinSetWindowPos( fId, 0, swp.x, swp.y, swp.cx, swp.cy, SWP_SIZE | SWP_MOVE );
    } else {
        // create child widget
        HWND parentw = parentWidget()->winId();
#if !defined(QT_NO_DEBUG) && defined(QT_DEBUGWINCREATEDESTROY)
        qDebug(
            "|Creating child window [%s]:\n"
            "|  owner & parent = %08lX\n"
            "|  class = '%s'\n"
            "|  title = '%s'\n"
            "|  style = %08lX",
            name(), parentw, pszClassName, title, style
        );
#endif
        id = WinCreateWindow(
                parentw, pszClassName, title, style,
                0, parentWidget()->crect.height() - 30, 100, 30,
                parentw, HWND_TOP, 0, NULL, NULL
        );
#ifndef QT_NO_DEBUG
#ifdef QT_DEBUGWINCREATEDESTROY
        qDebug( "|  hwnd = %08lX", id );
#endif
	if ( id == 0 )
	    qSystemWarning( "QWidget: Failed to create window" );
#endif
	setWinId( id );
    }

    if ( desktop ) {
	setWState( WState_Visible );
    } else {
//@@TODO (dmik): remove. probably this is done for embedded windows?
//	RECT  fr, cr;
//	GetWindowRect( id, &fr );		// update rects
//	GetClientRect( id, &cr );
//	if ( cr.top == cr.bottom && cr.left == cr.right ) {
//	    if ( initializeWindow ) {
//		int x, y, w, h;
//		if ( topLevel ) {
//		    x = sw/4;
//		    y = 3*sh/10;
//		    w = sw/2;
//		    h = 4*sh/10;
//		} else {
//		    x = y = 0;
//		    w = 100;
//		    h = 30;
//		}
//
//		MoveWindow( winId(), x, y, w, h, TRUE );
//	    }
//	    GetWindowRect( id, &fr );		// update rects
//	    GetClientRect( id, &cr );
//	}
        SWP cswp;
        WinQueryWindowPos( id, &cswp );
	if ( topLevel ) {
	    QTLWExtra *top = topData();
            if ( fId ) {
                SWP fswp;
                WinQueryWindowPos( fId, &fswp );
                // flip y coordinates
                fswp.y = sh - (fswp.y + fswp.cy);
                cswp.y = fswp.cy - (cswp.y + cswp.cy);
                crect.setRect(
                    fswp.x + cswp.x, fswp.y + cswp.y,
                    cswp.cx, cswp.cy
                );

                top->fleft = cswp.x;
                top->ftop = cswp.y;
                top->fright = fswp.cx - cswp.x - cswp.cx;
                top->fbottom = fswp.cy - cswp.y - cswp.cy;
                top->fId = fId;
            } else {
                // flip y coordinate
                cswp.y = sh - (cswp.y + cswp.cy);
                crect.setRect( cswp.x, cswp.y, cswp.cx, cswp.cy );
            }
	    fstrut_dirty = FALSE;
 	} else {
            int cy = parentWidget()->crect.height();
            // flip y coordinate
            cswp.y = cy - (cswp.y + cswp.cy);
	    crect.setRect( cswp.x, cswp.y, cswp.cx, cswp.cy );
	    // in case extra data already exists (eg. reparent()).  Set it.
            //@@TODO (dmik): what's this? ~~~^
	}
    }

    setWState( WState_Created );		// accept move/resize events
    hps = 0;					// no presentation space

//@@TODO (dmik): guess this is for embedded windows. remove?
//    if ( window ) {				// got window from outside
//	if ( IsWindowVisible(window) )
//	    setWState( WState_Visible );
//	else
//	    clearWState( WState_Visible );
//    }

//@@TODO (dmik): need?
//#if defined(QT_NON_COMMERCIAL)
//    QT_NC_WIDGET_CREATE
//#endif

//@@TODO (dmik): guess this is for embedded windows. remove?
//    if ( destroyw ) {
//	WinDestroyWindow( destroyw );
//    }

    setFontSys();
//@@TODO (dmik): remove?
//    QInputContext::enable( this, im_enabled & !((bool)testWState(WState_Disabled)) );
}


void QWidget::destroy( bool destroyWindow, bool destroySubWindows )
{
    deactivateWidgetCleanup();
    if ( testWState(WState_Created) ) {
	clearWState( WState_Created );
	if ( children() ) {
	    QObjectListIt it(*children());
	    register QObject *obj;
	    while ( (obj=it.current()) ) {	// destroy all widget children
		++it;
		if ( obj->isWidgetType() )
		    ((QWidget*)obj)->destroy(destroySubWindows,
					     destroySubWindows);
	    }
	}
	if ( mouseGrb == this )
	    releaseMouse();
	if ( keyboardGrb == this )
	    releaseKeyboard();
	if ( testWFlags(WShowModal) )		// just be sure we leave modal
	    qt_leave_modal( this );
	else if ( testWFlags(WType_Popup) )
	    qApp->closePopup( this );
	if ( destroyWindow && !testWFlags(WType_Desktop) ) {
            HWND id = winId();
            if ( isTopLevel() && !testWFlags(WType_Popup) ) {
                // extra data including extra->topextra has been already
                // deleted at this point by deleteExtra() and therefore
                // calling winFId() useless -- it will always return the
                // client window handle. Use WinQueryWindow() instead.
                id = WinQueryWindow( id, QW_PARENT );
            }
#if !defined(QT_NO_DEBUG) && defined(QT_DEBUGWINCREATEDESTROY)
            qDebug(
                "|Destroying window:\n"
                "|  hwnd = %08lX",
                id
            );
#endif
	    WinDestroyWindow( id );
	}
	setWinId( 0 );
    }
}

void QWidget::reparentSys( QWidget *parent, WFlags f, const QPoint &p,
			   bool showIt )
{
    QWidget* oldtlw = topLevelWidget();
    WId old_winfid = winFId();

    // hide and reparent our own window away. Otherwise we might get
    // destroyed when emitting the child remove event below. See QWorkspace.
    // this is also necessary for modal windows to leave the modal state
    // correctly.
    if ( isVisible() ) {
        hide();
	WinSetParent( old_winfid, HWND_OBJECT, FALSE );
	WinSetOwner( old_winfid, 0 );
    }

    // unblock the widget if blocked
    QWidget *blockedBy = 0;
    if ( isTopLevel() )
        blockedBy = (QWidget*) WinQueryWindowULong( winId(), QWL_QTMODAL );
    if ( !blockedBy && parentWidget() )
        blockedBy = (QWidget*) WinQueryWindowULong(
            parentWidget()->topLevelWidget()->winId(), QWL_QTMODAL );
    if ( blockedBy ) {
        QEvent e( QEvent::WindowUnblocked );
        qt_sendBlocked( this, blockedBy, &e, FALSE );
    }

    bool accept_drops = acceptDrops();
    if ( accept_drops )
	setAcceptDrops( FALSE ); // ole dnd unregister (we will register again below)
    if ( testWFlags(WType_Desktop) )
	old_winfid = 0;
    setWinId( 0 );
    if ( isTopLevel() ) {
        QTLWExtra *top = topData();
        if ( top->swEntry ) {
            WinRemoveSwitchEntry( top->swEntry );
            top->swEntry = 0;
        }
        top->fId = 0;
    }

    if ( parent != parentObj ) {
	if ( parentObj )				// remove from parent
	    parentObj->removeChild( this );
	if ( parent )					// insert into new parent
	    parent->insertChild( this );
    }

    bool enable     = isEnabled();		// remember status
    FocusPolicy fp  = focusPolicy();
    QSize s	    = size();
    QString capt    = caption();
    widget_flags    = f;
    clearWState( WState_Created | WState_Visible | WState_ForceHide );
    create();
    if ( isTopLevel() || (!parent || parent->isVisible() ) )
	setWState( WState_ForceHide );	// new widgets do not show up in already visible parents
    const QObjectList *chlist = children();
    if ( chlist ) {				// reparent children
        SWP swp;
	QObjectListIt it( *chlist );
	QObject *obj;
	while ( (obj=it.current()) ) {
	    if ( obj->isWidgetType() ) {
		QWidget *w = (QWidget *)obj;
		if ( w->isPopup() )
		    ;
		else if ( w->isTopLevel() ) {
		    w->reparent( this, w->getWFlags(), w->pos(), !w->isHidden() );
                } else {
		    WinSetParent( w->winId(), winId(), FALSE );
		    WinSetOwner( w->winId(), winId() );
                    // bring PM coords into accordance with Qt coords,
                    // otherwise setGeometry() below will wrongly position
                    // children if this widget manages their layout.
                    int hd = height() - s.height();
                    WinQueryWindowPos( w->winId(), &swp );
                    swp.y += hd;
                    WinSetWindowPos( w->winId(), 0, swp.x, swp.y, 0, 0, SWP_MOVE );
                }
	    }
	    ++it;
	}
    }

    // block the widget if it should be blocked
    blockedBy = 0;
    if ( parentWidget() )
        blockedBy = (QWidget*) WinQueryWindowULong(
            parentWidget()->topLevelWidget()->winId(), QWL_QTMODAL );
    if ( blockedBy ) {
        if ( isTopLevel() && testWFlags( WGroupLeader ) )
            blockedBy = 0;
    } else {
        QWidget *topModal = qApp->activeModalWidget();
        if (
            topModal && this != topModal && parentWidget() != topModal &&
            isTopLevel() && !testWFlags( WGroupLeader )
        )
            blockedBy = topModal;
    }
    if ( blockedBy ) {
        QEvent e( QEvent::WindowBlocked );
        qt_sendBlocked( this, blockedBy, &e, FALSE );
    }

    setGeometry( p.x(), p.y(), s.width(), s.height() );
    setEnabled( enable );
    setFocusPolicy( fp );
    if ( !capt.isNull() ) {
	extra->topextra->caption = QString::null;
	setCaption( capt );
    }
    if ( showIt )
	show();
    if ( old_winfid )
	WinDestroyWindow( old_winfid );

    reparentFocusWidgets( oldtlw );		// fix focus chains

    if ( accept_drops )
	setAcceptDrops( TRUE );

//@@TODO (dmik): remove?
//#ifdef Q_OS_TEMP
//    // Show borderless toplevel windows in tasklist & NavBar
//    if ( !parent ) {
//	QString txt = caption().isEmpty()?qAppName():caption();
//	SetWindowText( winId(), (TCHAR*)txt.ucs2() );
//    }
//#endif
}

QPoint QWidget::mapToGlobal( const QPoint &pos ) const
{
    if ( !isVisible() || isMinimized() )
	return mapTo( topLevelWidget(), pos ) + topLevelWidget()->pos() +
	(topLevelWidget()->geometry().topLeft() - topLevelWidget()->frameGeometry().topLeft());
    POINTL ptl;
    ptl.x = pos.x();
    // flip y (local) coordinate
    ptl.y = height() - (pos.y() + 1);
    WinMapWindowPoints( winId(), HWND_DESKTOP, &ptl, 1 );
    // flip y (global) coordinate
    ptl.y = QApplication::desktop()->height() - (ptl.y + 1);
    return QPoint( ptl.x, ptl.y );
}

QPoint QWidget::mapFromGlobal( const QPoint &pos ) const
{
    if ( !isVisible() || isMinimized() )
	return mapFrom( topLevelWidget(), pos - topLevelWidget()->pos() );
    POINTL ptl;
    ptl.x = pos.x();
    // flip y (global) coordinate
    ptl.y = QApplication::desktop()->height() - (pos.y() + 1);
    WinMapWindowPoints( HWND_DESKTOP, winId(), &ptl, 1 );
    // flip y (local) coordinate
    ptl.y = height() - (ptl.y + 1);
    return QPoint( ptl.x, ptl.y );
}

void QWidget::setFontSys( QFont *f )
{
//@@TODO (dmik): should this do something on OS/2?
//@@TODO (dmik): remove?
//    QInputContext::setFont( this, (f ? *f : font()) );
}

void QWidget::setMicroFocusHint(int x, int y, int width, int height, bool text, QFont *f)
{
//@@TODO (dmik): do we need to create a caret (cursor) in OS/2 also?
//  currently, try to do so (which can be useful for 3rd-party apps
//  that are interested in the current cursor position, i.e. where the user
//  input is now taking place.
    // flip y coordinate
    int fy = crect.height() - (y + height);
    WinCreateCursor( winId(), x, fy, width, height, CURSOR_SOLID, NULL );

//@@TODO (dmik): remove?
//    if ( text )
//	QInputContext::setFocusHint( x, y, width, height, this );
    setFontSys( f );

    if ( QRect( x, y, width, height ) != microFocusHint() )
	extraData()->micro_focus_hint.setRect( x, y, width, height );
}

void QWidget::resetInputContext()
{
//@@TODO (dmik): remove?
//    QInputContext::accept();
}

void QWidget::setBackgroundColorDirect( const QColor &color )
{
    bg_col = color;
    if ( extra && extra->bg_pix ) {		// kill the background pixmap
	delete extra->bg_pix;
	extra->bg_pix = 0;
    }
}


static int allow_null_pixmaps = 0;


void QWidget::setBackgroundPixmapDirect( const QPixmap &pixmap )
{
    QPixmap old;
    if ( extra && extra->bg_pix )
	old = *extra->bg_pix;
    if ( !allow_null_pixmaps && pixmap.isNull() ) {
	if ( extra && extra->bg_pix ) {
	    delete extra->bg_pix;
	    extra->bg_pix = 0;
	}
    } else {
	if ( extra && extra->bg_pix )
	    delete extra->bg_pix;
	else
	    createExtra();
	extra->bg_pix = new QPixmap( pixmap );
    }
}


void QWidget::setBackgroundEmpty()
{
    allow_null_pixmaps++;
    setErasePixmap(QPixmap());
    allow_null_pixmaps--;
}

extern void qt_set_cursor( QWidget *, const QCursor & ); // qapplication_pm.cpp

void QWidget::setCursor( const QCursor &cursor )
{
    if ( cursor.handle() != arrowCursor.handle()
	 || (extra && extra->curs) ) {
	createExtra();
	delete extra->curs;
	extra->curs = new QCursor(cursor);
    }
    setWState( WState_OwnCursor );
    qt_set_cursor( this, QWidget::cursor() );
}

void QWidget::unsetCursor()
{
    if ( extra ) {
	delete extra->curs;
	extra->curs = 0;
    }
    if ( !isTopLevel() )
	clearWState( WState_OwnCursor );
    qt_set_cursor( this, cursor() );
}

void QWidget::setCaption( const QString &caption )
{
    if ( QWidget::caption() == caption )
	return; // for less flicker
    topData()->caption = caption;

//@@TODO (dmik): need?
//#if defined(QT_NON_COMMERCIAL)
//    QT_NC_CAPTION
//#else
//    QString cap = caption;
//#endif

    QCString cap = caption.local8Bit();
    WinSetWindowText( winFId(), cap );

    HSWITCH swEntry = topData()->swEntry;
    if ( swEntry ) {
        SWCNTRL swc;
        WinQuerySwitchEntry( swEntry, &swc );
        strncpy( swc.szSwtitle, cap, sizeof(swc.szSwtitle)-1 );
        swc.szSwtitle [sizeof(swc.szSwtitle)-1] = 0;
        WinChangeSwitchEntry( swEntry, &swc );
    }

    QEvent e( QEvent::CaptionChange );
    QApplication::sendEvent( this, &e );
}

//@@TODO (dmik): later
///*
//  Create an icon mask the way Windows wants it using CreateBitmap.
//*/
//
//HBITMAP qt_createIconMask( const QBitmap &bitmap )
//{
//    QImage bm = bitmap.convertToImage();
//    int w = bm.width();
//    int h = bm.height();
//    int bpl = ((w+15)/16)*2;			// bpl, 16 bit alignment
//    uchar *bits = new uchar[bpl*h];
//    bm.invertPixels();
//    for ( int y=0; y<h; y++ )
//	memcpy( bits+y*bpl, bm.scanLine(y), bpl );
//    HBITMAP hbm = CreateBitmap( w, h, 1, 1, bits );
//    delete [] bits;
//    return hbm;
//}

void QWidget::setIcon( const QPixmap &pixmap )
{
    qWarning( "QWidget::setIcon() is not yet implemented on OS/2" );
//@@TODO (dmik): later
//    QTLWExtra* x = topData();
//    delete x->icon;
//    x->icon = 0;
//    if ( x->winIcon ) {
//	DestroyIcon( x->winIcon );
//	x->winIcon = 0;
//    }
//    if ( !pixmap.isNull() ) {			// valid icon
//	QPixmap pm( pixmap.size(), pixmap.depth(), QPixmap::NormalOptim );
//	QBitmap mask( pixmap.size(), FALSE, QPixmap::NormalOptim );
//	if ( pixmap.mask() ) {
//	    pm.fill( black );			// make masked area black
//	    bitBlt( &mask, 0, 0, pixmap.mask() );
//	} else {
//	    mask.fill( color1 );
//	}
//	bitBlt( &pm, 0, 0, &pixmap );
//	HBITMAP im = qt_createIconMask(mask);
//	ICONINFO ii;
//	ii.fIcon    = TRUE;
//	ii.hbmMask  = im;
//	ii.hbmColor = pm.hbm();
//	ii.xHotspot = 0;
//	ii.yHotspot = 0;
//	x->icon = new QPixmap( pixmap );
//	x->winIcon = CreateIconIndirect( &ii );
//	DeleteObject( im );
//    }
//    SendMessageA( winId(), WM_SETICON, 0, /* ICON_SMALL */
//		  (long)x->winIcon );
//    SendMessageA( winId(), WM_SETICON, 1, /* ICON_BIG */
//		  (long)x->winIcon );
//
//    QEvent e( QEvent::IconChange );
//    QApplication::sendEvent( this, &e );
}


void QWidget::setIconText( const QString &iconText )
{
    topData()->iconText = iconText;
}

QCursor *qt_grab_cursor()
{
    return mouseGrbCur;
}

void QWidget::grabMouse()
{
    if ( !qt_nograb() ) {
	if ( mouseGrb )
	    mouseGrb->releaseMouse();
	WinSetCapture( HWND_DESKTOP, winFId() );
	mouseGrb = this;
    }
}

void QWidget::grabMouse( const QCursor &cursor )
{
    if ( !qt_nograb() ) {
	if ( mouseGrb )
	    mouseGrb->releaseMouse();
	WinSetCapture( HWND_DESKTOP, winFId() );
	mouseGrbCur = new QCursor( cursor );
	WinSetPointer( HWND_DESKTOP, mouseGrbCur->handle() );
	mouseGrb = this;
    }
}

void QWidget::releaseMouse()
{
    if ( !qt_nograb() && mouseGrb == this ) {
	WinSetCapture( HWND_DESKTOP, 0 );
	if ( mouseGrbCur ) {
	    delete mouseGrbCur;
	    mouseGrbCur = 0;
	}
	mouseGrb = 0;
    }
}

void QWidget::grabKeyboard()
{
    if ( !qt_nograb() ) {
	if ( keyboardGrb )
	    keyboardGrb->releaseKeyboard();
	keyboardGrb = this;
    }
}

void QWidget::releaseKeyboard()
{
    if ( !qt_nograb() && keyboardGrb == this )
	keyboardGrb = 0;
}


QWidget *QWidget::mouseGrabber()
{
    return mouseGrb;
}

QWidget *QWidget::keyboardGrabber()
{
    return keyboardGrb;
}

void QWidget::setActiveWindow()
{
    WinSetActiveWindow( HWND_DESKTOP, topLevelWidget()->winFId() );
}

void QWidget::update()
{
    update( 0, 0, -1, -1 );
}

void QWidget::update( int x, int y, int w, int h )
{
    if ( w && h &&
	 (widget_state & (WState_Visible|WState_BlockUpdates)) == WState_Visible ) {
	if ( w < 0 )
	    w = crect.width() - x;
	if ( h < 0 )
	    h = crect.height() - y;

        // flip y coordinate
        y = crect.height() - (y + h);
        RECTL rcl = { x, y, x + w, y + h };

        // WinInvalidateRect() has such a "feature" that children are not
        // actually extracted from the window's update region when it has
        // the WS_CLIPCHILDREN flag, meaning that every child will anyway
        // receive a WM_PAINT message if its visible region intersects with
        // the update region of its parent, with its update region set to
        // that intersection. This in turn means that if we invalidate the
        // window completely, all its visible children wil completely repaint
        // themselves, what is not we want. The solution is to manually
        // substract children from the region we want to be updated.
        ULONG wstyle = WinQueryWindowULong( winId(), QWL_STYLE );
        if ( (wstyle & WS_CLIPCHILDREN) && children() ) {
            HPS lhps = hps;
            if ( !lhps ) lhps = qt_display_ps();
            HRGN hrgn = GpiCreateRegion( lhps, 1, &rcl );
            HRGN whrgn = GpiCreateRegion( lhps, 0, NULL );
            int hgt = crect.height();

            QObjectListIt it(*children());
            register QObject *object;
            QWidget *w;
            while ( it ) {
                object = it.current();
                ++it;
                if ( object->isWidgetType() ) {
                    w = (QWidget*)object;
                    if ( !w->isTopLevel() && w->isShown() ) {
//@@TODO (dmik): later: substract the region of the child window
// (WinQueryClipRegion()) instead of the window rectangle.
                        const QRect &r = w->crect;
                        rcl.xLeft = r.left();
                        rcl.yBottom = hgt - (r.bottom() + 1);
                        rcl.xRight = r.right() + 1;
                        rcl.yTop = hgt - r.top();
                        GpiSetRegion( lhps, whrgn, 1, &rcl );
                        GpiCombineRegion( lhps, hrgn, hrgn, whrgn, CRGN_DIFF );
                    }
                }
            }
            GpiDestroyRegion( lhps, whrgn );
            WinInvalidateRegion( winId(), hrgn, FALSE );
            GpiDestroyRegion( lhps, hrgn );
        } else {
            WinInvalidateRect( winId(), &rcl, FALSE );
        }
    }
}

void QWidget::repaint( int x, int y, int w, int h, bool erase )
{
    if ( (widget_state & (WState_Visible|WState_BlockUpdates)) == WState_Visible ) {
#if defined (DEBUG_REPAINTRESIZE)
        qDebug( "repaint(): [%s/%s/%08X] %d,%d; %d,%d erase: %d resizeNoErase: %d",
                name(), className(), widget_flags, x, y, w, h, erase,
                (testWFlags( WResizeNoErase ) != 0) );
#endif
	if ( w < 0 )
	    w = crect.width()  - x;
	if ( h < 0 )
	    h = crect.height() - y;
	QRect r( x, y, w, h );
	if ( r.isEmpty() )
	    return; // nothing to do

        // flip y coordinate
        int fy = crect.height() - (y + h);
        RECTL rcl = { x, fy, x + w, fy + h };
        WinValidateRect( winId(), &rcl, FALSE );

	QRegion *pcrgn = 0;
        if ( r != rect() ) {
            pcrgn = new QRegion( r );
            WinSetWindowULong( winId(), QWL_QTCLIPRGN, (ULONG) pcrgn );
        }

	QPaintEvent e( r, erase );
	if ( erase )
	    this->erase( x, y, w, h );
	QApplication::sendEvent( this, &e );

        if ( pcrgn ) {
            WinSetWindowULong( winId(), QWL_QTCLIPRGN, 0 );
            delete pcrgn;
        }
    }
}

void QWidget::repaint( const QRegion& reg, bool erase )
{
    if ( (widget_state & (WState_Visible|WState_BlockUpdates)) == WState_Visible ) {
#if defined (DEBUG_REPAINTRESIZE)
        qDebug( "repaint(): [%s/%s/%08X] <region> erase: %d resizeNoErase: %d",
                name(), className(), widget_flags,
                (testWFlags( WResizeNoErase ) != 0) );
#endif
        // convert region y coordinates from Qt to GPI (see qregion_pm.cpp)
        POINTL ptl = { 0, height() };
        GpiOffsetRegion( qt_display_ps(), reg.handle(), &ptl );
        WinValidateRegion( winId(), reg.handle(), FALSE );
        // convert region y coordinates back from GPI to Qt
        ptl.y = -ptl.y;
        GpiOffsetRegion( qt_display_ps(), reg.handle(), &ptl );

	QRegion *pcrgn = new QRegion( reg );
        WinSetWindowULong( winId(), QWL_QTCLIPRGN, (ULONG) pcrgn );

	QPaintEvent e( reg, erase );
	if ( erase )
	    this->erase( reg );
	QApplication::sendEvent( this, &e );

        WinSetWindowULong( winId(), QWL_QTCLIPRGN, 0 );
        delete pcrgn;
    }
}

void QWidget::setWindowState(uint newstate)
{
    uint oldstate = windowState();

    //@@TODO (dmik): should we deactivate the widget when no WindowActive
    //  is specified? Guess no, because such behavior can be seen in Win32
    //  (the only exception is when WindowMinimized is set w/o WindowActive).
    //  As well as nothing is done in Win32 when only WindowActive is
    //  specified.
    ULONG fl = (newstate & WindowActive) ?
        SWP_ACTIVATE :
        // mimic Win32 behavior
        (newstate & WindowMinimized) ? SWP_DEACTIVATE :
        // mimic Win32 behavior
        ((oldstate & WindowMinimized) &&
            (newstate & WindowMaximized)) ? SWP_ACTIVATE :
        0;

    if (isTopLevel()) {
        WId id = winFId();
        QTLWExtra *top = topData();

	if ((oldstate & WindowMaximized) != (newstate & WindowMaximized)) {
	    if (isVisible() && !(newstate & WindowMinimized)) {
                ULONG f = (newstate & WindowMaximized) ? SWP_MAXIMIZE : SWP_RESTORE;
		WinSetWindowPos( id, 0, 0, 0, 0, 0, fl | f );
                QRect r = topData()->normalGeometry;
		if (!(newstate & WindowMaximized) && r.width() >= 0) {
		    if (pos() != r.topLeft() || size() !=r.size()) {
			top->normalGeometry = QRect( 0, 0, -1, -1 );
			r.addCoords( top->fleft, top->ftop, top->fleft, top->ftop);
			setGeometry( r );
		    }
		}
	    }
	}

	if ((oldstate & WindowFullScreen) != (newstate & WindowFullScreen)) {
	    if (newstate & WindowFullScreen) {
		if ( top->normalGeometry.width() < 0 && !(oldstate & WindowMaximized) )
		    top->normalGeometry = QRect( pos(), size() );
		QRect r = QApplication::desktop()->screenGeometry(this);
                r.addCoords( -top->fleft, -top->fbottom, top->fright, top->ftop );
                WinSetWindowPos(
                        id, 0, r.x(), r.y(), r.width(), r.height(),
                        fl | SWP_SIZE | SWP_MOVE
                );
//@@TODO (dmik): we do not need to call updateFrameStrut() because the frame
//  is not changed, but who will update our crect?..
//		updateFrameStrut();
	    } else {
                ULONG f = fl;
		// the widget is still maximized
		if ( newstate & WindowMaximized ) {
		    if (isVisible())
                        f |= SWP_MAXIMIZE;
                }
                if ( f ) WinSetWindowPos( id, 0, 0, 0, 0, 0, f );
		if ( !(newstate & WindowMaximized) ) {
		    QRect r = top->normalGeometry;
		    top->normalGeometry = QRect( 0, 0, -1, -1 );
		    r.addCoords( top->fleft, top->ftop, top->fleft, top->ftop);
		    setGeometry( r );
		}
//@@TODO (dmik): we do not need to call updateFrameStrut() because the frame
//  is not changed, but who will update our crect?..
//		else {
//                    updateFrameStrut();
//                }
	    }
	}

	if ((oldstate & WindowMinimized) != (newstate & WindowMinimized)) {
	    if (isVisible()) {
                ULONG f =
                    (newstate & WindowMinimized) ? SWP_MINIMIZE :
                    (newstate & WindowMaximized) ? SWP_MAXIMIZE : SWP_RESTORE;
                WinSetWindowPos( id, 0, 0, 0, 0, 0, fl | f );
            }
	}
    }

    widget_state &= ~(WState_Minimized | WState_Maximized | WState_FullScreen);
    if (newstate & WindowMinimized)
	widget_state |= WState_Minimized;
    if (newstate & WindowMaximized)
	widget_state |= WState_Maximized;
    if (newstate & WindowFullScreen)
	widget_state |= WState_FullScreen;

    QEvent e(QEvent::WindowStateChange);
    QApplication::sendEvent(this, &e);
}


/*
  \internal
  Platform-specific part of QWidget::hide().
*/

void QWidget::hideWindow()
{
    deactivateWidgetCleanup();
    HWND id = winFId();
    WinShowWindow( id, FALSE );
    if ( isTopLevel() )
        WinSetWindowPos( id, 0, 0, 0, 0, 0, SWP_DEACTIVATE );

    HSWITCH swEntry = topData()->swEntry;
    if ( swEntry ) {
        SWCNTRL swc;
        WinQuerySwitchEntry( swEntry, &swc );
        swc.uchVisibility = SWL_INVISIBLE;
        WinChangeSwitchEntry( swEntry, &swc );
    }
}


/*
  \internal
  Platform-specific part of QWidget::show().
*/

void QWidget::showWindow()
{
//@@TODO (dmik): need?
//#if defined(QT_NON_COMMERCIAL)
//    QT_NC_SHOW_WINDOW
//#endif
    WinShowWindow( winFId(), TRUE );
    ULONG fl = 0;
    if ( isTopLevel() ) {
        // we do this check here bevause setWindowState() does not actually
        // change the window state when the window is not visible, assuming
        // it will be done here.
	if (testWState(WState_Minimized))
	    fl |= SWP_MINIMIZE;
	else if (testWState(WState_Maximized))
	    fl |= SWP_MAXIMIZE;

        if (
            !testWFlags(WType_Popup | WStyle_Tool) &&
            (!testWFlags(WType_Dialog) || !parentWidget())
        ) {
            HSWITCH &swEntry = topData()->swEntry;
            if ( !swEntry ) {
                // lazily create a new window list entry
                HWND id = winFId(); // frame handle, if any
                PID pid;
                WinQueryWindowProcess( id, &pid, NULL );
                SWCNTRL swc;
                memset( &swc, 0, sizeof(SWCNTRL) );
                swc.hwnd = id;
                swc.idProcess = pid;
                swc.uchVisibility = SWL_VISIBLE;
                swc.fbJump = SWL_JUMPABLE;
                WinQueryWindowText( id, sizeof(swc.szSwtitle), swc.szSwtitle );
                swEntry = WinAddSwitchEntry( &swc );
            } else {
                SWCNTRL swc;
                WinQuerySwitchEntry( swEntry, &swc );
                swc.uchVisibility = SWL_VISIBLE;
                WinChangeSwitchEntry( swEntry, &swc );
            }
        }
    }
    if (!testWFlags(WStyle_Tool) && !isPopup())
        fl |= SWP_ACTIVATE;
    if ( fl )
        WinSetWindowPos( winFId(), 0, 0, 0, 0, 0, fl );

//@@TODO (dmik): remove? in OS/2 WinShowWindow() does not influence
//  any other state flags of the window (such as maximized/minimized, active),
//  so, the window is always shown at its current state (i.e. if its state was
//  not changed while it was hidden it will be restored to that state upon
//  unhiding; if the state was changed, it will be restored to that new state).
//    int sm = SW_SHOWNORMAL;
//    if ( isTopLevel() ) {
//	if (testWState(WState_Minimized))
//	    sm = SW_SHOWMINIMIZED;
//	else if (testWState(WState_Maximized))
//	    sm = SW_SHOWMAXIMIZED;
//    }
//    if (testWFlags(WStyle_Tool) || isPopup())
//	sm = SW_SHOWNOACTIVATE;
//
//    ShowWindow( winId(), sm );
//    UpdateWindow( winId() );
}

void QWidget::raise()
{
    QWidget *p = parentWidget();
    if ( p && p->childObjects && p->childObjects->findRef(this) >= 0 )
	p->childObjects->append( p->childObjects->take() );
//@@TODO (dmik): remove? SWP_ZORDER doesn't cause activation in OS/2...
//    uint f = ( isPopup() || testWFlags(WStyle_Tool) ) ? SWP_NOACTIVATE : 0;
    WinSetWindowPos( winFId(), HWND_TOP, 0, 0, 0, 0, SWP_ZORDER );
}

void QWidget::lower()
{
    QWidget *p = parentWidget();
    if ( p && p->childObjects && p->childObjects->findRef(this) >= 0 )
	p->childObjects->insert( 0, p->childObjects->take() );
//@@TODO (dmik): remove? SWP_ZORDER doesn't cause activation in OS/2...
//    uint f = ( isPopup() || testWFlags(WStyle_Tool) ) ? SWP_NOACTIVATE : 0;
    WinSetWindowPos( winFId(), HWND_BOTTOM, 0, 0, 0, 0, SWP_ZORDER );
}

void QWidget::stackUnder( QWidget* w )
{
    QWidget *p = parentWidget();
    if ( !w || isTopLevel() || p != w->parentWidget() || this == w )
	return;
    if ( p && p->childObjects && p->childObjects->findRef(w) >= 0 && p->childObjects->findRef(this) >= 0 ) {
	p->childObjects->take();
	p->childObjects->insert( p->childObjects->findRef(w), this );
    }
    WinSetWindowPos( winId(), w->winId(), 0, 0, 0, 0, SWP_ZORDER );
}

//
// The internal qPMRequestConfig, defined in qeventloop_pm.cpp, stores move,
// resize and setGeometry requests for a widget that is already
// processing a config event. The purpose is to avoid recursion.
//
void qPMRequestConfig( WId, int, int, int, int, int );

void QWidget::internalSetGeometry( int x, int y, int w, int h, bool isMove )
{
    if ( extra ) {				// any size restrictions?
	w = QMIN(w,extra->maxw);
	h = QMIN(h,extra->maxh);
	w = QMAX(w,extra->minw);
	h = QMAX(h,extra->minh);
    }
    if ( w < 1 )				// invalid size
	w = 1;
    if ( h < 1 )
	h = 1;
    QSize  oldSize( size() );
    QPoint oldPos( pos() );
    if ( !isTopLevel() )
	isMove = (crect.topLeft() != QPoint( x, y ));
    if ( isMove == FALSE && oldSize.width()==w && oldSize.height()==h )
	return;
    clearWState(WState_Maximized);
    clearWState(WState_FullScreen);
    if (isTopLevel())
	topData()->normalGeometry = QRect(0, 0, -1, -1);
    if ( testWState(WState_ConfigPending) ) {	// processing config event
	qPMRequestConfig( winId(), isMove ? 2 : 1, x, y, w, h );
    } else {
	setWState( WState_ConfigPending );
	if ( isTopLevel() ) {
//@@TODO (dmik): remove, no need to check for extra...
//	    QRect fr( frameGeometry() );
//	    if ( extra ) {
//		fr.setLeft( fr.left() + x - crect.left() );
//		fr.setTop( fr.top() + y - crect.top() );
//		fr.setRight( fr.right() + ( x + w - 1 ) - crect.right() );
//		fr.setBottom( fr.bottom() + ( y + h - 1 ) - crect.bottom() );
//	    }
//	    MoveWindow( winId(), fr.x(), fr.y(), fr.width(), fr.height(), TRUE );
//	    crect.setRect( x, y, w, h );

//@@TODO (dmik): optimize: use extra->topextra directly (after updating fstrut
//  if necessary) instead of calling frameGeometry()
	    QRect fr( frameGeometry() );
            int fx = fr.left() + x - crect.left();
            int fy = fr.top() + y - crect.top();
            int fw = fr.width() + w - crect.width();
            int fh = fr.height() + h - crect.height();
            // flip y coordinate
            fy = QApplication::desktop()->height() - (fy + fh);
	    crect.setRect( x, y, w, h );
            WinSetWindowPos( winFId(), 0, fx, fy, fw, fh, SWP_MOVE | SWP_SIZE );
	} else {
            // flip y coordinate
            int fy = parentWidget()->height() - (y + h);
	    crect.setRect( x, y, w, h );
            WinSetWindowPos( winId(), 0, x, fy, w, h, SWP_MOVE | SWP_SIZE );
	}
	clearWState( WState_ConfigPending );
    }

    bool isResize = w != oldSize.width() || h != oldSize.height();
    if ( isVisible() ) {
	if ( isMove && pos() != oldPos ) {
	    QMoveEvent e( pos(), oldPos );
	    QApplication::sendEvent( this, &e );
	}
	if ( isResize ) {
	    QResizeEvent e( size(), oldSize );
	    QApplication::sendEvent( this, &e );
	    if ( !testWFlags( WStaticContents ) )
		repaint( !testWFlags(WResizeNoErase) );
	}
    } else {
	if ( isMove && pos() != oldPos )
	    QApplication::postEvent( this,
                new QMoveEvent( pos(), oldPos ) );
	if ( isResize )
	    QApplication::postEvent( this,
                new QResizeEvent( size(), oldSize ) );
    }
}

void QWidget::setMinimumSize( int minw, int minh )
{
#if defined(QT_CHECK_RANGE)
    if ( minw < 0 || minh < 0 )
	qWarning("QWidget::setMinimumSize: The smallest allowed size is (0,0)");
#endif
    createExtra();
    if ( extra->minw == minw && extra->minh == minh )
	return;
    extra->minw = minw;
    extra->minh = minh;
    if ( minw > width() || minh > height() ) {
	bool resized = testWState( WState_Resized );
	resize( QMAX(minw,width()), QMAX(minh,height()) );
	if ( !resized )
	    clearWState( WState_Resized ); //not a user resize
    }
    updateGeometry();
}

void QWidget::setMaximumSize( int maxw, int maxh )
{
#if defined(QT_CHECK_RANGE)
    if ( maxw > QWIDGETSIZE_MAX || maxh > QWIDGETSIZE_MAX ) {
	qWarning("QWidget::setMaximumSize: The largest allowed size is (%d,%d)",
		 QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
	maxw = QMIN( maxw, QWIDGETSIZE_MAX );
	maxh = QMIN( maxh, QWIDGETSIZE_MAX );
    }
    if ( maxw < 0 || maxh < 0 ) {
	qWarning("QWidget::setMaximumSize: (%s/%s) Negative sizes (%d,%d) "
		"are not possible",
		name( "unnamed" ), className(), maxw, maxh );
	maxw = QMAX( maxw, 0 );
	maxh = QMAX( maxh, 0 );
    }
#endif
    createExtra();
    if ( extra->maxw == maxw && extra->maxh == maxh )
	return;
    extra->maxw = maxw;
    extra->maxh = maxh;
    if ( maxw < width() || maxh < height() ) {
	bool resized = testWState( WState_Resized );
	resize( QMIN(maxw,width()), QMIN(maxh,height()) );
	if ( !resized )
	    clearWState( WState_Resized ); //not a user resize
    }
    updateGeometry();
}

void QWidget::setSizeIncrement( int w, int h )
{
    createTLExtra();
    extra->topextra->incw = w;
    extra->topextra->inch = h;
}

void QWidget::setBaseSize( int w, int h )
{
    createTLExtra();
    extra->topextra->basew = w;
    extra->topextra->baseh = h;
}

extern void qt_erase_background( HPS, int, int, int, int,
			 const QColor &, const QPixmap *, int, int, int );

void QWidget::erase( int x, int y, int w, int h )
{
    // SIMILAR TO region ERASE BELOW

    if ( backgroundMode()==NoBackground )
	return;
    if ( w < 0 )
	w = crect.width() - x;
    if ( h < 0 )
	h = crect.height() - y;

    HPS lhps;
    bool tmphps;

    if( QPainter::redirect( this ) ) {
	tmphps = FALSE;
	lhps = QPainter::redirect( this )->handle();
	Q_ASSERT( lhps );
    } else if ( !hps ) {
	tmphps = TRUE;
	lhps = WinGetPS( winId() );
    } else {
	tmphps = FALSE;
	lhps = hps;
    }

    QPoint offset = backgroundOffset();
    int ox = offset.x();
    int oy = offset.y();

    qt_erase_background(
        lhps, x, y, w, h, bg_col, backgroundPixmap(),
        ox, oy, crect.height()
    );

    if ( tmphps ) {
	WinReleasePS( lhps );
	hps = 0;
    }
}

void QWidget::erase( const QRegion& rgn )
{
    // SIMILAR TO rect ERASE ABOVE

    if ( backgroundMode()==NoBackground )
	return;

    HPS lhps;
    bool tmphps;

    if( QPainter::redirect( this ) ) {
	tmphps = FALSE;
	lhps = QPainter::redirect( this )->handle();
	Q_ASSERT( lhps );
    } else if ( !hps ) {
	tmphps = TRUE;
	lhps = WinGetPS( winId() );
    } else {
	tmphps = FALSE;
	lhps = hps;
    }

    // convert region y coordinates from Qt to GPI (see qregion_pm.cpp)
    POINTL ptl = { 0, height() };
    GpiOffsetRegion( lhps, rgn.handle(), &ptl );

    HRGN oldRegion = GpiQueryClipRegion( lhps );
    HRGN newRegion = 0;
    if ( oldRegion ) {
        GpiSetClipRegion( lhps, 0, NULL );
        newRegion = GpiCreateRegion( lhps, 0, NULL );
        GpiCombineRegion( lhps, newRegion, oldRegion, rgn.handle(), CRGN_AND );
    } else {
	newRegion = rgn.handle();
    }
    GpiSetClipRegion( lhps, newRegion, &oldRegion );

    QPoint offset = backgroundOffset();
    int ox = offset.x();
    int oy = offset.y();

    qt_erase_background(
        lhps, 0, 0, crect.width(), crect.height(),
        bg_col, backgroundPixmap(), ox, oy, crect.height()
    );

    GpiSetClipRegion( lhps, oldRegion, NULL );

    // convert region y coordinates back from GPI to Qt
    ptl.y = -ptl.y;
    GpiOffsetRegion( lhps, rgn.handle(), &ptl );

    if ( oldRegion )
	GpiDestroyRegion( lhps, newRegion );
    if ( tmphps ) {
	WinReleasePS( lhps );
	hps = 0;
    }
}


// helper function to extract regions of all windows that overlap the given
// hwnd subject to their z-order (excluding children of hwnd) from the given
// hrgn. hps is the presentation space of hrgn.
void qt_WinExcludeOverlappingWindows( HWND hwnd, HPS hps, HRGN hrgn )
{
    HRGN vr = GpiCreateRegion( hps, 0, NULL );
    RECTL r;

    // enumerate all windows that are on top of this hwnd
    HWND id = hwnd, deskId = QApplication::desktop()->winId();
    do {
        HWND i = id;
        while( (i = WinQueryWindow( i, QW_PREV )) ) {
            if ( WinIsWindowShowing( i ) ) {
//@@TODO (dmik): probably we should use WinQueryClipRegion() here to
//  handle non-rectangular windows properly
                WinQueryWindowRect( i, &r );
                WinMapWindowPoints( i, hwnd, (PPOINTL) &r, 2 );
                GpiSetRegion( hps, vr, 1, &r );
                GpiCombineRegion( hps, hrgn, hrgn, vr, CRGN_DIFF );
            }
        }
        id = WinQueryWindow( id, QW_PARENT );
    } while( id != deskId );

    GpiDestroyRegion( hps, vr );
}

// helper function to scroll window contents. WinScrollWindow() is a bit
// buggy and corrupts update regions sometimes (which leaves some outdated
// areas unpainted after scrolling), so we reimplement its functionality in
// this function. dy and clip->yBottom/yTop should be GPI coordinates, not Qt.
// all clip coordinates are inclusive.
void qt_WinScrollWindowWell( HWND hwnd, LONG dx, LONG dy, const PRECTL clip = NULL )
{
    WinLockVisRegions( HWND_DESKTOP, TRUE );

    HPS lhps = WinGetClipPS(
        hwnd, HWND_TOP,
        PSF_LOCKWINDOWUPDATE | PSF_CLIPSIBLINGS
    );
    if ( clip )
        GpiIntersectClipRectangle( lhps, clip );

    // remember the update region and validate it. it will be shifted and
    // invalidated again later
    HRGN update = GpiCreateRegion( lhps, 0, NULL );
    WinQueryUpdateRegion( hwnd, update );
    WinValidateRegion( hwnd, update, TRUE );

    POINTL ptls[4];
    RECTL &sr = *(PRECTL) &ptls[2];
    RECTL &tr = *(PRECTL) &ptls[0];

    // get the source rect for scrolling
    GpiQueryClipBox( lhps, &sr );
    sr.xRight++; sr.yTop++; // inclusive -> exclusive

    // get the visible region ignoring areas covered by children
    HRGN visible = GpiCreateRegion( lhps, 1, &sr );
    qt_WinExcludeOverlappingWindows( hwnd, lhps, visible );

    // scroll visible region rectangles separately to avoid the flicker
    // that could be produced by scrolling parts of overlapping windows
    RGNRECT ctl;
    ctl.ircStart = 1;
    ctl.crc = 0;
    ctl.crcReturned = 0;
    if ( dx >= 0 ) {
        if ( dy >= 0 ) ctl.ulDirection = RECTDIR_RTLF_TOPBOT;
        else ctl.ulDirection = RECTDIR_RTLF_BOTTOP;
    } else {
        if ( dy >= 0 ) ctl.ulDirection = RECTDIR_LFRT_TOPBOT;
        else ctl.ulDirection = RECTDIR_LFRT_BOTTOP;
    }
    GpiQueryRegionRects( lhps, visible, NULL, &ctl, NULL );
    ctl.crc = ctl.crcReturned;
    int rclcnt = ctl.crcReturned;
    PRECTL rcls = new RECTL[rclcnt];
    GpiQueryRegionRects( lhps, visible, NULL, &ctl, rcls );
    PRECTL r = rcls;
    for ( int i = 0; i < rclcnt; i++, r++ ) {
        // source rect
        sr = *r;
        // target rect
        tr.xLeft = sr.xLeft + dx;
        tr.xRight = sr.xRight + dx;
        tr.yBottom = sr.yBottom + dy;
        tr.yTop = sr.yTop + dy;
        GpiBitBlt( lhps, lhps, 3, ptls, ROP_SRCCOPY, BBO_IGNORE );
    }
    delete [] rcls;

    // make the scrolled version of the visible region
    HRGN scrolled = GpiCreateRegion( lhps, 0, NULL );
    GpiCombineRegion( lhps, scrolled, visible, 0, CRGN_COPY );
    // invalidate the initial update region
    GpiCombineRegion( lhps, scrolled, scrolled, update, CRGN_DIFF );
    // shift the region
    POINTL dp = { dx, dy };
    GpiOffsetRegion( lhps, scrolled, &dp );
    // substract scrolled from visible to get invalid areas
    GpiCombineRegion( lhps, scrolled, visible, scrolled, CRGN_DIFF );

    WinInvalidateRegion( hwnd, scrolled, TRUE );

    GpiDestroyRegion( lhps, scrolled );
    GpiDestroyRegion( lhps, visible );
    GpiDestroyRegion( lhps, update );

    WinReleasePS( lhps );

    WinLockVisRegions( HWND_DESKTOP, FALSE );

    WinUpdateWindow( hwnd );
}

void QWidget::scroll( int dx, int dy )
{
    if ( testWState( WState_BlockUpdates ) && !children() )
	return;

    // move non-toplevel children
    if ( children() ) {
        QObjectListIt it(*children());
        register QObject *obj;
        int h = crect.height();
        while ( (obj=it.current()) ) {
            ++it;
            if ( obj->isWidgetType() ) {
                QWidget *w = (QWidget*)obj;
                if ( !w->isTopLevel() ) {
                    WinSetWindowPos(
                        w->winId(), 0,
                        w->crect.left() + dx,
                        // flip y coordinate
                        h - (w->crect.bottom() + dy + 1),
                        0, 0,
                        SWP_MOVE | SWP_NOADJUST | SWP_NOREDRAW
                    );
                    // WinSetWindowPos() doesn't send WM_MOVE to windows w/o
                    // CS_MOVENOTIFY, but having this style for non-toplevel
                    // widgets is unwanted, so we send them WM_MOVE manually
                    // to let their geometry to be properly updated by
                    // QETWidget::translateConfigEvent().
                    WinSendMsg( w->winId(), WM_MOVE, 0, 0 );
                }
            }
        }
    }

    qt_WinScrollWindowWell( winId(), dx, -dy, NULL );
}

void QWidget::scroll( int dx, int dy, const QRect& r )
{
    if ( testWState( WState_BlockUpdates ) )
	return;

    int h = crect.height();
    // flip y coordinate (all coordinates are inclusive)
    RECTL rcl = { r.left(), h - (r.bottom() + 1), r.right(), h - (r.top() + 1) };
    qt_WinScrollWindowWell( winId(), dx, -dy, &rcl );
}

void QWidget::drawText( int x, int y, const QString &str )
{
    if ( testWState(WState_Visible) ) {
	QPainter paint;
	paint.begin( this );
	paint.drawText( x, y, str );
	paint.end();
    }
}


int QWidget::metric( int m ) const
{
    LONG val;
    if ( m == QPaintDeviceMetrics::PdmWidth ) {
	val = crect.width();
    } else if ( m == QPaintDeviceMetrics::PdmHeight ) {
	val = crect.height();
    } else {
	HDC hdc = GpiQueryDevice( qt_display_ps() );
	switch ( m ) {
            case QPaintDeviceMetrics::PdmDpiX:
            case QPaintDeviceMetrics::PdmPhysicalDpiX:
                DevQueryCaps( hdc, CAPS_HORIZONTAL_FONT_RES, 1, &val );
                break;
            case QPaintDeviceMetrics::PdmDpiY:
            case QPaintDeviceMetrics::PdmPhysicalDpiY:
                DevQueryCaps( hdc, CAPS_VERTICAL_FONT_RES, 1, &val );
                break;
            case QPaintDeviceMetrics::PdmWidthMM:
                DevQueryCaps( hdc, CAPS_HORIZONTAL_RESOLUTION, 1, &val );
                val = width() * 1000 / val;
                break;
            case QPaintDeviceMetrics::PdmHeightMM:
                DevQueryCaps( hdc, CAPS_VERTICAL_RESOLUTION, 1, &val );
                val = width() * 1000 / val;
                break;
            case QPaintDeviceMetrics::PdmNumColors:
                DevQueryCaps( hdc, CAPS_COLORS, 1, &val );
                break;
            case QPaintDeviceMetrics::PdmDepth:
                LONG colorInfo [2];
                DevQueryCaps( hdc, CAPS_COLOR_PLANES, 2, colorInfo );
                val = colorInfo [0] * colorInfo [1];
                break;
            default:
                val = 0;
#if defined(QT_CHECK_RANGE)
                qWarning( "QWidget::metric: Invalid metric command" );
#endif
	}
    }
    return val;
}

void QWidget::createSysExtra()
{
//@@TODO (dmik): later
//    extra->dropTarget = 0;
}

void QWidget::deleteSysExtra()
{
    setAcceptDrops( FALSE );
}

void QWidget::createTLSysExtra()
{
//@@TODO (dmik): remove?
//    extra->topextra->winIcon = 0;
    extra->topextra->fId = 0;
    extra->topextra->swEntry = 0;
}

void QWidget::deleteTLSysExtra()
{
    if ( extra->topextra->swEntry ) {
        WinRemoveSwitchEntry( extra->topextra->swEntry );
    }
    // frame window (extra->topextra->fId) is destroyed in
    // destroy() if it exists
//@@TODO (dmik): remove?
//    if ( extra->topextra->winIcon )
//	DestroyIcon( extra->topextra->winIcon );
}

bool QWidget::acceptDrops() const
{
    return 0;
//@@TODO (dmik): later
//    return ( extra && extra->dropTarget );
}

void QWidget::setAcceptDrops( bool on )
{
//@@TODO (dmik): later
//    // Enablement is defined by extra->dropTarget != 0.
//
//    if ( on ) {
//	// Turn on.
//	createExtra();
//	QWExtra *extra = extraData();
//	if ( !extra->dropTarget )
//	    extra->dropTarget = qt_olednd_register( this );
//    } else {
//	// Turn off.
//	QWExtra *extra = extraData();
//	if ( extra && extra->dropTarget ) {
//	    qt_olednd_unregister(this, extra->dropTarget);
//	    extra->dropTarget = 0;
//	}
//    }
}

void QWidget::setMask( const QRegion &region )
{
    qWarning( "QWidget::setMask() is not yet implemented on OS/2" );
//@@TODO (dmik): later (don't forget to offset region, see qregion_pm.cpp)
//    // Since SetWindowRegion takes ownership, and we need to translate,
//    // we take a copy.
//    HRGN wr = CreateRectRgn(0,0,1,1);
//    CombineRgn(wr, region.handle(), 0, RGN_COPY);
//
//    int fleft = 0, ftop = 0;
//    if (isTopLevel()) {
//	ftop = topData()->ftop;
//	fleft = topData()->fleft;
//    }
//    OffsetRgn(wr, fleft, ftop );
//    SetWindowRgn( winId(), wr, TRUE );
}

void QWidget::setMask( const QBitmap &bitmap )
{
    qWarning( "QWidget::setMask() is not yet implemented on OS/2" );
//@@TODO (dmik): later
//    HRGN wr = qt_win_bitmapToRegion(bitmap);
//
//    int fleft = 0, ftop = 0;
//    if (isTopLevel()) {
//	ftop = topData()->ftop;
//	fleft = topData()->fleft;
//    }
//    OffsetRgn(wr, fleft, ftop );
//    SetWindowRgn( winId(), wr, TRUE );
}

void QWidget::clearMask()
{
    qWarning( "QWidget::clearMask() is not yet implemented on OS/2" );
//@@TODO (dmik): later
//    SetWindowRgn( winId(), 0, TRUE );
}

void QWidget::setName( const char *name )
{
    QObject::setName( name );
}

void QWidget::updateFrameStrut() const
{
    QWidget *that = (QWidget *) this;

    if ( !isVisible() || isDesktop() ) {
	that->fstrut_dirty = isVisible();
	return;
    }

    QTLWExtra *top = that->topData();
    if ( top->fId ) {
        // this widget has WC_FRAME
        SWP cswp;
        WinQueryWindowPos( winId(), &cswp );
        SWP fswp;
        WinQueryWindowPos( top->fId, &fswp );
        // flip y coordinates
        fswp.y = QApplication::desktop()->height() - (fswp.y + fswp.cy);
        cswp.y = fswp.cy - (cswp.y + cswp.cy);
        that->crect.setRect(
            fswp.x + cswp.x, fswp.y + cswp.y,
            cswp.cx, cswp.cy
        );

        top->fleft = cswp.x;
        top->ftop = cswp.y;
        top->fright = fswp.cx - cswp.x - cswp.cx;
        top->fbottom = fswp.cy - cswp.y - cswp.cy;
    }
    that->fstrut_dirty = FALSE;
}

void QWidget::setMouseTracking( bool enable )
{
    if ( enable )
        setWState( WState_MouseTracking );
    else
        clearWState( WState_MouseTracking );
}

void QWidget::setWindowOpacity(double)
{
}

double QWidget::windowOpacity() const
{
    return 1.0;
}

/*
  \internal
  Returns the frame wihdow handle if this widget is a top-level widget and
  has the standard WC_FRAME as its parent/owner (where it is FID_CLIENT).
  If the widget does not have the standard frame or it is not top-level, this
  function simply retuns the winId() value.
*/
WId QWidget::winFId()
{
    HWND fId = 0;
    if ( isTopLevel() )
        fId = topData()->fId;
    if ( !fId )
        fId = winId();
    return fId;
}

