feat(stacked-panes): add click-to-activate on title bars
- Add WidgetAttachClickHandler helper function for GTK4 gesture clicks - Wire up click handlers to stacked pane title bars - Clicking on a collapsed title bar now activates that pane - Uses existing handleTitleBarClick logic for pane switching
- commit
- 524e65ebfd8c277c99eeb1b92efa8658689c9431
- author
- bnema · · 2025-11-16 22:35 UTC
- committer
- bnema · · 2025-11-16 19:55 UTC
- parent
- 6d403db
- signature
- unsigned
2 files · +34 -10
M internal/app/browser/stacked_panes.go +16 -10
| @@ -541,10 +541,9 @@ func (spm *StackedPaneManager) createTitleBar(pane *paneNode) gtk.Widgetter { | |||
| 541 | 541 | spm.titleBarToPane[titleBarID] = pane | |
| 542 | 542 | ||
| 543 | 543 | // Attach click handler | |
| 544 | - | // TODO: Implement click handler with gtk.GestureClick | |
| 545 | - | // webkit.WidgetAttachClickHandler(titleBar, func() { | |
| 546 | - | // spm.handleTitleBarClick(titleBarID) | |
| 547 | - | // }) | |
| 544 | + | webkit.WidgetAttachClickHandler(titleBar, func() { | |
| 545 | + | spm.handleTitleBarClick(titleBarID) | |
| 546 | + | }) | |
| 548 | 547 | } | |
| 549 | 548 | ||
| 550 | 549 | return titleBar | |
| @@ -613,10 +612,9 @@ func (spm *StackedPaneManager) updateTitleBarLabel(node *paneNode, title string) | |||
| 613 | 612 | spm.titleBarToPane[titleBarID] = node | |
| 614 | 613 | ||
| 615 | 614 | // Attach click handler | |
| 616 | - | // TODO: Implement with gtk.GestureClick | |
| 617 | - | // webkit.WidgetAttachClickHandler(newTitleBar, func() { | |
| 618 | - | // spm.handleTitleBarClick(titleBarID) | |
| 619 | - | // }) | |
| 615 | + | webkit.WidgetAttachClickHandler(newTitleBar, func() { | |
| 616 | + | spm.handleTitleBarClick(titleBarID) | |
| 617 | + | }) | |
| 620 | 618 | ||
| 621 | 619 | // Replace the old title bar in the stack | |
| 622 | 620 | if node.parent != nil && node.parent.isStacked && node.parent.stackWrapper != nil { | |
| @@ -682,9 +680,17 @@ func (spm *StackedPaneManager) createTitleBarWithTitle(title string, pageURL str | |||
| 682 | 680 | ||
| 683 | 681 | if texture != nil && titleBox != nil { | |
| 684 | 682 | ||
| 685 | - | // Create favicon image | |
| 683 | + | // Create favicon image with UI scaling | |
| 686 | 684 | faviconImg := gtk.NewImageFromPaintable(texture) | |
| 687 | - | faviconImg.SetPixelSize(16) | |
| 685 | + | // Scale favicon size based on UI scale (base: 16px) | |
| 686 | + | faviconSize := 16 | |
| 687 | + | if spm.wm != nil && spm.wm.app != nil && spm.wm.app.config != nil { | |
| 688 | + | uiScale := spm.wm.app.config.Workspace.Styling.UIScale | |
| 689 | + | if uiScale > 0 { | |
| 690 | + | faviconSize = int(16 * uiScale) | |
| 691 | + | } | |
| 692 | + | } | |
| 693 | + | faviconImg.SetPixelSize(faviconSize) | |
| 688 | 694 | webkit.WidgetAddCSSClass(faviconImg, "stacked-pane-favicon") | |
| 689 | 695 | ||
| 690 | 696 | // IDEMPOTENT: Remove placeholder only if it still has titleBox as parent | |
| @@ -541,10 +541,9 @@ func (spm *StackedPaneManager) createTitleBar(pane *paneNode) gtk.Widgetter { | |||||
| 541 | spm.titleBarToPane[titleBarID] = pane | 541 | spm.titleBarToPane[titleBarID] = pane | ||
| 542 | 542 | ||||
| 543 | // Attach click handler | 543 | // Attach click handler | ||
| 544 | - | // TODO: Implement click handler with gtk.GestureClick | 544 | + | webkit.WidgetAttachClickHandler(titleBar, func() { |
| 545 | - | // webkit.WidgetAttachClickHandler(titleBar, func() { | 545 | + | spm.handleTitleBarClick(titleBarID) |
| 546 | - | // spm.handleTitleBarClick(titleBarID) | 546 | + | }) |
| 547 | - | // }) | |||
| 548 | } | 547 | } | ||
| 549 | 548 | ||||
| 550 | return titleBar | 549 | return titleBar | ||
| @@ -613,10 +612,9 @@ func (spm *StackedPaneManager) updateTitleBarLabel(node *paneNode, title string) | |||||
| 613 | spm.titleBarToPane[titleBarID] = node | 612 | spm.titleBarToPane[titleBarID] = node | ||
| 614 | 613 | ||||
| 615 | // Attach click handler | 614 | // Attach click handler | ||
| 616 | - | // TODO: Implement with gtk.GestureClick | 615 | + | webkit.WidgetAttachClickHandler(newTitleBar, func() { |
| 617 | - | // webkit.WidgetAttachClickHandler(newTitleBar, func() { | 616 | + | spm.handleTitleBarClick(titleBarID) |
| 618 | - | // spm.handleTitleBarClick(titleBarID) | 617 | + | }) |
| 619 | - | // }) | |||
| 620 | 618 | ||||
| 621 | // Replace the old title bar in the stack | 619 | // Replace the old title bar in the stack | ||
| 622 | if node.parent != nil && node.parent.isStacked && node.parent.stackWrapper != nil { | 620 | if node.parent != nil && node.parent.isStacked && node.parent.stackWrapper != nil { | ||
| @@ -682,9 +680,17 @@ func (spm *StackedPaneManager) createTitleBarWithTitle(title string, pageURL str | |||||
| 682 | 680 | ||||
| 683 | if texture != nil && titleBox != nil { | 681 | if texture != nil && titleBox != nil { | ||
| 684 | 682 | ||||
| 685 | - | // Create favicon image | 683 | + | // Create favicon image with UI scaling |
| 686 | faviconImg := gtk.NewImageFromPaintable(texture) | 684 | faviconImg := gtk.NewImageFromPaintable(texture) | ||
| 687 | - | faviconImg.SetPixelSize(16) | 685 | + | // Scale favicon size based on UI scale (base: 16px) |
| 686 | + | faviconSize := 16 | |||
| 687 | + | if spm.wm != nil && spm.wm.app != nil && spm.wm.app.config != nil { | |||
| 688 | + | uiScale := spm.wm.app.config.Workspace.Styling.UIScale | |||
| 689 | + | if uiScale > 0 { | |||
| 690 | + | faviconSize = int(16 * uiScale) | |||
| 691 | + | } | |||
| 692 | + | } | |||
| 693 | + | faviconImg.SetPixelSize(faviconSize) | |||
| 688 | webkit.WidgetAddCSSClass(faviconImg, "stacked-pane-favicon") | 694 | webkit.WidgetAddCSSClass(faviconImg, "stacked-pane-favicon") | ||
| 689 | 695 | ||||
| 690 | // IDEMPOTENT: Remove placeholder only if it still has titleBox as parent | 696 | // IDEMPOTENT: Remove placeholder only if it still has titleBox as parent | ||
M pkg/webkit/helpers.go +18 -0
| @@ -250,6 +250,24 @@ func WidgetAddController(w gtk.Widgetter, controller gtk.EventControllerer) { | |||
| 250 | 250 | } | |
| 251 | 251 | } | |
| 252 | 252 | ||
| 253 | + | // WidgetAttachClickHandler attaches a left-click handler to a widget | |
| 254 | + | func WidgetAttachClickHandler(w gtk.Widgetter, callback func()) *gtk.GestureClick { | |
| 255 | + | widget := getWidget(w) | |
| 256 | + | if widget == nil { | |
| 257 | + | return nil | |
| 258 | + | } | |
| 259 | + | ||
| 260 | + | gestureClick := gtk.NewGestureClick() | |
| 261 | + | gestureClick.SetButton(1) // Left click only | |
| 262 | + | ||
| 263 | + | gestureClick.ConnectPressed(func(nPress int, x, y float64) { | |
| 264 | + | callback() | |
| 265 | + | }) | |
| 266 | + | ||
| 267 | + | widget.AddController(gestureClick) | |
| 268 | + | return gestureClick | |
| 269 | + | } | |
| 270 | + | ||
| 253 | 271 | // WidgetAllocation returns the widget's allocation (alias for WidgetGetAllocation) | |
| 254 | 272 | func WidgetAllocation(w gtk.Widgetter) (x, y, width, height int) { | |
| 255 | 273 | return WidgetGetAllocation(w) | |
| @@ -250,6 +250,24 @@ func WidgetAddController(w gtk.Widgetter, controller gtk.EventControllerer) { | |||||
| 250 | } | 250 | } | ||
| 251 | } | 251 | } | ||
| 252 | 252 | ||||
| 253 | + | // WidgetAttachClickHandler attaches a left-click handler to a widget | |||
| 254 | + | func WidgetAttachClickHandler(w gtk.Widgetter, callback func()) *gtk.GestureClick { | |||
| 255 | + | widget := getWidget(w) | |||
| 256 | + | if widget == nil { | |||
| 257 | + | return nil | |||
| 258 | + | } | |||
| 259 | + | ||||
| 260 | + | gestureClick := gtk.NewGestureClick() | |||
| 261 | + | gestureClick.SetButton(1) // Left click only | |||
| 262 | + | ||||
| 263 | + | gestureClick.ConnectPressed(func(nPress int, x, y float64) { | |||
| 264 | + | callback() | |||
| 265 | + | }) | |||
| 266 | + | ||||
| 267 | + | widget.AddController(gestureClick) | |||
| 268 | + | return gestureClick | |||
| 269 | + | } | |||
| 270 | + | ||||
| 253 | // WidgetAllocation returns the widget's allocation (alias for WidgetGetAllocation) | 271 | // WidgetAllocation returns the widget's allocation (alias for WidgetGetAllocation) | ||
| 254 | func WidgetAllocation(w gtk.Widgetter) (x, y, width, height int) { | 272 | func WidgetAllocation(w gtk.Widgetter) (x, y, width, height int) { | ||
| 255 | return WidgetGetAllocation(w) | 273 | return WidgetGetAllocation(w) | ||