Skip to content

Commit 06107b2

Browse files
committed
WIP
1 parent 55b28f7 commit 06107b2

3 files changed

Lines changed: 134 additions & 18 deletions

File tree

src/tabbookmark.cc

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -340,24 +340,10 @@ bool HandleKeepTab(WPARAM wParam) {
340340
return false;
341341
}
342342

343-
HWND hwnd = GetFocus();
344-
if (GetChromeWidgetWin(hwnd) == nullptr) {
345-
return false;
346-
}
347-
348-
if (IsFullScreen(hwnd)) {
349-
// Have to exit full screen to find the tab.
350-
ExecuteCommand(IDC_FULLSCREEN, hwnd);
351-
}
352-
353-
HWND tmp_hwnd = hwnd;
354-
hwnd = GetAncestor(tmp_hwnd, GA_ROOTOWNER);
355-
ExecuteCommand(IDC_CLOSE_FIND_OR_STOP, tmp_hwnd);
356-
357-
NodePtr top_container_view = GetTopContainerView(hwnd);
358-
// Use `GetTabCount` directly since we only need tab count here (no mouse pos)
359-
int tab_count = GetTabCount(top_container_view);
360-
if (!IsNeedKeep(tab_count, KeepTabTrigger::kKeyboardShortcut)) {
343+
HWND hwnd = GetForegroundWindow();
344+
const auto tab_count = FindTabCount(hwnd);
345+
if (tab_count.has_value() &&
346+
!IsNeedKeep(tab_count.value(), KeepTabTrigger::kKeyboardShortcut)) {
361347
return false;
362348
}
363349

src/uia.cc

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <initializer_list>
88
#include <optional>
99
#include <string_view>
10+
#include <vector>
1011

1112
#include "utils.h"
1213

@@ -208,6 +209,103 @@ ComPtr<IUIAutomationElement> FindFirstInSubtree(
208209
return hit;
209210
}
210211

212+
ComPtr<IUIAutomationElement> FindFirstInSubtreeRaw(
213+
const ComPtr<IUIAutomation>& automation,
214+
const ComPtr<IUIAutomationElement>& root,
215+
std::wstring_view class_name) {
216+
ComPtr<IUIAutomationTreeWalker> walker;
217+
if (FAILED(automation->get_RawViewWalker(&walker)) || !walker) {
218+
return nullptr;
219+
}
220+
221+
std::vector<ComPtr<IUIAutomationElement>> stack = {root};
222+
while (!stack.empty()) {
223+
auto node = std::move(stack.back());
224+
stack.pop_back();
225+
if (IsClassName(node, class_name)) {
226+
return node;
227+
}
228+
ComPtr<IUIAutomationElement> child;
229+
if (FAILED(walker->GetFirstChildElement(node.Get(),
230+
child.ReleaseAndGetAddressOf()))) {
231+
continue;
232+
}
233+
while (child) {
234+
stack.push_back(child);
235+
ComPtr<IUIAutomationElement> next;
236+
if (FAILED(walker->GetNextSiblingElement(
237+
child.Get(), next.ReleaseAndGetAddressOf()))) {
238+
break;
239+
}
240+
child = std::move(next);
241+
}
242+
}
243+
return nullptr;
244+
}
245+
246+
std::optional<int> CountClassInSubtreeRaw(
247+
const ComPtr<IUIAutomation>& automation,
248+
const ComPtr<IUIAutomationElement>& root,
249+
std::wstring_view class_name) {
250+
ComPtr<IUIAutomationTreeWalker> walker;
251+
if (FAILED(automation->get_RawViewWalker(&walker)) || !walker) {
252+
return std::nullopt;
253+
}
254+
255+
int count = 0;
256+
std::vector<ComPtr<IUIAutomationElement>> stack = {root};
257+
while (!stack.empty()) {
258+
auto node = std::move(stack.back());
259+
stack.pop_back();
260+
if (IsClassName(node, class_name)) {
261+
++count;
262+
}
263+
ComPtr<IUIAutomationElement> child;
264+
if (FAILED(walker->GetFirstChildElement(node.Get(),
265+
child.ReleaseAndGetAddressOf()))) {
266+
continue;
267+
}
268+
while (child) {
269+
stack.push_back(child);
270+
ComPtr<IUIAutomationElement> next;
271+
if (FAILED(walker->GetNextSiblingElement(
272+
child.Get(), next.ReleaseAndGetAddressOf()))) {
273+
break;
274+
}
275+
child = std::move(next);
276+
}
277+
}
278+
return count;
279+
}
280+
281+
std::optional<TabContainer> FindTabContainerFromHwnd(
282+
const ComPtr<IUIAutomation>& automation,
283+
HWND hwnd) {
284+
auto root = GetElementFromHandle(automation, hwnd);
285+
if (!root) {
286+
return std::nullopt;
287+
}
288+
289+
if (auto c = FindFirstInSubtree(
290+
root, CreateClassCondition(automation, L"TabContainerImpl")))
291+
return TabContainer{c, L"Tab"};
292+
if (auto c = FindFirstInSubtree(
293+
root, CreateClassCondition(automation,
294+
L"VerticalUnpinnedTabContainerView"))) {
295+
return TabContainer{c, L"VerticalTabView"};
296+
}
297+
298+
if (auto c = FindFirstInSubtreeRaw(automation, root, L"TabContainerImpl")) {
299+
return TabContainer{c, L"Tab"};
300+
}
301+
if (auto c = FindFirstInSubtreeRaw(automation, root,
302+
L"VerticalUnpinnedTabContainerView")) {
303+
return TabContainer{c, L"VerticalTabView"};
304+
}
305+
306+
return std::nullopt;
307+
}
308+
211309
ComPtr<IUIAutomationElement> FindSiblingByClass(
212310
const ComPtr<IUIAutomation>& automation,
213311
const ComPtr<IUIAutomationElement>& element,
@@ -400,6 +498,37 @@ std::optional<TabHitResult> FindTabHitResult(POINT pt,
400498
return std::nullopt;
401499
}
402500

501+
std::optional<int> FindTabCount(HWND hwnd) {
502+
if (!EnsureAutomation()) {
503+
return std::nullopt;
504+
}
505+
const auto& automation = GetUiaThreadState().automation;
506+
507+
const auto tab_container = FindTabContainerFromHwnd(automation, hwnd);
508+
if (!tab_container) {
509+
return std::nullopt;
510+
}
511+
512+
const auto condition =
513+
CreateClassCondition(automation, tab_container->tab_class);
514+
if (!condition) {
515+
return std::nullopt;
516+
}
517+
518+
ComPtr<IUIAutomationElementArray> arr;
519+
if (SUCCEEDED(tab_container->container->FindAll(
520+
TreeScope_Children, condition.Get(), arr.ReleaseAndGetAddressOf())) &&
521+
arr) {
522+
int count = 0;
523+
if (SUCCEEDED(arr->get_Length(&count)) && count > 0) {
524+
return count;
525+
}
526+
}
527+
// Fullscreen
528+
return CountClassInSubtreeRaw(automation, tab_container->container,
529+
tab_container->tab_class);
530+
}
531+
403532
bool IsOnTabBar(POINT pt) {
404533
if (!EnsureAutomation()) {
405534
return false;

src/uia.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ struct TabHitResult {
1515
std::optional<TabHitResult> FindTabHitResult(POINT pt,
1616
bool need_count,
1717
bool need_close_button);
18+
std::optional<int> FindTabCount(HWND hwnd);
1819
bool IsOnTabBar(POINT pt);
1920
bool IsOnBookmark(POINT pt);
2021
bool IsOmniboxFocused();

0 commit comments

Comments
 (0)