diff --git a/src/airplaywindow.cpp b/src/airplaywidget.cpp similarity index 92% rename from src/airplaywindow.cpp rename to src/airplaywidget.cpp index 1c9de58..b8de054 100644 --- a/src/airplaywindow.cpp +++ b/src/airplaywidget.cpp @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -#include "airplaywindow.h" +#include "airplaywidget.h" #include #include #include @@ -137,8 +137,8 @@ AirPlaySettings AirPlaySettingsDialog::getSettings() const return settings; } -AirPlayWindow::AirPlayWindow(QWidget *parent) - : QMainWindow(parent), m_stackedWidget(nullptr), m_tutorialWidget(nullptr), +AirPlayWidget::AirPlayWidget(QWidget *parent) + : Tool(parent), m_stackedWidget(nullptr), m_tutorialWidget(nullptr), m_streamingWidget(nullptr), m_loadingIndicator(nullptr), m_loadingLabel(nullptr), m_tutorialPlayer(nullptr), m_tutorialVideoWidget(nullptr), m_videoLabel(nullptr), @@ -167,14 +167,14 @@ AirPlayWindow::AirPlayWindow(QWidget *parent) DiagnoseDialog *diagnoseDialog = new DiagnoseDialog(); diagnoseDialog->show(); - QTimer::singleShot(0, this, &AirPlayWindow::close); + QTimer::singleShot(0, this, &AirPlayWidget::close); return; } #endif - QTimer::singleShot(500, this, &AirPlayWindow::startAirPlayServer); + QTimer::singleShot(500, this, &AirPlayWidget::startAirPlayServer); } -AirPlayWindow::~AirPlayWindow() +AirPlayWidget::~AirPlayWidget() { stopAirPlayServer(); #ifdef Q_OS_LINUX @@ -182,13 +182,11 @@ AirPlayWindow::~AirPlayWindow() #endif } -void AirPlayWindow::setupUI() +void AirPlayWidget::setupUI() { - setWindowTitle("AirPlay Receiver - iDescriptor"); + setWindowTitle("AirPlay - iDescriptor"); - // Create stacked widget m_stackedWidget = new QStackedWidget(this); - setCentralWidget(m_stackedWidget); m_tutorialWidget = new QWidget(); m_tutorialLayout = new QVBoxLayout(m_tutorialWidget); @@ -216,14 +214,14 @@ void AirPlayWindow::setupUI() m_settingsButton = new QPushButton("Settings"); m_settingsButton->setVisible(false); connect(m_settingsButton, &QPushButton::clicked, this, - &AirPlayWindow::showSettingsDialog); + &AirPlayWidget::showSettingsDialog); QHBoxLayout *settingsLayout = new QHBoxLayout(); settingsLayout->addStretch(); settingsLayout->addWidget(m_settingsButton); settingsLayout->addStretch(); m_tutorialLayout->addLayout(settingsLayout); - QTimer::singleShot(100, this, &AirPlayWindow::setupTutorialVideo); + QTimer::singleShot(100, this, &AirPlayWidget::setupTutorialVideo); m_streamingWidget = new QWidget(); QVBoxLayout *streamingLayout = new QVBoxLayout(m_streamingWidget); @@ -250,13 +248,14 @@ void AirPlayWindow::setupUI() // Start with tutorial widget m_stackedWidget->setCurrentWidget(m_tutorialWidget); + layout()->addWidget(m_stackedWidget); #ifdef __linux__ m_v4l2_enabled = false; // Disable V4L2 by default #endif } -void AirPlayWindow::setupTutorialVideo() +void AirPlayWidget::setupTutorialVideo() { m_tutorialPlayer = new QMediaPlayer(this); m_tutorialVideoWidget = new QVideoWidget(); @@ -289,7 +288,7 @@ void AirPlayWindow::setupTutorialVideo() m_tutorialLayout->addWidget(m_tutorialVideoWidget, 1); } -void AirPlayWindow::showTutorialView() +void AirPlayWidget::showTutorialView() { m_stackedWidget->setCurrentWidget(m_tutorialWidget); if (m_tutorialPlayer) { @@ -298,7 +297,7 @@ void AirPlayWindow::showTutorialView() } } -void AirPlayWindow::showStreamingView() +void AirPlayWidget::showStreamingView() { m_loadingIndicator->stop(); m_stackedWidget->setCurrentWidget(m_streamingWidget); @@ -307,7 +306,7 @@ void AirPlayWindow::showStreamingView() } } -void AirPlayWindow::showSettingsDialog() +void AirPlayWidget::showSettingsDialog() { AirPlaySettingsDialog dialog(this); if (dialog.exec() == QDialog::Accepted) { @@ -316,26 +315,26 @@ void AirPlayWindow::showSettingsDialog() // Save settings SettingsManager::sharedInstance()->setAirplayFps(newSettings.fps); SettingsManager::sharedInstance()->setAirplayNoHold(newSettings.noHold); - + QMessageBox::information(this, "Settings Saved", "AirPlay will be restarted to apply the new " "settings."); - ToolboxWidget::sharedInstance()->restartAirPlayWindow(); + ToolboxWidget::sharedInstance()->restartAirPlayWidget(); } } -void AirPlayWindow::startAirPlayServer() +void AirPlayWidget::startAirPlayServer() { if (m_serverRunning) return; m_serverThread = new AirPlayServerThread(this); connect(m_serverThread, &AirPlayServerThread::statusChanged, this, - &AirPlayWindow::onServerStatusChanged); + &AirPlayWidget::onServerStatusChanged); connect(m_serverThread, &AirPlayServerThread::videoFrameReady, this, - &AirPlayWindow::updateVideoFrame); + &AirPlayWidget::updateVideoFrame); connect(m_serverThread, &AirPlayServerThread::clientConnectionChanged, this, - &AirPlayWindow::onClientConnectionChanged); + &AirPlayWidget::onClientConnectionChanged); connect(m_serverThread, &AirPlayServerThread::errorOccurred, this, [this](const QString &message) { QMessageBox::critical(this, "AirPlay Server Error", message); @@ -347,7 +346,7 @@ void AirPlayWindow::startAirPlayServer() m_serverThread->start(); } -void AirPlayWindow::stopAirPlayServer() +void AirPlayWidget::stopAirPlayServer() { if (m_serverThread) { m_serverThread->quit(); @@ -357,7 +356,7 @@ void AirPlayWindow::stopAirPlayServer() m_serverRunning = false; } -void AirPlayWindow::updateVideoFrame(QByteArray frameData, int width, +void AirPlayWidget::updateVideoFrame(QByteArray frameData, int width, int height) { if (frameData.size() != width * height * 3) { @@ -386,7 +385,7 @@ void AirPlayWindow::updateVideoFrame(QByteArray frameData, int width, m_videoLabel->setPixmap(scaledPixmap); } -void AirPlayWindow::onServerStatusChanged(bool running) +void AirPlayWidget::onServerStatusChanged(bool running) { m_serverRunning = running; @@ -420,7 +419,7 @@ void AirPlayWindow::onServerStatusChanged(bool running) } } -void AirPlayWindow::onClientConnectionChanged(bool connected) +void AirPlayWidget::onClientConnectionChanged(bool connected) { m_clientConnected = connected; @@ -439,7 +438,7 @@ void AirPlayWindow::onClientConnectionChanged(bool connected) } #ifdef __linux__ -void AirPlayWindow::onV4L2CheckboxToggled(bool enabled) +void AirPlayWidget::onV4L2CheckboxToggled(bool enabled) { if (enabled) { // Check if V4L2 loopback exists @@ -566,7 +565,7 @@ void AirPlayServerThread::run() #ifdef __linux__ // V4L2 Implementation -void AirPlayWindow::initV4L2(int width, int height, const char *device) +void AirPlayWidget::initV4L2(int width, int height, const char *device) { closeV4L2(); // Close previous device if any @@ -598,7 +597,7 @@ void AirPlayWindow::initV4L2(int width, int height, const char *device) qDebug("V4L2 device %s initialized to %dx%d", device, width, height); } -void AirPlayWindow::closeV4L2() +void AirPlayWidget::closeV4L2() { if (m_v4l2_fd >= 0) { ::close(m_v4l2_fd); @@ -606,7 +605,7 @@ void AirPlayWindow::closeV4L2() } } -void AirPlayWindow::writeFrameToV4L2(uint8_t *data, int width, int height) +void AirPlayWidget::writeFrameToV4L2(uint8_t *data, int width, int height) { // Check if V4L2 device needs to be initialized or re-initialized if (m_v4l2_fd < 0 || m_v4l2_width != width || m_v4l2_height != height) { @@ -625,7 +624,7 @@ void AirPlayWindow::writeFrameToV4L2(uint8_t *data, int width, int height) } } -bool AirPlayWindow::checkV4L2LoopbackExists() +bool AirPlayWidget::checkV4L2LoopbackExists() { try { QFileInfo videoDevice("/dev/video0"); @@ -636,7 +635,7 @@ bool AirPlayWindow::checkV4L2LoopbackExists() } } -bool AirPlayWindow::createV4L2Loopback() +bool AirPlayWidget::createV4L2Loopback() { try { QProcess process; @@ -680,7 +679,7 @@ bool AirPlayWindow::createV4L2Loopback() } } -void AirPlayWindow::setupV4L2Checkbox() +void AirPlayWidget::setupV4L2Checkbox() { if (!SettingsManager::sharedInstance()->showV4L2()) return; @@ -692,7 +691,7 @@ void AirPlayWindow::setupV4L2Checkbox() m_v4l2Checkbox->setChecked(false); connect(m_v4l2Checkbox, &QCheckBox::toggled, this, - &AirPlayWindow::onV4L2CheckboxToggled); + &AirPlayWidget::onV4L2CheckboxToggled); } catch (...) { qWarning("Exception occurred while setting up V4L2 checkbox"); diff --git a/src/airplaywindow.h b/src/airplaywidget.h similarity index 94% rename from src/airplaywindow.h rename to src/airplaywidget.h index 1e6e5c0..e5e625d 100644 --- a/src/airplaywindow.h +++ b/src/airplaywidget.h @@ -17,9 +17,10 @@ * along with this program. If not, see . */ -#ifndef AIRPLAYWINDOW_H -#define AIRPLAYWINDOW_H +#ifndef AIRPLAYWIDGET_H +#define AIRPLAYWIDGET_H +#include "iDescriptor-ui.h" #include "qprocessindicator.h" #include #include @@ -93,13 +94,13 @@ private: AirPlaySettings m_settings; }; -class AirPlayWindow : public QMainWindow +class AirPlayWidget : public Tool { Q_OBJECT public: - explicit AirPlayWindow(QWidget *parent = nullptr); - ~AirPlayWindow(); + explicit AirPlayWidget(QWidget *parent = nullptr); + ~AirPlayWidget(); private slots: void updateVideoFrame(QByteArray frameData, int width, int height); @@ -154,4 +155,4 @@ private: AirPlaySettings m_settings; }; -#endif // AIRPLAYWINDOW_H +#endif // AIRPLAYWIDGET_H diff --git a/src/base/tool.cpp b/src/base/tool.cpp new file mode 100644 index 0000000..05ec12c --- /dev/null +++ b/src/base/tool.cpp @@ -0,0 +1,27 @@ +/* + * iDescriptor: A free and open-source idevice management tool. + * + * Copyright (C) 2025 Uncore + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include "tool.h" + +Tool::Tool(QWidget *parent) : QWidget(parent) +{ +#ifdef __APPLE__ + setupToolFrame(this); +#endif +} diff --git a/src/base/tool.h b/src/base/tool.h new file mode 100644 index 0000000..c92236a --- /dev/null +++ b/src/base/tool.h @@ -0,0 +1,35 @@ +/* + * iDescriptor: A free and open-source idevice management tool. + * + * Copyright (C) 2025 Uncore + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef TOOL_H +#define TOOL_H + +#include + +#ifdef __APPLE__ +#include "../platform/macos/macos.h" +#endif + +class Tool : public QWidget +{ +public: + explicit Tool(QWidget *parent = nullptr); +}; + +#endif // TOOL_H \ No newline at end of file diff --git a/src/cableinfowidget.cpp b/src/cableinfowidget.cpp index b85b9b2..60db9ef 100644 --- a/src/cableinfowidget.cpp +++ b/src/cableinfowidget.cpp @@ -27,7 +27,7 @@ #include CableInfoWidget::CableInfoWidget(iDescriptorDevice *device, QWidget *parent) - : QWidget(parent), m_device(device), m_response(nullptr) + : Tool(parent), m_device(device), m_response(nullptr) { setupUI(); connect(AppContext::sharedInstance(), &AppContext::deviceRemoved, this, diff --git a/src/cableinfowidget.h b/src/cableinfowidget.h index be6de40..eafe8d8 100644 --- a/src/cableinfowidget.h +++ b/src/cableinfowidget.h @@ -20,6 +20,7 @@ #ifndef CABLEINFOWIDGET_H #define CABLEINFOWIDGET_H +#include "iDescriptor-ui.h" #include "iDescriptor.h" #include "zloadingwidget.h" #include @@ -31,7 +32,7 @@ #include #include -class CableInfoWidget : public QWidget +class CableInfoWidget : public Tool { Q_OBJECT diff --git a/src/devdiskimageswidget.cpp b/src/devdiskimageswidget.cpp index 93a72bb..b47475c 100644 --- a/src/devdiskimageswidget.cpp +++ b/src/devdiskimageswidget.cpp @@ -51,10 +51,12 @@ DevDiskImagesWidget::DevDiskImagesWidget(iDescriptorDevice *device, QWidget *parent) - : QWidget{parent}, + : Tool(parent), m_currentDeviceUdid( device != nullptr ? QString::fromStdString(device->udid) : QString()) { + setMinimumSize(400, 400); + resize(800, 600); setupUi(); connect(DevDiskManager::sharedInstance(), &DevDiskManager::imageListFetched, this, &DevDiskImagesWidget::onImageListFetched); @@ -204,14 +206,27 @@ void DevDiskImagesWidget::displayImages() qDebug() << "Total images:" << allImages.size(); + int itemIndex = 0; + // Create UI items auto createVersionItem = [&](const ImageInfo &info) { bool isCompatible = (info.compatibility == ImageCompatibility::Compatible || info.compatibility == ImageCompatibility::MaybeCompatible); auto *itemWidget = new QWidget(); + itemWidget->setObjectName("itemWidget"); auto *itemLayout = new QHBoxLayout(itemWidget); + // TODO: maybe create a custom widget for this, if we ever need this + // elsewhere ? + QColor baseColor = QApplication::palette().color(QPalette::Window); + QColor bgColor = + itemIndex % 2 == 0 ? baseColor.lighter(110) : baseColor; + itemWidget->setStyleSheet( + QString("QWidget#itemWidget { background-color: %1; }") + .arg(bgColor.name())); + itemIndex++; + auto *versionLabel = new QLabel(info.version); if (isCompatible) { if (info.compatibility == ImageCompatibility::Compatible) { @@ -229,20 +244,20 @@ void DevDiskImagesWidget::displayImages() if (hasConnectedDevice) { if (isCompatible) { if (info.isMounted) { - auto *mountedLabel = new QLabel("✓ Mounted"); + auto *mountedLabel = new QLabel("Mounted"); mountedLabel->setStyleSheet( "QLabel { color: #1565C0; font-weight: bold; }"); itemLayout->addWidget(mountedLabel); } else if (info.compatibility == ImageCompatibility::MaybeCompatible) { - auto *maybeLabel = new QLabel("⚠ Maybe compatible"); + auto *maybeLabel = new QLabel("Maybe compatible"); maybeLabel->setStyleSheet("QLabel { color: #F57C00; " "margin-left: 10px; font-weight: " "bold; }"); itemLayout->addWidget(maybeLabel); } } else { - auto *incompatLabel = new QLabel("⚠ Not compatible"); + auto *incompatLabel = new QLabel("Not compatible"); incompatLabel->setStyleSheet( "QLabel { color: #D32F2F; margin-left: 10px; font-weight: " "bold; }"); diff --git a/src/devdiskimageswidget.h b/src/devdiskimageswidget.h index c6db239..487a014 100644 --- a/src/devdiskimageswidget.h +++ b/src/devdiskimageswidget.h @@ -20,6 +20,7 @@ #ifndef DEVDISKIMAGESWIDGET_H #define DEVDISKIMAGESWIDGET_H +#include "iDescriptor-ui.h" #include "iDescriptor.h" #include "qprocessindicator.h" #include @@ -35,7 +36,7 @@ #include #include -class DevDiskImagesWidget : public QWidget +class DevDiskImagesWidget : public Tool { Q_OBJECT public: diff --git a/src/diskusagebar.cpp b/src/diskusagebar.cpp index e11ddd8..fa9d857 100644 --- a/src/diskusagebar.cpp +++ b/src/diskusagebar.cpp @@ -19,7 +19,7 @@ #ifdef __APPLE__ #include "diskusagebar.h" -#include "platform/macos.h" +#include "platform/macos/macos.h" #include #include diff --git a/src/iDescriptor-ui.h b/src/iDescriptor-ui.h index 467df6b..d5a3708 100644 --- a/src/iDescriptor-ui.h +++ b/src/iDescriptor-ui.h @@ -36,8 +36,10 @@ #include #include +#include "./base/tool.h" + #ifdef __APPLE__ -#include "./platform/macos.h" +#include "./platform/macos/macos.h" #endif #define COLOR_GREEN QColor(0, 180, 0) // Green diff --git a/src/infolabel.h b/src/infolabel.h index 18e55d9..58f505b 100644 --- a/src/infolabel.h +++ b/src/infolabel.h @@ -37,7 +37,7 @@ public: protected: void mousePressEvent(QMouseEvent *event) override; - void enterEvent(QEnterEvent *event); + void enterEvent(QEnterEvent *event) override; void leaveEvent(QEvent *event) override; private slots: diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 416fdc9..4e770d9 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -435,11 +435,19 @@ MainWindow::MainWindow(QWidget *parent) connect(NetworkDeviceManager::sharedInstance(), &NetworkDeviceManager::deviceAdded, this, [this](const NetworkDevice &device) { - // return; // FIXME: disable for now - if (AppContext::sharedInstance()->getDeviceByMacAddress( - device.macAddress)) { - qDebug() << "Prefering wired connection on device MAC:" - << device.macAddress; + if (auto existingDevice = + AppContext::sharedInstance()->getDeviceByMacAddress( + device.macAddress)) { + if (existingDevice->deviceInfo.isWireless) { + qDebug() << "Ignoring wireless device with MAC:" + << device.macAddress + << "as it's already initialized"; + + } else { + qDebug() << "Prefering wired connection on device MAC:" + << device.macAddress; + } + return; } qDebug() << "Trying to add network device with MAC:" diff --git a/src/networkdeviceswidget.cpp b/src/networkdeviceswidget.cpp index 5799dea..efb79b9 100644 --- a/src/networkdeviceswidget.cpp +++ b/src/networkdeviceswidget.cpp @@ -18,7 +18,6 @@ */ #include "networkdeviceswidget.h" - #ifdef __linux__ #include "core/services/avahi/avahi_service.h" #else @@ -31,11 +30,12 @@ #include #include -NetworkDevicesWidget::NetworkDevicesWidget(QWidget *parent) : QWidget(parent) +NetworkDevicesWidget::NetworkDevicesWidget(QWidget *parent) : Tool(parent) { setWindowTitle("Network Devices - iDescriptor"); + resize(500, 600); + setMinimumSize(400, 300); setupUI(); - #ifdef __linux__ m_networkProvider = new AvahiService(this); connect(m_networkProvider, &AvahiService::deviceAdded, this, @@ -55,6 +55,7 @@ NetworkDevicesWidget::NetworkDevicesWidget(QWidget *parent) : QWidget(parent) // Initial device list update updateDeviceList(); + setMaximumHeight(sizeHint().height()); } NetworkDevicesWidget::~NetworkDevicesWidget() diff --git a/src/networkdeviceswidget.h b/src/networkdeviceswidget.h index 8762f94..f28448f 100644 --- a/src/networkdeviceswidget.h +++ b/src/networkdeviceswidget.h @@ -26,6 +26,7 @@ #include "core/services/dnssd/dnssd_service.h" #endif +#include "iDescriptor-ui.h" #include #include #include @@ -33,7 +34,7 @@ #include #include -class NetworkDevicesWidget : public QWidget +class NetworkDevicesWidget : public Tool { Q_OBJECT diff --git a/src/platform/macos.h b/src/platform/macos/macos.h similarity index 93% rename from src/platform/macos.h rename to src/platform/macos/macos.h index 70bd0e4..1f9ed92 100644 --- a/src/platform/macos.h +++ b/src/platform/macos/macos.h @@ -17,6 +17,7 @@ * along with this program. If not, see . */ +#pragma once #include #include #include @@ -33,4 +34,6 @@ void setupMacOSWindow(QMainWindow *window); void showPopoverForBarWidget(QWidget *widget, const UsageInfo &info); -void hidePopoverForBarWidget(); \ No newline at end of file +void hidePopoverForBarWidget(); + +void setupToolFrame(QWidget *parent); \ No newline at end of file diff --git a/src/platform/macos.mm b/src/platform/macos/macos.mm similarity index 63% rename from src/platform/macos.mm rename to src/platform/macos/macos.mm index e2cacbf..2ea392c 100644 --- a/src/platform/macos.mm +++ b/src/platform/macos/macos.mm @@ -191,3 +191,100 @@ void showPopoverForBarWidget(QWidget *widget, const UsageInfo &info) s_popover = [popover retain]; s_viewController = [viewController retain]; } + +// taken from +// https://github.com/tauri-apps/tao/blob/3c2b4447aa53151ae96d30a60928d1d71e9bb5fc/src/platform_impl/macos/view.rs#L1154 +void setTrafficLightInset(NSPoint position, NSWindow *window) +{ + CGFloat x = position.x; + CGFloat y = position.y; + + NSButton *closeButton = [window standardWindowButton:NSWindowCloseButton]; + NSButton *miniaturizeButton = + [window standardWindowButton:NSWindowMiniaturizeButton]; + NSButton *zoomButton = [window standardWindowButton:NSWindowZoomButton]; + + NSView *titleBarContainer = closeButton.superview.superview; + + NSRect closeRect = closeButton.frame; + CGFloat titleBarFrameHeight = closeRect.size.height + y; + NSRect titleBarRect = titleBarContainer.frame; + titleBarRect.size.height = titleBarFrameHeight; + titleBarRect.origin.y = window.frame.size.height - titleBarFrameHeight; + [titleBarContainer setFrame:titleBarRect]; + + CGFloat spaceBetween = NSMinX(miniaturizeButton.frame) - NSMinX(closeRect); + NSArray *buttons = + @[ closeButton, miniaturizeButton, zoomButton ]; + + for (NSUInteger i = 0; i < buttons.count; i++) { + NSButton *button = buttons[i]; + NSRect rect = button.frame; + rect.origin.x = x + (i * spaceBetween); + [button setFrameOrigin:rect.origin]; + } +} + +void setupToolFrame(QWidget *toolFrame) +{ + if (!toolFrame) { + qWarning() << "setupToolFrame: toolFrame is null"; + return; + } + + NSView *nativeView = reinterpret_cast(toolFrame->winId()); + if (!nativeView) { + qWarning() << "setupToolFrame: native view is null"; + return; + } + + NSWindow *window = [nativeView window]; + if (!window) { + qWarning() << "setupToolFrame: native window is null"; + return; + } + + // Doesn't work, need to figure out a better way, we need to remove + // fullscreen button NSWindowStyleMask mask = [window styleMask]; mask &= + // ~NSWindowStyleMaskClosable; mask &= ~NSWindowStyleMaskMiniaturizable; + // mask &= ~NSWindowStyleMaskFullScreen; + // [window setStyleMask:mask]; + + NSRect windowFrame = [[window contentView] frame]; + + // NSEdgeInsets insets = NSEdgeInsetsMake(20, 15, 0, 0); + // // macOS 12.0+ uses a single inset point; adjust as needed for your + // target if (@available(macOS 12.0, *)) { + // [window setTrafficLightInset:NSMakePoint(15, 20)]; + // } else { + // [window setTrafficLightInsets:insets]; + // } + + // Works but resizing messes up the styles + // dispatch_async(dispatch_get_main_queue(), ^{ + // setTrafficLightInset(NSMakePoint(20, 25), window); + // // x = horizontal inset from left, y = extra height added to title bar + // setTrafficLightInset(NSMakePoint(35.0, 44.0), window); + // }); + + NSToolbar *toolbar = + [[NSToolbar alloc] initWithIdentifier:@"HiddenInsetToolbar"]; + toolbar.showsBaselineSeparator = + NO; // equivalent to HideToolbarSeparator: true + [window setToolbar:toolbar]; + [window setBackgroundColor:[NSColor colorWithWhite:0.95 alpha:1.0]]; + // [toolbar setVisible:NO]; + // todo : is it ok ? + [toolbar release]; + // TODO: theming + [window setBackgroundColor:[NSColor colorWithWhite:0.95 alpha:1.0]]; + + // NSButton *closeBtn = [window standardWindowButton:NSWindowCloseButton]; + // if (closeBtn) { + // qDebug() << "Hiding close button"; + // [closeBtn setHidden:YES]; } + // // NSButton *miniBtn = [window + // standardWindowButton:NSWindowMiniaturizeButton]; if (miniBtn) { + // qDebug() << "Hiding minimize button"; + // [miniBtn setHidden:YES]// ; } +} diff --git a/src/qprocessindicator.h b/src/qprocessindicator.h index 11c75fd..a159899 100644 --- a/src/qprocessindicator.h +++ b/src/qprocessindicator.h @@ -46,7 +46,7 @@ public: ball_rotate, }; - void paintEvent(QPaintEvent *e); + void paintEvent(QPaintEvent *e) override; void start(); void stop(); diff --git a/src/querymobilegestaltwidget.cpp b/src/querymobilegestaltwidget.cpp index ba01781..2c57857 100644 --- a/src/querymobilegestaltwidget.cpp +++ b/src/querymobilegestaltwidget.cpp @@ -28,7 +28,7 @@ QueryMobileGestaltWidget::QueryMobileGestaltWidget(iDescriptorDevice *device, QWidget *parent) - : QWidget(parent), m_device(device) + : Tool(parent), m_device(device) { // FIXME: not tested on iOS 17,18 but it's deprecated on iOS 26 // i am assuming it won't work diff --git a/src/querymobilegestaltwidget.h b/src/querymobilegestaltwidget.h index f288b4f..f528c3a 100644 --- a/src/querymobilegestaltwidget.h +++ b/src/querymobilegestaltwidget.h @@ -20,6 +20,7 @@ #ifndef QUERYMOBILEGESTALTWIDGET_H #define QUERYMOBILEGESTALTWIDGET_H +#include "iDescriptor-ui.h" #include "iDescriptor.h" #include #include @@ -36,7 +37,7 @@ #include #include -class QueryMobileGestaltWidget : public QWidget +class QueryMobileGestaltWidget : public Tool { Q_OBJECT diff --git a/src/settingswidget.cpp b/src/settingswidget.cpp index 6a2736a..b1c2159 100644 --- a/src/settingswidget.cpp +++ b/src/settingswidget.cpp @@ -58,6 +58,7 @@ void SettingsWidget::setupUI() auto *scrollArea = new QScrollArea(); auto *scrollWidget = new QWidget(); auto *scrollLayout = new QVBoxLayout(scrollWidget); + scrollLayout->setSpacing(35); scrollLayout->setContentsMargins(10, 10, 10, 10); // === GENERAL SETTINGS === diff --git a/src/toolboxwidget.cpp b/src/toolboxwidget.cpp index 514418e..4f9248e 100644 --- a/src/toolboxwidget.cpp +++ b/src/toolboxwidget.cpp @@ -18,7 +18,7 @@ */ #include "toolboxwidget.h" -#include "airplaywindow.h" +#include "airplaywidget.h" #include "appcontext.h" #include "cableinfowidget.h" #include "devdiskimageswidget.h" @@ -411,17 +411,17 @@ void ToolboxWidget::onToolboxClicked(iDescriptorTool tool, bool requiresDevice) qDebug() << "idevice exists:" << (device != nullptr) << m_uuid.c_str(); switch (tool) { case iDescriptorTool::Airplayer: { - if (!m_airplayWindow) { - m_airplayWindow = new AirPlayWindow(); - connect(m_airplayWindow, &QObject::destroyed, this, - [this]() { m_airplayWindow = nullptr; }); - m_airplayWindow->setAttribute(Qt::WA_DeleteOnClose); - m_airplayWindow->setWindowFlag(Qt::Window); - m_airplayWindow->resize(400, 300); - m_airplayWindow->show(); + if (!m_airplayWidget) { + m_airplayWidget = new AirPlayWidget(); + connect(m_airplayWidget, &QObject::destroyed, this, + [this]() { m_airplayWidget = nullptr; }); + m_airplayWidget->setAttribute(Qt::WA_DeleteOnClose); + m_airplayWidget->setWindowFlag(Qt::Window); + m_airplayWidget->resize(400, 300); + m_airplayWidget->show(); } else { - m_airplayWindow->raise(); - m_airplayWindow->activateWindow(); + m_airplayWidget->raise(); + m_airplayWidget->activateWindow(); } } break; @@ -462,11 +462,8 @@ void ToolboxWidget::onToolboxClicked(iDescriptorTool tool, bool requiresDevice) devDiskImageHelper->start(); } break; case iDescriptorTool::VirtualLocation: { - // Handle virtual location functionality VirtualLocation *virtualLocation = new VirtualLocation(device); virtualLocation->setAttribute(Qt::WA_DeleteOnClose); - virtualLocation->setWindowFlag(Qt::Window); - virtualLocation->resize(800, 600); virtualLocation->show(); } break; case iDescriptorTool::Restart: { @@ -476,20 +473,15 @@ void ToolboxWidget::onToolboxClicked(iDescriptorTool tool, bool requiresDevice) shutdownDevice(device); } break; case iDescriptorTool::QueryMobileGestalt: { - // Handle querying MobileGestalt QueryMobileGestaltWidget *queryMobileGestaltWidget = new QueryMobileGestaltWidget(device); queryMobileGestaltWidget->setAttribute(Qt::WA_DeleteOnClose); - queryMobileGestaltWidget->setWindowFlag(Qt::Window); - queryMobileGestaltWidget->resize(800, 600); queryMobileGestaltWidget->show(); } break; case iDescriptorTool::DeveloperDiskImages: { if (!m_devDiskImagesWidget) { m_devDiskImagesWidget = new DevDiskImagesWidget(device); m_devDiskImagesWidget->setAttribute(Qt::WA_DeleteOnClose); - m_devDiskImagesWidget->setWindowFlag(Qt::Window); - m_devDiskImagesWidget->resize(800, 600); connect(m_devDiskImagesWidget, &QObject::destroyed, this, [this]() { m_devDiskImagesWidget = nullptr; }); m_devDiskImagesWidget->show(); @@ -504,8 +496,6 @@ void ToolboxWidget::onToolboxClicked(iDescriptorTool tool, bool requiresDevice) connect(m_wirelessGalleryImportWidget, &QObject::destroyed, this, [this]() { m_wirelessGalleryImportWidget = nullptr; }); m_wirelessGalleryImportWidget->setAttribute(Qt::WA_DeleteOnClose); - m_wirelessGalleryImportWidget->setWindowFlag(Qt::Window); - // m_wirelessGalleryImportWidget->resize(800, 600); m_wirelessGalleryImportWidget->show(); } else { m_wirelessGalleryImportWidget->raise(); @@ -533,7 +523,6 @@ void ToolboxWidget::onToolboxClicked(iDescriptorTool tool, bool requiresDevice) case iDescriptorTool::CableInfoWidget: { CableInfoWidget *cableInfoWidget = new CableInfoWidget(device); cableInfoWidget->setAttribute(Qt::WA_DeleteOnClose); - cableInfoWidget->setWindowFlag(Qt::Window); cableInfoWidget->resize(600, 400); cableInfoWidget->show(); } break; @@ -541,8 +530,6 @@ void ToolboxWidget::onToolboxClicked(iDescriptorTool tool, bool requiresDevice) if (!m_networkDevicesWidget) { m_networkDevicesWidget = new NetworkDevicesWidget(); m_networkDevicesWidget->setAttribute(Qt::WA_DeleteOnClose); - m_networkDevicesWidget->setWindowFlag(Qt::Window); - m_networkDevicesWidget->resize(500, 600); connect(m_networkDevicesWidget, &QObject::destroyed, this, [this]() { m_networkDevicesWidget = nullptr; }); m_networkDevicesWidget->show(); @@ -647,15 +634,15 @@ void ToolboxWidget::_enterRecoveryMode(iDescriptorDevice *device) // } } -void ToolboxWidget::restartAirPlayWindow() +void ToolboxWidget::restartAirPlayWidget() { - if (!m_airplayWindow) { + if (!m_airplayWidget) { onToolboxClicked(iDescriptorTool::Airplayer, false); return; } connect( - m_airplayWindow, &QObject::destroyed, this, + m_airplayWidget, &QObject::destroyed, this, [this]() { // give some time for cleanup QTimer::singleShot(100, this, [this]() { @@ -664,5 +651,5 @@ void ToolboxWidget::restartAirPlayWindow() }, Qt::SingleShotConnection); - m_airplayWindow->close(); + m_airplayWidget->close(); } \ No newline at end of file diff --git a/src/toolboxwidget.h b/src/toolboxwidget.h index 4320564..03d1111 100644 --- a/src/toolboxwidget.h +++ b/src/toolboxwidget.h @@ -20,7 +20,7 @@ #ifndef TOOLBOXWIDGET_H #define TOOLBOXWIDGET_H -#include "airplaywindow.h" +#include "airplaywidget.h" #include "devdiskimageswidget.h" #include "devicesidebarwidget.h" #include "iDescriptor-ui.h" @@ -48,7 +48,7 @@ public: static void shutdownDevice(iDescriptorDevice *device); static void _enterRecoveryMode(iDescriptorDevice *device); static ToolboxWidget *sharedInstance(); - void restartAirPlayWindow(); + void restartAirPlayWidget(); private slots: void onDeviceSelectionChanged(); void onToolboxClicked(iDescriptorTool tool, bool requiresDevice); @@ -71,7 +71,7 @@ private: std::string m_uuid; DevDiskImagesWidget *m_devDiskImagesWidget = nullptr; NetworkDevicesWidget *m_networkDevicesWidget = nullptr; - AirPlayWindow *m_airplayWindow = nullptr; + AirPlayWidget *m_airplayWidget = nullptr; #ifndef __APPLE__ iFuseWidget *m_ifuseWidget = nullptr; #endif diff --git a/src/virtuallocationwidget.cpp b/src/virtuallocationwidget.cpp index 198b161..3a20cfc 100644 --- a/src/virtuallocationwidget.cpp +++ b/src/virtuallocationwidget.cpp @@ -42,11 +42,15 @@ #include #include #include - +// FIXME: on macOS setupToolFrame in Tool widget does nothing +// probably because we are using a QQuickWidget VirtualLocation::VirtualLocation(iDescriptorDevice *device, QWidget *parent) - : QWidget{parent}, m_device(device) + : Tool(parent), m_device(device) { setWindowTitle("Virtual Location - iDescriptor"); + setMinimumSize(600, 400); + resize(800, 600); + // Create the main layout QHBoxLayout *mainLayout = new QHBoxLayout(this); mainLayout->setContentsMargins(10, 10, 10, 10); @@ -414,7 +418,7 @@ void VirtualLocation::onApplyClicked() if (err->code == ServiceNotFoundErrorCode) { auto res = QMessageBox::question( this, "Enable Developer Mode?", - "Location Simulation service not found. Enable Developer " + "Location Simulation service is not found. Enable Developer " "Mode on the device?", QMessageBox::Yes | QMessageBox::No); if (res == QMessageBox::Yes) { diff --git a/src/virtuallocationwidget.h b/src/virtuallocationwidget.h index b63bc91..7dd89ea 100644 --- a/src/virtuallocationwidget.h +++ b/src/virtuallocationwidget.h @@ -21,6 +21,7 @@ #define VIRTUAL_LOCATION_H #include "devdiskimagehelper.h" +#include "iDescriptor-ui.h" #include "iDescriptor.h" #include #include @@ -30,7 +31,7 @@ #include #include -class VirtualLocation : public QWidget +class VirtualLocation : public Tool { Q_OBJECT diff --git a/src/wirelessgalleryimportwidget.cpp b/src/wirelessgalleryimportwidget.cpp index 25e9029..2da8f81 100644 --- a/src/wirelessgalleryimportwidget.cpp +++ b/src/wirelessgalleryimportwidget.cpp @@ -29,7 +29,7 @@ #include WirelessGalleryImportWidget::WirelessGalleryImportWidget(QWidget *parent) - : QWidget(parent), m_scrollArea(nullptr), m_scrollContent(nullptr), + : Tool(parent), m_scrollArea(nullptr), m_scrollContent(nullptr), m_fileListLayout(nullptr), m_browseButton(nullptr), m_importButton(nullptr), m_statusLabel(nullptr) { diff --git a/src/wirelessgalleryimportwidget.h b/src/wirelessgalleryimportwidget.h index 30ae68c..50cd045 100644 --- a/src/wirelessgalleryimportwidget.h +++ b/src/wirelessgalleryimportwidget.h @@ -20,6 +20,7 @@ #ifndef WIRELESSGALLERYIMPORTWIDGET_H #define WIRELESSGALLERYIMPORTWIDGET_H +#include "iDescriptor-ui.h" #include "qprocessindicator.h" #include #include @@ -32,7 +33,7 @@ #include #include -class WirelessGalleryImportWidget : public QWidget +class WirelessGalleryImportWidget : public Tool { Q_OBJECT