mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-18 23:27:09 +02:00
Show just logo in Dwm Preview when passcoded.
This commit is contained in:
parent
c7b3c95dc6
commit
88f3aeca5b
2 changed files with 234 additions and 3 deletions
|
@ -47,7 +47,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include <Windowsx.h>
|
||||
#include <VersionHelpers.h>
|
||||
|
||||
// Taken from qtbase/src/gui/image/qpixmap_win.cpp
|
||||
HICON qt_pixmapToWinHICON(const QPixmap &);
|
||||
HBITMAP qt_imageToWinHBITMAP(const QImage &, int hbitmapFormat);
|
||||
|
||||
namespace ViewManagement = ABI::Windows::UI::ViewManagement;
|
||||
|
||||
|
@ -61,6 +63,15 @@ namespace {
|
|||
// icon click (both left or right button) was made from the active app.
|
||||
constexpr auto kKeepActiveForTrayIcon = crl::time(500);
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
// Taken from qtbase/src/gui/image/qpixmap_win.cpp
|
||||
enum HBitmapFormat {
|
||||
HBitmapNoAlpha,
|
||||
HBitmapPremultipliedAlpha,
|
||||
HBitmapAlpha
|
||||
};
|
||||
|
||||
class EventFilter final : public QAbstractNativeEventFilter {
|
||||
public:
|
||||
explicit EventFilter(not_null<MainWindow*> window);
|
||||
|
@ -82,9 +93,6 @@ private:
|
|||
|
||||
};
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
bool handleSessionNotification = false;
|
||||
|
||||
[[nodiscard]] HICON NativeIcon(const QIcon &icon, QSize size) {
|
||||
if (!icon.isNull()) {
|
||||
|
@ -96,6 +104,67 @@ bool handleSessionNotification = false;
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
struct RealSize {
|
||||
QSize value;
|
||||
bool maximized = false;
|
||||
};
|
||||
[[nodiscard]] RealSize DetectRealSize(HWND hwnd) {
|
||||
auto result = RECT();
|
||||
auto placement = WINDOWPLACEMENT();
|
||||
if (!GetWindowPlacement(hwnd, &placement)) {
|
||||
return {};
|
||||
} else if (placement.flags & WPF_RESTORETOMAXIMIZED) {
|
||||
const auto monitor = MonitorFromRect(
|
||||
&placement.rcNormalPosition,
|
||||
MONITOR_DEFAULTTONULL);
|
||||
if (!monitor) {
|
||||
return {};
|
||||
}
|
||||
auto info = MONITORINFO{ .cbSize = sizeof(MONITORINFO) };
|
||||
if (!GetMonitorInfo(monitor, &info)) {
|
||||
return {};
|
||||
}
|
||||
result = info.rcWork;
|
||||
} else {
|
||||
CopyRect(&result, &placement.rcNormalPosition);
|
||||
}
|
||||
return {
|
||||
{ int(result.right - result.left), int(result.bottom - result.top) },
|
||||
((placement.flags & WPF_RESTORETOMAXIMIZED) != 0)
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] QImage PrepareLogoPreview(
|
||||
QSize size,
|
||||
QImage::Format format,
|
||||
int radius = 0) {
|
||||
auto result = QImage(size, QImage::Format_RGB32);
|
||||
result.fill(st::windowBg->c);
|
||||
|
||||
const auto logo = Window::Logo();
|
||||
const auto width = size.width();
|
||||
const auto height = size.height();
|
||||
const auto side = logo.width();
|
||||
const auto skip = width / 8;
|
||||
const auto use = std::min({ width - skip, height - skip, side });
|
||||
auto p = QPainter(&result);
|
||||
if (use == side) {
|
||||
p.drawImage((width - side) / 2, (height - side) / 2, logo);
|
||||
} else {
|
||||
const auto scaled = logo.scaled(
|
||||
use,
|
||||
use,
|
||||
Qt::KeepAspectRatio,
|
||||
Qt::SmoothTransformation);
|
||||
p.drawImage((width - use) / 2, (height - use) / 2, scaled);
|
||||
}
|
||||
p.end();
|
||||
|
||||
return radius
|
||||
? Images::Round(std::move(result), Images::CornersMask(radius))
|
||||
: result;
|
||||
}
|
||||
|
||||
EventFilter::EventFilter(not_null<MainWindow*> window) : _window(window) {
|
||||
}
|
||||
|
||||
|
@ -150,6 +219,23 @@ bool EventFilter::mainWindowEvent(
|
|||
_window->positionUpdated();
|
||||
} return false;
|
||||
|
||||
case WM_DWMSENDICONICTHUMBNAIL: {
|
||||
if (!Core::App().passcodeLocked()) {
|
||||
return false;
|
||||
}
|
||||
const auto size = QSize(int(HIWORD(lParam)), int(LOWORD(lParam)));
|
||||
return _window->setDwmThumbnail(size);
|
||||
}
|
||||
|
||||
case WM_DWMSENDICONICLIVEPREVIEWBITMAP: {
|
||||
if (!Core::App().passcodeLocked()) {
|
||||
return false;
|
||||
}
|
||||
const auto size = DetectRealSize(hWnd);
|
||||
const auto radius = size.maximized ? 0 : style::ConvertScale(8);
|
||||
return _window->setDwmPreview(size.value, radius);
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -164,6 +250,46 @@ struct MainWindow::Private {
|
|||
ComPtr<ViewManagement::IUIViewSettings> viewSettings;
|
||||
};
|
||||
|
||||
MainWindow::BitmapPointer::BitmapPointer(HBITMAP value) : _value(value) {
|
||||
}
|
||||
|
||||
MainWindow::BitmapPointer::BitmapPointer(BitmapPointer &&other)
|
||||
: _value(base::take(other._value)) {
|
||||
}
|
||||
|
||||
MainWindow::BitmapPointer &MainWindow::BitmapPointer::operator=(
|
||||
BitmapPointer &&other) {
|
||||
if (_value != other._value) {
|
||||
reset();
|
||||
_value = base::take(other._value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
MainWindow::BitmapPointer::~BitmapPointer() {
|
||||
reset();
|
||||
}
|
||||
|
||||
HBITMAP MainWindow::BitmapPointer::get() const {
|
||||
return _value;
|
||||
}
|
||||
|
||||
MainWindow::BitmapPointer::operator bool() const {
|
||||
return _value != nullptr;
|
||||
}
|
||||
|
||||
void MainWindow::BitmapPointer::release() {
|
||||
_value = nullptr;
|
||||
}
|
||||
|
||||
void MainWindow::BitmapPointer::reset(HBITMAP value) {
|
||||
if (_value != value) {
|
||||
if (const auto old = std::exchange(_value, value)) {
|
||||
DeleteObject(old);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MainWindow::MainWindow(not_null<Window::Controller*> controller)
|
||||
: Window::MainWindow(controller)
|
||||
, _private(std::make_unique<Private>(this))
|
||||
|
@ -180,6 +306,27 @@ MainWindow::MainWindow(not_null<Window::Controller*> controller)
|
|||
) | rpl::filter(_1) | rpl::start_with_next([=] {
|
||||
_lastDeactivateTime = crl::now();
|
||||
}, lifetime());
|
||||
|
||||
setupPreviewPasscodeLock();
|
||||
}
|
||||
|
||||
void MainWindow::setupPreviewPasscodeLock() {
|
||||
Core::App().passcodeLockValue(
|
||||
) | rpl::start_with_next([=](bool locked) {
|
||||
// Use iconic bitmap instead of the window content if passcoded.
|
||||
BOOL fForceIconic = locked ? TRUE : FALSE;
|
||||
BOOL fHasIconicBitmap = fForceIconic;
|
||||
DwmSetWindowAttribute(
|
||||
_hWnd,
|
||||
DWMWA_FORCE_ICONIC_REPRESENTATION,
|
||||
&fForceIconic,
|
||||
sizeof(fForceIconic));
|
||||
DwmSetWindowAttribute(
|
||||
_hWnd,
|
||||
DWMWA_HAS_ICONIC_BITMAP,
|
||||
&fHasIconicBitmap,
|
||||
sizeof(fHasIconicBitmap));
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void MainWindow::setupNativeWindowFrame() {
|
||||
|
@ -211,6 +358,60 @@ void MainWindow::destroyedFromSystem() {
|
|||
}
|
||||
}
|
||||
|
||||
bool MainWindow::setDwmThumbnail(QSize size) {
|
||||
validateDwmPreviewColors();
|
||||
if (size.isEmpty()) {
|
||||
return false;
|
||||
} else if (!_dwmThumbnail || _dwmThumbnailSize != size) {
|
||||
const auto result = PrepareLogoPreview(size, QImage::Format_RGB32);
|
||||
const auto bitmap = qt_imageToWinHBITMAP(result, HBitmapNoAlpha);
|
||||
if (!bitmap) {
|
||||
return false;
|
||||
}
|
||||
_dwmThumbnail.reset(bitmap);
|
||||
_dwmThumbnailSize = size;
|
||||
}
|
||||
DwmSetIconicThumbnail(_hWnd, _dwmThumbnail.get(), NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MainWindow::setDwmPreview(QSize size, int radius) {
|
||||
Expects(radius >= 0);
|
||||
|
||||
validateDwmPreviewColors();
|
||||
if (size.isEmpty()) {
|
||||
return false;
|
||||
} else if (!_dwmPreview
|
||||
|| _dwmPreviewSize != size
|
||||
|| _dwmPreviewRadius != radius) {
|
||||
const auto format = (radius > 0)
|
||||
? QImage::Format_ARGB32_Premultiplied
|
||||
: QImage::Format_RGB32;
|
||||
const auto result = PrepareLogoPreview(size, format, radius);
|
||||
const auto bitmap = qt_imageToWinHBITMAP(
|
||||
result,
|
||||
(radius > 0) ? HBitmapPremultipliedAlpha : HBitmapNoAlpha);
|
||||
if (!bitmap) {
|
||||
return false;
|
||||
}
|
||||
_dwmPreview.reset(bitmap);
|
||||
_dwmPreviewRadius = radius;
|
||||
_dwmPreviewSize = size;
|
||||
}
|
||||
const auto flags = 0;
|
||||
DwmSetIconicLivePreviewBitmap(_hWnd, _dwmPreview.get(), NULL, flags);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainWindow::validateDwmPreviewColors() {
|
||||
if (_dwmBackground == st::windowBg->c) {
|
||||
return;
|
||||
}
|
||||
_dwmBackground = st::windowBg->c;
|
||||
_dwmThumbnail.reset();
|
||||
_dwmPreview.reset();
|
||||
}
|
||||
|
||||
int32 MainWindow::screenNameChecksum(const QString &name) const {
|
||||
constexpr int DeviceNameSize = base::array_size(MONITORINFOEX().szDevice);
|
||||
wchar_t buffer[DeviceNameSize] = { 0 };
|
||||
|
|
|
@ -34,6 +34,9 @@ public:
|
|||
|
||||
void destroyedFromSystem();
|
||||
|
||||
bool setDwmThumbnail(QSize size);
|
||||
bool setDwmPreview(QSize size, int radius);
|
||||
|
||||
~MainWindow();
|
||||
|
||||
protected:
|
||||
|
@ -50,12 +53,32 @@ protected:
|
|||
private:
|
||||
struct Private;
|
||||
|
||||
class BitmapPointer {
|
||||
public:
|
||||
BitmapPointer(HBITMAP value = nullptr);
|
||||
BitmapPointer(BitmapPointer &&other);
|
||||
BitmapPointer& operator=(BitmapPointer &&other);
|
||||
~BitmapPointer();
|
||||
|
||||
[[nodiscard]] HBITMAP get() const;
|
||||
[[nodiscard]] explicit operator bool() const;
|
||||
|
||||
void release();
|
||||
void reset(HBITMAP value = nullptr);
|
||||
|
||||
private:
|
||||
HBITMAP _value = nullptr;
|
||||
|
||||
};
|
||||
|
||||
void setupNativeWindowFrame();
|
||||
void setupPreviewPasscodeLock();
|
||||
void updateTaskbarAndIconCounters();
|
||||
void validateWindowTheme(bool native, bool night);
|
||||
|
||||
void forceIconRefresh();
|
||||
void destroyCachedIcons();
|
||||
void validateDwmPreviewColors();
|
||||
|
||||
const std::unique_ptr<Private> _private;
|
||||
const std::unique_ptr<QWindow> _taskbarHiderWindow;
|
||||
|
@ -65,6 +88,13 @@ private:
|
|||
HICON _iconSmall = nullptr;
|
||||
HICON _iconOverlay = nullptr;
|
||||
|
||||
BitmapPointer _dwmThumbnail;
|
||||
BitmapPointer _dwmPreview;
|
||||
QSize _dwmThumbnailSize;
|
||||
QSize _dwmPreviewSize;
|
||||
QColor _dwmBackground;
|
||||
int _dwmPreviewRadius = 0;
|
||||
|
||||
// Workarounds for activation from tray icon.
|
||||
crl::time _lastDeactivateTime = 0;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue