|
MythTV
0.25-pre
|
00001 #include "mythmainwindow.h" 00002 #include "mythmainwindow_internal.h" 00003 00004 // C headers 00005 #include <cmath> 00006 00007 // C++ headers 00008 #include <algorithm> 00009 #include <vector> 00010 using namespace std; 00011 00012 // QT headers 00013 #ifdef USE_OPENGL_PAINTER 00014 #include <QGLWidget> 00015 #endif 00016 00017 #include <QWaitCondition> 00018 #include <QApplication> 00019 #include <QTimer> 00020 #include <QDesktopWidget> 00021 #include <QHash> 00022 #include <QFile> 00023 #include <QDir> 00024 #include <QEvent> 00025 #include <QKeyEvent> 00026 #include <QKeySequence> 00027 #include <QSize> 00028 00029 // Platform headers 00030 #include "unistd.h" 00031 #ifdef QWS 00032 #include <qwindowsystem_qws.h> 00033 #endif 00034 #ifdef Q_WS_MACX_OLDQT 00035 #include <HIToolbox/Menus.h> // For GetMBarHeight() 00036 #endif 00037 00038 // libmythbase headers 00039 #include "mythdb.h" 00040 #include "mythlogging.h" 00041 #include "mythevent.h" 00042 #include "mythdirs.h" 00043 #include "compat.h" 00044 #include "mythsignalingtimer.h" 00045 #include "mythcorecontext.h" 00046 #include "mythmedia.h" 00047 00048 // libmythui headers 00049 #include "myththemebase.h" 00050 #include "screensaver.h" 00051 #include "lirc.h" 00052 #include "lircevent.h" 00053 #include "mythudplistener.h" 00054 #include "mythrender_base.h" 00055 #include "mythuistatetracker.h" 00056 00057 #ifdef USING_APPLEREMOTE 00058 #include "AppleRemoteListener.h" 00059 #endif 00060 00061 #ifdef USE_JOYSTICK_MENU 00062 #include "jsmenu.h" 00063 #include "jsmenuevent.h" 00064 #endif 00065 00066 #ifdef USING_LIBCEC 00067 #include "cecadapter.h" 00068 #endif 00069 00070 #include "mythscreentype.h" 00071 #include "mythpainter.h" 00072 #ifdef USE_OPENGL_PAINTER 00073 #include "mythpainter_ogl.h" 00074 #endif 00075 #include "mythpainter_qt.h" 00076 #include "mythgesture.h" 00077 #include "mythuihelper.h" 00078 #include "mythdialogbox.h" 00079 00080 #ifdef USING_MINGW 00081 #include "mythpainter_d3d9.h" 00082 #endif 00083 00084 #define GESTURE_TIMEOUT 1000 00085 #define STANDBY_TIMEOUT 30 // Minutes 00086 00087 #define LOC QString("MythMainWindow: ") 00088 00089 class KeyContext 00090 { 00091 public: 00092 void AddMapping(int key, QString action) 00093 { 00094 actionMap[key].append(action); 00095 } 00096 00097 bool GetMapping(int key, QStringList &actions) 00098 { 00099 if (actionMap.count(key) > 0) 00100 { 00101 actions += actionMap[key]; 00102 return true; 00103 } 00104 return false; 00105 } 00106 00107 QMap<int, QStringList> actionMap; 00108 }; 00109 00110 struct JumpData 00111 { 00112 void (*callback)(void); 00113 QString destination; 00114 QString description; 00115 bool exittomain; 00116 QString localAction; 00117 }; 00118 00119 struct MPData { 00120 QString description; 00121 MediaPlayCallback playFn; 00122 }; 00123 00124 class MythMainWindowPrivate 00125 { 00126 public: 00127 MythMainWindowPrivate() : 00128 wmult(1.0f), hmult(1.0f), 00129 screenwidth(0), screenheight(0), 00130 xbase(0), ybase(0), 00131 does_fill_screen(false), 00132 ignore_lirc_keys(false), 00133 ignore_joystick_keys(false), 00134 lircThread(NULL), 00135 #ifdef USE_JOYSTICK_MENU 00136 joystickThread(NULL), 00137 #endif 00138 00139 #ifdef USING_APPLEREMOTE 00140 appleRemoteListener(NULL), 00141 appleRemote(NULL), 00142 #endif 00143 00144 #ifdef USING_LIBCEC 00145 cecAdapter(NULL), 00146 #endif 00147 00148 exitingtomain(false), 00149 popwindows(false), 00150 00151 m_useDB(true), 00152 00153 exitmenucallback(NULL), 00154 00155 exitmenumediadevicecallback(NULL), 00156 mediadeviceforcallback(NULL), 00157 00158 escapekey(0), 00159 00160 sysEventHandler(NULL), 00161 00162 drawInterval(1000 / 70), 00163 drawTimer(NULL), 00164 mainStack(NULL), 00165 00166 painter(NULL), 00167 render(NULL), 00168 00169 AllowInput(true), 00170 00171 gesture(MythGesture()), 00172 gestureTimer(NULL), 00173 hideMouseTimer(NULL), 00174 00175 paintwin(NULL), 00176 00177 oldpaintwin(NULL), 00178 oldpainter(NULL), 00179 oldrender(NULL), 00180 00181 m_drawDisabledDepth(0), 00182 m_drawEnabled(true), 00183 00184 m_themeBase(NULL), 00185 00186 m_udpListener(NULL), 00187 00188 m_pendingUpdate(false), 00189 00190 idleTimer(NULL), 00191 standby(false) 00192 { 00193 } 00194 00195 int TranslateKeyNum(QKeyEvent *e); 00196 00197 float wmult, hmult; 00198 int screenwidth, screenheight; 00199 00200 QRect screenRect; 00201 QRect uiScreenRect; 00202 00203 int xbase, ybase; 00204 bool does_fill_screen; 00205 00206 bool ignore_lirc_keys; 00207 bool ignore_joystick_keys; 00208 00209 LIRC *lircThread; 00210 00211 #ifdef USE_JOYSTICK_MENU 00212 JoystickMenuThread *joystickThread; 00213 #endif 00214 00215 #ifdef USING_APPLEREMOTE 00216 AppleRemoteListener *appleRemoteListener; 00217 AppleRemote *appleRemote; 00218 #endif 00219 00220 #ifdef USING_LIBCEC 00221 CECAdapter* cecAdapter; 00222 #endif 00223 00224 bool exitingtomain; 00225 bool popwindows; 00226 00227 bool m_useDB; 00228 00229 QHash<QString, KeyContext *> keyContexts; 00230 QMap<int, JumpData*> jumpMap; 00231 QMap<QString, JumpData> destinationMap; 00232 QMap<QString, MPData> mediaPluginMap; 00233 00234 void (*exitmenucallback)(void); 00235 00236 void (*exitmenumediadevicecallback)(MythMediaDevice* mediadevice); 00237 MythMediaDevice * mediadeviceforcallback; 00238 00239 int escapekey; 00240 00241 QObject *sysEventHandler; 00242 00243 int drawInterval; 00244 MythSignalingTimer *drawTimer; 00245 QVector<MythScreenStack *> stackList; 00246 MythScreenStack *mainStack; 00247 00248 MythPainter *painter; 00249 MythRender *render; 00250 00251 00252 bool AllowInput; 00253 00254 QRegion repaintRegion; 00255 00256 MythGesture gesture; 00257 QTimer *gestureTimer; 00258 QTimer *hideMouseTimer; 00259 00260 /* compatibility only, FIXME remove */ 00261 std::vector<QWidget *> widgetList; 00262 00263 QWidget *paintwin; 00264 00265 QWidget *oldpaintwin; 00266 MythPainter *oldpainter; 00267 MythRender *oldrender; 00268 00269 QMutex m_drawDisableLock; 00270 QMutex m_setDrawEnabledLock; 00271 QWaitCondition m_setDrawEnabledWait; 00272 uint m_drawDisabledDepth; 00273 bool m_drawEnabled; 00274 00275 MythThemeBase *m_themeBase; 00276 MythUDPListener *m_udpListener; 00277 00278 bool m_pendingUpdate; 00279 00280 QTimer *idleTimer; 00281 bool standby; 00282 }; 00283 00284 // Make keynum in QKeyEvent be equivalent to what's in QKeySequence 00285 int MythMainWindowPrivate::TranslateKeyNum(QKeyEvent* e) 00286 { 00287 int keynum = e->key(); 00288 00289 if ((keynum != Qt::Key_Shift ) && (keynum !=Qt::Key_Control ) && 00290 (keynum != Qt::Key_Meta ) && (keynum !=Qt::Key_Alt ) && 00291 (keynum != Qt::Key_Super_L) && (keynum !=Qt::Key_Super_R ) && 00292 (keynum != Qt::Key_Hyper_L) && (keynum !=Qt::Key_Hyper_R ) && 00293 (keynum != Qt::Key_AltGr ) && (keynum !=Qt::Key_CapsLock ) && 00294 (keynum != Qt::Key_NumLock) && (keynum !=Qt::Key_ScrollLock )) 00295 { 00296 Qt::KeyboardModifiers modifiers; 00297 // if modifiers have been pressed, rebuild keynum 00298 if ((modifiers = e->modifiers()) != Qt::NoModifier) 00299 { 00300 int modnum = (((modifiers & Qt::ShiftModifier) && 00301 (keynum > 0x7f) && 00302 (keynum != Qt::Key_Backtab)) ? Qt::SHIFT : 0) | 00303 ((modifiers & Qt::ControlModifier) ? Qt::CTRL : 0) | 00304 ((modifiers & Qt::MetaModifier) ? Qt::META : 0) | 00305 ((modifiers & Qt::AltModifier) ? Qt::ALT : 0); 00306 modnum &= ~Qt::UNICODE_ACCEL; 00307 return (keynum |= modnum); 00308 } 00309 } 00310 00311 return keynum; 00312 } 00313 00314 static MythMainWindow *mainWin = NULL; 00315 static QMutex mainLock; 00316 00325 MythMainWindow *MythMainWindow::getMainWindow(const bool useDB) 00326 { 00327 if (mainWin) 00328 return mainWin; 00329 00330 QMutexLocker lock(&mainLock); 00331 00332 if (!mainWin) 00333 { 00334 mainWin = new MythMainWindow(useDB); 00335 gCoreContext->SetGUIObject(mainWin); 00336 } 00337 00338 return mainWin; 00339 } 00340 00341 void MythMainWindow::destroyMainWindow(void) 00342 { 00343 gCoreContext->SetGUIObject(NULL); 00344 delete mainWin; 00345 mainWin = NULL; 00346 } 00347 00348 MythMainWindow *GetMythMainWindow(void) 00349 { 00350 return MythMainWindow::getMainWindow(); 00351 } 00352 00353 bool HasMythMainWindow(void) 00354 { 00355 return (mainWin); 00356 } 00357 00358 void DestroyMythMainWindow(void) 00359 { 00360 MythMainWindow::destroyMainWindow(); 00361 } 00362 00363 MythPainter *GetMythPainter(void) 00364 { 00365 return MythMainWindow::getMainWindow()->GetCurrentPainter(); 00366 } 00367 00368 #ifdef USE_OPENGL_PAINTER 00369 MythPainterWindowGL::MythPainterWindowGL(MythMainWindow *win, 00370 MythMainWindowPrivate *priv, 00371 MythRenderOpenGL *rend) 00372 : QGLWidget(rend, win), 00373 parent(win), d(priv), render(rend) 00374 { 00375 setAutoBufferSwap(false); 00376 } 00377 00378 void MythPainterWindowGL::paintEvent(QPaintEvent *pe) 00379 { 00380 d->repaintRegion = d->repaintRegion.unite(pe->region()); 00381 parent->drawScreen(); 00382 } 00383 #endif 00384 00385 #ifdef USING_MINGW 00386 MythPainterWindowD3D9::MythPainterWindowD3D9(MythMainWindow *win, 00387 MythMainWindowPrivate *priv) 00388 : QGLWidget(win), 00389 parent(win), d(priv) 00390 { 00391 setAutoBufferSwap(false); 00392 } 00393 00394 void MythPainterWindowD3D9::paintEvent(QPaintEvent *pe) 00395 { 00396 d->repaintRegion = d->repaintRegion.unite(pe->region()); 00397 parent->drawScreen(); 00398 } 00399 #endif 00400 00401 MythPainterWindowQt::MythPainterWindowQt(MythMainWindow *win, 00402 MythMainWindowPrivate *priv) 00403 : QWidget(win), 00404 parent(win), d(priv) 00405 { 00406 } 00407 00408 void MythPainterWindowQt::paintEvent(QPaintEvent *pe) 00409 { 00410 d->repaintRegion = d->repaintRegion.unite(pe->region()); 00411 parent->drawScreen(); 00412 } 00413 00414 MythMainWindow::MythMainWindow(const bool useDB) 00415 : QWidget(NULL) 00416 { 00417 d = new MythMainWindowPrivate; 00418 00419 setObjectName("mainwindow"); 00420 00421 d->AllowInput = false; 00422 00423 // This prevents database errors from RegisterKey() when there is no DB: 00424 d->m_useDB = useDB; 00425 d->painter = NULL; 00426 d->paintwin = NULL; 00427 d->oldpainter = NULL; 00428 d->oldpaintwin = NULL; 00429 d->oldrender = NULL; 00430 00431 //Init(); 00432 00433 d->ignore_lirc_keys = false; 00434 d->ignore_joystick_keys = false; 00435 d->exitingtomain = false; 00436 d->popwindows = true; 00437 d->exitmenucallback = false; 00438 d->exitmenumediadevicecallback = false; 00439 d->mediadeviceforcallback = NULL; 00440 d->escapekey = Qt::Key_Escape; 00441 d->mainStack = NULL; 00442 d->sysEventHandler = NULL; 00443 00444 installEventFilter(this); 00445 00446 d->lircThread = NULL; 00447 StartLIRC(); 00448 00449 #ifdef USE_JOYSTICK_MENU 00450 d->ignore_joystick_keys = false; 00451 00452 QString joy_config_file = GetConfDir() + "/joystickmenurc"; 00453 00454 d->joystickThread = NULL; 00455 d->joystickThread = new JoystickMenuThread(this); 00456 if (!d->joystickThread->Init(joy_config_file)) 00457 d->joystickThread->start(); 00458 #endif 00459 00460 #ifdef USING_APPLEREMOTE 00461 d->appleRemoteListener = new AppleRemoteListener(this); 00462 d->appleRemote = AppleRemote::Get(); 00463 00464 d->appleRemote->setListener(d->appleRemoteListener); 00465 d->appleRemote->startListening(); 00466 if (d->appleRemote->isListeningToRemote()) 00467 d->appleRemote->start(); 00468 #endif 00469 00470 #ifdef USING_LIBCEC 00471 d->cecAdapter = new CECAdapter(); 00472 if (!d->cecAdapter->IsValid()) 00473 { 00474 delete d->cecAdapter; 00475 d->cecAdapter = NULL; 00476 } 00477 #endif 00478 00479 d->m_udpListener = new MythUDPListener(); 00480 00481 InitKeys(); 00482 00483 d->gestureTimer = new QTimer(this); 00484 connect(d->gestureTimer, SIGNAL(timeout()), this, SLOT(mouseTimeout())); 00485 d->hideMouseTimer = new QTimer(this); 00486 d->hideMouseTimer->setSingleShot(true); 00487 d->hideMouseTimer->setInterval(3000); // 3 seconds 00488 connect(d->hideMouseTimer, SIGNAL(timeout()), SLOT(HideMouseTimeout())); 00489 00490 d->drawTimer = new MythSignalingTimer(this, SLOT(animate())); 00491 d->drawTimer->start(d->drawInterval); 00492 00493 d->AllowInput = true; 00494 00495 d->repaintRegion = QRegion(QRect(0,0,0,0)); 00496 00497 d->m_drawEnabled = true; 00498 00499 connect(this, SIGNAL(signalRemoteScreenShot(QString,int,int)), 00500 this, SLOT(doRemoteScreenShot(QString,int,int)), 00501 Qt::BlockingQueuedConnection); 00502 00503 // We need to listen for playback start/end events 00504 gCoreContext->addListener(this); 00505 00506 int idletime = gCoreContext->GetNumSetting("FrontendIdleTimeout", 00507 STANDBY_TIMEOUT); 00508 if (idletime <= 0) 00509 idletime = STANDBY_TIMEOUT; 00510 00511 d->idleTimer = new QTimer(this); 00512 d->idleTimer->setSingleShot(true); 00513 d->idleTimer->setInterval(1000 * 60 * idletime); // 30 minutes 00514 connect(d->idleTimer, SIGNAL(timeout()), SLOT(IdleTimeout())); 00515 d->idleTimer->start(); 00516 } 00517 00518 MythMainWindow::~MythMainWindow() 00519 { 00520 d->drawTimer->stop(); 00521 00522 while (!d->stackList.isEmpty()) 00523 { 00524 MythScreenStack *stack = d->stackList.back(); 00525 d->stackList.pop_back(); 00526 00527 if (stack == d->mainStack) 00528 d->mainStack = NULL; 00529 00530 delete stack; 00531 } 00532 00533 delete d->m_themeBase; 00534 00535 while (!d->keyContexts.isEmpty()) 00536 { 00537 KeyContext *context = *d->keyContexts.begin(); 00538 d->keyContexts.erase(d->keyContexts.begin()); 00539 delete context; 00540 } 00541 00542 #ifdef USE_LIRC 00543 if (d->lircThread) 00544 { 00545 d->lircThread->deleteLater(); 00546 d->lircThread = NULL; 00547 } 00548 #endif 00549 00550 #ifdef USE_JOYSTICK_MENU 00551 if (d->joystickThread) 00552 { 00553 if (d->joystickThread->isRunning()) 00554 { 00555 d->joystickThread->Stop(); 00556 d->joystickThread->wait(); 00557 } 00558 00559 delete d->joystickThread; 00560 d->joystickThread = NULL; 00561 } 00562 #endif 00563 00564 #ifdef USING_APPLEREMOTE 00565 // We don't delete this, just disable its plumbing. If we create another 00566 // MythMainWindow later, AppleRemote::get() will retrieve the instance. 00567 if (d->appleRemote->isRunning()) 00568 d->appleRemote->stopListening(); 00569 00570 delete d->appleRemoteListener; 00571 #endif 00572 00573 #ifdef USING_LIBCEC 00574 if (d->cecAdapter) 00575 delete d->cecAdapter; 00576 #endif 00577 00578 delete d; 00579 } 00580 00581 MythPainter *MythMainWindow::GetCurrentPainter(void) 00582 { 00583 return d->painter; 00584 } 00585 00586 QWidget *MythMainWindow::GetPaintWindow(void) 00587 { 00588 return d->paintwin; 00589 } 00590 00591 void MythMainWindow::ShowPainterWindow(void) 00592 { 00593 if (d->paintwin) 00594 d->paintwin->show(); 00595 if (d->render) 00596 d->render->Release(); 00597 } 00598 00599 void MythMainWindow::HidePainterWindow(void) 00600 { 00601 if (d->paintwin) 00602 { 00603 d->paintwin->clearMask(); 00604 if (!(d->render && d->render->IsShared())) 00605 d->paintwin->hide(); 00606 } 00607 } 00608 00609 void MythMainWindow::ResizePainterWindow(const QSize &size) 00610 { 00611 if (!d->paintwin) 00612 return; 00613 d->paintwin->setFixedSize(size); 00614 d->paintwin->resize(size); 00615 } 00616 00617 MythRender *MythMainWindow::GetRenderDevice() 00618 { 00619 return d->render; 00620 } 00621 00622 void MythMainWindow::AddScreenStack(MythScreenStack *stack, bool main) 00623 { 00624 d->stackList.push_back(stack); 00625 if (main) 00626 d->mainStack = stack; 00627 } 00628 00629 void MythMainWindow::PopScreenStack() 00630 { 00631 delete d->stackList.back(); 00632 d->stackList.pop_back(); 00633 } 00634 00635 int MythMainWindow::GetStackCount(void) 00636 { 00637 return d->stackList.size(); 00638 } 00639 00640 MythScreenStack *MythMainWindow::GetMainStack(void) 00641 { 00642 return d->mainStack; 00643 } 00644 00645 MythScreenStack *MythMainWindow::GetStack(const QString &stackname) 00646 { 00647 QVector<MythScreenStack *>::Iterator it; 00648 for (it = d->stackList.begin(); it != d->stackList.end(); ++it) 00649 { 00650 if ((*it)->objectName() == stackname) 00651 return *it; 00652 } 00653 return NULL; 00654 } 00655 00656 MythScreenStack* MythMainWindow::GetStackAt(int pos) 00657 { 00658 if (pos >= 0 && pos < d->stackList.size()) 00659 return d->stackList.at(pos); 00660 00661 return NULL; 00662 } 00663 00664 void MythMainWindow::animate(void) 00665 { 00666 /* FIXME: remove */ 00667 if (currentWidget() || !d->m_drawEnabled) 00668 return; 00669 00670 if (!d->paintwin) 00671 return; 00672 00673 d->drawTimer->blockSignals(true); 00674 00675 bool redraw = false; 00676 00677 if (!d->repaintRegion.isEmpty()) 00678 redraw = true; 00679 00680 QVector<MythScreenStack *>::Iterator it; 00681 for (it = d->stackList.begin(); it != d->stackList.end(); ++it) 00682 { 00683 QVector<MythScreenType *> drawList; 00684 (*it)->GetDrawOrder(drawList); 00685 00686 QVector<MythScreenType *>::Iterator screenit; 00687 for (screenit = drawList.begin(); screenit != drawList.end(); 00688 ++screenit) 00689 { 00690 (*screenit)->Pulse(); 00691 00692 if ((*screenit)->NeedsRedraw()) 00693 { 00694 QRegion topDirty = (*screenit)->GetDirtyArea(); 00695 (*screenit)->ResetNeedsRedraw(); 00696 d->repaintRegion = d->repaintRegion.unite(topDirty); 00697 redraw = true; 00698 } 00699 } 00700 } 00701 00702 if (redraw && !(d->render && d->render->IsShared())) 00703 d->paintwin->update(d->repaintRegion); 00704 00705 for (it = d->stackList.begin(); it != d->stackList.end(); ++it) 00706 (*it)->ScheduleInitIfNeeded(); 00707 00708 d->drawTimer->blockSignals(false); 00709 } 00710 00711 void MythMainWindow::drawScreen(void) 00712 { 00713 /* FIXME: remove */ 00714 if (currentWidget() || !d->m_drawEnabled) 00715 return; 00716 00717 if (!d->painter->SupportsClipping()) 00718 d->repaintRegion = d->repaintRegion.unite(d->uiScreenRect); 00719 else 00720 { 00721 // Ensure that the region is not larger than the screen which 00722 // can happen with bad themes 00723 d->repaintRegion = d->repaintRegion.intersect(d->uiScreenRect); 00724 00725 // Check for any widgets that have been updated since we built 00726 // the dirty region list in ::animate() 00727 QVector<MythScreenStack *>::Iterator it; 00728 for (it = d->stackList.begin(); it != d->stackList.end(); ++it) 00729 { 00730 QVector<MythScreenType *> redrawList; 00731 (*it)->GetDrawOrder(redrawList); 00732 00733 QVector<MythScreenType *>::Iterator screenit; 00734 for (screenit = redrawList.begin(); screenit != redrawList.end(); 00735 ++screenit) 00736 { 00737 if ((*screenit)->NeedsRedraw()) 00738 { 00739 QRegion topDirty = (*screenit)->GetDirtyArea(); 00740 QVector<QRect> wrects = topDirty.rects(); 00741 for (int i = 0; i < wrects.size(); i++) 00742 { 00743 bool foundThisRect = false; 00744 QVector<QRect> drects = d->repaintRegion.rects(); 00745 for (int j = 0; j < drects.size(); j++) 00746 { 00747 if (drects[j].contains(wrects[i])) 00748 { 00749 foundThisRect = true; 00750 break; 00751 } 00752 } 00753 00754 if (!foundThisRect) 00755 return; 00756 } 00757 } 00758 } 00759 } 00760 } 00761 00762 if (!(d->render && d->render->IsShared())) 00763 draw(); 00764 00765 d->repaintRegion = QRegion(QRect(0, 0, 0, 0)); 00766 } 00767 00768 void MythMainWindow::draw(void) 00769 { 00770 if (!d->painter) 00771 return; 00772 00773 d->painter->Begin(d->paintwin); 00774 00775 QVector<QRect> rects = d->repaintRegion.rects(); 00776 00777 for (int i = 0; i < rects.size(); i++) 00778 { 00779 if (rects[i].width() == 0 || rects[i].height() == 0) 00780 continue; 00781 00782 if (rects[i] != d->uiScreenRect) 00783 d->painter->SetClipRect(rects[i]); 00784 00785 QVector<MythScreenStack *>::Iterator it; 00786 for (it = d->stackList.begin(); it != d->stackList.end(); ++it) 00787 { 00788 QVector<MythScreenType *> redrawList; 00789 (*it)->GetDrawOrder(redrawList); 00790 00791 QVector<MythScreenType *>::Iterator screenit; 00792 for (screenit = redrawList.begin(); screenit != redrawList.end(); 00793 ++screenit) 00794 { 00795 (*screenit)->Draw(d->painter, 0, 0, 255, rects[i]); 00796 } 00797 } 00798 } 00799 00800 d->painter->End(); 00801 } 00802 00803 void MythMainWindow::closeEvent(QCloseEvent *e) 00804 { 00805 if (e->spontaneous()) 00806 { 00807 QKeyEvent *key = new QKeyEvent(QEvent::KeyPress, d->escapekey, 00808 Qt::NoModifier); 00809 QCoreApplication::postEvent(this, key); 00810 e->ignore(); 00811 } 00812 else 00813 QWidget::closeEvent(e); 00814 } 00815 00816 void MythMainWindow::GrabWindow(QImage &image) 00817 { 00818 WId winid; 00819 QWidget *active = QApplication::activeWindow(); 00820 if (active) 00821 winid = active->winId(); 00822 else 00823 winid = QApplication::desktop()->winId(); 00824 00825 QPixmap p = QPixmap::grabWindow(winid); 00826 image = p.toImage(); 00827 } 00828 00829 /* This is required to allow a screenshot to be requested by another thread 00830 * other than the UI thread, and to wait for the screenshot before returning. 00831 * It is used by mythweb for the remote access screenshots 00832 */ 00833 void MythMainWindow::doRemoteScreenShot(QString filename, int x, int y) 00834 { 00835 // This will be running in the UI thread, as is required by QPixmap 00836 QStringList args; 00837 args << QString::number(x); 00838 args << QString::number(y); 00839 args << filename; 00840 00841 MythEvent me(MythEvent::MythEventMessage, ACTION_SCREENSHOT, args); 00842 qApp->sendEvent(this, &me); 00843 } 00844 00845 void MythMainWindow::RemoteScreenShot(QString filename, int x, int y) 00846 { 00847 // This will be running in a non-UI thread and is used to trigger a 00848 // function in the UI thread, and waits for completion of that handler 00849 emit signalRemoteScreenShot(filename, x, y); 00850 } 00851 00852 bool MythMainWindow::SaveScreenShot(const QImage &image, QString filename) 00853 { 00854 if (filename.isEmpty()) 00855 { 00856 QString fpath = GetMythDB()->GetSetting("ScreenShotPath", "/tmp"); 00857 filename = QString("%1/myth-screenshot-%2.png").arg(fpath) 00858 .arg(QDateTime::currentDateTime().toString("yyyy-MM-ddThh-mm-ss.zzz")); 00859 } 00860 00861 QString extension = filename.section('.', -1, -1); 00862 if (extension == "jpg") 00863 extension = "JPEG"; 00864 else 00865 extension = "PNG"; 00866 00867 LOG(VB_GENERAL, LOG_INFO, QString("Saving screenshot to %1 (%2x%3)") 00868 .arg(filename).arg(image.width()).arg(image.height())); 00869 00870 if (image.save(filename, extension.toAscii(), 100)) 00871 { 00872 LOG(VB_GENERAL, LOG_INFO, "MythMainWindow::screenShot succeeded"); 00873 return true; 00874 } 00875 00876 LOG(VB_GENERAL, LOG_INFO, "MythMainWindow::screenShot Failed!"); 00877 return false; 00878 } 00879 00880 bool MythMainWindow::ScreenShot(int w, int h, QString filename) 00881 { 00882 QImage img; 00883 GrabWindow(img); 00884 if (w <= 0) 00885 w = img.width(); 00886 if (h <= 0) 00887 h = img.height(); 00888 00889 img = img.scaled(w, h, Qt::KeepAspectRatio, Qt::SmoothTransformation); 00890 return SaveScreenShot(img, filename); 00891 } 00892 00893 bool MythMainWindow::event(QEvent *e) 00894 { 00895 if (!updatesEnabled() && (e->type() == QEvent::UpdateRequest)) 00896 d->m_pendingUpdate = true; 00897 00898 if (e->type() == QEvent::Show && !e->spontaneous()) 00899 { 00900 QCoreApplication::postEvent( 00901 this, new QEvent(MythEvent::kMythPostShowEventType)); 00902 } 00903 00904 if (e->type() == MythEvent::kMythPostShowEventType) 00905 { 00906 raise(); 00907 activateWindow(); 00908 return true; 00909 } 00910 00911 #ifdef USING_APPLEREMOTE 00912 if (d->appleRemote) 00913 { 00914 if (e->type() == QEvent::WindowActivate) 00915 d->appleRemote->startListening(); 00916 00917 if (e->type() == QEvent::WindowDeactivate) 00918 d->appleRemote->stopListening(); 00919 } 00920 #endif 00921 00922 return QWidget::event(e); 00923 } 00924 00925 void MythMainWindow::Init(void) 00926 { 00927 GetMythUI()->GetScreenSettings(d->xbase, d->screenwidth, d->wmult, 00928 d->ybase, d->screenheight, d->hmult); 00929 00930 if (GetMythDB()->GetNumSetting("GuiOffsetX") > 0 || 00931 GetMythDB()->GetNumSetting("GuiWidth") > 0 || 00932 GetMythDB()->GetNumSetting("GuiOffsetY") > 0 || 00933 GetMythDB()->GetNumSetting("GuiHeight") > 0) 00934 d->does_fill_screen = false; 00935 else 00936 d->does_fill_screen = true; 00937 00938 // Set window border based on fullscreen attribute 00939 Qt::WindowFlags flags = Qt::Window; 00940 00941 if (!GetMythDB()->GetNumSetting("RunFrontendInWindow", 0)) 00942 { 00943 LOG(VB_GENERAL, LOG_INFO, "Using Frameless Window"); 00944 flags |= Qt::FramelessWindowHint; 00945 } 00946 00947 // Workaround Qt/Windows playback bug? 00948 #ifdef _WIN32 00949 flags |= Qt::MSWindowsOwnDC; 00950 #endif 00951 00952 setWindowFlags(flags); 00953 00954 if (d->does_fill_screen && !GetMythUI()->IsGeometryOverridden()) 00955 { 00956 LOG(VB_GENERAL, LOG_INFO, "Using Full Screen Window"); 00957 setWindowState(Qt::WindowFullScreen); 00958 } 00959 00960 d->screenRect = QRect(d->xbase, d->ybase, d->screenwidth, d->screenheight); 00961 d->uiScreenRect = QRect(0, 0, d->screenwidth, d->screenheight); 00962 00963 setGeometry(d->xbase, d->ybase, d->screenwidth, d->screenheight); 00964 setFixedSize(QSize(d->screenwidth, d->screenheight)); 00965 00966 GetMythUI()->ThemeWidget(this); 00967 Show(); 00968 00969 if (!GetMythDB()->GetNumSetting("HideMouseCursor", 0)) 00970 setMouseTracking(true); // Required for mouse cursor auto-hide 00971 // Set cursor call must come after Show() to work on some systems. 00972 ShowMouseCursor(false); 00973 00974 move(d->xbase, d->ybase); 00975 00976 if (d->paintwin) 00977 { 00978 d->oldpaintwin = d->paintwin; 00979 d->paintwin = NULL; 00980 d->drawTimer->stop(); 00981 } 00982 00983 if (d->painter) 00984 { 00985 d->oldpainter = d->painter; 00986 d->painter = NULL; 00987 } 00988 00989 if (d->render) 00990 { 00991 d->oldrender = d->render; 00992 d->render = NULL; 00993 } 00994 00995 QString painter = GetMythDB()->GetSetting("UIPainter", "auto"); 00996 #ifdef USING_MINGW 00997 if (painter == "auto" || painter == "d3d9") 00998 { 00999 LOG(VB_GENERAL, LOG_INFO, "Using the D3D9 painter"); 01000 d->painter = new MythD3D9Painter(); 01001 d->paintwin = new MythPainterWindowD3D9(this, d); 01002 } 01003 #endif 01004 #ifdef USE_OPENGL_PAINTER 01005 if ((painter == "auto" && (!d->painter && !d->paintwin)) || 01006 painter.contains("opengl")) 01007 { 01008 LOG(VB_GENERAL, LOG_INFO, "Trying the OpenGL painter"); 01009 d->painter = new MythOpenGLPainter(); 01010 d->render = MythRenderOpenGL::Create(painter); 01011 MythRenderOpenGL *gl = dynamic_cast<MythRenderOpenGL*>(d->render); 01012 d->paintwin = new MythPainterWindowGL(this, d, gl); 01013 QGLWidget *qgl = dynamic_cast<QGLWidget *>(d->paintwin); 01014 if (qgl) 01015 { 01016 bool teardown = false; 01017 if (!qgl->isValid()) 01018 { 01019 LOG(VB_GENERAL, LOG_ERR, "Failed to create OpenGL painter. " 01020 "Check your OpenGL installation."); 01021 teardown = true; 01022 } 01023 else if (painter == "auto" && gl && !gl->IsRecommendedRenderer()) 01024 { 01025 LOG(VB_GENERAL, LOG_WARNING, 01026 "OpenGL painter not recommended with this system's " 01027 "hardware/drivers. Falling back to Qt painter."); 01028 teardown = true; 01029 } 01030 if (teardown) 01031 { 01032 delete d->painter; 01033 d->painter = NULL; 01034 delete d->paintwin; 01035 d->paintwin = NULL; 01036 d->render = NULL; // deleted by the painterwindow 01037 } 01038 else 01039 gl->Init(); 01040 } 01041 } 01042 #endif 01043 01044 if (!d->painter && !d->paintwin) 01045 { 01046 LOG(VB_GENERAL, LOG_INFO, "Using the Qt painter"); 01047 d->painter = new MythQtPainter(); 01048 d->paintwin = new MythPainterWindowQt(this, d); 01049 } 01050 01051 if (!d->paintwin) 01052 { 01053 LOG(VB_GENERAL, LOG_ERR, "MythMainWindow failed to create a " 01054 "painter window."); 01055 return; 01056 } 01057 01058 if (d->painter->GetName() != "Qt") 01059 { 01060 setAttribute(Qt::WA_NoSystemBackground); 01061 setAutoFillBackground(false); 01062 } 01063 01064 d->paintwin->move(0, 0); 01065 ResizePainterWindow(size()); 01066 d->paintwin->raise(); 01067 ShowPainterWindow(); 01068 if (!GetMythDB()->GetNumSetting("HideMouseCursor", 0)) 01069 d->paintwin->setMouseTracking(true); // Required for mouse cursor auto-hide 01070 01071 GetMythUI()->UpdateImageCache(); 01072 if (d->m_themeBase) 01073 d->m_themeBase->Reload(); 01074 else 01075 d->m_themeBase = new MythThemeBase(); 01076 } 01077 01078 void MythMainWindow::InitKeys() 01079 { 01080 RegisterKey("Global", ACTION_UP, QT_TRANSLATE_NOOP("MythControls", 01081 "Up Arrow"), "Up"); 01082 RegisterKey("Global", ACTION_DOWN, QT_TRANSLATE_NOOP("MythControls", 01083 "Down Arrow"), "Down"); 01084 RegisterKey("Global", ACTION_LEFT, QT_TRANSLATE_NOOP("MythControls", 01085 "Left Arrow"), "Left"); 01086 RegisterKey("Global", ACTION_RIGHT, QT_TRANSLATE_NOOP("MythControls", 01087 "Right Arrow"), "Right"); 01088 RegisterKey("Global", "NEXT", QT_TRANSLATE_NOOP("MythControls", 01089 "Move to next widget"), "Tab"); 01090 RegisterKey("Global", "PREVIOUS", QT_TRANSLATE_NOOP("MythControls", 01091 "Move to preview widget"), "Backtab"); 01092 RegisterKey("Global", ACTION_SELECT, QT_TRANSLATE_NOOP("MythControls", 01093 "Select"), "Return,Enter,Space"); 01094 RegisterKey("Global", "BACKSPACE", QT_TRANSLATE_NOOP("MythControls", 01095 "Backspace"), "Backspace"); 01096 RegisterKey("Global", "ESCAPE", QT_TRANSLATE_NOOP("MythControls", 01097 "Escape"), "Esc"); 01098 RegisterKey("Global", "MENU", QT_TRANSLATE_NOOP("MythControls", 01099 "Pop-up menu"), "M"); 01100 RegisterKey("Global", "INFO", QT_TRANSLATE_NOOP("MythControls", 01101 "More information"), "I"); 01102 RegisterKey("Global", "DELETE", QT_TRANSLATE_NOOP("MythControls", 01103 "Delete"), "D"); 01104 RegisterKey("Global", "EDIT", QT_TRANSLATE_NOOP("MythControls", 01105 "Edit"), "E"); 01106 RegisterKey("Global", ACTION_SCREENSHOT, QT_TRANSLATE_NOOP("MythControls", 01107 "Save screenshot"), ""); 01108 RegisterKey("Global", ACTION_HANDLEMEDIA, QT_TRANSLATE_NOOP("MythControls", 01109 "Play a media resource"), ""); 01110 01111 RegisterKey("Global", "PAGEUP", QT_TRANSLATE_NOOP("MythControls", 01112 "Page Up"), "PgUp"); 01113 RegisterKey("Global", "PAGEDOWN", QT_TRANSLATE_NOOP("MythControls", 01114 "Page Down"), "PgDown"); 01115 RegisterKey("Global", "PAGETOP", QT_TRANSLATE_NOOP("MythControls", 01116 "Page to top of list"), ""); 01117 RegisterKey("Global", "PAGEMIDDLE", QT_TRANSLATE_NOOP("MythControls", 01118 "Page to middle of list"), ""); 01119 RegisterKey("Global", "PAGEBOTTOM", QT_TRANSLATE_NOOP("MythControls", 01120 "Page to bottom of list"), ""); 01121 01122 RegisterKey("Global", "PREVVIEW", QT_TRANSLATE_NOOP("MythControls", 01123 "Previous View"), "Home"); 01124 RegisterKey("Global", "NEXTVIEW", QT_TRANSLATE_NOOP("MythControls", 01125 "Next View"), "End"); 01126 01127 RegisterKey("Global", "HELP", QT_TRANSLATE_NOOP("MythControls", 01128 "Help"), "F1"); 01129 RegisterKey("Global", "EJECT", QT_TRANSLATE_NOOP("MythControls" 01130 ,"Eject Removable Media"), ""); 01131 01132 RegisterKey("Global", "CUT", QT_TRANSLATE_NOOP("MythControls", 01133 "Cut text from textedit"), "Ctrl+X"); 01134 RegisterKey("Global", "COPY", QT_TRANSLATE_NOOP("MythControls" 01135 ,"Copy text from textedit"), "Ctrl+C"); 01136 RegisterKey("Global", "PASTE", QT_TRANSLATE_NOOP("MythControls", 01137 "Paste text into textedit"), "Ctrl+V"); 01138 RegisterKey("Global", "UNDO", QT_TRANSLATE_NOOP("MythControls", 01139 "Undo"), "Ctrl+Z"); 01140 RegisterKey("Global", "REDO", QT_TRANSLATE_NOOP("MythControls", 01141 "Redo"), "Ctrl+Y"); 01142 RegisterKey("Global", "SEARCH", QT_TRANSLATE_NOOP("MythControls", 01143 "Show incremental search dialog"), "Ctrl+S"); 01144 01145 RegisterKey("Global", ACTION_0, QT_TRANSLATE_NOOP("MythControls","0"), "0"); 01146 RegisterKey("Global", ACTION_1, QT_TRANSLATE_NOOP("MythControls","1"), "1"); 01147 RegisterKey("Global", ACTION_2, QT_TRANSLATE_NOOP("MythControls","2"), "2"); 01148 RegisterKey("Global", ACTION_3, QT_TRANSLATE_NOOP("MythControls","3"), "3"); 01149 RegisterKey("Global", ACTION_4, QT_TRANSLATE_NOOP("MythControls","4"), "4"); 01150 RegisterKey("Global", ACTION_5, QT_TRANSLATE_NOOP("MythControls","5"), "5"); 01151 RegisterKey("Global", ACTION_6, QT_TRANSLATE_NOOP("MythControls","6"), "6"); 01152 RegisterKey("Global", ACTION_7, QT_TRANSLATE_NOOP("MythControls","7"), "7"); 01153 RegisterKey("Global", ACTION_8, QT_TRANSLATE_NOOP("MythControls","8"), "8"); 01154 RegisterKey("Global", ACTION_9, QT_TRANSLATE_NOOP("MythControls","9"), "9"); 01155 01156 RegisterKey("Global", ACTION_TVPOWERON, QT_TRANSLATE_NOOP("MythControls", 01157 "Turn the display on"), ""); 01158 RegisterKey("Global", ACTION_TVPOWEROFF, QT_TRANSLATE_NOOP("MythControls", 01159 "Turn the display off"), ""); 01160 01161 RegisterKey("Global", "SYSEVENT01", QT_TRANSLATE_NOOP("MythControls", 01162 "Trigger System Key Event #1"), ""); 01163 RegisterKey("Global", "SYSEVENT02", QT_TRANSLATE_NOOP("MythControls", 01164 "Trigger System Key Event #2"), ""); 01165 RegisterKey("Global", "SYSEVENT03", QT_TRANSLATE_NOOP("MythControls", 01166 "Trigger System Key Event #3"), ""); 01167 RegisterKey("Global", "SYSEVENT04", QT_TRANSLATE_NOOP("MythControls", 01168 "Trigger System Key Event #4"), ""); 01169 RegisterKey("Global", "SYSEVENT05", QT_TRANSLATE_NOOP("MythControls", 01170 "Trigger System Key Event #5"), ""); 01171 RegisterKey("Global", "SYSEVENT06", QT_TRANSLATE_NOOP("MythControls", 01172 "Trigger System Key Event #6"), ""); 01173 RegisterKey("Global", "SYSEVENT07", QT_TRANSLATE_NOOP("MythControls", 01174 "Trigger System Key Event #7"), ""); 01175 RegisterKey("Global", "SYSEVENT08", QT_TRANSLATE_NOOP("MythControls", 01176 "Trigger System Key Event #8"), ""); 01177 RegisterKey("Global", "SYSEVENT09", QT_TRANSLATE_NOOP("MythControls", 01178 "Trigger System Key Event #9"), ""); 01179 RegisterKey("Global", "SYSEVENT10", QT_TRANSLATE_NOOP("MythControls", 01180 "Trigger System Key Event #10"), ""); 01181 01182 // these are for the html viewer widget (MythUIWebBrowser) 01183 RegisterKey("Browser", "ZOOMIN", QT_TRANSLATE_NOOP("MythControls", 01184 "Zoom in on browser window"), ".,>"); 01185 RegisterKey("Browser", "ZOOMOUT", QT_TRANSLATE_NOOP("MythControls", 01186 "Zoom out on browser window"), ",,<"); 01187 RegisterKey("Browser", "TOGGLEINPUT", QT_TRANSLATE_NOOP("MythControls", 01188 "Toggle where keyboard input goes to"), "F1"); 01189 01190 RegisterKey("Browser", "MOUSEUP", QT_TRANSLATE_NOOP("MythControls", 01191 "Move mouse pointer up"), "2"); 01192 RegisterKey("Browser", "MOUSEDOWN", QT_TRANSLATE_NOOP("MythControls", 01193 "Move mouse pointer down"), "8"); 01194 RegisterKey("Browser", "MOUSELEFT", QT_TRANSLATE_NOOP("MythControls", 01195 "Move mouse pointer left"), "4"); 01196 RegisterKey("Browser", "MOUSERIGHT", QT_TRANSLATE_NOOP("MythControls", 01197 "Move mouse pointer right"), "6"); 01198 RegisterKey("Browser", "MOUSELEFTBUTTON", QT_TRANSLATE_NOOP("MythControls", 01199 "Mouse Left button click"), "5"); 01200 01201 RegisterKey("Browser", "PAGEDOWN", QT_TRANSLATE_NOOP("MythControls", 01202 "Scroll down half a page"), "9"); 01203 RegisterKey("Browser", "PAGEUP", QT_TRANSLATE_NOOP("MythControls", 01204 "Scroll up half a page"), "3"); 01205 RegisterKey("Browser", "PAGELEFT", QT_TRANSLATE_NOOP("MythControls", 01206 "Scroll left half a page"), "7"); 01207 RegisterKey("Browser", "PAGERIGHT", QT_TRANSLATE_NOOP("MythControls", 01208 "Scroll right half a page"), "1"); 01209 01210 RegisterKey("Browser", "NEXTLINK", QT_TRANSLATE_NOOP("MythControls", 01211 "Move selection to next link"), "Z"); 01212 RegisterKey("Browser", "PREVIOUSLINK", QT_TRANSLATE_NOOP("MythControls", 01213 "Move selection to previous link"), "Q"); 01214 RegisterKey("Browser", "FOLLOWLINK", QT_TRANSLATE_NOOP("MythControls", 01215 "Follow selected link"), "Return,Space,Enter"); 01216 RegisterKey("Browser", "HISTORYBACK", QT_TRANSLATE_NOOP("MythControls", 01217 "Go back to previous page"), "R,Backspace"); 01218 RegisterKey("Browser", "HISTORYFORWARD", QT_TRANSLATE_NOOP("MythControls", 01219 "Go forward to previous page"), "F"); 01220 01221 RegisterKey("Main Menu", "EXIT", QT_TRANSLATE_NOOP("MythControls", 01222 "System Exit"), ""); 01223 RegisterKey("Main Menu", "EXITPROMPT", QT_TRANSLATE_NOOP("MythControls", 01224 "Display System Exit Prompt"), "Esc"); 01225 } 01226 01227 void MythMainWindow::ReloadKeys() 01228 { 01229 ClearKeyContext("Global"); 01230 ClearKeyContext("Browser"); 01231 ClearKeyContext("Main Menu"); 01232 InitKeys(); 01233 } 01234 01235 void MythMainWindow::ReinitDone(void) 01236 { 01237 delete d->oldpainter; 01238 d->oldpainter = NULL; 01239 01240 delete d->oldpaintwin; 01241 d->oldpaintwin = NULL; 01242 01243 // For OpenGL contexts (at least), deleting the painter window also 01244 // deletes the render context 01245 d->oldrender = NULL; 01246 01247 d->paintwin->move(0, 0); 01248 d->paintwin->setFixedSize(size()); 01249 d->paintwin->raise(); 01250 ShowPainterWindow(); 01251 01252 d->drawTimer->start(1000 / 70); 01253 } 01254 01255 void MythMainWindow::Show(void) 01256 { 01257 show(); 01258 #ifdef Q_WS_MACX_OLDQT 01259 if (d->does_fill_screen) 01260 HideMenuBar(); 01261 else 01262 ShowMenuBar(); 01263 #endif 01264 } 01265 01266 /* FIXME compatibility only */ 01267 void MythMainWindow::attach(QWidget *child) 01268 { 01269 #ifdef USING_MINGW 01270 # ifdef _MSC_VER 01271 # pragma message( "TODO FIXME MythMainWindow::attach() does not always work on MS Windows!") 01272 # else 01273 # warning TODO FIXME MythMainWindow::attach() does not always work on MS Windows! 01274 # endif 01275 01276 // if windows are created on different threads, 01277 // or if setFocus() is called from a thread other than the main UI thread, 01278 // setFocus() hangs the thread that called it 01279 LOG(VB_GENERAL, LOG_ERR, 01280 QString("MythMainWindow::attach old: %1, new: %2, thread: %3") 01281 .arg(currentWidget() ? currentWidget()->objectName() : "none") 01282 .arg(child->objectName()) 01283 .arg(::GetCurrentThreadId())); 01284 #endif 01285 if (currentWidget()) 01286 currentWidget()->setEnabled(false); 01287 01288 d->widgetList.push_back(child); 01289 child->winId(); 01290 child->raise(); 01291 child->setFocus(); 01292 child->setMouseTracking(true); 01293 } 01294 01295 void MythMainWindow::detach(QWidget *child) 01296 { 01297 std::vector<QWidget*>::iterator it = 01298 std::find(d->widgetList.begin(), d->widgetList.end(), child); 01299 01300 if (it == d->widgetList.end()) 01301 { 01302 LOG(VB_GENERAL, LOG_ERR, "Could not find widget to detach"); 01303 return; 01304 } 01305 01306 d->widgetList.erase(it); 01307 QWidget *current = currentWidget(); 01308 01309 if (current) 01310 { 01311 current->setEnabled(true); 01312 current->setFocus(); 01313 current->setMouseTracking(true); 01314 } 01315 01316 if (d->exitingtomain) 01317 { 01318 QCoreApplication::postEvent( 01319 this, new QEvent(MythEvent::kExitToMainMenuEventType)); 01320 } 01321 } 01322 01323 QWidget *MythMainWindow::currentWidget(void) 01324 { 01325 if (d->widgetList.size() > 0) 01326 return d->widgetList.back(); 01327 return NULL; 01328 } 01329 /* FIXME: end compatibility */ 01330 01331 uint MythMainWindow::PushDrawDisabled(void) 01332 { 01333 QMutexLocker locker(&d->m_drawDisableLock); 01334 d->m_drawDisabledDepth++; 01335 if (d->m_drawDisabledDepth && d->m_drawEnabled) 01336 SetDrawEnabled(false); 01337 return d->m_drawDisabledDepth; 01338 } 01339 01340 uint MythMainWindow::PopDrawDisabled(void) 01341 { 01342 QMutexLocker locker(&d->m_drawDisableLock); 01343 if (d->m_drawDisabledDepth) 01344 { 01345 d->m_drawDisabledDepth--; 01346 if (!d->m_drawDisabledDepth && !d->m_drawEnabled) 01347 SetDrawEnabled(true); 01348 } 01349 return d->m_drawDisabledDepth; 01350 } 01351 01352 void MythMainWindow::SetDrawEnabled(bool enable) 01353 { 01354 QMutexLocker locker(&d->m_setDrawEnabledLock); 01355 01356 if (!gCoreContext->IsUIThread()) 01357 { 01358 QCoreApplication::postEvent( 01359 this, new MythEvent( 01360 (enable) ? 01361 MythEvent::kEnableDrawingEventType : 01362 MythEvent::kDisableDrawingEventType)); 01363 01364 while (QCoreApplication::hasPendingEvents()) 01365 d->m_setDrawEnabledWait.wait(&d->m_setDrawEnabledLock); 01366 01367 return; 01368 } 01369 01370 setUpdatesEnabled(enable); 01371 d->m_drawEnabled = enable; 01372 01373 if (enable) 01374 { 01375 if (d->m_pendingUpdate) 01376 { 01377 QApplication::postEvent(this, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority); 01378 d->m_pendingUpdate = false; 01379 } 01380 d->drawTimer->start(1000 / 70); 01381 ShowPainterWindow(); 01382 } 01383 else 01384 { 01385 HidePainterWindow(); 01386 d->drawTimer->stop(); 01387 } 01388 01389 d->m_setDrawEnabledWait.wakeAll(); 01390 } 01391 01392 void MythMainWindow::SetEffectsEnabled(bool enable) 01393 { 01394 QVector<MythScreenStack *>::Iterator it; 01395 for (it = d->stackList.begin(); it != d->stackList.end(); ++it) 01396 { 01397 if (enable) 01398 (*it)->EnableEffects(); 01399 else 01400 (*it)->DisableEffects(); 01401 } 01402 } 01403 01404 bool MythMainWindow::IsExitingToMain(void) const 01405 { 01406 return d->exitingtomain; 01407 } 01408 01409 void MythMainWindow::ExitToMainMenu(void) 01410 { 01411 bool jumpdone = !(d->popwindows); 01412 01413 d->exitingtomain = true; 01414 01415 /* compatibility code, remove, FIXME */ 01416 QWidget *current = currentWidget(); 01417 if (current && d->exitingtomain && d->popwindows) 01418 { 01419 if (current->objectName() != QString("mainmenu")) 01420 { 01421 if (current->objectName() == QString("video playback window")) 01422 { 01423 MythEvent *me = new MythEvent("EXIT_TO_MENU"); 01424 QCoreApplication::postEvent(current, me); 01425 } 01426 else if (current->inherits("MythDialog")) 01427 { 01428 QKeyEvent *key = new QKeyEvent(QEvent::KeyPress, d->escapekey, 01429 Qt::NoModifier); 01430 QObject *key_target = getTarget(*key); 01431 QCoreApplication::postEvent(key_target, key); 01432 } 01433 return; 01434 } 01435 else 01436 jumpdone = true; 01437 } 01438 01439 MythScreenStack *toplevel = GetMainStack(); 01440 if (toplevel && d->popwindows) 01441 { 01442 MythScreenType *screen = toplevel->GetTopScreen(); 01443 if (screen && screen->objectName() != QString("mainmenu")) 01444 { 01445 if (screen->objectName() == QString("video playback window")) 01446 { 01447 MythEvent *me = new MythEvent("EXIT_TO_MENU"); 01448 QCoreApplication::postEvent(screen, me); 01449 } 01450 else 01451 { 01452 QKeyEvent *key = new QKeyEvent(QEvent::KeyPress, d->escapekey, 01453 Qt::NoModifier); 01454 QCoreApplication::postEvent(this, key); 01455 } 01456 return; 01457 } 01458 else 01459 jumpdone = true; 01460 } 01461 01462 if (jumpdone) 01463 { 01464 d->exitingtomain = false; 01465 d->popwindows = true; 01466 if (d->exitmenucallback) 01467 { 01468 void (*callback)(void) = d->exitmenucallback; 01469 d->exitmenucallback = NULL; 01470 callback(); 01471 } 01472 else if (d->exitmenumediadevicecallback) 01473 { 01474 void (*callback)(MythMediaDevice*) = d->exitmenumediadevicecallback; 01475 MythMediaDevice * mediadevice = d->mediadeviceforcallback; 01476 d->mediadeviceforcallback = NULL; 01477 callback(mediadevice); 01478 } 01479 } 01480 } 01481 01492 bool MythMainWindow::TranslateKeyPress(const QString &context, 01493 QKeyEvent *e, QStringList &actions, 01494 bool allowJumps) 01495 { 01496 actions.clear(); 01497 01498 // Special case for custom QKeyEvent where the action is embedded directly 01499 // in the QKeyEvent text property. Used by MythFEXML http extension 01500 if (e->key() == 0 && !e->text().isEmpty() && 01501 e->modifiers() == Qt::NoModifier) 01502 { 01503 QString action = e->text(); 01504 // check if it is a jumppoint 01505 if (!d->destinationMap.contains(action)) 01506 { 01507 actions.append(action); 01508 return false; 01509 } 01510 01511 if (allowJumps) 01512 { 01513 // This does not filter the jump based on the current location but 01514 // is consistent with handling of other actions that do not need 01515 // a keybinding. The network control code tries to match 01516 // GetCurrentLocation with the jumppoint but matching is utterly 01517 // inconsistent e.g. mainmenu<->Main Menu, Playback<->Live TV 01518 JumpTo(action); 01519 return true; 01520 } 01521 01522 return false; 01523 } 01524 01525 int keynum = d->TranslateKeyNum(e); 01526 01527 QStringList localActions; 01528 if (allowJumps && (d->jumpMap.count(keynum) > 0) && 01529 (!d->jumpMap[keynum]->localAction.isEmpty()) && 01530 (d->keyContexts.value(context)) && 01531 (d->keyContexts.value(context)->GetMapping(keynum, localActions))) 01532 { 01533 if (localActions.contains(d->jumpMap[keynum]->localAction)) 01534 allowJumps = false; 01535 } 01536 01537 if (allowJumps && d->jumpMap.count(keynum) > 0 && 01538 !d->jumpMap[keynum]->exittomain && d->exitmenucallback == NULL) 01539 { 01540 void (*callback)(void) = d->jumpMap[keynum]->callback; 01541 callback(); 01542 return true; 01543 } 01544 01545 if (allowJumps && 01546 d->jumpMap.count(keynum) > 0 && d->exitmenucallback == NULL) 01547 { 01548 d->exitingtomain = true; 01549 d->exitmenucallback = d->jumpMap[keynum]->callback; 01550 QCoreApplication::postEvent( 01551 this, new QEvent(MythEvent::kExitToMainMenuEventType)); 01552 return true; 01553 } 01554 01555 if (d->keyContexts.value(context)) 01556 d->keyContexts.value(context)->GetMapping(keynum, actions); 01557 01558 if (context != "Global") 01559 d->keyContexts.value("Global")->GetMapping(keynum, actions); 01560 01561 return false; 01562 } 01563 01564 void MythMainWindow::ClearKey(const QString &context, const QString &action) 01565 { 01566 KeyContext * keycontext = d->keyContexts.value(context); 01567 if (keycontext == NULL) return; 01568 01569 QMutableMapIterator<int, QStringList> it(keycontext->actionMap); 01570 while (it.hasNext()) 01571 { 01572 it.next(); 01573 QStringList list = it.value(); 01574 01575 list.removeAll(action); 01576 if (list.isEmpty()) 01577 it.remove(); 01578 } 01579 } 01580 01581 void MythMainWindow::ClearKeyContext(const QString &context) 01582 { 01583 KeyContext *keycontext = d->keyContexts.value(context); 01584 if (keycontext != NULL) 01585 keycontext->actionMap.clear(); 01586 } 01587 01588 void MythMainWindow::BindKey(const QString &context, const QString &action, 01589 const QString &key) 01590 { 01591 QKeySequence keyseq(key); 01592 01593 if (!d->keyContexts.contains(context)) 01594 d->keyContexts.insert(context, new KeyContext()); 01595 01596 for (unsigned int i = 0; i < keyseq.count(); i++) 01597 { 01598 int keynum = keyseq[i]; 01599 keynum &= ~Qt::UNICODE_ACCEL; 01600 01601 QStringList dummyaction(""); 01602 if (d->keyContexts.value(context)->GetMapping(keynum, dummyaction)) 01603 { 01604 LOG(VB_GENERAL, LOG_WARNING, 01605 QString("Key %1 is bound to multiple actions in context %2.") 01606 .arg(key).arg(context)); 01607 } 01608 01609 d->keyContexts.value(context)->AddMapping(keynum, action); 01610 #if 0 01611 LOG(VB_GENERAL, LOG_DEBUG, QString("Binding: %1 to action: %2 (%3)") 01612 .arg(key).arg(action).arg(context)); 01613 #endif 01614 01615 if (action == "ESCAPE" && context == "Global" && i == 0) 01616 d->escapekey = keynum; 01617 } 01618 } 01619 01620 void MythMainWindow::RegisterKey(const QString &context, const QString &action, 01621 const QString &description, const QString &key) 01622 { 01623 QString keybind = key; 01624 01625 MSqlQuery query(MSqlQuery::InitCon()); 01626 01627 if (d->m_useDB && query.isConnected()) 01628 { 01629 query.prepare("SELECT keylist, description FROM keybindings WHERE " 01630 "context = :CONTEXT AND action = :ACTION AND " 01631 "hostname = :HOSTNAME ;"); 01632 query.bindValue(":CONTEXT", context); 01633 query.bindValue(":ACTION", action); 01634 query.bindValue(":HOSTNAME", GetMythDB()->GetHostName()); 01635 01636 if (query.exec() && query.next()) 01637 { 01638 keybind = query.value(0).toString(); 01639 QString db_description = query.value(1).toString(); 01640 01641 // Update keybinding description if changed 01642 if (db_description != description) 01643 { 01644 LOG(VB_GENERAL, LOG_NOTICE, 01645 "Updating keybinding description..."); 01646 query.prepare( 01647 "UPDATE keybindings " 01648 "SET description = :DESCRIPTION " 01649 "WHERE context = :CONTEXT AND " 01650 " action = :ACTION AND " 01651 " hostname = :HOSTNAME"); 01652 01653 query.bindValue(":DESCRIPTION", description); 01654 query.bindValue(":CONTEXT", context); 01655 query.bindValue(":ACTION", action); 01656 query.bindValue(":HOSTNAME", GetMythDB()->GetHostName()); 01657 01658 if (!query.exec() && !(GetMythDB()->SuppressDBMessages())) 01659 { 01660 MythDB::DBError("Update Keybinding", query); 01661 } 01662 } 01663 } 01664 else 01665 { 01666 QString inskey = keybind; 01667 01668 query.prepare("INSERT INTO keybindings (context, action, " 01669 "description, keylist, hostname) VALUES " 01670 "( :CONTEXT, :ACTION, :DESCRIPTION, :KEYLIST, " 01671 ":HOSTNAME );"); 01672 query.bindValue(":CONTEXT", context); 01673 query.bindValue(":ACTION", action); 01674 query.bindValue(":DESCRIPTION", description); 01675 query.bindValue(":KEYLIST", inskey); 01676 query.bindValue(":HOSTNAME", GetMythDB()->GetHostName()); 01677 01678 if (!query.exec() && !(GetMythDB()->SuppressDBMessages())) 01679 { 01680 MythDB::DBError("Insert Keybinding", query); 01681 } 01682 } 01683 } 01684 01685 BindKey(context, action, keybind); 01686 } 01687 01688 QString MythMainWindow::GetKey(const QString &context, 01689 const QString &action) const 01690 { 01691 MSqlQuery query(MSqlQuery::InitCon()); 01692 if (!query.isConnected()) 01693 return "?"; 01694 01695 query.prepare("SELECT keylist " 01696 "FROM keybindings " 01697 "WHERE context = :CONTEXT AND " 01698 " action = :ACTION AND " 01699 " hostname = :HOSTNAME"); 01700 query.bindValue(":CONTEXT", context); 01701 query.bindValue(":ACTION", action); 01702 query.bindValue(":HOSTNAME", GetMythDB()->GetHostName()); 01703 01704 if (!query.exec() || !query.isActive() || !query.next()) 01705 return "?"; 01706 01707 return query.value(0).toString(); 01708 } 01709 01710 void MythMainWindow::ClearJump(const QString &destination) 01711 { 01712 /* make sure that the jump point exists (using [] would add it)*/ 01713 if (d->destinationMap.find(destination) == d->destinationMap.end()) 01714 { 01715 LOG(VB_GENERAL, LOG_ERR, 01716 "Cannot clear ficticious jump point" + destination); 01717 return; 01718 } 01719 01720 QMutableMapIterator<int, JumpData*> it(d->jumpMap); 01721 while (it.hasNext()) 01722 { 01723 it.next(); 01724 JumpData *jd = it.value(); 01725 if (jd->destination == destination) 01726 it.remove(); 01727 } 01728 } 01729 01730 01731 void MythMainWindow::BindJump(const QString &destination, const QString &key) 01732 { 01733 /* make sure the jump point exists */ 01734 if (d->destinationMap.find(destination) == d->destinationMap.end()) 01735 { 01736 LOG(VB_GENERAL, LOG_ERR, 01737 "Cannot bind to ficticious jump point" + destination); 01738 return; 01739 } 01740 01741 QKeySequence keyseq(key); 01742 01743 for (unsigned int i = 0; i < keyseq.count(); i++) 01744 { 01745 int keynum = keyseq[i]; 01746 keynum &= ~Qt::UNICODE_ACCEL; 01747 01748 if (d->jumpMap.count(keynum) == 0) 01749 { 01750 #if 0 01751 LOG(VB_GENERAL, LOG_DEBUG, QString("Binding: %1 to JumpPoint: %2") 01752 .arg(keybind).arg(destination)); 01753 #endif 01754 01755 d->jumpMap[keynum] = &d->destinationMap[destination]; 01756 } 01757 else 01758 { 01759 LOG(VB_GENERAL, LOG_WARNING, 01760 QString("Key %1 is already bound to a jump point.").arg(key)); 01761 } 01762 } 01763 #if 0 01764 else 01765 LOG(VB_GENERAL, LOG_DEBUG, 01766 QString("JumpPoint: %2 exists, no keybinding") .arg(destination)); 01767 #endif 01768 } 01769 01770 void MythMainWindow::RegisterJump(const QString &destination, 01771 const QString &description, 01772 const QString &key, void (*callback)(void), 01773 bool exittomain, QString localAction) 01774 { 01775 QString keybind = key; 01776 01777 MSqlQuery query(MSqlQuery::InitCon()); 01778 if (query.isConnected()) 01779 { 01780 query.prepare("SELECT keylist FROM jumppoints WHERE " 01781 "destination = :DEST and hostname = :HOST ;"); 01782 query.bindValue(":DEST", destination); 01783 query.bindValue(":HOST", GetMythDB()->GetHostName()); 01784 01785 if (query.exec() && query.next()) 01786 { 01787 keybind = query.value(0).toString(); 01788 } 01789 else 01790 { 01791 QString inskey = keybind; 01792 01793 query.prepare("INSERT INTO jumppoints (destination, description, " 01794 "keylist, hostname) VALUES ( :DEST, :DESC, :KEYLIST, " 01795 ":HOST );"); 01796 query.bindValue(":DEST", destination); 01797 query.bindValue(":DESC", description); 01798 query.bindValue(":KEYLIST", inskey); 01799 query.bindValue(":HOST", GetMythDB()->GetHostName()); 01800 01801 if (!query.exec() || !query.isActive()) 01802 { 01803 MythDB::DBError("Insert Jump Point", query); 01804 } 01805 } 01806 } 01807 01808 JumpData jd = 01809 { callback, destination, description, exittomain, localAction }; 01810 d->destinationMap[destination] = jd; 01811 01812 BindJump(destination, keybind); 01813 } 01814 01815 void MythMainWindow::ClearAllJumps() 01816 { 01817 QList<QString> destinations = d->destinationMap.keys(); 01818 QList<QString>::Iterator it; 01819 for (it = destinations.begin(); it != destinations.end(); ++it) 01820 ClearJump(*it); 01821 } 01822 01823 void MythMainWindow::JumpTo(const QString& destination, bool pop) 01824 { 01825 if (d->destinationMap.count(destination) > 0 && d->exitmenucallback == NULL) 01826 { 01827 d->exitingtomain = true; 01828 d->popwindows = pop; 01829 d->exitmenucallback = d->destinationMap[destination].callback; 01830 QCoreApplication::postEvent( 01831 this, new QEvent(MythEvent::kExitToMainMenuEventType)); 01832 return; 01833 } 01834 } 01835 01836 bool MythMainWindow::DestinationExists(const QString& destination) const 01837 { 01838 return (d->destinationMap.count(destination) > 0) ? true : false; 01839 } 01840 01841 QStringList MythMainWindow::EnumerateDestinations(void) const 01842 { 01843 return d->destinationMap.keys(); 01844 } 01845 01846 void MythMainWindow::RegisterMediaPlugin(const QString &name, 01847 const QString &desc, 01848 MediaPlayCallback fn) 01849 { 01850 if (d->mediaPluginMap.count(name) == 0) 01851 { 01852 LOG(VB_GENERAL, LOG_NOTICE, 01853 QString("Registering %1 as a media playback plugin.").arg(name)); 01854 MPData mpd = {desc, fn}; 01855 d->mediaPluginMap[name] = mpd; 01856 } 01857 else 01858 { 01859 LOG(VB_GENERAL, LOG_NOTICE, 01860 QString("%1 is already registered as a media playback plugin.") 01861 .arg(name)); 01862 } 01863 } 01864 01865 bool MythMainWindow::HandleMedia(const QString &handler, const QString &mrl, 01866 const QString &plot, const QString &title, 01867 const QString &subtitle, 01868 const QString &director, int season, 01869 int episode, const QString &inetref, 01870 int lenMins, const QString &year, 01871 const QString &id, bool useBookmarks) 01872 { 01873 QString lhandler(handler); 01874 if (lhandler.isEmpty()) 01875 lhandler = "Internal"; 01876 01877 // Let's see if we have a plugin that matches the handler name... 01878 if (d->mediaPluginMap.count(lhandler)) 01879 { 01880 d->mediaPluginMap[lhandler].playFn(mrl, plot, title, subtitle, 01881 director, season, episode, 01882 inetref, lenMins, year, id, 01883 useBookmarks); 01884 return true; 01885 } 01886 01887 return false; 01888 } 01889 01890 void MythMainWindow::HandleTVPower(bool poweron) 01891 { 01892 #ifdef USING_LIBCEC 01893 if (d->cecAdapter) 01894 d->cecAdapter->Action((poweron) ? ACTION_TVPOWERON : ACTION_TVPOWEROFF); 01895 #else 01896 (void) poweron; 01897 #endif 01898 } 01899 01900 void MythMainWindow::AllowInput(bool allow) 01901 { 01902 d->AllowInput = allow; 01903 } 01904 01905 void MythMainWindow::mouseTimeout(void) 01906 { 01907 MythGestureEvent *e; 01908 01909 /* complete the stroke if its our first timeout */ 01910 if (d->gesture.recording()) 01911 { 01912 d->gesture.stop(); 01913 } 01914 01915 /* get the last gesture */ 01916 e = d->gesture.gesture(); 01917 01918 if (e->gesture() < MythGestureEvent::Click) 01919 QCoreApplication::postEvent(this, e); 01920 } 01921 01922 bool MythMainWindow::eventFilter(QObject *, QEvent *e) 01923 { 01924 MythGestureEvent *ge; 01925 01926 /* Don't let anything through if input is disallowed. */ 01927 if (!d->AllowInput) 01928 return true; 01929 01930 switch (e->type()) 01931 { 01932 case QEvent::KeyPress: 01933 { 01934 ResetIdleTimer(); 01935 QKeyEvent *ke = dynamic_cast<QKeyEvent*>(e); 01936 01937 // Work around weird GCC run-time bug. Only manifest on Mac OS X 01938 if (!ke) 01939 ke = static_cast<QKeyEvent *>(e); 01940 01941 if (currentWidget()) 01942 { 01943 ke->accept(); 01944 QWidget *current = currentWidget(); 01945 if (current && current->isEnabled()) 01946 qApp->notify(current, ke); 01947 01948 break; 01949 } 01950 01951 QVector<MythScreenStack *>::Iterator it; 01952 for (it = d->stackList.end()-1; it != d->stackList.begin()-1; --it) 01953 { 01954 MythScreenType *top = (*it)->GetTopScreen(); 01955 if (top) 01956 { 01957 if (top->keyPressEvent(ke)) 01958 return true; 01959 01960 // Note: The following break prevents keypresses being 01961 // sent to windows below popups 01962 if ((*it)->objectName() == "popup stack") 01963 break; 01964 } 01965 } 01966 break; 01967 } 01968 case QEvent::MouseButtonPress: 01969 { 01970 ResetIdleTimer(); 01971 ShowMouseCursor(true); 01972 if (!d->gesture.recording()) 01973 { 01974 d->gesture.start(); 01975 d->gesture.record(dynamic_cast<QMouseEvent*>(e)->pos()); 01976 01977 /* start a single shot timer */ 01978 d->gestureTimer->start(GESTURE_TIMEOUT); 01979 01980 return true; 01981 } 01982 break; 01983 } 01984 case QEvent::MouseButtonRelease: 01985 { 01986 ResetIdleTimer(); 01987 ShowMouseCursor(true); 01988 if (d->gestureTimer->isActive()) 01989 d->gestureTimer->stop(); 01990 01991 if (currentWidget()) 01992 break; 01993 01994 if (d->gesture.recording()) 01995 { 01996 d->gesture.stop(); 01997 ge = d->gesture.gesture(); 01998 01999 /* handle clicks separately */ 02000 if (ge->gesture() == MythGestureEvent::Click) 02001 { 02002 QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent*>(e); 02003 if (!mouseEvent) 02004 return false; 02005 02006 QVector<MythScreenStack *>::iterator it; 02007 QPoint p = mouseEvent->pos(); 02008 02009 ge->SetPosition(p); 02010 02011 MythGestureEvent::Button button = MythGestureEvent::NoButton; 02012 switch (mouseEvent->button()) 02013 { 02014 case Qt::LeftButton : 02015 button = MythGestureEvent::LeftButton; 02016 break; 02017 case Qt::RightButton : 02018 button = MythGestureEvent::RightButton; 02019 break; 02020 case Qt::MidButton : 02021 button = MythGestureEvent::MiddleButton; 02022 break; 02023 case Qt::XButton1 : 02024 button = MythGestureEvent::Aux1Button; 02025 break; 02026 case Qt::XButton2 : 02027 button = MythGestureEvent::Aux2Button; 02028 break; 02029 default : 02030 button = MythGestureEvent::NoButton; 02031 } 02032 02033 ge->SetButton(button); 02034 02035 for (it = d->stackList.end()-1; it != d->stackList.begin()-1; 02036 --it) 02037 { 02038 MythScreenType *screen = (*it)->GetTopScreen(); 02039 02040 if (!screen || !screen->ContainsPoint(p)) 02041 continue; 02042 02043 if (screen->gestureEvent(ge)) 02044 break; 02045 02046 // Note: The following break prevents clicks being 02047 // sent to windows below popups 02048 // 02049 // we want to permit this in some cases, e.g. 02050 // when the music miniplayer is on screen or a 02051 // non-interactive alert/news scroller. So these 02052 // things need to be in a third or more stack 02053 if ((*it)->objectName() == "popup stack") 02054 break; 02055 } 02056 02057 delete ge; 02058 } 02059 else 02060 QCoreApplication::postEvent(this, ge); 02061 02062 return true; 02063 } 02064 break; 02065 } 02066 case QEvent::MouseMove: 02067 { 02068 ResetIdleTimer(); 02069 ShowMouseCursor(true); 02070 if (d->gesture.recording()) 02071 { 02072 /* reset the timer */ 02073 d->gestureTimer->stop(); 02074 d->gestureTimer->start(GESTURE_TIMEOUT); 02075 02076 d->gesture.record(dynamic_cast<QMouseEvent*>(e)->pos()); 02077 return true; 02078 } 02079 break; 02080 } 02081 case QEvent::Wheel: 02082 { 02083 ResetIdleTimer(); 02084 ShowMouseCursor(true); 02085 QWheelEvent* qmw = dynamic_cast<QWheelEvent*>(e); 02086 int delta = qmw->delta(); 02087 if (delta>0) 02088 { 02089 qmw->accept(); 02090 QKeyEvent *key = new QKeyEvent(QEvent::KeyPress, Qt::Key_Up, 02091 Qt::NoModifier); 02092 QObject *key_target = getTarget(*key); 02093 if (!key_target) 02094 QCoreApplication::postEvent(this, key); 02095 else 02096 QCoreApplication::postEvent(key_target, key); 02097 } 02098 if (delta<0) 02099 { 02100 qmw->accept(); 02101 QKeyEvent *key = new QKeyEvent(QEvent::KeyPress, Qt::Key_Down, 02102 Qt::NoModifier); 02103 QObject *key_target = getTarget(*key); 02104 if (!key_target) 02105 QCoreApplication::postEvent(this, key); 02106 else 02107 QCoreApplication::postEvent(key_target, key); 02108 } 02109 break; 02110 } 02111 default: 02112 break; 02113 } 02114 02115 return false; 02116 } 02117 02118 void MythMainWindow::customEvent(QEvent *ce) 02119 { 02120 if (ce->type() == MythGestureEvent::kEventType) 02121 { 02122 MythGestureEvent *ge = static_cast<MythGestureEvent*>(ce); 02123 MythScreenStack *toplevel = GetMainStack(); 02124 if (toplevel && !currentWidget()) 02125 { 02126 MythScreenType *screen = toplevel->GetTopScreen(); 02127 if (screen) 02128 screen->gestureEvent(ge); 02129 } 02130 LOG(VB_GUI, LOG_DEBUG, QString("Gesture: %1") .arg(QString(*ge))); 02131 } 02132 else if (ce->type() == MythEvent::kExitToMainMenuEventType && 02133 d->exitingtomain) 02134 { 02135 ExitToMainMenu(); 02136 } 02137 else if (ce->type() == ExternalKeycodeEvent::kEventType) 02138 { 02139 ExternalKeycodeEvent *eke = static_cast<ExternalKeycodeEvent *>(ce); 02140 int keycode = eke->getKeycode(); 02141 02142 QKeyEvent key(QEvent::KeyPress, keycode, Qt::NoModifier); 02143 02144 QObject *key_target = getTarget(key); 02145 if (!key_target) 02146 QCoreApplication::sendEvent(this, &key); 02147 else 02148 QCoreApplication::sendEvent(key_target, &key); 02149 } 02150 #if defined(USE_LIRC) || defined(USING_APPLEREMOTE) 02151 else if (ce->type() == LircKeycodeEvent::kEventType && 02152 !d->ignore_lirc_keys) 02153 { 02154 LircKeycodeEvent *lke = static_cast<LircKeycodeEvent *>(ce); 02155 02156 if (LircKeycodeEvent::kLIRCInvalidKeyCombo == lke->modifiers()) 02157 { 02158 LOG(VB_GENERAL, LOG_WARNING, 02159 QString("Attempt to convert LIRC key sequence '%1' " 02160 "to a Qt key sequence failed.") 02161 .arg(lke->lirctext())); 02162 } 02163 else 02164 { 02165 GetMythUI()->ResetScreensaver(); 02166 if (GetMythUI()->GetScreenIsAsleep()) 02167 return; 02168 02169 QKeyEvent key(lke->keytype(), lke->key(), 02170 lke->modifiers(), lke->text()); 02171 02172 QObject *key_target = getTarget(key); 02173 if (!key_target) 02174 QCoreApplication::sendEvent(this, &key); 02175 else 02176 QCoreApplication::sendEvent(key_target, &key); 02177 } 02178 } 02179 #endif 02180 #ifdef USE_JOYSTICK_MENU 02181 else if (ce->type() == JoystickKeycodeEvent::kEventType && 02182 !d->ignore_joystick_keys) 02183 { 02184 JoystickKeycodeEvent *jke = static_cast<JoystickKeycodeEvent *>(ce); 02185 int keycode = jke->getKeycode(); 02186 02187 if (keycode) 02188 { 02189 GetMythUI()->ResetScreensaver(); 02190 if (GetMythUI()->GetScreenIsAsleep()) 02191 return; 02192 02193 Qt::KeyboardModifiers mod = Qt::KeyboardModifiers(keycode & Qt::MODIFIER_MASK); 02194 int k = (keycode & ~Qt::MODIFIER_MASK); /* trim off the mod */ 02195 QString text; 02196 02197 if (k & Qt::UNICODE_ACCEL) 02198 { 02199 QChar c(k & ~Qt::UNICODE_ACCEL); 02200 text = QString(c); 02201 } 02202 02203 QKeyEvent key(jke->isKeyDown() ? QEvent::KeyPress : 02204 QEvent::KeyRelease, k, mod, text); 02205 02206 QObject *key_target = getTarget(key); 02207 if (!key_target) 02208 QCoreApplication::sendEvent(this, &key); 02209 else 02210 QCoreApplication::sendEvent(key_target, &key); 02211 } 02212 else 02213 { 02214 LOG(VB_GENERAL, LOG_WARNING, 02215 QString("attempt to convert '%1' to a key sequence failed. " 02216 "Fix your key mappings.") 02217 .arg(jke->getJoystickMenuText())); 02218 } 02219 } 02220 #endif 02221 else if (ce->type() == MythMediaEvent::kEventType) 02222 { 02223 MythMediaEvent *me = static_cast<MythMediaEvent*>(ce); 02224 02225 // A listener based system might be more efficient, but we should never 02226 // have that many screens open at once so impact should be minimal. 02227 // 02228 // This approach is simpler for everyone to follow. Plugin writers 02229 // don't have to worry about adding their screens to the list because 02230 // all screens receive media events. 02231 // 02232 // Events are even sent to hidden or backgrounded screens, this avoids 02233 // the need for those to poll for changes when they become visible again 02234 // however this needs to be kept in mind if media changes trigger 02235 // actions which would not be appropriate when the screen doesn't have 02236 // focus. It is the programmers responsibility to ignore events when 02237 // necessary. 02238 QVector<MythScreenStack *>::Iterator it; 02239 for (it = d->stackList.begin(); it != d->stackList.end(); ++it) 02240 { 02241 QVector<MythScreenType *> screenList; 02242 (*it)->GetScreenList(screenList); 02243 QVector<MythScreenType *>::Iterator sit; 02244 for (sit = screenList.begin(); sit != screenList.end(); ++sit) 02245 { 02246 MythScreenType *screen = (*sit); 02247 if (screen) 02248 screen->mediaEvent(me); 02249 } 02250 } 02251 02252 // Debugging 02253 MythMediaDevice *device = me->getDevice(); 02254 if (device) 02255 { 02256 LOG(VB_GENERAL, LOG_DEBUG, QString("Media Event: %1 - %2") 02257 .arg(device->getDevicePath()).arg(device->getStatus())); 02258 } 02259 } 02260 else if (ce->type() == ScreenSaverEvent::kEventType) 02261 { 02262 ScreenSaverEvent *sse = static_cast<ScreenSaverEvent *>(ce); 02263 switch (sse->getSSEventType()) 02264 { 02265 case ScreenSaverEvent::ssetDisable: 02266 { 02267 GetMythUI()->DoDisableScreensaver(); 02268 break; 02269 } 02270 case ScreenSaverEvent::ssetRestore: 02271 { 02272 GetMythUI()->DoRestoreScreensaver(); 02273 break; 02274 } 02275 case ScreenSaverEvent::ssetReset: 02276 { 02277 GetMythUI()->DoResetScreensaver(); 02278 break; 02279 } 02280 default: 02281 { 02282 LOG(VB_GENERAL, LOG_ERR, 02283 QString("Unknown ScreenSaverEvent type: %1") 02284 .arg(sse->getSSEventType())); 02285 } 02286 } 02287 } 02288 else if (ce->type() == MythEvent::kPushDisableDrawingEventType) 02289 { 02290 PushDrawDisabled(); 02291 } 02292 else if (ce->type() == MythEvent::kPopDisableDrawingEventType) 02293 { 02294 PopDrawDisabled(); 02295 } 02296 else if (ce->type() == MythEvent::kDisableDrawingEventType) 02297 { 02298 SetDrawEnabled(false); 02299 } 02300 else if (ce->type() == MythEvent::kEnableDrawingEventType) 02301 { 02302 SetDrawEnabled(true); 02303 } 02304 else if (ce->type() == MythEvent::kLockInputDevicesEventType) 02305 { 02306 LockInputDevices(true); 02307 } 02308 else if (ce->type() == MythEvent::kUnlockInputDevicesEventType) 02309 { 02310 LockInputDevices(false); 02311 } 02312 else if ((MythEvent::Type)(ce->type()) == MythEvent::MythEventMessage) 02313 { 02314 MythEvent *me = (MythEvent *)ce; 02315 QString message = me->Message(); 02316 02317 if (message.startsWith(ACTION_HANDLEMEDIA)) 02318 { 02319 if (me->ExtraDataCount() == 1) 02320 HandleMedia("Internal", me->ExtraData(0)); 02321 else if (me->ExtraDataCount() == 11) 02322 HandleMedia("Internal", me->ExtraData(0), 02323 me->ExtraData(1), me->ExtraData(2), 02324 me->ExtraData(3), me->ExtraData(4), 02325 me->ExtraData(5).toInt(), me->ExtraData(6).toInt(), 02326 me->ExtraData(7), me->ExtraData(8).toInt(), 02327 me->ExtraData(9), me->ExtraData(10), true); 02328 else 02329 LOG(VB_GENERAL, LOG_ERR, "Failed to handle media"); 02330 } 02331 else if (message.startsWith(ACTION_SCREENSHOT)) 02332 { 02333 int width = 0; 02334 int height = 0; 02335 QString filename; 02336 02337 if (me->ExtraDataCount() >= 2) 02338 { 02339 width = me->ExtraData(0).toInt(); 02340 height = me->ExtraData(1).toInt(); 02341 02342 if (me->ExtraDataCount() == 3) 02343 filename = me->ExtraData(2); 02344 } 02345 ScreenShot(width, height, filename); 02346 } 02347 else if (message == ACTION_GETSTATUS) 02348 { 02349 QVariantMap state; 02350 state.insert("state", "idle"); 02351 state.insert("menutheme", 02352 GetMythDB()->GetSetting("menutheme", "defaultmenu")); 02353 state.insert("currentlocation", GetMythUI()->GetCurrentLocation()); 02354 MythUIStateTracker::SetState(state); 02355 } 02356 else if (message.startsWith("PLAYBACK_START")) 02357 { 02358 PauseIdleTimer(true); 02359 } 02360 else if (message.startsWith("PLAYBACK_END")) 02361 { 02362 PauseIdleTimer(false); 02363 } 02364 } 02365 else if ((MythEvent::Type)(ce->type()) == MythEvent::MythUserMessage) 02366 { 02367 MythEvent *me = (MythEvent *)ce; 02368 QString message = me->Message(); 02369 02370 if (!message.isEmpty()) 02371 ShowOkPopup(message); 02372 } 02373 } 02374 02375 QObject *MythMainWindow::getTarget(QKeyEvent &key) 02376 { 02377 QObject *key_target = NULL; 02378 02379 if (!currentWidget()) 02380 return key_target; 02381 02382 key_target = QWidget::keyboardGrabber(); 02383 02384 if (!key_target) 02385 { 02386 QWidget *focus_widget = qApp->focusWidget(); 02387 if (focus_widget && focus_widget->isEnabled()) 02388 { 02389 key_target = focus_widget; 02390 02391 // Yes this is special code for handling the 02392 // the escape key. 02393 if (key.key() == d->escapekey && focus_widget->topLevelWidget()) 02394 key_target = focus_widget->topLevelWidget(); 02395 } 02396 } 02397 02398 if (!key_target) 02399 key_target = this; 02400 02401 return key_target; 02402 } 02403 02404 int MythMainWindow::NormalizeFontSize(int pointSize) 02405 { 02406 float floatSize = pointSize; 02407 float desired = 100.0; 02408 02409 #ifdef USING_MINGW 02410 // logicalDpiY not supported in QT3/win. 02411 int logicalDpiY = 100; 02412 HDC hdc = GetDC(NULL); 02413 if (hdc) 02414 { 02415 logicalDpiY = GetDeviceCaps(hdc, LOGPIXELSY); 02416 ReleaseDC(NULL, hdc); 02417 } 02418 #else 02419 int logicalDpiY = this->logicalDpiY(); 02420 #endif 02421 02422 // adjust for screen resolution relative to 100 dpi 02423 floatSize = floatSize * desired / logicalDpiY; 02424 // adjust for myth GUI size relative to 800x600 02425 floatSize = floatSize * d->hmult; 02426 // round to the nearest point size 02427 pointSize = (int)(floatSize + 0.5); 02428 02429 return pointSize; 02430 } 02431 02432 MythRect MythMainWindow::NormRect(const MythRect &rect) 02433 { 02434 MythRect ret; 02435 ret.setWidth((int)(rect.width() * d->wmult)); 02436 ret.setHeight((int)(rect.height() * d->hmult)); 02437 ret.moveTopLeft(QPoint((int)(rect.x() * d->wmult), 02438 (int)(rect.y() * d->hmult))); 02439 ret = ret.normalized(); 02440 02441 return ret; 02442 } 02443 02444 QPoint MythMainWindow::NormPoint(const QPoint &point) 02445 { 02446 QPoint ret; 02447 ret.setX((int)(point.x() * d->wmult)); 02448 ret.setY((int)(point.y() * d->hmult)); 02449 02450 return ret; 02451 } 02452 02453 QSize MythMainWindow::NormSize(const QSize &size) 02454 { 02455 QSize ret; 02456 ret.setWidth((int)(size.width() * d->wmult)); 02457 ret.setHeight((int)(size.height() * d->hmult)); 02458 02459 return ret; 02460 } 02461 02462 int MythMainWindow::NormX(const int x) 02463 { 02464 return (int)(x * d->wmult); 02465 } 02466 02467 int MythMainWindow::NormY(const int y) 02468 { 02469 return (int)(y * d->hmult); 02470 } 02471 02472 void MythMainWindow::SetScalingFactors(float wmult, float hmult) 02473 { 02474 d->wmult = wmult; 02475 d->hmult = hmult; 02476 } 02477 02478 QRect MythMainWindow::GetUIScreenRect(void) 02479 { 02480 return d->uiScreenRect; 02481 } 02482 02483 void MythMainWindow::SetUIScreenRect(QRect &rect) 02484 { 02485 d->uiScreenRect = rect; 02486 } 02487 02488 int MythMainWindow::GetDrawInterval() const 02489 { 02490 return d->drawInterval; 02491 } 02492 02493 void MythMainWindow::StartLIRC(void) 02494 { 02495 #ifdef USE_LIRC 02496 if (d->lircThread) 02497 { 02498 d->lircThread->deleteLater(); 02499 d->lircThread = NULL; 02500 } 02501 02502 QString config_file = GetConfDir() + "/lircrc"; 02503 if (!QFile::exists(config_file)) 02504 config_file = QDir::homePath() + "/.lircrc"; 02505 02506 /* lircd socket moved from /dev/ to /var/run/lirc/ in lirc 0.8.6 */ 02507 QString lirc_socket = "/dev/lircd"; 02508 if (!QFile::exists(lirc_socket)) 02509 lirc_socket = "/var/run/lirc/lircd"; 02510 02511 d->lircThread = new LIRC( 02512 this, 02513 GetMythDB()->GetSetting("LircSocket", lirc_socket), 02514 "mythtv", config_file); 02515 02516 if (d->lircThread->Init()) 02517 { 02518 d->lircThread->start(); 02519 } 02520 else 02521 { 02522 d->lircThread->deleteLater(); 02523 d->lircThread = NULL; 02524 } 02525 #endif 02526 } 02527 02528 void MythMainWindow::LockInputDevices( bool locked ) 02529 { 02530 if( locked ) 02531 LOG(VB_GENERAL, LOG_INFO, "Locking input devices"); 02532 else 02533 LOG(VB_GENERAL, LOG_INFO, "Unlocking input devices"); 02534 02535 #ifdef USE_LIRC 02536 d->ignore_lirc_keys = locked; 02537 #endif 02538 02539 #ifdef USE_JOYSTICK_MENU 02540 d->ignore_joystick_keys = locked; 02541 #endif 02542 } 02543 02544 void MythMainWindow::ShowMouseCursor(bool show) 02545 { 02546 if (show && GetMythDB()->GetNumSetting("HideMouseCursor", 0)) 02547 return; 02548 #ifdef QWS 02549 QWSServer::setCursorVisible(show); 02550 #endif 02551 // Set cursor call must come after Show() to work on some systems. 02552 setCursor(show ? (Qt::ArrowCursor) : (Qt::BlankCursor)); 02553 02554 if (show) 02555 d->hideMouseTimer->start(); 02556 } 02557 02558 void MythMainWindow::HideMouseTimeout(void) 02559 { 02560 ShowMouseCursor(false); 02561 } 02562 02563 void MythMainWindow::ResetIdleTimer(void) 02564 { 02565 // If the timer isn't active then it's been paused 02566 if (!d->idleTimer->isActive() && !d->standby) 02567 return; 02568 02569 if (d->standby) 02570 ExitStandby(); 02571 02572 d->idleTimer->start(); 02573 } 02574 02575 void MythMainWindow::PauseIdleTimer(bool pause) 02576 { 02577 if (pause) 02578 d->idleTimer->stop(); 02579 else 02580 d->idleTimer->start(); 02581 02582 ResetIdleTimer(); 02583 } 02584 02585 void MythMainWindow::IdleTimeout(void) 02586 { 02587 EnterStandby(); 02588 } 02589 02590 void MythMainWindow::EnterStandby() 02591 { 02592 int idletimeout = gCoreContext->GetNumSetting("FrontendIdleTimeout", 02593 STANDBY_TIMEOUT); 02594 LOG(VB_GENERAL, LOG_NOTICE, QString("Entering standby mode after " 02595 "%1 minutes of inactivity") 02596 .arg(idletimeout)); 02597 //JumpTo("Main Menu"); 02598 d->standby = true; 02599 gCoreContext->AllowShutdown(); 02600 } 02601 02602 void MythMainWindow::ExitStandby() 02603 { 02604 LOG(VB_GENERAL, LOG_NOTICE, "Leaving standby mode"); 02605 d->standby = false; 02606 gCoreContext->BlockShutdown(); 02607 } 02608 02609 02610 /* vim: set expandtab tabstop=4 shiftwidth=4: */
1.7.6.1