Subject: [PATCH v3 2/2] gitk: make Tags and Heads window geometry sticky

From: Michael Rappazzo <[email-masked]>
Date: Sun, 28 Sep 2025 09:54:35 -0400

Currently, the Tags and Heads window always opens at a default position
and size, requiring users to reposition it each time. This patch makes
the window remember its geometry between sessions.

This change saves and restores the Tags and Heads window size and position
relative to the main gitk window. The geometry is stored in the config file
as `geometry(showrefs)` and persists between gitk sessions. The window
position is stored relative to the main window, so it maintains the same
spatial relationship when the main window is moved or when gitk is restarted
on different monitors.

Signed-off-by: Michael Rappazzo <[email-masked]>
---
 gitk | 39 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/gitk b/gitk
index 275f353811..79a6dcdb4c 100755
--- a/gitk
+++ b/gitk
@@ -3106,6 +3106,11 @@ proc savestuff {w} {
         puts $f "set geometry(pwsash1) \"[.tf.histframe.pwclist sashpos 1] 1\""
         puts $f "set geometry(botwidth) [winfo width .bleft]"
         puts $f "set geometry(botheight) [winfo height .bleft]"
+        if {[winfo exists .showrefs]} {
+            puts $f "set geometry(showrefs) \"[wm geometry .showrefs]\""
+        } elseif {[info exists geometry(showrefs)]} {
+            puts $f "set geometry(showrefs) \"$geometry(showrefs)\""
+        }
 
         array set view_save {}
         array set views {}
@@ -10199,11 +10204,13 @@ proc showrefs {} {
     if {[winfo exists $top]} {
         raise $top
         refill_reflist
+        wm protocol $top WM_DELETE_WINDOW [list destroy_showrefs $top]
         return
     }
     ttk_toplevel $top
     wm title $top [mc "Tags and heads: %s" [file tail [pwd]]]
     make_transient $top .
+    wm protocol $top WM_DELETE_WINDOW [list destroy_showrefs $top]
     text $top.list -background $bgcolor -foreground $fgcolor \
         -selectbackground $selectbgcolor -font mainfont \
         -xscrollcommand "$top.xsb set" -yscrollcommand "$top.ysb set" \
@@ -10229,8 +10236,8 @@ proc showrefs {} {
     ttk::checkbutton $top.sort -text [mc "Sort refs by type"] \
         -variable sortrefsbytype -command {refill_reflist}
     grid $top.sort - -sticky w -pady 2
-    ttk::button $top.close -command [list destroy $top] -text [mc "Close"]
-    bind $top <Key-Escape> [list destroy $top]
+    ttk::button $top.close -command [list destroy_showrefs $top] -text [mc "Close"]
+    bind $top <Key-Escape> [list destroy_showrefs $top]
     grid $top.close -
     grid columnconfigure $top 0 -weight 1
     grid rowconfigure $top 0 -weight 1
@@ -10239,6 +10246,9 @@ proc showrefs {} {
     bind $top.list <ButtonRelease-1> {sel_reflist %W %x %y; break}
     set reflist {}
     refill_reflist
+    # Restore geometry after the window is fully created and mapped
+    # Delay Configure binding to avoid overwriting restored geometry
+    bind $top <Map> [list after idle [list setup_showrefs_geometry_tracking $top]]
 }
 
 proc sel_reflist {w x y} {
@@ -10271,6 +10281,31 @@ proc reflistfilter_change {n1 n2 op} {
     after 200 refill_reflist
 }
 
+proc save_showrefs_geometry {top} {
+    global geometry
+    if {[winfo exists $top]} {
+        set geometry(showrefs) [wm geometry $top]
+    }
+}
+
+proc restore_showrefs_geometry {top} {
+    global geometry
+    if {[info exists geometry(showrefs)] && [winfo exists $top]} {
+        wm geometry $top $geometry(showrefs)
+    }
+}
+
+proc setup_showrefs_geometry_tracking {top} {
+    restore_showrefs_geometry $top
+    bind $top <Configure> [list save_showrefs_geometry $top]
+}
+
+proc destroy_showrefs {top} {
+    save_showrefs_geometry $top
+    savestuff .
+    destroy $top
+}
+
 proc refill_reflist {} {
     global reflist reflistfilter showrefstop headids tagids otherrefids sortrefsbytype
     global curview upstreamofref
-- 
2.51.0