/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qapplication.h" #include "qapplication_p.h" #include "qbitmap.h" #include "qcursor.h" #include "qdesktopwidget.h" #include "qevent.h" #include "qimage.h" #include "qlayout.h" #include "qlibrary.h" #include "qpainter.h" #include "qstack.h" #include "qt_windows.h" #include "qwidget.h" #include "qwidget_p.h" #include "private/qbackingstore_p.h" #include "private/qwindowsurface_raster_p.h" #include "qscrollbar.h" #include "qabstractscrollarea.h" #include #include #include #include #include #if defined(Q_WS_WINCE) #include "qguifunctions_wince.h" QT_USE_NAMESPACE extern void qt_wince_maximize(QWidget *widget); //defined in qguifunctions_wince.cpp extern void qt_wince_minimize(HWND hwnd); //defined in qguifunctions_wince.cpp extern void qt_wince_full_screen(HWND hwnd, bool fullScreen, UINT swpf); //defined in qguifunctions_wince.cpp extern bool qt_wince_is_mobile(); //defined in qguifunctions_wince.cpp #endif typedef BOOL (WINAPI *PtrSetLayeredWindowAttributes)(HWND hwnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags); static PtrSetLayeredWindowAttributes ptrSetLayeredWindowAttributes = 0; #ifndef QT_NO_DIRECTDRAW #include #include static IDirectDraw *qt_ddraw_object; static IDirectDrawSurface *qt_ddraw_primary; #endif #if defined(QT_NON_COMMERCIAL) #include "qnc_win.h" #endif #if !defined(WS_EX_TOOLWINDOW) #define WS_EX_TOOLWINDOW 0x00000080 #endif #if !defined(GWLP_WNDPROC) #define GWLP_WNDPROC GWL_WNDPROC #endif //#define TABLET_DEBUG #define PACKETDATA (PK_X | PK_Y | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE \ | PK_ORIENTATION | PK_CURSOR | PK_Z) #define PACKETMODE 0 #include #include QT_BEGIN_NAMESPACE typedef HCTX (API *PtrWTOpen)(HWND, LPLOGCONTEXT, BOOL); typedef BOOL (API *PtrWTClose)(HCTX); typedef UINT (API *PtrWTInfo)(UINT, UINT, LPVOID); typedef BOOL (API *PtrWTEnable)(HCTX, BOOL); typedef BOOL (API *PtrWTOverlap)(HCTX, BOOL); typedef int (API *PtrWTPacketsGet)(HCTX, int, LPVOID); typedef BOOL (API *PtrWTGet)(HCTX, LPLOGCONTEXT); typedef int (API *PtrWTQueueSizeGet)(HCTX); typedef BOOL (API *PtrWTQueueSizeSet)(HCTX, int); static PtrWTOpen ptrWTOpen = 0; static PtrWTClose ptrWTClose = 0; static PtrWTInfo ptrWTInfo = 0; static PtrWTQueueSizeGet ptrWTQueueSizeGet = 0; static PtrWTQueueSizeSet ptrWTQueueSizeSet = 0; static void init_wintab_functions(); static void qt_tablet_init(); static void qt_tablet_cleanup(); extern HCTX qt_tablet_context; extern bool qt_tablet_tilt_support; static QWidget *qt_tablet_widget = 0; QWidget* qt_get_tablet_widget() { return qt_tablet_widget; } extern bool qt_is_gui_used; static void init_wintab_functions() { #if defined(Q_OS_WINCE) return; #else if (!qt_is_gui_used) return; QLibrary library(QLatin1String("wintab32")); ptrWTOpen = (PtrWTOpen)library.resolve("WTOpenW"); ptrWTInfo = (PtrWTInfo)library.resolve("WTInfoW"); ptrWTClose = (PtrWTClose)library.resolve("WTClose"); ptrWTQueueSizeGet = (PtrWTQueueSizeGet)library.resolve("WTQueueSizeGet"); ptrWTQueueSizeSet = (PtrWTQueueSizeSet)library.resolve("WTQueueSizeSet"); #endif // Q_OS_WINCE } static void qt_tablet_init() { static bool firstTime = true; if (!firstTime) return; firstTime = false; qt_tablet_widget = new QWidget(0); qt_tablet_widget->createWinId(); qt_tablet_widget->setObjectName(QLatin1String("Qt internal tablet widget")); // We dont need this internal widget to appear in QApplication::topLevelWidgets() if (QWidgetPrivate::allWidgets) QWidgetPrivate::allWidgets->remove(qt_tablet_widget); LOGCONTEXT lcMine; qAddPostRoutine(qt_tablet_cleanup); struct tagAXIS tpOri[3]; init_wintab_functions(); if (ptrWTInfo && ptrWTOpen && ptrWTQueueSizeGet && ptrWTQueueSizeSet) { // make sure we have WinTab if (!ptrWTInfo(0, 0, NULL)) { #ifdef TABLET_DEBUG qWarning("QWidget: Wintab services not available"); #endif return; } // some tablets don't support tilt, check if it is possible, qt_tablet_tilt_support = ptrWTInfo(WTI_DEVICES, DVC_ORIENTATION, &tpOri); if (qt_tablet_tilt_support) { // check for azimuth and altitude qt_tablet_tilt_support = tpOri[0].axResolution && tpOri[1].axResolution; } // build our context from the default context ptrWTInfo(WTI_DEFSYSCTX, 0, &lcMine); // Go for the raw coordinates, the tablet event will return good stuff lcMine.lcOptions |= CXO_MESSAGES | CXO_CSRMESSAGES; lcMine.lcPktData = PACKETDATA; lcMine.lcPktMode = PACKETMODE; lcMine.lcMoveMask = PACKETDATA; lcMine.lcOutOrgX = 0; lcMine.lcOutExtX = lcMine.lcInExtX; lcMine.lcOutOrgY = 0; lcMine.lcOutExtY = -lcMine.lcInExtY; qt_tablet_context = ptrWTOpen(qt_tablet_widget->winId(), &lcMine, true); #ifdef TABLET_DEBUG qDebug("Tablet is %p", qt_tablet_context); #endif if (!qt_tablet_context) { #ifdef TABLET_DEBUG qWarning("QWidget: Failed to open the tablet"); #endif return; } // Set the size of the Packet Queue to the correct size... int currSize = ptrWTQueueSizeGet(qt_tablet_context); if (!ptrWTQueueSizeSet(qt_tablet_context, QT_TABLET_NPACKETQSIZE)) { // Ideally one might want to use a smaller // multiple, but for now, since we managed to destroy // the existing Q with the previous call, set it back // to the other size, which should work. If not, // there will be trouble. if (!ptrWTQueueSizeSet(qt_tablet_context, currSize)) { Q_ASSERT_X(0, "Qt::Internal", "There is no packet queue for" " the tablet. The tablet will not work"); } } } } static void qt_tablet_cleanup() { if (ptrWTClose) ptrWTClose(qt_tablet_context); delete qt_tablet_widget; qt_tablet_widget = 0; } const QString qt_reg_winclass(QWidget *w); // defined in qapplication_win.cpp #ifndef QT_NO_DRAGANDDROP void qt_olednd_unregister(QWidget* widget, QOleDropTarget *dst); // dnd_win QOleDropTarget* qt_olednd_register(QWidget* widget); #endif extern bool qt_nograb(); extern HRGN qt_win_bitmapToRegion(const QBitmap& bitmap); static QWidget *mouseGrb = 0; static QCursor *mouseGrbCur = 0; static QWidget *keyboardGrb = 0; static HHOOK journalRec = 0; extern "C" LRESULT CALLBACK QtWndProc(HWND, UINT, WPARAM, LPARAM); #define XCOORD_MAX 16383 #define WRECT_MAX 16383 /***************************************************************************** QWidget member functions *****************************************************************************/ #ifndef Q_WS_WINCE void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyOldWindow) { Q_Q(QWidget); static int sw = -1, sh = -1; Qt::WindowType type = q->windowType(); Qt::WindowFlags flags = data.window_flags; bool topLevel = (flags & Qt::Window); bool popup = (type == Qt::Popup); bool dialog = (type == Qt::Dialog || type == Qt::Sheet || (flags & Qt::MSWindowsFixedSizeDialogHint)); bool desktop = (type == Qt::Desktop); bool tool = (type == Qt::Tool || type == Qt::Drawer); HINSTANCE appinst = qWinAppInst(); HWND parentw, destroyw = 0; WId id = 0; QString windowClassName = qt_reg_winclass(q); if (!window) // always initialize initializeWindow = true; if (popup) flags |= Qt::WindowStaysOnTopHint; // a popup stays on top if (sw < 0) { // get the (primary) screen size sw = GetSystemMetrics(SM_CXSCREEN); sh = GetSystemMetrics(SM_CYSCREEN); } if (desktop && !q->testAttribute(Qt::WA_DontShowOnScreen)) { // desktop widget popup = false; // force this flags off data.crect.setRect(GetSystemMetrics(76 /* SM_XVIRTUALSCREEN */), GetSystemMetrics(77 /* SM_YVIRTUALSCREEN */), GetSystemMetrics(78 /* SM_CXVIRTUALSCREEN */), GetSystemMetrics(79 /* SM_CYVIRTUALSCREEN */)); } parentw = q->parentWidget() ? q->parentWidget()->effectiveWinId() : 0; QString title; int style = WS_CHILD; int exsty = 0; if (window) { style = GetWindowLong(window, GWL_STYLE); if (!style) qErrnoWarning("QWidget::create: GetWindowLong failed"); topLevel = false; // #### needed for some IE plugins?? } else if (popup || (type == Qt::ToolTip) || (type == Qt::SplashScreen)) { style = WS_POPUP; } else if (topLevel && !desktop) { if (flags & Qt::FramelessWindowHint) style = WS_POPUP; // no border else if (flags & Qt::WindowTitleHint) style = WS_OVERLAPPED; else style = 0; } if (!desktop) { // if (!testAttribute(Qt::WA_PaintUnclipped)) // ### Commented out for now as it causes some problems, but // this should be correct anyway, so dig some more into this #ifndef Q_FLATTEN_EXPOSE style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN ; #endif if (topLevel) { if ((type == Qt::Window || dialog || tool)) { if (!(flags & Qt::FramelessWindowHint)) { if (!(flags & Qt::MSWindowsFixedSizeDialogHint)) { style |= WS_THICKFRAME; if(!(flags & ( Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint | Qt::WindowContextHelpButtonHint))) style |= WS_POPUP; } else { style |= WS_POPUP | WS_DLGFRAME; } } if (flags & Qt::WindowTitleHint) style |= WS_CAPTION; if (flags & Qt::WindowSystemMenuHint) style |= WS_SYSMENU; if (flags & Qt::WindowMinimizeButtonHint) style |= WS_MINIMIZEBOX; if (shouldShowMaximizeButton()) style |= WS_MAXIMIZEBOX; if (tool) exsty |= WS_EX_TOOLWINDOW; if (flags & Qt::WindowContextHelpButtonHint) exsty |= WS_EX_CONTEXTHELP; } else { exsty |= WS_EX_TOOLWINDOW; } } } if (flags & Qt::WindowTitleHint) { title = q->isWindow() ? qAppName() : q->objectName(); } // The Qt::WA_WState_Created flag is checked by translateConfigEvent() in // qapplication_win.cpp. We switch it off temporarily to avoid move // and resize events during creationt q->setAttribute(Qt::WA_WState_Created, false); if (window) { // override the old window if (destroyOldWindow) destroyw = data.winid; id = window; setWinId(window); LONG res = SetWindowLong(window, GWL_STYLE, style); if (!res) qErrnoWarning("QWidget::create: Failed to set window style"); #ifdef _WIN64 res = SetWindowLongPtr( window, GWLP_WNDPROC, (LONG_PTR)QtWndProc ); #else res = SetWindowLong( window, GWL_WNDPROC, (LONG)QtWndProc ); #endif if (!res) qErrnoWarning("QWidget::create: Failed to set window procedure"); } else if (desktop) { // desktop widget id = GetDesktopWindow(); // QWidget *otherDesktop = QWidget::find(id); // is there another desktop? // if (otherDesktop && otherDesktop->testWFlags(Qt::WPaintDesktop)) { // otherDesktop->d_func()->setWinId(0); // remove id from widget mapper // d->setWinId(id); // make sure otherDesktop is // otherDesktop->d_func()->setWinId(id); // found first // } else { setWinId(id); // } } else if (topLevel) { // create top-level widget if (popup) parentw = 0; const bool wasMoved = q->testAttribute(Qt::WA_Moved); int x = wasMoved ? data.crect.left() : CW_USEDEFAULT; int y = wasMoved ? data.crect.top() : CW_USEDEFAULT; int w = CW_USEDEFAULT; int h = CW_USEDEFAULT; // Adjust for framestrut when needed RECT rect = {0,0,0,0}; bool isVisibleOnScreen = !q->testAttribute(Qt::WA_DontShowOnScreen); if (isVisibleOnScreen && AdjustWindowRectEx(&rect, style & ~WS_OVERLAPPED, FALSE, exsty)) { QTLWExtra *td = maybeTopData(); if (wasMoved && (td && !td->posFromMove)) { x = data.crect.x() + rect.left; y = data.crect.y() + rect.top; } if (q->testAttribute(Qt::WA_Resized)) { w = data.crect.width() + (rect.right - rect.left); h = data.crect.height() + (rect.bottom - rect.top); } } //update position & initial size of POPUP window if (isVisibleOnScreen && topLevel && initializeWindow && (style & WS_POPUP)) { if (!q->testAttribute(Qt::WA_Resized)) { w = sw/2; h = 4*sh/10; } if (!wasMoved) { x = sw/2 - w/2; y = sh/2 - h/2; } } id = CreateWindowEx(exsty, reinterpret_cast(windowClassName.utf16()), reinterpret_cast(title.utf16()), style, x, y, w, h, parentw, NULL, appinst, NULL); if (!id) qErrnoWarning("QWidget::create: Failed to create window"); setWinId(id); if ((flags & Qt::WindowStaysOnTopHint) || (type == Qt::ToolTip)) { SetWindowPos(id, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); if (flags & Qt::WindowStaysOnBottomHint) qWarning() << "QWidget: Incompatible window flags: the window can't be on top and on bottom at the same time"; } else if (flags & Qt::WindowStaysOnBottomHint) SetWindowPos(id, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); winUpdateIsOpaque(); } else if (q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) { // create child widget id = CreateWindowEx(exsty, reinterpret_cast(windowClassName.utf16()), reinterpret_cast(title.utf16()), style, data.crect.left(), data.crect.top(), data.crect.width(), data.crect.height(), parentw, NULL, appinst, NULL); if (!id) qErrnoWarning("QWidget::create: Failed to create window"); SetWindowPos(id, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); setWinId(id); } if (desktop) { q->setAttribute(Qt::WA_WState_Visible); } else if (topLevel && !q->testAttribute(Qt::WA_DontShowOnScreen)) { RECT cr; GetClientRect(id, &cr); // one cannot trust cr.left and cr.top, use a correction POINT instead POINT pt; pt.x = 0; pt.y = 0; ClientToScreen(id, &pt); if (data.crect.width() == 0 || data.crect.height() == 0) { data.crect = QRect(pt.x, pt.y, data.crect.width(), data.crect.height()); } else { data.crect = QRect(QPoint(pt.x, pt.y), QPoint(pt.x + cr.right - 1, pt.y + cr.bottom - 1)); } if (data.fstrut_dirty) { // be nice to activeqt updateFrameStrut(); } } if (topLevel) { if (data.window_flags & Qt::CustomizeWindowHint && data.window_flags & Qt::WindowTitleHint) { HMENU systemMenu = GetSystemMenu((HWND)q->internalWinId(), FALSE); if (data.window_flags & Qt::WindowCloseButtonHint) EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_ENABLED); else EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_GRAYED); } } q->setAttribute(Qt::WA_WState_Created); // accept move/resize events hd = 0; // no display context if (q->testAttribute(Qt::WA_AcceptTouchEvents)) registerTouchWindow(); if (window) { // got window from outside if (IsWindowVisible(window)) q->setAttribute(Qt::WA_WState_Visible); else q->setAttribute(Qt::WA_WState_Visible, false); } if (extra && !extra->mask.isEmpty()) setMask_sys(extra->mask); #if defined(QT_NON_COMMERCIAL) QT_NC_WIDGET_CREATE #endif if (q->hasFocus() && q->testAttribute(Qt::WA_InputMethodEnabled)) q->inputContext()->setFocusWidget(q); if (destroyw) { DestroyWindow(destroyw); } if (q != qt_tablet_widget && QWidgetPrivate::mapper) qt_tablet_init(); if (q->testAttribute(Qt::WA_DropSiteRegistered)) registerDropSite(true); if (maybeTopData() && maybeTopData()->opacity != 255) q->setWindowOpacity(maybeTopData()->opacity/255.); if (topLevel && (data.crect.width() == 0 || data.crect.height() == 0)) { q->setAttribute(Qt::WA_OutsideWSRange, true); } if (!topLevel && q->testAttribute(Qt::WA_NativeWindow) && q->testAttribute(Qt::WA_Mapped)) { Q_ASSERT(q->internalWinId()); ShowWindow(q->internalWinId(), SW_SHOW); } } #endif //Q_WS_WINCE void QWidget::destroy(bool destroyWindow, bool destroySubWindows) { Q_D(QWidget); if (!isWindow() && parentWidget()) parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry())); d->deactivateWidgetCleanup(); if (testAttribute(Qt::WA_WState_Created)) { setAttribute(Qt::WA_WState_Created, false); for(int i = 0; i < d->children.size(); ++i) { // destroy all widget children register QObject *obj = d->children.at(i); if (obj->isWidgetType()) ((QWidget*)obj)->destroy(destroySubWindows, destroySubWindows); } if (mouseGrb == this) releaseMouse(); if (keyboardGrb == this) releaseKeyboard(); if (testAttribute(Qt::WA_ShowModal)) // just be sure we leave modal QApplicationPrivate::leaveModal(this); else if ((windowType() == Qt::Popup)) qApp->d_func()->closePopup(this); if (destroyWindow && !(windowType() == Qt::Desktop) && internalWinId()) { DestroyWindow(internalWinId()); } #ifdef Q_WS_WINCE if (destroyWindow && (windowType() == Qt::Desktop) && !GetDesktopWindow()) { DestroyWindow(internalWinId()); } #endif QT_TRY { d->setWinId(0); } QT_CATCH (const std::bad_alloc &) { // swallow - destructors must not throw } } } void QWidgetPrivate::reparentChildren() { Q_Q(QWidget); QObjectList chlist = q->children(); for(int i = 0; i < chlist.size(); ++i) { // reparent children QObject *obj = chlist.at(i); if (obj->isWidgetType()) { QWidget *w = (QWidget *)obj; if ((w->windowType() == Qt::Popup)) { ; } else if (w->isWindow()) { bool showIt = w->isVisible(); QPoint old_pos = w->pos(); w->setParent(q, w->windowFlags()); w->move(old_pos); if (showIt) w->show(); } else { w->d_func()->invalidateBuffer(w->rect()); SetParent(w->effectiveWinId(), q->effectiveWinId()); w->d_func()->reparentChildren(); } } } } void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f) { Q_Q(QWidget); bool wasCreated = q->testAttribute(Qt::WA_WState_Created); if (q->isVisible() && q->parentWidget() && parent != q->parentWidget()) q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry())); WId old_winid = data.winid; // hide and reparent our own window away. Otherwise we might get // destroyed when emitting the child remove event below. See QWorkspace. if (q->isVisible() && data.winid) { ShowWindow(data.winid, SW_HIDE); SetParent(data.winid, 0); } bool dropSiteWasRegistered = false; if (q->testAttribute(Qt::WA_DropSiteRegistered)) { dropSiteWasRegistered = true; q->setAttribute(Qt::WA_DropSiteRegistered, false); // ole dnd unregister (we will register again below) } if ((q->windowType() == Qt::Desktop)) old_winid = 0; setWinId(0); QObjectPrivate::setParent_helper(parent); bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide); data.window_flags = f; data.fstrut_dirty = true; q->setAttribute(Qt::WA_WState_Created, false); q->setAttribute(Qt::WA_WState_Visible, false); q->setAttribute(Qt::WA_WState_Hidden, false); adjustFlags(data.window_flags, q); // keep compatibility with previous versions, we need to preserve the created state // (but we recreate the winId for the widget being reparented, again for compatibility) if (wasCreated || (!q->isWindow() && parent->testAttribute(Qt::WA_WState_Created))) createWinId(); if (q->isWindow() || (!parent || parent->isVisible()) || explicitlyHidden) q->setAttribute(Qt::WA_WState_Hidden); q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden); if (wasCreated) { reparentChildren(); } if (extra && !extra->mask.isEmpty()) { QRegion r = extra->mask; extra->mask = QRegion(); q->setMask(r); } if (extra && extra->topextra && !extra->topextra->caption.isEmpty()) { setWindowIcon_sys(true); setWindowTitle_helper(extra->topextra->caption); } if (old_winid) DestroyWindow(old_winid); if (q->testAttribute(Qt::WA_AcceptDrops) || dropSiteWasRegistered || (!q->isWindow() && q->parentWidget() && q->parentWidget()->testAttribute(Qt::WA_DropSiteRegistered))) q->setAttribute(Qt::WA_DropSiteRegistered, true); #ifdef Q_WS_WINCE // Show borderless toplevel windows in tasklist & NavBar if (!parent) { QString txt = q->windowTitle().isEmpty()?qAppName():q->windowTitle(); SetWindowText(q->internalWinId(), (wchar_t*)txt.utf16()); } #endif invalidateBuffer(q->rect()); } QPoint QWidget::mapToGlobal(const QPoint &pos) const { Q_D(const QWidget); QWidget *parentWindow = window(); QWExtra *extra = parentWindow->d_func()->extra; if (!isVisible() || parentWindow->isMinimized() || !testAttribute(Qt::WA_WState_Created) || !internalWinId() || (extra #ifndef QT_NO_GRAPHICSVIEW && extra->proxyWidget #endif //QT_NO_GRAPHICSVIEW )) { if (extra && extra->topextra && extra->topextra->embedded) { QPoint pt = mapTo(parentWindow, pos); POINT p = {pt.x(), pt.y()}; ClientToScreen(parentWindow->effectiveWinId(), &p); return QPoint(p.x, p.y); } else { QPoint toGlobal = mapTo(parentWindow, pos) + parentWindow->pos(); // Adjust for window decorations toGlobal += parentWindow->geometry().topLeft() - parentWindow->frameGeometry().topLeft(); return toGlobal; } } POINT p; QPoint tmp = d->mapToWS(pos); p.x = tmp.x(); p.y = tmp.y(); ClientToScreen(internalWinId(), &p); return QPoint(p.x, p.y); } QPoint QWidget::mapFromGlobal(const QPoint &pos) const { Q_D(const QWidget); QWidget *parentWindow = window(); QWExtra *extra = parentWindow->d_func()->extra; if (!isVisible() || parentWindow->isMinimized() || !testAttribute(Qt::WA_WState_Created) || !internalWinId() || (extra #ifndef QT_NO_GRAPHICSVIEW && extra->proxyWidget #endif //QT_NO_GRAPHICSVIEW )) { if (extra && extra->topextra && extra->topextra->embedded) { POINT p = {pos.x(), pos.y()}; ScreenToClient(parentWindow->effectiveWinId(), &p); return mapFrom(parentWindow, QPoint(p.x, p.y)); } else { QPoint fromGlobal = mapFrom(parentWindow, pos - parentWindow->pos()); // Adjust for window decorations fromGlobal -= parentWindow->geometry().topLeft() - parentWindow->frameGeometry().topLeft(); return fromGlobal; } } POINT p; p.x = pos.x(); p.y = pos.y(); ScreenToClient(internalWinId(), &p); return d->mapFromWS(QPoint(p.x, p.y)); } void QWidgetPrivate::updateSystemBackground() {} #ifndef QT_NO_CURSOR void QWidgetPrivate::setCursor_sys(const QCursor &cursor) { Q_UNUSED(cursor); Q_Q(QWidget); qt_win_set_cursor(q, false); } void QWidgetPrivate::unsetCursor_sys() { Q_Q(QWidget); qt_win_set_cursor(q, false); } #endif void QWidgetPrivate::setWindowTitle_sys(const QString &caption) { Q_Q(QWidget); if (!q->isWindow()) return; Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); SetWindowText(q->internalWinId(), (wchar_t*)caption.utf16()); } HICON qt_createIcon(QIcon icon, int xSize, int ySize, QPixmap **cache) { HICON result = 0; if (!icon.isNull()) { // valid icon QSize size = icon.actualSize(QSize(xSize, ySize)); QPixmap pm = icon.pixmap(size); if (pm.isNull()) return 0; result = pm.toWinHICON(); if (cache) { delete *cache; *cache = new QPixmap(pm);; } } return result; } void QWidgetPrivate::setWindowIcon_sys(bool forceReset) { Q_Q(QWidget); if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow()) return; QTLWExtra* x = topData(); if (x->iconPixmap && !forceReset) // already been set return; if (x->winIconBig) { DestroyIcon(x->winIconBig); x->winIconBig = 0; } if (x->winIconSmall) { DestroyIcon(x->winIconSmall); x->winIconSmall = 0; } x->winIconSmall = qt_createIcon(q->windowIcon(), GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), &(x->iconPixmap)); x->winIconBig = qt_createIcon(q->windowIcon(), GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), &(x->iconPixmap)); if (x->winIconBig) { SendMessage(q->internalWinId(), WM_SETICON, 0 /* ICON_SMALL */, (LPARAM)x->winIconSmall); SendMessage(q->internalWinId(), WM_SETICON, 1 /* ICON_BIG */, (LPARAM)x->winIconBig); } else { SendMessage(q->internalWinId(), WM_SETICON, 0 /* ICON_SMALL */, (LPARAM)x->winIconSmall); SendMessage(q->internalWinId(), WM_SETICON, 1 /* ICON_BIG */, (LPARAM)x->winIconSmall); } } void QWidgetPrivate::setWindowIconText_sys(const QString &iconText) { Q_UNUSED(iconText); } QCursor *qt_grab_cursor() { return mouseGrbCur; } // The procedure does nothing, but is required for mousegrabbing to work #ifndef Q_WS_WINCE LRESULT CALLBACK qJournalRecordProc(int nCode, WPARAM wParam, LPARAM lParam) { return CallNextHookEx(journalRec, nCode, wParam, lParam); } #endif //Q_WS_WINCE /* Works only as long as pointer is inside the application's window, which is good enough for QDockWidget. Doesn't call SetWindowsHookEx() - this function causes a system-wide freeze if any other app on the system installs a hook and fails to process events. */ void QWidgetPrivate::grabMouseWhileInWindow() { Q_Q(QWidget); if (!qt_nograb()) { if (mouseGrb) mouseGrb->releaseMouse(); Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); SetCapture(q->effectiveWinId()); mouseGrb = q; #ifndef QT_NO_CURSOR mouseGrbCur = new QCursor(mouseGrb->cursor()); #endif } } #ifndef Q_WS_WINCE void QWidget::grabMouse() { if (!qt_nograb()) { if (mouseGrb) mouseGrb->releaseMouse(); journalRec = SetWindowsHookEx(WH_JOURNALRECORD, (HOOKPROC)qJournalRecordProc, GetModuleHandle(0), 0); Q_ASSERT(testAttribute(Qt::WA_WState_Created)); SetCapture(effectiveWinId()); mouseGrb = this; #ifndef QT_NO_CURSOR mouseGrbCur = new QCursor(mouseGrb->cursor()); #endif } } #ifndef QT_NO_CURSOR void QWidget::grabMouse(const QCursor &cursor) { if (!qt_nograb()) { if (mouseGrb) mouseGrb->releaseMouse(); journalRec = SetWindowsHookEx(WH_JOURNALRECORD, (HOOKPROC)qJournalRecordProc, GetModuleHandle(0), 0); Q_ASSERT(testAttribute(Qt::WA_WState_Created)); SetCapture(effectiveWinId()); mouseGrbCur = new QCursor(cursor); SetCursor(mouseGrbCur->handle()); mouseGrb = this; } } #endif void QWidget::releaseMouse() { if (!qt_nograb() && mouseGrb == this) { ReleaseCapture(); if (journalRec) { UnhookWindowsHookEx(journalRec); journalRec = 0; } if (mouseGrbCur) { delete mouseGrbCur; mouseGrbCur = 0; } mouseGrb = 0; } } #endif 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::activateWindow() { window()->createWinId(); SetForegroundWindow(window()->internalWinId()); } #ifndef Q_WS_WINCE void QWidget::setWindowState(Qt::WindowStates newstate) { Q_D(QWidget); Qt::WindowStates oldstate = windowState(); if (oldstate == newstate) return; int max = SW_MAXIMIZE; int min = SW_MINIMIZE; int normal = SW_SHOWNOACTIVATE; if (newstate & Qt::WindowActive) { max = SW_SHOWMAXIMIZED; min = SW_SHOWMINIMIZED; normal = SW_SHOWNORMAL; } if (isWindow()) { createWinId(); Q_ASSERT(testAttribute(Qt::WA_WState_Created)); // Ensure the initial size is valid, since we store it as normalGeometry below. if (!testAttribute(Qt::WA_Resized) && !isVisible()) adjustSize(); if ((oldstate & Qt::WindowMaximized) != (newstate & Qt::WindowMaximized)) { if (newstate & Qt::WindowMaximized && !(oldstate & Qt::WindowFullScreen)) d->topData()->normalGeometry = geometry(); if (isVisible() && !(newstate & Qt::WindowMinimized)) { ShowWindow(internalWinId(), (newstate & Qt::WindowMaximized) ? max : normal); if (!(newstate & Qt::WindowFullScreen)) { QRect r = d->topData()->normalGeometry; if (!(newstate & Qt::WindowMaximized) && r.width() >= 0) { if (pos() != r.topLeft() || size() !=r.size()) { d->topData()->normalGeometry = QRect(0,0,-1,-1); setGeometry(r); } } } else { d->updateFrameStrut(); } } } if ((oldstate & Qt::WindowFullScreen) != (newstate & Qt::WindowFullScreen)) { if (newstate & Qt::WindowFullScreen) { if (d->topData()->normalGeometry.width() < 0 && !(oldstate & Qt::WindowMaximized)) d->topData()->normalGeometry = geometry(); d->topData()->savedFlags = Qt::WindowFlags(GetWindowLong(internalWinId(), GWL_STYLE)); #ifndef Q_FLATTEN_EXPOSE UINT style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP; #else UINT style = WS_POPUP; #endif if (ulong(d->topData()->savedFlags) & WS_SYSMENU) style |= WS_SYSMENU; if (isVisible()) style |= WS_VISIBLE; SetWindowLong(internalWinId(), GWL_STYLE, style); QRect r = QApplication::desktop()->screenGeometry(this); UINT swpf = SWP_FRAMECHANGED; if (newstate & Qt::WindowActive) swpf |= SWP_NOACTIVATE; SetWindowPos(internalWinId(), HWND_TOP, r.left(), r.top(), r.width(), r.height(), swpf); d->updateFrameStrut(); } else { UINT style = d->topData()->savedFlags; if (isVisible()) style |= WS_VISIBLE; SetWindowLong(internalWinId(), GWL_STYLE, style); UINT swpf = SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE; if (newstate & Qt::WindowActive) swpf |= SWP_NOACTIVATE; SetWindowPos(internalWinId(), 0, 0, 0, 0, 0, swpf); d->updateFrameStrut(); // preserve maximized state if (isVisible()) ShowWindow(internalWinId(), (newstate & Qt::WindowMaximized) ? max : normal); if (!(newstate & Qt::WindowMaximized)) { QRect r = d->topData()->normalGeometry; d->topData()->normalGeometry = QRect(0,0,-1,-1); if (r.isValid()) setGeometry(r); } } } if ((oldstate & Qt::WindowMinimized) != (newstate & Qt::WindowMinimized)) { if (isVisible()) ShowWindow(internalWinId(), (newstate & Qt::WindowMinimized) ? min : (newstate & Qt::WindowMaximized) ? max : normal); } } data->window_state = newstate; QWindowStateChangeEvent e(oldstate); QApplication::sendEvent(this, &e); } #endif //Q_WS_WINCE /* \internal Platform-specific part of QWidget::hide(). */ void QWidgetPrivate::hide_sys() { Q_Q(QWidget); deactivateWidgetCleanup(); Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); #ifdef Q_WS_WINCE if (!qt_wince_is_mobile() && q->isFullScreen()) { HWND handle = FindWindow(L"HHTaskBar", L""); if (handle) { ShowWindow(handle, 1); EnableWindow(handle, true); } } #endif if (q->windowFlags() != Qt::Desktop) { if ((q->windowFlags() & Qt::Popup) && q->internalWinId()) ShowWindow(q->internalWinId(), SW_HIDE); else if (q->internalWinId()) SetWindowPos(q->internalWinId(),0, 0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER); } if (q->isWindow()) { if (QWidgetBackingStore *bs = maybeBackingStore()) bs->releaseBuffer(); } else { invalidateBuffer(q->rect()); } q->setAttribute(Qt::WA_Mapped, false); } /* \internal Platform-specific part of QWidget::show(). */ #ifndef Q_WS_WINCE void QWidgetPrivate::show_sys() { Q_Q(QWidget); #if defined(QT_NON_COMMERCIAL) QT_NC_SHOW_WINDOW #endif if (q->testAttribute(Qt::WA_OutsideWSRange)) return; q->setAttribute(Qt::WA_Mapped); Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); if (q->testAttribute(Qt::WA_DontShowOnScreen)) { invalidateBuffer(q->rect()); return; } if (data.window_flags & Qt::Window) { QTLWExtra *extra = topData(); if (!extra->hotkeyRegistered) { // Try to set the hotkey using information from STARTUPINFO STARTUPINFO startupInfo; GetStartupInfo(&startupInfo); // If STARTF_USEHOTKEY is set, hStdInput is the virtual keycode if (startupInfo.dwFlags & 0x00000200) { WPARAM hotKey = (WPARAM)startupInfo.hStdInput; SendMessage(data.winid, WM_SETHOTKEY, hotKey, 0); } extra->hotkeyRegistered = 1; } } int sm = SW_SHOWNORMAL; bool fakedMaximize = false; if (q->isWindow()) { if (q->isMinimized()) { sm = SW_SHOWMINIMIZED; if (!IsWindowVisible(q->internalWinId())) sm = SW_SHOWMINNOACTIVE; } else if (q->isMaximized()) { sm = SW_SHOWMAXIMIZED; // Windows will not behave correctly when we try to maximize a window which does not // have minimize nor maximize buttons in the window frame. Windows would then ignore // non-available geometry, and rather maximize the widget to the full screen, minus the // window frame (caption). So, we do a trick here, by adding a maximize button before // maximizing the widget, and then remove the maximize button afterwards. Qt::WindowFlags &flags = data.window_flags; if (flags & Qt::WindowTitleHint && !(flags & (Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint))) { fakedMaximize = TRUE; int style = GetWindowLong(q->internalWinId(), GWL_STYLE); SetWindowLong(q->internalWinId(), GWL_STYLE, style | WS_MAXIMIZEBOX); } } } if (q->testAttribute(Qt::WA_ShowWithoutActivating) || (q->windowType() == Qt::Popup) || (q->windowType() == Qt::ToolTip) || (q->windowType() == Qt::Tool)) { sm = SW_SHOWNOACTIVATE; } if (q->internalWinId()) ShowWindow(q->internalWinId(), sm); if (fakedMaximize) { int style = GetWindowLong(q->internalWinId(), GWL_STYLE); SetWindowLong(q->internalWinId(), GWL_STYLE, style & ~WS_MAXIMIZEBOX); SetWindowPos(q->internalWinId(), 0, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED); } if (q->internalWinId()) { if (IsIconic(q->internalWinId())) data.window_state |= Qt::WindowMinimized; if (IsZoomed(q->internalWinId())) data.window_state |= Qt::WindowMaximized; // This is to resolve the problem where popups are opened from the // system tray and not being implicitly activated if (q->windowType() == Qt::Popup && (!q->parentWidget() || !q->parentWidget()->isActiveWindow())) q->activateWindow(); } winSetupGestures(); invalidateBuffer(q->rect()); } #endif //Q_WS_WINCE void QWidgetPrivate::setFocus_sys() { Q_Q(QWidget); if (q->testAttribute(Qt::WA_WState_Created) && q->window()->windowType() != Qt::Popup) SetFocus(q->effectiveWinId()); } void QWidgetPrivate::raise_sys() { Q_Q(QWidget); Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); if (q->internalWinId()) SetWindowPos(q->internalWinId(), HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); } void QWidgetPrivate::lower_sys() { Q_Q(QWidget); Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); if (q->internalWinId()) SetWindowPos(q->internalWinId(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); invalidateBuffer(q->rect()); } void QWidgetPrivate::stackUnder_sys(QWidget* w) { Q_Q(QWidget); Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); if (q->internalWinId() && w->internalWinId()) SetWindowPos(q->internalWinId(), w->internalWinId() , 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); invalidateBuffer(q->rect()); } /* Helper function for non-toplevel widgets. Helps to map Qt's 32bit coordinate system to Windpws's 16bit coordinate system. This code is duplicated from the X11 code, so any changes there should also (most likely) be reflected here. (In all comments below: s/X/Windows/g) */ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &) { Q_Q(QWidget); Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); /* There are up to four different coordinate systems here: Qt coordinate system for this widget. X coordinate system for this widget (relative to wrect). Qt coordinate system for parent X coordinate system for parent (relative to parent's wrect). */ QRect validRange(-XCOORD_MAX,-XCOORD_MAX, 2*XCOORD_MAX, 2*XCOORD_MAX); QRect wrectRange(-WRECT_MAX,-WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX); QRect wrect; //xrect is the X geometry of my X widget. (starts out in parent's Qt coord sys, and ends up in parent's X coord sys) QRect xrect = data.crect; const QWidget *const parent = q->parentWidget(); QRect parentWRect = parent->data->wrect; if (parentWRect.isValid()) { // parent is clipped, and we have to clip to the same limit as parent if (!parentWRect.contains(xrect)) { xrect &= parentWRect; wrect = xrect; //translate from parent's to my Qt coord sys wrect.translate(-data.crect.topLeft()); } //translate from parent's Qt coords to parent's X coords xrect.translate(-parentWRect.topLeft()); } else { // parent is not clipped, we may or may not have to clip if (data.wrect.isValid() && QRect(QPoint(),data.crect.size()).contains(data.wrect)) { // This is where the main optimization is: we are already // clipped, and if our clip is still valid, we can just // move our window, and do not need to move or clip // children QRect vrect = xrect & parent->rect(); vrect.translate(-data.crect.topLeft()); //the part of me that's visible through parent, in my Qt coords if (data.wrect.contains(vrect)) { xrect = data.wrect; xrect.translate(data.crect.topLeft()); if (q->internalWinId()) MoveWindow(q->internalWinId(), xrect.x(), xrect.y(), xrect.width(), xrect.height(), true); return; } } if (!validRange.contains(xrect)) { // we are too big, and must clip xrect &=wrectRange; wrect = xrect; wrect.translate(-data.crect.topLeft()); //parent's X coord system is equal to parent's Qt coord //sys, so we don't need to map xrect. } } // unmap if we are outside the valid window system coord system bool outsideRange = !xrect.isValid(); bool mapWindow = false; if (q->testAttribute(Qt::WA_OutsideWSRange) != outsideRange) { q->setAttribute(Qt::WA_OutsideWSRange, outsideRange); if (outsideRange) { if (q->internalWinId()) ShowWindow(q->internalWinId(), SW_HIDE); q->setAttribute(Qt::WA_Mapped, false); } else if (!q->isHidden()) { mapWindow = true; } } if (outsideRange) return; bool jump = (data.wrect != wrect); data.wrect = wrect; // and now recursively for all children... for (int i = 0; i < children.size(); ++i) { QObject *object = children.at(i); if (object->isWidgetType()) { QWidget *w = static_cast(object); if (!w->isWindow() && w->testAttribute(Qt::WA_WState_Created)) w->d_func()->setWSGeometry(); } } // move ourselves to the new position and map (if necessary) after // the movement. Rationale: moving unmapped windows is much faster // than moving mapped windows if (q->internalWinId()) { if (!parent->internalWinId()) xrect.translate(parent->mapTo(q->nativeParentWidget(), QPoint(0, 0))); MoveWindow(q->internalWinId(), xrect.x(), xrect.y(), xrect.width(), xrect.height(), !jump); } if (mapWindow && !dontShow) { q->setAttribute(Qt::WA_Mapped); if (q->internalWinId()) ShowWindow(q->internalWinId(), SW_SHOWNOACTIVATE); } if (jump && q->internalWinId()) InvalidateRect(q->internalWinId(), 0, false); } // // The internal qWinRequestConfig, defined in qapplication_win.cpp, stores move, // resize and setGeometry requests for a widget that is already // processing a config event. The purpose is to avoid recursion. // void qWinRequestConfig(WId, int, int, int, int, int); void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove) { Q_Q(QWidget); Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); 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 (q->isWindow()) topData()->normalGeometry = QRect(0, 0, -1, -1); QSize oldSize(q->size()); QPoint oldPos(q->pos()); if (!q->isWindow()) isMove = (data.crect.topLeft() != QPoint(x, y)); bool isResize = w != oldSize.width() || h != oldSize.height(); if (!isMove && !isResize) return; if (isResize && !q->testAttribute(Qt::WA_StaticContents) && q->internalWinId()) ValidateRgn(q->internalWinId(), 0); #ifdef Q_WS_WINCE // On Windows CE we can't just fiddle around with the window state. // Too much magic in setWindowState. if (isResize && q->isMaximized()) q->setWindowState(q->windowState() & ~Qt::WindowMaximized); #else if (isResize) data.window_state &= ~Qt::WindowMaximized; #endif if (data.window_state & Qt::WindowFullScreen) { QTLWExtra *top = topData(); if (q->isWindow()) { // We need to update these flags when we remove the full screen state // or the frame will not be updated UINT style = top->savedFlags; if (q->isVisible()) style |= WS_VISIBLE; SetWindowLong(q->internalWinId(), GWL_STYLE, style); UINT swpf = SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE; if (data.window_state & Qt::WindowActive) swpf |= SWP_NOACTIVATE; SetWindowPos(q->internalWinId(), 0, 0, 0, 0, 0, swpf); updateFrameStrut(); } data.window_state &= ~Qt::WindowFullScreen; topData()->savedFlags = 0; } QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData(); const bool inTopLevelResize = tlwExtra ? tlwExtra->inTopLevelResize : false; const bool isTranslucentWindow = !isOpaque && ptrUpdateLayeredWindowIndirect && (data.window_flags & Qt::FramelessWindowHint) && GetWindowLong(q->internalWinId(), GWL_EXSTYLE) & Q_WS_EX_LAYERED; if (q->testAttribute(Qt::WA_WState_ConfigPending)) { // processing config event if (q->internalWinId()) qWinRequestConfig(q->internalWinId(), isMove ? 2 : 1, x, y, w, h); } else { if (!q->testAttribute(Qt::WA_DontShowOnScreen)) q->setAttribute(Qt::WA_WState_ConfigPending); if (q->windowType() == Qt::Desktop) { data.crect.setRect(x, y, w, h); } else if (q->isWindow()) { QRect fs(frameStrut()); if (extra) { fs.setLeft(x - fs.left()); fs.setTop(y - fs.top()); fs.setRight((x + w - 1) + fs.right()); fs.setBottom((y + h - 1) + fs.bottom()); } if (w == 0 || h == 0) { q->setAttribute(Qt::WA_OutsideWSRange, true); if (q->isVisible() && q->testAttribute(Qt::WA_Mapped)) hide_sys(); data.crect = QRect(x, y, w, h); } else if (q->isVisible() && q->testAttribute(Qt::WA_OutsideWSRange)) { q->setAttribute(Qt::WA_OutsideWSRange, false); // put the window in its place and show it MoveWindow(q->internalWinId(), fs.x(), fs.y(), fs.width(), fs.height(), true); RECT rect; if (!q->testAttribute(Qt::WA_DontShowOnScreen)) { GetClientRect(q->internalWinId(), &rect); data.crect.setRect(x, y, rect.right - rect.left, rect.bottom - rect.top); } else { data.crect.setRect(x, y, w, h); } show_sys(); } else if (!q->testAttribute(Qt::WA_DontShowOnScreen)) { q->setAttribute(Qt::WA_OutsideWSRange, false); #ifndef Q_WS_WINCE // If the window is hidden and in maximized state or minimized, instead of moving the // window, set the normal position of the window. WINDOWPLACEMENT wndpl; GetWindowPlacement(q->internalWinId(), &wndpl); if ((wndpl.showCmd == SW_MAXIMIZE && !IsWindowVisible(q->internalWinId())) || wndpl.showCmd == SW_SHOWMINIMIZED) { RECT normal = {fs.x(), fs.y(), fs.x()+fs.width(), fs.y()+fs.height()}; wndpl.rcNormalPosition = normal; wndpl.showCmd = wndpl.showCmd == SW_SHOWMINIMIZED ? SW_SHOWMINIMIZED : SW_HIDE; SetWindowPlacement(q->internalWinId(), &wndpl); } else { #else if (data.window_state & Qt::WindowMaximized) { qt_wince_maximize(q); } else { #endif MoveWindow(q->internalWinId(), fs.x(), fs.y(), fs.width(), fs.height(), true); } if (!q->isVisible()) InvalidateRect(q->internalWinId(), 0, FALSE); RECT rect; // If the layout has heightForWidth, the MoveWindow() above can // change the size/position, so refresh them. if (isTranslucentWindow) { data.crect.setRect(x, y, w, h); } else { GetClientRect(q->internalWinId(), &rect); RECT rcNormalPosition ={0}; // Use (0,0) as window position for embedded ActiveQt controls. if (!tlwExtra || !tlwExtra->embedded) GetWindowRect(q->internalWinId(), &rcNormalPosition); QRect fStrut(frameStrut()); data.crect.setRect(rcNormalPosition.left + fStrut.left(), rcNormalPosition.top + fStrut.top(), rect.right - rect.left, rect.bottom - rect.top); isResize = data.crect.size() != oldSize; } } else { q->setAttribute(Qt::WA_OutsideWSRange, false); data.crect.setRect(x, y, w, h); } } else { QRect oldGeom(data.crect); data.crect.setRect(x, y, w, h); if (q->isVisible() && (!inTopLevelResize || q->internalWinId())) { // Top-level resize optimization does not work for native child widgets; // disable it for this particular widget. if (inTopLevelResize) tlwExtra->inTopLevelResize = false; if (!isResize) moveRect(QRect(oldPos, oldSize), x - oldPos.x(), y - oldPos.y()); else invalidateBuffer_resizeHelper(oldPos, oldSize); if (inTopLevelResize) tlwExtra->inTopLevelResize = true; } if (q->testAttribute(Qt::WA_WState_Created)) setWSGeometry(); } q->setAttribute(Qt::WA_WState_ConfigPending, false); } if (q->isWindow() && q->isVisible() && isResize && !inTopLevelResize) { invalidateBuffer(q->rect()); //after the resize } // Process events immediately rather than in translateConfigEvent to // avoid windows message process delay. if (q->isVisible()) { if (isMove && q->pos() != oldPos) { QMoveEvent e(q->pos(), oldPos); QApplication::sendEvent(q, &e); } if (isResize) { static bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt(); // If we have a backing store with static contents, we have to disable the top-level // resize optimization in order to get invalidated regions for resized widgets. // The optimization discards all invalidateBuffer() calls since we're going to // repaint everything anyways, but that's not the case with static contents. const bool setTopLevelResize = !slowResize && q->isWindow() && extra && extra->topextra && !extra->topextra->inTopLevelResize && (!extra->topextra->backingStore || !extra->topextra->backingStore->hasStaticContents()); if (setTopLevelResize) extra->topextra->inTopLevelResize = true; QResizeEvent e(q->size(), oldSize); QApplication::sendEvent(q, &e); if (setTopLevelResize) extra->topextra->inTopLevelResize = false; } } else { if (isMove && q->pos() != oldPos) q->setAttribute(Qt::WA_PendingMoveEvent, true); if (isResize) q->setAttribute(Qt::WA_PendingResizeEvent, true); } } bool QWidgetPrivate::shouldShowMaximizeButton() { if (data.window_flags & Qt::MSWindowsFixedSizeDialogHint) return false; // if the user explicitely asked for the maximize button, we try to add // it even if the window has fixed size. if (data.window_flags & Qt::CustomizeWindowHint && data.window_flags & Qt::WindowMaximizeButtonHint) return true; if (extra) { if ((extra->maxw && extra->maxw != QWIDGETSIZE_MAX && extra->maxw != QLAYOUTSIZE_MAX) || (extra->maxh && extra->maxh != QWIDGETSIZE_MAX && extra->maxh != QLAYOUTSIZE_MAX)) return false; } return data.window_flags & Qt::WindowMaximizeButtonHint; } void QWidgetPrivate::winUpdateIsOpaque() { #ifndef Q_WS_WINCE Q_Q(QWidget); if (!q->isWindow() || !q->testAttribute(Qt::WA_TranslucentBackground)) return; if ((data.window_flags & Qt::FramelessWindowHint) == 0) return; if (!isOpaque && ptrUpdateLayeredWindowIndirect) { SetWindowLong(q->internalWinId(), GWL_EXSTYLE, GetWindowLong(q->internalWinId(), GWL_EXSTYLE) | Q_WS_EX_LAYERED); } else { SetWindowLong(q->internalWinId(), GWL_EXSTYLE, GetWindowLong(q->internalWinId(), GWL_EXSTYLE) & ~Q_WS_EX_LAYERED); } #endif } void QWidgetPrivate::setConstraints_sys() { #ifndef Q_WS_WINCE_WM Q_Q(QWidget); if (q->isWindow() && q->testAttribute(Qt::WA_WState_Created)) { int style = GetWindowLong(q->internalWinId(), GWL_STYLE); if (shouldShowMaximizeButton()) style |= WS_MAXIMIZEBOX; else style &= ~WS_MAXIMIZEBOX; SetWindowLong(q->internalWinId(), GWL_STYLE, style); } #endif } void QWidgetPrivate::scroll_sys(int dx, int dy) { Q_Q(QWidget); scrollChildren(dx, dy); if (!paintOnScreen()) { scrollRect(q->rect(), dx, dy); } else { UINT flags = SW_INVALIDATE; if (!q->testAttribute(Qt::WA_OpaquePaintEvent)) flags |= SW_ERASE; Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); ScrollWindowEx(q->internalWinId(), dx, dy, 0, 0, 0, 0, flags); UpdateWindow(q->internalWinId()); } } void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r) { Q_Q(QWidget); if (!paintOnScreen()) { scrollRect(r, dx, dy); } else { RECT wr; wr.top = r.top(); wr.left = r.left(); wr.bottom = r.bottom()+1; wr.right = r.right()+1; UINT flags = SW_INVALIDATE; if (!q->testAttribute(Qt::WA_OpaquePaintEvent)) flags |= SW_ERASE; Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); ScrollWindowEx(q->internalWinId(), dx, dy, &wr, &wr, 0, 0, flags); UpdateWindow(q->internalWinId()); } } extern Q_GUI_EXPORT HDC qt_win_display_dc(); int QWidget::metric(PaintDeviceMetric m) const { Q_D(const QWidget); int val; if (m == PdmWidth) { val = data->crect.width(); } else if (m == PdmHeight) { val = data->crect.height(); } else { HDC gdc = qt_win_display_dc(); switch (m) { case PdmDpiX: case PdmPhysicalDpiX: if (d->extra && d->extra->customDpiX) val = d->extra->customDpiX; else if (d->parent) val = static_cast(d->parent)->metric(m); else val = GetDeviceCaps(gdc, LOGPIXELSX); break; case PdmDpiY: case PdmPhysicalDpiY: if (d->extra && d->extra->customDpiY) val = d->extra->customDpiY; else if (d->parent) val = static_cast(d->parent)->metric(m); else val = GetDeviceCaps(gdc, LOGPIXELSY); break; case PdmWidthMM: val = data->crect.width() * GetDeviceCaps(gdc, HORZSIZE) / GetDeviceCaps(gdc, HORZRES); break; case PdmHeightMM: val = data->crect.height() * GetDeviceCaps(gdc, VERTSIZE) / GetDeviceCaps(gdc, VERTRES); break; case PdmNumColors: if (GetDeviceCaps(gdc, RASTERCAPS) & RC_PALETTE) val = GetDeviceCaps(gdc, SIZEPALETTE); else { HDC hd = d->hd ? HDC(d->hd) : gdc; int bpp = GetDeviceCaps(hd, BITSPIXEL); if (bpp == 32) val = INT_MAX; // ### this is bogus, it should be 2^24 colors for 32 bit as well else if(bpp<=8) val = GetDeviceCaps(hd, NUMCOLORS); else val = 1 << (bpp * GetDeviceCaps(hd, PLANES)); } break; case PdmDepth: val = GetDeviceCaps(gdc, BITSPIXEL); break; default: val = 0; qWarning("QWidget::metric: Invalid metric command"); } } return val; } void QWidgetPrivate::createSysExtra() { #ifndef QT_NO_DRAGANDDROP extra->dropTarget = 0; #endif } #ifndef Q_WS_WINCE void QWidgetPrivate::deleteSysExtra() { } #endif //Q_WS_WINCE void QWidgetPrivate::createTLSysExtra() { extra->topextra->hotkeyRegistered = 0; extra->topextra->savedFlags = 0; extra->topextra->winIconBig = 0; extra->topextra->winIconSmall = 0; } void QWidgetPrivate::deleteTLSysExtra() { if (extra->topextra->winIconSmall) DestroyIcon(extra->topextra->winIconSmall); if (extra->topextra->winIconBig) DestroyIcon(extra->topextra->winIconBig); } void QWidgetPrivate::registerDropSite(bool on) { Q_Q(QWidget); if (!q->testAttribute(Qt::WA_WState_Created)) return; // Enablement is defined by d->extra->dropTarget != 0. if (on) { // Turn on. createExtra(); #ifndef QT_NO_DRAGANDDROP if (!q->internalWinId()) q->nativeParentWidget()->d_func()->createExtra(); QWExtra *extra = extraData(); if (!extra->dropTarget) extra->dropTarget = registerOleDnd(q); #endif } else { // Turn off. QWExtra *extra = extraData(); #ifndef QT_NO_DRAGANDDROP if (extra && extra->dropTarget) { unregisterOleDnd(q, extra->dropTarget); extra->dropTarget = 0; } #endif } } #ifndef QT_NO_DRAGANDDROP QOleDropTarget* QWidgetPrivate::registerOleDnd(QWidget *widget) { QOleDropTarget *dropTarget = new QOleDropTarget(widget); Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created)); if (!widget->internalWinId()) { QWidget *nativeParent = widget->nativeParentWidget(); Q_ASSERT(nativeParent); QWExtra *nativeExtra = nativeParent->d_func()->extra; Q_ASSERT(nativeExtra); if (!nativeParent->acceptDrops()) nativeParent->setAcceptDrops(true); if (!nativeExtra->oleDropWidgets.contains(widget)) nativeExtra->oleDropWidgets.append(widget); if (!nativeExtra->dropTarget) { nativeExtra->dropTarget = registerOleDnd(nativeParent); Q_ASSERT(nativeExtra->dropTarget); #ifndef Q_OS_WINCE CoLockObjectExternal(nativeExtra->dropTarget, false, true); #endif RegisterDragDrop(nativeParent->internalWinId(), nativeExtra->dropTarget); } } else { RegisterDragDrop(widget->internalWinId(), dropTarget); #ifndef Q_OS_WINCE CoLockObjectExternal(dropTarget, true, true); #endif } return dropTarget; } void QWidgetPrivate::unregisterOleDnd(QWidget *widget, QOleDropTarget *dropTarget) { dropTarget->releaseQt(); dropTarget->Release(); Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created)); if (!widget->internalWinId()) { QWidget *nativeParent = widget->nativeParentWidget(); Q_ASSERT(nativeParent); QWExtra *nativeExtra = nativeParent->d_func()->extra; Q_ASSERT(nativeExtra); nativeExtra->oleDropWidgets.removeAll(widget); nativeExtra->oleDropWidgets.removeAll(static_cast(0)); if (nativeExtra->oleDropWidgets.isEmpty() && nativeExtra->dropTarget && !nativeParent->testAttribute(Qt::WA_DropSiteRegistered)) { #ifndef Q_OS_WINCE CoLockObjectExternal(nativeExtra->dropTarget, false, true); #endif RevokeDragDrop(nativeParent->internalWinId()); nativeExtra->dropTarget = 0; } } else { #ifndef Q_OS_WINCE CoLockObjectExternal(dropTarget, false, true); #endif RevokeDragDrop(widget->internalWinId()); } } #endif //QT_NO_DRAGANDDROP // from qregion_win.cpp extern HRGN qt_tryCreateRegion(QRegion::RegionType type, int left, int top, int right, int bottom); void QWidgetPrivate::setMask_sys(const QRegion ®ion) { Q_Q(QWidget); if (!q->internalWinId()) return; if (region.isEmpty()) { SetWindowRgn(q->internalWinId(), 0, true); return; } // Since SetWindowRegion takes ownership, and we need to translate, // we take a copy. HRGN wr = qt_tryCreateRegion(QRegion::Rectangle, 0,0,0,0); CombineRgn(wr, region.handle(), 0, RGN_COPY); QPoint offset = (q->isWindow() ? frameStrut().topLeft() : QPoint(0, 0)); OffsetRgn(wr, offset.x(), offset.y()); Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); if (!SetWindowRgn(data.winid, wr, true)) DeleteObject(wr); } void QWidgetPrivate::updateFrameStrut() { Q_Q(QWidget); if (!q->testAttribute(Qt::WA_WState_Created)) return; if (!q->internalWinId()) { data.fstrut_dirty = false; return; } RECT rect = {0,0,0,0}; QTLWExtra *top = topData(); uint exstyle = GetWindowLong(q->internalWinId(), GWL_EXSTYLE); uint style = GetWindowLong(q->internalWinId(), GWL_STYLE); #ifndef Q_WS_WINCE if (AdjustWindowRectEx(&rect, style & ~(WS_OVERLAPPED), FALSE, exstyle)) { #else if (AdjustWindowRectEx(&rect, style, FALSE, exstyle)) { #endif top->frameStrut.setCoords(-rect.left, -rect.top, rect.right, rect.bottom); data.fstrut_dirty = false; } } #ifndef Q_WS_WINCE void QWidgetPrivate::setWindowOpacity_sys(qreal level) { Q_Q(QWidget); if (!isOpaque && ptrUpdateLayeredWindow && (data.window_flags & Qt::FramelessWindowHint)) { if (GetWindowLong(q->internalWinId(), GWL_EXSTYLE) & Q_WS_EX_LAYERED) { BLENDFUNCTION blend = {AC_SRC_OVER, 0, (int)(255.0 * level), AC_SRC_ALPHA}; ptrUpdateLayeredWindow(q->internalWinId(), NULL, NULL, NULL, NULL, NULL, 0, &blend, Q_ULW_ALPHA); } return; } static bool function_resolved = false; if (!function_resolved) { ptrSetLayeredWindowAttributes = (PtrSetLayeredWindowAttributes) QLibrary::resolve(QLatin1String("user32"), "SetLayeredWindowAttributes"); function_resolved = true; } if (!ptrSetLayeredWindowAttributes) return; int wl = GetWindowLong(q->internalWinId(), GWL_EXSTYLE); if (level != 1.0) { if ((wl&Q_WS_EX_LAYERED) == 0) SetWindowLong(q->internalWinId(), GWL_EXSTYLE, wl | Q_WS_EX_LAYERED); } else if (wl&Q_WS_EX_LAYERED) { SetWindowLong(q->internalWinId(), GWL_EXSTYLE, wl & ~Q_WS_EX_LAYERED); } ptrSetLayeredWindowAttributes(q->internalWinId(), 0, (int)(level * 255), Q_LWA_ALPHA); } #endif //Q_WS_WINCE // class QGlobalRasterPaintEngine: public QRasterPaintEngine // { // public: // inline QGlobalRasterPaintEngine() : QRasterPaintEngine() { setFlushOnEnd(false); } // }; // Q_GLOBAL_STATIC(QGlobalRasterPaintEngine, globalRasterPaintEngine) #ifndef QT_NO_DIRECTDRAW static uchar *qt_primary_surface_bits; static int qt_primary_surface_stride; static QImage::Format qt_primary_surface_format; void qt_win_initialize_directdraw() { HRESULT res; // Some initialization... if (!qt_ddraw_object) { res = DirectDrawCreate(0, &qt_ddraw_object, 0); if (res != DD_OK) qWarning("DirectDrawCreate failed: %d", res); qt_ddraw_object->SetCooperativeLevel(0, DDSCL_NORMAL); DDSURFACEDESC surfaceDesc; memset(&surfaceDesc, 0, sizeof(DDSURFACEDESC)); surfaceDesc.dwSize = sizeof(DDSURFACEDESC); surfaceDesc.dwFlags = DDSD_CAPS; surfaceDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; res = qt_ddraw_object->CreateSurface(&surfaceDesc, &qt_ddraw_primary, 0); if (res != DD_OK) qWarning("CreateSurface failed: %d", res); memset(&surfaceDesc, 0, sizeof(DDSURFACEDESC)); surfaceDesc.dwSize = sizeof(DDSURFACEDESC); res = qt_ddraw_primary->Lock(0, &surfaceDesc, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, 0); if (res != DD_OK) qWarning("Locking surface failed: %d", res); if (surfaceDesc.ddpfPixelFormat.dwFlags == DDPF_RGB) { qt_primary_surface_bits = (uchar *) surfaceDesc.lpSurface; qt_primary_surface_stride = surfaceDesc.lPitch; qt_primary_surface_format = QImage::Format_RGB32; } else { qWarning("QWidget painting: unsupported device depth for onscreen painting...\n"); } qt_ddraw_primary->Unlock(0); } } class QOnScreenRasterPaintEngine : public QRasterPaintEngine { public: // The image allocated here leaks... Fix if this code is ifdef'ed // in QOnScreenRasterPaintEngine() : QRasterPaintEngine(new QImage(qt_primary_surface_bits, QApplication::desktop()->width(), QApplication::desktop()->height(), qt_primary_surface_stride, qt_primary_surface_format)) { device = static_cast(d_func()->device); } bool begin(QPaintDevice *) { QRegion clip = systemClip(); originalSystemClip = clip; clip.translate(widget->mapToGlobal(QPoint(0, 0))); setSystemClip(clip); QRect bounds = clip.boundingRect(); DDSURFACEDESC surface; surface.dwSize = sizeof(DDSURFACEDESC); HRESULT res = qt_ddraw_primary->Lock((RECT *) &bounds, &surface, DDLOCK_WAIT, 0); if (res != DD_OK) { qWarning("QWidget painting: locking onscreen bits failed: %d\n", res); return false; } if (surface.lpSurface == qt_primary_surface_bits) { qt_primary_surface_bits = (uchar *) surface.lpSurface; device->data_ptr()->data = qt_primary_surface_bits; } return QRasterPaintEngine::begin(device); } bool end() { HRESULT res = qt_ddraw_primary->Unlock(0); if (res != DD_OK) qWarning("QWidget::paint, failed to unlock DirectDraw surface: %d", res); bool ok = QRasterPaintEngine::end(); setSystemClip(originalSystemClip); return ok; } QPoint coordinateOffset() const { return -widget->mapToGlobal(QPoint(0, 0)); } const QWidget *widget; QImage *device; QRegion originalSystemClip; }; Q_GLOBAL_STATIC(QOnScreenRasterPaintEngine, onScreenPaintEngine) #else void qt_win_initialize_directdraw() { } #endif QPaintEngine *QWidget::paintEngine() const { #ifndef QT_NO_DIRECTDRAW QOnScreenRasterPaintEngine *pe = onScreenPaintEngine(); pe->widget = this; return pe; #endif // We set this bit which is checked in setAttribute for // Qt::WA_PaintOnScreen. We do this to allow these two scenarios: // // 1. Users accidentally set Qt::WA_PaintOnScreen on X and port to // windows which would mean suddenly their widgets stop working. // // 2. Users set paint on screen and subclass paintEngine() to // return 0, in which case we have a "hole" in the backingstore // allowing use of GDI or DirectX directly. // // 1 is WRONG, but to minimize silent failures, we have set this // bit to ignore the setAttribute call. 2. needs to be // supported because its our only means of embeddeding native // graphics stuff. const_cast(d_func())->noPaintOnScreen = 1; return 0; } QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys() { Q_Q(QWidget); return new QRasterWindowSurface(q); } void QWidgetPrivate::setModal_sys() { } void QWidgetPrivate::registerTouchWindow() { Q_Q(QWidget); // enable WM_TOUCH* messages on our window if (q->testAttribute(Qt::WA_WState_Created) && QApplicationPrivate::RegisterTouchWindow && q->windowType() != Qt::Desktop) QApplicationPrivate::RegisterTouchWindow(q->effectiveWinId(), 0); } void QWidgetPrivate::winSetupGestures() { #if !defined(QT_NO_NATIVE_GESTURES) Q_Q(QWidget); if (!q || !q->isVisible() || !nativeGesturePanEnabled) return; if (!QApplicationPrivate::HasTouchSupport) return; QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); if (!qAppPriv->SetGestureConfig) return; WId winid = q->internalWinId(); bool needh = false; bool needv = false; bool singleFingerPanEnabled = false; #ifndef QT_NO_SCROLLAREA if (QAbstractScrollArea *asa = qobject_cast(q->parent())) { QScrollBar *hbar = asa->horizontalScrollBar(); QScrollBar *vbar = asa->verticalScrollBar(); Qt::ScrollBarPolicy hbarpolicy = asa->horizontalScrollBarPolicy(); Qt::ScrollBarPolicy vbarpolicy = asa->verticalScrollBarPolicy(); needh = (hbarpolicy == Qt::ScrollBarAlwaysOn || (hbarpolicy == Qt::ScrollBarAsNeeded && hbar->minimum() < hbar->maximum())); needv = (vbarpolicy == Qt::ScrollBarAlwaysOn || (vbarpolicy == Qt::ScrollBarAsNeeded && vbar->minimum() < vbar->maximum())); singleFingerPanEnabled = asa->d_func()->singleFingerPanEnabled; if (!winid) { winid = q->winId(); // enforces the native winid on the viewport } } #endif //QT_NO_SCROLLAREA if (winid) { GESTURECONFIG gc[1]; memset(gc, 0, sizeof(gc)); gc[0].dwID = GID_PAN; if (nativeGesturePanEnabled) { gc[0].dwWant = GC_PAN; if (needv && singleFingerPanEnabled) gc[0].dwWant |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY; else gc[0].dwBlock |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY; if (needh && singleFingerPanEnabled) gc[0].dwWant |= GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY; else gc[0].dwBlock |= GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY; } else { gc[0].dwBlock = GC_PAN; } qAppPriv->SetGestureConfig(winid, 0, sizeof(gc)/sizeof(gc[0]), gc, sizeof(gc[0])); } #endif } QT_END_NAMESPACE #ifdef Q_WS_WINCE # include "qwidget_wince.cpp" #endif