make mac window buttons location settable
This commit is contained in:
parent
92681dc9d9
commit
dcb5fb1da4
|
@ -71,4 +71,5 @@ Thumbs.db
|
||||||
.qmake.conf
|
.qmake.conf
|
||||||
*.res
|
*.res
|
||||||
|
|
||||||
.vscode/
|
.vscode/
|
||||||
|
*/.DS_Store
|
|
@ -106,7 +106,7 @@ void MainWindow::showEvent(QShowEvent *event)
|
||||||
titleBarWidget->minimizeButton->hide();
|
titleBarWidget->minimizeButton->hide();
|
||||||
titleBarWidget->maximizeButton->hide();
|
titleBarWidget->maximizeButton->hide();
|
||||||
titleBarWidget->closeButton->hide();
|
titleBarWidget->closeButton->hide();
|
||||||
Utilities::showMacWindowButton(windowHandle());
|
Utilities::setStandardWindowButtonsVisibility(windowHandle(), true);
|
||||||
#endif // Q_OS_MAC
|
#endif // Q_OS_MAC
|
||||||
inited = true;
|
inited = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,10 @@ void FLWindow::initFramelessWindow()
|
||||||
m_minimizeButton->hide();
|
m_minimizeButton->hide();
|
||||||
m_maximizeButton->hide();
|
m_maximizeButton->hide();
|
||||||
m_closeButton->hide();
|
m_closeButton->hide();
|
||||||
Utilities::showMacWindowButton(windowHandle());
|
Utilities::setStandardWindowButtonsVisibility(windowHandle(), true);
|
||||||
|
auto btnGroupSize = Utilities::standardWindowButtonsSize(windowHandle());
|
||||||
|
Utilities::setStandardWindowButtonsPosition(windowHandle(),
|
||||||
|
QPoint(12, (m_titleBarWidget->height() - btnGroupSize.height())/2));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,7 @@ void Widget::showEvent(QShowEvent *event)
|
||||||
m_minimizeButton->hide();
|
m_minimizeButton->hide();
|
||||||
m_maximizeButton->hide();
|
m_maximizeButton->hide();
|
||||||
m_closeButton->hide();
|
m_closeButton->hide();
|
||||||
Utilities::showMacWindowButton(windowHandle());
|
Utilities::setStandardWindowButtonsVisibility(windowHandle(), true);
|
||||||
#endif // Q_OS_MAC
|
#endif // Q_OS_MAC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,11 @@ else()
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
list(APPEND SOURCES
|
list(APPEND SOURCES
|
||||||
core/utilities_macos.mm
|
core/utilities_macos.mm
|
||||||
|
core/nswindow_proxy.h
|
||||||
|
core/nswindow_proxy.mm
|
||||||
core/window_buttons_proxy.h
|
core/window_buttons_proxy.h
|
||||||
core/window_buttons_proxy.mm
|
core/window_buttons_proxy.mm
|
||||||
|
core/scoped_nsobject.h
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS X11Extras REQUIRED)
|
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS X11Extras REQUIRED)
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
#ifndef NSWINDOWPROXY_H
|
||||||
|
#define NSWINDOWPROXY_H
|
||||||
|
|
||||||
|
#include <objc/runtime.h>
|
||||||
|
#include <Cocoa/Cocoa.h>
|
||||||
|
#include <Carbon/Carbon.h>
|
||||||
|
#include <Quartz/Quartz.h>
|
||||||
|
|
||||||
|
#include <QtCore/qpoint.h>
|
||||||
|
|
||||||
|
#include "framelesshelper.h"
|
||||||
|
#include "scoped_nsobject.h"
|
||||||
|
#include "window_buttons_proxy.h"
|
||||||
|
|
||||||
|
@class NSWindowProxyDelegate;
|
||||||
|
|
||||||
|
class NSWindowProxy
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
NSWindow* m_window;
|
||||||
|
scoped_nsobject<WindowButtonsProxy> m_buttonProxy;
|
||||||
|
scoped_nsobject<NSWindowProxyDelegate> m_windowDelegate;
|
||||||
|
bool m_windowButtonVisibility;
|
||||||
|
QPoint m_trafficLightPosition;
|
||||||
|
|
||||||
|
public:
|
||||||
|
NSWindowProxy(NSWindow *window);
|
||||||
|
~NSWindowProxy();
|
||||||
|
|
||||||
|
NSWindow* window() { return m_window; }
|
||||||
|
|
||||||
|
QPoint trafficLightPosition() { return m_trafficLightPosition; }
|
||||||
|
void setTrafficLightPosition(const QPoint &pos);
|
||||||
|
|
||||||
|
bool windowButtonVisibility() { return m_windowButtonVisibility; }
|
||||||
|
void setWindowButtonVisibility(bool visible);
|
||||||
|
|
||||||
|
void redrawTrafficLights();
|
||||||
|
|
||||||
|
bool isFullscreen() const;
|
||||||
|
void setTitle(const QString& title);
|
||||||
|
|
||||||
|
void notifyWindowEnterFullScreen();
|
||||||
|
void notifyWindowLeaveFullScreen();
|
||||||
|
void notifyWindowWillEnterFullScreen();
|
||||||
|
void notifyWindowWillLeaveFullScreen();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
@interface NSWindowProxyDelegate : NSObject<NSWindowDelegate> {
|
||||||
|
@private
|
||||||
|
NSWindowProxy* m_windowProxy;
|
||||||
|
bool m_isZooming;
|
||||||
|
int m_level;
|
||||||
|
bool m_isResizable;
|
||||||
|
|
||||||
|
// Only valid during a live resize.
|
||||||
|
// Used to keep track of whether a resize is happening horizontally or
|
||||||
|
// vertically, even if physically the user is resizing in both directions.
|
||||||
|
bool m_resizingHorizontally;
|
||||||
|
}
|
||||||
|
- (id)initWithWindowProxy:(NSWindowProxy*)proxy;
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif // NSWINDOWPROXY_H
|
|
@ -0,0 +1,291 @@
|
||||||
|
#include "nswindow_proxy.h"
|
||||||
|
|
||||||
|
#include <QtGui/qguiapplication.h>
|
||||||
|
|
||||||
|
static QList<NSWindow*> gFlsWindows;
|
||||||
|
static bool gNSWindowOverrode = false;
|
||||||
|
|
||||||
|
typedef void (*setStyleMaskType)(id, SEL, NSWindowStyleMask);
|
||||||
|
static setStyleMaskType gOrigSetStyleMask = nullptr;
|
||||||
|
static void __setStyleMask(id obj, SEL sel, NSWindowStyleMask styleMask)
|
||||||
|
{
|
||||||
|
if (gFlsWindows.contains(reinterpret_cast<NSWindow *>(obj)))
|
||||||
|
{
|
||||||
|
styleMask = styleMask | NSWindowStyleMaskFullSizeContentView;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gOrigSetStyleMask != nullptr)
|
||||||
|
gOrigSetStyleMask(obj, sel, styleMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (*setTitlebarAppearsTransparentType)(id, SEL, BOOL);
|
||||||
|
static setTitlebarAppearsTransparentType gOrigSetTitlebarAppearsTransparent = nullptr;
|
||||||
|
static void __setTitlebarAppearsTransparent(id obj, SEL sel, BOOL transparent)
|
||||||
|
{
|
||||||
|
if (gFlsWindows.contains(reinterpret_cast<NSWindow *>(obj)))
|
||||||
|
transparent = true;
|
||||||
|
|
||||||
|
if (gOrigSetTitlebarAppearsTransparent != nullptr)
|
||||||
|
gOrigSetTitlebarAppearsTransparent(obj, sel, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef BOOL (*canBecomeKeyWindowType)(id, SEL);
|
||||||
|
static canBecomeKeyWindowType gOrigCanBecomeKeyWindow = nullptr;
|
||||||
|
static BOOL __canBecomeKeyWindow(id obj, SEL sel)
|
||||||
|
{
|
||||||
|
if (gFlsWindows.contains(reinterpret_cast<NSWindow *>(obj)))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gOrigCanBecomeKeyWindow != nullptr)
|
||||||
|
return gOrigCanBecomeKeyWindow(obj, sel);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef BOOL (*canBecomeMainWindowType)(id, SEL);
|
||||||
|
static canBecomeMainWindowType gOrigCanBecomeMainWindow = nullptr;
|
||||||
|
static BOOL __canBecomeMainWindow(id obj, SEL sel)
|
||||||
|
{
|
||||||
|
if (gFlsWindows.contains(reinterpret_cast<NSWindow *>(obj)))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gOrigCanBecomeMainWindow != nullptr)
|
||||||
|
return gOrigCanBecomeMainWindow(obj, sel);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (*sendEventType)(id, SEL, NSEvent*);
|
||||||
|
static sendEventType gOrigSendEvent = nullptr;
|
||||||
|
static void __sendEvent(id obj, SEL sel, NSEvent* event)
|
||||||
|
{
|
||||||
|
if (gOrigSendEvent != nullptr)
|
||||||
|
gOrigSendEvent(obj, sel, event);
|
||||||
|
|
||||||
|
|
||||||
|
if (!gFlsWindows.contains(reinterpret_cast<NSWindow *>(obj)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (event.type == NSEventTypeLeftMouseDown)
|
||||||
|
QGuiApplication::processEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef BOOL (*isFlippedType)(id, SEL);
|
||||||
|
static isFlippedType gOrigIsFlipped = nullptr;
|
||||||
|
static BOOL __isFlipped(id obj, SEL sel)
|
||||||
|
{
|
||||||
|
if (!gFlsWindows.contains(reinterpret_cast<NSWindow *>(obj)))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (gOrigIsFlipped != nullptr)
|
||||||
|
return gOrigIsFlipped(obj, sel);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Replace origin method \a origSEL of class \a cls with new one \a newIMP ,
|
||||||
|
then return old method as function pointer.
|
||||||
|
*/
|
||||||
|
static void* replaceMethod(Class cls, SEL origSEL, IMP newIMP)
|
||||||
|
{
|
||||||
|
Method origMethod = class_getInstanceMethod(cls, origSEL);
|
||||||
|
void *funcPtr = (void *)method_getImplementation(origMethod);
|
||||||
|
if (!class_addMethod(cls, origSEL, newIMP, method_getTypeEncoding(origMethod))) {
|
||||||
|
method_setImplementation(origMethod, newIMP);
|
||||||
|
}
|
||||||
|
|
||||||
|
return funcPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void restoreMethod(Class cls, SEL origSEL, IMP oldIMP)
|
||||||
|
{
|
||||||
|
Method method = class_getInstanceMethod(cls, origSEL);
|
||||||
|
method_setImplementation(method, oldIMP);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void overrideNSWindowMethods(NSWindow* window)
|
||||||
|
{
|
||||||
|
if (!gNSWindowOverrode) {
|
||||||
|
Class cls = [window class];
|
||||||
|
|
||||||
|
gOrigSetStyleMask = (setStyleMaskType) replaceMethod(
|
||||||
|
cls, @selector(setStyleMask:), (IMP) __setStyleMask);
|
||||||
|
gOrigSetTitlebarAppearsTransparent = (setTitlebarAppearsTransparentType) replaceMethod(
|
||||||
|
cls, @selector(setTitlebarAppearsTransparent:), (IMP) __setTitlebarAppearsTransparent);
|
||||||
|
gOrigCanBecomeKeyWindow = (canBecomeKeyWindowType) replaceMethod(
|
||||||
|
cls, @selector(canBecomeKeyWindow), (IMP) __canBecomeKeyWindow);
|
||||||
|
gOrigCanBecomeMainWindow = (canBecomeMainWindowType) replaceMethod(
|
||||||
|
cls, @selector(canBecomeMainWindow), (IMP) __canBecomeMainWindow);
|
||||||
|
gOrigSendEvent = (sendEventType) replaceMethod(
|
||||||
|
cls, @selector(sendEvent:), (IMP) __sendEvent);
|
||||||
|
//gOrigIsFlipped = (isFlippedType) replaceMethod(
|
||||||
|
// cls, @selector (isFlipped), (IMP) __isFlipped);
|
||||||
|
|
||||||
|
gNSWindowOverrode = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
gFlsWindows.append(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void restoreNSWindowMethods(NSWindow* window)
|
||||||
|
{
|
||||||
|
gFlsWindows.removeAll(window);
|
||||||
|
if (gFlsWindows.size() == 0) {
|
||||||
|
Class cls = [window class];
|
||||||
|
|
||||||
|
restoreMethod(cls, @selector(setStyleMask:), (IMP) gOrigSetStyleMask);
|
||||||
|
gOrigSetStyleMask = nullptr;
|
||||||
|
|
||||||
|
restoreMethod(cls, @selector(setTitlebarAppearsTransparent:), (IMP) gOrigSetTitlebarAppearsTransparent);
|
||||||
|
gOrigSetTitlebarAppearsTransparent = nullptr;
|
||||||
|
|
||||||
|
restoreMethod(cls, @selector(canBecomeKeyWindow), (IMP) gOrigCanBecomeKeyWindow);
|
||||||
|
gOrigCanBecomeKeyWindow = nullptr;
|
||||||
|
|
||||||
|
restoreMethod(cls, @selector(canBecomeMainWindow), (IMP) gOrigCanBecomeMainWindow);
|
||||||
|
gOrigCanBecomeMainWindow = nullptr;
|
||||||
|
|
||||||
|
restoreMethod(cls, @selector(sendEvent:), (IMP) gOrigSendEvent);
|
||||||
|
gOrigSendEvent = nullptr;
|
||||||
|
|
||||||
|
//restoreMethod(cls, @selector(isFlipped), (IMP) gOrigIsFlipped);
|
||||||
|
//gOrigIsFlipped = nullptr;
|
||||||
|
|
||||||
|
gNSWindowOverrode = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
NSWindowProxy::NSWindowProxy(NSWindow *window)
|
||||||
|
: m_windowButtonVisibility(false)
|
||||||
|
, m_buttonProxy(nullptr)
|
||||||
|
, m_window(window)
|
||||||
|
{
|
||||||
|
overrideNSWindowMethods(window);
|
||||||
|
m_buttonProxy.reset([[WindowButtonsProxy alloc] initWithWindow:window]);
|
||||||
|
m_windowDelegate.reset([[NSWindowProxyDelegate alloc] initWithWindowProxy:this]);
|
||||||
|
[m_window setDelegate:m_windowDelegate.get()];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSWindowProxy::~NSWindowProxy()
|
||||||
|
{
|
||||||
|
restoreNSWindowMethods(m_window);
|
||||||
|
[m_buttonProxy release];
|
||||||
|
}
|
||||||
|
|
||||||
|
void NSWindowProxy::setTrafficLightPosition(const QPoint &pos) {
|
||||||
|
m_trafficLightPosition = pos;
|
||||||
|
if (m_buttonProxy) {
|
||||||
|
[m_buttonProxy setMargin:m_trafficLightPosition];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NSWindowProxy::setWindowButtonVisibility(bool visible) {
|
||||||
|
m_windowButtonVisibility = visible;
|
||||||
|
// The visibility of window buttons are managed by |buttons_proxy_| if the
|
||||||
|
// style is customButtonsOnHover.
|
||||||
|
if (false /*title_bar_style_ == TitleBarStyle::kCustomButtonsOnHover*/)
|
||||||
|
[m_buttonProxy setVisible:visible];
|
||||||
|
else {
|
||||||
|
[[m_window standardWindowButton:NSWindowCloseButton] setHidden:!visible];
|
||||||
|
[[m_window standardWindowButton:NSWindowMiniaturizeButton] setHidden:!visible];
|
||||||
|
[[m_window standardWindowButton:NSWindowZoomButton] setHidden:!visible];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NSWindowProxy::isFullscreen() const {
|
||||||
|
return [m_window styleMask] & NSWindowStyleMaskFullScreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NSWindowProxy::redrawTrafficLights() {
|
||||||
|
if (m_buttonProxy && !isFullscreen())
|
||||||
|
[m_buttonProxy redraw];
|
||||||
|
}
|
||||||
|
|
||||||
|
void NSWindowProxy::setTitle(const QString& title) {
|
||||||
|
[m_window setTitle:title.toNSString()];
|
||||||
|
if (m_buttonProxy)
|
||||||
|
[m_buttonProxy redraw];
|
||||||
|
}
|
||||||
|
|
||||||
|
void NSWindowProxy::notifyWindowEnterFullScreen() {
|
||||||
|
// Restore the window title under fullscreen mode.
|
||||||
|
if (m_buttonProxy) {
|
||||||
|
[m_window setTitleVisibility:NSWindowTitleVisible];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NSWindowProxy::notifyWindowLeaveFullScreen() {
|
||||||
|
// Restore window buttons.
|
||||||
|
if (m_buttonProxy && m_windowButtonVisibility) {
|
||||||
|
[m_buttonProxy redraw];
|
||||||
|
[m_buttonProxy setVisible:YES];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NSWindowProxy::notifyWindowWillEnterFullScreen() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void NSWindowProxy::notifyWindowWillLeaveFullScreen() {
|
||||||
|
if (m_buttonProxy) {
|
||||||
|
// Hide window title when leaving fullscreen.
|
||||||
|
[m_window setTitleVisibility:NSWindowTitleHidden];
|
||||||
|
// Hide the container otherwise traffic light buttons jump.
|
||||||
|
[m_buttonProxy setVisible:NO];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@implementation NSWindowProxyDelegate
|
||||||
|
- (id)initWithWindowProxy:(NSWindowProxy*)proxy {
|
||||||
|
m_windowProxy = proxy;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)windowDidBecomeMain:(NSNotification*)notification {
|
||||||
|
m_windowProxy->redrawTrafficLights();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)windowDidResignMain:(NSNotification*)notification {
|
||||||
|
m_windowProxy->redrawTrafficLights();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)windowDidBecomeKey:(NSNotification*)notification {
|
||||||
|
m_windowProxy->redrawTrafficLights();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)windowDidResignKey:(NSNotification*)notification {
|
||||||
|
// If our app is still active and we're still the key window, ignore this
|
||||||
|
// message, since it just means that a menu extra (on the "system status bar")
|
||||||
|
// was activated; we'll get another |-windowDidResignKey| if we ever really
|
||||||
|
// lose key window status.
|
||||||
|
if ([NSApp isActive] && ([NSApp keyWindow] == [notification object]))
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_windowProxy->redrawTrafficLights();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)windowDidResize:(NSNotification*)notification {
|
||||||
|
m_windowProxy->redrawTrafficLights();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)windowWillEnterFullScreen:(NSNotification*)notification {
|
||||||
|
m_windowProxy->notifyWindowWillEnterFullScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)windowDidEnterFullScreen:(NSNotification*)notification {
|
||||||
|
m_windowProxy->notifyWindowEnterFullScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)windowWillExitFullScreen:(NSNotification*)notification {
|
||||||
|
m_windowProxy->notifyWindowWillLeaveFullScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)windowDidExitFullScreen:(NSNotification*)notification {
|
||||||
|
m_windowProxy->notifyWindowLeaveFullScreen();
|
||||||
|
}
|
||||||
|
@end
|
|
@ -0,0 +1,203 @@
|
||||||
|
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef SCOPED_NSOBJECT_H
|
||||||
|
#define SCOPED_NSOBJECT_H
|
||||||
|
|
||||||
|
// Include NSObject.h directly because Foundation.h pulls in many dependencies.
|
||||||
|
// (Approx 100k lines of code versus 1.5k for NSObject.h). scoped_nsobject gets
|
||||||
|
// singled out because it is most typically included from other header files.
|
||||||
|
#import <Foundation/NSObject.h>
|
||||||
|
|
||||||
|
#if !defined(__GNUC__) && !defined(__clang__) && !defined(_MSC_VER)
|
||||||
|
#error Unsupported compiler.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Annotate a variable indicating it's ok if the variable is not used.
|
||||||
|
// (Typically used to silence a compiler warning when the assignment
|
||||||
|
// is important for some other reason.)
|
||||||
|
// Use like:
|
||||||
|
// int x = ...;
|
||||||
|
// FML_ALLOW_UNUSED_LOCAL(x);
|
||||||
|
#define FML_ALLOW_UNUSED_LOCAL(x) false ? (void)x : (void)0
|
||||||
|
|
||||||
|
// Annotate a typedef or function indicating it's ok if it's not used.
|
||||||
|
// Use like:
|
||||||
|
// typedef Foo Bar ALLOW_UNUSED_TYPE;
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
#define FML_ALLOW_UNUSED_TYPE __attribute__((unused))
|
||||||
|
#else
|
||||||
|
#define FML_ALLOW_UNUSED_TYPE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FML_USED_ON_EMBEDDER
|
||||||
|
|
||||||
|
#define FML_EMBEDDER_ONLY [[deprecated]]
|
||||||
|
|
||||||
|
#else // FML_USED_ON_EMBEDDER
|
||||||
|
|
||||||
|
#define FML_EMBEDDER_ONLY
|
||||||
|
|
||||||
|
#endif // FML_USED_ON_EMBEDDER
|
||||||
|
|
||||||
|
#define FML_DISALLOW_COPY(TypeName) TypeName(const TypeName&) = delete
|
||||||
|
|
||||||
|
#define FML_DISALLOW_ASSIGN(TypeName) \
|
||||||
|
TypeName& operator=(const TypeName&) = delete
|
||||||
|
|
||||||
|
#define FML_DISALLOW_MOVE(TypeName) \
|
||||||
|
TypeName(TypeName&&) = delete; \
|
||||||
|
TypeName& operator=(TypeName&&) = delete
|
||||||
|
|
||||||
|
#define FML_DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||||
|
TypeName(const TypeName&) = delete; \
|
||||||
|
TypeName& operator=(const TypeName&) = delete
|
||||||
|
|
||||||
|
#define FML_DISALLOW_COPY_ASSIGN_AND_MOVE(TypeName) \
|
||||||
|
TypeName(const TypeName&) = delete; \
|
||||||
|
TypeName(TypeName&&) = delete; \
|
||||||
|
TypeName& operator=(const TypeName&) = delete; \
|
||||||
|
TypeName& operator=(TypeName&&) = delete
|
||||||
|
|
||||||
|
#define FML_DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
|
||||||
|
TypeName() = delete; \
|
||||||
|
FML_DISALLOW_COPY_ASSIGN_AND_MOVE(TypeName)
|
||||||
|
|
||||||
|
@class NSAutoreleasePool;
|
||||||
|
|
||||||
|
// scoped_nsobject<> is patterned after scoped_ptr<>, but maintains ownership
|
||||||
|
// of an NSObject subclass object. Style deviations here are solely for
|
||||||
|
// compatibility with scoped_ptr<>'s interface, with which everyone is already
|
||||||
|
// familiar.
|
||||||
|
//
|
||||||
|
// scoped_nsobject<> takes ownership of an object (in the constructor or in
|
||||||
|
// reset()) by taking over the caller's existing ownership claim. The caller
|
||||||
|
// must own the object it gives to scoped_nsobject<>, and relinquishes an
|
||||||
|
// ownership claim to that object. scoped_nsobject<> does not call -retain,
|
||||||
|
// callers have to call this manually if appropriate.
|
||||||
|
//
|
||||||
|
// scoped_nsprotocol<> has the same behavior as scoped_nsobject, but can be used
|
||||||
|
// with protocols.
|
||||||
|
//
|
||||||
|
// scoped_nsobject<> is not to be used for NSAutoreleasePools. For
|
||||||
|
// NSAutoreleasePools use ScopedNSAutoreleasePool from
|
||||||
|
// scoped_nsautorelease_pool.h instead.
|
||||||
|
// We check for bad uses of scoped_nsobject and NSAutoreleasePool at compile
|
||||||
|
// time with a template specialization (see below).
|
||||||
|
|
||||||
|
template <typename NST>
|
||||||
|
class scoped_nsprotocol {
|
||||||
|
public:
|
||||||
|
explicit scoped_nsprotocol(NST object = nil) : object_(object) {}
|
||||||
|
|
||||||
|
scoped_nsprotocol(const scoped_nsprotocol<NST>& that) : object_([that.object_ retain]) {}
|
||||||
|
|
||||||
|
template <typename NSU>
|
||||||
|
scoped_nsprotocol(const scoped_nsprotocol<NSU>& that) : object_([that.get() retain]) {}
|
||||||
|
|
||||||
|
~scoped_nsprotocol() { [object_ release]; }
|
||||||
|
|
||||||
|
scoped_nsprotocol& operator=(const scoped_nsprotocol<NST>& that) {
|
||||||
|
reset([that.get() retain]);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset(NST object = nil) {
|
||||||
|
// We intentionally do not check that object != object_ as the caller must
|
||||||
|
// either already have an ownership claim over whatever it passes to this
|
||||||
|
// method, or call it with the |RETAIN| policy which will have ensured that
|
||||||
|
// the object is retained once more when reaching this point.
|
||||||
|
[object_ release];
|
||||||
|
object_ = object;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(NST that) const { return object_ == that; }
|
||||||
|
bool operator!=(NST that) const { return object_ != that; }
|
||||||
|
|
||||||
|
operator NST() const { return object_; }
|
||||||
|
|
||||||
|
NST get() const { return object_; }
|
||||||
|
|
||||||
|
void swap(scoped_nsprotocol& that) {
|
||||||
|
NST temp = that.object_;
|
||||||
|
that.object_ = object_;
|
||||||
|
object_ = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shift reference to the autorelease pool to be released later.
|
||||||
|
NST autorelease() { return [release() autorelease]; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
NST object_;
|
||||||
|
|
||||||
|
// scoped_nsprotocol<>::release() is like scoped_ptr<>::release. It is NOT a
|
||||||
|
// wrapper for [object_ release]. To force a scoped_nsprotocol<> to call
|
||||||
|
// [object_ release], use scoped_nsprotocol<>::reset().
|
||||||
|
[[nodiscard]] NST release() {
|
||||||
|
NST temp = object_;
|
||||||
|
object_ = nil;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Free functions
|
||||||
|
template <class C>
|
||||||
|
void swap(scoped_nsprotocol<C>& p1, scoped_nsprotocol<C>& p2) {
|
||||||
|
p1.swap(p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class C>
|
||||||
|
bool operator==(C p1, const scoped_nsprotocol<C>& p2) {
|
||||||
|
return p1 == p2.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class C>
|
||||||
|
bool operator!=(C p1, const scoped_nsprotocol<C>& p2) {
|
||||||
|
return p1 != p2.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename NST>
|
||||||
|
class scoped_nsobject : public scoped_nsprotocol<NST*> {
|
||||||
|
public:
|
||||||
|
explicit scoped_nsobject(NST* object = nil) : scoped_nsprotocol<NST*>(object) {}
|
||||||
|
|
||||||
|
scoped_nsobject(const scoped_nsobject<NST>& that) : scoped_nsprotocol<NST*>(that) {}
|
||||||
|
|
||||||
|
template <typename NSU>
|
||||||
|
scoped_nsobject(const scoped_nsobject<NSU>& that) : scoped_nsprotocol<NST*>(that) {}
|
||||||
|
|
||||||
|
scoped_nsobject& operator=(const scoped_nsobject<NST>& that) {
|
||||||
|
scoped_nsprotocol<NST*>::operator=(that);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specialization to make scoped_nsobject<id> work.
|
||||||
|
template <>
|
||||||
|
class scoped_nsobject<id> : public scoped_nsprotocol<id> {
|
||||||
|
public:
|
||||||
|
explicit scoped_nsobject(id object = nil) : scoped_nsprotocol<id>(object) {}
|
||||||
|
|
||||||
|
scoped_nsobject(const scoped_nsobject<id>& that) : scoped_nsprotocol<id>(that) {}
|
||||||
|
|
||||||
|
template <typename NSU>
|
||||||
|
scoped_nsobject(const scoped_nsobject<NSU>& that) : scoped_nsprotocol<id>(that) {}
|
||||||
|
|
||||||
|
scoped_nsobject& operator=(const scoped_nsobject<id>& that) {
|
||||||
|
scoped_nsprotocol<id>::operator=(that);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Do not use scoped_nsobject for NSAutoreleasePools, use
|
||||||
|
// ScopedNSAutoreleasePool instead. This is a compile time check. See details
|
||||||
|
// at top of header.
|
||||||
|
template <>
|
||||||
|
class scoped_nsobject<NSAutoreleasePool> {
|
||||||
|
private:
|
||||||
|
explicit scoped_nsobject(NSAutoreleasePool* object = nil);
|
||||||
|
FML_DISALLOW_COPY_AND_ASSIGN(scoped_nsobject);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SCOPED_NSOBJECT_H
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include "framelesshelper_global.h"
|
#include "framelesshelper_global.h"
|
||||||
#include <QtGui/qwindow.h>
|
#include <QtGui/qwindow.h>
|
||||||
|
#include <QtCore/qsize.h>
|
||||||
|
|
||||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
@ -75,13 +76,9 @@ FRAMELESSHELPER_API bool setMacWindowFrameless(QWindow* w);
|
||||||
FRAMELESSHELPER_API bool unsetMacWindowFrameless(QWindow* w);
|
FRAMELESSHELPER_API bool unsetMacWindowFrameless(QWindow* w);
|
||||||
FRAMELESSHELPER_API bool startMacDrag(QWindow* w, const QPoint& pos);
|
FRAMELESSHELPER_API bool startMacDrag(QWindow* w, const QPoint& pos);
|
||||||
FRAMELESSHELPER_API Qt::MouseButtons getMacMouseButtons();
|
FRAMELESSHELPER_API Qt::MouseButtons getMacMouseButtons();
|
||||||
FRAMELESSHELPER_API bool showMacWindowButton(QWindow *w);
|
FRAMELESSHELPER_API bool setStandardWindowButtonsVisibility(QWindow *w, bool visible);
|
||||||
FRAMELESSHELPER_API bool isMacKeyWindow(QWindow *w);
|
FRAMELESSHELPER_API bool setStandardWindowButtonsPosition(QWindow *w, const QPoint &pos);
|
||||||
FRAMELESSHELPER_API bool isMacMainWindow(QWindow *w);
|
FRAMELESSHELPER_API QSize standardWindowButtonsSize(QWindow *w);
|
||||||
FRAMELESSHELPER_API bool makeMacKeyWindow(QWindow *w);
|
|
||||||
FRAMELESSHELPER_API bool makeMacMainWindow(QWindow *w);
|
|
||||||
FRAMELESSHELPER_API bool setStandardWindowButtonsOffset(QWindow *w, const QPoint &offset);
|
|
||||||
FRAMELESSHELPER_API bool setTrafficLightPosition(QWindow *w, const QPoint &pos);
|
|
||||||
#endif // Q_OS_MAC
|
#endif // Q_OS_MAC
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,15 +24,11 @@
|
||||||
|
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
#include <objc/runtime.h>
|
|
||||||
#include <Cocoa/Cocoa.h>
|
|
||||||
#include <Carbon/Carbon.h>
|
|
||||||
|
|
||||||
#include <QtGui/qguiapplication.h>
|
#include <QtGui/qguiapplication.h>
|
||||||
#include <QtCore/qlist.h>
|
#include <QtCore/qlist.h>
|
||||||
#include <QtCore/qdebug.h>
|
#include <QtCore/qdebug.h>
|
||||||
|
|
||||||
#include "window_buttons_proxy.h"
|
#include "nswindow_proxy.h"
|
||||||
|
|
||||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
@ -123,201 +119,7 @@ bool showSystemMenu(const WId winId, const QPointF &pos)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QList<NSWindow*> gFlsWindows;
|
static QHash<QWindow*, NSWindowProxy*> gQWindowToNSWindow;
|
||||||
static bool gNSWindowOverrode = false;
|
|
||||||
|
|
||||||
typedef void (*setStyleMaskType)(id, SEL, NSWindowStyleMask);
|
|
||||||
static setStyleMaskType gOrigSetStyleMask = nullptr;
|
|
||||||
static void __setStyleMask(id obj, SEL sel, NSWindowStyleMask styleMask)
|
|
||||||
{
|
|
||||||
if (gFlsWindows.contains(reinterpret_cast<NSWindow *>(obj)))
|
|
||||||
{
|
|
||||||
styleMask = styleMask | NSWindowStyleMaskFullSizeContentView;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gOrigSetStyleMask != nullptr)
|
|
||||||
gOrigSetStyleMask(obj, sel, styleMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef void (*setTitlebarAppearsTransparentType)(id, SEL, BOOL);
|
|
||||||
static setTitlebarAppearsTransparentType gOrigSetTitlebarAppearsTransparent = nullptr;
|
|
||||||
static void __setTitlebarAppearsTransparent(id obj, SEL sel, BOOL transparent)
|
|
||||||
{
|
|
||||||
if (gFlsWindows.contains(reinterpret_cast<NSWindow *>(obj)))
|
|
||||||
transparent = true;
|
|
||||||
|
|
||||||
if (gOrigSetTitlebarAppearsTransparent != nullptr)
|
|
||||||
gOrigSetTitlebarAppearsTransparent(obj, sel, transparent);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef BOOL (*canBecomeKeyWindowType)(id, SEL);
|
|
||||||
static canBecomeKeyWindowType gOrigCanBecomeKeyWindow = nullptr;
|
|
||||||
static BOOL __canBecomeKeyWindow(id obj, SEL sel)
|
|
||||||
{
|
|
||||||
if (gFlsWindows.contains(reinterpret_cast<NSWindow *>(obj)))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gOrigCanBecomeKeyWindow != nullptr)
|
|
||||||
return gOrigCanBecomeKeyWindow(obj, sel);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef BOOL (*canBecomeMainWindowType)(id, SEL);
|
|
||||||
static canBecomeMainWindowType gOrigCanBecomeMainWindow = nullptr;
|
|
||||||
static BOOL __canBecomeMainWindow(id obj, SEL sel)
|
|
||||||
{
|
|
||||||
if (gFlsWindows.contains(reinterpret_cast<NSWindow *>(obj)))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gOrigCanBecomeMainWindow != nullptr)
|
|
||||||
return gOrigCanBecomeMainWindow(obj, sel);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef void (*sendEventType)(id, SEL, NSEvent*);
|
|
||||||
static sendEventType gOrigSendEvent = nullptr;
|
|
||||||
static void __sendEvent(id obj, SEL sel, NSEvent* event)
|
|
||||||
{
|
|
||||||
if (gOrigSendEvent != nullptr)
|
|
||||||
gOrigSendEvent(obj, sel, event);
|
|
||||||
|
|
||||||
|
|
||||||
if (!gFlsWindows.contains(reinterpret_cast<NSWindow *>(obj)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (event.type == NSEventTypeLeftMouseDown)
|
|
||||||
QGuiApplication::processEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef BOOL (*isFlippedType)(id, SEL);
|
|
||||||
static isFlippedType gOrigIsFlipped = nullptr;
|
|
||||||
static BOOL __isFlipped(id obj, SEL sel)
|
|
||||||
{
|
|
||||||
if (!gFlsWindows.contains(reinterpret_cast<NSWindow *>(obj)))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (gOrigIsFlipped != nullptr)
|
|
||||||
return gOrigIsFlipped(obj, sel);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Replace origin method \a origSEL of class \a cls with new one \a newIMP ,
|
|
||||||
then return old method as function pointer.
|
|
||||||
*/
|
|
||||||
static void* replaceMethod(Class cls, SEL origSEL, IMP newIMP)
|
|
||||||
{
|
|
||||||
Method origMethod = class_getInstanceMethod(cls, origSEL);
|
|
||||||
void *funcPtr = (void *)method_getImplementation(origMethod);
|
|
||||||
if (!class_addMethod(cls, origSEL, newIMP, method_getTypeEncoding(origMethod))) {
|
|
||||||
method_setImplementation(origMethod, newIMP);
|
|
||||||
}
|
|
||||||
|
|
||||||
return funcPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void restoreMethod(Class cls, SEL origSEL, IMP oldIMP)
|
|
||||||
{
|
|
||||||
Method method = class_getInstanceMethod(cls, origSEL);
|
|
||||||
method_setImplementation(method, oldIMP);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void overrideNSWindowMethods(NSWindow* window)
|
|
||||||
{
|
|
||||||
if (!gNSWindowOverrode) {
|
|
||||||
Class cls = [window class];
|
|
||||||
|
|
||||||
gOrigSetStyleMask = (setStyleMaskType) replaceMethod(
|
|
||||||
cls, @selector(setStyleMask:), (IMP) __setStyleMask);
|
|
||||||
gOrigSetTitlebarAppearsTransparent = (setTitlebarAppearsTransparentType) replaceMethod(
|
|
||||||
cls, @selector(setTitlebarAppearsTransparent:), (IMP) __setTitlebarAppearsTransparent);
|
|
||||||
gOrigCanBecomeKeyWindow = (canBecomeKeyWindowType) replaceMethod(
|
|
||||||
cls, @selector(canBecomeKeyWindow), (IMP) __canBecomeKeyWindow);
|
|
||||||
gOrigCanBecomeMainWindow = (canBecomeMainWindowType) replaceMethod(
|
|
||||||
cls, @selector(canBecomeMainWindow), (IMP) __canBecomeMainWindow);
|
|
||||||
gOrigSendEvent = (sendEventType) replaceMethod(
|
|
||||||
cls, @selector(sendEvent:), (IMP) __sendEvent);
|
|
||||||
//gOrigIsFlipped = (isFlippedType) replaceMethod(
|
|
||||||
// cls, @selector (isFlipped), (IMP) __isFlipped);
|
|
||||||
|
|
||||||
gNSWindowOverrode = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
gFlsWindows.append(window);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void restoreNSWindowMethods(NSWindow* window)
|
|
||||||
{
|
|
||||||
gFlsWindows.removeAll(window);
|
|
||||||
if (gFlsWindows.size() == 0) {
|
|
||||||
Class cls = [window class];
|
|
||||||
|
|
||||||
restoreMethod(cls, @selector(setStyleMask:), (IMP) gOrigSetStyleMask);
|
|
||||||
gOrigSetStyleMask = nullptr;
|
|
||||||
|
|
||||||
restoreMethod(cls, @selector(setTitlebarAppearsTransparent:), (IMP) gOrigSetTitlebarAppearsTransparent);
|
|
||||||
gOrigSetTitlebarAppearsTransparent = nullptr;
|
|
||||||
|
|
||||||
restoreMethod(cls, @selector(canBecomeKeyWindow), (IMP) gOrigCanBecomeKeyWindow);
|
|
||||||
gOrigCanBecomeKeyWindow = nullptr;
|
|
||||||
|
|
||||||
restoreMethod(cls, @selector(canBecomeMainWindow), (IMP) gOrigCanBecomeMainWindow);
|
|
||||||
gOrigCanBecomeMainWindow = nullptr;
|
|
||||||
|
|
||||||
restoreMethod(cls, @selector(sendEvent:), (IMP) gOrigSendEvent);
|
|
||||||
gOrigSendEvent = nullptr;
|
|
||||||
|
|
||||||
//restoreMethod(cls, @selector(isFlipped), (IMP) gOrigIsFlipped);
|
|
||||||
//gOrigIsFlipped = nullptr;
|
|
||||||
|
|
||||||
gNSWindowOverrode = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class NSWindowData
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
NSWindow* m_window;
|
|
||||||
WindowButtonsProxy *m_buttonProxy;
|
|
||||||
bool m_windowButtonVisibility;
|
|
||||||
QPoint m_trafficLightPosition;
|
|
||||||
|
|
||||||
public:
|
|
||||||
NSWindowData(NSWindow *window)
|
|
||||||
: m_windowButtonVisibility(false)
|
|
||||||
, m_buttonProxy(nullptr)
|
|
||||||
, m_window(window)
|
|
||||||
{
|
|
||||||
overrideNSWindowMethods(window);
|
|
||||||
m_buttonProxy = [[WindowButtonsProxy alloc] initWithWindow:window];
|
|
||||||
}
|
|
||||||
|
|
||||||
~NSWindowData()
|
|
||||||
{
|
|
||||||
restoreNSWindowMethods(m_window);
|
|
||||||
[m_buttonProxy release];
|
|
||||||
}
|
|
||||||
|
|
||||||
NSWindow* window() { return m_window; }
|
|
||||||
|
|
||||||
QPoint trafficLightPosition() { return m_trafficLightPosition; }
|
|
||||||
bool setTrafficLightPosition(const QPoint &pos) {
|
|
||||||
m_trafficLightPosition = pos;
|
|
||||||
if (m_buttonProxy) {
|
|
||||||
[m_buttonProxy setMargin:m_trafficLightPosition];
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static QHash<QWindow*, NSWindowData*> gQWindowToNSWindow;
|
|
||||||
|
|
||||||
static NSWindow* getNSWindow(QWindow* w)
|
static NSWindow* getNSWindow(QWindow* w)
|
||||||
{
|
{
|
||||||
|
@ -341,7 +143,7 @@ bool setMacWindowHook(QWindow* w)
|
||||||
if (nswindow == nullptr)
|
if (nswindow == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
NSWindowData *obj = new NSWindowData(nswindow);
|
NSWindowProxy *obj = new NSWindowProxy(nswindow);
|
||||||
gQWindowToNSWindow.insert(w, obj);
|
gQWindowToNSWindow.insert(w, obj);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -352,7 +154,7 @@ bool unsetMacWindowHook(QWindow* w)
|
||||||
if (!gQWindowToNSWindow.contains(w))
|
if (!gQWindowToNSWindow.contains(w))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
NSWindowData* obj = gQWindowToNSWindow[w];
|
NSWindowProxy* obj = gQWindowToNSWindow[w];
|
||||||
gQWindowToNSWindow.remove(w);
|
gQWindowToNSWindow.remove(w);
|
||||||
delete obj;
|
delete obj;
|
||||||
|
|
||||||
|
@ -414,20 +216,6 @@ bool unsetMacWindowFrameless(QWindow* w)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool showMacWindowButton(QWindow *w)
|
|
||||||
{
|
|
||||||
NSWindow* nswindow = getNSWindow(w);
|
|
||||||
if (nswindow == nullptr)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
nswindow.showsToolbarButton = true;
|
|
||||||
[nswindow standardWindowButton:NSWindowCloseButton].hidden = false;
|
|
||||||
[nswindow standardWindowButton:NSWindowMiniaturizeButton].hidden = false;
|
|
||||||
[nswindow standardWindowButton:NSWindowZoomButton].hidden = false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool startMacDrag(QWindow* w, const QPoint& pos)
|
bool startMacDrag(QWindow* w, const QPoint& pos)
|
||||||
{
|
{
|
||||||
NSWindow* nswindow = getNSWindow(w);
|
NSWindow* nswindow = getNSWindow(w);
|
||||||
|
@ -447,89 +235,33 @@ Qt::MouseButtons getMacMouseButtons()
|
||||||
return static_cast<Qt::MouseButtons>((uint)(NSEvent.pressedMouseButtons & Qt::MouseButtonMask));
|
return static_cast<Qt::MouseButtons>((uint)(NSEvent.pressedMouseButtons & Qt::MouseButtonMask));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isMacKeyWindow(QWindow *w)
|
bool setStandardWindowButtonsVisibility(QWindow *w, bool visible)
|
||||||
{
|
{
|
||||||
NSWindow* nswindow = getNSWindow(w);
|
NSWindowProxy* obj = gQWindowToNSWindow[w];
|
||||||
if (nswindow == nullptr) {
|
obj->setWindowButtonVisibility(visible);
|
||||||
qWarning() << "Unable to get NSView.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [nswindow isKeyWindow];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isMacMainWindow(QWindow *w)
|
|
||||||
{
|
|
||||||
NSWindow* nswindow = getNSWindow(w);
|
|
||||||
if (nswindow == nullptr)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return [nswindow isMainWindow];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool makeMacKeyWindow(QWindow *w)
|
|
||||||
{
|
|
||||||
NSWindow* nswindow = getNSWindow(w);
|
|
||||||
if (nswindow == nullptr)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
[nswindow makeKeyWindow];
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool makeMacMainWindow(QWindow *w)
|
/*! The origin of \a pos is top-left of window. */
|
||||||
|
bool setStandardWindowButtonsPosition(QWindow *w, const QPoint &pos)
|
||||||
{
|
{
|
||||||
NSWindow* nswindow = getNSWindow(w);
|
NSWindowProxy* obj = gQWindowToNSWindow[w];
|
||||||
if (nswindow == nullptr)
|
obj->setWindowButtonVisibility(true);
|
||||||
return false;
|
obj->setTrafficLightPosition(pos);
|
||||||
|
|
||||||
[nswindow makeMainWindow];
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setButtonLocation(NSButton * btn, const QPoint &offset, NSView *contentview)
|
QSize standardWindowButtonsSize(QWindow *w)
|
||||||
{
|
|
||||||
if (btn.superview != contentview) {
|
|
||||||
[btn.superview willRemoveSubview:btn];
|
|
||||||
[btn removeFromSuperview];
|
|
||||||
[btn viewWillMoveToSuperview:contentview];
|
|
||||||
[contentview addSubview:btn];
|
|
||||||
[btn viewDidMoveToSuperview];
|
|
||||||
}
|
|
||||||
|
|
||||||
auto frame = btn.frame;
|
|
||||||
btn.frame = NSMakeRect(
|
|
||||||
frame.origin.x + offset.x(),
|
|
||||||
frame.origin.y + offset.y(),
|
|
||||||
frame.size.width, frame.size.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! The origin of AppKit coordinate system is bottom-left. */
|
|
||||||
bool setStandardWindowButtonsOffset(QWindow *w, const QPoint &offset)
|
|
||||||
{
|
{
|
||||||
NSWindow* nswindow = getNSWindow(w);
|
NSWindow* nswindow = getNSWindow(w);
|
||||||
if (nswindow == nullptr)
|
if (nswindow == nullptr)
|
||||||
return false;
|
return QSize();
|
||||||
|
|
||||||
NSView* contentview = nswindow.contentView;
|
NSButton* left = [nswindow standardWindowButton:NSWindowCloseButton];
|
||||||
if (contentview == nullptr)
|
NSButton* right = [nswindow standardWindowButton:NSWindowZoomButton];
|
||||||
return false;
|
float height = NSHeight(left.frame);
|
||||||
|
float width = NSMaxX(right.frame) - NSMinX(left.frame);
|
||||||
auto close = [nswindow standardWindowButton:NSWindowCloseButton];
|
return QSize(width, height);
|
||||||
auto min = [nswindow standardWindowButton:NSWindowMiniaturizeButton];
|
|
||||||
auto zoom = [nswindow standardWindowButton:NSWindowZoomButton];
|
|
||||||
|
|
||||||
setButtonLocation(close, offset, contentview);
|
|
||||||
setButtonLocation(min, offset, contentview);
|
|
||||||
setButtonLocation(zoom, offset, contentview);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool setTrafficLightPosition(QWindow *w, const QPoint &pos)
|
|
||||||
{
|
|
||||||
NSWindowData* obj = gQWindowToNSWindow[w];
|
|
||||||
return obj->setTrafficLightPosition(pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Utilities
|
} // namespace Utilities
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
#include <QtCore/qpoint.h>
|
#include <QtCore/qpoint.h>
|
||||||
|
|
||||||
|
#include "scoped_nsobject.h"
|
||||||
|
|
||||||
@class WindowButtonsProxy;
|
@class WindowButtonsProxy;
|
||||||
|
|
||||||
// A helper view that floats above the window buttons.
|
// A helper view that floats above the window buttons.
|
||||||
|
@ -32,8 +34,8 @@
|
||||||
// Track mouse moves above window buttons.
|
// Track mouse moves above window buttons.
|
||||||
BOOL show_on_hover_;
|
BOOL show_on_hover_;
|
||||||
BOOL mouse_inside_;
|
BOOL mouse_inside_;
|
||||||
NSTrackingArea* tracking_area_;
|
scoped_nsobject<NSTrackingArea> tracking_area_;
|
||||||
ButtonsAreaHoverView* hover_view_;
|
scoped_nsobject<ButtonsAreaHoverView> hover_view_;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithWindow:(NSWindow*)window;
|
- (id)initWithWindow:(NSWindow*)window;
|
||||||
|
|
|
@ -65,15 +65,12 @@
|
||||||
// Put a transparent view above the window buttons so we can track mouse
|
// Put a transparent view above the window buttons so we can track mouse
|
||||||
// events when mouse enter/leave the window buttons.
|
// events when mouse enter/leave the window buttons.
|
||||||
if (show_on_hover_) {
|
if (show_on_hover_) {
|
||||||
auto old_ptr = hover_view_;
|
hover_view_.reset([[ButtonsAreaHoverView alloc] initWithProxy:self]);
|
||||||
hover_view_ = [[ButtonsAreaHoverView alloc] initWithProxy:self];
|
|
||||||
[old_ptr release];
|
|
||||||
[hover_view_ setFrame:[self getButtonsBounds]];
|
[hover_view_ setFrame:[self getButtonsBounds]];
|
||||||
[titleBarContainer addSubview:hover_view_];
|
[titleBarContainer addSubview:hover_view_.get()];
|
||||||
} else {
|
} else {
|
||||||
[hover_view_ removeFromSuperview];
|
[hover_view_ removeFromSuperview];
|
||||||
[hover_view_ release];
|
hover_view_.reset();
|
||||||
hover_view_ = nullptr;
|
|
||||||
}
|
}
|
||||||
[self updateButtonsVisibility];
|
[self updateButtonsVisibility];
|
||||||
}
|
}
|
||||||
|
@ -126,16 +123,14 @@
|
||||||
|
|
||||||
- (void)updateTrackingAreas {
|
- (void)updateTrackingAreas {
|
||||||
if (tracking_area_)
|
if (tracking_area_)
|
||||||
[hover_view_ removeTrackingArea:tracking_area_];
|
[hover_view_ removeTrackingArea:tracking_area_.get()];
|
||||||
auto old_ptr = tracking_area_;
|
tracking_area_.reset([[NSTrackingArea alloc]
|
||||||
tracking_area_ = [[NSTrackingArea alloc]
|
|
||||||
initWithRect:NSZeroRect
|
initWithRect:NSZeroRect
|
||||||
options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways |
|
options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways |
|
||||||
NSTrackingInVisibleRect
|
NSTrackingInVisibleRect
|
||||||
owner:self
|
owner:self
|
||||||
userInfo:nil];
|
userInfo:nil]);
|
||||||
[old_ptr release];
|
[hover_view_ addTrackingArea:tracking_area_.get()];
|
||||||
[hover_view_ addTrackingArea:tracking_area_];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseEntered:(NSEvent*)event {
|
- (void)mouseEntered:(NSEvent*)event {
|
||||||
|
|
Loading…
Reference in New Issue