Skip to content
Browse files

Fix remote (mythweb) screenshots

Seems in the rework done in fa9f32b, there
was an incorrect assumption as to the use of GetScreenShot as used over the
frontend's control socket.  It is actually used by mythweb to give a
rudimentary (so far) remote control setup, and the screenshot has to be
actually sent back to mythweb for this to work.  Also, since this is going
over the public internet in many cases, the size of PNG is not acceptable, so
specific support was made for JPG for this use.  I kinda reverted part of that
changeset in the process of fixing this regression.

To take a screenshot in any thread other than the UI thread, it is necessary
to get the UI thread to do the work.  This is why we need a signal to force
the code to cross the thread boundary.  If not, QPixmap spews a warning (which
can become fatal with QT_FATAL_WARNINGS set, or in some debug modes).

The flow for a remote (i.e. non-UI) thread to get a screenshot is:
MythMainWindow *window = GetMythMainWindow();
window->RemoteScreenShot(sFileName, nWidth, nHeight);

This calls a method in the MythMainWindow class that will then signal (and
block until the slot has returned) that is also in the MythMainWindow class
to cross the boundary into the UI thread.  The slot will then create an event
and use sendEvent to run that event immediately in the main window (which
remains in the UI thread).  When that completes, following the same code path
as a UI-triggered screenshot, the slot returns, which then causes the
RemoteScreenShot method to return, unblocking the original HTTPServer thread,
precipitating the resultant file to be sent back to mythweb as a response.

This is all horribly complex, but it pretty much has to be that way to be
  • Loading branch information
Beirdo committed Jun 11, 2011
1 parent 8fb317c commit 204f81881ee95e1c913075e04b6381d81b1b5953
@@ -464,6 +464,10 @@ MythMainWindow::MythMainWindow(const bool useDB)
d->repaintRegion = QRegion(QRect(0,0,0,0));

d->m_drawEnabled = true;

connect(this, SIGNAL(signalRemoteScreenShot(QString,int,int)),
this, SLOT(doRemoteScreenShot(QString,int,int)),

@@ -777,16 +781,48 @@ void MythMainWindow::GrabWindow(QImage &image)
image = p.toImage();

bool MythMainWindow::SaveScreenShot(const QImage &image)
/* This is required to allow a screenshot to be requested by another thread
* other than the UI thread, and to wait for the screenshot before returning.
* It is used by mythweb for the remote access screenshots
void MythMainWindow::doRemoteScreenShot(QString filename, int x, int y)
QString fpath = GetMythDB()->GetSetting("ScreenShotPath", "/tmp");
QString fname = QString("%1/myth-screenshot-%2.png").arg(fpath)
// This will be running in the UI thread, as is required by QPixmap
QStringList args;
args << QString::number(x);
args << QString::number(y);
args << filename;

MythEvent me(MythEvent::MythEventMessage, ACTION_SCREENSHOT, args);
qApp->sendEvent(this, &me);

void MythMainWindow::RemoteScreenShot(QString filename, int x, int y)
// This will be running in a non-UI thread and is used to trigger a
// function in the UI thread, and waits for completion of that handler
emit signalRemoteScreenShot(filename, x, y);

bool MythMainWindow::SaveScreenShot(const QImage &image, QString filename)
if (filename.isEmpty())
QString fpath = GetMythDB()->GetSetting("ScreenShotPath", "/tmp");
filename = QString("%1/myth-screenshot-%2.png").arg(fpath)

QString extension = filename.section('.', -1, -1);
if (extension == "jpg")
extension = "JPEG";
extension = "PNG";

VERBOSE(VB_GENERAL,QString("Saving screenshot to %1 (%2x%3)")

if (
if (, extension.toAscii(), 100))
VERBOSE(VB_GENERAL, "MythMainWindow::screenShot succeeded");
return true;
@@ -796,7 +832,7 @@ bool MythMainWindow::SaveScreenShot(const QImage &image)
return false;

bool MythMainWindow::ScreenShot(int w, int h)
bool MythMainWindow::ScreenShot(int w, int h, QString filename)
QImage img;
@@ -806,7 +842,7 @@ bool MythMainWindow::ScreenShot(int w, int h)
h = img.height();

img = img.scaled(w, h, Qt::KeepAspectRatio, Qt::SmoothTransformation);
return SaveScreenShot(img);
return SaveScreenShot(img, filename);

bool MythMainWindow::event(QEvent *e)
@@ -2200,11 +2236,18 @@ void MythMainWindow::customEvent(QEvent *ce)
else if (message.startsWith(ACTION_SCREENSHOT))
if (me->ExtraDataCount() == 2)
if (me->ExtraDataCount() >= 2)
int width = me->ExtraData(0).toInt();
int height = me->ExtraData(1).toInt();
ScreenShot(width, height);

if (me->ExtraDataCount() == 3)
QString filename = me->ExtraData(2);
ScreenShot(width, height, filename);
ScreenShot(width, height);
@@ -95,8 +95,9 @@ class MUI_PUBLIC MythMainWindow : public QWidget
void ResizePainterWindow(const QSize &size);

void GrabWindow(QImage &image);
bool SaveScreenShot(const QImage &image);
bool ScreenShot(int w = 0, int h = 0);
bool SaveScreenShot(const QImage &image, QString filename = "");
bool ScreenShot(int w = 0, int h = 0, QString filename = "");
void RemoteScreenShot(QString filename, int x, int y);

void AllowInput(bool allow);

@@ -130,6 +131,10 @@ class MUI_PUBLIC MythMainWindow : public QWidget

protected slots:
void animate();
void doRemoteScreenShot(QString filename, int x, int y);

void signalRemoteScreenShot(QString filename, int x, int y);

MythMainWindow(const bool useDB = true);
@@ -132,25 +132,33 @@ bool MythFEXML::ProcessRequest( HttpWorkerThread *pThread, HTTPRequest *pRequest

void MythFEXML::GetScreenShot(HTTPRequest *pRequest)
pRequest->m_eResponseType = ResponseTypeHTML;
pRequest->m_eResponseType = ResponseTypeFile;

// Optional Parameters
int nWidth = pRequest->m_mapParams[ "width" ].toInt();
int nHeight = pRequest->m_mapParams[ "height" ].toInt();

VERBOSE(VB_GENERAL, QString("Screen shot requested (%1x%2)")
QString sFormat = pRequest->m_mapParams[ "format" ];

MythMainWindow *window = GetMythMainWindow();
QStringList args;
if (nWidth && nHeight)
if (sFormat.isEmpty())
sFormat = "png";

if (sFormat != "jpg" && sFormat != "png")
args << QString::number(nWidth);
args << QString::number(nHeight);
VERBOSE(VB_GENERAL, "Invalid screen shot format: " + sFormat);
MythEvent* me = new MythEvent(MythEvent::MythEventMessage,
qApp->postEvent(window, me);

VERBOSE(VB_GENERAL, QString("Screen shot requested (%1x%2), format %3")

QString sFileName = QString("/%1/myth-screenshot-XML.%2")

MythMainWindow *window = GetMythMainWindow();
window->RemoteScreenShot(sFileName, nWidth, nHeight);

pRequest->m_sFileName = sFileName;

void MythFEXML::SendMessage(HTTPRequest *pRequest)

0 comments on commit 204f818

Please sign in to comment.
You can’t perform that action at this time.