mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-04-11 04:01:18 +00:00
parent
d2246337a2
commit
973f91b5e4
BIN
Telegram/Resources/icons/win_quit.png
Normal file
BIN
Telegram/Resources/icons/win_quit.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 406 B |
BIN
Telegram/Resources/icons/win_quit@2x.png
Normal file
BIN
Telegram/Resources/icons/win_quit@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 686 B |
BIN
Telegram/Resources/icons/win_quit@3x.png
Normal file
BIN
Telegram/Resources/icons/win_quit@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 952 B |
@ -7,17 +7,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
*/
|
*/
|
||||||
#include "platform/win/integration_win.h"
|
#include "platform/win/integration_win.h"
|
||||||
|
|
||||||
#include "platform/platform_integration.h"
|
#include "base/platform/win/base_windows_winrt.h"
|
||||||
#include "platform/platform_specific.h"
|
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "core/core_settings.h"
|
#include "core/core_settings.h"
|
||||||
#include "core/sandbox.h"
|
#include "core/sandbox.h"
|
||||||
|
#include "lang/lang_keys.h"
|
||||||
|
#include "platform/win/windows_app_user_model_id.h"
|
||||||
|
#include "platform/win/tray_win.h"
|
||||||
|
#include "platform/platform_integration.h"
|
||||||
|
#include "platform/platform_specific.h"
|
||||||
#include "tray.h"
|
#include "tray.h"
|
||||||
#include "base/platform/win/base_windows_winrt.h"
|
#include "styles/style_window.h"
|
||||||
|
|
||||||
#include <QtCore/QCoreApplication>
|
#include <QtCore/QCoreApplication>
|
||||||
#include <QtCore/QAbstractNativeEventFilter>
|
#include <QtCore/QAbstractNativeEventFilter>
|
||||||
|
|
||||||
|
#include <propvarutil.h>
|
||||||
|
#include <propkey.h>
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
|
|
||||||
void WindowsIntegration::init() {
|
void WindowsIntegration::init() {
|
||||||
@ -48,6 +55,78 @@ bool WindowsIntegration::nativeEventFilter(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowsIntegration::createCustomJumpList() {
|
||||||
|
_jumpList = base::WinRT::TryCreateInstance<ICustomDestinationList>(
|
||||||
|
CLSID_DestinationList);
|
||||||
|
if (_jumpList) {
|
||||||
|
refreshCustomJumpList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowsIntegration::refreshCustomJumpList() {
|
||||||
|
auto added = false;
|
||||||
|
auto maxSlots = UINT();
|
||||||
|
auto removed = (IObjectArray*)nullptr;
|
||||||
|
auto hr = _jumpList->BeginList(&maxSlots, IID_PPV_ARGS(&removed));
|
||||||
|
if (!SUCCEEDED(hr)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto guard = gsl::finally([&] {
|
||||||
|
if (added) {
|
||||||
|
_jumpList->CommitList();
|
||||||
|
} else {
|
||||||
|
_jumpList->AbortList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
auto shellLink = base::WinRT::TryCreateInstance<IShellLink>(
|
||||||
|
CLSID_ShellLink);
|
||||||
|
if (!shellLink) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the path to your application and the command-line argument for quitting
|
||||||
|
const auto exe = QDir::toNativeSeparators(cExeDir() + cExeName());
|
||||||
|
const auto dir = QDir::toNativeSeparators(QDir(cWorkingDir()).absolutePath());
|
||||||
|
const auto icon = Tray::QuitJumpListIconPath();
|
||||||
|
shellLink->SetArguments(L"-quit");
|
||||||
|
shellLink->SetPath(exe.toStdWString().c_str());
|
||||||
|
shellLink->SetWorkingDirectory(dir.toStdWString().c_str());
|
||||||
|
shellLink->SetIconLocation(icon.toStdWString().c_str(), 0);
|
||||||
|
|
||||||
|
if (const auto propertyStore = shellLink.try_as<IPropertyStore>()) {
|
||||||
|
auto appIdPropVar = PROPVARIANT();
|
||||||
|
hr = InitPropVariantFromString(
|
||||||
|
AppUserModelId::Id().c_str(),
|
||||||
|
&appIdPropVar);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
hr = propertyStore->SetValue(
|
||||||
|
AppUserModelId::Key(),
|
||||||
|
appIdPropVar);
|
||||||
|
PropVariantClear(&appIdPropVar);
|
||||||
|
}
|
||||||
|
auto titlePropVar = PROPVARIANT();
|
||||||
|
hr = InitPropVariantFromString(
|
||||||
|
tr::lng_quit_from_tray(tr::now).toStdWString().c_str(),
|
||||||
|
&titlePropVar);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
hr = propertyStore->SetValue(PKEY_Title, titlePropVar);
|
||||||
|
PropVariantClear(&titlePropVar);
|
||||||
|
}
|
||||||
|
propertyStore->Commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto collection = base::WinRT::TryCreateInstance<IObjectCollection>(
|
||||||
|
CLSID_EnumerableObjectCollection);
|
||||||
|
if (!collection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
collection->AddObject(shellLink.get());
|
||||||
|
|
||||||
|
_jumpList->AddUserTasks(collection.get());
|
||||||
|
added = true;
|
||||||
|
}
|
||||||
|
|
||||||
bool WindowsIntegration::processEvent(
|
bool WindowsIntegration::processEvent(
|
||||||
HWND hWnd,
|
HWND hWnd,
|
||||||
UINT msg,
|
UINT msg,
|
||||||
@ -58,6 +137,9 @@ bool WindowsIntegration::processEvent(
|
|||||||
_taskbarList = base::WinRT::TryCreateInstance<ITaskbarList3>(
|
_taskbarList = base::WinRT::TryCreateInstance<ITaskbarList3>(
|
||||||
CLSID_TaskbarList,
|
CLSID_TaskbarList,
|
||||||
CLSCTX_ALL);
|
CLSCTX_ALL);
|
||||||
|
if (_taskbarList) {
|
||||||
|
createCustomJumpList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
@ -80,10 +162,14 @@ bool WindowsIntegration::processEvent(
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_SETTINGCHANGE:
|
case WM_SETTINGCHANGE:
|
||||||
|
RefreshTaskbarThemeValue();
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(6, 5, 0)
|
#if QT_VERSION < QT_VERSION_CHECK(6, 5, 0)
|
||||||
Core::App().settings().setSystemDarkMode(Platform::IsDarkMode());
|
Core::App().settings().setSystemDarkMode(Platform::IsDarkMode());
|
||||||
#endif // Qt < 6.5.0
|
#endif // Qt < 6.5.0
|
||||||
Core::App().tray().updateIconCounters();
|
Core::App().tray().updateIconCounters();
|
||||||
|
if (_jumpList) {
|
||||||
|
refreshCustomJumpList();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -37,8 +37,12 @@ private:
|
|||||||
LPARAM lParam,
|
LPARAM lParam,
|
||||||
LRESULT *result);
|
LRESULT *result);
|
||||||
|
|
||||||
|
void createCustomJumpList();
|
||||||
|
void refreshCustomJumpList();
|
||||||
|
|
||||||
uint32 _taskbarCreatedMsgId = 0;
|
uint32 _taskbarCreatedMsgId = 0;
|
||||||
winrt::com_ptr<ITaskbarList3> _taskbarList;
|
winrt::com_ptr<ITaskbarList3> _taskbarList;
|
||||||
|
winrt::com_ptr<ICustomDestinationList> _jumpList;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -195,8 +195,7 @@ bool ManageAppLink(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const auto shellLink = base::WinRT::TryCreateInstance<IShellLink>(
|
const auto shellLink = base::WinRT::TryCreateInstance<IShellLink>(
|
||||||
CLSID_ShellLink,
|
CLSID_ShellLink);
|
||||||
CLSCTX_INPROC_SERVER);
|
|
||||||
if (!shellLink) {
|
if (!shellLink) {
|
||||||
if (!silent) LOG(("App Error: could not create instance of IID_IShellLink %1").arg(hr));
|
if (!silent) LOG(("App Error: could not create instance of IID_IShellLink %1").arg(hr));
|
||||||
return false;
|
return false;
|
||||||
|
@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
#include <private/qguiapplication_p.h>
|
#include <private/qguiapplication_p.h>
|
||||||
#include <private/qhighdpiscaling_p.h>
|
#include <private/qhighdpiscaling_p.h>
|
||||||
#include <QSvgRenderer>
|
#include <QSvgRenderer>
|
||||||
|
#include <QBuffer>
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
|
|
||||||
@ -33,18 +34,10 @@ namespace {
|
|||||||
|
|
||||||
constexpr auto kTooltipDelay = crl::time(10000);
|
constexpr auto kTooltipDelay = crl::time(10000);
|
||||||
|
|
||||||
[[nodiscard]] std::optional<bool> IsDarkTaskbar() {
|
std::optional<bool> DarkTaskbar;
|
||||||
static const auto kSystemVersion = QOperatingSystemVersion::current();
|
bool DarkTasbarValueValid/* = false*/;
|
||||||
static const auto kDarkModeAddedVersion = QOperatingSystemVersion(
|
|
||||||
QOperatingSystemVersion::Windows,
|
|
||||||
10,
|
|
||||||
0,
|
|
||||||
18282);
|
|
||||||
static const auto kSupported = (kSystemVersion >= kDarkModeAddedVersion);
|
|
||||||
if (!kSupported) {
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
[[nodiscard]] std::optional<bool> ReadDarkTaskbarValue() {
|
||||||
const auto keyName = L""
|
const auto keyName = L""
|
||||||
"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
|
"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
|
||||||
const auto valueName = L"SystemUsesLightTheme";
|
const auto valueName = L"SystemUsesLightTheme";
|
||||||
@ -64,6 +57,23 @@ constexpr auto kTooltipDelay = crl::time(10000);
|
|||||||
return (value == 0);
|
return (value == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::optional<bool> IsDarkTaskbar() {
|
||||||
|
static const auto kSystemVersion = QOperatingSystemVersion::current();
|
||||||
|
static const auto kDarkModeAddedVersion = QOperatingSystemVersion(
|
||||||
|
QOperatingSystemVersion::Windows,
|
||||||
|
10,
|
||||||
|
0,
|
||||||
|
18282);
|
||||||
|
static const auto kSupported = (kSystemVersion >= kDarkModeAddedVersion);
|
||||||
|
if (!kSupported) {
|
||||||
|
return std::nullopt;
|
||||||
|
} else if (!DarkTasbarValueValid) {
|
||||||
|
DarkTasbarValueValid = true;
|
||||||
|
DarkTaskbar = ReadDarkTaskbarValue();
|
||||||
|
}
|
||||||
|
return DarkTaskbar;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] QImage MonochromeIconFor(int size, bool darkMode) {
|
[[nodiscard]] QImage MonochromeIconFor(int size, bool darkMode) {
|
||||||
Expects(size > 0);
|
Expects(size > 0);
|
||||||
|
|
||||||
@ -339,8 +349,99 @@ QPixmap Tray::IconWithCounter(
|
|||||||
monochrome));
|
monochrome));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WriteIco(const QString &path, std::vector<QImage> images) {
|
||||||
|
Expects(!images.empty());
|
||||||
|
|
||||||
|
auto buffer = QByteArray();
|
||||||
|
const auto write = [&](auto value) {
|
||||||
|
buffer.append(reinterpret_cast<const char*>(&value), sizeof(value));
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto count = int(images.size());
|
||||||
|
|
||||||
|
auto full = 0;
|
||||||
|
auto pngs = std::vector<QByteArray>();
|
||||||
|
pngs.reserve(count);
|
||||||
|
for (const auto &image : images) {
|
||||||
|
pngs.emplace_back();
|
||||||
|
{
|
||||||
|
auto buffer = QBuffer(&pngs.back());
|
||||||
|
image.save(&buffer, "PNG");
|
||||||
|
}
|
||||||
|
full += pngs.back().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Images directory
|
||||||
|
constexpr auto entry = sizeof(int8)
|
||||||
|
+ sizeof(int8)
|
||||||
|
+ sizeof(int8)
|
||||||
|
+ sizeof(int8)
|
||||||
|
+ sizeof(int16)
|
||||||
|
+ sizeof(int16)
|
||||||
|
+ sizeof(uint32)
|
||||||
|
+ sizeof(uint32);
|
||||||
|
static_assert(entry == 16);
|
||||||
|
|
||||||
|
auto offset = 3 * sizeof(int16) + count * entry;
|
||||||
|
full += offset;
|
||||||
|
|
||||||
|
buffer.reserve(full);
|
||||||
|
|
||||||
|
// Thanks https://stackoverflow.com/a/54289564/6509833
|
||||||
|
write(int16(0));
|
||||||
|
write(int16(1));
|
||||||
|
write(int16(count));
|
||||||
|
|
||||||
|
for (auto i = 0; i != count; ++i) {
|
||||||
|
const auto &image = images[i];
|
||||||
|
Assert(image.width() <= 256 && image.height() <= 256);
|
||||||
|
|
||||||
|
write(int8(image.width() == 256 ? 0 : image.width()));
|
||||||
|
write(int8(image.height() == 256 ? 0 : image.height()));
|
||||||
|
write(int8(0)); // palette size
|
||||||
|
write(int8(0)); // reserved
|
||||||
|
write(int16(1)); // color planes
|
||||||
|
write(int16(image.depth())); // bits-per-pixel
|
||||||
|
write(uint32(pngs[i].size())); // size of image in bytes
|
||||||
|
write(uint32(offset)); // offset
|
||||||
|
offset += pngs[i].size();
|
||||||
|
}
|
||||||
|
for (auto i = 0; i != count; ++i) {
|
||||||
|
buffer.append(pngs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto f = QFile(path);
|
||||||
|
if (f.open(QIODevice::WriteOnly)) {
|
||||||
|
f.write(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Tray::QuitJumpListIconPath() {
|
||||||
|
const auto dark = IsDarkTaskbar();
|
||||||
|
const auto key = !dark ? 0 : *dark ? 1 : 2;
|
||||||
|
const auto path = cWorkingDir() + u"tdata/temp/quit_%1.ico"_q.arg(key);
|
||||||
|
if (QFile::exists(path)) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
const auto color = !dark
|
||||||
|
? st::trayCounterBg->c
|
||||||
|
: *dark
|
||||||
|
? QColor(255, 255, 255)
|
||||||
|
: QColor(0, 0, 0, 228);
|
||||||
|
WriteIco(path, {
|
||||||
|
st::winQuitIcon.instance(color, 100, true),
|
||||||
|
st::winQuitIcon.instance(color, 200, true),
|
||||||
|
st::winQuitIcon.instance(color, 300, true),
|
||||||
|
});
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
bool HasMonochromeSetting() {
|
bool HasMonochromeSetting() {
|
||||||
return IsDarkTaskbar().has_value();
|
return IsDarkTaskbar().has_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RefreshTaskbarThemeValue() {
|
||||||
|
DarkTasbarValueValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Platform
|
} // namespace Platform
|
||||||
|
@ -59,6 +59,7 @@ public:
|
|||||||
bool smallIcon,
|
bool smallIcon,
|
||||||
bool monochrome,
|
bool monochrome,
|
||||||
bool supportMode);
|
bool supportMode);
|
||||||
|
[[nodiscard]] static QString QuitJumpListIconPath();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
base::unique_qptr<QPlatformSystemTrayIcon> _icon;
|
base::unique_qptr<QPlatformSystemTrayIcon> _icon;
|
||||||
@ -73,4 +74,6 @@ private:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void RefreshTaskbarThemeValue();
|
||||||
|
|
||||||
} // namespace Platform
|
} // namespace Platform
|
||||||
|
@ -317,6 +317,10 @@ windowArchiveToast: Toast(defaultToast) {
|
|||||||
maxWidth: boxWideWidth;
|
maxWidth: boxWideWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Windows specific
|
||||||
|
|
||||||
|
winQuitIcon: icon {{ "win_quit", windowFg }};
|
||||||
|
|
||||||
// Mac specific
|
// Mac specific
|
||||||
|
|
||||||
macAccessoryWidth: 450.;
|
macAccessoryWidth: 450.;
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 99e36f9ac64048a6b7fcb0e6ee2e8eaca48935e1
|
Subproject commit 7fef09421c2b71e5ab9cf481c0fcf2a0b6d2daf0
|
Loading…
Reference in New Issue
Block a user