| Home · All Classes · Main Classes · Deprecated |
00001 /*************************************************************************** 00002 ** 00003 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). 00004 ** All rights reserved. 00005 ** Contact: Nokia Corporation (directui@nokia.com) 00006 ** 00007 ** This file is part of libmeegotouch. 00008 ** 00009 ** If you have questions regarding the use of this file, please contact 00010 ** Nokia at directui@nokia.com. 00011 ** 00012 ** This library is free software; you can redistribute it and/or 00013 ** modify it under the terms of the GNU Lesser General Public 00014 ** License version 2.1 as published by the Free Software Foundation 00015 ** and appearing in the file LICENSE.LGPL included in the packaging 00016 ** of this file. 00017 ** 00018 ****************************************************************************/ 00019 00020 #ifdef QT_OPENGL_LIB 00021 #include "mgles2renderer.h" 00022 #endif 00023 00024 #include "mwindow.h" 00025 #include "mwindow_p.h" 00026 00027 #include "mscene.h" 00028 #include "mscene_p.h" 00029 #include "mapplication.h" 00030 #include "mapplication_p.h" 00031 #include "mcomponentcache.h" 00032 #include "morientationtracker.h" 00033 #include "mdeviceprofile.h" 00034 #include "mdeviceprofile.h" 00035 #include "mwidget.h" 00036 #include "mcomponentdata.h" 00037 #include "morientationchangeevent.h" 00038 #include "mondisplaychangeevent.h" 00039 #include "mdebug.h" 00040 #include "mgconfitem.h" 00041 #include "mlocale.h" 00042 #include "mgraphicssystemhelper.h" 00043 00044 #include <QPropertyAnimation> 00045 #include <QSettings> 00046 #include <QDir> 00047 #include <QTimer> 00048 #include <QDynamicPropertyChangeEvent> 00049 00050 #include "morientationtracker_p.h" 00051 #include "mscenemanager_p.h" 00052 00053 #ifdef Q_WS_X11 00054 # include <QX11Info> 00055 # include <X11/Xatom.h> 00056 # include <X11/Xlib.h> 00057 // Avoid conflict with QEvent::KeyPress usage in MWindow::Event 00058 # undef KeyPress 00059 #endif 00060 00061 namespace { 00062 const QString ImagesPath(QDir::homePath() + "/MyDocs/.images"); 00063 const int DisplayExitedDelay = 1000; //ms. 00064 #ifdef Q_WS_X11 00065 const char* FollowsCurrentApplicationWindowOrientationPropertyName = 00066 "followsCurrentApplicationWindowOrientation"; 00067 #endif 00068 } 00069 00071 00072 MWindowPrivate::MWindowPrivate() : 00073 glContext(0), 00074 sceneManager(0), 00075 oldOrientation(M::Landscape), // the initial value is not used at all 00076 orientationAngleLocked(false), 00077 orientationLocked(false), 00078 isLogicallyClosed(true), 00079 isInSwitcher(false), 00080 closeOnLazyShutdown(false), 00081 delayedMOnDisplayChangeEvent(0), 00082 onDisplay(false), 00083 onDisplaySet(false), 00084 displayExitedTimer(), 00085 visibleInSwitcher(false), 00086 fullyObscured(false), 00087 #ifdef HAVE_GCONF 00088 minimizedSoftwareSwitchItem("/meegotouch/debug/minimized_software_switch"), 00089 #endif 00090 minimizedSoftwareSwitch(false), 00091 updateIsPending(false), 00092 discardedPaintEvent(false), 00093 q_ptr(NULL) 00094 { 00095 #ifdef Q_WS_X11 00096 removeWindowFromSwitcherInProgress = false; 00097 skipTaskbar = false; 00098 #endif 00099 00100 MWindow *window = MApplication::activeWindow(); 00101 00102 if (window) 00103 angle = window->orientationAngle(); 00104 else 00105 angle = MOrientationTracker::instance()->orientationAngle(); 00106 00107 timeSinceLastPaintInSwitcher.invalidate(); 00108 } 00109 00110 MWindowPrivate::~MWindowPrivate() 00111 { 00112 delete delayedMOnDisplayChangeEvent; 00113 } 00114 00115 void MWindowPrivate::init() 00116 { 00117 Q_Q(MWindow); 00118 00119 displayExitedTimer.connect(&displayExitedTimer, SIGNAL(timeout()), 00120 q, SLOT(_q_exitDisplayStabilized())); 00121 displayExitedTimer.setInterval(DisplayExitedDelay); 00122 displayExitedTimer.setSingleShot(true); 00123 00124 #ifdef HAVE_GCONF 00125 minimizedSoftwareSwitch = minimizedSoftwareSwitchItem.value(true).toBool(); 00126 QObject::connect(&minimizedSoftwareSwitchItem, SIGNAL(valueChanged()), q_ptr, SLOT(_q_updateMinimizedSoftwareSwitch())); 00127 #endif 00128 00129 #ifdef Q_WS_X11 00130 // We do window decorations ourselves. Set env variable accordingly for 00131 // development purposes 00132 00133 #ifdef M_OS_MAEMO5 00134 if ( !MApplication::fullScreen() ) { 00135 #endif //M_OS_MAEMO5 00136 00137 QString env = qgetenv("M_DECORATED"); 00138 if (env.contains("0")) { 00139 q->setWindowFlags(Qt::FramelessWindowHint); 00140 } 00141 /* Workaround until we get M_DECORATED defined in the target env */ 00142 #ifdef __arm__ 00143 else if (env.isEmpty()) { 00144 q->setWindowFlags(Qt::FramelessWindowHint); 00145 } 00146 #endif // __arm__ 00147 00148 #ifdef M_OS_MAEMO5 00149 } 00150 #endif //M_OS_MAEMO5 00151 00152 #endif // Q_WS_X11 00153 00154 // resize always to the size in landscape mode, 00155 // since it's not the window but the scene content that is rotated 00156 q->resize(q->visibleSceneSize(M::Landscape)); 00157 q->setFrameStyle(0); 00158 q->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 00159 q->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 00160 00161 if (MApplication::softwareRendering() == false) { 00162 #ifdef QT_OPENGL_LIB 00163 mDebug("MWindowPrivate") << "Renderer: OpenGL"; 00164 #else 00165 mDebug("MWindowPrivate") << "Renderer: Software"; 00166 #endif 00167 } else { 00168 mDebug("MWindowPrivate") << "Renderer: Software (forced)"; 00169 } 00170 00171 #ifdef Q_WS_X11 00172 appendVisibilityChangeMask(); 00173 // If the window is created for the application in prestarted mode 00174 // we have to set X11 property _MEEGOTOUCH_PRESTARTED 00175 if(MApplication::isPrestarted()) { 00176 setX11PrestartProperty(true); 00177 } 00178 setX11OrientationAngleProperty(angle); 00179 #endif 00180 00181 q->setTranslucentBackground(false); 00182 00183 if (MApplication::fullScreen()) 00184 q->showFullScreen(); 00185 } 00186 00187 void MWindowPrivate::initSoftwareViewport() 00188 { 00189 Q_Q(MWindow); 00190 00191 mDebug("MWindow") << "Switching to software rendering"; 00192 00193 #ifdef M_USE_OPENGL 00194 MGLES2Renderer::activate((QGLContext*)NULL); 00195 MGLES2Renderer::destroy(glContext); 00196 glContext = NULL; 00197 #endif 00198 00199 MGraphicsSystemHelper::switchToSoftwareRendering(q); 00200 00201 q->setViewportUpdateMode(MWindow::MinimalViewportUpdate); 00202 00203 configureViewport(); 00204 } 00205 00206 void MWindowPrivate::initGLViewport() 00207 { 00208 Q_Q(MWindow); 00209 00210 #ifdef QT_OPENGL_LIB 00211 mDebug("MWindow") << "Window restored, switching to GL rendering"; 00212 00213 bool translucent = q->testAttribute(Qt::WA_TranslucentBackground); 00214 00215 MGraphicsSystemHelper::switchToHardwareRendering(q, &glContext); 00216 00217 if (translucent) { 00218 QPalette palette; 00219 palette.setColor(QPalette::Base, Qt::transparent); 00220 palette.setColor(QPalette::Window, Qt::transparent); 00221 q->setAutoFillBackground(true); 00222 q->setPalette(palette); 00223 q->viewport()->setAutoFillBackground(true); 00224 q->viewport()->setPalette(palette); 00225 } 00226 00227 #ifdef M_USE_OPENGL 00228 MGLES2Renderer::instance(glContext); 00229 MGLES2Renderer::activate(glContext); 00230 #endif 00231 #endif // QT_OPENGL_LIB 00232 00233 q->setViewportUpdateMode(MWindow::FullViewportUpdate); 00234 00235 configureViewport(); 00236 } 00237 00238 void MWindowPrivate::configureViewport() 00239 { 00240 Q_Q(MWindow); 00241 00242 q->viewport()->grabGesture(Qt::TapAndHoldGesture); 00243 q->viewport()->grabGesture(Qt::PinchGesture); 00244 q->viewport()->grabGesture(Qt::PanGesture); 00245 q->viewport()->grabGesture(Qt::SwipeGesture); 00246 q->viewport()->grabGesture(Qt::TapGesture); 00247 00248 q->setAttribute(Qt::WA_AcceptTouchEvents); 00249 00250 // If we don't set this flag, the technique of discarding paintEvent() calls 00251 // for limiting the framerate (e.g. because window is a thumbnail in the 00252 // application switcher) will cause the window to flicker between its regular 00253 // appearance and a blank window. 00254 // That's because even though we avoided the actual rendering of the contents, 00255 // by the time paintEvent() is called Qt might have already painted the system 00256 // background over of the window's previous state. This seems to be happening only 00257 // with softare rendering. 00258 q->setAttribute(Qt::WA_OpaquePaintEvent); 00259 q->setAttribute(Qt::WA_NoSystemBackground); 00260 q->viewport()->setAttribute(Qt::WA_OpaquePaintEvent); 00261 q->viewport()->setAttribute(Qt::WA_NoSystemBackground); 00262 } 00263 00264 00266 class ScreenshotEffect : public QGraphicsWidget 00267 { 00268 virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, 00269 QWidget *widget = 0) 00270 { 00271 Q_UNUSED(option); 00272 Q_UNUSED(widget); 00273 00274 painter->fillRect(boundingRect(), Qt::white); 00275 } 00276 }; 00278 00279 void MWindowPrivate::playScreenshotEffect() 00280 { 00281 Q_Q(MWindow); 00282 00283 ScreenshotEffect *flash = new ScreenshotEffect(); 00284 flash->setGeometry(0, 0, q->width(), q->height()); 00285 00286 QPropertyAnimation *animation = new QPropertyAnimation(flash, "opacity", q); 00287 animation->setDuration(400); 00288 animation->setEndValue(0.0f); 00289 animation->start(QAbstractAnimation::DeleteWhenStopped); 00290 00291 q->scene()->addItem(flash); 00292 00293 QObject::connect(animation, SIGNAL(finished()), flash, SLOT(deleteLater())); 00294 } 00295 00296 WId MWindowPrivate::robustEffectiveWinId() const 00297 { 00298 Q_Q(const MWindow); 00299 if (q->isVisible()) { 00300 return q->effectiveWinId(); 00301 } else { 00302 if (QWidget *parent = q->parentWidget()) { 00303 while (parent->parentWidget()) { 00304 parent = parent->parentWidget(); 00305 } 00306 return parent->winId(); 00307 } else { 00308 return q->winId(); 00309 } 00310 } 00311 } 00312 00313 #ifdef Q_WS_X11 00314 void MWindowPrivate::appendVisibilityChangeMask() 00315 { 00316 XWindowAttributes existingAttributes; 00317 XSetWindowAttributes newAttributes; 00318 Status status; 00319 00320 status = XGetWindowAttributes(QX11Info::display(), robustEffectiveWinId(), &existingAttributes); 00321 if (status == 0) { 00322 qFatal("MWindow: XGetWindowAttributes() failed!"); 00323 } 00324 00325 newAttributes.event_mask = existingAttributes.your_event_mask | VisibilityChangeMask; 00326 00327 XChangeWindowAttributes(QX11Info::display(), robustEffectiveWinId(), CWEventMask, &newAttributes); 00328 } 00329 #endif 00330 00331 void MWindowPrivate::_q_onPixmapRequestsFinished() 00332 { 00333 Q_Q(MWindow); 00334 00335 q->disconnect(MTheme::instance(), SIGNAL(pixmapRequestsFinished()), 00336 q, SLOT(_q_onPixmapRequestsFinished())); 00337 q->setVisible(true); 00338 } 00339 00340 void MWindowPrivate::handleApplicationLayoutDirectionChangeEvent(QGraphicsItem *item) 00341 { 00342 if (item->isWidget()) { 00343 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item); 00344 Qt::LayoutDirection direction = qApp->layoutDirection(); 00345 // if the direction has not changed or has been specified 00346 // directly, do not update. 00347 if (((direction == Qt::RightToLeft) == widget->testAttribute(Qt::WA_RightToLeft)) 00348 || widget->testAttribute(Qt::WA_SetLayoutDirection)) 00349 return; 00350 widget->setAttribute(Qt::WA_RightToLeft, (direction == Qt::RightToLeft)); 00351 // Send the notification event to this widget item. 00352 QEvent e(QEvent::LayoutDirectionChange); 00353 QApplication::sendEvent(widget, &e); 00354 } 00355 // Propagate this change to all children. 00356 const int size = item->childItems().size(); 00357 for (int i = 0; i < size; ++i) { 00358 QGraphicsItem *childItem = item->childItems().at(i); 00359 handleApplicationLayoutDirectionChangeEvent(childItem); 00360 } 00361 } 00362 00363 void MWindowPrivate::handleLanguageChangeEvent(QGraphicsItem *item) 00364 { 00365 if (item->isWidget()) { 00366 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item); 00367 if (qobject_cast<MWidget*> (widget)) { 00368 // If it is a MWidget, sent it the language change event 00369 // to trigger the retranslateUi() method of the MWidget: 00370 QEvent e(QEvent::LanguageChange); 00371 qApp->sendEvent(widget, &e); 00372 } 00373 } 00374 // Propagate this change to all children. 00375 const int size = item->childItems().size(); 00376 for (int i = 0; i < size; ++i) { 00377 QGraphicsItem *childItem = item->childItems().at(i); 00378 handleLanguageChangeEvent(childItem); 00379 } 00380 } 00381 00382 bool MWindow::isInSwitcher() const 00383 { 00384 Q_D(const MWindow); 00385 00386 return d->isInSwitcher; 00387 } 00388 00389 M::Orientation MWindowPrivate::orientation(M::OrientationAngle angle) const 00390 { 00391 return (angle == M::Angle0 || angle == M::Angle180) ? M::Landscape : M::Portrait; 00392 } 00393 00394 // return true if modifiers match what is required for debug keyboard shortcuts 00395 bool MWindowPrivate::debugShortcutModifiersPresent(Qt::KeyboardModifiers modifiers) const 00396 { 00397 return (modifiers & (Qt::ControlModifier | Qt::AltModifier) 00398 && (modifiers & Qt::ShiftModifier)); 00399 } 00400 00401 void MWindowPrivate::notifyWidgetsAboutOrientationChange() 00402 { 00403 Q_Q(MWindow); 00404 00405 M::Orientation newOrientation = q->orientation(); 00406 00407 if (sceneManager == 0 && oldOrientation != newOrientation) { 00408 QGraphicsScene *graphicsScene = q->QGraphicsView::scene(); 00409 if (graphicsScene) { 00410 MOrientationChangeEvent event(newOrientation); 00411 foreach(QGraphicsItem * item, graphicsScene->items()) 00412 graphicsScene->sendEvent(item, &event); 00413 } 00414 00415 emit q->orientationChanged(newOrientation); 00416 emit q->orientationChangeFinished(newOrientation); 00417 } 00418 } 00419 00420 void MWindowPrivate::doEnterDisplayEvent() 00421 { 00422 Q_Q(MWindow); 00423 00424 onDisplay = true; 00425 onDisplaySet = true; 00426 00427 q->enterDisplayEvent(); 00428 emit q->displayEntered(); 00429 00430 if (discardedPaintEvent) { 00431 // we discarded a paint event while beeing invisible 00432 // make sure the screen is up to date 00433 discardedPaintEvent = false; 00434 QTimer::singleShot(0, q->viewport(), SLOT(update())); 00435 } 00436 } 00437 00438 void MWindowPrivate::doExitDisplayEvent() 00439 { 00440 Q_Q(MWindow); 00441 00442 onDisplay = false; 00443 onDisplaySet = true; 00444 00445 q->exitDisplayEvent(); 00446 emit q->displayExited(); 00447 00448 if (q->scene() && delayedMOnDisplayChangeEvent != 0) { 00449 propagateMOnDisplayChangeEventToScene(delayedMOnDisplayChangeEvent); 00450 delete delayedMOnDisplayChangeEvent; 00451 delayedMOnDisplayChangeEvent = 0; 00452 } 00453 } 00454 00455 void MWindowPrivate::_q_exitDisplayStabilized() 00456 { 00457 doExitDisplayEvent(); 00458 } 00459 00460 void MWindowPrivate::sendExitDisplayEvent(bool delayedSending) 00461 { 00462 Q_Q(MWindow); 00463 00464 delete delayedMOnDisplayChangeEvent; 00465 delayedMOnDisplayChangeEvent = new MOnDisplayChangeEvent(MOnDisplayChangeEvent::FullyOffDisplay, q->sceneRect()); 00466 if (delayedSending) { 00467 displayExitedTimer.start(); 00468 } else { 00469 _q_exitDisplayStabilized(); 00470 } 00471 } 00472 00473 void MWindowPrivate::propagateMOnDisplayChangeEventToScene(MOnDisplayChangeEvent *event) 00474 { 00475 Q_Q(MWindow); 00476 00477 MOnDisplayChangeEvent::State eventState; 00478 00479 if (event->state() == MOnDisplayChangeEvent::PartiallyOnDisplay || 00480 event->state() == MOnDisplayChangeEvent::FullyOnDisplay || 00481 event->state() == MOnDisplayChangeEvent::MustBeResolved) { 00482 eventState = MOnDisplayChangeEvent::MustBeResolved; 00483 } else { 00484 eventState = MOnDisplayChangeEvent::FullyOffDisplay; 00485 } 00486 00487 00488 MOnDisplayChangeEvent ev(eventState, q->sceneRect()); 00489 00490 // FIXME: 00491 // Actually sending the event would require overriding customEvent() which 00492 // would mess ABI compatibility. Calling the event handler directly for now 00493 q->scene()->d_func()->onDisplayChangeEvent(&ev); 00494 00495 } 00496 00497 void MWindowPrivate::_q_enablePaintUpdates() 00498 { 00499 Q_Q(MWindow); 00500 00501 q->setUpdatesEnabled(true); 00502 } 00503 00504 void MWindowPrivate::windowStateChangeEvent(QWindowStateChangeEvent *event) 00505 { 00506 Q_Q(MWindow); 00507 00508 // Check if window has entered / left the switcher 00509 if (!event->oldState().testFlag(Qt::WindowMinimized) && q->windowState().testFlag(Qt::WindowMinimized)) { 00510 isInSwitcher = true; 00511 emit q->switcherEntered(); 00512 } 00513 else if (event->oldState().testFlag(Qt::WindowMinimized) && 00514 !q->windowState().testFlag(Qt::WindowMinimized)) { 00515 isInSwitcher = false; 00516 timeSinceLastPaintInSwitcher.invalidate(); 00517 emit q->switcherExited(); 00518 } 00519 00520 #ifdef QT_OPENGL_LIB 00521 if (!minimizedSoftwareSwitch || MApplication::softwareRendering()) 00522 return; 00523 00524 if (!event->oldState().testFlag(Qt::WindowMinimized) && q->windowState().testFlag(Qt::WindowMinimized)) { 00525 initSoftwareViewport(); 00526 MComponentCache::cleanupCache(); 00527 MTheme::cleanupGarbage(); 00528 } else if (event->oldState().testFlag(Qt::WindowMinimized) 00529 && !q->windowState().testFlag(Qt::WindowMinimized)) { 00530 if (MGraphicsSystemHelper::isRunningNativeGraphicssystem()) { 00531 q->setUpdatesEnabled(false); 00532 } 00533 initGLViewport(); 00534 if (MGraphicsSystemHelper::isRunningNativeGraphicssystem()) { 00535 QTimer::singleShot(700, q, SLOT(_q_enablePaintUpdates())); 00536 } 00537 } 00538 #endif 00539 } 00540 00541 void MWindowPrivate::closeEvent(QCloseEvent *event) 00542 { 00543 Q_Q(MWindow); 00544 00545 // Call close event manually here, because we want to check if the 00546 // event got ignored before executing lazy shutdown routines. 00547 q->closeEvent(static_cast<QCloseEvent *>(event)); 00548 00549 if (!event->isAccepted()) { 00550 return; 00551 } 00552 00553 isLogicallyClosed = true; 00554 00555 sendExitDisplayEvent(false); 00556 00557 if (MApplication::prestartMode() == M::LazyShutdownMultiWindow || 00558 MApplication::prestartMode() == M::LazyShutdown) { 00559 00560 #ifdef Q_WS_X11 00561 MApplicationPrivate::removeWindowFromSwitcher(q->effectiveWinId(), true); 00562 #endif 00563 00564 // Check if all windows are closed. If so, 00565 // return to the prestarted state. 00566 bool allWindowsLogicallyClosed = true; 00567 Q_FOREACH(MWindow * win, MApplication::windows()) { 00568 if (!win->d_ptr->isLogicallyClosed) { 00569 allWindowsLogicallyClosed = false; 00570 } 00571 } 00572 00573 if (allWindowsLogicallyClosed) { 00574 MApplication::setPrestarted(true); 00575 } 00576 00577 if (!q->closeOnLazyShutdown()) { 00578 q->hide(); 00579 q->lower(); 00580 event->ignore(); 00581 return; 00582 } 00583 } 00584 00585 #ifdef M_USE_OPENGL 00586 if (!MApplication::softwareRendering()) { 00587 MGLES2Renderer::destroy(glContext); 00588 } 00589 #endif 00590 00591 } 00592 00593 #ifdef HAVE_GCONF 00594 void MWindowPrivate::_q_updateMinimizedSoftwareSwitch() { 00595 minimizedSoftwareSwitch = minimizedSoftwareSwitchItem.value().toBool(); 00596 } 00597 #endif 00598 00599 MWindow::MWindow(MWindowPrivate &dd, QWidget *parent) 00600 : QGraphicsView(parent), 00601 d_ptr(&dd) 00602 { 00603 Q_D(MWindow); 00604 00605 d->q_ptr = this; 00606 d->init(); 00607 MComponentData::registerWindow(this); 00608 } 00609 00610 MWindow::MWindow(MWindowPrivate &dd, MScene *scene, QWidget *parent) 00611 : QGraphicsView(parent), d_ptr(&dd) 00612 { 00613 Q_D(MWindow); 00614 d->q_ptr = this; 00615 d->init(); 00616 MComponentData::registerWindow(this); 00617 setSceneManager(new MSceneManager(scene, this)); 00618 } 00619 00620 MWindow::MWindow(MWindowPrivate &dd, MSceneManager *sceneManager, QWidget *parent) 00621 : QGraphicsView(parent), d_ptr(&dd) 00622 { 00623 Q_D(MWindow); 00624 d->q_ptr = this; 00625 d->init(); 00626 MComponentData::registerWindow(this); 00627 setSceneManager(sceneManager); 00628 } 00629 00630 MWindow::MWindow(MSceneManager *sceneManager, QWidget *parent) 00631 : QGraphicsView(parent), d_ptr(new MWindowPrivate) 00632 { 00633 Q_D(MWindow); 00634 d->q_ptr = this; 00635 d->init(); 00636 MComponentData::registerWindow(this); 00637 setSceneManager(sceneManager); 00638 } 00639 00640 MWindow::MWindow(QWidget *parent) 00641 : QGraphicsView(parent), 00642 d_ptr(new MWindowPrivate) 00643 { 00644 Q_D(MWindow); 00645 d->q_ptr = this; 00646 d->init(); 00647 MComponentData::registerWindow(this); 00648 } 00649 00650 MWindow::~MWindow() 00651 { 00652 #ifdef Q_WS_X11 00653 MOrientationTracker::instance()->d_func()->stopFollowingCurrentAppWindow(this); 00654 #endif 00655 MComponentData::unregisterWindow(this); 00656 delete d_ptr; 00657 } 00658 00659 void MWindow::setTranslucentBackground(bool enable) 00660 { 00661 Q_D(MWindow); 00662 00663 if (enable) { 00664 setAttribute(Qt::WA_TranslucentBackground); 00665 #ifdef Q_WS_X11 00666 // This is workaround for NB#170883 00667 // Setting Qt::WA_TranslucentBackground property for window 00668 // changes mask for yet unknown reason, only on hardware, 00669 // not in scratchbox and supposingly its a candidate for 00670 // filing bug against Qt when confirmed 00671 d->appendVisibilityChangeMask(); 00672 #endif 00673 } 00674 00675 // when the gl widget is not initialized yet we will also not initialize it 00676 if (MApplication::softwareRendering() || MApplication::isPrestarted() || 00677 (MGraphicsSystemHelper::isRunningNativeGraphicssystem() && !dynamic_cast<QGLWidget*>(viewport()))) { 00678 d->initSoftwareViewport(); 00679 } else { 00680 d->initGLViewport(); 00681 } 00682 00683 if (MApplication::softwareRendering()) 00684 viewport()->setAutoFillBackground(!enable); 00685 } 00686 00687 #ifdef Q_WS_X11 00688 void MWindowPrivate::setX11Property(const char *propertyName, qreal value) 00689 { 00690 Q_Q(MWindow); 00691 00692 Atom atom = XInternAtom(QX11Info::display(), propertyName, False); 00693 00694 if (value < 0.0 || value >= 1.0) { 00695 XDeleteProperty(QX11Info::display(), q->effectiveWinId(), atom); 00696 } else { 00697 // We use same conventions as _NET_WM_WINDOW_OPACITY so we could re-use 00698 // same code in the compositor 00699 unsigned int opacity = (unsigned int) (0xffffffff * value); 00700 00701 XChangeProperty(QX11Info::display(), q->effectiveWinId(), atom, XA_CARDINAL, 32 , 00702 PropModeReplace, (unsigned char *) &opacity, 1); 00703 } 00704 } 00705 00706 qreal MWindowPrivate::getX11Property(const char *propertyName) const 00707 { 00708 Q_Q(const MWindow); 00709 00710 qreal level = 1.0; 00711 Atom actualType = 0; 00712 int actualFormat = 0; 00713 unsigned long nitems = 0; 00714 unsigned long bytes = 0; 00715 00716 union { 00717 unsigned char* asUChar; 00718 unsigned long* asULong; 00719 } data = {0}; 00720 00721 Atom propertyAtom = XInternAtom(QX11Info::display(), propertyName, False); 00722 00723 int status = XGetWindowProperty(QX11Info::display(), q->effectiveWinId(), propertyAtom, 00724 0, 1, False, AnyPropertyType, 00725 &actualType, &actualFormat, &nitems, 00726 &bytes, &data.asUChar); 00727 00728 if (status == Success && actualType == XA_CARDINAL && actualFormat == 32 && nitems == 1) 00729 level = (qreal)data.asULong[0] / 0xffffffff; 00730 if (status == Success) 00731 XFree(data.asUChar); 00732 return level; 00733 } 00734 00735 void MWindowPrivate::setX11PrestartProperty(bool set) 00736 { 00737 Q_Q(MWindow); 00738 Display *dpy = QX11Info::display(); 00739 if (dpy) { 00740 Atom prestartAtom = XInternAtom(dpy, "_MEEGOTOUCH_PRESTARTED", False); 00741 unsigned char data=1; 00742 if (set) { 00743 XChangeProperty(dpy, q->effectiveWinId(), prestartAtom, 00744 XA_CARDINAL, 8, PropModeAppend, &data, 1); 00745 } else { 00746 XDeleteProperty(dpy, q->effectiveWinId(), prestartAtom); 00747 } 00748 } 00749 } 00750 00751 void MWindowPrivate::setX11OrientationAngleProperty(M::OrientationAngle angle) 00752 { 00753 Q_Q(MWindow); 00754 Display *display = QX11Info::display(); 00755 00756 if (!display) 00757 return; 00758 00759 //sometimes this class is used without valid x11 window 00760 if (q->effectiveWinId() == 0) 00761 return; 00762 00763 Atom orientationAngleAtom = XInternAtom(display, "_MEEGOTOUCH_ORIENTATION_ANGLE", False); 00764 00765 XChangeProperty(display, q->effectiveWinId(), orientationAngleAtom, XA_CARDINAL, 32, 00766 PropModeReplace, (unsigned char*)&angle, 1); 00767 } 00768 #endif 00769 00770 void MWindow::setGlobalAlpha(qreal level) 00771 { 00772 #ifdef Q_WS_X11 00773 Q_D(MWindow); 00774 d->setX11Property("_MEEGOTOUCH_GLOBAL_ALPHA", level); 00775 #else 00776 Q_UNUSED(level); 00777 #endif 00778 } 00779 00780 qreal MWindow::globalAlpha() 00781 { 00782 #ifdef Q_WS_X11 00783 Q_D(MWindow); 00784 return d->getX11Property("_MEEGOTOUCH_GLOBAL_ALPHA"); 00785 #else 00786 return 1.0; 00787 #endif 00788 } 00789 00790 void MWindow::setVideoGlobalAlpha(qreal level) 00791 { 00792 #ifdef Q_WS_X11 00793 Q_D(MWindow); 00794 d->setX11Property("_MEEGOTOUCH_VIDEO_ALPHA", level); 00795 #else 00796 Q_UNUSED(level); 00797 #endif 00798 } 00799 00800 qreal MWindow::videoGlobalAlpha() 00801 { 00802 #ifdef Q_WS_X11 00803 Q_D(MWindow); 00804 return d->getX11Property("_MEEGOTOUCH_VIDEO_ALPHA"); 00805 #else 00806 return 1.0; 00807 #endif 00808 } 00809 00810 MScene *MWindow::scene() 00811 { 00812 return qobject_cast<MScene *>(QGraphicsView::scene()); 00813 } 00814 00815 bool MWindow::isOrientationAngleLocked() const 00816 { 00817 Q_D(const MWindow); 00818 00819 return d->orientationAngleLocked; 00820 } 00821 00822 void MWindow::setOrientationAngleLocked(bool locked) 00823 { 00824 Q_D(MWindow); 00825 00826 if (d->orientationAngleLocked != locked) { 00827 d->orientationAngleLocked = locked; 00828 00829 // update from the orientation tracker if we're unlocking orientation changes 00830 if (!locked) 00831 setOrientationAngle(MOrientationTracker::instance()->orientationAngle()); 00832 } 00833 } 00834 00835 bool MWindow::isOrientationLocked() const 00836 { 00837 Q_D(const MWindow); 00838 00839 return d->orientationLocked; 00840 } 00841 00842 void MWindow::setOrientationLocked(bool locked) 00843 { 00844 Q_D(MWindow); 00845 00846 if (d->orientationLocked != locked) { 00847 d->orientationLocked = locked; 00848 00849 // update from the orientation tracker if we're unlocking orientation changes 00850 if (!locked) 00851 setOrientationAngle(MOrientationTracker::instance()->orientationAngle()); 00852 } 00853 } 00854 00855 void MWindow::lockOrientationAngle() 00856 { 00857 setOrientationAngleLocked(true); 00858 } 00859 00860 void MWindow::unlockOrientationAngle() 00861 { 00862 setOrientationAngleLocked(false); 00863 } 00864 00865 void MWindow::lockOrientation() 00866 { 00867 setOrientationLocked(true); 00868 } 00869 00870 void MWindow::unlockOrientation() 00871 { 00872 setOrientationLocked(false); 00873 } 00874 00875 void MWindow::setSceneManager(MSceneManager *sceneManager) 00876 { 00877 Q_D(MWindow); 00878 00879 if (d->sceneManager == sceneManager) { 00880 return; 00881 } 00882 00883 if (d->sceneManager) { 00884 delete d->sceneManager; 00885 } 00886 00887 d->sceneManager = sceneManager; 00888 00889 if (sceneManager) { 00890 connect(sceneManager, SIGNAL(orientationAngleChanged(M::OrientationAngle)), 00891 SIGNAL(orientationAngleChanged(M::OrientationAngle))); 00892 connect(sceneManager, SIGNAL(orientationChanged(M::Orientation)), 00893 SIGNAL(orientationChanged(M::Orientation))); 00894 connect(sceneManager, SIGNAL(orientationChangeFinished(M::Orientation)), 00895 SIGNAL(orientationChangeFinished(M::Orientation))); 00896 sceneManager->setParent(this); 00897 setScene(sceneManager->scene()); 00898 setSceneRect(QRectF(QPointF(), visibleSceneSize(M::Landscape))); 00899 centerOn(sceneRect().center()); 00900 } 00901 } 00902 00903 MSceneManager *MWindow::sceneManager() 00904 { 00905 Q_D(MWindow); 00906 00907 // A scene manager is needed. Let's create one on the fly 00908 // if we don't have one already. 00909 if (!d->sceneManager) { 00910 setSceneManager(new MSceneManager); 00911 } 00912 00913 return d->sceneManager; 00914 } 00915 00916 MSceneManager *MWindow::sceneManager() const 00917 { 00918 Q_D(const MWindow); 00919 00920 return d->sceneManager; 00921 } 00922 00923 M::Orientation MWindow::orientation() const 00924 { 00925 Q_D(const MWindow); 00926 00927 if (d->sceneManager) { 00928 return d->sceneManager->orientation(); 00929 } else { 00930 return d->orientation(d->angle); 00931 } 00932 } 00933 00934 M::OrientationAngle MWindow::orientationAngle() const 00935 { 00936 Q_D(const MWindow); 00937 00938 if (d->sceneManager) { 00939 return d->sceneManager->orientationAngle(); 00940 } else { 00941 return d->angle; 00942 } 00943 } 00944 00945 void MWindow::setOrientationAngle(M::OrientationAngle angle) 00946 { 00947 Q_D(MWindow); 00948 00949 //orientation was forced by command line option 00950 if (MComponentData::isOrientationForced()) 00951 return; 00952 00953 M::OrientationAngle targetAngle; 00954 if (d->sceneManager && d->sceneManager->d_ptr->pendingRotation) 00955 targetAngle = d->sceneManager->d_ptr->pendingRotation->angle; 00956 else 00957 targetAngle = orientationAngle(); 00958 00959 if (targetAngle != angle) { 00960 d->oldOrientation = orientation(); 00961 d->angle = angle; 00962 00963 if (d->sceneManager) { 00964 MSceneManager::TransitionMode mode = isVisible() ? 00965 MSceneManager::AnimatedTransition : 00966 MSceneManager::ImmediateTransition; 00967 00968 d->sceneManager->setOrientationAngle(angle, mode); 00969 } else { 00970 // first notify widgets, then emit the signal (in case someone 00971 // would like to connect to the signal and get correct size hints for widgets) 00972 d->notifyWidgetsAboutOrientationChange(); 00973 emit orientationAngleChanged(angle); 00974 } 00975 #ifdef Q_WS_X11 00976 d->setX11OrientationAngleProperty(angle); 00977 #endif 00978 } 00979 } 00980 00981 void MWindow::setLandscapeOrientation() 00982 { 00983 if (orientation() != M::Landscape) 00984 setOrientationAngle(M::Angle0); 00985 } 00986 00987 void MWindow::setPortraitOrientation() 00988 { 00989 if (orientation() != M::Portrait) 00990 setOrientationAngle(M::Angle270); 00991 } 00992 00993 QSize MWindow::visibleSceneSize(M::Orientation orientation) const 00994 { 00995 QSize s; 00996 00997 if (orientation == M::Landscape) { 00998 s = MDeviceProfile::instance()->resolution(); 00999 } else { 01000 s = QSize(MDeviceProfile::instance()->resolution().height(), 01001 MDeviceProfile::instance()->resolution().width()); 01002 } 01003 01004 return s; 01005 } 01006 01007 QSize MWindow::visibleSceneSize() const 01008 { 01009 return visibleSceneSize(orientation()); 01010 } 01011 01012 bool MWindow::isOnDisplay() const 01013 { 01014 Q_D(const MWindow); 01015 01016 return d->onDisplay; 01017 } 01018 01019 void MWindow::enterDisplayEvent() 01020 {} 01021 01022 void MWindow::exitDisplayEvent() 01023 {} 01024 01025 void MWindow::onDisplayChangeEvent(MOnDisplayChangeEvent *event) 01026 { 01027 Q_D(MWindow); 01028 01029 switch (event->state()) { 01030 01031 case MOnDisplayChangeEvent::FullyOnDisplay: 01032 d->displayExitedTimer.stop(); 01033 if (!d->onDisplay || !d->onDisplaySet) { 01034 d->doEnterDisplayEvent(); 01035 if (scene()) { 01036 d->propagateMOnDisplayChangeEventToScene(event); 01037 } 01038 } 01039 break; 01040 01041 case MOnDisplayChangeEvent::FullyOffDisplay: 01042 if (d->onDisplay || !d->onDisplaySet) { 01043 // displayEntered signal is emitted immediately above, but 01044 // emitting displayExited is delayed by default. Emitting 01045 // will be canceled if FullyOnDisplay event is received 01046 // during the delay. displayExitedTimer timeout will call 01047 // d->doExitDisplayEvent() which will take care of 01048 // propagating delayedMOnDisplayChangeEvent to the scene. 01049 d->sendExitDisplayEvent(true); 01050 } 01051 break; 01052 01053 default: 01054 event->ignore(); 01055 break; 01056 } 01057 } 01058 01059 void MWindow::paintEvent(QPaintEvent *event) 01060 { 01061 Q_D(MWindow); 01062 #ifdef M_USE_OPENGL 01063 if (!MApplication::softwareRendering()) { 01064 MGLES2Renderer::activate(d->glContext); 01065 } 01066 #endif // M_USE_OPENGL 01067 01068 if (isInSwitcher()) { 01069 if (!isOnDisplay()) { 01070 // TODO: also do this check for the foreground app not visible in the switcher once onDisplay is immediately 01071 // true when starting an application. right now during startup the first frames would be discarded 01072 mWarning("MWindow::paintEvent") << "Application is not visible. Paint event discarded. Make sure the application does not paint in the first place."; 01073 event->accept(); 01074 d->discardedPaintEvent = true; 01075 return; 01076 } else if (!d->timeSinceLastPaintInSwitcher.isValid()) { 01077 d->timeSinceLastPaintInSwitcher.start(); 01078 d->updateIsPending = false; 01079 } else { 01080 const int maxFpsInSwitcher = 5; 01081 const int minDelay = 1000. / maxFpsInSwitcher; 01082 qint64 msSinceLastPaint = d->timeSinceLastPaintInSwitcher.elapsed(); 01083 if (msSinceLastPaint < minDelay) { 01084 event->accept(); 01085 if (!d->updateIsPending) { 01086 // trigger a new paint event as otherwise the screen may not be up to date 01087 QTimer::singleShot(minDelay, viewport(), SLOT(update())); 01088 d->updateIsPending = true; 01089 } 01090 return; 01091 } else { 01092 d->timeSinceLastPaintInSwitcher.restart(); 01093 d->updateIsPending = false; 01094 } 01095 } 01096 } 01097 01098 QGraphicsView::paintEvent(event); 01099 } 01100 01101 bool MWindow::event(QEvent *event) 01102 { 01103 Q_D(MWindow); 01104 01105 if (event->type() == QEvent::Show || event->type() == QEvent::WindowActivate) { 01106 MComponentData::setActiveWindow(this); 01107 } else if (event->type() == QEvent::WindowStateChange) { 01108 d->windowStateChangeEvent(static_cast<QWindowStateChangeEvent *>(event)); 01109 } else if (event->type() == QEvent::Close) { 01110 d->closeEvent(static_cast<QCloseEvent *>(event)); 01111 // closeEvent() already called. 01112 return true; 01113 } else if (QEvent::KeyPress == event->type()) { 01114 bool updateNeeded = false; 01115 01116 //SIMULATION OF ROTATION FOR DEVELOPMENT PURPOSES 01117 QKeyEvent *k = static_cast<QKeyEvent *>(event); 01118 if (Qt::Key_R == k->key() && d->debugShortcutModifiersPresent(k->modifiers())) { 01119 foreach (MWindow *window, MApplication::windows()) { 01120 int newAngle = (window->orientationAngle() 01121 + ((k->modifiers() & Qt::AltModifier) ? 270 : 90)) % 360; 01122 if (!window->isOrientationAngleLocked()) { 01123 if ((!window->isOrientationLocked()) 01124 || window->orientation() == static_cast<M::Orientation>(newAngle)) { 01125 window->setOrientationAngle(static_cast<M::OrientationAngle>(newAngle)); 01126 } 01127 } 01128 } 01129 } else if (Qt::Key_T == k->key() && d->debugShortcutModifiersPresent(k->modifiers())) { 01130 MApplication::setShowPosition(!MApplication::showPosition()); 01131 updateNeeded = true; 01132 } else if (Qt::Key_S == k->key() && d->debugShortcutModifiersPresent(k->modifiers())) { 01133 MApplication::setShowSize(!MApplication::showSize()); 01134 updateNeeded = true; 01135 } else if (Qt::Key_B == k->key() && d->debugShortcutModifiersPresent(k->modifiers())) { 01136 MApplication::setShowBoundingRect(!MApplication::showBoundingRect()); 01137 updateNeeded = true; 01138 } else if (Qt::Key_M == k->key() && d->debugShortcutModifiersPresent(k->modifiers())) { 01139 MApplication::setShowMargins(!MApplication::showMargins()); 01140 updateNeeded = true; 01141 } else if (Qt::Key_N == k->key() && d->debugShortcutModifiersPresent(k->modifiers())) { 01142 MApplication::setShowObjectNames(!MApplication::showObjectNames()); 01143 MApplication::setShowStyleNames(!MApplication::showStyleNames()); 01144 updateNeeded = true; 01145 } else if (Qt::Key_F == k->key() && d->debugShortcutModifiersPresent(k->modifiers())) { 01146 MApplication::setShowFps(!MApplication::showFps()); 01147 updateNeeded = true; 01148 } else if (Qt::Key_D == k->key() && d->debugShortcutModifiersPresent(k->modifiers())) { 01149 Qt::LayoutDirection dir = MApplication::layoutDirection(); 01150 01151 if (dir == Qt::LeftToRight) 01152 dir = Qt::RightToLeft; 01153 else 01154 dir = Qt::LeftToRight; 01155 01156 MApplication::setLayoutDirection(dir); 01157 01158 updateNeeded = true; 01159 } else if (Qt::Key_L == k->key() && d->debugShortcutModifiersPresent(k->modifiers())) { 01160 // switch language 01161 QString language; 01162 01163 MLocale oldLocale; // get current system default 01164 language = oldLocale.name(); 01165 01166 if (language == "en_US_POSIX" || language.isEmpty()) 01167 language = "fi"; 01168 else if (language == "fi") 01169 language = "en"; 01170 else if (language == "en") 01171 language = "de"; 01172 else if (language == "de") 01173 language = "ar"; 01174 else if (language == "ar") 01175 language = "hu"; 01176 else if (language == "hu") 01177 language = "ur"; 01178 else if (language == "ur") 01179 language = "zh_CN"; 01180 else 01181 // engineering English: 01182 language = ""; 01183 01184 MLocale newLocale(language); 01185 MLocale::setDefault(newLocale); 01186 01187 updateNeeded = true; 01188 } else if (Qt::Key_P == k->key() && d->debugShortcutModifiersPresent(k->modifiers())) { 01189 QPixmap screenshot; 01190 screenshot = QPixmap::grabWindow(effectiveWinId()); 01191 01192 QString path; 01193 if (QDir(ImagesPath).exists()) 01194 path = ImagesPath; 01195 else 01196 path = QDir::homePath(); 01197 01198 if (!screenshot.save(QString("%1/%2-%3.png").arg(path) 01199 .arg(QDate::currentDate().toString("yyyyMMdd")) 01200 .arg(QTime::currentTime().toString("hhmmss")))) 01201 mWarning("MWindow") << "Could not save screenshot to" << path; 01202 01203 d->playScreenshotEffect(); 01204 } else if (Qt::Key_Q == k->key() && (k->modifiers() & Qt::ControlModifier)) { 01205 foreach(MWindow* window, MApplication::windows()) 01206 window->close(); 01207 } 01208 01209 if (updateNeeded) { 01210 this->viewport()->update(); 01211 } 01212 } else if (event->type() == QEvent::ApplicationLayoutDirectionChange) { 01213 // tell the scene and its items about the layout change 01214 if (scene()) { 01215 QList<QGraphicsItem *> items = scene()->items(); 01216 01217 // call setLayoutDirection_helper() for all top-level items 01218 for (int i = 0; i < items.size(); i++) { 01219 QGraphicsItem *item = items.at(i); 01220 if (scene()->items().contains(item) && !item->parentItem()) { 01221 d->handleApplicationLayoutDirectionChangeEvent(item); 01222 } 01223 } 01224 } 01225 return true; 01226 } else if (event->type() == QEvent::LanguageChange) { 01227 // Tell the scene and its top-level items about the language change 01228 if (scene()) { 01229 QList<QGraphicsItem *> items = scene()->items(); 01230 // Call handler for language change event only for top 01231 // level widgets. The handler then recurses over the 01232 // children. 01233 QList<QGraphicsItem *> itemsWithoutParents; 01234 foreach(QGraphicsItem *item, items) 01235 if(!item->parentItem()) itemsWithoutParents << item; 01236 foreach(QGraphicsItem * item, itemsWithoutParents) { 01237 d->handleLanguageChangeEvent(item); 01238 } 01239 } 01240 return true; 01241 } else if (event->type() == MOnDisplayChangeEvent::eventNumber()) { 01242 onDisplayChangeEvent(static_cast<MOnDisplayChangeEvent *>(event)); 01243 return true; 01244 } 01245 #ifdef Q_WS_X11 01246 else if (event->type() == QEvent::DynamicPropertyChange) { 01247 QDynamicPropertyChangeEvent* dynamicEvent = static_cast<QDynamicPropertyChangeEvent*>(event); 01248 if (dynamicEvent->propertyName() == FollowsCurrentApplicationWindowOrientationPropertyName) { 01249 //property was set, does not matter what value 01250 if (property(FollowsCurrentApplicationWindowOrientationPropertyName).isValid()) { 01251 mDebug("MWindow") << "window follows current app window orientation"; 01252 MOrientationTracker::instance()->d_func()->startFollowingCurrentAppWindow(this); 01253 } 01254 //propery was unset 01255 else 01256 MOrientationTracker::instance()->d_func()->stopFollowingCurrentAppWindow(this); 01257 } 01258 } 01259 #endif 01260 return QGraphicsView::event(event); 01261 } 01262 01263 void MWindow::setVisible(bool visible) 01264 { 01265 Q_D(MWindow); 01266 01267 if (visible) { 01268 01269 // This effectively overrides call to show() when in 01270 // prestarted state. 01271 if (MApplication::isPrestarted()) { 01272 return; 01273 } 01274 01275 // Set onDisplay if it's not already set, because 01276 // it is used to discard paint events and we don't have 01277 // time to wait for visibility notifies from compositor. 01278 if (!d->onDisplaySet) { 01279 d->onDisplay = true; 01280 } 01281 01282 if (MTheme::hasPendingRequests()) { 01283 // The showing of the window gets delayed until the theme 01284 // has finished to load all pixmap requests. This prevents 01285 // a flickering of the application on startup and improves 01286 // the performance. 01287 connect(MTheme::instance(), SIGNAL(pixmapRequestsFinished()), 01288 this, SLOT(_q_onPixmapRequestsFinished())); 01289 return; 01290 } else { 01291 if (!windowState().testFlag(Qt::WindowMinimized) && !MApplication::softwareRendering()) { 01292 if (MGraphicsSystemHelper::isRunningNativeGraphicssystem()) { 01293 if (!dynamic_cast<QGLWidget*>(viewport())) { 01294 d->initGLViewport(); 01295 } 01296 } else { 01297 d->initGLViewport(); 01298 } 01299 } 01300 d->isLogicallyClosed = false; 01301 } 01302 01303 #ifdef Q_WS_X11 01304 MApplicationPrivate::removeWindowFromSwitcher(effectiveWinId(), false); 01305 #endif 01306 01307 } else { 01308 MOnDisplayChangeEvent ev(false, sceneRect()); 01309 onDisplayChangeEvent(&ev); 01310 } 01311 01312 QGraphicsView::setVisible(visible); 01313 } 01314 01315 void MWindow::setCloseOnLazyShutdown(bool enable) 01316 { 01317 Q_D(MWindow); 01318 01319 d->closeOnLazyShutdown = enable; 01320 } 01321 01322 bool MWindow::closeOnLazyShutdown() const 01323 { 01324 Q_D(const MWindow); 01325 01326 return d->closeOnLazyShutdown; 01327 } 01328 01329 #include "moc_mwindow.cpp"
| Copyright © 2010 Nokia Corporation | Generated on Thu Nov 4 2010 18:14:22 (PDT) Doxygen 1.7.1 |
MeeGo Touch |