[qtwin] Fix crash on pasting screenshots

Workaround for an issue with the Windows Qt version where Celestia crashes
when a copied screenshot is pasted into another application. This appears to
be because the data sent to the clipboard still contains a reference to the
data in the destructed Image object, despite the Qt documentation stating that
QClipboard::setImage causes the clipboard to take ownership of the data. This
does not occur if the QImage manages its own buffer.
pull/1281/head
Andrew Tribick 2022-01-01 13:13:03 +01:00 committed by ajtribick
parent 4a9403ecf5
commit 7b762832a4
3 changed files with 34 additions and 23 deletions

View File

@ -4745,22 +4745,25 @@ View* CelestiaCore::getViewByObserver(const Observer *obs) const
return nullptr;
}
Image CelestiaCore::captureImage() const
void CelestiaCore::getCaptureInfo(std::array<int, 4>& viewport, celestia::PixelFormat& format) const
{
// Get the dimensions of the current viewport
array<int, 4> viewport;
getRenderer()->getViewport(viewport);
renderer->getViewport(viewport);
format = renderer->getPreferredCaptureFormat();
}
PixelFormat format = renderer->getPreferredCaptureFormat();
Image image(format, viewport[2], viewport[3]);
if (!renderer->captureFrame(viewport[0], viewport[1],
viewport[2], viewport[3],
format, image.getPixels()))
bool CelestiaCore::captureImage(std::uint8_t* buffer,
const std::array<int, 4>& viewport,
celestia::PixelFormat format) const
{
if (renderer->captureFrame(viewport[0], viewport[1],
viewport[2], viewport[3],
format, buffer))
{
GetLogger()->error(_("Unable to capture a frame!\n"));
return true;
}
return image;
GetLogger()->error(_("Unable to capture a frame!\n"));
return false;
}
bool CelestiaCore::saveScreenShot(const fs::path& filename, ContentType type) const
@ -4774,8 +4777,11 @@ bool CelestiaCore::saveScreenShot(const fs::path& filename, ContentType type) co
return false;
}
Image image = captureImage();
if (!image.isValid())
std::array<int, 4> viewport;
PixelFormat format;
getCaptureInfo(viewport, format);
Image image(format, viewport[2], viewport[3]);
if (!captureImage(image.getPixels(), viewport, format))
return false;
switch (type)

View File

@ -10,6 +10,7 @@
#ifndef _CELESTIACORE_H_
#define _CELESTIACORE_H_
#include <array>
#include <fstream>
#include <string>
#include <functional>
@ -19,6 +20,7 @@
// #include <celutil/watchable.h>
#include <celengine/solarsys.h>
#include <celengine/overlay.h>
#include <celengine/pixelformat.h>
#include <celengine/texture.h>
#include <celengine/universe.h>
#include <celengine/render.h>
@ -384,7 +386,8 @@ class CelestiaCore // : public Watchable<CelestiaCore>
void setScriptHook(std::unique_ptr<celestia::scripts::IScriptHook> &&hook) { m_scriptHook = std::move(hook); }
const std::shared_ptr<celestia::scripts::ScriptMaps>& scriptMaps() const { return m_scriptMaps; }
Image captureImage() const;
void getCaptureInfo(std::array<int, 4>& viewport, celestia::PixelFormat& format) const;
bool captureImage(std::uint8_t* buffer, const std::array<int, 4>& viewport, celestia::PixelFormat format) const;
bool saveScreenShot(const fs::path&, ContentType = Content_Unknown) const;
void setMeasurementSystem(MeasurementSystem);

View File

@ -750,14 +750,16 @@ static QImage::Format toQFormat(PixelFormat format)
void CelestiaAppWindow::slotCopyImage()
{
//glWidget->repaint();
Image image = m_appCore->captureImage();
QImage grabbedImage = QImage(image.getPixels(),
image.getWidth(),
image.getHeight(),
image.getPitch(),
toQFormat(image.getFormat()));
QApplication::clipboard()->setImage(grabbedImage);
m_appCore->flash(_("Captured screen shot to clipboard"));
std::array<int, 4> viewport;
celestia::PixelFormat format;
m_appCore->getCaptureInfo(viewport, format);
QImage grabbedImage = QImage(viewport[2], viewport[3],
toQFormat(format));
if (m_appCore->captureImage(grabbedImage.bits(), viewport, format))
{
QApplication::clipboard()->setImage(grabbedImage);
m_appCore->flash(_("Captured screen shot to clipboard"));
}
}