Improve calls panel in macOS.

Use Qt::Dialog instead of Qt::Tool which works better with window
activation / deactivation handling.

Stop displaying the panel on all spaces when the call is established.
This commit is contained in:
John Preston 2017-05-02 12:08:08 +03:00
parent 0cdac83f8a
commit 5f2e295d63
14 changed files with 149 additions and 129 deletions

View File

@ -184,7 +184,7 @@ void Panel::refreshCallbacks() {
}
void Panel::initLayout() {
setWindowFlags(Qt::WindowFlags(Qt::FramelessWindowHint) | Qt::WindowStaysOnTopHint | Qt::BypassWindowManagerHint | Qt::NoDropShadowWindowHint | Qt::Tool);
setWindowFlags(Qt::WindowFlags(Qt::FramelessWindowHint) | Qt::WindowStaysOnTopHint | Qt::BypassWindowManagerHint | Qt::NoDropShadowWindowHint | Qt::Dialog);
setAttribute(Qt::WA_MacAlwaysShowToolWindow);
setAttribute(Qt::WA_NoSystemBackground, true);
setAttribute(Qt::WA_TranslucentBackground, true);
@ -267,8 +267,9 @@ bool Panel::isGoodUserPhoto(PhotoData *photo) {
void Panel::initGeometry() {
auto center = Messenger::Instance().getPointForCallPanelCenter();
_useTransparency = Platform::TransparentWindowsSupported(center);
_padding = _useTransparency ? st::callShadow.extend : style::margins();
_useTransparency = Platform::TranslucentWindowsSupported(center);
setAttribute(Qt::WA_OpaquePaintEvent, !_useTransparency);
_padding = _useTransparency ? st::callShadow.extend : style::margins(st::lineWidth, st::lineWidth, st::lineWidth, st::lineWidth);
_contentTop = _padding.top() + st::callWidth;
auto screen = QApplication::desktop()->screenGeometry(center);
auto rect = QRect(0, 0, st::callWidth, st::callHeight);
@ -359,10 +360,17 @@ void Panel::updateStatusGeometry() {
void Panel::paintEvent(QPaintEvent *e) {
Painter p(this);
if (_useTransparency) {
Platform::StartTranslucentPaint(p, e);
p.drawPixmapLeft(0, 0, width(), _cache);
} else {
p.drawPixmapLeft(0, 0, width(), _userPhoto);
p.fillRect(myrtlrect(0, st::callWidth, width(), height() - st::callWidth), st::callBg);
p.drawPixmapLeft(_padding.left(), _padding.top(), width(), _userPhoto);
auto callBgOpaque = st::callBg->c;
callBgOpaque.setAlpha(255);
auto brush = QBrush(callBgOpaque);
p.fillRect(0, 0, width(), _padding.top(), brush);
p.fillRect(myrtlrect(0, _padding.top(), _padding.left(), _contentTop - _padding.top()), brush);
p.fillRect(myrtlrect(width() - _padding.right(), _padding.top(), _padding.right(), _contentTop - _padding.top()), brush);
p.fillRect(0, _contentTop, width(), height() - _contentTop, brush);
}
if (!_fingerprint.empty()) {
@ -381,10 +389,16 @@ void Panel::paintEvent(QPaintEvent *e) {
void Panel::mousePressEvent(QMouseEvent *e) {
auto dragArea = myrtlrect(_padding.left(), _padding.top(), st::callWidth, st::callWidth);
if (e->button() == Qt::LeftButton && dragArea.contains(e->pos())) {
_dragging = true;
_dragStartMousePosition = e->globalPos();
_dragStartMyPosition = QPoint(x(), y());
if (e->button() == Qt::LeftButton) {
if (dragArea.contains(e->pos())) {
_dragging = true;
_dragStartMousePosition = e->globalPos();
_dragStartMyPosition = QPoint(x(), y());
} else if (!rect().contains(e->pos())) {
if (_call && _call->state() == State::Established) {
hideDeactivated();
}
}
}
}
@ -458,8 +472,15 @@ void Panel::stateChanged(State state) {
if (_fingerprint.empty() && _call && _call->isKeyShaForFingerprintReady()) {
fillFingerprint();
}
if (state == State::Established && !isActiveWindow()) {
hideDeactivated();
if ((state == State::Starting) || (state == State::WaitingIncoming)) {
Platform::ReInitOnTopPanel(this);
} else {
Platform::DeInitOnTopPanel(this);
}
if (state == State::Established) {
if (!isActiveWindow()) {
hideDeactivated();
}
}
}

View File

@ -377,10 +377,7 @@ void finish() {
_psEventFilter = nullptr;
}
void SetWatchingMediaKeys(bool watching) {
}
bool TransparentWindowsSupported(QPoint globalPosition) {
bool TranslucentWindowsSupported(QPoint globalPosition) {
if (auto app = static_cast<QGuiApplication*>(QCoreApplication::instance())) {
if (auto native = app->platformNativeInterface()) {
if (auto desktop = QApplication::desktop()) {
@ -405,9 +402,6 @@ bool TransparentWindowsSupported(QPoint globalPosition) {
return false;
}
void InitOnTopPanel(QWidget *panel) {
}
namespace ThirdParty {
void start() {

View File

@ -20,6 +20,25 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include <execinfo.h>
#include <signal.h>
namespace Platform {
inline void SetWatchingMediaKeys(bool watching) {
}
inline void StartTranslucentPaint(QPainter &p, QPaintEvent *e) {
}
inline void InitOnTopPanel(QWidget *panel) {
}
inline void DeInitOnTopPanel(QWidget *panel) {
}
inline void ReInitOnTopPanel(QWidget *panel) {
}
} // namespace Platform
inline QString psServerPrefix() {
return qsl("/tmp/");
}

View File

@ -48,9 +48,6 @@ public:
return _customTitleHeight;
}
// It is placed here while the window handles activeSpaceDidChange event.
void customNotificationCreated(QWidget *notification);
~MainWindow();
class Private;
@ -104,16 +101,9 @@ private:
void updateTitleCounter();
void updateIconCounters();
class CustomNotificationHandle;
friend class CustomNotificationHandle;
void customNotificationDestroyed(CustomNotificationHandle *handle);
void activateCustomNotifications();
friend class Private;
std::unique_ptr<Private> _private;
std::set<CustomNotificationHandle*> _customNotifications;
mutable bool psIdle;
mutable QTimer psIdleTimer;

View File

@ -73,7 +73,6 @@ public:
void willEnterFullScreen();
void willExitFullScreen();
void activateCustomNotifications();
void initCustomTitle(NSWindow *window, NSView *view);
@ -92,25 +91,6 @@ private:
};
class MainWindow::CustomNotificationHandle : public QObject {
public:
CustomNotificationHandle(QWidget *parent) : QObject(parent) {
}
void activate() {
auto widget = static_cast<QWidget*>(parent());
NSWindow *wnd = [reinterpret_cast<NSView *>(widget->winId()) window];
[wnd orderFront:wnd];
}
~CustomNotificationHandle() {
if (auto window = App::wnd()) {
window->customNotificationDestroyed(this);
}
}
};
} // namespace Platform
@implementation MainWindowObserver {
@ -126,7 +106,6 @@ public:
}
- (void) activeSpaceDidChange:(NSNotification *)aNotification {
_private->activateCustomNotifications();
}
- (void) darkModeChanged:(NSNotification *)aNotification {
@ -211,10 +190,6 @@ void MainWindow::Private::willExitFullScreen() {
_public->setTitleVisible(true);
}
void MainWindow::Private::activateCustomNotifications() {
_public->activateCustomNotifications();
}
void MainWindow::Private::enableShadow(WId winId) {
// [[(NSView*)winId window] setStyleMask:NSBorderlessWindowMask];
// [[(NSView*)winId window] setHasShadow:YES];
@ -527,20 +502,6 @@ void MainWindow::psUpdateSysMenu(Qt::WindowState state) {
void MainWindow::psUpdateMargins() {
}
void MainWindow::customNotificationCreated(QWidget *notification) {
_customNotifications.insert(object_ptr<CustomNotificationHandle>(notification));
}
void MainWindow::customNotificationDestroyed(CustomNotificationHandle *handle) {
_customNotifications.erase(handle);
}
void MainWindow::activateCustomNotifications() {
for (auto handle : _customNotifications) {
handle->activate();
}
}
void MainWindow::updateGlobalMenuHook() {
if (!App::wnd() || !positionInited()) return;

View File

@ -396,19 +396,14 @@ void finish() {
objc_finish();
}
bool TransparentWindowsSupported(QPoint globalPosition) {
return true;
void StartTranslucentPaint(QPainter &p, QPaintEvent *e) {
#ifdef OS_MAC_OLD
p.setCompositionMode(QPainter::CompositionMode_Source);
p.fillRect(e->rect(), Qt::transparent);
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
#endif // OS_MAC_OLD
}
namespace ThirdParty {
void start() {
}
void finish() {
}
} // namespace ThirdParty
} // namespace Platform
void psNewVersion() {

View File

@ -19,6 +19,23 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "platform/mac/specific_mac_p.h"
namespace Platform {
inline bool TranslucentWindowsSupported(QPoint globalPosition) {
return true;
}
namespace ThirdParty {
inline void start() {
}
inline void finish() {
}
} // namespace ThirdParty
} // namespace Platform
inline QString psServerPrefix() {
#ifndef OS_MAC_STORE
return qsl("/tmp/");

View File

@ -215,13 +215,27 @@ void InitOnTopPanel(QWidget *panel) {
[platformPanel setFloatingPanel:YES];
[platformPanel setHidesOnDeactivate:NO];
if (auto window = App::wnd()) {
window->customNotificationCreated(panel);
}
objc_ignoreApplicationActivationRightNow();
}
void DeInitOnTopPanel(QWidget *panel) {
auto platformWindow = [reinterpret_cast<NSView*>(panel->winId()) window];
t_assert([platformWindow isKindOfClass:[NSPanel class]]);
auto platformPanel = static_cast<NSPanel*>(platformWindow);
auto newBehavior = ([platformPanel collectionBehavior] & (~NSWindowCollectionBehaviorCanJoinAllSpaces)) | NSWindowCollectionBehaviorMoveToActiveSpace;
[platformPanel setCollectionBehavior:newBehavior];
}
void ReInitOnTopPanel(QWidget *panel) {
auto platformWindow = [reinterpret_cast<NSView*>(panel->winId()) window];
t_assert([platformWindow isKindOfClass:[NSPanel class]]);
auto platformPanel = static_cast<NSPanel*>(platformWindow);
auto newBehavior = ([platformPanel collectionBehavior] & (~NSWindowCollectionBehaviorMoveToActiveSpace)) | NSWindowCollectionBehaviorCanJoinAllSpaces;
[platformPanel setCollectionBehavior:newBehavior];
}
} // namespace Platform
bool objc_darkMode() {

View File

@ -34,9 +34,11 @@ void start();
void finish();
void SetWatchingMediaKeys(bool watching);
bool TransparentWindowsSupported(QPoint globalPosition);
bool TranslucentWindowsSupported(QPoint globalPosition);
void StartTranslucentPaint(QPainter &p, QPaintEvent *e);
void InitOnTopPanel(QWidget *panel);
void DeInitOnTopPanel(QWidget *panel);
void ReInitOnTopPanel(QWidget *panel);
namespace ThirdParty {

View File

@ -527,16 +527,6 @@ void finish() {
EventFilter::destroy();
}
void SetWatchingMediaKeys(bool watching) {
}
bool TransparentWindowsSupported(QPoint globalPosition) {
return true;
}
void InitOnTopPanel(QWidget *panel) {
}
namespace ThirdParty {
void start() {

View File

@ -22,6 +22,29 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include <windows.h>
namespace Platform {
inline void SetWatchingMediaKeys(bool watching) {
}
inline bool TranslucentWindowsSupported(QPoint globalPosition) {
return true;
}
inline void StartTranslucentPaint(QPainter &p, QPaintEvent *e) {
}
inline void InitOnTopPanel(QWidget *panel) {
}
inline void DeInitOnTopPanel(QWidget *panel) {
}
inline void ReInitOnTopPanel(QWidget *panel) {
}
} // namespace Platform
inline QString psServerPrefix() {
return qsl("Global\\");
}

View File

@ -107,11 +107,9 @@ PopupMenu::Actions &PopupMenu::actions() {
void PopupMenu::paintEvent(QPaintEvent *e) {
Painter p(this);
#ifdef OS_MAC_OLD
p.setCompositionMode(QPainter::CompositionMode_Source);
p.fillRect(e->rect(), Qt::transparent);
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
#endif // OS_MAC_OLD
if (_useTransparency) {
Platform::StartTranslucentPaint(p, e);
}
auto ms = getms();
if (_a_show.animating(ms)) {
@ -425,7 +423,8 @@ void PopupMenu::showMenu(const QPoint &p, PopupMenu *parent, TriggeredSource sou
auto origin = PanelAnimation::Origin::TopLeft;
auto w = p - QPoint(0, _padding.top());
auto r = Sandbox::screenGeometry(p);
_useTransparency = Platform::TransparentWindowsSupported(p);
_useTransparency = Platform::TranslucentWindowsSupported(p);
setAttribute(Qt::WA_OpaquePaintEvent, !_useTransparency);
handleCompositingUpdate();
if (rtl()) {
if (w.x() - width() < r.x() - _padding.left()) {

View File

@ -19,6 +19,7 @@
#include "mainwindow.h"
#include "styles/style_widgets.h"
#include "platform/platform_specific.h"
namespace Ui {
@ -45,17 +46,17 @@ AbstractTooltipShower::~AbstractTooltipShower() {
Tooltip::Tooltip() : TWidget(nullptr) {
TooltipInstance = this;
setWindowFlags(Qt::WindowFlags(Qt::FramelessWindowHint) | Qt::BypassWindowManagerHint | Qt::ToolTip | Qt::NoDropShadowWindowHint);
setWindowFlags(Qt::WindowFlags(Qt::FramelessWindowHint) | Qt::BypassWindowManagerHint | Qt::NoDropShadowWindowHint | Qt::ToolTip);
setAttribute(Qt::WA_NoSystemBackground, true);
setAttribute(Qt::WA_TranslucentBackground, true);
_showTimer.setSingleShot(true);
connect(&_showTimer, SIGNAL(timeout()), this, SLOT(onShow()));
_showTimer.setCallback([this] { performShow(); });
_hideByLeaveTimer.setCallback([this] { Hide(); });
connect(App::wnd()->windowHandle(), SIGNAL(activeChanged()), this, SLOT(onWndActiveChanged()));
}
void Tooltip::onShow() {
void Tooltip::performShow() {
if (_shower) {
auto text = _shower->tooltipWindowActive() ? _shower->tooltipText() : QString();
if (text.isEmpty()) {
@ -74,9 +75,9 @@ void Tooltip::onWndActiveChanged() {
bool Tooltip::eventFilter(QObject *o, QEvent *e) {
if (e->type() == QEvent::Leave) {
_hideByLeaveTimer.start(10);
_hideByLeaveTimer.callOnce(10);
} else if (e->type() == QEvent::Enter) {
_hideByLeaveTimer.stop();
_hideByLeaveTimer.cancel();
} else if (e->type() == QEvent::MouseMove) {
if ((QCursor::pos() - _point).manhattanLength() > QApplication::startDragDistance()) {
Hide();
@ -85,10 +86,6 @@ bool Tooltip::eventFilter(QObject *o, QEvent *e) {
return TWidget::eventFilter(o, e);
}
void Tooltip::onHideByLeave() {
Hide();
}
Tooltip::~Tooltip() {
if (TooltipInstance == this) {
TooltipInstance = 0;
@ -96,10 +93,7 @@ Tooltip::~Tooltip() {
}
void Tooltip::popup(const QPoint &m, const QString &text, const style::Tooltip *st) {
if (!_hideByLeaveTimer.isSingleShot()) {
_hideByLeaveTimer.setSingleShot(true);
connect(&_hideByLeaveTimer, SIGNAL(timeout()), this, SLOT(onHideByLeave()));
if (!_isEventFilter) {
QCoreApplication::instance()->installEventFilter(this);
}
@ -107,7 +101,7 @@ void Tooltip::popup(const QPoint &m, const QString &text, const style::Tooltip *
_st = st;
_text = Text(_st->textStyle, text, _textPlainOptions, _st->widthMax, true);
_useTransparency = Platform::TransparentWindowsSupported(_point);
_useTransparency = Platform::TranslucentWindowsSupported(_point);
setAttribute(Qt::WA_OpaquePaintEvent, !_useTransparency);
int32 addw = 2 * st::lineWidth + _st->textPadding.left() + _st->textPadding.right();
@ -150,18 +144,16 @@ void Tooltip::popup(const QPoint &m, const QString &text, const style::Tooltip *
setGeometry(QRect(p, s));
_hideByLeaveTimer.stop();
_hideByLeaveTimer.cancel();
show();
}
void Tooltip::paintEvent(QPaintEvent *e) {
Painter p(this);
#ifdef OS_MAC_OLD
p.setCompositionMode(QPainter::CompositionMode_Source);
p.fillRect(e->rect(), Qt::transparent);
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
#endif // OS_MAC_OLD
if (_useTransparency) {
Platform::StartTranslucentPaint(p, e);
}
if (_useTransparency) {
p.setPen(_st->textBorder);
@ -194,17 +186,17 @@ void Tooltip::Show(int32 delay, const AbstractTooltipShower *shower) {
}
TooltipInstance->_shower = shower;
if (delay >= 0) {
TooltipInstance->_showTimer.start(delay);
TooltipInstance->_showTimer.callOnce(delay);
} else {
TooltipInstance->onShow();
TooltipInstance->performShow();
}
}
void Tooltip::Hide() {
if (auto instance = TooltipInstance) {
TooltipInstance = nullptr;
instance->_showTimer.stop();
instance->_hideByLeaveTimer.stop();
instance->_showTimer.cancel();
instance->_hideByLeaveTimer.cancel();
instance->hide();
instance->deleteLater();
}

View File

@ -17,6 +17,8 @@
*/
#pragma once
#include "base/timer.h"
namespace style {
struct Tooltip;
} // namespace style
@ -41,9 +43,7 @@ public:
static void Hide();
private slots:
void onShow();
void onWndActiveChanged();
void onHideByLeave();
protected:
void paintEvent(QPaintEvent *e) override;
@ -52,6 +52,8 @@ protected:
bool eventFilter(QObject *o, QEvent *e) override;
private:
void performShow();
Tooltip();
~Tooltip();
@ -59,14 +61,15 @@ private:
friend class AbstractTooltipShower;
const AbstractTooltipShower *_shower = nullptr;
QTimer _showTimer;
base::Timer _showTimer;
Text _text;
QPoint _point;
const style::Tooltip *_st = nullptr;
QTimer _hideByLeaveTimer;
base::Timer _hideByLeaveTimer;
bool _isEventFilter = false;
bool _useTransparency = true;
};