screenwall_widget.cpp 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073
  1. // #include "screenwall_widget.h"
  2. // #include <QApplication>
  3. // #include <QDebug>
  4. // #include <QDesktopWidget>
  5. // #include <QHideEvent>
  6. // #include <QMessageBox>
  7. // #include <QMouseEvent>
  8. // #include <QPainter>
  9. // #include <QResizeEvent>
  10. // #include <QShowEvent>
  11. // #include <QStyle>
  12. // #include <QStyleOption>
  13. // #include <QToolTip>
  14. // #include "qfileinfo.h"
  15. // #include <dwmapi.h>
  16. // #include <psapi.h>
  17. // #include <shellapi.h>
  18. // #pragma comment(lib, "dwmapi.lib")
  19. // #pragma comment(lib, "shell32.lib")
  20. // #pragma comment(lib, "psapi.lib")
  21. // // ============================================================================
  22. // // ScreenWallWidget Implementation
  23. // // ============================================================================
  24. // ScreenWallWidget::ScreenWallWidget(QWidget* parent)
  25. // : QWidget(parent)
  26. // , m_mainLayout(nullptr)
  27. // , m_desktopPreview(nullptr)
  28. // , m_windowList(nullptr)
  29. // , m_windowPreview(nullptr)
  30. // , m_updateTimer(new QTimer(this))
  31. // , m_performanceTimer(new QTimer(this))
  32. // , m_isRunning(false)
  33. // , m_selectedWindow(nullptr)
  34. // , m_activeCaptureCount(0)
  35. // {
  36. // setupUI();
  37. // setupConnections();
  38. // // 设置默认配置
  39. // m_config = ScreenWallConfig();
  40. // setMinimumSize(800, 600);
  41. // resize(1200, 900);
  42. // }
  43. // ScreenWallWidget::~ScreenWallWidget()
  44. // {
  45. // stopScreenWall();
  46. // cleanupResources();
  47. // }
  48. // void ScreenWallWidget::setupUI()
  49. // {
  50. // m_mainLayout = new QVBoxLayout(this);
  51. // m_mainLayout->setContentsMargins(5, 5, 5, 5);
  52. // m_mainLayout->setSpacing(5);
  53. // // 桌面预览区域 (30%)
  54. // m_desktopPreview = new DesktopPreviewWidget(this);
  55. // m_desktopPreview->setMinimumHeight(200);
  56. // m_desktopPreview->setStyleSheet("border: 2px solid #3498db; border-radius: 5px;");
  57. // m_mainLayout->addWidget(m_desktopPreview, 3);
  58. // // 窗口图标列表 (20%)
  59. // m_windowList = new WindowIconListWidget(this);
  60. // m_windowList->setMaximumHeight(180);
  61. // m_windowList->setMinimumHeight(120);
  62. // m_windowList->setStyleSheet("border: 1px solid #bdc3c7; border-radius: 3px;");
  63. // m_mainLayout->addWidget(m_windowList, 2);
  64. // // 窗口预览区域 (50%)
  65. // m_windowPreview = new WindowPreviewWidget(this);
  66. // m_windowPreview->setMinimumHeight(300);
  67. // m_windowPreview->setStyleSheet("border: 2px solid #e74c3c; border-radius: 5px;");
  68. // m_mainLayout->addWidget(m_windowPreview, 5);
  69. // }
  70. // void ScreenWallWidget::setupConnections()
  71. // {
  72. // // 桌面预览点击
  73. // connect(m_desktopPreview, &DesktopPreviewWidget::clicked,
  74. // this, &ScreenWallWidget::onDesktopClicked);
  75. // // 窗口选择
  76. // connect(m_windowList, &WindowIconListWidget::windowSelected,
  77. // this, &ScreenWallWidget::onWindowSelected);
  78. // // 定时更新
  79. // connect(m_updateTimer, &QTimer::timeout,
  80. // this, &ScreenWallWidget::updatePreviews);
  81. // // 性能优化定时器
  82. // connect(m_performanceTimer, &QTimer::timeout,
  83. // this, &ScreenWallWidget::optimizePerformance);
  84. // }
  85. // void ScreenWallWidget::setConfig(const ScreenWallConfig& config)
  86. // {
  87. // m_config = config;
  88. // if (m_windowList) {
  89. // m_windowList->setThumbnailSize(config.thumbnailSize);
  90. // }
  91. // if (m_updateTimer) {
  92. // m_updateTimer->setInterval(config.updateInterval);
  93. // }
  94. // }
  95. // void ScreenWallWidget::startScreenWall()
  96. // {
  97. // if (m_isRunning) {
  98. // return;
  99. // }
  100. // qDebug() << "Starting ScreenWall...";
  101. // // 启动桌面预览
  102. // m_desktopPreview->startDesktopCapture(m_config.desktopFrameRate);
  103. // // 刷新窗口列表
  104. // refreshWindowList();
  105. // // 启动定时器
  106. // m_updateTimer->start(m_config.updateInterval);
  107. // m_performanceTimer->start(5000); // 每5秒优化一次性能
  108. // m_isRunning = true;
  109. // qDebug() << "ScreenWall started successfully";
  110. // }
  111. // void ScreenWallWidget::stopScreenWall()
  112. // {
  113. // if (!m_isRunning) {
  114. // return;
  115. // }
  116. // qDebug() << "Stopping ScreenWall...";
  117. // // 停止定时器
  118. // m_updateTimer->stop();
  119. // m_performanceTimer->stop();
  120. // // 停止预览
  121. // m_desktopPreview->stopDesktopCapture();
  122. // m_windowPreview->stopPreview();
  123. // // 清理资源
  124. // ResourceManager::instance().cleanup();
  125. // m_isRunning = false;
  126. // m_selectedWindow = nullptr;
  127. // qDebug() << "ScreenWall stopped";
  128. // }
  129. // void ScreenWallWidget::refreshWindowList()
  130. // {
  131. // if (m_windowList) {
  132. // m_windowList->refreshWindowList();
  133. // }
  134. // }
  135. // void ScreenWallWidget::onWindowSelected(HWND hwnd)
  136. // {
  137. // if (m_selectedWindow == hwnd) {
  138. // return;
  139. // }
  140. // // 停止之前的预览
  141. // if (m_selectedWindow) {
  142. // m_windowPreview->stopPreview();
  143. // ResourceManager::instance().removeCaptureSession(m_selectedWindow);
  144. // }
  145. // m_selectedWindow = hwnd;
  146. // if (hwnd && IsWindow(hwnd)) {
  147. // // 检查是否可以开始新的捕获
  148. // if (ResourceManager::instance().canStartCapture()) {
  149. // m_windowPreview->setTargetWindow(hwnd);
  150. // m_windowPreview->startPreview(m_config.windowFrameRate);
  151. // ResourceManager::instance().addCaptureSession(hwnd);
  152. // // 获取窗口标题
  153. // wchar_t title[256];
  154. // GetWindowTextW(hwnd, title, 256);
  155. // QString windowTitle = QString::fromWCharArray(title);
  156. // emit windowSelected(hwnd, windowTitle);
  157. // } else {
  158. // QMessageBox::warning(this, "资源限制",
  159. // "已达到最大同时捕获数量限制,请先关闭其他预览。");
  160. // }
  161. // }
  162. // }
  163. // void ScreenWallWidget::onDesktopClicked()
  164. // {
  165. // // 取消窗口选择,显示桌面
  166. // if (m_selectedWindow) {
  167. // m_windowPreview->stopPreview();
  168. // ResourceManager::instance().removeCaptureSession(m_selectedWindow);
  169. // m_selectedWindow = nullptr;
  170. // }
  171. // emit desktopSelected();
  172. // }
  173. // void ScreenWallWidget::updatePreviews()
  174. // {
  175. // // 刷新窗口列表
  176. // refreshWindowList();
  177. // // 检查选中窗口是否仍然有效
  178. // if (m_selectedWindow && !IsWindow(m_selectedWindow)) {
  179. // onWindowSelected(nullptr);
  180. // }
  181. // }
  182. // void ScreenWallWidget::optimizePerformance()
  183. // {
  184. // // 根据窗口状态调整帧率
  185. // if (m_selectedWindow && IsWindow(m_selectedWindow)) {
  186. // bool isMinimized = IsIconic(m_selectedWindow);
  187. // bool isVisible = IsWindowVisible(m_selectedWindow);
  188. // int frameRate = m_config.windowFrameRate;
  189. // if (isMinimized) {
  190. // frameRate = 1; // 最小化窗口使用极低帧率
  191. // } else if (!isVisible) {
  192. // frameRate = 5; // 不可见窗口使用低帧率
  193. // }
  194. // // 这里可以调整捕获帧率(需要在VideoRecorder中实现)
  195. // // m_windowPreview->setFrameRate(frameRate);
  196. // }
  197. // }
  198. // void ScreenWallWidget::resizeEvent(QResizeEvent* event)
  199. // {
  200. // QWidget::resizeEvent(event);
  201. // // 调整窗口列表布局
  202. // if (m_windowList) {
  203. // QTimer::singleShot(100, m_windowList, &WindowIconListWidget::refreshWindowList);
  204. // }
  205. // }
  206. // void ScreenWallWidget::showEvent(QShowEvent* event)
  207. // {
  208. // QWidget::showEvent(event);
  209. // if (!m_isRunning) {
  210. // QTimer::singleShot(500, this, &ScreenWallWidget::startScreenWall);
  211. // }
  212. // }
  213. // void ScreenWallWidget::hideEvent(QHideEvent* event)
  214. // {
  215. // QWidget::hideEvent(event);
  216. // if (m_isRunning) {
  217. // stopScreenWall();
  218. // }
  219. // }
  220. // void ScreenWallWidget::cleanupResources()
  221. // {
  222. // ResourceManager::instance().cleanup();
  223. // }
  224. // // ============================================================================
  225. // // DesktopPreviewWidget Implementation
  226. // // ============================================================================
  227. // DesktopPreviewWidget::DesktopPreviewWidget(QWidget* parent)
  228. // : OpenGLVideoWidget(parent)
  229. // , m_captureTimer(new QTimer(this))
  230. // , m_isCapturing(false)
  231. // , m_monitorIndex(0)
  232. // {
  233. // // connect(m_captureTimer, &QTimer::timeout,
  234. // // this, &DesktopPreviewWidget::captureDesktop);
  235. // // setNoVideoTip("点击开始桌面预览");
  236. // setCursor(Qt::PointingHandCursor);
  237. // }
  238. // DesktopPreviewWidget::~DesktopPreviewWidget()
  239. // {
  240. // stopDesktopCapture();
  241. // }
  242. // void DesktopPreviewWidget::startDesktopCapture(int frameRate)
  243. // {
  244. // if (m_isCapturing) {
  245. // return;
  246. // }
  247. // qDebug() << "Starting desktop capture at" << frameRate << "fps";
  248. // // 使用主显示器
  249. // Encoder<MediaType::VIDEO>::Param videoParam;
  250. // videoParam.width = GetSystemMetrics(SM_CXSCREEN);
  251. // videoParam.height = GetSystemMetrics(SM_CYSCREEN);
  252. // videoParam.fps = frameRate;
  253. // if (m_desktopRecorder.Open(m_monitorIndex, videoParam, CaptureMethod::WGC)) {
  254. // m_captureTimer->start(1000 / frameRate);
  255. // m_isCapturing = true;
  256. // setNoVideoTip("");
  257. // } else {
  258. // qWarning() << "Failed to start desktop capture";
  259. // setNoVideoTip("桌面捕获失败");
  260. // }
  261. // }
  262. // void ScreenWallWidget::onWindowStateChanged()
  263. // {
  264. // // 处理窗口状态变化
  265. // updatePreviews();
  266. // }
  267. // void DesktopPreviewWidget::stopDesktopCapture()
  268. // {
  269. // if (!m_isCapturing) {
  270. // return;
  271. // }
  272. // qDebug() << "Stopping desktop capture";
  273. // m_captureTimer->stop();
  274. // m_desktopRecorder.Close();
  275. // m_isCapturing = false;
  276. // setNoVideoTip("桌面预览已停止");
  277. // }
  278. // void DesktopPreviewWidget::captureDesktop()
  279. // {
  280. // if (!m_isCapturing) {
  281. // return;
  282. // }
  283. // AVFrame* frame = m_desktopRecorder.GetRenderFrame();
  284. // if (frame) {
  285. // // 异步渲染帧
  286. // QMetaObject::invokeMethod(this, "Render", Qt::QueuedConnection,
  287. // Q_ARG(AVFrame*, av_frame_clone(frame)));
  288. // }
  289. // }
  290. // void DesktopPreviewWidget::mousePressEvent(QMouseEvent* event)
  291. // {
  292. // if (event->button() == Qt::LeftButton) {
  293. // emit clicked();
  294. // }
  295. // OpenGLVideoWidget::mousePressEvent(event);
  296. // }
  297. // void DesktopPreviewWidget::paintEvent(QPaintEvent* event)
  298. // {
  299. // OpenGLVideoWidget::paintEvent(event);
  300. // // 绘制边框和状态信息
  301. // QPainter painter(this);
  302. // painter.setRenderHint(QPainter::Antialiasing);
  303. // if (m_isCapturing) {
  304. // // 绘制录制指示器
  305. // painter.setPen(QPen(Qt::red, 2));
  306. // painter.setBrush(Qt::red);
  307. // painter.drawEllipse(width() - 20, 10, 10, 10);
  308. // painter.setPen(Qt::white);
  309. // painter.drawText(width() - 60, 25, "LIVE");
  310. // }
  311. // }
  312. // // ============================================================================
  313. // // WindowIconListWidget Implementation
  314. // // ============================================================================
  315. // WindowIconListWidget::WindowIconListWidget(QWidget* parent)
  316. // : QScrollArea(parent)
  317. // , m_contentWidget(new QWidget)
  318. // , m_layout(new QGridLayout(m_contentWidget))
  319. // , m_thumbnailSize(120, 90)
  320. // , m_columnsCount(6)
  321. // {
  322. // setWidget(m_contentWidget);
  323. // setWidgetResizable(true);
  324. // setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
  325. // setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
  326. // m_layout->setSpacing(5);
  327. // m_layout->setContentsMargins(5, 5, 5, 5);
  328. // // 设置样式
  329. // setStyleSheet(
  330. // "QScrollArea { background-color: #f8f9fa; }"
  331. // "QWidget { background-color: transparent; }"
  332. // );
  333. // }
  334. // WindowIconListWidget::~WindowIconListWidget()
  335. // {
  336. // clearLayout();
  337. // }
  338. // void WindowIconListWidget::refreshWindowList()
  339. // {
  340. // qDebug() << "Refreshing window list...";
  341. // // 获取窗口列表
  342. // auto newWindows = EnhancedWindowFinder::GetExtendedList(true);
  343. // // 检查是否有变化
  344. // bool hasChanges = (newWindows.size() != m_windows.size());
  345. // if (!hasChanges) {
  346. // for (int i = 0; i < newWindows.size(); ++i) {
  347. // if (newWindows[i].hwnd != m_windows[i].hwnd) {
  348. // hasChanges = true;
  349. // break;
  350. // }
  351. // }
  352. // }
  353. // if (hasChanges) {
  354. // m_windows = newWindows;
  355. // updateLayout();
  356. // qDebug() << "Window list updated:" << m_windows.size() << "windows";
  357. // }
  358. // }
  359. // void WindowIconListWidget::setThumbnailSize(const QSize& size)
  360. // {
  361. // if (m_thumbnailSize != size) {
  362. // m_thumbnailSize = size;
  363. // updateLayout();
  364. // }
  365. // }
  366. // void WindowIconListWidget::updateLayout()
  367. // {
  368. // clearLayout();
  369. // if (m_windows.isEmpty()) {
  370. // return;
  371. // }
  372. // // 计算列数
  373. // int availableWidth = viewport()->width() - 20;
  374. // m_columnsCount = qMax(1, availableWidth / (m_thumbnailSize.width() + 10));
  375. // int row = 0, col = 0;
  376. // for (const auto& window : m_windows) {
  377. // auto* iconWidget = createWindowIcon(window);
  378. // if (iconWidget) {
  379. // m_layout->addWidget(iconWidget, row, col);
  380. // col++;
  381. // if (col >= m_columnsCount) {
  382. // col = 0;
  383. // row++;
  384. // }
  385. // }
  386. // }
  387. // // 添加弹性空间
  388. // m_layout->setRowStretch(row + 1, 1);
  389. // m_layout->setColumnStretch(m_columnsCount, 1);
  390. // }
  391. // QWidget* WindowIconListWidget::createWindowIcon(const WindowInfo& info)
  392. // {
  393. // auto* widget = new QWidget;
  394. // widget->setFixedSize(m_thumbnailSize + QSize(10, 30));
  395. // widget->setCursor(Qt::PointingHandCursor);
  396. // auto* layout = new QVBoxLayout(widget);
  397. // layout->setContentsMargins(2, 2, 2, 2);
  398. // layout->setSpacing(2);
  399. // // 缩略图
  400. // auto* thumbnailLabel = new QLabel;
  401. // thumbnailLabel->setFixedSize(m_thumbnailSize);
  402. // thumbnailLabel->setScaledContents(true);
  403. // thumbnailLabel->setStyleSheet(
  404. // "QLabel { "
  405. // " border: 1px solid #bdc3c7; "
  406. // " border-radius: 3px; "
  407. // " background-color: #ecf0f1; "
  408. // "}"
  409. // );
  410. // // 设置缩略图
  411. // if (!info.thumbnail.isNull()) {
  412. // thumbnailLabel->setPixmap(info.thumbnail.scaled(m_thumbnailSize, Qt::KeepAspectRatio, Qt::SmoothTransformation));
  413. // } else {
  414. // // 使用图标作为占位符
  415. // QPixmap iconPixmap = info.icon.pixmap(64, 64);
  416. // thumbnailLabel->setPixmap(iconPixmap);
  417. // }
  418. // layout->addWidget(thumbnailLabel);
  419. // // 标题
  420. // auto* titleLabel = new QLabel(info.title);
  421. // titleLabel->setAlignment(Qt::AlignCenter);
  422. // titleLabel->setWordWrap(true);
  423. // titleLabel->setMaximumHeight(20);
  424. // titleLabel->setStyleSheet("font-size: 10px; color: #2c3e50;");
  425. // // 截断过长的标题
  426. // QString displayTitle = info.title;
  427. // if (displayTitle.length() > 20) {
  428. // displayTitle = displayTitle.left(17) + "...";
  429. // }
  430. // titleLabel->setText(displayTitle);
  431. // titleLabel->setToolTip(info.title);
  432. // layout->addWidget(titleLabel);
  433. // // 存储窗口句柄
  434. // widget->setProperty("hwnd", reinterpret_cast<qintptr>(info.hwnd));
  435. // // 连接点击事件
  436. // widget->installEventFilter(this);
  437. // // 最小化窗口的视觉提示
  438. // if (info.isMinimized) {
  439. // widget->setStyleSheet("QWidget { opacity: 0.7; }");
  440. // }
  441. // return widget;
  442. // }
  443. // void WindowIconListWidget::clearLayout()
  444. // {
  445. // while (QLayoutItem* item = m_layout->takeAt(0)) {
  446. // if (QWidget* widget = item->widget()) {
  447. // widget->deleteLater();
  448. // }
  449. // delete item;
  450. // }
  451. // }
  452. // void WindowIconListWidget::resizeEvent(QResizeEvent* event)
  453. // {
  454. // QScrollArea::resizeEvent(event);
  455. // // 延迟更新布局,避免频繁重绘
  456. // QTimer::singleShot(100, this, &WindowIconListWidget::updateLayout);
  457. // }
  458. // bool WindowIconListWidget::eventFilter(QObject* obj, QEvent* event)
  459. // {
  460. // if (auto* widget = qobject_cast<QWidget*>(obj)) {
  461. // HWND hwnd = reinterpret_cast<HWND>(widget->property("hwnd").value<qintptr>());
  462. // if (event->type() == QEvent::MouseButtonPress) {
  463. // auto* mouseEvent = static_cast<QMouseEvent*>(event);
  464. // if (mouseEvent->button() == Qt::LeftButton) {
  465. // emit windowSelected(hwnd);
  466. // return true;
  467. // }
  468. // } else if (event->type() == QEvent::MouseButtonDblClick) {
  469. // emit windowDoubleClicked(hwnd);
  470. // return true;
  471. // }
  472. // }
  473. // return QScrollArea::eventFilter(obj, event);
  474. // }
  475. // // ============================================================================
  476. // // WindowPreviewWidget Implementation
  477. // // ============================================================================
  478. // WindowPreviewWidget::WindowPreviewWidget(QWidget* parent)
  479. // : OpenGLVideoWidget(parent)
  480. // , m_captureTimer(new QTimer(this))
  481. // , m_stateTimer(new QTimer(this))
  482. // , m_targetHwnd(nullptr)
  483. // , m_isPreviewActive(false)
  484. // , m_isWindowMinimized(false)
  485. // {
  486. // connect(m_captureTimer, &QTimer::timeout,
  487. // this, &WindowPreviewWidget::captureWindow);
  488. // connect(m_stateTimer, &QTimer::timeout,
  489. // this, &WindowPreviewWidget::checkWindowState);
  490. // setNoVideoTip("请选择要预览的窗口");
  491. // }
  492. // WindowPreviewWidget::~WindowPreviewWidget()
  493. // {
  494. // stopPreview();
  495. // }
  496. // void WindowPreviewWidget::setTargetWindow(HWND hwnd)
  497. // {
  498. // if (m_targetHwnd == hwnd) {
  499. // return;
  500. // }
  501. // stopPreview();
  502. // m_targetHwnd = hwnd;
  503. // if (hwnd && IsWindow(hwnd)) {
  504. // // 获取窗口标题
  505. // wchar_t title[256];
  506. // GetWindowTextW(hwnd, title, 256);
  507. // m_windowTitle = QString::fromWCharArray(title);
  508. // setNoVideoTip(QString("准备预览: %1").arg(m_windowTitle));
  509. // } else {
  510. // m_windowTitle.clear();
  511. // setNoVideoTip("请选择要预览的窗口");
  512. // }
  513. // }
  514. // void WindowPreviewWidget::startPreview(int frameRate)
  515. // {
  516. // if (!m_targetHwnd || !IsWindow(m_targetHwnd) || m_isPreviewActive) {
  517. // return;
  518. // }
  519. // qDebug() << "Starting window preview for" << m_windowTitle << "at" << frameRate << "fps";
  520. // // 配置视频参数
  521. // Encoder<MediaType::VIDEO>::Param videoParam;
  522. // RECT rect;
  523. // GetClientRect(m_targetHwnd, &rect);
  524. // videoParam.width = rect.right - rect.left;
  525. // videoParam.height = rect.bottom - rect.top;
  526. // videoParam.fps = frameRate;
  527. // if (videoParam.width <= 0 || videoParam.height <= 0) {
  528. // qWarning() << "Invalid window size for" << m_windowTitle;
  529. // setNoVideoTip("窗口尺寸无效");
  530. // return;
  531. // }
  532. // if (m_windowRecorder.Open(m_targetHwnd, videoParam, CaptureMethod::WGC)) {
  533. // m_captureTimer->start(1000 / frameRate);
  534. // m_stateTimer->start(1000); // 每秒检查窗口状态
  535. // m_isPreviewActive = true;
  536. // m_isWindowMinimized = IsIconic(m_targetHwnd);
  537. // setNoVideoTip("");
  538. // qDebug() << "Window preview started successfully";
  539. // } else {
  540. // qWarning() << "Failed to start window preview for" << m_windowTitle;
  541. // setNoVideoTip("预览启动失败");
  542. // }
  543. // }
  544. // void WindowPreviewWidget::stopPreview()
  545. // {
  546. // if (!m_isPreviewActive) {
  547. // return;
  548. // }
  549. // qDebug() << "Stopping window preview";
  550. // m_captureTimer->stop();
  551. // m_stateTimer->stop();
  552. // m_windowRecorder.Close();
  553. // m_isPreviewActive = false;
  554. // if (!m_windowTitle.isEmpty()) {
  555. // setNoVideoTip(QString("预览已停止: %1").arg(m_windowTitle));
  556. // } else {
  557. // setNoVideoTip("请选择要预览的窗口");
  558. // }
  559. // }
  560. // void WindowPreviewWidget::captureWindow()
  561. // {
  562. // if (!m_isPreviewActive || !m_targetHwnd || !IsWindow(m_targetHwnd)) {
  563. // return;
  564. // }
  565. // AVFrame* frame = m_windowRecorder.GetRenderFrame();
  566. // if (frame) {
  567. // // 如果窗口未最小化,保存最后一帧
  568. // if (!m_isWindowMinimized) {
  569. // // 这里可以将AVFrame转换为QPixmap保存
  570. // // m_lastFrame = convertAVFrameToPixmap(frame);
  571. // }
  572. // // 异步渲染帧
  573. // QMetaObject::invokeMethod(this, "Render", Qt::QueuedConnection,
  574. // Q_ARG(AVFrame*, av_frame_clone(frame)));
  575. // } else if (m_isWindowMinimized && !m_lastFrame.isNull()) {
  576. // // 显示最后一帧
  577. // handleMinimizedWindow();
  578. // }
  579. // }
  580. // void WindowPreviewWidget::checkWindowState()
  581. // {
  582. // if (!m_targetHwnd || !IsWindow(m_targetHwnd)) {
  583. // stopPreview();
  584. // return;
  585. // }
  586. // bool isMinimized = IsIconic(m_targetHwnd);
  587. // if (isMinimized != m_isWindowMinimized) {
  588. // m_isWindowMinimized = isMinimized;
  589. // if (isMinimized) {
  590. // handleMinimizedWindow();
  591. // } else {
  592. // handleRestoredWindow();
  593. // }
  594. // }
  595. // }
  596. // void WindowPreviewWidget::handleMinimizedWindow()
  597. // {
  598. // qDebug() << "Window minimized:" << m_windowTitle;
  599. // if (!m_lastFrame.isNull()) {
  600. // // 显示最后一帧的静态图像
  601. // // 这里需要实现将QPixmap显示在OpenGL组件上的功能
  602. // setNoVideoTip(QString("窗口已最小化: %1\n(显示最后画面)").arg(m_windowTitle));
  603. // } else {
  604. // setNoVideoTip(QString("窗口已最小化: %1").arg(m_windowTitle));
  605. // }
  606. // }
  607. // void WindowPreviewWidget::handleRestoredWindow()
  608. // {
  609. // qDebug() << "Window restored:" << m_windowTitle;
  610. // setNoVideoTip("");
  611. // }
  612. // void WindowPreviewWidget::setLastFrame(const QPixmap& frame)
  613. // {
  614. // m_lastFrame = frame;
  615. // }
  616. // void WindowPreviewWidget::paintEvent(QPaintEvent* event)
  617. // {
  618. // OpenGLVideoWidget::paintEvent(event);
  619. // // 绘制窗口信息
  620. // if (!m_windowTitle.isEmpty()) {
  621. // QPainter painter(this);
  622. // painter.setRenderHint(QPainter::Antialiasing);
  623. // // 绘制窗口标题
  624. // painter.setPen(Qt::white);
  625. // painter.drawText(10, height() - 10, m_windowTitle);
  626. // // 绘制状态指示器
  627. // if (m_isPreviewActive) {
  628. // painter.setPen(QPen(Qt::green, 2));
  629. // painter.setBrush(Qt::green);
  630. // painter.drawEllipse(width() - 20, 10, 10, 10);
  631. // }
  632. // if (m_isWindowMinimized) {
  633. // painter.setPen(Qt::yellow);
  634. // painter.drawText(width() - 100, 25, "MINIMIZED");
  635. // }
  636. // }
  637. // }
  638. // // ============================================================================
  639. // // EnhancedWindowFinder Implementation
  640. // // ============================================================================
  641. // QVector<EnhancedWindowFinder::ExtendedInfo> EnhancedWindowFinder::GetExtendedList(bool includeMinimized)
  642. // {
  643. // QVector<ExtendedInfo> result;
  644. // // 获取基本窗口列表
  645. // const auto& basicList = WindowFinder::GetList(true);
  646. // for (const auto& basic : basicList) {
  647. // if (!IsWindow(basic.hwnd)) {
  648. // continue;
  649. // }
  650. // bool isMinimized = IsWindowMinimized(basic.hwnd);
  651. // if (!includeMinimized && isMinimized) {
  652. // continue;
  653. // }
  654. // ExtendedInfo info;
  655. // info.hwnd = basic.hwnd;
  656. // info.title = "";
  657. // //basic.title;
  658. // info.isMinimized = isMinimized;
  659. // info.isVisible = IsWindowVisible(basic.hwnd);
  660. // info.rect = GetWindowRect(basic.hwnd);
  661. // info.processId = GetProcessId(basic.hwnd);
  662. // info.processName = GetProcessName(basic.hwnd);
  663. // info.icon = GetWindowIcon(basic.hwnd);
  664. // // 获取缩略图(可选,比较耗时)
  665. // if (!isMinimized && info.isVisible) {
  666. // info.thumbnail = ResourceManager::instance().getCachedThumbnail(basic.hwnd);
  667. // if (info.thumbnail.isNull()) {
  668. // info.thumbnail = GetWindowThumbnail(basic.hwnd);
  669. // if (!info.thumbnail.isNull()) {
  670. // ResourceManager::instance().cacheThumbnail(basic.hwnd, info.thumbnail);
  671. // }
  672. // }
  673. // }
  674. // result.append(info);
  675. // }
  676. // return result;
  677. // }
  678. // QIcon EnhancedWindowFinder::GetWindowIcon(HWND hwnd)
  679. // {
  680. // HICON hIcon = GetWindowIconHandle(hwnd);
  681. // if (hIcon) {
  682. // // Qt5兼容的HICON转换
  683. // QPixmap pixmap;
  684. // ICONINFO iconInfo;
  685. // if (GetIconInfo(hIcon, &iconInfo)) {
  686. // // 获取位图信息
  687. // BITMAP bmp;
  688. // if (GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bmp)) {
  689. // // 创建设备上下文
  690. // HDC hdc = CreateCompatibleDC(NULL);
  691. // if (hdc) {
  692. // // 准备位图信息头
  693. // BITMAPINFOHEADER bih = {0};
  694. // bih.biSize = sizeof(BITMAPINFOHEADER);
  695. // bih.biWidth = bmp.bmWidth;
  696. // bih.biHeight = -bmp.bmHeight;
  697. // bih.biPlanes = 1;
  698. // bih.biBitCount = 32;
  699. // bih.biCompression = BI_RGB;
  700. // // 分配内存
  701. // int dataSize = bmp.bmWidth * bmp.bmHeight * 4;
  702. // uchar* data = new uchar[dataSize];
  703. // // 获取位图数据
  704. // BITMAPINFO bi = {0};
  705. // bi.bmiHeader = bih;
  706. // if (GetDIBits(hdc, iconInfo.hbmColor, 0, bmp.bmHeight, data, &bi, DIB_RGB_COLORS)) {
  707. // // 创建QImage
  708. // QImage image(data, bmp.bmWidth, bmp.bmHeight, QImage::Format_ARGB32);
  709. // pixmap = QPixmap::fromImage(image.rgbSwapped());
  710. // }
  711. // delete[] data;
  712. // DeleteDC(hdc);
  713. // }
  714. // }
  715. // // 清理资源
  716. // if (iconInfo.hbmColor) DeleteObject(iconInfo.hbmColor);
  717. // if (iconInfo.hbmMask) DeleteObject(iconInfo.hbmMask);
  718. // }
  719. // DestroyIcon(hIcon);
  720. // if (!pixmap.isNull()) {
  721. // return QIcon(pixmap);
  722. // }
  723. // }
  724. // // 使用默认图标
  725. // return QApplication::style()->standardIcon(QStyle::SP_ComputerIcon);
  726. // }
  727. // HICON EnhancedWindowFinder::GetWindowIconHandle(HWND hwnd)
  728. // {
  729. // // 尝试多种方式获取图标
  730. // HICON hIcon = nullptr;
  731. // // 方法1: 发送消息获取大图标
  732. // hIcon = reinterpret_cast<HICON>(SendMessage(hwnd, WM_GETICON, ICON_BIG, 0));
  733. // if (hIcon) return hIcon;
  734. // // 方法2: 发送消息获取小图标
  735. // hIcon = reinterpret_cast<HICON>(SendMessage(hwnd, WM_GETICON, ICON_SMALL, 0));
  736. // if (hIcon) return hIcon;
  737. // // 方法3: 从窗口类获取图标
  738. // hIcon = reinterpret_cast<HICON>(GetClassLongPtr(hwnd, GCLP_HICON));
  739. // if (hIcon) return hIcon;
  740. // // 方法4: 从窗口类获取小图标
  741. // hIcon = reinterpret_cast<HICON>(GetClassLongPtr(hwnd, GCLP_HICONSM));
  742. // if (hIcon) return hIcon;
  743. // return nullptr;
  744. // }
  745. // QPixmap EnhancedWindowFinder::GetWindowThumbnail(HWND hwnd, const QSize& size)
  746. // {
  747. // return CaptureWindow(hwnd, size);
  748. // }
  749. // QPixmap EnhancedWindowFinder::CaptureWindow(HWND hwnd, const QSize& size)
  750. // {
  751. // if (!IsWindow(hwnd) || !IsWindowVisible(hwnd)) {
  752. // return QPixmap();
  753. // }
  754. // RECT rect;
  755. // ::GetWindowRect(hwnd, &rect);
  756. // int width = rect.right - rect.left;
  757. // int height = rect.bottom - rect.top;
  758. // if (width <= 0 || height <= 0) {
  759. // return QPixmap();
  760. // }
  761. // // 使用PrintWindow API捕获窗口
  762. // HDC hdcWindow = GetDC(hwnd);
  763. // HDC hdcMemDC = CreateCompatibleDC(hdcWindow);
  764. // HBITMAP hbmScreen = CreateCompatibleBitmap(hdcWindow, width, height);
  765. // SelectObject(hdcMemDC, hbmScreen);
  766. // // 尝试使用PrintWindow
  767. // BOOL result = PrintWindow(hwnd, hdcMemDC, PW_CLIENTONLY);
  768. // if (!result) {
  769. // // 如果PrintWindow失败,尝试BitBlt
  770. // BitBlt(hdcMemDC, 0, 0, width, height, hdcWindow, 0, 0, SRCCOPY);
  771. // }
  772. // // 转换为QPixmap (Qt5兼容)
  773. // QPixmap pixmap;
  774. // // 获取位图信息
  775. // BITMAP bmp;
  776. // if (GetObject(hbmScreen, sizeof(BITMAP), &bmp)) {
  777. // // 创建设备上下文
  778. // HDC hdc = CreateCompatibleDC(NULL);
  779. // if (hdc) {
  780. // // 准备位图信息头
  781. // BITMAPINFOHEADER bih = {0};
  782. // bih.biSize = sizeof(BITMAPINFOHEADER);
  783. // bih.biWidth = bmp.bmWidth;
  784. // bih.biHeight = -bmp.bmHeight; // 负值表示自上而下
  785. // bih.biPlanes = 1;
  786. // bih.biBitCount = 32;
  787. // bih.biCompression = BI_RGB;
  788. // // 分配内存
  789. // int dataSize = bmp.bmWidth * bmp.bmHeight * 4;
  790. // uchar* data = new uchar[dataSize];
  791. // // 获取位图数据
  792. // BITMAPINFO bi = {0};
  793. // bi.bmiHeader = bih;
  794. // if (GetDIBits(hdc, hbmScreen, 0, bmp.bmHeight, data, &bi, DIB_RGB_COLORS)) {
  795. // // 创建QImage
  796. // QImage image(data, bmp.bmWidth, bmp.bmHeight, QImage::Format_ARGB32);
  797. // pixmap = QPixmap::fromImage(image.rgbSwapped());
  798. // }
  799. // delete[] data;
  800. // DeleteDC(hdc);
  801. // }
  802. // }
  803. // // 清理资源
  804. // DeleteObject(hbmScreen);
  805. // DeleteDC(hdcMemDC);
  806. // ReleaseDC(hwnd, hdcWindow);
  807. // // 缩放到指定尺寸
  808. // if (!pixmap.isNull() && !size.isEmpty()) {
  809. // pixmap = pixmap.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
  810. // }
  811. // return pixmap;
  812. // }
  813. // bool EnhancedWindowFinder::IsWindowMinimized(HWND hwnd)
  814. // {
  815. // return IsIconic(hwnd);
  816. // }
  817. // QString EnhancedWindowFinder::GetProcessName(HWND hwnd)
  818. // {
  819. // DWORD processId = GetProcessId(hwnd);
  820. // HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId);
  821. // if (!hProcess) {
  822. // return QString();
  823. // }
  824. // wchar_t processName[MAX_PATH];
  825. // DWORD size = MAX_PATH;
  826. // if (QueryFullProcessImageNameW(hProcess, 0, processName, &size)) {
  827. // CloseHandle(hProcess);
  828. // QString fullPath = QString::fromWCharArray(processName);
  829. // return QFileInfo(fullPath).baseName();
  830. // }
  831. // CloseHandle(hProcess);
  832. // return QString();
  833. // }
  834. // DWORD EnhancedWindowFinder::GetProcessId(HWND hwnd)
  835. // {
  836. // DWORD processId = 0;
  837. // GetWindowThreadProcessId(hwnd, &processId);
  838. // return processId;
  839. // }
  840. // RECT EnhancedWindowFinder::GetWindowRect(HWND hwnd)
  841. // {
  842. // RECT rect = {0};
  843. // ::GetWindowRect(hwnd, &rect);
  844. // return rect;
  845. // }
  846. // // ============================================================================
  847. // // ResourceManager Implementation
  848. // // ============================================================================
  849. // ResourceManager& ResourceManager::instance()
  850. // {
  851. // static ResourceManager instance;
  852. // return instance;
  853. // }
  854. // bool ResourceManager::canStartCapture() const
  855. // {
  856. // return m_activeSessions.size() < MAX_CONCURRENT_CAPTURES;
  857. // }
  858. // void ResourceManager::addCaptureSession(HWND hwnd)
  859. // {
  860. // m_activeSessions.insert(hwnd);
  861. // }
  862. // void ResourceManager::removeCaptureSession(HWND hwnd)
  863. // {
  864. // m_activeSessions.remove(hwnd);
  865. // }
  866. // void ResourceManager::cacheThumbnail(HWND hwnd, const QPixmap& thumbnail)
  867. // {
  868. // m_thumbnailCache.insert(hwnd, new QPixmap(thumbnail));
  869. // }
  870. // QPixmap ResourceManager::getCachedThumbnail(HWND hwnd) const
  871. // {
  872. // QPixmap* cached = m_thumbnailCache.object(hwnd);
  873. // return cached ? *cached : QPixmap();
  874. // }
  875. // void ResourceManager::cleanup()
  876. // {
  877. // m_activeSessions.clear();
  878. // m_thumbnailCache.clear();
  879. // }