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