plyght's own C++ browser for macOS
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

up

plyght 431149c7 730820ea

+37 -22
+1 -1
CMakeLists.txt
··· 1 1 cmake_minimum_required(VERSION 3.24) 2 2 3 - project(pocb VERSION 0.1.0 LANGUAGES CXX OBJCXX) 3 + project(pocb VERSION 0.1.1 LANGUAGES CXX OBJCXX) 4 4 5 5 set(CMAKE_CXX_STANDARD 20) 6 6 set(CMAKE_CXX_STANDARD_REQUIRED ON)
+28
src/app/BrowserWindow.cpp
··· 151 151 if (m_tabTree->currentView() == view) m_tabTree->closeCurrent(); 152 152 } 153 153 154 + void BrowserWindow::extensionSetAction(const QString &key, const QString &label, std::function<void()> handler) { 155 + if (!m_topbar) return; 156 + QToolButton *button = m_extensionActionButtons.value(key, nullptr); 157 + if (!button) { 158 + button = new QToolButton(m_topbar); 159 + button->setAutoRaise(true); 160 + button->setFocusPolicy(Qt::NoFocus); 161 + button->setCursor(Qt::PointingHandCursor); 162 + button->setIconSize(QSize(16, 16)); 163 + button->setFixedSize(28, 28); 164 + button->setStyleSheet(QString( 165 + "QToolButton { background: transparent; border: none; border-radius: 6px; padding: 0px; color: %1; }" 166 + "QToolButton:hover { background: %2; }" 167 + "QToolButton:pressed { background: %3; }") 168 + .arg(m_theme.foreground.name(), m_theme.hover.name(), m_theme.raised.name())); 169 + if (auto *layout = qobject_cast<QHBoxLayout *>(m_topbar->layout())) { 170 + const int index = m_settingsBtn ? layout->indexOf(m_settingsBtn) : layout->count(); 171 + layout->insertWidget(qMax(0, index), button); 172 + } 173 + m_extensionActionButtons.insert(key, button); 174 + } 175 + button->setText(label.left(1).toUpper()); 176 + button->setToolTip(label); 177 + button->disconnect(); 178 + connect(button, &QToolButton::clicked, this, [handler = std::move(handler)] { handler(); }); 179 + button->show(); 180 + } 181 + 154 182 void BrowserWindow::loadFromOmnibox() { 155 183 if (auto *view = currentView()) view->load(urlFromInput(m_omnibox->text())); 156 184 }
+2
src/app/BrowserWindow.hpp
··· 39 39 WebView *extensionCreateTab(const QUrl &url, bool background); 40 40 void extensionSelectView(WebView *view); 41 41 void extensionCloseView(WebView *view); 42 + void extensionSetAction(const QString &key, const QString &label, std::function<void()> handler); 42 43 43 44 protected: 44 45 void showEvent(QShowEvent *e) override; ··· 78 79 QToolButton *m_reloadBtn = nullptr; 79 80 QToolButton *m_settingsBtn = nullptr; 80 81 QToolButton *m_newTabBtn = nullptr; 82 + QHash<QString, QToolButton *> m_extensionActionButtons; 81 83 QLineEdit *m_addressBar = nullptr; 82 84 QLabel *m_lockIcon = nullptr; 83 85 QLabel *m_searchIcon = nullptr;
-5
src/mac/MacIntegration.hpp
··· 61 61 // the text field that spawned them. 62 62 void preventWindowActivation(QWidget *window); 63 63 64 - // Ask AppKit to keep the mouse pointer visible after typing. This counters 65 - // macOS hiding the pointer while a non-activating suggestion popup is being 66 - // repositioned under a focused text field. 67 - void keepMouseCursorVisible(); 68 - 69 64 // Make the NSWindow's titlebar transparent and hide its title text, so the 70 65 // behind-window vibrancy reads through the titlebar area as well. The 71 66 // content view is expanded to full size so Qt widgets can paint into the
+1 -7
src/mac/Vibrancy.mm
··· 104 104 nsw.level = NSFloatingWindowLevel; 105 105 nsw.collectionBehavior |= NSWindowCollectionBehaviorFullScreenAuxiliary; 106 106 nsw.ignoresMouseEvents = NO; 107 + [nsw setCanHide:NO]; 107 108 #else 108 109 (void)window; 109 - #endif 110 - } 111 - 112 - void keepMouseCursorVisible() { 113 - #ifdef __APPLE__ 114 - [NSCursor setHiddenUntilMouseMoves:NO]; 115 - #else 116 110 #endif 117 111 } 118 112
+5
src/services/ChromeExtensionManager.cpp
··· 16 16 #import <WebKit/WKWebExtensionContext.h> 17 17 #import <WebKit/WKWebExtensionController.h> 18 18 #import <WebKit/WKWebExtensionControllerConfiguration.h> 19 + #import <WebKit/WKWebExtensionAction.h> 19 20 #import <WebKit/WKWebExtensionMatchPattern.h> 20 21 #import <WebKit/WKWebExtensionTab.h> 21 22 #import <WebKit/WKWebExtensionTabConfiguration.h> ··· 63 64 - (NSArray<id<WKWebExtensionWindow>> *)webExtensionController:(WKWebExtensionController *)controller openWindowsForExtensionContext:(WKWebExtensionContext *)extensionContext { (void)controller; (void)extensionContext; return g_browserWindow ? @[ [PocbExtensionWindow new] ] : @[]; } 64 65 - (id<WKWebExtensionWindow>)webExtensionController:(WKWebExtensionController *)controller focusedWindowForExtensionContext:(WKWebExtensionContext *)extensionContext { (void)controller; (void)extensionContext; return g_browserWindow ? [PocbExtensionWindow new] : nil; } 65 66 - (void)webExtensionController:(WKWebExtensionController *)controller openNewTabUsingConfiguration:(WKWebExtensionTabConfiguration *)configuration forExtensionContext:(WKWebExtensionContext *)extensionContext completionHandler:(void (^)(id<WKWebExtensionTab>, NSError *))completionHandler { (void)controller; (void)extensionContext; NSURL *url = [configuration respondsToSelector:@selector(URL)] ? [configuration valueForKey:@"URL"] : nil; WebView *view = g_browserWindow ? g_browserWindow->extensionCreateTab(url ? QUrl(QString::fromNSString(url.absoluteString)) : QUrl(), false) : nullptr; if (!view) { completionHandler(nil, [NSError errorWithDomain:@"pocb.extensions" code:1 userInfo:@{NSLocalizedDescriptionKey:@"No browser window is available"}]); return; } PocbExtensionTab *tab = [PocbExtensionTab new]; tab.view = view; completionHandler(tab, nil); } 67 + - (void)webExtensionController:(WKWebExtensionController *)controller openNewWindowUsingConfiguration:(WKWebExtensionWindowConfiguration *)configuration forExtensionContext:(WKWebExtensionContext *)extensionContext completionHandler:(void (^)(id<WKWebExtensionWindow>, NSError *))completionHandler { (void)controller; (void)configuration; (void)extensionContext; if (!g_browserWindow) { completionHandler(nil, [NSError errorWithDomain:@"pocb.extensions" code:2 userInfo:@{NSLocalizedDescriptionKey:@"No browser window is available"}]); return; } g_browserWindow->extensionCreateTab(QUrl(), false); completionHandler([PocbExtensionWindow new], nil); } 68 + - (void)webExtensionController:(WKWebExtensionController *)controller openOptionsPageForExtensionContext:(WKWebExtensionContext *)extensionContext completionHandler:(void (^)(NSError *))completionHandler { (void)controller; if (!g_browserWindow || !extensionContext.optionsPageURL) { completionHandler([NSError errorWithDomain:@"pocb.extensions" code:3 userInfo:@{NSLocalizedDescriptionKey:@"No options page is available"}]); return; } g_browserWindow->extensionCreateTab(QUrl(QString::fromNSString(extensionContext.optionsPageURL.absoluteString)), false); completionHandler(nil); } 69 + - (void)webExtensionController:(WKWebExtensionController *)controller didUpdateAction:(WKWebExtensionAction *)action forExtensionContext:(WKWebExtensionContext *)context { (void)controller; if (!g_browserWindow) return; QString key = QString::fromNSString(context.webExtension.displayName ?: context.webExtension.version ?: @"extension"); QString label = QString::fromNSString(action.label.length ? action.label : (context.webExtension.displayName ?: @"Extension")); g_browserWindow->extensionSetAction(key, label, [action] { if (action.presentsPopup && action.popupPopover) { NSWindow *window = g_browserWindow ? (__bridge NSWindow *)reinterpret_cast<void *>(g_browserWindow->winId()) : nil; NSView *view = window.contentView; [action.popupPopover showRelativeToRect:NSMakeRect(NSMidX(view.bounds), NSMaxY(view.bounds) - 44, 1, 1) ofView:view preferredEdge:NSMinYEdge]; } }); } 70 + - (void)webExtensionController:(WKWebExtensionController *)controller presentPopupForAction:(WKWebExtensionAction *)action forExtensionContext:(WKWebExtensionContext *)context completionHandler:(void (^)(NSError *))completionHandler { (void)controller; (void)context; if (!g_browserWindow || !action.presentsPopup || !action.popupPopover) { completionHandler([NSError errorWithDomain:@"pocb.extensions" code:4 userInfo:@{NSLocalizedDescriptionKey:@"No popup is available"}]); return; } NSWindow *window = (__bridge NSWindow *)reinterpret_cast<void *>(g_browserWindow->winId()); NSView *view = window.contentView; [action.popupPopover showRelativeToRect:NSMakeRect(NSMidX(view.bounds), NSMaxY(view.bounds) - 44, 1, 1) ofView:view preferredEdge:NSMinYEdge]; completionHandler(nil); } 66 71 - (void)webExtensionController:(WKWebExtensionController *)controller promptForPermissions:(NSSet<WKWebExtensionPermission> *)permissions inTab:(id<WKWebExtensionTab>)tab forExtensionContext:(WKWebExtensionContext *)extensionContext completionHandler:(void (^)(NSSet<WKWebExtensionPermission> *, NSDate *))completionHandler { (void)controller; (void)tab; (void)extensionContext; completionHandler(permissions, [NSDate distantFuture]); } 67 72 - (void)webExtensionController:(WKWebExtensionController *)controller promptForPermissionToAccessURLs:(NSSet<NSURL *> *)urls inTab:(id<WKWebExtensionTab>)tab forExtensionContext:(WKWebExtensionContext *)extensionContext completionHandler:(void (^)(NSSet<NSURL *> *, NSDate *))completionHandler { (void)controller; (void)tab; (void)extensionContext; completionHandler(urls, [NSDate distantFuture]); } 68 73 - (void)webExtensionController:(WKWebExtensionController *)controller promptForPermissionMatchPatterns:(NSSet<WKWebExtensionMatchPattern *> *)matchPatterns inTab:(id<WKWebExtensionTab>)tab forExtensionContext:(WKWebExtensionContext *)extensionContext completionHandler:(void (^)(NSSet<WKWebExtensionMatchPattern *> *, NSDate *))completionHandler { (void)controller; (void)tab; (void)extensionContext; completionHandler(matchPatterns, [NSDate distantFuture]); }
-9
src/ui/AddressBarController.cpp
··· 120 120 m_pendingQuery = t.trimmed(); 121 121 m_statusText.clear(); 122 122 if (m_pendingQuery.isEmpty()) { hidePopup(); return; } 123 - mac::keepMouseCursorVisible(); 124 123 m_debounce->start(); 125 124 }); 126 125 connect(m_bar, &QLineEdit::returnPressed, this, &AddressBarController::commit); ··· 565 564 566 565 void AddressBarController::showPopup() { 567 566 if (!m_popup) return; 568 - mac::keepMouseCursorVisible(); 569 567 positionPopup(); 570 - if (m_bar && !m_bar->hasFocus()) m_bar->setFocus(Qt::OtherFocusReason); 571 568 if (!m_popup->isVisible()) m_popup->show(); 572 569 mac::makeFloatingVibrantPanel(m_popup, mac::VibrancyMaterial::Popover, 12.0); 573 570 mac::preventWindowActivation(m_popup); ··· 579 576 m_popupList->viewport()->raise(); 580 577 } 581 578 m_popup->raise(); 582 - if (m_bar) { 583 - m_bar->activateWindow(); 584 - m_bar->setFocus(Qt::OtherFocusReason); 585 - m_bar->update(); 586 - } 587 - mac::keepMouseCursorVisible(); 588 579 } 589 580 590 581 void AddressBarController::hidePopup() {