Skip to content

Commit

Permalink
Fix remote (mythweb) screenshots
Browse files Browse the repository at this point in the history
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
operational.
  • Loading branch information
Beirdo committed Jun 11, 2011
1 parent 8fb317c commit 204f818
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 24 deletions.
63 changes: 53 additions & 10 deletions mythtv/libs/libmythui/mythmainwindow.cpp
Expand Up @@ -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)),
Qt::BlockingQueuedConnection);
}

MythMainWindow::~MythMainWindow()
Expand Down Expand Up @@ -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)
.arg(QDateTime::currentDateTime().toString("yyyy-MM-ddThh-mm-ss.zzz"));
// 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)
.arg(QDateTime::currentDateTime().toString("yyyy-MM-ddThh-mm-ss.zzz"));
}

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

VERBOSE(VB_GENERAL,QString("Saving screenshot to %1 (%2x%3)")
.arg(fname).arg(image.width()).arg(image.height()));
.arg(filename).arg(image.width()).arg(image.height()));

if (image.save(fname))
if (image.save(filename, extension.toAscii(), 100))
{
VERBOSE(VB_GENERAL, "MythMainWindow::screenShot succeeded");
return true;
Expand All @@ -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;
GrabWindow(img);
Expand All @@ -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)
Expand Down Expand Up @@ -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);
}
else
ScreenShot(width, height);
}
else
{
Expand Down
9 changes: 7 additions & 2 deletions mythtv/libs/libmythui/mythmainwindow.h
Expand Up @@ -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);

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

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

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

protected:
MythMainWindow(const bool useDB = true);
Expand Down
32 changes: 20 additions & 12 deletions mythtv/programs/mythfrontend/mythfexml.cpp
Expand Up @@ -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)")
.arg(nWidth).arg(nHeight));
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);
return;
}
MythEvent* me = new MythEvent(MythEvent::MythEventMessage,
ACTION_SCREENSHOT, args);
qApp->postEvent(window, me);

VERBOSE(VB_GENERAL, QString("Screen shot requested (%1x%2), format %3")
.arg(nWidth).arg(nHeight).arg(sFormat));

QString sFileName = QString("/%1/myth-screenshot-XML.%2")
.arg(gCoreContext->GetSetting("ScreenShotPath","/tmp"))
.arg(sFormat);

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

pRequest->m_sFileName = sFileName;
}

void MythFEXML::SendMessage(HTTPRequest *pRequest)
Expand Down

0 comments on commit 204f818

Please sign in to comment.