mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Fix pasting images from Firefox on Windows.
Fixes #10564. Together with the image data Firefox sets to the clipboard an URLs list which has a path to local temp file, created from that image. Reading images from disk is slower + sometimes the content of the file is wrong so for this case we prefer to read the image data directly.
This commit is contained in:
parent
c687882760
commit
ff4af1b9bc
10 changed files with 70 additions and 34 deletions
|
@ -69,10 +69,10 @@ namespace {
|
||||||
|
|
||||||
auto ListFromMimeData(not_null<const QMimeData*> data, bool premium) {
|
auto ListFromMimeData(not_null<const QMimeData*> data, bool premium) {
|
||||||
using Error = Ui::PreparedList::Error;
|
using Error = Ui::PreparedList::Error;
|
||||||
auto result = data->hasUrls()
|
const auto list = Core::ReadMimeUrls(data);
|
||||||
|
auto result = !list.isEmpty()
|
||||||
? Storage::PrepareMediaList(
|
? Storage::PrepareMediaList(
|
||||||
// When we edit media, we need only 1 file.
|
list.mid(0, 1), // When we edit media, we need only 1 file.
|
||||||
base::GetMimeUrls(data).mid(0, 1),
|
|
||||||
st::sendMediaPreviewSize,
|
st::sendMediaPreviewSize,
|
||||||
premium)
|
premium)
|
||||||
: Ui::PreparedList(Error::EmptyFile, QString());
|
: Ui::PreparedList(Error::EmptyFile, QString());
|
||||||
|
|
|
@ -1091,13 +1091,13 @@ void SendFilesBox::captionResized() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SendFilesBox::canAddFiles(not_null<const QMimeData*> data) const {
|
bool SendFilesBox::canAddFiles(not_null<const QMimeData*> data) const {
|
||||||
return CanAddUrls(base::GetMimeUrls(data)) || data->hasImage();
|
return data->hasImage() || CanAddUrls(Core::ReadMimeUrls(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SendFilesBox::addFiles(not_null<const QMimeData*> data) {
|
bool SendFilesBox::addFiles(not_null<const QMimeData*> data) {
|
||||||
const auto premium = _controller->session().premium();
|
const auto premium = _controller->session().premium();
|
||||||
auto list = [&] {
|
auto list = [&] {
|
||||||
const auto urls = base::GetMimeUrls(data);
|
const auto urls = Core::ReadMimeUrls(data);
|
||||||
auto result = CanAddUrls(urls)
|
auto result = CanAddUrls(urls)
|
||||||
? Storage::PrepareMediaList(
|
? Storage::PrepareMediaList(
|
||||||
urls,
|
urls,
|
||||||
|
|
|
@ -14,6 +14,28 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include <QtCore/QMimeData>
|
#include <QtCore/QMimeData>
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
[[nodiscard]] bool IsImageFromFirefox(not_null<const QMimeData*> data) {
|
||||||
|
// See https://bugs.telegram.org/c/6765/public
|
||||||
|
// See https://github.com/telegramdesktop/tdesktop/issues/10564
|
||||||
|
//
|
||||||
|
// Usually we prefer pasting from URLs list instead of pasting from
|
||||||
|
// image data, because sometimes a file is copied together with an
|
||||||
|
// image data of its File Explorer thumbnail or smth like that. In
|
||||||
|
// that case you end up sending this thumbnail instead of the file.
|
||||||
|
//
|
||||||
|
// But in case of "Copy Image" from Firefox on Windows we get both
|
||||||
|
// URLs list with a file path to some Temp folder in the list and
|
||||||
|
// the image data that was copied. The file is read slower + it may
|
||||||
|
// have incorrect content in case the URL can't be accessed without
|
||||||
|
// authorization. So in that case we want only image data and we
|
||||||
|
// check for a special Firefox mime type to check for that case.
|
||||||
|
return data->hasFormat(u"application/x-moz-nativeimage"_q)
|
||||||
|
&& data->hasImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
MimeType::MimeType(const QMimeType &type) : _typeStruct(type) {
|
MimeType::MimeType(const QMimeType &type) : _typeStruct(type) {
|
||||||
}
|
}
|
||||||
|
@ -170,9 +192,10 @@ std::shared_ptr<QMimeData> ShareMimeMediaData(
|
||||||
result->setData(u"application/x-td-use-jpeg"_q, "1");
|
result->setData(u"application/x-td-use-jpeg"_q, "1");
|
||||||
result->setData(u"image/jpeg"_q, original->data(u"image/jpeg"_q));
|
result->setData(u"image/jpeg"_q, original->data(u"image/jpeg"_q));
|
||||||
}
|
}
|
||||||
if (auto list = base::GetMimeUrls(original); !list.isEmpty()) {
|
if (auto list = Core::ReadMimeUrls(original); !list.isEmpty()) {
|
||||||
result->setUrls(std::move(list));
|
result->setUrls(std::move(list));
|
||||||
}
|
}
|
||||||
|
result->setText(Core::ReadMimeText(original));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,4 +215,16 @@ MimeImageData ReadMimeImage(not_null<const QMimeData*> data) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ReadMimeText(not_null<const QMimeData*> data) {
|
||||||
|
return IsImageFromFirefox(data) ? QString() : data->text();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QUrl> ReadMimeUrls(not_null<const QMimeData*> data) {
|
||||||
|
return (data->hasUrls() && !IsImageFromFirefox(data))
|
||||||
|
? KUrlMimeData::urlsFromMimeData(
|
||||||
|
data,
|
||||||
|
KUrlMimeData::PreferLocalUrls)
|
||||||
|
: QList<QUrl>();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
|
|
@ -65,5 +65,7 @@ struct MimeImageData {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
[[nodiscard]] MimeImageData ReadMimeImage(not_null<const QMimeData*> data);
|
[[nodiscard]] MimeImageData ReadMimeImage(not_null<const QMimeData*> data);
|
||||||
|
[[nodiscard]] QString ReadMimeText(not_null<const QMimeData*> data);
|
||||||
|
[[nodiscard]] QList<QUrl> ReadMimeUrls(not_null<const QMimeData*> data);
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
|
|
@ -38,18 +38,6 @@ inline bool in_range(Value &&value, From &&from, Till &&till) {
|
||||||
return (value >= from) && (value < till);
|
return (value >= from) && (value < till);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __has_include(<kurlmimedata.h>)
|
|
||||||
inline QList<QUrl> GetMimeUrls(const QMimeData *data) {
|
|
||||||
if (!data->hasUrls()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
return KUrlMimeData::urlsFromMimeData(
|
|
||||||
data,
|
|
||||||
KUrlMimeData::PreferLocalUrls);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __has_include(<ksandbox.h>)
|
#if __has_include(<ksandbox.h>)
|
||||||
inline QString IconName() {
|
inline QString IconName() {
|
||||||
static const auto Result = KSandbox::isFlatpak()
|
static const auto Result = KSandbox::isFlatpak()
|
||||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "editor/editor_paint.h"
|
#include "editor/editor_paint.h"
|
||||||
|
|
||||||
|
#include "core/mime_type.h"
|
||||||
#include "ui/boxes/confirm_box.h"
|
#include "ui/boxes/confirm_box.h"
|
||||||
#include "editor/controllers/controllers.h"
|
#include "editor/controllers/controllers.h"
|
||||||
#include "editor/scene/scene.h"
|
#include "editor/scene/scene.h"
|
||||||
|
@ -204,16 +205,17 @@ void Paint::handleMimeData(const QMimeData *data) {
|
||||||
|
|
||||||
using Error = Ui::PreparedList::Error;
|
using Error = Ui::PreparedList::Error;
|
||||||
const auto premium = false; // Don't support > 2GB files here.
|
const auto premium = false; // Don't support > 2GB files here.
|
||||||
auto result = data->hasUrls()
|
const auto list = Core::ReadMimeUrls(data);
|
||||||
|
auto result = !list.isEmpty()
|
||||||
? Storage::PrepareMediaList(
|
? Storage::PrepareMediaList(
|
||||||
base::GetMimeUrls(data).mid(0, 1),
|
list.mid(0, 1),
|
||||||
_imageSize.width() / 2,
|
_imageSize.width() / 2,
|
||||||
premium)
|
premium)
|
||||||
: Ui::PreparedList(Error::EmptyFile, QString());
|
: Ui::PreparedList(Error::EmptyFile, QString());
|
||||||
if (result.error == Error::None) {
|
if (result.error == Error::None) {
|
||||||
add(base::take(result.files.front().preview));
|
add(base::take(result.files.front().preview));
|
||||||
} else if (data->hasImage()) {
|
} else if (auto read = Core::ReadMimeImage(data)) {
|
||||||
add(qvariant_cast<QImage>(data->imageData()));
|
add(std::move(read.image));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -459,7 +459,10 @@ HistoryWidget::HistoryWidget(
|
||||||
if (action == Ui::InputField::MimeAction::Check) {
|
if (action == Ui::InputField::MimeAction::Check) {
|
||||||
return canSendFiles(data);
|
return canSendFiles(data);
|
||||||
} else if (action == Ui::InputField::MimeAction::Insert) {
|
} else if (action == Ui::InputField::MimeAction::Insert) {
|
||||||
return confirmSendingFiles(data, std::nullopt, data->text());
|
return confirmSendingFiles(
|
||||||
|
data,
|
||||||
|
std::nullopt,
|
||||||
|
Core::ReadMimeText(data));
|
||||||
}
|
}
|
||||||
Unexpected("action in MimeData hook.");
|
Unexpected("action in MimeData hook.");
|
||||||
});
|
});
|
||||||
|
@ -5230,7 +5233,7 @@ bool HistoryWidget::canSendFiles(not_null<const QMimeData*> data) const {
|
||||||
return false;
|
return false;
|
||||||
} else if (data->hasImage()) {
|
} else if (data->hasImage()) {
|
||||||
return true;
|
return true;
|
||||||
} else if (const auto urls = base::GetMimeUrls(data); !urls.empty()) {
|
} else if (const auto urls = Core::ReadMimeUrls(data); !urls.empty()) {
|
||||||
if (ranges::all_of(urls, &QUrl::isLocalFile)) {
|
if (ranges::all_of(urls, &QUrl::isLocalFile)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -5249,7 +5252,7 @@ bool HistoryWidget::confirmSendingFiles(
|
||||||
const auto hasImage = data->hasImage();
|
const auto hasImage = data->hasImage();
|
||||||
const auto premium = controller()->session().user()->isPremium();
|
const auto premium = controller()->session().user()->isPremium();
|
||||||
|
|
||||||
if (const auto urls = base::GetMimeUrls(data); !urls.empty()) {
|
if (const auto urls = Core::ReadMimeUrls(data); !urls.empty()) {
|
||||||
auto list = Storage::PrepareMediaList(
|
auto list = Storage::PrepareMediaList(
|
||||||
urls,
|
urls,
|
||||||
st::sendMediaPreviewSize,
|
st::sendMediaPreviewSize,
|
||||||
|
|
|
@ -100,7 +100,7 @@ constexpr auto kRefreshSlowmodeLabelTimeout = crl::time(200);
|
||||||
bool CanSendFiles(not_null<const QMimeData*> data) {
|
bool CanSendFiles(not_null<const QMimeData*> data) {
|
||||||
if (data->hasImage()) {
|
if (data->hasImage()) {
|
||||||
return true;
|
return true;
|
||||||
} else if (const auto urls = base::GetMimeUrls(data); !urls.empty()) {
|
} else if (const auto urls = Core::ReadMimeUrls(data); !urls.empty()) {
|
||||||
if (ranges::all_of(urls, &QUrl::isLocalFile)) {
|
if (ranges::all_of(urls, &QUrl::isLocalFile)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -825,7 +825,10 @@ void RepliesWidget::setupComposeControls() {
|
||||||
if (action == Ui::InputField::MimeAction::Check) {
|
if (action == Ui::InputField::MimeAction::Check) {
|
||||||
return CanSendFiles(data);
|
return CanSendFiles(data);
|
||||||
} else if (action == Ui::InputField::MimeAction::Insert) {
|
} else if (action == Ui::InputField::MimeAction::Insert) {
|
||||||
return confirmSendingFiles(data, std::nullopt, data->text());
|
return confirmSendingFiles(
|
||||||
|
data,
|
||||||
|
std::nullopt,
|
||||||
|
Core::ReadMimeText(data));
|
||||||
}
|
}
|
||||||
Unexpected("action in MimeData hook.");
|
Unexpected("action in MimeData hook.");
|
||||||
});
|
});
|
||||||
|
@ -908,7 +911,7 @@ bool RepliesWidget::confirmSendingFiles(
|
||||||
const auto hasImage = data->hasImage();
|
const auto hasImage = data->hasImage();
|
||||||
const auto premium = controller()->session().user()->isPremium();
|
const auto premium = controller()->session().user()->isPremium();
|
||||||
|
|
||||||
if (const auto urls = base::GetMimeUrls(data); !urls.empty()) {
|
if (const auto urls = Core::ReadMimeUrls(data); !urls.empty()) {
|
||||||
auto list = Storage::PrepareMediaList(
|
auto list = Storage::PrepareMediaList(
|
||||||
urls,
|
urls,
|
||||||
st::sendMediaPreviewSize,
|
st::sendMediaPreviewSize,
|
||||||
|
|
|
@ -70,7 +70,7 @@ namespace {
|
||||||
bool CanSendFiles(not_null<const QMimeData*> data) {
|
bool CanSendFiles(not_null<const QMimeData*> data) {
|
||||||
if (data->hasImage()) {
|
if (data->hasImage()) {
|
||||||
return true;
|
return true;
|
||||||
} else if (const auto urls = base::GetMimeUrls(data); !urls.empty()) {
|
} else if (const auto urls = Core::ReadMimeUrls(data); !urls.empty()) {
|
||||||
if (ranges::all_of(urls, &QUrl::isLocalFile)) {
|
if (ranges::all_of(urls, &QUrl::isLocalFile)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -314,7 +314,10 @@ void ScheduledWidget::setupComposeControls() {
|
||||||
if (action == Ui::InputField::MimeAction::Check) {
|
if (action == Ui::InputField::MimeAction::Check) {
|
||||||
return CanSendFiles(data);
|
return CanSendFiles(data);
|
||||||
} else if (action == Ui::InputField::MimeAction::Insert) {
|
} else if (action == Ui::InputField::MimeAction::Insert) {
|
||||||
return confirmSendingFiles(data, std::nullopt, data->text());
|
return confirmSendingFiles(
|
||||||
|
data,
|
||||||
|
std::nullopt,
|
||||||
|
Core::ReadMimeText(data));
|
||||||
}
|
}
|
||||||
Unexpected("action in MimeData hook.");
|
Unexpected("action in MimeData hook.");
|
||||||
});
|
});
|
||||||
|
@ -373,7 +376,7 @@ bool ScheduledWidget::confirmSendingFiles(
|
||||||
const auto hasImage = data->hasImage();
|
const auto hasImage = data->hasImage();
|
||||||
const auto premium = controller()->session().user()->isPremium();
|
const auto premium = controller()->session().user()->isPremium();
|
||||||
|
|
||||||
if (const auto urls = base::GetMimeUrls(data); !urls.empty()) {
|
if (const auto urls = Core::ReadMimeUrls(data); !urls.empty()) {
|
||||||
auto list = Storage::PrepareMediaList(
|
auto list = Storage::PrepareMediaList(
|
||||||
urls,
|
urls,
|
||||||
st::sendMediaPreviewSize,
|
st::sendMediaPreviewSize,
|
||||||
|
|
|
@ -74,7 +74,7 @@ void PrepareDetailsInParallel(PreparedList &result, int previewWidth) {
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
bool ValidatePhotoEditorMediaDragData(not_null<const QMimeData*> data) {
|
bool ValidatePhotoEditorMediaDragData(not_null<const QMimeData*> data) {
|
||||||
const auto urls = base::GetMimeUrls(data);
|
const auto urls = Core::ReadMimeUrls(data);
|
||||||
if (urls.size() > 1) {
|
if (urls.size() > 1) {
|
||||||
return false;
|
return false;
|
||||||
} else if (data->hasImage()) {
|
} else if (data->hasImage()) {
|
||||||
|
@ -98,7 +98,7 @@ bool ValidatePhotoEditorMediaDragData(not_null<const QMimeData*> data) {
|
||||||
bool ValidateEditMediaDragData(
|
bool ValidateEditMediaDragData(
|
||||||
not_null<const QMimeData*> data,
|
not_null<const QMimeData*> data,
|
||||||
Ui::AlbumType albumType) {
|
Ui::AlbumType albumType) {
|
||||||
const auto urls = base::GetMimeUrls(data);
|
const auto urls = Core::ReadMimeUrls(data);
|
||||||
if (urls.size() > 1) {
|
if (urls.size() > 1) {
|
||||||
return false;
|
return false;
|
||||||
} else if (data->hasImage()) {
|
} else if (data->hasImage()) {
|
||||||
|
@ -126,7 +126,7 @@ MimeDataState ComputeMimeDataState(const QMimeData *data) {
|
||||||
return MimeDataState::Image;
|
return MimeDataState::Image;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto urls = base::GetMimeUrls(data);
|
const auto urls = Core::ReadMimeUrls(data);
|
||||||
if (urls.isEmpty()) {
|
if (urls.isEmpty()) {
|
||||||
return MimeDataState::None;
|
return MimeDataState::None;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue