Paint native title instead of using custom.

This commit is contained in:
John Preston 2017-11-15 16:46:34 +04:00
parent 4e1b94d37d
commit 7fdeab829f
7 changed files with 162 additions and 15 deletions

View File

@ -65,6 +65,7 @@ public slots:
protected:
bool eventFilter(QObject *obj, QEvent *evt) override;
void handleActiveChangedHook() override;
void stateChangedHook(Qt::WindowState state) override;
void initHook() override;
void updateWindowIcon() override;

View File

@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "history/history_inner_widget.h"
#include "storage/localstorage.h"
#include "window/notifications_manager_default.h"
#include "window/themes/window_theme.h"
#include "platform/platform_notifications_manager.h"
#include "boxes/peer_list_controllers.h"
#include "boxes/about_box.h"
@ -44,6 +45,17 @@ namespace {
// fullscreen mode, after that we'll hide the window no matter what.
constexpr auto kHideAfterFullscreenTimeoutMs = 3000;
id FindClassInSubviews(NSView *parent, NSString *className) {
for (NSView *child in [parent subviews]) {
if ([child isKindOfClass:NSClassFromString(className)]) {
return child;
} else if (id inchild = FindClassInSubviews(child, className)) {
return inchild;
}
}
return nil;
}
} // namespace
@interface MainWindowObserver : NSObject {
@ -65,7 +77,10 @@ class MainWindow::Private {
public:
Private(MainWindow *window);
void setNativeWindow(NSWindow *window, NSView *view);
void setWindowBadge(const QString &str);
void setWindowTitle(const QString &str);
void updateNativeTitle();
void enableShadow(WId winId);
@ -74,16 +89,29 @@ public:
void willEnterFullScreen();
void willExitFullScreen();
void initCustomTitle(NSWindow *window, NSView *view);
bool clipboardHasText();
~Private();
private:
void initCustomTitle();
void refreshWeakTitleReferences();
MainWindow *_public;
friend class MainWindow;
#ifdef OS_MAC_OLD
NSWindow *_nativeWindow = nil;
NSView *_nativeView = nil;
#else // OS_MAC_OLD
NSWindow * __weak _nativeWindow = nil;
NSView * __weak _nativeView = nil;
id __weak _nativeTitleWrapWeak = nil;
id __weak _nativeTitleWeak = nil;
#endif // !OS_MAC_OLD
bool _useNativeTitle = false;
bool _inFullScreen = false;
MainWindowObserver *_observer;
NSPasteboard *_generalPasteboard = nullptr;
int _generalPasteboardChangeCount = -1;
@ -160,16 +188,107 @@ void MainWindow::Private::setWindowBadge(const QString &str) {
}
}
void MainWindow::Private::initCustomTitle(NSWindow *window, NSView *view) {
[window setStyleMask:[window styleMask] | NSFullSizeContentViewWindowMask];
[window setTitlebarAppearsTransparent:YES];
auto inner = [window contentLayoutRect];
auto full = [view frame];
_public->_customTitleHeight = qMax(qRound(full.size.height - inner.size.height), 0);
void MainWindow::Private::setWindowTitle(const QString &str) {
_public->setWindowTitle(str);
updateNativeTitle();
}
void MainWindow::Private::setNativeWindow(NSWindow *window, NSView *view) {
_nativeWindow = window;
_nativeView = view;
initCustomTitle();
}
void MainWindow::Private::initCustomTitle() {
#ifndef OS_MAC_OLD
if (![_nativeWindow respondsToSelector:@selector(contentLayoutRect)]
|| ![_nativeWindow respondsToSelector:@selector(setTitlebarAppearsTransparent:)]) {
return;
}
[_nativeWindow setTitlebarAppearsTransparent:YES];
[[NSNotificationCenter defaultCenter] addObserver:_observer selector:@selector(windowWillEnterFullScreen:) name:NSWindowWillEnterFullScreenNotification object:_nativeWindow];
[[NSNotificationCenter defaultCenter] addObserver:_observer selector:@selector(windowWillExitFullScreen:) name:NSWindowWillExitFullScreenNotification object:_nativeWindow];
// Qt has bug with layer-backed widgets containing QOpenGLWidgets.
// See https://bugreports.qt.io/browse/QTBUG-64494
// Emulate custom title instead (code below).
// [window setStyleMask:[window styleMask] | NSFullSizeContentViewWindowMask];
// auto inner = [window contentLayoutRect];
// auto full = [view frame];
// _public->_customTitleHeight = qMax(qRound(full.size.height - inner.size.height), 0);
_useNativeTitle = true;
setWindowTitle(qsl("Telegram"));
#endif // !OS_MAC_OLD
}
void MainWindow::Private::refreshWeakTitleReferences() {
if (!_nativeWindow) {
return;
}
#ifndef OS_MAC_OLD
[[NSNotificationCenter defaultCenter] addObserver:_observer selector:@selector(windowWillEnterFullScreen:) name:NSWindowWillEnterFullScreenNotification object:window];
[[NSNotificationCenter defaultCenter] addObserver:_observer selector:@selector(windowWillExitFullScreen:) name:NSWindowWillExitFullScreenNotification object:window];
@autoreleasepool {
if (NSView *parent = [[_nativeWindow contentView] superview]) {
if (id titleWrap = FindClassInSubviews(parent, Q2NSString(strTitleWrapClass()))) {
if ([titleWrap respondsToSelector:@selector(setBackgroundColor:)]) {
if (id title = FindClassInSubviews(titleWrap, Q2NSString(strTitleClass()))) {
if ([title respondsToSelector:@selector(setAttributedStringValue:)]) {
_nativeTitleWrapWeak = titleWrap;
_nativeTitleWeak = title;
}
}
}
}
}
}
#endif // !OS_MAC_OLD
}
void MainWindow::Private::updateNativeTitle() {
if (!_useNativeTitle) {
return;
}
#ifndef OS_MAC_OLD
if (!_nativeTitleWrapWeak || !_nativeTitleWeak) {
refreshWeakTitleReferences();
}
if (_nativeTitleWrapWeak && _nativeTitleWeak) {
@autoreleasepool {
auto convertColor = [](QColor color) {
return [NSColor colorWithDeviceRed:color.redF() green:color.greenF() blue:color.blueF() alpha:color.alphaF()];
};
auto adjustFg = [](const style::color &st) {
// Weird thing with NSTextField taking NSAttributedString with
// NSForegroundColorAttributeName set to colorWithDeviceRed:green:blue
// with components all equal to 128 - it ignores it and prints black text!
auto color = st->c;
return (color.red() == 128 && color.green() == 128 && color.blue() == 128)
? QColor(129, 129, 129, color.alpha())
: color;
};
auto active = _public->isActiveWindow();
auto bgColor = (active ? st::titleBgActive : st::titleBg)->c;
auto fgColor = adjustFg(active ? st::titleFgActive : st::titleFg);
auto bgConverted = convertColor(bgColor);
auto fgConverted = convertColor(fgColor);
[_nativeTitleWrapWeak setBackgroundColor:bgConverted];
auto title = Q2NSString(_public->windowTitle());
NSDictionary *attributes = _inFullScreen
? nil
: [NSDictionary dictionaryWithObjectsAndKeys: fgConverted, NSForegroundColorAttributeName, bgConverted, NSBackgroundColorAttributeName, nil];
NSAttributedString *string = [[NSAttributedString alloc] initWithString:title attributes:attributes];
[_nativeTitleWeak setAttributedStringValue:string];
}
}
#endif // !OS_MAC_OLD
}
@ -183,10 +302,12 @@ bool MainWindow::Private::clipboardHasText() {
}
void MainWindow::Private::willEnterFullScreen() {
_inFullScreen = true;
_public->setTitleVisible(false);
}
void MainWindow::Private::willExitFullScreen() {
_inFullScreen = false;
_public->setTitleVisible(true);
}
@ -222,6 +343,12 @@ MainWindow::MainWindow()
trayImgSel = st::macTrayIcon.instance(QColor(255, 255, 255), dbisOne);
_hideAfterFullScreenTimer.setCallback([this] { hideAndDeactivate(); });
subscribe(Window::Theme::Background(), [this](const Window::Theme::BackgroundUpdate &data) {
if (data.paletteChanged()) {
_private->updateNativeTitle();
}
});
}
void MainWindow::closeWithoutDestroy() {
@ -242,14 +369,15 @@ void MainWindow::stateChangedHook(Qt::WindowState state) {
}
}
void MainWindow::handleActiveChangedHook() {
InvokeQueued(this, [this] { _private->updateNativeTitle(); });
}
void MainWindow::initHook() {
_customTitleHeight = 0;
if (auto view = reinterpret_cast<NSView*>(winId())) {
if (auto window = [view window]) {
if ([window respondsToSelector:@selector(contentLayoutRect)]
&& [window respondsToSelector:@selector(setTitlebarAppearsTransparent:)]) {
_private->initCustomTitle(window, view);
}
_private->setNativeWindow(window, view);
}
}
}
@ -345,7 +473,8 @@ void _placeCounter(QImage &img, int size, int count, style::color bg, style::col
}
void MainWindow::updateTitleCounter() {
setWindowTitle(titleVisible() ? QString() : titleText());
//setWindowTitle(titleVisible() ? QString() : titleText());
_private->setWindowTitle(titleText());
}
void MainWindow::unreadCounterChangedHook() {

View File

@ -122,5 +122,7 @@ QString strNotificationAboutThemeChange();
QString strNotificationAboutScreenLocked();
QString strNotificationAboutScreenUnlocked();
QString strStyleOfInterface();
QString strTitleWrapClass();
QString strTitleClass();
bool psLaunchMaps(const LocationCoords &coords);

View File

@ -467,3 +467,13 @@ QString strStyleOfInterface() {
const uint32 letters[] = { 0xEF004041, 0x4C007F70, 0x1F007A70, 0x9E00A76C, 0x8500D165, 0x2E003749, 0x7B00526E, 0x3400E774, 0x3C00FA65, 0x6200B172, 0xF7001D66, 0x0B002961, 0x71008C63, 0x86005465, 0xA3006F53, 0x11006174, 0xCD001779, 0x8200556C, 0x6C009B65 };
return strMakeFromLetters(letters);
}
QString strTitleWrapClass() {
const uint32 letters[] = { 0x4B00F54E, 0x2500A853, 0x2D008154, 0x4600EF69, 0x15006B74, 0xB900E86C, 0x66008A65, 0x3200B262, 0x9F00DC61, 0xA0009E72, 0xCF00EE43, 0x5600316F, 0x9100A76E, 0xBB000A74, 0xB6002661, 0xC7000769, 0x6200386E, 0x6B006D65, 0x1200C572, 0x41009156, 0x3D005569, 0xFE008C65, 0xB800D477 };
return strMakeFromLetters(letters);
}
QString strTitleClass() {
const uint32 letters[] = { 0xF900894E, 0xF300BF53, 0x63009554, 0xEA008965, 0xEB004A78, 0x2E006074, 0xEC008446, 0x5C00DB69, 0x3C00CC65, 0x6F005D6C, 0x6400A064 };
return strMakeFromLetters(letters);
}

View File

@ -173,6 +173,7 @@ void MainWindow::handleActiveChanged() {
}
App::CallDelayed(1, this, [this] {
updateTrayMenu();
handleActiveChangedHook();
});
}

View File

@ -112,6 +112,9 @@ protected:
virtual void updateIsActiveHook() {
}
virtual void handleActiveChangedHook() {
}
void clearWidgets();
virtual void clearWidgetsHook() {
}

View File

@ -100,6 +100,7 @@
}, {
'xcode_settings': {
'CLANG_CXX_LIBRARY': 'libc++',
'CLANG_ENABLE_OBJC_WEAK': 'YES',
'OTHER_LDFLAGS': [
'-framework', 'VideoToolbox',
'-framework', 'VideoDecodeAcceleration',