diff --git a/CMakeLists.txt b/CMakeLists.txt index ca49686..3c6cf82 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,8 +19,15 @@ elseif (APPLE) set(CMAKE_PREFIX_PATH "/opt/homebrew/opt/qt") include_directories("/opt/homebrew/opt/tesseract/include") link_directories("/opt/homebrew/opt/tesseract/lib") + + set(CMAKE_CXX_STANDARD 17) # или 20, если нужно + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ObjC++") endif () +set(SCRCPY + ${CMAKE_CURRENT_SOURCE_DIR}/views/scrcpy/ScrcpyWindow_mac.mm +) + find_package(Qt6 REQUIRED COMPONENTS Widgets Sql @@ -52,6 +59,7 @@ add_executable(ARCDesktopProject ${SERVICES_SOURCES} ${DB_SOURCES} ${MODELS_SOURCES} + ${SCRCPY} ) if (WIN32) diff --git a/database/app_data.db b/database/app_data.db index 7b2a33b..e65c406 100644 Binary files a/database/app_data.db and b/database/app_data.db differ diff --git a/views/MainWindow.cpp b/views/MainWindow.cpp index de0a84b..1cdd484 100644 --- a/views/MainWindow.cpp +++ b/views/MainWindow.cpp @@ -48,6 +48,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { stackedWidget->setCurrentWidget(accountPage); deleteDevicePage(); // освобождаем ресурсы }); + + scrcpyWindow = new ScrcpyWindow(); + scrcpyWindow->show(); } diff --git a/views/MainWindow.h b/views/MainWindow.h index 685b957..8d8e001 100644 --- a/views/MainWindow.h +++ b/views/MainWindow.h @@ -4,6 +4,7 @@ #include #include #include "db/DeviceInfo.h" +#include "scrcpy/ScrcpyWindow.h" #include "widget/FlowLayout.h" class MainWindow final : public QMainWindow { @@ -21,6 +22,8 @@ private: QWidget* devicePage = nullptr; QWidget* accountPage = nullptr; + ScrcpyWindow *scrcpyWindow; + void createDevicePage(); void deleteDevicePage(); }; diff --git a/views/scrcpy/ScrcpyWindow.cpp b/views/scrcpy/ScrcpyWindow.cpp new file mode 100644 index 0000000..ee040df --- /dev/null +++ b/views/scrcpy/ScrcpyWindow.cpp @@ -0,0 +1,68 @@ +#include "ScrcpyWindow.h" +#include +#include + +#ifdef Q_OS_WIN +#include +#endif + +ScrcpyWindow::ScrcpyWindow(QWidget *parent) : QWidget(parent), m_process(nullptr) { + setWindowFlag(Qt::WindowStaysOnTopHint); + startScrcpy(); +} + +ScrcpyWindow::~ScrcpyWindow() { + stopScrcpy(); +} + +void ScrcpyWindow::startScrcpy() { + m_process = new QProcess(this); + m_process->start("scrcpy", {"--window-title", "scrcpy", "--always-on-top"}); + + // Подождём немного, чтобы окно scrcpy запустилось + QTimer::singleShot(5000, this, &ScrcpyWindow::embedPlatformSpecific); +} + +void ScrcpyWindow::stopScrcpy() { + if (m_process) { + m_process->terminate(); + m_process->waitForFinished(); + delete m_process; + m_process = nullptr; + } +} + + +void ScrcpyWindow::embedPlatformSpecific() { +#ifdef Q_OS_WIN + + HWND hwndScrcpy = FindWindowW(nullptr, L"scrcpy"); + if (!hwndScrcpy) { + qDebug() << "scrcpy window not found"; + return; + } + + HWND hwndTarget = (HWND)this->winId(); + SetParent(hwndScrcpy, hwndTarget); + + LONG style = GetWindowLong(hwndScrcpy, GWL_STYLE); + style &= ~(WS_CAPTION | WS_THICKFRAME | WS_BORDER); + SetWindowLong(hwndScrcpy, GWL_STYLE, style); + + RECT rect; + GetClientRect(hwndTarget, &rect); + SetWindowPos(hwndScrcpy, HWND_TOP, 0, 0, + rect.right - rect.left, rect.bottom - rect.top, + SWP_SHOWWINDOW); + +#elif defined(Q_OS_MAC) + + extern void embedScrcpyMac(QWidget *container); + embedScrcpyMac(this); + +#else + + qDebug() << "Scrcpy embedding not implemented for this OS."; + +#endif +} \ No newline at end of file diff --git a/views/scrcpy/ScrcpyWindow.h b/views/scrcpy/ScrcpyWindow.h new file mode 100644 index 0000000..e52d635 --- /dev/null +++ b/views/scrcpy/ScrcpyWindow.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +class ScrcpyWindow final : public QWidget { + Q_OBJECT + +public: + explicit ScrcpyWindow(QWidget *parent = nullptr); + + ~ScrcpyWindow() override; + +private: + QProcess *m_process; + + void startScrcpy(); + + void stopScrcpy(); + + void embedPlatformSpecific(); +}; diff --git a/views/scrcpy/ScrcpyWindow_mac.mm b/views/scrcpy/ScrcpyWindow_mac.mm new file mode 100644 index 0000000..e7da188 --- /dev/null +++ b/views/scrcpy/ScrcpyWindow_mac.mm @@ -0,0 +1,61 @@ +#import +#import +#import +#include +#include + +void listAllWindows() { + CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID); + + for (NSDictionary *entry in (__bridge NSArray *)windowList) { + NSString *name = entry[(NSString *)kCGWindowName]; + NSString *owner = entry[(NSString *)kCGWindowOwnerName]; + NSNumber *windowNumber = entry[(NSString *)kCGWindowNumber]; + if (name.length > 0) { + qDebug() << "Window:" << owner.UTF8String << "-" << name.UTF8String + << "ID:" << windowNumber.intValue; + } + } + + CFRelease(windowList); +} + +void embedScrcpyMac(QWidget *container) { + // Получаем список окон + NSArray *windows = [NSApp windows]; + NSWindow *scrcpyWindow = nil; + + listAllWindows(); + + for (NSWindow *window in windows) { + NSString *title = [window title]; + qDebug() << "Found window title:" << title.UTF8String; + + if ([[window title] isEqualToString:@"scrcpy"]) { + scrcpyWindow = window; + break; + } + } + + if (!scrcpyWindow) { + qDebug() << "scrcpy window not found"; + return; + } + + // Убираем заголовок и рамку + [scrcpyWindow setStyleMask:NSWindowStyleMaskBorderless]; + + // Получаем координаты окна Qt + NSView *nativeView = (NSView *)container->winId(); + NSWindow *qtWindow = [nativeView window]; + NSRect frame = [qtWindow frame]; + + // Задаём новый размер и позицию для окна scrcpy + CGFloat width = frame.size.width; + CGFloat height = frame.size.height; + CGFloat x = frame.origin.x; + CGFloat y = frame.origin.y; + + [scrcpyWindow setFrame:NSMakeRect(x, y, width, height) display:YES]; + [scrcpyWindow orderFront:nil]; +}