mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-01-29 19:03:03 +00:00
Fix calls build in Xcode. Fix calls panel in Retina.
Also implement panels that appear in all spaces on macOS. Using them for calls panels and custom notifications, so it will be possible to use custom notifications in macOS as well.
This commit is contained in:
parent
e050e270fc
commit
0cdac83f8a
@ -483,7 +483,7 @@ index 83c960d..03ae969 100755
|
||||
}
|
||||
@end
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
|
||||
index 4d0458a..fde238a 100644
|
||||
index 4d0458a..3357a5e 100644
|
||||
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
|
||||
@@ -167,7 +167,8 @@ static bool isMouseEvent(NSEvent *ev)
|
||||
@ -496,7 +496,24 @@ index 4d0458a..fde238a 100644
|
||||
NSPoint loc = [theEvent locationInWindow];
|
||||
NSRect windowFrame = [self.window legacyConvertRectFromScreen:[self.window frame]];
|
||||
NSRect contentFrame = [[self.window contentView] frame];
|
||||
@@ -914,6 +915,19 @@ void QCocoaWindow::setWindowFilePath(const QString &filePath)
|
||||
@@ -795,6 +796,16 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags)
|
||||
{
|
||||
Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
|
||||
NSInteger styleMask = NSBorderlessWindowMask;
|
||||
+
|
||||
+ // Patch: allow creating panels floating on all spaces in macOS.
|
||||
+ // If you call "setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary" before
|
||||
+ // setting the "NSNonactivatingPanelMask" bit in the style mask it won't work after that.
|
||||
+ // So we need a way to set that bit before Qt sets collection behavior the way it does.
|
||||
+ QVariant nonactivatingPanelMask = window()->property("_td_macNonactivatingPanelMask");
|
||||
+ if (nonactivatingPanelMask.isValid() && nonactivatingPanelMask.toBool()) {
|
||||
+ styleMask |= NSNonactivatingPanelMask;
|
||||
+ }
|
||||
+
|
||||
if (flags & Qt::FramelessWindowHint)
|
||||
return styleMask;
|
||||
if ((type & Qt::Popup) == Qt::Popup) {
|
||||
@@ -914,6 +925,19 @@ void QCocoaWindow::setWindowFilePath(const QString &filePath)
|
||||
[m_nsWindow setRepresentedFilename: fi.exists() ? QCFString::toNSString(filePath) : @""];
|
||||
}
|
||||
|
||||
@ -516,7 +533,7 @@ index 4d0458a..fde238a 100644
|
||||
void QCocoaWindow::setWindowIcon(const QIcon &icon)
|
||||
{
|
||||
QCocoaAutoReleasePool pool;
|
||||
@@ -929,7 +943,10 @@ void QCocoaWindow::setWindowIcon(const QIcon &icon)
|
||||
@@ -929,7 +953,10 @@ void QCocoaWindow::setWindowIcon(const QIcon &icon)
|
||||
if (icon.isNull()) {
|
||||
[iconButton setImage:nil];
|
||||
} else {
|
||||
|
@ -11505,7 +11505,7 @@ index 8152c57..5ddd7b3 100644
|
||||
}
|
||||
}
|
||||
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
|
||||
index c0d5904..2991fca 100644
|
||||
index c0d5904..f3c2047 100644
|
||||
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
|
||||
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
|
||||
@@ -141,7 +141,8 @@ static bool isMouseEvent(NSEvent *ev)
|
||||
@ -11518,7 +11518,24 @@ index c0d5904..2991fca 100644
|
||||
NSPoint loc = [theEvent locationInWindow];
|
||||
NSRect windowFrame = [self.window convertRectFromScreen:[self.window frame]];
|
||||
NSRect contentFrame = [[self.window contentView] frame];
|
||||
@@ -943,6 +944,19 @@ void QCocoaWindow::setWindowFilePath(const QString &filePath)
|
||||
@@ -811,6 +812,16 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags)
|
||||
{
|
||||
Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
|
||||
NSInteger styleMask = NSBorderlessWindowMask;
|
||||
+
|
||||
+ // Patch: allow creating panels floating on all spaces in macOS.
|
||||
+ // If you call "setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary" before
|
||||
+ // setting the "NSNonactivatingPanelMask" bit in the style mask it won't work after that.
|
||||
+ // So we need a way to set that bit before Qt sets collection behavior the way it does.
|
||||
+ QVariant nonactivatingPanelMask = window()->property("_td_macNonactivatingPanelMask");
|
||||
+ if (nonactivatingPanelMask.isValid() && nonactivatingPanelMask.toBool()) {
|
||||
+ styleMask |= NSNonactivatingPanelMask;
|
||||
+ }
|
||||
+
|
||||
if (flags & Qt::FramelessWindowHint)
|
||||
return styleMask;
|
||||
if ((type & Qt::Popup) == Qt::Popup) {
|
||||
@@ -943,6 +954,19 @@ void QCocoaWindow::setWindowFilePath(const QString &filePath)
|
||||
[m_nsWindow setRepresentedFilename: fi.exists() ? QCFString::toNSString(filePath) : @""];
|
||||
}
|
||||
|
||||
@ -11538,7 +11555,7 @@ index c0d5904..2991fca 100644
|
||||
void QCocoaWindow::setWindowIcon(const QIcon &icon)
|
||||
{
|
||||
QMacAutoReleasePool pool;
|
||||
@@ -958,7 +972,9 @@ void QCocoaWindow::setWindowIcon(const QIcon &icon)
|
||||
@@ -958,7 +982,9 @@ void QCocoaWindow::setWindowIcon(const QIcon &icon)
|
||||
if (icon.isNull()) {
|
||||
[iconButton setImage:nil];
|
||||
} else {
|
||||
|
@ -46,10 +46,10 @@ public:
|
||||
, _cache(cache) {
|
||||
resize(cache.width() / cache.devicePixelRatio(), cache.height() / cache.devicePixelRatio());
|
||||
|
||||
setWindowFlags(Qt::WindowFlags(Qt::FramelessWindowHint) | Qt::WindowStaysOnTopHint | Qt::BypassWindowManagerHint | Qt::NoDropShadowWindowHint | Qt::Tool);
|
||||
setAttribute(Qt::WA_MacAlwaysShowToolWindow);
|
||||
setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::BypassWindowManagerHint | Qt::NoDropShadowWindowHint);
|
||||
|
||||
setWindowOpacity(0.);
|
||||
show();
|
||||
|
@ -113,16 +113,16 @@ BoxController::Row::Row(HistoryItem *item) : PeerListBox::Row(item->history()->p
|
||||
}
|
||||
|
||||
void BoxController::Row::paintStatusText(Painter &p, int x, int y, int outerWidth, bool selected) {
|
||||
auto &icon = ([this] {
|
||||
auto icon = ([this] {
|
||||
switch (_type) {
|
||||
case Type::In: return st::callArrowIn;
|
||||
case Type::Out: return st::callArrowOut;
|
||||
case Type::Missed: return st::callArrowMissed;
|
||||
case Type::In: return &st::callArrowIn;
|
||||
case Type::Out: return &st::callArrowOut;
|
||||
case Type::Missed: return &st::callArrowMissed;
|
||||
}
|
||||
Unexpected("_type in Calls::BoxController::Row::paintStatusText().");
|
||||
})();
|
||||
icon.paint(p, x + st::callArrowPosition.x(), y + st::callArrowPosition.y(), outerWidth);
|
||||
x += + st::callArrowPosition.x() + icon.width() + st::callArrowSkip;
|
||||
icon->paint(p, x + st::callArrowPosition.x(), y + st::callArrowPosition.y(), outerWidth);
|
||||
x += + st::callArrowPosition.x() + icon->width() + st::callArrowSkip;
|
||||
|
||||
PeerListBox::Row::paintStatusText(p, x, y, outerWidth, selected);
|
||||
}
|
||||
@ -285,7 +285,7 @@ bool BoxController::insertRow(HistoryItem *item, InsertWay way) {
|
||||
}
|
||||
}
|
||||
(way == InsertWay::Append) ? view()->appendRow(createRow(item)) : view()->prependRow(createRow(item));
|
||||
view()->reorderRows([](auto &begin, auto &end) {
|
||||
view()->reorderRows([](auto &&begin, auto &&end) {
|
||||
std::sort(begin, end, [](auto &a, auto &b) {
|
||||
return static_cast<Row&>(*a).maxItemId() > static_cast<Row&>(*a).maxItemId();
|
||||
});
|
||||
|
@ -184,8 +184,6 @@ void Panel::refreshCallbacks() {
|
||||
}
|
||||
|
||||
void Panel::initLayout() {
|
||||
hide();
|
||||
|
||||
setWindowFlags(Qt::WindowFlags(Qt::FramelessWindowHint) | Qt::WindowStaysOnTopHint | Qt::BypassWindowManagerHint | Qt::NoDropShadowWindowHint | Qt::Tool);
|
||||
setAttribute(Qt::WA_MacAlwaysShowToolWindow);
|
||||
setAttribute(Qt::WA_NoSystemBackground, true);
|
||||
@ -203,6 +201,8 @@ void Panel::initLayout() {
|
||||
refreshUserPhoto();
|
||||
});
|
||||
createDefaultCacheImage();
|
||||
|
||||
Platform::InitOnTopPanel(this);
|
||||
}
|
||||
|
||||
void Panel::processUserPhoto() {
|
||||
@ -235,7 +235,7 @@ void Panel::refreshUserPhoto() {
|
||||
|
||||
void Panel::createUserpicCache(ImagePtr image) {
|
||||
auto size = st::callWidth * cIntRetinaFactor();
|
||||
auto options = _useTransparency ? (Images::Option::RoundedLarge | Images::Option::RoundedTopLeft | Images::Option::RoundedTopRight | Images::Option::Smooth) : 0;
|
||||
auto options = _useTransparency ? (Images::Option::RoundedLarge | Images::Option::RoundedTopLeft | Images::Option::RoundedTopRight | Images::Option::Smooth) : Images::Option::None;
|
||||
auto width = image->width();
|
||||
auto height = image->height();
|
||||
if (width > height) {
|
||||
@ -245,7 +245,7 @@ void Panel::createUserpicCache(ImagePtr image) {
|
||||
height = qMax((height * size) / width, 1);
|
||||
width = size;
|
||||
}
|
||||
_userPhoto = image->pixNoCache(width, height, options, size, size);
|
||||
_userPhoto = image->pixNoCache(width, height, options, st::callWidth, st::callWidth);
|
||||
if (cRetina()) _userPhoto.setDevicePixelRatio(cRetinaFactor());
|
||||
|
||||
refreshCacheImageUserPhoto();
|
||||
@ -301,7 +301,8 @@ void Panel::createDefaultCacheImage() {
|
||||
if (!_useTransparency || !_cache.isNull()) {
|
||||
return;
|
||||
}
|
||||
auto cache = QImage(size(), QImage::Format_ARGB32_Premultiplied);
|
||||
auto cache = QImage(size() * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
|
||||
cache.setDevicePixelRatio(cRetinaFactor());
|
||||
cache.fill(Qt::transparent);
|
||||
{
|
||||
Painter p(&cache);
|
||||
@ -317,7 +318,8 @@ void Panel::createDefaultCacheImage() {
|
||||
}
|
||||
|
||||
void Panel::refreshCacheImageUserPhoto() {
|
||||
auto cache = QImage(size(), QImage::Format_ARGB32_Premultiplied);
|
||||
auto cache = QImage(size() * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
|
||||
cache.setDevicePixelRatio(cRetinaFactor());
|
||||
cache.fill(Qt::transparent);
|
||||
{
|
||||
Painter p(&cache);
|
||||
|
@ -45,11 +45,9 @@ void TopBar::initControls() {
|
||||
_mute->setClickedCallback([this] {
|
||||
_call->setMute(!_call->isMute());
|
||||
});
|
||||
setMuted(_call->isMute());
|
||||
subscribe(_call->muteChanged(), [this](bool mute) {
|
||||
_mute->setIconOverride(mute ? &st::callBarUnmuteIcon : nullptr);
|
||||
_mute->setRippleColorOverride(mute ? &st::callBarUnmuteRipple : nullptr);
|
||||
_hangup->setRippleColorOverride(mute ? &st::callBarUnmuteRipple : nullptr);
|
||||
_muted = mute;
|
||||
setMuted(mute);
|
||||
update();
|
||||
});
|
||||
_info->setClickedCallback([this] {
|
||||
@ -66,6 +64,13 @@ void TopBar::initControls() {
|
||||
updateDurationText();
|
||||
}
|
||||
|
||||
void TopBar::setMuted(bool mute) {
|
||||
_mute->setIconOverride(mute ? &st::callBarUnmuteIcon : nullptr);
|
||||
_mute->setRippleColorOverride(mute ? &st::callBarUnmuteRipple : nullptr);
|
||||
_hangup->setRippleColorOverride(mute ? &st::callBarUnmuteRipple : nullptr);
|
||||
_muted = mute;
|
||||
}
|
||||
|
||||
void TopBar::updateDurationText() {
|
||||
if (!_call) {
|
||||
return;
|
||||
|
@ -48,6 +48,7 @@ private:
|
||||
void updateDurationText();
|
||||
void updateControlsGeometry();
|
||||
void startDurationUpdateTimer(TimeMs currentDuration);
|
||||
void setMuted(bool mute);
|
||||
|
||||
base::weak_unique_ptr<Call> _call;
|
||||
|
||||
|
@ -25,9 +25,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
namespace Platform {
|
||||
namespace Notifications {
|
||||
|
||||
inline void CustomNotificationShownHook(QWidget *widget) {
|
||||
}
|
||||
|
||||
inline bool SkipAudio() {
|
||||
return false;
|
||||
}
|
||||
|
@ -405,6 +405,9 @@ bool TransparentWindowsSupported(QPoint globalPosition) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void InitOnTopPanel(QWidget *panel) {
|
||||
}
|
||||
|
||||
namespace ThirdParty {
|
||||
|
||||
void start() {
|
||||
|
@ -168,16 +168,6 @@ void FlashBounce() {
|
||||
[NSApp requestUserAttention:NSInformationalRequest];
|
||||
}
|
||||
|
||||
void CustomNotificationShownHook(QWidget *widget) {
|
||||
widget->hide();
|
||||
objc_holdOnTop(widget->winId());
|
||||
widget->show();
|
||||
psShowOverAll(widget, false);
|
||||
if (auto window = App::wnd()) {
|
||||
window->customNotificationCreated(widget);
|
||||
}
|
||||
}
|
||||
|
||||
class Manager::Private : public QObject, private base::Subscriber {
|
||||
public:
|
||||
Private(Manager *manager);
|
||||
|
@ -20,7 +20,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
// e is NSEvent*
|
||||
bool objc_handleMediaKeyEvent(void *e);
|
||||
|
||||
void objc_holdOnTop(WId winId);
|
||||
bool objc_darkMode();
|
||||
void objc_showOverAll(WId winId, bool canFocus = true);
|
||||
void objc_bringToBack(WId winId);
|
||||
|
@ -36,7 +36,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kIgnoreActivationTimeoutMs = 1500;
|
||||
constexpr auto kIgnoreActivationTimeoutMs = 500;
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -196,13 +196,34 @@ void SetWatchingMediaKeys(bool watching) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Platform
|
||||
void InitOnTopPanel(QWidget *panel) {
|
||||
Expects(!panel->windowHandle());
|
||||
|
||||
void objc_holdOnTop(WId winId) {
|
||||
NSWindow *wnd = [reinterpret_cast<NSView *>(winId) window];
|
||||
[wnd setHidesOnDeactivate:NO];
|
||||
// Force creating windowHandle() without creating the platform window yet.
|
||||
panel->setAttribute(Qt::WA_NativeWindow, true);
|
||||
panel->windowHandle()->setProperty("_td_macNonactivatingPanelMask", QVariant(true));
|
||||
panel->setAttribute(Qt::WA_NativeWindow, false);
|
||||
|
||||
panel->createWinId();
|
||||
|
||||
auto platformWindow = [reinterpret_cast<NSView*>(panel->winId()) window];
|
||||
t_assert([platformWindow isKindOfClass:[NSPanel class]]);
|
||||
|
||||
auto platformPanel = static_cast<NSPanel*>(platformWindow);
|
||||
[platformPanel setLevel:NSPopUpMenuWindowLevel];
|
||||
[platformPanel setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces|NSWindowCollectionBehaviorStationary|NSWindowCollectionBehaviorFullScreenAuxiliary|NSWindowCollectionBehaviorIgnoresCycle];
|
||||
[platformPanel setFloatingPanel:YES];
|
||||
[platformPanel setHidesOnDeactivate:NO];
|
||||
|
||||
if (auto window = App::wnd()) {
|
||||
window->customNotificationCreated(panel);
|
||||
}
|
||||
|
||||
objc_ignoreApplicationActivationRightNow();
|
||||
}
|
||||
|
||||
} // namespace Platform
|
||||
|
||||
bool objc_darkMode() {
|
||||
bool result = false;
|
||||
@autoreleasepool {
|
||||
|
@ -25,7 +25,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
namespace Platform {
|
||||
namespace Notifications {
|
||||
|
||||
void CustomNotificationShownHook(QWidget *widget);
|
||||
bool SkipAudio();
|
||||
bool SkipToast();
|
||||
|
||||
|
@ -36,6 +36,8 @@ void finish();
|
||||
void SetWatchingMediaKeys(bool watching);
|
||||
bool TransparentWindowsSupported(QPoint globalPosition);
|
||||
|
||||
void InitOnTopPanel(QWidget *panel);
|
||||
|
||||
namespace ThirdParty {
|
||||
|
||||
void start();
|
||||
|
@ -25,9 +25,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||
namespace Platform {
|
||||
namespace Notifications {
|
||||
|
||||
inline void CustomNotificationShownHook(QWidget *widget) {
|
||||
}
|
||||
|
||||
class Manager : public Window::Notifications::NativeManager {
|
||||
public:
|
||||
Manager(Window::Notifications::System *system);
|
||||
|
@ -534,6 +534,9 @@ bool TransparentWindowsSupported(QPoint globalPosition) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void InitOnTopPanel(QWidget *panel) {
|
||||
}
|
||||
|
||||
namespace ThirdParty {
|
||||
|
||||
void start() {
|
||||
|
@ -199,7 +199,6 @@ void Manager::showNextFromQueue() {
|
||||
queued.item,
|
||||
queued.forwardedCount,
|
||||
startPosition, startShift, shiftDirection);
|
||||
Platform::Notifications::CustomNotificationShownHook(notification.get());
|
||||
_notifications.push_back(std::move(notification));
|
||||
--count;
|
||||
} while (count > 0 && !_queuedNotifications.empty());
|
||||
@ -353,9 +352,11 @@ Widget::Widget(Manager *manager, QPoint startPosition, int shift, Direction shif
|
||||
, _a_shift(animation(this, &Widget::step_shift)) {
|
||||
setWindowOpacity(0.);
|
||||
|
||||
setWindowFlags(qFlags(Qt::Tool) | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::BypassWindowManagerHint | Qt::NoDropShadowWindowHint);
|
||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
setWindowFlags(Qt::WindowFlags(Qt::FramelessWindowHint) | Qt::WindowStaysOnTopHint | Qt::BypassWindowManagerHint | Qt::NoDropShadowWindowHint | Qt::Tool);
|
||||
setAttribute(Qt::WA_MacAlwaysShowToolWindow);
|
||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
|
||||
Platform::InitOnTopPanel(this);
|
||||
|
||||
_a_opacity.start([this] { opacityAnimationCallback(); }, 0., 1., st::notifyFastAnim);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user