Standardize macOS detection and prompt on close

Unify platform checks to use Q_OS_MACOS for Qt6 compatibility and switch the QtScrcpyCore submodule URL to HTTPS for easier cloning.
Introduce a confirmation dialog on window close that lets users choose between minimizing to tray or exiting the app.

Improve project hygiene by extending .gitignore rules for IDE and cache files, adding missing QDebug includes, and applying minor formatting tweaks for consistency.

Standardize macOS detection and add close prompt

Unify all platform checks to Q_OS_MACOS for Qt6 compatibility.
Switch submodule URL to HTTPS for easier cloning.
Introduce a close confirmation dialog letting users minimize to tray or exit.
Improve project hygiene: extend .gitignore for IDE/cache files, add missing QDebug includes, and apply formatting tweaks.
This commit is contained in:
hupochun 2025-05-03 01:41:40 +08:00
commit efa41142b4
7 changed files with 79 additions and 45 deletions

6
.gitignore vendored
View file

@ -14,4 +14,8 @@ build-*
*.DS_Store *.DS_Store
userdata.ini userdata.ini
Info_Mac.plist Info_Mac.plist
/ci/build_temp /ci/build_temp
.vscode/
.gitignore
.gitmodules
.cache/

2
.gitmodules vendored
View file

@ -1,3 +1,3 @@
[submodule "QtScrcpy/QtScrcpyCore"] [submodule "QtScrcpy/QtScrcpyCore"]
path = QtScrcpy/QtScrcpyCore path = QtScrcpy/QtScrcpyCore
url = git@github.com:barry-ran/QtScrcpyCore.git url = https://github.com/barry-ran/QtScrcpyCore.git

View file

@ -28,7 +28,7 @@ int main(int argc, char *argv[])
qputenv("QTSCRCPY_CONFIG_PATH", "../../../config"); qputenv("QTSCRCPY_CONFIG_PATH", "../../../config");
#endif #endif
#ifdef Q_OS_OSX #ifdef Q_OS_MACOS
qputenv("QTSCRCPY_ADB_PATH", "../../../../../../QtScrcpy/QtScrcpyCore/src/third_party/adb/mac/adb"); qputenv("QTSCRCPY_ADB_PATH", "../../../../../../QtScrcpy/QtScrcpyCore/src/third_party/adb/mac/adb");
qputenv("QTSCRCPY_SERVER_PATH", "../../../../../../QtScrcpy/QtScrcpyCore/src/third_party/scrcpy-server"); qputenv("QTSCRCPY_SERVER_PATH", "../../../../../../QtScrcpy/QtScrcpyCore/src/third_party/scrcpy-server");
qputenv("QTSCRCPY_KEYMAP_PATH", "../../../../../../keymap"); qputenv("QTSCRCPY_KEYMAP_PATH", "../../../../../../keymap");
@ -58,7 +58,7 @@ int main(int argc, char *argv[])
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#if (QT_VERSION >= QT_VERSION_CHECK(5,14,0)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif #endif
#endif #endif
@ -92,7 +92,7 @@ int main(int argc, char *argv[])
} }
installTranslator(); installTranslator();
#if defined(Q_OS_WIN32) || defined(Q_OS_OSX) #if defined(Q_OS_WIN32) || defined(Q_OS_MACOS)
MouseTap::getInstance()->initMouseEventTap(); MouseTap::getInstance()->initMouseEventTap();
#endif #endif
@ -108,11 +108,11 @@ int main(int argc, char *argv[])
qsc::AdbProcess::setAdbPath(Config::getInstance().getAdbPath()); qsc::AdbProcess::setAdbPath(Config::getInstance().getAdbPath());
g_mainDlg = new Dialog {}; g_mainDlg = new Dialog{};
g_mainDlg->show(); g_mainDlg->show();
qInfo() << QObject::tr("This software is completely open source and free. Use it at your own risk. You can download it at the " qInfo() << QObject::tr("This software is completely open source and free. Use it at your own risk. You can download it at the "
"following address:"); "following address:");
qInfo() << QString("QtScrcpy %1 <https://github.com/barry-ran/QtScrcpy>").arg(QCoreApplication::applicationVersion()); qInfo() << QString("QtScrcpy %1 <https://github.com/barry-ran/QtScrcpy>").arg(QCoreApplication::applicationVersion());
qInfo() << QObject::tr("If you need more professional batch control mirror software, you can try the following software:"); qInfo() << QObject::tr("If you need more professional batch control mirror software, you can try the following software:");
@ -126,7 +126,7 @@ int main(int argc, char *argv[])
int ret = a.exec(); int ret = a.exec();
delete g_mainDlg; delete g_mainDlg;
#if defined(Q_OS_WIN32) || defined(Q_OS_OSX) #if defined(Q_OS_WIN32) || defined(Q_OS_MACOS)
MouseTap::getInstance()->quitMouseEventTap(); MouseTap::getInstance()->quitMouseEventTap();
#endif #endif
return ret; return ret;

View file

@ -5,6 +5,10 @@
#include <QRandomGenerator> #include <QRandomGenerator>
#include <QTime> #include <QTime>
#include <QTimer> #include <QTimer>
#include <QDialog>
#include <QVBoxLayout>
#include <QRadioButton>
#include <QDialogButtonBox>
#include "config.h" #include "config.h"
#include "dialog.h" #include "dialog.h"
@ -291,13 +295,32 @@ void Dialog::slotActivated(QSystemTrayIcon::ActivationReason reason)
void Dialog::closeEvent(QCloseEvent *event) void Dialog::closeEvent(QCloseEvent *event)
{ {
this->hide(); // 弹出选择对话框
if (!Config::getInstance().getTrayMessageShown()) { QDialog choiceDialog(this);
Config::getInstance().setTrayMessageShown(true); choiceDialog.setWindowTitle(tr("关闭选项"));
m_hideIcon->showMessage(tr("Notice"), QVBoxLayout *layout = new QVBoxLayout(&choiceDialog);
tr("Hidden here!"), QRadioButton *minimizeRadio = new QRadioButton(tr("最小化窗口"), &choiceDialog);
QSystemTrayIcon::Information, QRadioButton *exitRadio = new QRadioButton(tr("退出窗口"), &choiceDialog);
3000); minimizeRadio->setChecked(true);
layout->addWidget(minimizeRadio);
layout->addWidget(exitRadio);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &choiceDialog);
layout->addWidget(buttonBox);
// 设置按钮为“确认”和“取消”
buttonBox->button(QDialogButtonBox::Ok)->setText(tr("确认"));
buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("取消"));
connect(buttonBox, &QDialogButtonBox::accepted, &choiceDialog, &QDialog::accept);
connect(buttonBox, &QDialogButtonBox::rejected, &choiceDialog, &QDialog::reject);
if (choiceDialog.exec() == QDialog::Accepted) {
if (minimizeRadio->isChecked()) {
this->hide();
if (!Config::getInstance().getTrayMessageShown()) {
Config::getInstance().setTrayMessageShown(true);
m_hideIcon->showMessage(tr("Notice"), tr("Hidden here!"), QSystemTrayIcon::Information, 3000);
}
} else {
qApp->quit();
}
} }
event->ignore(); event->ignore();
} }

View file

@ -19,9 +19,9 @@
#include "config.h" #include "config.h"
#include "iconhelper.h" #include "iconhelper.h"
#include "mousetap/mousetap.h"
#include "qyuvopenglwidget.h" #include "qyuvopenglwidget.h"
#include "toolform.h" #include "toolform.h"
#include "mousetap/mousetap.h"
#include "ui_videoform.h" #include "ui_videoform.h"
#include "videoform.h" #include "videoform.h"
@ -54,7 +54,7 @@ void VideoForm::initUI()
m_widthHeightRatio = 1.0f * phone.width() / phone.height(); m_widthHeightRatio = 1.0f * phone.width() / phone.height();
} }
#ifndef Q_OS_OSX #ifndef Q_OS_MACOS
// mac下去掉标题栏影响showfullscreen // mac下去掉标题栏影响showfullscreen
// 去掉标题栏 // 去掉标题栏
setWindowFlags(windowFlags() | Qt::FramelessWindowHint); setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
@ -96,7 +96,7 @@ QRect VideoForm::getGrabCursorRect()
rc.setY(rc.y() + 10); rc.setY(rc.y() + 10);
rc.setWidth(rc.width() - 20); rc.setWidth(rc.width() - 20);
rc.setHeight(rc.height() - 20); rc.setHeight(rc.height() - 20);
#elif defined(Q_OS_OSX) #elif defined(Q_OS_MACOS)
rc = m_videoWidget->geometry(); rc = m_videoWidget->geometry();
rc.setTopLeft(ui->keepRatioWidget->mapToGlobal(rc.topLeft())); rc.setTopLeft(ui->keepRatioWidget->mapToGlobal(rc.topLeft()));
rc.setBottomRight(ui->keepRatioWidget->mapToGlobal(rc.bottomRight())); rc.setBottomRight(ui->keepRatioWidget->mapToGlobal(rc.bottomRight()));
@ -147,7 +147,7 @@ void VideoForm::showFPS(bool show)
m_fpsLabel->setVisible(show); m_fpsLabel->setVisible(show);
} }
void VideoForm::updateRender(int width, int height, uint8_t* dataY, uint8_t* dataU, uint8_t* dataV, int linesizeY, int linesizeU, int linesizeV) void VideoForm::updateRender(int width, int height, uint8_t *dataY, uint8_t *dataU, uint8_t *dataV, int linesizeY, int linesizeU, int linesizeV)
{ {
if (m_videoWidget->isHidden()) { if (m_videoWidget->isHidden()) {
if (m_loadingWidget) { if (m_loadingWidget) {
@ -474,7 +474,7 @@ void VideoForm::switchFullScreen()
// fullscreen window will move (0,0). qt bug? // fullscreen window will move (0,0). qt bug?
move(m_fullScreenBeforePos); move(m_fullScreenBeforePos);
#ifdef Q_OS_OSX #ifdef Q_OS_MACOS
//setWindowFlags(windowFlags() | Qt::FramelessWindowHint); //setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
//show(); //show();
#endif #endif
@ -497,7 +497,7 @@ void VideoForm::switchFullScreen()
m_fullScreenBeforePos = pos(); m_fullScreenBeforePos = pos();
// 这种临时增加标题栏再全屏的方案会导致收不到mousemove事件导致setmousetrack失效 // 这种临时增加标题栏再全屏的方案会导致收不到mousemove事件导致setmousetrack失效
// mac fullscreen must show title bar // mac fullscreen must show title bar
#ifdef Q_OS_OSX #ifdef Q_OS_MACOS
//setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint); //setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint);
#endif #endif
showToolForm(false); showToolForm(false);
@ -574,11 +574,11 @@ void VideoForm::mousePressEvent(QMouseEvent *event)
} }
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
QPointF localPos = event->localPos(); QPointF localPos = event->localPos();
QPointF globalPos = event->globalPos(); QPointF globalPos = event->globalPos();
#else #else
QPointF localPos = event->position(); QPointF localPos = event->position();
QPointF globalPos = event->globalPosition(); QPointF globalPos = event->globalPosition();
#endif #endif
if (m_videoWidget->geometry().contains(event->pos())) { if (m_videoWidget->geometry().contains(event->pos())) {
@ -642,11 +642,11 @@ void VideoForm::mouseReleaseEvent(QMouseEvent *event)
void VideoForm::mouseMoveEvent(QMouseEvent *event) void VideoForm::mouseMoveEvent(QMouseEvent *event)
{ {
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
QPointF localPos = event->localPos(); QPointF localPos = event->localPos();
QPointF globalPos = event->globalPos(); QPointF globalPos = event->globalPos();
#else #else
QPointF localPos = event->position(); QPointF localPos = event->position();
QPointF globalPos = event->globalPosition(); QPointF globalPos = event->globalPosition();
#endif #endif
auto device = qsc::IDeviceManage::getInstance().getDevice(m_serial); auto device = qsc::IDeviceManage::getInstance().getDevice(m_serial);
if (m_videoWidget->geometry().contains(event->pos())) { if (m_videoWidget->geometry().contains(event->pos())) {
@ -713,8 +713,17 @@ void VideoForm::wheelEvent(QWheelEvent *event)
QPointF pos = m_videoWidget->mapFrom(this, event->pos()); QPointF pos = m_videoWidget->mapFrom(this, event->pos());
QWheelEvent wheelEvent( QWheelEvent wheelEvent(
pos, event->globalPosF(), event->pixelDelta(), event->angleDelta(), event->delta(), event->orientation(), pos,
event->buttons(), event->modifiers(), event->phase(), event->source(), event->inverted()); event->globalPosF(),
event->pixelDelta(),
event->angleDelta(),
event->delta(),
event->orientation(),
event->buttons(),
event->modifiers(),
event->phase(),
event->source(),
event->inverted());
#endif #endif
emit device->wheelEvent(&wheelEvent, m_videoWidget->frameSize(), m_videoWidget->size()); emit device->wheelEvent(&wheelEvent, m_videoWidget->frameSize(), m_videoWidget->size());
} }
@ -759,9 +768,7 @@ void VideoForm::showEvent(QShowEvent *event)
{ {
Q_UNUSED(event) Q_UNUSED(event)
if (!isFullScreen() && this->show_toolbar) { if (!isFullScreen() && this->show_toolbar) {
QTimer::singleShot(500, this, [this](){ QTimer::singleShot(500, this, [this]() { showToolForm(this->show_toolbar); });
showToolForm(this->show_toolbar);
});
} }
} }

View file

@ -1,10 +1,10 @@
#include <QCoreApplication> #include <QCoreApplication>
#include <QDebug>
#include <QFileInfo> #include <QFileInfo>
#include <QSettings> #include <QSettings>
#include <QDebug>
#include "config.h" #include "config.h"
#ifdef Q_OS_OSX #ifdef Q_OS_MACOS
#include "path.h" #include "path.h"
#endif #endif
@ -127,7 +127,7 @@ Config::Config(QObject *parent) : QObject(parent)
m_userData->setIniCodec("UTF-8"); m_userData->setIniCodec("UTF-8");
#endif #endif
qDebug()<<m_userData->childGroups(); qDebug() << m_userData->childGroups();
} }
Config &Config::getInstance() Config &Config::getInstance()
@ -145,7 +145,7 @@ const QString &Config::getConfigPath()
// default application dir // default application dir
// mac系统当从finder打开app时默认工作目录不再是可执行程序的目录了而是"/" // mac系统当从finder打开app时默认工作目录不再是可执行程序的目录了而是"/"
// 而Qt的获取工作目录的api都依赖QCoreApplication的初始化所以使用mac api获取当前目录 // 而Qt的获取工作目录的api都依赖QCoreApplication的初始化所以使用mac api获取当前目录
#ifdef Q_OS_OSX #ifdef Q_OS_MACOS
// get */QtScrcpy.app path // get */QtScrcpy.app path
s_configPath = Path::GetCurrentPath(); s_configPath = Path::GetCurrentPath();
s_configPath += "/Contents/MacOS/config"; s_configPath += "/Contents/MacOS/config";
@ -199,7 +199,7 @@ UserBootConfig Config::getUserBootConfig()
config.keepAlive = m_userData->value(COMMON_KEEP_ALIVE_KEY, COMMON_KEEP_ALIVE_DEF).toBool(); config.keepAlive = m_userData->value(COMMON_KEEP_ALIVE_KEY, COMMON_KEEP_ALIVE_DEF).toBool();
config.simpleMode = m_userData->value(COMMON_SIMPLE_MODE_KEY, COMMON_SIMPLE_MODE_DEF).toBool(); config.simpleMode = m_userData->value(COMMON_SIMPLE_MODE_KEY, COMMON_SIMPLE_MODE_DEF).toBool();
config.autoUpdateDevice = m_userData->value(COMMON_AUTO_UPDATE_DEVICE_KEY, COMMON_AUTO_UPDATE_DEVICE_DEF).toBool(); config.autoUpdateDevice = m_userData->value(COMMON_AUTO_UPDATE_DEVICE_KEY, COMMON_AUTO_UPDATE_DEVICE_DEF).toBool();
config.showToolbar =m_userData->value(COMMON_SHOW_TOOLBAR_KEY,COMMON_SHOW_TOOLBAR_DEF).toBool(); config.showToolbar = m_userData->value(COMMON_SHOW_TOOLBAR_KEY, COMMON_SHOW_TOOLBAR_DEF).toBool();
m_userData->endGroup(); m_userData->endGroup();
return config; return config;
} }
@ -393,18 +393,18 @@ QString Config::getTitle()
void Config::saveIpHistory(const QString &ip) void Config::saveIpHistory(const QString &ip)
{ {
QStringList ipList = getIpHistory(); QStringList ipList = getIpHistory();
// 移除已存在的相同IP避免重复 // 移除已存在的相同IP避免重复
ipList.removeAll(ip); ipList.removeAll(ip);
// 将新IP添加到开头 // 将新IP添加到开头
ipList.prepend(ip); ipList.prepend(ip);
// 限制历史记录数量 // 限制历史记录数量
while (ipList.size() > IP_HISTORY_MAX) { while (ipList.size() > IP_HISTORY_MAX) {
ipList.removeLast(); ipList.removeLast();
} }
m_userData->setValue(IP_HISTORY_KEY, ipList); m_userData->setValue(IP_HISTORY_KEY, ipList);
m_userData->sync(); m_userData->sync();
} }

View file

@ -4,7 +4,7 @@
#ifdef Q_OS_WIN32 #ifdef Q_OS_WIN32
#include "winmousetap.h" #include "winmousetap.h"
#endif #endif
#ifdef Q_OS_OSX #ifdef Q_OS_MACOS
#include "cocoamousetap.h" #include "cocoamousetap.h"
#endif #endif
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
@ -18,7 +18,7 @@ MouseTap *MouseTap::getInstance()
#ifdef Q_OS_WIN32 #ifdef Q_OS_WIN32
s_instance = new WinMouseTap(); s_instance = new WinMouseTap();
#endif #endif
#ifdef Q_OS_OSX #ifdef Q_OS_MACOS
s_instance = new CocoaMouseTap(); s_instance = new CocoaMouseTap();
#endif #endif
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX