1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include "qwidget_p.h"
43 #include "qdesktopwidget.h"
44 #include "qapplication.h"
45 #include "qapplication_p.h"
46 #include "private/qbackingstore_p.h"
51 #include "private/qwindowsurface_s60_p.h"
53 #include <qinputcontext.h>
57 #include <akntoolbar.h>
61 // This is necessary in order to be able to perform delayed invocation on slots
62 // which take arguments of type WId. One example is
63 // QWidgetPrivate::_q_delayedDestroy, which is used to delay destruction of
64 // CCoeControl objects until after the CONE event handler has finished running.
65 Q_DECLARE_METATYPE(WId)
69 extern bool qt_nograb();
71 QWidget *QWidgetPrivate::mouseGrabber = 0;
72 QWidget *QWidgetPrivate::keyboardGrabber = 0;
73 CEikButtonGroupContainer *QS60Data::cba = 0;
75 static bool isEqual(const QList<QAction*>& a, const QList<QAction*>& b)
77 if ( a.count() != b.count())
80 while (index<a.count()) {
81 if (a.at(index)->softKeyRole() != b.at(index)->softKeyRole())
83 if (a.at(index)->text().compare(b.at(index)->text())!=0)
90 void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &)
92 // Note: based on x11 implementation
94 static const int XCOORD_MAX = 16383;
95 static const int WRECT_MAX = 16383;
99 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
102 There are up to four different coordinate systems here:
103 Qt coordinate system for this widget.
104 Symbian coordinate system for this widget (relative to wrect).
105 Qt coordinate system for parent
106 Symbian coordinate system for parent (relative to parent's wrect).
109 QRect validRange(-XCOORD_MAX,-XCOORD_MAX, 2*XCOORD_MAX, 2*XCOORD_MAX);
110 QRect wrectRange(-WRECT_MAX,-WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX);
112 //xrect is the Symbian geometry of my widget. (starts out in parent's Qt coord sys, and ends up in parent's Symbian coord sys)
113 QRect xrect = data.crect;
115 const QWidget *const parent = q->parentWidget();
116 QRect parentWRect = parent->data->wrect;
118 if (parentWRect.isValid()) {
119 // parent is clipped, and we have to clip to the same limit as parent
120 if (!parentWRect.contains(xrect)) {
121 xrect &= parentWRect;
123 //translate from parent's to my Qt coord sys
124 wrect.translate(-data.crect.topLeft());
126 //translate from parent's Qt coords to parent's X coords
127 xrect.translate(-parentWRect.topLeft());
130 // parent is not clipped, we may or may not have to clip
132 if (data.wrect.isValid() && QRect(QPoint(),data.crect.size()).contains(data.wrect)) {
133 // This is where the main optimization is: we are already
134 // clipped, and if our clip is still valid, we can just
135 // move our window, and do not need to move or clip
138 QRect vrect = xrect & parent->rect();
139 vrect.translate(-data.crect.topLeft()); //the part of me that's visible through parent, in my Qt coords
140 if (data.wrect.contains(vrect)) {
142 xrect.translate(data.crect.topLeft());
144 data.winid->SetExtent(TPoint(xrect.x(), xrect.y()), TSize(xrect.width(), xrect.height()));
149 if (!validRange.contains(xrect)) {
150 // we are too big, and must clip
153 wrect.translate(-data.crect.topLeft());
154 //parent's X coord system is equal to parent's Qt coord
155 //sys, so we don't need to map xrect.
159 // unmap if we are outside the valid window system coord system
160 bool outsideRange = !xrect.isValid();
161 bool mapWindow = false;
162 if (q->testAttribute(Qt::WA_OutsideWSRange) != outsideRange) {
163 q->setAttribute(Qt::WA_OutsideWSRange, outsideRange);
166 data.winid->DrawableWindow()->SetVisible(EFalse);
167 q->setAttribute(Qt::WA_Mapped, false);
168 } else if (!q->isHidden()) {
176 bool jump = (data.wrect != wrect);
179 // and now recursively for all children...
180 for (int i = 0; i < children.size(); ++i) {
181 QObject *object = children.at(i);
182 if (object->isWidgetType()) {
183 QWidget *w = static_cast<QWidget *>(object);
184 if (!w->isWindow() && w->testAttribute(Qt::WA_WState_Created))
185 w->d_func()->setWSGeometry(jump);
190 // move ourselves to the new position and map (if necessary) after
191 // the movement. Rationale: moving unmapped windows is much faster
192 // than moving mapped windows
193 if (!parent->internalWinId())
194 xrect.translate(parent->mapTo(q->nativeParentWidget(), QPoint(0, 0)));
196 data.winid->SetExtent(TPoint(xrect.x(), xrect.y()), TSize(xrect.width(), xrect.height()));
199 if (mapWindow and !dontShow) {
200 q->setAttribute(Qt::WA_Mapped);
201 if (q->internalWinId())
202 q->internalWinId()->DrawableWindow()->SetVisible(ETrue);
205 if (jump && data.winid) {
206 RWindow *const window = static_cast<RWindow *>(data.winid->DrawableWindow());
207 window->Invalidate(TRect(0, 0, wrect.width(), wrect.height()));
211 void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
215 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
217 if ((q->windowType() == Qt::Desktop))
220 QPoint oldPos(q->pos());
221 QSize oldSize(q->size());
222 QRect oldGeom(data.crect);
224 // Lose maximized status if deliberate resize
225 if (w != oldSize.width() || h != oldSize.height())
226 data.window_state &= ~Qt::WindowMaximized;
228 if (extra) { // any size restrictions?
229 w = qMin(w,extra->maxw);
230 h = qMin(h,extra->maxh);
231 w = qMax(w,extra->minw);
232 h = qMax(h,extra->minh);
236 topData()->normalGeometry = QRect(0, 0, -1, -1);
238 uint s = data.window_state;
239 s &= ~(Qt::WindowMaximized | Qt::WindowFullScreen);
240 data.window_state = s;
243 bool isResize = w != oldSize.width() || h != oldSize.height();
244 if (!isMove && !isResize)
248 if (w == 0 || h == 0) {
249 q->setAttribute(Qt::WA_OutsideWSRange, true);
250 if (q->isVisible() && q->testAttribute(Qt::WA_Mapped))
252 data.crect = QRect(x, y, w, h);
253 data.window_state &= ~Qt::WindowFullScreen;
254 } else if (q->isVisible() && q->testAttribute(Qt::WA_OutsideWSRange)) {
255 q->setAttribute(Qt::WA_OutsideWSRange, false);
257 // put the window in its place and show it
258 q->internalWinId()->SetRect(TRect(TPoint(x, y), TSize(w, h)));
259 data.crect.setRect(x, y, w, h);
262 QRect r = QRect(x, y, w, h);
264 q->internalWinId()->SetRect(TRect(TPoint(x, y), TSize(w, h)));
265 topData()->normalGeometry = data.crect;
268 data.crect.setRect(x, y, w, h);
270 QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();
271 const bool inTopLevelResize = tlwExtra ? tlwExtra->inTopLevelResize : false;
273 if (q->isVisible() && (!inTopLevelResize || q->internalWinId())) {
274 // Top-level resize optimization does not work for native child widgets;
275 // disable it for this particular widget.
276 if (inTopLevelResize)
277 tlwExtra->inTopLevelResize = false;
278 if (!isResize && maybeBackingStore())
279 moveRect(QRect(oldPos, oldSize), x - oldPos.x(), y - oldPos.y());
281 invalidateBuffer_resizeHelper(oldPos, oldSize);
283 if (inTopLevelResize)
284 tlwExtra->inTopLevelResize = true;
286 if (q->testAttribute(Qt::WA_WState_Created))
290 if (q->isVisible()) {
291 if (isMove && q->pos() != oldPos) {
292 QMoveEvent e(q->pos(), oldPos);
293 QApplication::sendEvent(q, &e);
296 bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt();
297 const bool setTopLevelResize = !slowResize && q->isWindow() && extra && extra->topextra
298 && !extra->topextra->inTopLevelResize;
299 if (setTopLevelResize)
300 extra->topextra->inTopLevelResize = true;
301 QResizeEvent e(q->size(), oldSize);
302 QApplication::sendEvent(q, &e);
303 if (!q->testAttribute(Qt::WA_StaticContents) && q->internalWinId())
304 q->internalWinId()->DrawDeferred();
305 if (setTopLevelResize)
306 extra->topextra->inTopLevelResize = false;
309 if (isMove && q->pos() != oldPos)
310 q->setAttribute(Qt::WA_PendingMoveEvent, true);
312 q->setAttribute(Qt::WA_PendingResizeEvent, true);
316 void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool destroyOldWindow)
320 Qt::WindowType type = q->windowType();
321 Qt::WindowFlags &flags = data.window_flags;
322 QWidget *parentWidget = q->parentWidget();
324 bool topLevel = (flags & Qt::Window);
325 bool popup = (type == Qt::Popup);
326 bool dialog = (type == Qt::Dialog
328 || (flags & Qt::MSWindowsFixedSizeDialogHint));
329 bool desktop = (type == Qt::Desktop);
330 //bool tool = (type == Qt::Tool || type == Qt::Drawer);
333 flags |= Qt::WindowStaysOnTopHint; // a popup stays on top
335 TRect clientRect = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
336 int sw = clientRect.Width();
337 int sh = clientRect.Height();
340 TSize screenSize = S60->screenDevice()->SizeInPixels();
341 data.crect.setRect(0, 0, screenSize.iWidth, screenSize.iHeight);
342 q->setAttribute(Qt::WA_DontShowOnScreen);
343 } else if (topLevel && !q->testAttribute(Qt::WA_Resized)){
347 width = qMax(qMin(width, extra->maxw), extra->minw);
348 height = qMax(qMin(height, extra->maxh), extra->minh);
350 data.crect.setSize(QSize(width, height));
353 CCoeControl *const destroyw = destroyOldWindow ? data.winid : 0;
358 TRect tr = window->Rect();
359 data.crect.setRect(tr.iTl.iX, tr.iTl.iY, tr.Width(), tr.Height());
361 } else if (topLevel) {
362 if (!q->testAttribute(Qt::WA_Moved) && !q->testAttribute(Qt::WA_DontShowOnScreen))
363 data.crect.moveTopLeft(QPoint(clientRect.iTl.iX, clientRect.iTl.iY));
365 QScopedPointer<QSymbianControl> control( q_check_ptr(new QSymbianControl(q)) );
366 QT_TRAP_THROWING(control->ConstructL(true, desktop));
367 control->SetMopParent(static_cast<CEikAppUi*>(S60->appUi()));
369 // Symbian windows are always created in an inactive state
370 // We perform this assignment for the case where the window is being re-created
371 // as a result of a call to setParent_sys, on either this widget or one of its
373 extra->activated = 0;
377 if ((q->windowType() & Qt::Popup) == Qt::Popup) {
378 stackingFlags = ECoeStackFlagRefusesAllKeys | ECoeStackFlagRefusesFocus;
380 stackingFlags = ECoeStackFlagStandard;
382 control->MakeVisible(false);
383 QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control.data(), ECoeStackPriorityDefault, stackingFlags));
384 // Avoid keyboard focus to a hidden window.
385 control->setFocusSafely(false);
387 RDrawableWindow *const drawableWindow = control->DrawableWindow();
388 // Request mouse move events.
389 drawableWindow->PointerFilter(EPointerFilterEnterExit
390 | EPointerFilterMove | EPointerFilterDrag, 0);
391 drawableWindow->EnableVisibilityChangeEvents();
395 q->setAttribute(Qt::WA_WState_Created);
398 data.crect.getRect(&x, &y, &w, &h);
399 control->SetRect(TRect(TPoint(x, y), TSize(w, h)));
401 // We wait until the control is fully constructed before calling setWinId, because
402 // this generates a WinIdChanged event.
403 setWinId(control.take());
406 s60UpdateIsOpaque(); // must be called after setWinId()
408 } else if (q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) { // create native child widget
410 QScopedPointer<QSymbianControl> control( q_check_ptr(new QSymbianControl(q)) );
411 QT_TRAP_THROWING(control->ConstructL(!parentWidget));
413 // Symbian windows are always created in an inactive state
414 // We perform this assignment for the case where the window is being re-created
415 // as a result of a call to setParent_sys, on either this widget or one of its
417 extra->activated = 0;
420 if ((q->windowType() & Qt::Popup) == Qt::Popup) {
421 stackingFlags = ECoeStackFlagRefusesAllKeys | ECoeStackFlagRefusesFocus;
423 stackingFlags = ECoeStackFlagStandard;
425 control->MakeVisible(false);
426 QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control.data(), ECoeStackPriorityDefault, stackingFlags));
427 // Avoid keyboard focus to a hidden window.
428 control->setFocusSafely(false);
430 q->setAttribute(Qt::WA_WState_Created);
432 data.crect.getRect(&x, &y, &w, &h);
433 control->SetRect(TRect(TPoint(x, y), TSize(w, h)));
435 RDrawableWindow *const drawableWindow = control->DrawableWindow();
436 // Request mouse move events.
437 drawableWindow->PointerFilter(EPointerFilterEnterExit
438 | EPointerFilterMove | EPointerFilterDrag, 0);
439 drawableWindow->EnableVisibilityChangeEvents();
441 if (q->isVisible() && q->testAttribute(Qt::WA_Mapped)) {
442 activateSymbianWindow(control.data());
443 control->MakeVisible(true);
446 // We wait until the control is fully constructed before calling setWinId, because
447 // this generates a WinIdChanged event.
448 setWinId(control.take());
452 destroyw->ControlEnv()->AppUi()->RemoveFromStack(destroyw);
454 // Delay deletion of the control in case this function is called in the
455 // context of a CONE event handler such as
456 // CCoeControl::ProcessPointerEventL
457 QMetaObject::invokeMethod(q, "_q_delayedDestroy",
458 Qt::QueuedConnection, Q_ARG(WId, destroyw));
461 if (q->testAttribute(Qt::WA_AcceptTouchEvents))
462 registerTouchWindow();
466 void QWidgetPrivate::show_sys()
470 if (q->testAttribute(Qt::WA_OutsideWSRange))
473 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
475 q->setAttribute(Qt::WA_Mapped);
477 if (q->testAttribute(Qt::WA_DontShowOnScreen)) {
478 invalidateBuffer(q->rect());
482 if (q->internalWinId()) {
483 if (!extra->activated)
484 activateSymbianWindow();
486 QSymbianControl *id = static_cast<QSymbianControl *>(q->internalWinId());
487 const bool isFullscreen = q->windowState() & Qt::WindowFullScreen;
488 const TBool cbaRequested = q->windowFlags() & Qt::WindowSoftkeysVisibleHint;
491 // Lazily initialize the S60 screen furniture when the first window is shown.
492 if (q->isWindow() && !QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes)
493 && !S60->buttonGroupContainer() && !S60->statusPane()) {
495 if (!q->testAttribute(Qt::WA_DontShowOnScreen)) {
497 // Create the status pane and CBA here
498 CEikAppUi *ui = static_cast<CEikAppUi *>(S60->appUi());
499 MEikAppUiFactory *factory = CEikonEnv::Static()->AppUiFactory();
502 factory->CreateResourceIndependentFurnitureL(ui);
504 TRect boundingRect = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
506 CEikButtonGroupContainer *cba = CEikButtonGroupContainer::NewL(CEikButtonGroupContainer::ECba,
507 CEikButtonGroupContainer::EHorizontal,ui,R_AVKON_SOFTKEYS_EMPTY_WITH_IDS);
508 if (isFullscreen && !cbaRequested)
509 cba->MakeVisible(false);
511 CEikButtonGroupContainer *oldCba = factory->SwapButtonGroup(cba);
513 S60->setButtonGroupContainer(cba);
515 // If the creation of the first widget is delayed, for example by doing it
516 // inside the event loop, S60 somehow "forgets" to set the visibility of the
517 // toolbar (the three middle softkeys) when you flip the phone over, so we
518 // need to do it ourselves to avoid a "hole" in the application, even though
519 // Qt itself does not use the toolbar directly..
520 CAknAppUi *appui = dynamic_cast<CAknAppUi *>(CEikonEnv::Static()->AppUi());
522 CAknToolbar *toolbar = appui->PopupToolbar();
523 if (toolbar && !toolbar->IsVisible())
524 toolbar->SetToolbarVisibility(ETrue);
527 CEikMenuBar *menuBar = new(ELeave) CEikMenuBar;
528 menuBar->ConstructL(ui, 0, R_AVKON_MENUPANE_EMPTY);
529 menuBar->SetMenuType(CEikMenuBar::EMenuOptions);
530 S60->appUi()->AddToStackL(menuBar,ECoeStackPriorityMenu,ECoeStackFlagRefusesFocus);
532 CEikMenuBar *oldMenu = factory->SwapMenuBar(menuBar);
536 if (S60->statusPane()) {
537 // Use QDesktopWidget as the status pane observer to proxy for the AppUi.
538 // Can't use AppUi directly because it privately inherits from MEikStatusPaneObserver.
539 QSymbianControl *desktopControl = static_cast<QSymbianControl *>(QApplication::desktop()->winId());
540 S60->statusPane()->SetObserver(desktopControl);
542 const bool cbaVisible = S60->buttonGroupContainer() && S60->buttonGroupContainer()->IsVisible();
543 S60->setStatusPaneAndButtonGroupVisibility(false, cbaVisible);
550 // Fill client area if maximized OR
551 // Put window below status pane unless the window has an explicit position.
553 if (q->windowState() & Qt::WindowMaximized) {
554 TRect r = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
555 id->SetExtent(r.iTl, r.Size());
556 } else if (!q->testAttribute(Qt::WA_Moved) && q->windowType() != Qt::Dialog) {
557 id->SetPosition(static_cast<CEikAppUi*>(S60->appUi())->ClientRect().iTl);
561 id->MakeVisible(true);
563 if(q->isWindow()&&!q->testAttribute(Qt::WA_ShowWithoutActivating))
564 id->setFocusSafely(true);
567 invalidateBuffer(q->rect());
570 void QWidgetPrivate::activateSymbianWindow(WId wid)
574 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
575 Q_ASSERT(q->testAttribute(Qt::WA_Mapped));
576 Q_ASSERT(!extra->activated);
579 wid = q->internalWinId();
583 QT_TRAP_THROWING(wid->ActivateL());
584 extra->activated = 1;
587 void QWidgetPrivate::hide_sys()
591 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
592 deactivateWidgetCleanup();
593 QSymbianControl *id = static_cast<QSymbianControl *>(q->internalWinId());
596 //Incorrect optimization - for popup windows, Qt's focus is moved before
597 //hide_sys is called, resulting in the popup window keeping its elevated
598 //position in the CONE control stack.
599 //This can result in keyboard focus being in an invisible widget in some
600 //conditions - e.g. QTBUG-4733
601 //if(id->IsFocused()) // Avoid unnecessary calls to FocusChanged()
602 id->setFocusSafely(false);
603 id->MakeVisible(false);
604 if (QWidgetBackingStore *bs = maybeBackingStore())
607 invalidateBuffer(q->rect());
610 q->setAttribute(Qt::WA_Mapped, false);
613 void QWidgetPrivate::setFocus_sys()
616 if (q->testAttribute(Qt::WA_WState_Created) && q->window()->windowType() != Qt::Popup)
617 if (!q->effectiveWinId()->IsFocused()) // Avoid unnecessry calls to FocusChanged()
618 static_cast<QSymbianControl *>(q->effectiveWinId())->setFocusSafely(true);
621 void QWidgetPrivate::raise_sys()
625 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
626 if (q->internalWinId()) {
627 q->internalWinId()->DrawableWindow()->SetOrdinalPosition(0);
629 // If toplevel widget, raise app to foreground
631 S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup().Identifier(), 0);
635 void QWidgetPrivate::lower_sys()
639 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
640 if (q->internalWinId()) {
641 // If toplevel widget, lower app to background
643 S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup().Identifier(), -1);
645 q->internalWinId()->DrawableWindow()->SetOrdinalPosition(-1);
649 invalidateBuffer(q->rect());
652 void QWidgetPrivate::setModal_sys()
657 void QWidgetPrivate::stackUnder_sys(QWidget* w)
660 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
662 if (q->internalWinId() && w->internalWinId()) {
663 RDrawableWindow *const thisWindow = q->internalWinId()->DrawableWindow();
664 RDrawableWindow *const otherWindow = w->internalWinId()->DrawableWindow();
665 thisWindow->SetOrdinalPosition(otherWindow->OrdinalPosition() + 1);
668 if (!q->isWindow() || !w->internalWinId())
669 invalidateBuffer(q->rect());
672 void QWidgetPrivate::reparentChildren()
676 QObjectList chlist = q->children();
677 for (int i = 0; i < chlist.size(); ++i) { // reparent children
678 QObject *obj = chlist.at(i);
679 if (obj->isWidgetType()) {
680 QWidget *w = (QWidget *)obj;
681 if (!w->testAttribute(Qt::WA_WState_Created))
683 if (!w->isWindow()) {
684 w->d_func()->invalidateBuffer(w->rect());
685 WId parent = q->effectiveWinId();
686 WId child = w->effectiveWinId();
687 if (parent != child) {
688 // Child widget is native. Because Symbian windows cannot be
689 // re-parented, we must re-create the window.
690 const WId window = 0;
691 const bool initializeWindow = false;
692 const bool destroyOldWindow = true;
693 w->d_func()->create_sys(window, initializeWindow, destroyOldWindow);
695 // ### TODO: We probably also need to update the component array here
696 w->d_func()->reparentChildren();
698 bool showIt = w->isVisible();
699 QPoint old_pos = w->pos();
700 w->setParent(q, w->windowFlags());
709 void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
713 bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
715 if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
716 q->parentWidget()->d_func()->invalidateBuffer(q->geometry());
718 if (q->testAttribute(Qt::WA_DropSiteRegistered))
719 q->setAttribute(Qt::WA_DropSiteRegistered, false);
721 QSymbianControl *old_winid = static_cast<QSymbianControl *>(wasCreated ? data.winid : 0);
722 if ((q->windowType() == Qt::Desktop))
725 // old_winid may not have received a 'not visible' visibility
726 // changed event before being destroyed; make sure that it is
727 // removed from the backing store's list of visible windows.
729 S60->controlVisibilityChanged(old_winid, false);
733 // hide and reparent our own window away. Otherwise we might get
734 // destroyed when emitting the child remove event below. See QWorkspace.
735 if (wasCreated && old_winid) {
736 old_winid->MakeVisible(false);
737 if (old_winid->IsFocused()) // Avoid unnecessary calls to FocusChanged()
738 old_winid->setFocusSafely(false);
739 old_winid->SetParent(0);
742 QObjectPrivate::setParent_helper(parent);
743 bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide);
745 data.window_flags = f;
746 data.fstrut_dirty = true;
747 q->setAttribute(Qt::WA_WState_Created, false);
748 q->setAttribute(Qt::WA_WState_Visible, false);
749 q->setAttribute(Qt::WA_WState_Hidden, false);
750 adjustFlags(data.window_flags, q);
751 // keep compatibility with previous versions, we need to preserve the created state
752 // (but we recreate the winId for the widget being reparented, again for compatibility)
753 if (wasCreated || (!q->isWindow() && parent->testAttribute(Qt::WA_WState_Created)))
755 if (q->isWindow() || (!parent || parent->isVisible()) || explicitlyHidden)
756 q->setAttribute(Qt::WA_WState_Hidden);
757 q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden);
763 CBase::Delete(old_winid);
766 if (q->testAttribute(Qt::WA_AcceptDrops)
767 || (!q->isWindow() && q->parentWidget() && q->parentWidget()->testAttribute(Qt::WA_DropSiteRegistered)))
768 q->setAttribute(Qt::WA_DropSiteRegistered, true);
770 invalidateBuffer(q->rect());
773 void QWidgetPrivate::setConstraints_sys()
779 void QWidgetPrivate::s60UpdateIsOpaque()
783 if (!q->testAttribute(Qt::WA_WState_Created) || !q->testAttribute(Qt::WA_TranslucentBackground))
788 RWindow *const window = static_cast<RWindow *>(q->effectiveWinId()->DrawableWindow());
790 #ifdef Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE
791 window->SetSurfaceTransparency(!isOpaque);
792 extra->topextra->nativeWindowTransparencyEnabled = !isOpaque;
795 const TDisplayMode displayMode = static_cast<TDisplayMode>(window->SetRequiredDisplayMode(EColor16MA));
796 if (window->SetTransparencyAlphaChannel() == KErrNone) {
797 window->SetBackgroundColor(TRgb(255, 255, 255, 0));
798 extra->topextra->nativeWindowTransparencyEnabled = 1;
800 if (extra->topextra->backingStore.data() &&
801 QApplicationPrivate::graphics_system_name == QLatin1String("openvg")) {
802 // Semi-transparent EGL surfaces aren't supported. We need to
803 // recreate backing store to get translucent surface (raster surface).
804 extra->topextra->backingStore.create(q);
805 extra->topextra->backingStore.registerWidget(q);
808 } else if (extra->topextra->nativeWindowTransparencyEnabled) {
809 window->SetTransparentRegion(TRegionFix<1>());
810 extra->topextra->nativeWindowTransparencyEnabled = 0;
815 void QWidgetPrivate::setWindowIcon_sys(bool forceReset)
820 if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow() )
823 QTLWExtra* topData = this->topData();
824 if (topData->iconPixmap && !forceReset)
829 TBool found = AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EContextPane, cPaneRect );
830 CAknContextPane* contextPane = S60->contextPane();
831 if (found && contextPane) { // We have context pane with valid metrics
832 QIcon icon = q->windowIcon();
833 if (!icon.isNull()) {
834 // Valid icon -> set it as an context pane picture
835 QSize size = icon.actualSize(QSize(cPaneRect.Size().iWidth, cPaneRect.Size().iHeight));
836 QPixmap pm = icon.pixmap(size);
837 QBitmap mask = pm.mask();
839 mask = QBitmap(pm.size());
840 mask.fill(Qt::color1);
843 CFbsBitmap* nBitmap = pm.toSymbianCFbsBitmap();
844 CFbsBitmap* nMask = mask.toSymbianCFbsBitmap();
845 contextPane->SetPicture(nBitmap,nMask);
847 // Icon set to null -> set context pane picture to default
848 QT_TRAP_THROWING(contextPane->SetPictureToDefaultL());
851 // Context pane does not exist, try setting small icon to title pane
853 TBool found = AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::ETitlePane, titlePaneRect );
854 CAknTitlePane* titlePane = S60->titlePane();
855 if (found && titlePane) { // We have title pane with valid metrics
856 // The API to get title_pane graphics size is not public -> assume square space based
857 // on titlebar font height. CAknBitmap would be optimum, wihtout setting the size, since
858 // then title pane would automatically scale the bitmap. Unfortunately it is not public API
859 // Also this function is leaving, although it is not named as such.
861 QT_TRAP_THROWING(font = AknLayoutUtils::FontFromId(EAknLogicalFontTitleFont));
862 TSize iconSize(font->HeightInPixels(), font->HeightInPixels());
864 QIcon icon = q->windowIcon();
865 if (!icon.isNull()) {
866 // Valid icon -> set it as an title pane small picture
867 QSize size = icon.actualSize(QSize(iconSize.iWidth, iconSize.iHeight));
868 QPixmap pm = icon.pixmap(size);
869 QBitmap mask = pm.mask();
871 mask = QBitmap(pm.size());
872 mask.fill(Qt::color1);
875 CFbsBitmap* nBitmap = pm.toSymbianCFbsBitmap();
876 CFbsBitmap* nMask = mask.toSymbianCFbsBitmap();
877 titlePane->SetSmallPicture( nBitmap, nMask, ETrue );
879 // Icon set to null -> set context pane picture to default
880 titlePane->SetSmallPicture( NULL, NULL, EFalse );
890 void QWidgetPrivate::setWindowTitle_sys(const QString &caption)
895 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
896 CAknTitlePane* titlePane = S60->titlePane();
898 if (caption.isEmpty()) {
899 QT_TRAP_THROWING(titlePane->SetTextToDefaultL());
901 QT_TRAP_THROWING(titlePane->SetTextL(qt_QString2TPtrC(caption)));
910 void QWidgetPrivate::setWindowIconText_sys(const QString & /*iconText */)
915 void QWidgetPrivate::scroll_sys(int dx, int dy)
919 scrollChildren(dx, dy);
920 if (!paintOnScreen() || !q->internalWinId() || !q->internalWinId()->OwnsWindow()) {
921 scrollRect(q->rect(), dx, dy);
923 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
924 RDrawableWindow *const window = q->internalWinId()->DrawableWindow();
925 window->Scroll(TPoint(dx, dy));
929 void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r)
933 if (!paintOnScreen() || !q->internalWinId() || !q->internalWinId()->OwnsWindow()) {
934 scrollRect(r, dx, dy);
936 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
937 RDrawableWindow *const window = q->internalWinId()->DrawableWindow();
938 window->Scroll(TPoint(dx, dy), qt_QRect2TRect(r));
943 For this function to work in the emulator, you must add:
945 To a line in the wsini.ini file.
947 void QWidgetPrivate::setWindowOpacity_sys(qreal)
949 // ### TODO: Implement uniform window transparency
952 void QWidgetPrivate::updateFrameStrut()
957 void QWidgetPrivate::updateSystemBackground()
962 void QWidgetPrivate::registerDropSite(bool /* on */)
967 void QWidgetPrivate::createTLSysExtra()
969 extra->topextra->inExpose = 0;
970 extra->topextra->nativeWindowTransparencyEnabled = 0;
973 void QWidgetPrivate::deleteTLSysExtra()
975 extra->topextra->backingStore.destroy();
978 void QWidgetPrivate::createSysExtra()
980 extra->activated = 0;
981 extra->nativePaintMode = QWExtra::Default;
982 extra->receiveNativePaintEvents = 0;
985 void QWidgetPrivate::deleteSysExtra()
987 // this should only be non-zero if destroy() has not run due to constructor fail
989 data.winid->ControlEnv()->AppUi()->RemoveFromStack(data.winid);
995 QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys()
997 return new QS60WindowSurface(q_func());
1000 void QWidgetPrivate::setMask_sys(const QRegion& /* region */)
1005 void QWidgetPrivate::registerTouchWindow()
1007 #ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
1009 if (q->testAttribute(Qt::WA_WState_Created) && q->windowType() != Qt::Desktop) {
1010 RWindow *rwindow = static_cast<RWindow *>(q->effectiveWinId()->DrawableWindow());
1011 QSymbianControl *window = static_cast<QSymbianControl *>(q->effectiveWinId());
1012 //Enabling advanced pointer events for controls that already have active windows causes a panic.
1013 if (!window->isControlActive())
1014 rwindow->EnableAdvancedPointers();
1019 int QWidget::metric(PaintDeviceMetric m) const
1023 if (m == PdmWidth) {
1024 val = data->crect.width();
1025 } else if (m == PdmHeight) {
1026 val = data->crect.height();
1028 CWsScreenDevice *scr = S60->screenDevice();
1031 case PdmPhysicalDpiX:
1032 if (d->extra && d->extra->customDpiX) {
1033 val = d->extra->customDpiX;
1035 const QWidgetPrivate *p = d;
1037 p = static_cast<const QWidget *>(p->parent)->d_func();
1038 if (p->extra && p->extra->customDpiX) {
1039 val = p->extra->customDpiX;
1043 if (p == d || !(p->extra && p->extra->customDpiX))
1044 val = S60->defaultDpiX;
1048 case PdmPhysicalDpiY:
1049 if (d->extra && d->extra->customDpiY) {
1050 val = d->extra->customDpiY;
1052 const QWidgetPrivate *p = d;
1054 p = static_cast<const QWidget *>(p->parent)->d_func();
1055 if (p->extra && p->extra->customDpiY) {
1056 val = p->extra->customDpiY;
1060 if (p == d || !(p->extra && p->extra->customDpiY))
1061 val = S60->defaultDpiY;
1066 TInt twips = scr->HorizontalPixelsToTwips(data->crect.width());
1067 val = (int)(twips * (25.4/KTwipsPerInch));
1072 TInt twips = scr->VerticalPixelsToTwips(data->crect.height());
1073 val = (int)(twips * (25.4/KTwipsPerInch));
1077 val = TDisplayModeUtils::NumDisplayModeColors(scr->DisplayMode());
1080 val = TDisplayModeUtils::NumDisplayModeBitsPerPixel(scr->DisplayMode());
1084 qWarning("QWidget::metric: Invalid metric command");
1090 QPaintEngine *QWidget::paintEngine() const
1095 QPoint QWidget::mapToGlobal(const QPoint &pos) const
1098 if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
1100 QPoint p = pos + data->crect.topLeft();
1101 return (isWindow() || !parentWidget()) ? p : parentWidget()->mapToGlobal(p);
1103 } else if ((d->data.window_flags & Qt::Window) && internalWinId()) { //toplevel
1104 QPoint tp = geometry().topLeft();
1108 // Native window case
1109 const TPoint widgetScreenOffset = internalWinId()->PositionRelativeToScreen();
1110 const QPoint globalPos = QPoint(widgetScreenOffset.iX, widgetScreenOffset.iY) + pos;
1114 QPoint QWidget::mapFromGlobal(const QPoint &pos) const
1117 if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
1118 QPoint p = (isWindow() || !parentWidget()) ? pos : parentWidget()->mapFromGlobal(pos);
1119 return p - data->crect.topLeft();
1120 } else if ((d->data.window_flags & Qt::Window) && internalWinId()) { //toplevel
1121 QPoint tp = geometry().topLeft();
1125 // Native window case
1126 const TPoint widgetScreenOffset = internalWinId()->PositionRelativeToScreen();
1127 const QPoint widgetPos = pos - QPoint(widgetScreenOffset.iX, widgetScreenOffset.iY);
1131 static Qt::WindowStates effectiveState(Qt::WindowStates state)
1133 if (state & Qt::WindowMinimized)
1134 return Qt::WindowMinimized;
1135 else if (state & Qt::WindowFullScreen)
1136 return Qt::WindowFullScreen;
1137 else if (state & Qt::WindowMaximized)
1138 return Qt::WindowMaximized;
1139 return Qt::WindowNoState;
1142 void QWidget::setWindowState(Qt::WindowStates newstate)
1146 Qt::WindowStates oldstate = windowState();
1148 const TBool isFullscreen = newstate & Qt::WindowFullScreen;
1150 const TBool cbaRequested = windowFlags() & Qt::WindowSoftkeysVisibleHint;
1151 const TBool cbaVisible = CEikButtonGroupContainer::Current() ? true : false;
1152 const TBool softkeyVisibilityChange = isFullscreen && (cbaRequested != cbaVisible);
1154 if (oldstate == newstate && !softkeyVisibilityChange)
1160 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1162 const bool wasResized = testAttribute(Qt::WA_Resized);
1163 const bool wasMoved = testAttribute(Qt::WA_Moved);
1165 QSymbianControl *window = static_cast<QSymbianControl *>(effectiveWinId());
1166 if (window && newstate & Qt::WindowMinimized) {
1167 window->setFocusSafely(false);
1168 window->MakeVisible(false);
1169 } else if (window && oldstate & Qt::WindowMinimized) {
1170 window->setFocusSafely(true);
1171 window->MakeVisible(true);
1175 bool decorationsVisible(false);
1176 if (!parentWidget()) { // Only top level native windows have control over cba/status pane
1177 // Hide window decoration when switching to fullscreen / minimized otherwise show decoration.
1178 // The window decoration visibility has to be changed before doing actual window state
1179 // change since in that order the availableGeometry will return directly the right size and
1180 // we will avoid unnecessary redraws
1181 decorationsVisible = !(newstate & (Qt::WindowFullScreen | Qt::WindowMinimized));
1182 const bool statusPaneVisibility = decorationsVisible;
1183 const bool buttonGroupVisibility = (decorationsVisible || (isFullscreen && cbaRequested));
1184 S60->setStatusPaneAndButtonGroupVisibility(statusPaneVisibility, buttonGroupVisibility);
1188 // Ensure the initial size is valid, since we store it as normalGeometry below.
1189 if (!wasResized && !isVisible())
1192 QTLWExtra *top = d->topData();
1193 QRect normalGeometry = (top->normalGeometry.width() < 0) ? geometry() : top->normalGeometry;
1195 const bool cbaVisibilityHint = windowFlags() & Qt::WindowSoftkeysVisibleHint;
1196 if (newstate & Qt::WindowFullScreen && !cbaVisibilityHint) {
1197 setAttribute(Qt::WA_OutsideWSRange, false);
1198 window->SetExtentToWholeScreen();
1199 } else if (newstate & Qt::WindowMaximized || ((newstate & Qt::WindowFullScreen) && cbaVisibilityHint)) {
1200 setAttribute(Qt::WA_OutsideWSRange, false);
1201 TRect maxExtent = qt_QRect2TRect(qApp->desktop()->availableGeometry(this));
1202 window->SetExtent(maxExtent.iTl, maxExtent.Size());
1205 // With delayed creation of S60 app panes, the normalGeometry calculated above is not
1206 // accurate because it did not consider the status pane. This means that when returning
1207 // normal mode after showing the status pane, the geometry would overlap so we should
1208 // move it if it never had an explicit position.
1209 if (!wasMoved && S60->statusPane() && decorationsVisible) {
1210 TPoint tl = static_cast<CEikAppUi*>(S60->appUi())->ClientRect().iTl;
1211 normalGeometry.setTopLeft(QPoint(tl.iX, tl.iY));
1214 setGeometry(normalGeometry);
1217 //restore normal geometry
1218 top->normalGeometry = normalGeometry;
1221 // In some platforms, WA_Resized and WA_Moved are also not set when application window state is
1222 // anything else than normal. In Symbian we can restore them only for normal window state since
1223 // restoring for other modes, will make fluidlauncher to be launched in wrong size (200x100)
1224 if (effectiveState(newstate) == Qt::WindowNoState) {
1225 setAttribute(Qt::WA_Resized, wasResized);
1226 setAttribute(Qt::WA_Moved, wasMoved);
1230 data->window_state = newstate;
1232 if (newstate & Qt::WindowActive)
1235 QWindowStateChangeEvent e(oldstate);
1236 QApplication::sendEvent(this, &e);
1240 void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
1243 d->aboutToDestroy();
1244 if (!isWindow() && parentWidget())
1245 parentWidget()->d_func()->invalidateBuffer(geometry());
1246 d->deactivateWidgetCleanup();
1247 QSymbianControl *id = static_cast<QSymbianControl *>(internalWinId());
1248 if (testAttribute(Qt::WA_WState_Created)) {
1254 QInputContext *ic = QApplicationPrivate::inputContext;
1256 ic->widgetDestroyed(this);
1261 if (QWidgetPrivate::mouseGrabber == this)
1263 if (QWidgetPrivate::keyboardGrabber == this)
1265 setAttribute(Qt::WA_WState_Created, false);
1266 QObjectList childList = children();
1267 for (int i = 0; i < childList.size(); ++i) { // destroy all widget children
1268 register QObject *obj = childList.at(i);
1269 if (obj->isWidgetType())
1270 static_cast<QWidget*>(obj)->destroy(destroySubWindows,
1273 if (destroyWindow && !(windowType() == Qt::Desktop) && id) {
1274 if (id->IsFocused()) // Avoid unnecessry calls to FocusChanged()
1275 id->setFocusSafely(false);
1276 id->ControlEnv()->AppUi()->RemoveFromStack(id);
1282 } QT_CATCH (const std::bad_alloc &) {
1283 // swallow - destructors must not throw
1286 if (destroyWindow) {
1288 // At this point the backing store should already be destroyed
1289 // so we flush the command buffer to ensure that the freeing of
1290 // those resources and deleting the window can happen "atomically"
1292 S60->wsSession().Flush();
1296 QWidget *QWidget::mouseGrabber()
1298 return QWidgetPrivate::mouseGrabber;
1301 QWidget *QWidget::keyboardGrabber()
1303 return QWidgetPrivate::keyboardGrabber;
1306 void QWidget::grabKeyboard()
1309 if (QWidgetPrivate::keyboardGrabber && QWidgetPrivate::keyboardGrabber != this)
1310 QWidgetPrivate::keyboardGrabber->releaseKeyboard();
1312 // ### TODO: Native keyboard grab
1314 QWidgetPrivate::keyboardGrabber = this;
1318 void QWidget::releaseKeyboard()
1320 if (!qt_nograb() && QWidgetPrivate::keyboardGrabber == this) {
1321 // ### TODO: Native keyboard release
1322 QWidgetPrivate::keyboardGrabber = 0;
1326 void QWidget::grabMouse()
1328 if (isVisible() && !qt_nograb()) {
1329 if (QWidgetPrivate::mouseGrabber && QWidgetPrivate::mouseGrabber != this)
1330 QWidgetPrivate::mouseGrabber->releaseMouse();
1331 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1332 WId id = effectiveWinId();
1333 id->SetPointerCapture(true);
1334 QWidgetPrivate::mouseGrabber = this;
1336 #ifndef QT_NO_CURSOR
1337 QApplication::setOverrideCursor(cursor());
1342 #ifndef QT_NO_CURSOR
1343 void QWidget::grabMouse(const QCursor &cursor)
1345 if (isVisible() && !qt_nograb()) {
1346 if (QWidgetPrivate::mouseGrabber && QWidgetPrivate::mouseGrabber != this)
1347 QWidgetPrivate::mouseGrabber->releaseMouse();
1348 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1349 WId id = effectiveWinId();
1350 id->SetPointerCapture(true);
1351 QWidgetPrivate::mouseGrabber = this;
1353 QApplication::setOverrideCursor(cursor);
1358 void QWidget::releaseMouse()
1360 if (!qt_nograb() && QWidgetPrivate::mouseGrabber == this) {
1361 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1362 if(!window()->isModal()) {
1363 WId id = effectiveWinId();
1364 id->SetPointerCapture(false);
1366 QWidgetPrivate::mouseGrabber = 0;
1367 #ifndef QT_NO_CURSOR
1368 QApplication::restoreOverrideCursor();
1373 void QWidget::activateWindow()
1377 QWidget *tlw = window();
1378 if (tlw->isVisible()) {
1379 window()->createWinId();
1380 QSymbianControl *id = static_cast<QSymbianControl *>(tlw->internalWinId());
1381 id->setFocusSafely(true);
1385 #ifndef QT_NO_CURSOR
1387 void QWidgetPrivate::setCursor_sys(const QCursor &cursor)
1391 qt_symbian_set_cursor(q, false);
1394 void QWidgetPrivate::unsetCursor_sys()
1397 qt_symbian_set_cursor(q, false);