source: trunk/src/gui/kernel/qwidget_s60.cpp@ 750

Last change on this file since 750 was 651, checked in by Dmitry A. Kuminov, 16 years ago

trunk: Merged in qt 4.6.2 sources.

  • Property svn:eol-style set to native
File size: 41.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
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.
23**
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.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qwidget_p.h"
43#include "qdesktopwidget.h"
44#include "qapplication.h"
45#include "qapplication_p.h"
46#include "private/qbackingstore_p.h"
47#include "qevent.h"
48#include "qt_s60_p.h"
49
50#include "qbitmap.h"
51#include "private/qwindowsurface_s60_p.h"
52
53#include <qinputcontext.h>
54
55#ifdef Q_WS_S60
56#include <aknappui.h>
57#endif
58
59// This is necessary in order to be able to perform delayed invokation on slots
60// which take arguments of type WId. One example is
61// QWidgetPrivate::_q_delayedDestroy, which is used to delay destruction of
62// CCoeControl objects until after the CONE event handler has finished running.
63Q_DECLARE_METATYPE(WId)
64
65QT_BEGIN_NAMESPACE
66
67extern bool qt_nograb();
68
69QWidget *QWidgetPrivate::mouseGrabber = 0;
70QWidget *QWidgetPrivate::keyboardGrabber = 0;
71
72static bool isEqual(const QList<QAction*>& a, const QList<QAction*>& b)
73{
74 if ( a.count() != b.count())
75 return false;
76 int index=0;
77 while (index<a.count()) {
78 if (a.at(index)->softKeyRole() != b.at(index)->softKeyRole())
79 return false;
80 if (a.at(index)->text().compare(b.at(index)->text())!=0)
81 return false;
82 index++;
83 }
84 return true;
85}
86
87void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &)
88{
89 // Note: based on x11 implementation
90
91 static const int XCOORD_MAX = 16383;
92 static const int WRECT_MAX = 16383;
93
94 Q_Q(QWidget);
95
96 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
97
98 /*
99 There are up to four different coordinate systems here:
100 Qt coordinate system for this widget.
101 Symbian coordinate system for this widget (relative to wrect).
102 Qt coordinate system for parent
103 Symbian coordinate system for parent (relative to parent's wrect).
104 */
105
106 QRect validRange(-XCOORD_MAX,-XCOORD_MAX, 2*XCOORD_MAX, 2*XCOORD_MAX);
107 QRect wrectRange(-WRECT_MAX,-WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX);
108 QRect wrect;
109 //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)
110 QRect xrect = data.crect;
111
112 const QWidget *const parent = q->parentWidget();
113 QRect parentWRect = parent->data->wrect;
114
115 if (parentWRect.isValid()) {
116 // parent is clipped, and we have to clip to the same limit as parent
117 if (!parentWRect.contains(xrect)) {
118 xrect &= parentWRect;
119 wrect = xrect;
120 //translate from parent's to my Qt coord sys
121 wrect.translate(-data.crect.topLeft());
122 }
123 //translate from parent's Qt coords to parent's X coords
124 xrect.translate(-parentWRect.topLeft());
125
126 } else {
127 // parent is not clipped, we may or may not have to clip
128
129 if (data.wrect.isValid() && QRect(QPoint(),data.crect.size()).contains(data.wrect)) {
130 // This is where the main optimization is: we are already
131 // clipped, and if our clip is still valid, we can just
132 // move our window, and do not need to move or clip
133 // children
134
135 QRect vrect = xrect & parent->rect();
136 vrect.translate(-data.crect.topLeft()); //the part of me that's visible through parent, in my Qt coords
137 if (data.wrect.contains(vrect)) {
138 xrect = data.wrect;
139 xrect.translate(data.crect.topLeft());
140 if (data.winid)
141 data.winid->SetExtent(TPoint(xrect.x(), xrect.y()), TSize(xrect.width(), xrect.height()));
142 return;
143 }
144 }
145
146 if (!validRange.contains(xrect)) {
147 // we are too big, and must clip
148 xrect &=wrectRange;
149 wrect = xrect;
150 wrect.translate(-data.crect.topLeft());
151 //parent's X coord system is equal to parent's Qt coord
152 //sys, so we don't need to map xrect.
153 }
154 }
155
156 // unmap if we are outside the valid window system coord system
157 bool outsideRange = !xrect.isValid();
158 bool mapWindow = false;
159 if (q->testAttribute(Qt::WA_OutsideWSRange) != outsideRange) {
160 q->setAttribute(Qt::WA_OutsideWSRange, outsideRange);
161 if (outsideRange) {
162 if (data.winid)
163 data.winid->DrawableWindow()->SetVisible(EFalse);
164 q->setAttribute(Qt::WA_Mapped, false);
165 } else if (!q->isHidden()) {
166 mapWindow = true;
167 }
168 }
169
170 if (outsideRange)
171 return;
172
173 bool jump = (data.wrect != wrect);
174 data.wrect = wrect;
175
176 // and now recursively for all children...
177 for (int i = 0; i < children.size(); ++i) {
178 QObject *object = children.at(i);
179 if (object->isWidgetType()) {
180 QWidget *w = static_cast<QWidget *>(object);
181 if (!w->isWindow() && w->testAttribute(Qt::WA_WState_Created))
182 w->d_func()->setWSGeometry(jump);
183 }
184 }
185
186 if (data.winid) {
187 // move ourselves to the new position and map (if necessary) after
188 // the movement. Rationale: moving unmapped windows is much faster
189 // than moving mapped windows
190 if (!parent->internalWinId())
191 xrect.translate(parent->mapTo(q->nativeParentWidget(), QPoint(0, 0)));
192
193 data.winid->SetExtent(TPoint(xrect.x(), xrect.y()), TSize(xrect.width(), xrect.height()));
194 }
195
196 if (mapWindow and !dontShow) {
197 q->setAttribute(Qt::WA_Mapped);
198 if (q->internalWinId())
199 q->internalWinId()->DrawableWindow()->SetVisible(ETrue);
200 }
201
202 if (jump && data.winid) {
203 RWindow *const window = static_cast<RWindow *>(data.winid->DrawableWindow());
204 window->Invalidate(TRect(0, 0, wrect.width(), wrect.height()));
205 }
206}
207
208void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
209{
210 Q_Q(QWidget);
211
212 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
213
214 if ((q->windowType() == Qt::Desktop))
215 return;
216
217 QPoint oldPos(q->pos());
218 QSize oldSize(q->size());
219 QRect oldGeom(data.crect);
220
221 // Lose maximized status if deliberate resize
222 if (w != oldSize.width() || h != oldSize.height())
223 data.window_state &= ~Qt::WindowMaximized;
224
225 if (extra) { // any size restrictions?
226 w = qMin(w,extra->maxw);
227 h = qMin(h,extra->maxh);
228 w = qMax(w,extra->minw);
229 h = qMax(h,extra->minh);
230 }
231
232 if (q->isWindow())
233 topData()->normalGeometry = QRect(0, 0, -1, -1);
234 else {
235 uint s = data.window_state;
236 s &= ~(Qt::WindowMaximized | Qt::WindowFullScreen);
237 data.window_state = s;
238 }
239
240 bool isResize = w != oldSize.width() || h != oldSize.height();
241 if (!isMove && !isResize)
242 return;
243
244 if (q->isWindow()) {
245 if (w == 0 || h == 0) {
246 q->setAttribute(Qt::WA_OutsideWSRange, true);
247 if (q->isVisible() && q->testAttribute(Qt::WA_Mapped))
248 hide_sys();
249 data.crect = QRect(x, y, w, h);
250 data.window_state &= ~Qt::WindowFullScreen;
251 } else if (q->isVisible() && q->testAttribute(Qt::WA_OutsideWSRange)) {
252 q->setAttribute(Qt::WA_OutsideWSRange, false);
253
254 // put the window in its place and show it
255 q->internalWinId()->SetRect(TRect(TPoint(x, y), TSize(w, h)));
256 data.crect.setRect(x, y, w, h);
257 show_sys();
258 } else {
259 QRect r = QRect(x, y, w, h);
260 data.crect = r;
261 q->internalWinId()->SetRect(TRect(TPoint(x, y), TSize(w, h)));
262 topData()->normalGeometry = data.crect;
263 }
264 } else {
265 data.crect.setRect(x, y, w, h);
266
267 QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();
268 const bool inTopLevelResize = tlwExtra ? tlwExtra->inTopLevelResize : false;
269
270 if (q->isVisible() && (!inTopLevelResize || q->internalWinId())) {
271 // Top-level resize optimization does not work for native child widgets;
272 // disable it for this particular widget.
273 if (inTopLevelResize)
274 tlwExtra->inTopLevelResize = false;
275 if (!isResize && maybeBackingStore())
276 moveRect(QRect(oldPos, oldSize), x - oldPos.x(), y - oldPos.y());
277 else
278 invalidateBuffer_resizeHelper(oldPos, oldSize);
279
280 if (inTopLevelResize)
281 tlwExtra->inTopLevelResize = true;
282 }
283 if (q->testAttribute(Qt::WA_WState_Created))
284 setWSGeometry();
285 }
286
287 if (q->isVisible()) {
288 if (isMove && q->pos() != oldPos) {
289 QMoveEvent e(q->pos(), oldPos);
290 QApplication::sendEvent(q, &e);
291 }
292 if (isResize) {
293 bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt();
294 const bool setTopLevelResize = !slowResize && q->isWindow() && extra && extra->topextra
295 && !extra->topextra->inTopLevelResize;
296 if (setTopLevelResize)
297 extra->topextra->inTopLevelResize = true;
298 QResizeEvent e(q->size(), oldSize);
299 QApplication::sendEvent(q, &e);
300 if (!q->testAttribute(Qt::WA_StaticContents) && q->internalWinId())
301 q->internalWinId()->DrawDeferred();
302 if (setTopLevelResize)
303 extra->topextra->inTopLevelResize = false;
304 }
305 } else {
306 if (isMove && q->pos() != oldPos)
307 q->setAttribute(Qt::WA_PendingMoveEvent, true);
308 if (isResize)
309 q->setAttribute(Qt::WA_PendingResizeEvent, true);
310 }
311}
312
313void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool destroyOldWindow)
314{
315 Q_Q(QWidget);
316
317 Qt::WindowType type = q->windowType();
318 Qt::WindowFlags &flags = data.window_flags;
319 QWidget *parentWidget = q->parentWidget();
320
321 bool topLevel = (flags & Qt::Window);
322 bool popup = (type == Qt::Popup);
323 bool dialog = (type == Qt::Dialog
324 || type == Qt::Sheet
325 || (flags & Qt::MSWindowsFixedSizeDialogHint));
326 bool desktop = (type == Qt::Desktop);
327 //bool tool = (type == Qt::Tool || type == Qt::Drawer);
328
329 if (popup)
330 flags |= Qt::WindowStaysOnTopHint; // a popup stays on top
331
332 TRect clientRect = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
333 int sw = clientRect.Width();
334 int sh = clientRect.Height();
335
336 if (desktop) {
337 TSize screenSize = S60->screenDevice()->SizeInPixels();
338 data.crect.setRect(0, 0, screenSize.iWidth, screenSize.iHeight);
339 q->setAttribute(Qt::WA_DontShowOnScreen);
340 } else if (topLevel && !q->testAttribute(Qt::WA_Resized)){
341 int width = sw;
342 int height = sh;
343 if (extra) {
344 width = qMax(qMin(width, extra->maxw), extra->minw);
345 height = qMax(qMin(height, extra->maxh), extra->minh);
346 }
347 data.crect.setSize(QSize(width, height));
348 }
349
350 CCoeControl *const destroyw = destroyOldWindow ? data.winid : 0;
351
352 createExtra();
353 if (window) {
354 setWinId(window);
355 TRect tr = window->Rect();
356 data.crect.setRect(tr.iTl.iX, tr.iTl.iY, tr.Width(), tr.Height());
357
358 } else if (topLevel) {
359 if (!q->testAttribute(Qt::WA_Moved) && !q->testAttribute(Qt::WA_DontShowOnScreen))
360 data.crect.moveTopLeft(QPoint(clientRect.iTl.iX, clientRect.iTl.iY));
361
362 QScopedPointer<QSymbianControl> control( q_check_ptr(new QSymbianControl(q)) );
363 QT_TRAP_THROWING(control->ConstructL(true, desktop));
364 control->SetMopParent(static_cast<CEikAppUi*>(S60->appUi()));
365
366 // Symbian windows are always created in an inactive state
367 // We perform this assignment for the case where the window is being re-created
368 // as aa result of a call to setParent_sys, on either this widget or one of its
369 // ancestors.
370 extra->activated = 0;
371
372 if (!desktop) {
373 TInt stackingFlags;
374 if ((q->windowType() & Qt::Popup) == Qt::Popup) {
375 stackingFlags = ECoeStackFlagRefusesAllKeys | ECoeStackFlagRefusesFocus;
376 } else {
377 stackingFlags = ECoeStackFlagStandard;
378 }
379 control->MakeVisible(false);
380 QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control.data(), ECoeStackPriorityDefault, stackingFlags));
381 // Avoid keyboard focus to a hidden window.
382 control->setFocusSafely(false);
383
384 RDrawableWindow *const drawableWindow = control->DrawableWindow();
385 // Request mouse move events.
386 drawableWindow->PointerFilter(EPointerFilterEnterExit
387 | EPointerFilterMove | EPointerFilterDrag, 0);
388 drawableWindow->EnableVisibilityChangeEvents();
389
390 if (!isOpaque) {
391 RWindow *const window = static_cast<RWindow *>(drawableWindow);
392#ifdef Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE
393 window->SetSurfaceTransparency(true);
394#else
395 const TDisplayMode displayMode = static_cast<TDisplayMode>(window->SetRequiredDisplayMode(EColor16MA));
396 if (window->SetTransparencyAlphaChannel() == KErrNone)
397 window->SetBackgroundColor(TRgb(255, 255, 255, 0));
398#endif
399 }
400 }
401
402 q->setAttribute(Qt::WA_WState_Created);
403
404 int x, y, w, h;
405 data.crect.getRect(&x, &y, &w, &h);
406 control->SetRect(TRect(TPoint(x, y), TSize(w, h)));
407
408 // We wait until the control is fully constructed before calling setWinId, because
409 // this generates a WinIdChanged event.
410 setWinId(control.take());
411
412 } else if (q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) { // create native child widget
413
414 QScopedPointer<QSymbianControl> control( q_check_ptr(new QSymbianControl(q)) );
415 QT_TRAP_THROWING(control->ConstructL(!parentWidget));
416
417 // Symbian windows are always created in an inactive state
418 // We perform this assignment for the case where the window is being re-created
419 // as aa result of a call to setParent_sys, on either this widget or one of its
420 // ancestors.
421 extra->activated = 0;
422
423 TInt stackingFlags;
424 if ((q->windowType() & Qt::Popup) == Qt::Popup) {
425 stackingFlags = ECoeStackFlagRefusesAllKeys | ECoeStackFlagRefusesFocus;
426 } else {
427 stackingFlags = ECoeStackFlagStandard;
428 }
429 control->MakeVisible(false);
430 QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control.data(), ECoeStackPriorityDefault, stackingFlags));
431 // Avoid keyboard focus to a hidden window.
432 control->setFocusSafely(false);
433
434 q->setAttribute(Qt::WA_WState_Created);
435 int x, y, w, h;
436 data.crect.getRect(&x, &y, &w, &h);
437 control->SetRect(TRect(TPoint(x, y), TSize(w, h)));
438
439 RDrawableWindow *const drawableWindow = control->DrawableWindow();
440 // Request mouse move events.
441 drawableWindow->PointerFilter(EPointerFilterEnterExit
442 | EPointerFilterMove | EPointerFilterDrag, 0);
443
444 if (q->isVisible() && q->testAttribute(Qt::WA_Mapped)) {
445 activateSymbianWindow(control.data());
446 control->MakeVisible(true);
447 }
448
449 // We wait until the control is fully constructed before calling setWinId, because
450 // this generates a WinIdChanged event.
451 setWinId(control.take());
452 }
453
454 if (destroyw) {
455 destroyw->ControlEnv()->AppUi()->RemoveFromStack(destroyw);
456
457 // Delay deletion of the control in case this function is called in the
458 // context of a CONE event handler such as
459 // CCoeControl::ProcessPointerEventL
460 QMetaObject::invokeMethod(q, "_q_delayedDestroy",
461 Qt::QueuedConnection, Q_ARG(WId, destroyw));
462 }
463
464 if (q->testAttribute(Qt::WA_AcceptTouchEvents))
465 registerTouchWindow();
466}
467
468
469void QWidgetPrivate::show_sys()
470{
471 Q_Q(QWidget);
472
473 if (q->testAttribute(Qt::WA_OutsideWSRange))
474 return;
475
476 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
477
478 q->setAttribute(Qt::WA_Mapped);
479
480 if (q->testAttribute(Qt::WA_DontShowOnScreen)) {
481 invalidateBuffer(q->rect());
482 return;
483 }
484
485 if (q->internalWinId()) {
486 if (!extra->activated)
487 activateSymbianWindow();
488
489 QSymbianControl *id = static_cast<QSymbianControl *>(q->internalWinId());
490
491 id->MakeVisible(true);
492
493 if(q->isWindow())
494 id->setFocusSafely(true);
495 }
496
497 invalidateBuffer(q->rect());
498}
499
500void QWidgetPrivate::activateSymbianWindow(WId wid)
501{
502 Q_Q(QWidget);
503
504 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
505 Q_ASSERT(q->testAttribute(Qt::WA_Mapped));
506 Q_ASSERT(!extra->activated);
507
508 if(!wid)
509 wid = q->internalWinId();
510
511 Q_ASSERT(wid);
512
513 QT_TRAP_THROWING(wid->ActivateL());
514 extra->activated = 1;
515}
516
517void QWidgetPrivate::hide_sys()
518{
519 Q_Q(QWidget);
520
521 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
522 deactivateWidgetCleanup();
523 QSymbianControl *id = static_cast<QSymbianControl *>(q->internalWinId());
524
525 if (id) {
526 //Incorrect optimisation - for popup windows, Qt's focus is moved before
527 //hide_sys is called, resulting in the popup window keeping its elevated
528 //position in the CONE control stack.
529 //This can result in keyboard focus being in an invisible widget in some
530 //conditions - e.g. QTBUG-4733
531 //if(id->IsFocused()) // Avoid unnecessary calls to FocusChanged()
532 id->setFocusSafely(false);
533 id->MakeVisible(false);
534 if (QWidgetBackingStore *bs = maybeBackingStore())
535 bs->releaseBuffer();
536 } else {
537 invalidateBuffer(q->rect());
538 }
539
540 q->setAttribute(Qt::WA_Mapped, false);
541}
542
543void QWidgetPrivate::setFocus_sys()
544{
545 Q_Q(QWidget);
546 if (q->testAttribute(Qt::WA_WState_Created) && q->window()->windowType() != Qt::Popup)
547 if (!q->effectiveWinId()->IsFocused()) // Avoid unnecessry calls to FocusChanged()
548 static_cast<QSymbianControl *>(q->effectiveWinId())->setFocusSafely(true);
549}
550
551void QWidgetPrivate::raise_sys()
552{
553 Q_Q(QWidget);
554
555 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
556 if (q->internalWinId()) {
557 q->internalWinId()->DrawableWindow()->SetOrdinalPosition(0);
558
559 // If toplevel widget, raise app to foreground
560 if (q->isWindow())
561 S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup().Identifier(), 0);
562 }
563}
564
565void QWidgetPrivate::lower_sys()
566{
567 Q_Q(QWidget);
568
569 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
570 if (q->internalWinId()) {
571 // If toplevel widget, lower app to background
572 if (q->isWindow())
573 S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup().Identifier(), -1);
574 else
575 q->internalWinId()->DrawableWindow()->SetOrdinalPosition(-1);
576 }
577
578 if (!q->isWindow())
579 invalidateBuffer(q->rect());
580}
581
582void QWidgetPrivate::setModal_sys()
583{
584
585}
586
587void QWidgetPrivate::stackUnder_sys(QWidget* w)
588{
589 Q_Q(QWidget);
590 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
591
592 if (q->internalWinId() && w->internalWinId()) {
593 RDrawableWindow *const thisWindow = q->internalWinId()->DrawableWindow();
594 RDrawableWindow *const otherWindow = w->internalWinId()->DrawableWindow();
595 thisWindow->SetOrdinalPosition(otherWindow->OrdinalPosition() + 1);
596 }
597
598 if (!q->isWindow() || !w->internalWinId())
599 invalidateBuffer(q->rect());
600}
601
602void QWidgetPrivate::reparentChildren()
603{
604 Q_Q(QWidget);
605
606 QObjectList chlist = q->children();
607 for (int i = 0; i < chlist.size(); ++i) { // reparent children
608 QObject *obj = chlist.at(i);
609 if (obj->isWidgetType()) {
610 QWidget *w = (QWidget *)obj;
611 if (!w->testAttribute(Qt::WA_WState_Created))
612 continue;
613 if (!w->isWindow()) {
614 w->d_func()->invalidateBuffer(w->rect());
615 WId parent = q->effectiveWinId();
616 WId child = w->effectiveWinId();
617 if (parent != child) {
618 // Child widget is native. Because Symbian windows cannot be
619 // re-parented, we must re-create the window.
620 const WId window = 0;
621 const bool initializeWindow = false;
622 const bool destroyOldWindow = true;
623 w->d_func()->create_sys(window, initializeWindow, destroyOldWindow);
624 }
625 // ### TODO: We probably also need to update the component array here
626 w->d_func()->reparentChildren();
627 } else {
628 bool showIt = w->isVisible();
629 QPoint old_pos = w->pos();
630 w->setParent(q, w->windowFlags());
631 w->move(old_pos);
632 if (showIt)
633 w->show();
634 }
635 }
636 }
637}
638
639void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
640{
641 Q_Q(QWidget);
642
643 bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
644
645 if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
646 q->parentWidget()->d_func()->invalidateBuffer(q->geometry());
647
648 if (q->testAttribute(Qt::WA_DropSiteRegistered))
649 q->setAttribute(Qt::WA_DropSiteRegistered, false);
650
651 QSymbianControl *old_winid = static_cast<QSymbianControl *>(wasCreated ? data.winid : 0);
652 if ((q->windowType() == Qt::Desktop))
653 old_winid = 0;
654 setWinId(0);
655
656 // hide and reparent our own window away. Otherwise we might get
657 // destroyed when emitting the child remove event below. See QWorkspace.
658 if (wasCreated && old_winid) {
659 old_winid->MakeVisible(false);
660 if (old_winid->IsFocused()) // Avoid unnecessary calls to FocusChanged()
661 old_winid->setFocusSafely(false);
662 old_winid->SetParent(0);
663 }
664
665 QObjectPrivate::setParent_helper(parent);
666 bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide);
667
668 data.window_flags = f;
669 data.fstrut_dirty = true;
670 q->setAttribute(Qt::WA_WState_Created, false);
671 q->setAttribute(Qt::WA_WState_Visible, false);
672 q->setAttribute(Qt::WA_WState_Hidden, false);
673 adjustFlags(data.window_flags, q);
674 // keep compatibility with previous versions, we need to preserve the created state
675 // (but we recreate the winId for the widget being reparented, again for compatibility)
676 if (wasCreated || (!q->isWindow() && parent->testAttribute(Qt::WA_WState_Created)))
677 createWinId();
678 if (q->isWindow() || (!parent || parent->isVisible()) || explicitlyHidden)
679 q->setAttribute(Qt::WA_WState_Hidden);
680 q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden);
681
682 if (wasCreated)
683 reparentChildren();
684
685 if (old_winid) {
686 CBase::Delete(old_winid);
687 }
688
689 if (q->testAttribute(Qt::WA_AcceptDrops)
690 || (!q->isWindow() && q->parentWidget() && q->parentWidget()->testAttribute(Qt::WA_DropSiteRegistered)))
691 q->setAttribute(Qt::WA_DropSiteRegistered, true);
692
693 invalidateBuffer(q->rect());
694}
695
696void QWidgetPrivate::setConstraints_sys()
697{
698
699}
700
701
702void QWidgetPrivate::s60UpdateIsOpaque()
703{
704 Q_Q(QWidget);
705
706 if (!q->testAttribute(Qt::WA_WState_Created) || !q->testAttribute(Qt::WA_TranslucentBackground))
707 return;
708
709 if ((data.window_flags & Qt::FramelessWindowHint) == 0)
710 return;
711
712 RWindow *const window = static_cast<RWindow *>(q->effectiveWinId()->DrawableWindow());
713
714#ifdef Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE
715 window->SetSurfaceTransparency(!isOpaque);
716#else
717 if (!isOpaque) {
718 const TDisplayMode displayMode = static_cast<TDisplayMode>(window->SetRequiredDisplayMode(EColor16MA));
719 if (window->SetTransparencyAlphaChannel() == KErrNone)
720 window->SetBackgroundColor(TRgb(255, 255, 255, 0));
721 } else
722 window->SetTransparentRegion(TRegionFix<1>());
723#endif
724}
725
726void QWidgetPrivate::setWindowIcon_sys(bool forceReset)
727{
728#ifdef Q_WS_S60
729 Q_Q(QWidget);
730
731 if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow() )
732 return;
733
734 QTLWExtra* topData = this->topData();
735 if (topData->iconPixmap && !forceReset)
736 // already been set
737 return;
738
739 TRect cPaneRect;
740 TBool found = AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EContextPane, cPaneRect );
741 CAknContextPane* contextPane = S60->contextPane();
742 if (found && contextPane) { // We have context pane with valid metrics
743 QIcon icon = q->windowIcon();
744 if (!icon.isNull()) {
745 // Valid icon -> set it as an context pane picture
746 QSize size = icon.actualSize(QSize(cPaneRect.Size().iWidth, cPaneRect.Size().iHeight));
747 QPixmap pm = icon.pixmap(size);
748 QBitmap mask = pm.mask();
749 if (mask.isNull()) {
750 mask = QBitmap(pm.size());
751 mask.fill(Qt::color1);
752 }
753
754 CFbsBitmap* nBitmap = pm.toSymbianCFbsBitmap();
755 CFbsBitmap* nMask = mask.toSymbianCFbsBitmap();
756 contextPane->SetPicture(nBitmap,nMask);
757 } else {
758 // Icon set to null -> set context pane picture to default
759 QT_TRAP_THROWING(contextPane->SetPictureToDefaultL());
760 }
761 } else {
762 // Context pane does not exist, try setting small icon to title pane
763 TRect titlePaneRect;
764 TBool found = AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::ETitlePane, titlePaneRect );
765 CAknTitlePane* titlePane = S60->titlePane();
766 if (found && titlePane) { // We have title pane with valid metrics
767 // The API to get title_pane graphics size is not public -> assume square space based
768 // on titlebar font height. CAknBitmap would be optimum, wihtout setting the size, since
769 // then title pane would automatically scale the bitmap. Unfortunately it is not public API
770 // Also this function is leaving, although it is not named as such.
771 const CFont * font;
772 QT_TRAP_THROWING(font = AknLayoutUtils::FontFromId(EAknLogicalFontTitleFont));
773 TSize iconSize(font->HeightInPixels(), font->HeightInPixels());
774
775 QIcon icon = q->windowIcon();
776 if (!icon.isNull()) {
777 // Valid icon -> set it as an title pane small picture
778 QSize size = icon.actualSize(QSize(iconSize.iWidth, iconSize.iHeight));
779 QPixmap pm = icon.pixmap(size);
780 QBitmap mask = pm.mask();
781 if (mask.isNull()) {
782 mask = QBitmap(pm.size());
783 mask.fill(Qt::color1);
784 }
785
786 CFbsBitmap* nBitmap = pm.toSymbianCFbsBitmap();
787 CFbsBitmap* nMask = mask.toSymbianCFbsBitmap();
788 titlePane->SetSmallPicture( nBitmap, nMask, ETrue );
789 } else {
790 // Icon set to null -> set context pane picture to default
791 titlePane->SetSmallPicture( NULL, NULL, EFalse );
792 }
793 }
794 }
795
796#else
797 Q_UNUSED(forceReset)
798#endif
799}
800
801void QWidgetPrivate::setWindowTitle_sys(const QString &caption)
802{
803#ifdef Q_WS_S60
804 Q_Q(QWidget);
805 if (q->isWindow()) {
806 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
807 CAknTitlePane* titlePane = S60->titlePane();
808 if (titlePane) {
809 if (caption.isEmpty()) {
810 QT_TRAP_THROWING(titlePane->SetTextToDefaultL());
811 } else {
812 QT_TRAP_THROWING(titlePane->SetTextL(qt_QString2TPtrC(caption)));
813 }
814 }
815 }
816#else
817 Q_UNUSED(caption)
818#endif
819}
820
821void QWidgetPrivate::setWindowIconText_sys(const QString & /*iconText */)
822{
823
824}
825
826void QWidgetPrivate::scroll_sys(int dx, int dy)
827{
828 Q_Q(QWidget);
829
830 scrollChildren(dx, dy);
831 if (!paintOnScreen() || !q->internalWinId() || !q->internalWinId()->OwnsWindow()) {
832 scrollRect(q->rect(), dx, dy);
833 } else {
834 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
835 RDrawableWindow *const window = q->internalWinId()->DrawableWindow();
836 window->Scroll(TPoint(dx, dy));
837 }
838}
839
840void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r)
841{
842 Q_Q(QWidget);
843
844 if (!paintOnScreen() || !q->internalWinId() || !q->internalWinId()->OwnsWindow()) {
845 scrollRect(r, dx, dy);
846 } else {
847 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
848 RDrawableWindow *const window = q->internalWinId()->DrawableWindow();
849 window->Scroll(TPoint(dx, dy), qt_QRect2TRect(r));
850 }
851}
852
853/*!
854 For this function to work in the emulator, you must add:
855 TRANSPARENCY
856 To a line in the wsini.ini file.
857*/
858void QWidgetPrivate::setWindowOpacity_sys(qreal)
859{
860 // ### TODO: Implement uniform window transparency
861}
862
863void QWidgetPrivate::updateFrameStrut()
864{
865
866}
867
868void QWidgetPrivate::updateSystemBackground()
869{
870
871}
872
873void QWidgetPrivate::registerDropSite(bool /* on */)
874{
875
876}
877
878void QWidgetPrivate::createTLSysExtra()
879{
880 extra->topextra->backingStore = 0;
881 extra->topextra->inExpose = 0;
882}
883
884void QWidgetPrivate::deleteTLSysExtra()
885{
886 delete extra->topextra->backingStore;
887 extra->topextra->backingStore = 0;
888}
889
890void QWidgetPrivate::createSysExtra()
891{
892 extra->activated = 0;
893 extra->nativePaintMode = QWExtra::Default;
894 extra->receiveNativePaintEvents = 0;
895}
896
897void QWidgetPrivate::deleteSysExtra()
898{
899 // this should only be non-zero if destroy() has not run due to constructor fail
900 if (data.winid) {
901 data.winid->ControlEnv()->AppUi()->RemoveFromStack(data.winid);
902 delete data.winid;
903 data.winid = 0;
904 }
905}
906
907QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys()
908{
909 return new QS60WindowSurface(q_func());
910}
911
912void QWidgetPrivate::setMask_sys(const QRegion& /* region */)
913{
914
915}
916
917void QWidgetPrivate::registerTouchWindow()
918{
919#ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
920 Q_Q(QWidget);
921 if (q->testAttribute(Qt::WA_WState_Created) && q->windowType() != Qt::Desktop) {
922 RWindow *rwindow = static_cast<RWindow *>(q->effectiveWinId()->DrawableWindow());
923 rwindow->EnableAdvancedPointers();
924 }
925#endif
926}
927
928int QWidget::metric(PaintDeviceMetric m) const
929{
930 Q_D(const QWidget);
931 int val;
932 if (m == PdmWidth) {
933 val = data->crect.width();
934 } else if (m == PdmHeight) {
935 val = data->crect.height();
936 } else {
937 CWsScreenDevice *scr = S60->screenDevice();
938 switch(m) {
939 case PdmDpiX:
940 case PdmPhysicalDpiX:
941 if (d->extra && d->extra->customDpiX) {
942 val = d->extra->customDpiX;
943 } else {
944 const QWidgetPrivate *p = d;
945 while (p->parent) {
946 p = static_cast<const QWidget *>(p->parent)->d_func();
947 if (p->extra && p->extra->customDpiX) {
948 val = p->extra->customDpiX;
949 break;
950 }
951 }
952 if (p == d || !(p->extra && p->extra->customDpiX))
953 val = S60->defaultDpiX;
954 }
955 break;
956 case PdmDpiY:
957 case PdmPhysicalDpiY:
958 if (d->extra && d->extra->customDpiY) {
959 val = d->extra->customDpiY;
960 } else {
961 const QWidgetPrivate *p = d;
962 while (p->parent) {
963 p = static_cast<const QWidget *>(p->parent)->d_func();
964 if (p->extra && p->extra->customDpiY) {
965 val = p->extra->customDpiY;
966 break;
967 }
968 }
969 if (p == d || !(p->extra && p->extra->customDpiY))
970 val = S60->defaultDpiY;
971 }
972 break;
973 case PdmWidthMM:
974 {
975 TInt twips = scr->HorizontalPixelsToTwips(data->crect.width());
976 val = (int)(twips * (25.4/KTwipsPerInch));
977 break;
978 }
979 case PdmHeightMM:
980 {
981 TInt twips = scr->VerticalPixelsToTwips(data->crect.height());
982 val = (int)(twips * (25.4/KTwipsPerInch));
983 break;
984 }
985 case PdmNumColors:
986 val = TDisplayModeUtils::NumDisplayModeColors(scr->DisplayMode());
987 break;
988 case PdmDepth:
989 val = TDisplayModeUtils::NumDisplayModeBitsPerPixel(scr->DisplayMode());
990 break;
991 default:
992 val = 0;
993 qWarning("QWidget::metric: Invalid metric command");
994 }
995 }
996 return val;
997}
998
999QPaintEngine *QWidget::paintEngine() const
1000{
1001 return 0;
1002}
1003
1004QPoint QWidget::mapToGlobal(const QPoint &pos) const
1005{
1006 Q_D(const QWidget);
1007 if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
1008
1009 QPoint p = pos + data->crect.topLeft();
1010 return (isWindow() || !parentWidget()) ? p : parentWidget()->mapToGlobal(p);
1011
1012 } else if ((d->data.window_flags & Qt::Window) && internalWinId()) { //toplevel
1013 QPoint tp = geometry().topLeft();
1014 return pos + tp;
1015 }
1016
1017 // Native window case
1018 const TPoint widgetScreenOffset = internalWinId()->PositionRelativeToScreen();
1019 const QPoint globalPos = QPoint(widgetScreenOffset.iX, widgetScreenOffset.iY) + pos;
1020 return globalPos;
1021}
1022
1023QPoint QWidget::mapFromGlobal(const QPoint &pos) const
1024{
1025 Q_D(const QWidget);
1026 if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
1027 QPoint p = (isWindow() || !parentWidget()) ? pos : parentWidget()->mapFromGlobal(pos);
1028 return p - data->crect.topLeft();
1029 } else if ((d->data.window_flags & Qt::Window) && internalWinId()) { //toplevel
1030 QPoint tp = geometry().topLeft();
1031 return pos - tp;
1032 }
1033
1034 // Native window case
1035 const TPoint widgetScreenOffset = internalWinId()->PositionRelativeToScreen();
1036 const QPoint widgetPos = pos - QPoint(widgetScreenOffset.iX, widgetScreenOffset.iY);
1037 return widgetPos;
1038}
1039
1040void QWidget::setWindowState(Qt::WindowStates newstate)
1041{
1042 Q_D(QWidget);
1043
1044 Qt::WindowStates oldstate = windowState();
1045 if (oldstate == newstate)
1046 return;
1047
1048 if (isWindow()) {
1049
1050 QSymbianControl *window = static_cast<QSymbianControl *>(effectiveWinId());
1051 if (window && newstate & Qt::WindowMinimized) {
1052 window->setFocusSafely(false);
1053 window->MakeVisible(false);
1054 } else if (window && oldstate & Qt::WindowMinimized) {
1055 window->setFocusSafely(true);
1056 window->MakeVisible(true);
1057 }
1058
1059#ifdef Q_WS_S60
1060 // Hide window decoration when switching to fullsccreen / minimized otherwise show decoration.
1061 // The window decoration visibility has to be changed before doing actual window state
1062 // change since in that order the availableGeometry will return directly the right size and
1063 // we will avoid unnecessarty redraws
1064 CEikStatusPane* statusPane = S60->statusPane();
1065 CEikButtonGroupContainer* buttonGroup = S60->buttonGroupContainer();
1066 TBool visible = !(newstate & (Qt::WindowFullScreen | Qt::WindowMinimized));
1067 if (statusPane)
1068 statusPane->MakeVisible(visible);
1069 if (buttonGroup)
1070 buttonGroup->MakeVisible(visible);
1071#endif // Q_WS_S60
1072
1073 createWinId();
1074 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1075 // Ensure the initial size is valid, since we store it as normalGeometry below.
1076 if (!testAttribute(Qt::WA_Resized) && !isVisible())
1077 adjustSize();
1078
1079 QTLWExtra *top = d->topData();
1080 const QRect normalGeometry = (top->normalGeometry.width() < 0) ? geometry() : top->normalGeometry;
1081
1082 if (newstate & Qt::WindowFullScreen)
1083 setGeometry(qApp->desktop()->screenGeometry(this));
1084 else if (newstate & Qt::WindowMaximized)
1085 setGeometry(qApp->desktop()->availableGeometry(this));
1086 else
1087 setGeometry(normalGeometry);
1088
1089 //restore normal geometry
1090 top->normalGeometry = normalGeometry;
1091 }
1092
1093 data->window_state = newstate;
1094
1095 if (newstate & Qt::WindowActive)
1096 activateWindow();
1097
1098 QWindowStateChangeEvent e(oldstate);
1099 QApplication::sendEvent(this, &e);
1100}
1101
1102
1103void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
1104{
1105 Q_D(QWidget);
1106 if (!isWindow() && parentWidget())
1107 parentWidget()->d_func()->invalidateBuffer(geometry());
1108 d->deactivateWidgetCleanup();
1109 QSymbianControl *id = static_cast<QSymbianControl *>(internalWinId());
1110 if (testAttribute(Qt::WA_WState_Created)) {
1111
1112#ifndef QT_NO_IM
1113 if (d->ic) {
1114 delete d->ic;
1115 } else {
1116 QInputContext *ic = QApplicationPrivate::inputContext;
1117 if (ic) {
1118 ic->widgetDestroyed(this);
1119 }
1120 }
1121#endif
1122
1123 if (QWidgetPrivate::mouseGrabber == this)
1124 releaseMouse();
1125 if (QWidgetPrivate::keyboardGrabber == this)
1126 releaseKeyboard();
1127 setAttribute(Qt::WA_WState_Created, false);
1128 QObjectList childList = children();
1129 for (int i = 0; i < childList.size(); ++i) { // destroy all widget children
1130 register QObject *obj = childList.at(i);
1131 if (obj->isWidgetType())
1132 static_cast<QWidget*>(obj)->destroy(destroySubWindows,
1133 destroySubWindows);
1134 }
1135 if (destroyWindow && !(windowType() == Qt::Desktop) && id) {
1136 if (id->IsFocused()) // Avoid unnecessry calls to FocusChanged()
1137 id->setFocusSafely(false);
1138 id->ControlEnv()->AppUi()->RemoveFromStack(id);
1139 }
1140 }
1141
1142 QT_TRY {
1143 d->setWinId(0);
1144 } QT_CATCH (const std::bad_alloc &) {
1145 // swallow - destructors must not throw
1146 }
1147
1148 if (destroyWindow) {
1149 delete id;
1150 // At this point the backing store should already be destroyed
1151 // so we flush the command buffer to ensure that the freeing of
1152 // those resources and deleting the window can happen "atomically"
1153 S60->wsSession().Flush();
1154 }
1155}
1156
1157QWidget *QWidget::mouseGrabber()
1158{
1159 return QWidgetPrivate::mouseGrabber;
1160}
1161
1162QWidget *QWidget::keyboardGrabber()
1163{
1164 return QWidgetPrivate::keyboardGrabber;
1165}
1166
1167void QWidget::grabKeyboard()
1168{
1169 if (!qt_nograb()) {
1170 if (QWidgetPrivate::keyboardGrabber && QWidgetPrivate::keyboardGrabber != this)
1171 QWidgetPrivate::keyboardGrabber->releaseKeyboard();
1172
1173 // ### TODO: Native keyboard grab
1174
1175 QWidgetPrivate::keyboardGrabber = this;
1176 }
1177}
1178
1179void QWidget::releaseKeyboard()
1180{
1181 if (!qt_nograb() && QWidgetPrivate::keyboardGrabber == this) {
1182 // ### TODO: Native keyboard release
1183 QWidgetPrivate::keyboardGrabber = 0;
1184 }
1185}
1186
1187void QWidget::grabMouse()
1188{
1189 if (isVisible() && !qt_nograb()) {
1190 if (QWidgetPrivate::mouseGrabber && QWidgetPrivate::mouseGrabber != this)
1191 QWidgetPrivate::mouseGrabber->releaseMouse();
1192 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1193 WId id = effectiveWinId();
1194 id->SetPointerCapture(true);
1195 QWidgetPrivate::mouseGrabber = this;
1196
1197#ifndef QT_NO_CURSOR
1198 QApplication::setOverrideCursor(cursor());
1199#endif
1200 }
1201}
1202
1203#ifndef QT_NO_CURSOR
1204void QWidget::grabMouse(const QCursor &cursor)
1205{
1206 if (isVisible() && !qt_nograb()) {
1207 if (QWidgetPrivate::mouseGrabber && QWidgetPrivate::mouseGrabber != this)
1208 QWidgetPrivate::mouseGrabber->releaseMouse();
1209 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1210 WId id = effectiveWinId();
1211 id->SetPointerCapture(true);
1212 QWidgetPrivate::mouseGrabber = this;
1213
1214 QApplication::setOverrideCursor(cursor);
1215 }
1216}
1217#endif
1218
1219void QWidget::releaseMouse()
1220{
1221 if (!qt_nograb() && QWidgetPrivate::mouseGrabber == this) {
1222 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1223 WId id = effectiveWinId();
1224 id->SetPointerCapture(false);
1225 QWidgetPrivate::mouseGrabber = 0;
1226#ifndef QT_NO_CURSOR
1227 QApplication::restoreOverrideCursor();
1228#endif
1229 }
1230}
1231
1232void QWidget::activateWindow()
1233{
1234 Q_D(QWidget);
1235
1236 QWidget *tlw = window();
1237 if (tlw->isVisible()) {
1238 window()->createWinId();
1239 QSymbianControl *id = static_cast<QSymbianControl *>(tlw->internalWinId());
1240 id->setFocusSafely(true);
1241 }
1242}
1243
1244#ifndef QT_NO_CURSOR
1245
1246void QWidgetPrivate::setCursor_sys(const QCursor &cursor)
1247{
1248 Q_UNUSED(cursor);
1249 Q_Q(QWidget);
1250 qt_symbian_set_cursor(q, false);
1251}
1252
1253void QWidgetPrivate::unsetCursor_sys()
1254{
1255 Q_Q(QWidget);
1256 qt_symbian_set_cursor(q, false);
1257}
1258#endif
1259
1260QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.