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