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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
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>
60 // This is necessary in order to be able to perform delayed invocation on slots
61 // which take arguments of type WId.
62 Q_DECLARE_METATYPE(WId)
64 // Workaround for the fact that S60 SDKs 3.x do not contain the akntoolbar.h
65 // header, even though the documentation says that it should be there, and indeed
66 // it is present in the library.
67 class CAknToolbar : public CAknControl,
68 public MCoeControlObserver,
69 public MCoeControlBackground,
70 public MEikCommandObserver,
71 public MAknFadedComponent
74 IMPORT_C void SetToolbarVisibility(const TBool visible);
79 extern bool qt_nograb();
81 QWidget *QWidgetPrivate::mouseGrabber = 0;
82 QWidget *QWidgetPrivate::keyboardGrabber = 0;
83 CEikButtonGroupContainer *QS60Data::cba = 0;
85 int qt_symbian_create_desktop_on_screen = -1;
87 static bool isEqual(const QList<QAction*>& a, const QList<QAction*>& b)
89 if ( a.count() != b.count())
92 while (index<a.count()) {
93 if (a.at(index)->softKeyRole() != b.at(index)->softKeyRole())
95 if (a.at(index)->text().compare(b.at(index)->text())!=0)
102 void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &)
104 // Note: based on x11 implementation
106 static const int XCOORD_MAX = 16383;
107 static const int WRECT_MAX = 16383;
111 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
114 There are up to four different coordinate systems here:
115 Qt coordinate system for this widget.
116 Symbian coordinate system for this widget (relative to wrect).
117 Qt coordinate system for parent
118 Symbian coordinate system for parent (relative to parent's wrect).
121 QRect validRange(-XCOORD_MAX,-XCOORD_MAX, 2*XCOORD_MAX, 2*XCOORD_MAX);
122 QRect wrectRange(-WRECT_MAX,-WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX);
124 //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)
125 QRect xrect = data.crect;
127 const QWidget *const parent = q->parentWidget();
128 QRect parentWRect = parent->data->wrect;
130 if (parentWRect.isValid()) {
131 // parent is clipped, and we have to clip to the same limit as parent
132 if (!parentWRect.contains(xrect)) {
133 xrect &= parentWRect;
135 //translate from parent's to my Qt coord sys
136 wrect.translate(-data.crect.topLeft());
138 //translate from parent's Qt coords to parent's X coords
139 xrect.translate(-parentWRect.topLeft());
142 // parent is not clipped, we may or may not have to clip
144 if (data.wrect.isValid() && QRect(QPoint(),data.crect.size()).contains(data.wrect)) {
145 // This is where the main optimization is: we are already
146 // clipped, and if our clip is still valid, we can just
147 // move our window, and do not need to move or clip
150 QRect vrect = xrect & parent->rect();
151 vrect.translate(-data.crect.topLeft()); //the part of me that's visible through parent, in my Qt coords
152 if (data.wrect.contains(vrect)) {
154 xrect.translate(data.crect.topLeft());
156 data.winid->SetExtent(TPoint(xrect.x(), xrect.y()), TSize(xrect.width(), xrect.height()));
161 if (!validRange.contains(xrect)) {
162 // we are too big, and must clip
165 wrect.translate(-data.crect.topLeft());
166 //parent's X coord system is equal to parent's Qt coord
167 //sys, so we don't need to map xrect.
171 // unmap if we are outside the valid window system coord system
172 bool outsideRange = !xrect.isValid();
173 bool mapWindow = false;
174 if (q->testAttribute(Qt::WA_OutsideWSRange) != outsideRange) {
175 q->setAttribute(Qt::WA_OutsideWSRange, outsideRange);
178 data.winid->DrawableWindow()->SetVisible(EFalse);
179 q->setAttribute(Qt::WA_Mapped, false);
180 } else if (!q->isHidden()) {
188 bool jump = (data.wrect != wrect);
191 // and now recursively for all children...
192 for (int i = 0; i < children.size(); ++i) {
193 QObject *object = children.at(i);
194 if (object->isWidgetType()) {
195 QWidget *w = static_cast<QWidget *>(object);
196 if (!w->isWindow() && w->testAttribute(Qt::WA_WState_Created))
197 w->d_func()->setWSGeometry(jump);
202 // move ourselves to the new position and map (if necessary) after
203 // the movement. Rationale: moving unmapped windows is much faster
204 // than moving mapped windows
205 if (!parent->internalWinId())
206 xrect.translate(parent->mapTo(q->nativeParentWidget(), QPoint(0, 0)));
208 data.winid->SetExtent(TPoint(xrect.x(), xrect.y()), TSize(xrect.width(), xrect.height()));
211 if (mapWindow and !dontShow) {
212 q->setAttribute(Qt::WA_Mapped);
213 if (q->internalWinId())
214 q->internalWinId()->DrawableWindow()->SetVisible(ETrue);
217 if (jump && data.winid) {
218 RWindow *const window = static_cast<RWindow *>(data.winid->DrawableWindow());
219 window->Invalidate(TRect(0, 0, wrect.width(), wrect.height()));
223 void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
227 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
229 if ((q->windowType() == Qt::Desktop))
232 QPoint oldPos(q->pos());
233 QSize oldSize(q->size());
234 QRect oldGeom(data.crect);
236 bool checkExtra = true;
237 if (q->isWindow() && (data.window_state & (Qt::WindowFullScreen | Qt::WindowMaximized))) {
238 // Do not allow fullscreen/maximized windows to expand beyond client rect
239 TRect r = S60->clientRect();
240 w = qMin(w, r.Width());
241 h = qMin(h, r.Height());
243 if (w == r.Width() && h == r.Height())
247 // Lose maximized status if deliberate resize
248 if (w != oldSize.width() || h != oldSize.height())
249 data.window_state &= ~Qt::WindowMaximized;
251 if (checkExtra && extra) { // any size restrictions?
252 w = qMin(w,extra->maxw);
253 h = qMin(h,extra->maxh);
254 w = qMax(w,extra->minw);
255 h = qMax(h,extra->minh);
259 topData()->normalGeometry = QRect(0, 0, -1, -1);
261 uint s = data.window_state;
262 s &= ~(Qt::WindowMaximized | Qt::WindowFullScreen);
263 data.window_state = s;
266 bool isResize = w != oldSize.width() || h != oldSize.height();
267 if (!isMove && !isResize)
271 if (w == 0 || h == 0) {
272 q->setAttribute(Qt::WA_OutsideWSRange, true);
273 if (q->isVisible() && q->testAttribute(Qt::WA_Mapped))
275 data.crect = QRect(x, y, w, h);
276 data.window_state &= ~Qt::WindowFullScreen;
277 } else if (q->isVisible() && q->testAttribute(Qt::WA_OutsideWSRange)) {
278 q->setAttribute(Qt::WA_OutsideWSRange, false);
280 // put the window in its place and show it
281 q->internalWinId()->SetRect(TRect(TPoint(x, y), TSize(w, h)));
282 data.crect.setRect(x, y, w, h);
285 QRect r = QRect(x, y, w, h);
287 q->internalWinId()->SetRect(TRect(TPoint(x, y), TSize(w, h)));
288 topData()->normalGeometry = data.crect;
290 QSymbianControl *window = static_cast<QSymbianControl *>(q->internalWinId());
291 window->ensureFixNativeOrientation();
293 data.crect.setRect(x, y, w, h);
295 QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();
296 const bool inTopLevelResize = tlwExtra ? tlwExtra->inTopLevelResize : false;
298 if (q->isVisible() && (!inTopLevelResize || q->internalWinId())) {
299 // Top-level resize optimization does not work for native child widgets;
300 // disable it for this particular widget.
301 if (inTopLevelResize)
302 tlwExtra->inTopLevelResize = false;
303 if (!isResize && maybeBackingStore())
304 moveRect(QRect(oldPos, oldSize), x - oldPos.x(), y - oldPos.y());
306 invalidateBuffer_resizeHelper(oldPos, oldSize);
308 if (inTopLevelResize)
309 tlwExtra->inTopLevelResize = true;
311 if (q->testAttribute(Qt::WA_WState_Created))
315 if (q->isVisible()) {
316 if (isMove && q->pos() != oldPos) {
317 QMoveEvent e(q->pos(), oldPos);
318 QApplication::sendEvent(q, &e);
321 bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt();
322 const bool setTopLevelResize = !slowResize && q->isWindow() && extra && extra->topextra
323 && !extra->topextra->inTopLevelResize;
324 if (setTopLevelResize)
325 extra->topextra->inTopLevelResize = true;
326 QResizeEvent e(q->size(), oldSize);
327 QApplication::sendEvent(q, &e);
328 if (!q->testAttribute(Qt::WA_StaticContents) && q->internalWinId())
329 q->internalWinId()->DrawDeferred();
330 if (setTopLevelResize)
331 extra->topextra->inTopLevelResize = false;
334 if (isMove && q->pos() != oldPos)
335 q->setAttribute(Qt::WA_PendingMoveEvent, true);
337 q->setAttribute(Qt::WA_PendingResizeEvent, true);
341 void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool destroyOldWindow)
345 Qt::WindowType type = q->windowType();
346 Qt::WindowFlags &flags = data.window_flags;
347 QWidget *parentWidget = q->parentWidget();
349 bool topLevel = (flags & Qt::Window);
350 bool popup = (type == Qt::Popup);
351 bool dialog = (type == Qt::Dialog
353 || (flags & Qt::MSWindowsFixedSizeDialogHint));
354 bool desktop = (type == Qt::Desktop);
355 //bool tool = (type == Qt::Tool || type == Qt::Drawer);
358 flags |= Qt::WindowStaysOnTopHint; // a popup stays on top
360 TRect clientRect = S60->clientRect();
361 int sw = clientRect.Width();
362 int sh = clientRect.Height();
365 symbianScreenNumber = qMax(qt_symbian_create_desktop_on_screen, 0);
366 TSize screenSize = S60->screenDevice(symbianScreenNumber)->SizeInPixels();
367 data.crect.setRect(0, 0, screenSize.iWidth, screenSize.iHeight);
368 q->setAttribute(Qt::WA_DontShowOnScreen);
369 } else if (topLevel && !q->testAttribute(Qt::WA_Resized)){
372 if (symbianScreenNumber > 0) {
373 TSize screenSize = S60->screenDevice(symbianScreenNumber)->SizeInPixels();
374 width = screenSize.iWidth;
375 height = screenSize.iHeight;
378 width = qMax(qMin(width, extra->maxw), extra->minw);
379 height = qMax(qMin(height, extra->maxh), extra->minh);
381 data.crect.setSize(QSize(width, height));
384 CCoeControl *const destroyw = destroyOldWindow ? data.winid : 0;
389 TRect tr = window->Rect();
390 data.crect.setRect(tr.iTl.iX, tr.iTl.iY, tr.Width(), tr.Height());
392 } else if (topLevel) {
393 if (!q->testAttribute(Qt::WA_Moved) && !q->testAttribute(Qt::WA_DontShowOnScreen))
394 data.crect.moveTopLeft(QPoint(clientRect.iTl.iX, clientRect.iTl.iY));
396 QScopedPointer<QSymbianControl> control( new QSymbianControl(q) );
397 Q_CHECK_PTR(control);
399 QT_TRAP_THROWING(control->ConstructL(true, desktop));
400 control->SetMopParent(static_cast<CEikAppUi*>(S60->appUi()));
402 // Symbian windows are always created in an inactive state
403 // We perform this assignment for the case where the window is being re-created
404 // as a result of a call to setParent_sys, on either this widget or one of its
406 extra->activated = 0;
410 if ((q->windowType() & Qt::Popup) == Qt::Popup) {
411 stackingFlags = ECoeStackFlagRefusesAllKeys | ECoeStackFlagRefusesFocus;
413 stackingFlags = ECoeStackFlagStandard;
415 control->MakeVisible(false);
416 QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control.data(), ECoeStackPriorityDefault, stackingFlags));
417 // Avoid keyboard focus to a hidden window.
418 control->setFocusSafely(false);
420 RDrawableWindow *const drawableWindow = control->DrawableWindow();
421 // Request mouse move events.
422 drawableWindow->PointerFilter(EPointerFilterEnterExit
423 | EPointerFilterMove | EPointerFilterDrag, 0);
424 drawableWindow->EnableVisibilityChangeEvents();
428 q->setAttribute(Qt::WA_WState_Created);
431 data.crect.getRect(&x, &y, &w, &h);
432 control->SetRect(TRect(TPoint(x, y), TSize(w, h)));
434 // We wait until the control is fully constructed before calling setWinId, because
435 // this generates a WinIdChanged event.
436 setWinId(control.take());
439 s60UpdateIsOpaque(); // must be called after setWinId()
441 } else if (q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) { // create native child widget
443 QScopedPointer<QSymbianControl> control( new QSymbianControl(q) );
444 Q_CHECK_PTR(control);
446 QT_TRAP_THROWING(control->ConstructL(!parentWidget));
448 // Symbian windows are always created in an inactive state
449 // We perform this assignment for the case where the window is being re-created
450 // as a result of a call to setParent_sys, on either this widget or one of its
452 extra->activated = 0;
455 if ((q->windowType() & Qt::Popup) == Qt::Popup) {
456 stackingFlags = ECoeStackFlagRefusesAllKeys | ECoeStackFlagRefusesFocus;
458 stackingFlags = ECoeStackFlagStandard;
460 control->MakeVisible(false);
461 QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control.data(), ECoeStackPriorityDefault, stackingFlags));
462 // Avoid keyboard focus to a hidden window.
463 control->setFocusSafely(false);
465 q->setAttribute(Qt::WA_WState_Created);
467 data.crect.getRect(&x, &y, &w, &h);
468 control->SetRect(TRect(TPoint(x, y), TSize(w, h)));
470 RDrawableWindow *const drawableWindow = control->DrawableWindow();
471 // Request mouse move events.
472 drawableWindow->PointerFilter(EPointerFilterEnterExit
473 | EPointerFilterMove | EPointerFilterDrag, 0);
474 drawableWindow->EnableVisibilityChangeEvents();
476 if (q->isVisible() && q->testAttribute(Qt::WA_Mapped)) {
477 activateSymbianWindow(control.data());
478 control->MakeVisible(true);
481 // We wait until the control is fully constructed before calling setWinId, because
482 // this generates a WinIdChanged event.
483 setWinId(control.take());
487 destroyw->ControlEnv()->AppUi()->RemoveFromStack(destroyw);
489 // Delay deletion of the control in case this function is called in the
490 // context of a CONE event handler such as
491 // CCoeControl::ProcessPointerEventL
492 widCleanupList << destroyw;
493 QMetaObject::invokeMethod(q, "_q_cleanupWinIds", Qt::QueuedConnection);
496 if (q->testAttribute(Qt::WA_AcceptTouchEvents))
497 registerTouchWindow();
501 void QWidgetPrivate::show_sys()
505 if (q->testAttribute(Qt::WA_OutsideWSRange))
508 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
510 q->setAttribute(Qt::WA_Mapped);
512 if (q->testAttribute(Qt::WA_DontShowOnScreen)) {
513 invalidateBuffer(q->rect());
517 if (q->internalWinId()) {
518 if (!extra->activated)
519 activateSymbianWindow();
521 QSymbianControl *id = static_cast<QSymbianControl *>(q->internalWinId());
522 const bool isFullscreen = q->windowState() & Qt::WindowFullScreen;
523 const TBool cbaRequested = q->windowFlags() & Qt::WindowSoftkeysVisibleHint;
526 // Lazily initialize the S60 screen furniture when the first window is shown.
527 if (q->isWindow() && !QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes)
528 && !S60->buttonGroupContainer() && !S60->statusPane()) {
530 if (!q->testAttribute(Qt::WA_DontShowOnScreen)) {
532 // Create the status pane and CBA here
533 CEikAppUi *ui = static_cast<CEikAppUi *>(S60->appUi());
534 MEikAppUiFactory *factory = CEikonEnv::Static()->AppUiFactory();
537 factory->CreateResourceIndependentFurnitureL(ui);
539 CEikButtonGroupContainer *cba = CEikButtonGroupContainer::NewL(CEikButtonGroupContainer::ECba,
540 CEikButtonGroupContainer::EHorizontal,ui,R_AVKON_SOFTKEYS_EMPTY_WITH_IDS);
541 if (isFullscreen && !cbaRequested)
542 cba->MakeVisible(false);
544 CEikButtonGroupContainer *oldCba = factory->SwapButtonGroup(cba);
546 S60->setButtonGroupContainer(cba);
548 // If the creation of the first widget is delayed, for example by doing it
549 // inside the event loop, S60 somehow "forgets" to set the visibility of the
550 // toolbar (the three middle softkeys) when you flip the phone over, so we
551 // need to do it ourselves to avoid a "hole" in the application, even though
552 // Qt itself does not use the toolbar directly..
553 CAknAppUi *appui = dynamic_cast<CAknAppUi *>(CEikonEnv::Static()->AppUi());
555 CAknToolbar *toolbar = appui->PopupToolbar();
556 if (toolbar && !toolbar->IsVisible())
557 toolbar->SetToolbarVisibility(ETrue);
560 CEikMenuBar *menuBar = new(ELeave) CEikMenuBar;
561 menuBar->ConstructL(ui, 0, R_AVKON_MENUPANE_EMPTY);
562 menuBar->SetMenuType(CEikMenuBar::EMenuOptions);
563 S60->appUi()->AddToStackL(menuBar,ECoeStackPriorityMenu,ECoeStackFlagRefusesFocus);
565 CEikMenuBar *oldMenu = factory->SwapMenuBar(menuBar);
569 if (S60->statusPane()) {
570 // Use QDesktopWidget as the status pane observer to proxy for the AppUi.
571 // Can't use AppUi directly because it privately inherits from MEikStatusPaneObserver.
572 QSymbianControl *desktopControl = static_cast<QSymbianControl *>(QApplication::desktop()->winId());
573 S60->statusPane()->SetObserver(desktopControl);
575 const bool cbaVisible = S60->buttonGroupContainer() && S60->buttonGroupContainer()->IsVisible();
576 S60->setStatusPaneAndButtonGroupVisibility(false, cbaVisible);
578 // Fix window dimensions as without screen furniture they will have
579 // defaulted to full screen dimensions initially.
580 id->handleClientAreaChange();
588 // Fill client area if maximized OR
589 // Put window below status pane unless the window has an explicit position.
591 // Use QS60Data::clientRect to take into account that native keyboard
592 // might affect ClientRect() return value.
593 if (q->windowState() & Qt::WindowMaximized) {
594 TRect r = S60->clientRect();
595 id->SetExtent(r.iTl, r.Size());
596 } else if (!q->testAttribute(Qt::WA_Moved) && q->windowType() != Qt::Dialog) {
597 id->SetPosition(S60->clientRect().iTl);
601 id->MakeVisible(true);
603 if(q->isWindow()&&!q->testAttribute(Qt::WA_ShowWithoutActivating))
604 id->setFocusSafely(true);
607 invalidateBuffer(q->rect());
610 void QWidgetPrivate::activateSymbianWindow(WId wid)
614 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
615 Q_ASSERT(q->testAttribute(Qt::WA_Mapped));
616 Q_ASSERT(!extra->activated);
619 wid = q->internalWinId();
623 QT_TRAP_THROWING(wid->ActivateL());
624 extra->activated = 1;
627 void QWidgetPrivate::hide_sys()
631 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
632 deactivateWidgetCleanup();
633 QSymbianControl *id = static_cast<QSymbianControl *>(q->internalWinId());
636 //Incorrect optimization - for popup windows, Qt's focus is moved before
637 //hide_sys is called, resulting in the popup window keeping its elevated
638 //position in the CONE control stack.
639 //This can result in keyboard focus being in an invisible widget in some
640 //conditions - e.g. QTBUG-4733
641 //if(id->IsFocused()) // Avoid unnecessary calls to FocusChanged()
642 id->setFocusSafely(false);
643 id->MakeVisible(false);
644 if (QWidgetBackingStore *bs = maybeBackingStore())
647 invalidateBuffer(q->rect());
650 q->setAttribute(Qt::WA_Mapped, false);
653 void QWidgetPrivate::setFocus_sys()
656 if (q->testAttribute(Qt::WA_WState_Created) && q->window()->windowType() != Qt::Popup)
657 if (!q->effectiveWinId()->IsFocused()) // Avoid unnecessry calls to FocusChanged()
658 static_cast<QSymbianControl *>(q->effectiveWinId())->setFocusSafely(true);
661 void QWidgetPrivate::raise_sys()
665 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
666 if (q->internalWinId()) {
667 q->internalWinId()->DrawableWindow()->SetOrdinalPosition(0);
669 // If toplevel widget, raise app to foreground
671 S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup(q).Identifier(), 0);
675 void QWidgetPrivate::lower_sys()
679 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
680 if (q->internalWinId()) {
681 // If toplevel widget, lower app to background
683 S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup(q).Identifier(), -1);
685 q->internalWinId()->DrawableWindow()->SetOrdinalPosition(-1);
689 invalidateBuffer(q->rect());
692 void QWidgetPrivate::setModal_sys()
697 void QWidgetPrivate::stackUnder_sys(QWidget* w)
700 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
702 if (q->internalWinId() && w->internalWinId()) {
703 RDrawableWindow *const thisWindow = q->internalWinId()->DrawableWindow();
704 RDrawableWindow *const otherWindow = w->internalWinId()->DrawableWindow();
705 thisWindow->SetOrdinalPosition(otherWindow->OrdinalPosition() + 1);
708 if (!q->isWindow() || !w->internalWinId())
709 invalidateBuffer(q->rect());
712 void QWidgetPrivate::reparentChildren()
716 QObjectList chlist = q->children();
717 for (int i = 0; i < chlist.size(); ++i) { // reparent children
718 QObject *obj = chlist.at(i);
719 if (obj->isWidgetType()) {
720 QWidget *w = (QWidget *)obj;
721 if (!w->testAttribute(Qt::WA_WState_Created))
723 if (!w->isWindow()) {
724 w->d_func()->invalidateBuffer(w->rect());
725 WId parent = q->effectiveWinId();
726 WId child = w->effectiveWinId();
727 if (parent != child) {
728 // Child widget is native. Because Symbian windows cannot be
729 // re-parented, we must re-create the window.
730 const WId window = 0;
731 const bool initializeWindow = false;
732 const bool destroyOldWindow = true;
733 w->d_func()->create_sys(window, initializeWindow, destroyOldWindow);
735 // ### TODO: We probably also need to update the component array here
736 w->d_func()->reparentChildren();
738 bool showIt = w->isVisible();
739 QPoint old_pos = w->pos();
740 w->setParent(q, w->windowFlags());
749 void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
753 if (parent && parent->windowType() == Qt::Desktop) {
754 symbianScreenNumber = qt_widget_private(parent)->symbianScreenNumber;
758 bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
760 if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
761 q->parentWidget()->d_func()->invalidateBuffer(q->geometry());
763 if (q->testAttribute(Qt::WA_DropSiteRegistered))
764 q->setAttribute(Qt::WA_DropSiteRegistered, false);
766 QSymbianControl *old_winid = static_cast<QSymbianControl *>(wasCreated ? data.winid : 0);
767 if ((q->windowType() == Qt::Desktop))
770 // old_winid may not have received a 'not visible' visibility
771 // changed event before being destroyed; make sure that it is
772 // removed from the backing store's list of visible windows.
774 S60->controlVisibilityChanged(old_winid, false);
778 // hide and reparent our own window away. Otherwise we might get
779 // destroyed when emitting the child remove event below. See QWorkspace.
780 if (wasCreated && old_winid) {
781 old_winid->MakeVisible(false);
782 if (old_winid->IsFocused()) // Avoid unnecessary calls to FocusChanged()
783 old_winid->setFocusSafely(false);
784 old_winid->SetParent(0);
787 QObjectPrivate::setParent_helper(parent);
788 bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide);
790 data.window_flags = f;
791 data.fstrut_dirty = true;
792 q->setAttribute(Qt::WA_WState_Created, false);
793 q->setAttribute(Qt::WA_WState_Visible, false);
794 q->setAttribute(Qt::WA_WState_Hidden, false);
795 adjustFlags(data.window_flags, q);
796 // keep compatibility with previous versions, we need to preserve the created state
797 // (but we recreate the winId for the widget being reparented, again for compatibility)
798 if (wasCreated || (!q->isWindow() && parent && parent->testAttribute(Qt::WA_WState_Created)))
800 if (q->isWindow() || (!parent || parent->isVisible()) || explicitlyHidden)
801 q->setAttribute(Qt::WA_WState_Hidden);
802 q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden);
808 CBase::Delete(old_winid);
811 if (q->testAttribute(Qt::WA_AcceptDrops)
812 || (!q->isWindow() && q->parentWidget() && q->parentWidget()->testAttribute(Qt::WA_DropSiteRegistered)))
813 q->setAttribute(Qt::WA_DropSiteRegistered, true);
815 invalidateBuffer(q->rect());
818 void QWidgetPrivate::setConstraints_sys()
824 void QWidgetPrivate::s60UpdateIsOpaque()
828 if (!q->testAttribute(Qt::WA_WState_Created))
831 const bool writeAlpha = extraData()->nativePaintMode == QWExtra::BlitWriteAlpha;
832 if (!q->testAttribute(Qt::WA_TranslucentBackground) && !writeAlpha)
834 const bool requireAlphaChannel = !isOpaque || writeAlpha;
838 RWindow *const window = static_cast<RWindow *>(q->effectiveWinId()->DrawableWindow());
840 #ifdef Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE
841 if (QApplicationPrivate::instance()->useTranslucentEGLSurfaces
842 && !extra->topextra->forcedToRaster) {
843 window->SetSurfaceTransparency(!isOpaque);
844 extra->topextra->nativeWindowTransparencyEnabled = !isOpaque;
848 if (requireAlphaChannel) {
849 const TDisplayMode displayMode = static_cast<TDisplayMode>(window->SetRequiredDisplayMode(EColor16MA));
850 if (window->SetTransparencyAlphaChannel() == KErrNone) {
851 window->SetBackgroundColor(TRgb(255, 255, 255, 0));
852 extra->topextra->nativeWindowTransparencyEnabled = 1;
853 if (extra->topextra->backingStore.data() && (
854 QApplicationPrivate::graphics_system_name == QLatin1String("openvg")
855 || QApplicationPrivate::graphics_system_name == QLatin1String("opengl"))) {
856 // Semi-transparent EGL surfaces aren't supported. We need to
857 // recreate backing store to get translucent surface (raster surface).
858 extra->topextra->backingStore.create(q);
859 extra->topextra->backingStore.registerWidget(q);
860 // FixNativeOrientation() will not work without an EGL surface.
861 q->setAttribute(Qt::WA_SymbianNoSystemRotation, false);
864 } else if (extra->topextra->nativeWindowTransparencyEnabled) {
865 window->SetTransparentRegion(TRegionFix<1>());
866 extra->topextra->nativeWindowTransparencyEnabled = 0;
870 void QWidgetPrivate::setWindowIcon_sys(bool forceReset)
875 if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow() )
878 QTLWExtra* topData = this->topData();
879 if (topData->iconPixmap && !forceReset)
884 TBool found = AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EContextPane, cPaneRect );
885 CAknContextPane* contextPane = S60->contextPane();
886 if (found && contextPane) { // We have context pane with valid metrics
887 QIcon icon = q->windowIcon();
888 if (!icon.isNull()) {
889 // Valid icon -> set it as an context pane picture
890 QSize size = icon.actualSize(QSize(cPaneRect.Size().iWidth, cPaneRect.Size().iHeight));
891 QPixmap pm = icon.pixmap(size);
892 QBitmap mask = pm.mask();
894 mask = QBitmap(pm.size());
895 mask.fill(Qt::color1);
898 CFbsBitmap* nBitmap = pm.toSymbianCFbsBitmap();
899 CFbsBitmap* nMask = mask.toSymbianCFbsBitmap();
900 contextPane->SetPicture(nBitmap,nMask);
902 // Icon set to null -> set context pane picture to default
903 QT_TRAP_THROWING(contextPane->SetPictureToDefaultL());
906 // Context pane does not exist, try setting small icon to title pane
908 TBool found = AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::ETitlePane, titlePaneRect );
909 CAknTitlePane* titlePane = S60->titlePane();
910 if (found && titlePane) { // We have title pane with valid metrics
911 // The API to get title_pane graphics size is not public -> assume square space based
912 // on titlebar font height. CAknBitmap would be optimum, wihtout setting the size, since
913 // then title pane would automatically scale the bitmap. Unfortunately it is not public API
914 // Also this function is leaving, although it is not named as such.
916 QT_TRAP_THROWING(font = AknLayoutUtils::FontFromId(EAknLogicalFontTitleFont));
917 TSize iconSize(font->HeightInPixels(), font->HeightInPixels());
919 QIcon icon = q->windowIcon();
920 if (!icon.isNull()) {
921 // Valid icon -> set it as an title pane small picture
922 QSize size = icon.actualSize(QSize(iconSize.iWidth, iconSize.iHeight));
923 QPixmap pm = icon.pixmap(size);
924 QBitmap mask = pm.mask();
926 mask = QBitmap(pm.size());
927 mask.fill(Qt::color1);
930 CFbsBitmap* nBitmap = pm.toSymbianCFbsBitmap();
931 CFbsBitmap* nMask = mask.toSymbianCFbsBitmap();
932 titlePane->SetSmallPicture( nBitmap, nMask, ETrue );
934 // Icon set to null -> set context pane picture to default
935 titlePane->SetSmallPicture( NULL, NULL, EFalse );
945 void QWidgetPrivate::setWindowTitle_sys(const QString &caption)
950 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
951 CAknTitlePane* titlePane = S60->titlePane();
953 if (caption.isEmpty()) {
954 QT_TRAP_THROWING(titlePane->SetTextToDefaultL());
956 QT_TRAP_THROWING(titlePane->SetTextL(qt_QString2TPtrC(caption)));
965 void QWidgetPrivate::setWindowIconText_sys(const QString & /*iconText */)
970 void QWidgetPrivate::scroll_sys(int dx, int dy)
974 scrollChildren(dx, dy);
975 if (!paintOnScreen() || !q->internalWinId() || !q->internalWinId()->OwnsWindow()) {
976 scrollRect(q->rect(), dx, dy);
978 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
979 RDrawableWindow *const window = q->internalWinId()->DrawableWindow();
980 window->Scroll(TPoint(dx, dy));
984 void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r)
988 if (!paintOnScreen() || !q->internalWinId() || !q->internalWinId()->OwnsWindow()) {
989 scrollRect(r, dx, dy);
991 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
992 RDrawableWindow *const window = q->internalWinId()->DrawableWindow();
993 window->Scroll(TPoint(dx, dy), qt_QRect2TRect(r));
998 For this function to work in the emulator, you must add:
1000 To a line in the wsini.ini file.
1002 void QWidgetPrivate::setWindowOpacity_sys(qreal)
1004 // ### TODO: Implement uniform window transparency
1007 void QWidgetPrivate::updateFrameStrut()
1012 void QWidgetPrivate::updateSystemBackground()
1017 void QWidgetPrivate::registerDropSite(bool /* on */)
1022 void QWidgetPrivate::createTLSysExtra()
1024 extra->topextra->inExpose = 0;
1025 extra->topextra->nativeWindowTransparencyEnabled = 0;
1026 extra->topextra->forcedToRaster = 0;
1029 void QWidgetPrivate::deleteTLSysExtra()
1031 extra->topextra->backingStore.destroy();
1034 void QWidgetPrivate::createSysExtra()
1036 extra->activated = 0;
1037 extra->nativePaintMode = QWExtra::Default;
1038 extra->receiveNativePaintEvents = 0;
1041 void QWidgetPrivate::deleteSysExtra()
1043 // this should only be non-zero if destroy() has not run due to constructor fail
1045 data.winid->ControlEnv()->AppUi()->RemoveFromStack(data.winid);
1051 QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys()
1053 return new QS60WindowSurface(q_func());
1056 void QWidgetPrivate::setMask_sys(const QRegion& /* region */)
1061 void QWidgetPrivate::registerTouchWindow()
1063 #ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
1065 if (q->testAttribute(Qt::WA_WState_Created) && q->windowType() != Qt::Desktop) {
1066 RWindow *rwindow = static_cast<RWindow *>(q->effectiveWinId()->DrawableWindow());
1067 QSymbianControl *window = static_cast<QSymbianControl *>(q->effectiveWinId());
1068 //Enabling advanced pointer events for controls that already have active windows causes a panic.
1069 if (!window->isControlActive())
1070 rwindow->EnableAdvancedPointers();
1075 int QWidget::metric(PaintDeviceMetric m) const
1079 if (m == PdmWidth) {
1080 val = data->crect.width();
1081 } else if (m == PdmHeight) {
1082 val = data->crect.height();
1084 CWsScreenDevice *scr = S60->screenDevice(this);
1087 case PdmPhysicalDpiX:
1088 if (d->extra && d->extra->customDpiX) {
1089 val = d->extra->customDpiX;
1091 const QWidgetPrivate *p = d;
1093 p = static_cast<const QWidget *>(p->parent)->d_func();
1094 if (p->extra && p->extra->customDpiX) {
1095 val = p->extra->customDpiX;
1099 if (p == d || !(p->extra && p->extra->customDpiX))
1100 val = S60->defaultDpiX;
1104 case PdmPhysicalDpiY:
1105 if (d->extra && d->extra->customDpiY) {
1106 val = d->extra->customDpiY;
1108 const QWidgetPrivate *p = d;
1110 p = static_cast<const QWidget *>(p->parent)->d_func();
1111 if (p->extra && p->extra->customDpiY) {
1112 val = p->extra->customDpiY;
1116 if (p == d || !(p->extra && p->extra->customDpiY))
1117 val = S60->defaultDpiY;
1122 TInt twips = scr->HorizontalPixelsToTwips(data->crect.width());
1123 val = (int)(twips * (25.4/KTwipsPerInch));
1128 TInt twips = scr->VerticalPixelsToTwips(data->crect.height());
1129 val = (int)(twips * (25.4/KTwipsPerInch));
1133 val = TDisplayModeUtils::NumDisplayModeColors(scr->DisplayMode());
1136 val = TDisplayModeUtils::NumDisplayModeBitsPerPixel(scr->DisplayMode());
1140 qWarning("QWidget::metric: Invalid metric command");
1146 QPaintEngine *QWidget::paintEngine() const
1151 QPoint QWidget::mapToGlobal(const QPoint &pos) const
1154 if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
1156 QPoint p = pos + data->crect.topLeft();
1157 return (isWindow() || !parentWidget()) ? p : parentWidget()->mapToGlobal(p);
1159 } else if ((d->data.window_flags & Qt::Window) && internalWinId()) { //toplevel
1160 QPoint tp = geometry().topLeft();
1164 // Native window case
1165 const TPoint widgetScreenOffset = internalWinId()->PositionRelativeToScreen();
1166 const QPoint globalPos = QPoint(widgetScreenOffset.iX, widgetScreenOffset.iY) + pos;
1170 QPoint QWidget::mapFromGlobal(const QPoint &pos) const
1173 if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
1174 QPoint p = (isWindow() || !parentWidget()) ? pos : parentWidget()->mapFromGlobal(pos);
1175 return p - data->crect.topLeft();
1176 } else if ((d->data.window_flags & Qt::Window) && internalWinId()) { //toplevel
1177 QPoint tp = geometry().topLeft();
1181 // Native window case
1182 const TPoint widgetScreenOffset = internalWinId()->PositionRelativeToScreen();
1183 const QPoint widgetPos = pos - QPoint(widgetScreenOffset.iX, widgetScreenOffset.iY);
1187 static Qt::WindowStates effectiveState(Qt::WindowStates state)
1189 if (state & Qt::WindowMinimized)
1190 return Qt::WindowMinimized;
1191 else if (state & Qt::WindowFullScreen)
1192 return Qt::WindowFullScreen;
1193 else if (state & Qt::WindowMaximized)
1194 return Qt::WindowMaximized;
1195 return Qt::WindowNoState;
1198 void QWidget::setWindowState(Qt::WindowStates newstate)
1202 Qt::WindowStates oldstate = windowState();
1204 const TBool isFullscreen = newstate & Qt::WindowFullScreen;
1206 const TBool cbaRequested = windowFlags() & Qt::WindowSoftkeysVisibleHint;
1207 const TBool cbaVisible = CEikButtonGroupContainer::Current() ? true : false;
1208 const TBool softkeyVisibilityChange = isFullscreen && (cbaRequested != cbaVisible);
1210 if (oldstate == newstate && !softkeyVisibilityChange)
1216 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1218 const bool wasResized = testAttribute(Qt::WA_Resized);
1219 const bool wasMoved = testAttribute(Qt::WA_Moved);
1221 QSymbianControl *window = static_cast<QSymbianControl *>(effectiveWinId());
1222 if (window && newstate & Qt::WindowMinimized) {
1223 window->setFocusSafely(false);
1224 window->MakeVisible(false);
1225 } else if (window && oldstate & Qt::WindowMinimized) {
1226 window->setFocusSafely(true);
1227 window->MakeVisible(true);
1231 // The window decoration visibility has to be changed before doing actual window state
1232 // change since in that order the availableGeometry will return directly the right size and
1233 // we will avoid unnecessary redraws
1234 bool decorationsVisible = S60->setRecursiveDecorationsVisibility(this, newstate);
1237 // Ensure the initial size is valid, since we store it as normalGeometry below.
1238 if (!wasResized && !isVisible())
1241 QTLWExtra *top = d->topData();
1242 QRect normalGeometry = (top->normalGeometry.width() < 0) ? geometry() : top->normalGeometry;
1244 const bool cbaVisibilityHint = windowFlags() & Qt::WindowSoftkeysVisibleHint;
1245 if (newstate & Qt::WindowFullScreen && !cbaVisibilityHint) {
1246 setAttribute(Qt::WA_OutsideWSRange, false);
1247 if (d->symbianScreenNumber > 0) {
1248 int w = S60->screenWidthInPixelsForScreen[d->symbianScreenNumber];
1249 int h = S60->screenHeightInPixelsForScreen[d->symbianScreenNumber];
1250 if (w <= 0 || h <= 0)
1251 window->SetExtentToWholeScreen();
1253 window->SetExtent(TPoint(0, 0), TSize(w, h));
1255 window->SetExtentToWholeScreen();
1257 } else if (newstate & Qt::WindowMaximized || ((newstate & Qt::WindowFullScreen) && cbaVisibilityHint)) {
1258 setAttribute(Qt::WA_OutsideWSRange, false);
1259 TRect maxExtent = qt_QRect2TRect(qApp->desktop()->availableGeometry(this));
1260 window->SetExtent(maxExtent.iTl, maxExtent.Size());
1263 // With delayed creation of S60 app panes, the normalGeometry calculated above is not
1264 // accurate because it did not consider the status pane. This means that when returning
1265 // normal mode after showing the status pane, the geometry would overlap so we should
1266 // move it if it never had an explicit position.
1267 if (!wasMoved && S60->statusPane() && decorationsVisible) {
1268 TPoint tl = S60->clientRect().iTl;
1269 normalGeometry.setTopLeft(QPoint(tl.iX, tl.iY));
1272 setGeometry(normalGeometry);
1275 //restore normal geometry
1276 top->normalGeometry = normalGeometry;
1279 // In some platforms, WA_Resized and WA_Moved are also not set when application window state is
1280 // anything else than normal. In Symbian we can restore them only for normal window state since
1281 // restoring for other modes, will make fluidlauncher to be launched in wrong size (200x100)
1282 if (effectiveState(newstate) == Qt::WindowNoState) {
1283 setAttribute(Qt::WA_Resized, wasResized);
1284 setAttribute(Qt::WA_Moved, wasMoved);
1288 data->window_state = newstate;
1290 if (newstate & Qt::WindowActive)
1294 // Now that the new state is set, fix the display memory layout, if needed.
1295 QSymbianControl *window = static_cast<QSymbianControl *>(effectiveWinId());
1296 window->ensureFixNativeOrientation();
1299 QWindowStateChangeEvent e(oldstate);
1300 QApplication::sendEvent(this, &e);
1304 void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
1307 d->aboutToDestroy();
1308 if (!isWindow() && parentWidget())
1309 parentWidget()->d_func()->invalidateBuffer(geometry());
1310 d->deactivateWidgetCleanup();
1311 QSymbianControl *id = static_cast<QSymbianControl *>(internalWinId());
1312 if (testAttribute(Qt::WA_WState_Created)) {
1318 QInputContext *ic = QApplicationPrivate::inputContext;
1320 ic->widgetDestroyed(this);
1325 if (QWidgetPrivate::mouseGrabber == this)
1327 if (QWidgetPrivate::keyboardGrabber == this)
1329 setAttribute(Qt::WA_WState_Created, false);
1330 QObjectList childList = children();
1331 for (int i = 0; i < childList.size(); ++i) { // destroy all widget children
1332 register QObject *obj = childList.at(i);
1333 if (obj->isWidgetType())
1334 static_cast<QWidget*>(obj)->destroy(destroySubWindows,
1337 if (destroyWindow && !(windowType() == Qt::Desktop) && id) {
1338 if (id->IsFocused()) // Avoid unnecessry calls to FocusChanged()
1339 id->setFocusSafely(false);
1340 id->ControlEnv()->AppUi()->RemoveFromStack(id);
1346 } QT_CATCH (const std::bad_alloc &) {
1347 // swallow - destructors must not throw
1350 if (destroyWindow) {
1352 // At this point the backing store should already be destroyed
1353 // so we flush the command buffer to ensure that the freeing of
1354 // those resources and deleting the window can happen "atomically"
1356 S60->wsSession().Flush();
1360 QWidget *QWidget::mouseGrabber()
1362 return QWidgetPrivate::mouseGrabber;
1365 QWidget *QWidget::keyboardGrabber()
1367 return QWidgetPrivate::keyboardGrabber;
1370 void QWidget::grabKeyboard()
1373 if (QWidgetPrivate::keyboardGrabber && QWidgetPrivate::keyboardGrabber != this)
1374 QWidgetPrivate::keyboardGrabber->releaseKeyboard();
1376 // ### TODO: Native keyboard grab
1378 QWidgetPrivate::keyboardGrabber = this;
1382 void QWidget::releaseKeyboard()
1384 if (!qt_nograb() && QWidgetPrivate::keyboardGrabber == this) {
1385 // ### TODO: Native keyboard release
1386 QWidgetPrivate::keyboardGrabber = 0;
1390 void QWidget::grabMouse()
1392 if (isVisible() && !qt_nograb()) {
1393 if (QWidgetPrivate::mouseGrabber && QWidgetPrivate::mouseGrabber != this)
1394 QWidgetPrivate::mouseGrabber->releaseMouse();
1395 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1396 WId id = effectiveWinId();
1397 id->SetPointerCapture(true);
1398 QWidgetPrivate::mouseGrabber = this;
1400 #ifndef QT_NO_CURSOR
1401 QApplication::setOverrideCursor(cursor());
1406 #ifndef QT_NO_CURSOR
1407 void QWidget::grabMouse(const QCursor &cursor)
1409 if (isVisible() && !qt_nograb()) {
1410 if (QWidgetPrivate::mouseGrabber && QWidgetPrivate::mouseGrabber != this)
1411 QWidgetPrivate::mouseGrabber->releaseMouse();
1412 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1413 WId id = effectiveWinId();
1414 id->SetPointerCapture(true);
1415 QWidgetPrivate::mouseGrabber = this;
1417 QApplication::setOverrideCursor(cursor);
1422 void QWidget::releaseMouse()
1424 if (!qt_nograb() && QWidgetPrivate::mouseGrabber == this) {
1425 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1426 if(!window()->isModal()) {
1427 WId id = effectiveWinId();
1428 id->SetPointerCapture(false);
1430 QWidgetPrivate::mouseGrabber = 0;
1431 #ifndef QT_NO_CURSOR
1432 QApplication::restoreOverrideCursor();
1437 void QWidget::activateWindow()
1441 QWidget *tlw = window();
1442 if (tlw->isVisible()) {
1443 window()->createWinId();
1444 QSymbianControl *id = static_cast<QSymbianControl *>(tlw->internalWinId());
1445 if (!id->IsFocused())
1446 id->setFocusSafely(true);
1450 #ifndef QT_NO_CURSOR
1452 void QWidgetPrivate::setCursor_sys(const QCursor &cursor)
1456 qt_symbian_set_cursor(q, false);
1459 void QWidgetPrivate::unsetCursor_sys()
1462 qt_symbian_set_cursor(q, false);