mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 14:17:12 +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) {
|
||||
using Error = Ui::PreparedList::Error;
|
||||
auto result = data->hasUrls()
|
||||
const auto list = Core::ReadMimeUrls(data);
|
||||
auto result = !list.isEmpty()
|
||||
? Storage::PrepareMediaList(
|
||||
// When we edit media, we need only 1 file.
|
||||
base::GetMimeUrls(data).mid(0, 1),
|
||||
list.mid(0, 1), // When we edit media, we need only 1 file.
|
||||
st::sendMediaPreviewSize,
|
||||
premium)
|
||||
: Ui::PreparedList(Error::EmptyFile, QString());
|
||||
|
|
|
@ -1091,13 +1091,13 @@ void SendFilesBox::captionResized() {
|
|||
}
|
||||
|
||||
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) {
|
||||
const auto premium = _controller->session().premium();
|
||||
auto list = [&] {
|
||||
const auto urls = base::GetMimeUrls(data);
|
||||
const auto urls = Core::ReadMimeUrls(data);
|
||||
auto result = CanAddUrls(urls)
|
||||
? Storage::PrepareMediaList(
|
||||
urls,
|
||||
|
|
|
@ -14,6 +14,28 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include <QtCore/QMimeData>
|
||||
|
||||
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) {
|
||||
}
|
||||
|
@ -170,9 +192,10 @@ std::shared_ptr<QMimeData> ShareMimeMediaData(
|
|||
result->setData(u"application/x-td-use-jpeg"_q, "1");
|
||||
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->setText(Core::ReadMimeText(original));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -192,4 +215,16 @@ MimeImageData ReadMimeImage(not_null<const QMimeData*> data) {
|
|||
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
|
||||
|
|
|
@ -65,5 +65,7 @@ struct MimeImageData {
|
|||
}
|
||||
};
|
||||
[[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
|
||||
|
|
|
@ -38,18 +38,6 @@ inline bool in_range(Value &&value, From &&from, Till &&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>)
|
||||
inline QString IconName() {
|
||||
static const auto Result = KSandbox::isFlatpak()
|
||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "editor/editor_paint.h"
|
||||
|
||||
#include "core/mime_type.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "editor/controllers/controllers.h"
|
||||
#include "editor/scene/scene.h"
|
||||
|
@ -204,16 +205,17 @@ void Paint::handleMimeData(const QMimeData *data) {
|
|||
|
||||
using Error = Ui::PreparedList::Error;
|
||||
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(
|
||||
base::GetMimeUrls(data).mid(0, 1),
|
||||
list.mid(0, 1),
|
||||
_imageSize.width() / 2,
|
||||
premium)
|
||||
: Ui::PreparedList(Error::EmptyFile, QString());
|
||||
if (result.error == Error::None) {
|
||||
add(base::take(result.files.front().preview));
|
||||
} else if (data->hasImage()) {
|
||||
add(qvariant_cast<QImage>(data->imageData()));
|
||||
} else if (auto read = Core::ReadMimeImage(data)) {
|
||||
add(std::move(read.image));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -459,7 +459,10 @@ HistoryWidget::HistoryWidget(
|
|||
if (action == Ui::InputField::MimeAction::Check) {
|
||||
return canSendFiles(data);
|
||||
} 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.");
|
||||
});
|
||||
|
@ -5230,7 +5233,7 @@ bool HistoryWidget::canSendFiles(not_null<const QMimeData*> data) const {
|
|||
return false;
|
||||
} else if (data->hasImage()) {
|
||||
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)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -5249,7 +5252,7 @@ bool HistoryWidget::confirmSendingFiles(
|
|||
const auto hasImage = data->hasImage();
|
||||
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(
|
||||
urls,
|
||||
st::sendMediaPreviewSize,
|
||||
|
|
|
@ -100,7 +100,7 @@ constexpr auto kRefreshSlowmodeLabelTimeout = crl::time(200);
|
|||
bool CanSendFiles(not_null<const QMimeData*> data) {
|
||||
if (data->hasImage()) {
|
||||
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)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -825,7 +825,10 @@ void RepliesWidget::setupComposeControls() {
|
|||
if (action == Ui::InputField::MimeAction::Check) {
|
||||
return CanSendFiles(data);
|
||||
} 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.");
|
||||
});
|
||||
|
@ -908,7 +911,7 @@ bool RepliesWidget::confirmSendingFiles(
|
|||
const auto hasImage = data->hasImage();
|
||||
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(
|
||||
urls,
|
||||
st::sendMediaPreviewSize,
|
||||
|
|
|
@ -70,7 +70,7 @@ namespace {
|
|||
bool CanSendFiles(not_null<const QMimeData*> data) {
|
||||
if (data->hasImage()) {
|
||||
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)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -314,7 +314,10 @@ void ScheduledWidget::setupComposeControls() {
|
|||
if (action == Ui::InputField::MimeAction::Check) {
|
||||
return CanSendFiles(data);
|
||||
} 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.");
|
||||
});
|
||||
|
@ -373,7 +376,7 @@ bool ScheduledWidget::confirmSendingFiles(
|
|||
const auto hasImage = data->hasImage();
|
||||
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(
|
||||
urls,
|
||||
st::sendMediaPreviewSize,
|
||||
|
|
|
@ -74,7 +74,7 @@ void PrepareDetailsInParallel(PreparedList &result, int previewWidth) {
|
|||
} // namespace
|
||||
|
||||
bool ValidatePhotoEditorMediaDragData(not_null<const QMimeData*> data) {
|
||||
const auto urls = base::GetMimeUrls(data);
|
||||
const auto urls = Core::ReadMimeUrls(data);
|
||||
if (urls.size() > 1) {
|
||||
return false;
|
||||
} else if (data->hasImage()) {
|
||||
|
@ -98,7 +98,7 @@ bool ValidatePhotoEditorMediaDragData(not_null<const QMimeData*> data) {
|
|||
bool ValidateEditMediaDragData(
|
||||
not_null<const QMimeData*> data,
|
||||
Ui::AlbumType albumType) {
|
||||
const auto urls = base::GetMimeUrls(data);
|
||||
const auto urls = Core::ReadMimeUrls(data);
|
||||
if (urls.size() > 1) {
|
||||
return false;
|
||||
} else if (data->hasImage()) {
|
||||
|
@ -126,7 +126,7 @@ MimeDataState ComputeMimeDataState(const QMimeData *data) {
|
|||
return MimeDataState::Image;
|
||||
}
|
||||
|
||||
const auto urls = base::GetMimeUrls(data);
|
||||
const auto urls = Core::ReadMimeUrls(data);
|
||||
if (urls.isEmpty()) {
|
||||
return MimeDataState::None;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue