Repos / gorts / 08331e310b
commit 08331e310b6e09a2622baf7aa03b200037ac985d
Author: Nhân <hi@imnhan.com>
Date:   Thu Jun 22 14:43:39 2023 +0700

    force tk window to foreground on Windows
    
    It's not 100% working yet: the window is brought above existing windows
    but isn't focused. I have no idea how to proceed tbh.

diff --git a/go.mod b/go.mod
index 118e815..a9f68c4 100644
--- a/go.mod
+++ b/go.mod
@@ -3,3 +3,8 @@ module go.imnhan.com/gorts
 go 1.20
 
 require golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
+
+require (
+	github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect
+	golang.org/x/sys v0.1.0 // indirect
+)
diff --git a/go.sum b/go.sum
index 001575f..b29d7b5 100644
--- a/go.sum
+++ b/go.sum
@@ -1,2 +1,7 @@
+github.com/lxn/win v0.0.0-20210218163916-a377121e959e h1:H+t6A/QJMbhCSEH5rAuRxh+CtW96g0Or0Fxa9IKr4uc=
+github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
 golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
 golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
+golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
diff --git a/hacks_linux.go b/hacks_linux.go
new file mode 100644
index 0000000..e3d4782
--- /dev/null
+++ b/hacks_linux.go
@@ -0,0 +1,5 @@
+//go:build linux
+
+package main
+
+func forceFocus(handle string) error { return nil }
diff --git a/hacks_windows.go b/hacks_windows.go
new file mode 100644
index 0000000..0adaf6f
--- /dev/null
+++ b/hacks_windows.go
@@ -0,0 +1,23 @@
+//go:build windows
+
+package main
+
+import (
+	"fmt"
+	"strconv"
+
+	"github.com/lxn/win"
+)
+
+func forceFocus(handle string) error {
+	hex := handle[2:] // trim the "0x" prefix
+	uintHandle, err := strconv.ParseUint(hex, 16, 64)
+	if err != nil {
+		return fmt.Errorf("failed to parse handle: %w", err)
+	}
+
+	h := win.HWND(uintptr(uintHandle))
+	win.SetForegroundWindow(h)
+	win.SetFocus(h)
+	return nil
+}
diff --git a/main.go b/main.go
index 48a4a38..8b9992f 100644
--- a/main.go
+++ b/main.go
@@ -107,6 +107,12 @@ func startGUI() {
 		req := netstring.DecodeMultiple(scanner.Text())
 		fmt.Printf("--> %v\n", strings.Join(req, ", "))
 		switch req[0] {
+		case "forcefocus":
+			err := forceFocus(req[1])
+			if err != nil {
+				fmt.Printf("forcefocus: %s\n", err)
+			}
+			respond("ok")
 		case "geticon":
 			respond(string(gortsPngIcon))
 
diff --git a/tcl/main.tcl b/tcl/main.tcl
index d86049e..92d5b1d 100644
--- a/tcl/main.tcl
+++ b/tcl/main.tcl
@@ -179,6 +179,15 @@ proc initialize {} {
 
     setupdiffcheck
     #setupplayersuggestion
+
+
+    # By default this window is not focused and not even brought to
+    # foreground on Windows. I suspect it's because tcl is exec'ed from Go.
+    # The old "iconify, deiconify" trick no longer seems to work, so this time
+    # I'm passing it to Go to call the winapi's SetForegroundWindow directly.
+    if {$::tcl_platform(platform) == "windows"} {
+        windows_forcefocus
+    }
 }
 
 # Very simple IPC system where Tcl client talks to Go server via stdin/stdout
@@ -196,6 +205,11 @@ proc ipc {method args} {
     return [ipc_read]
 }
 
+proc windows_forcefocus {} {
+    set handle [winfo id .]
+    ipc "forcefocus" $handle
+}
+
 proc loadicon {} {
     set resp [ipc "geticon"]
     set iconblob [lindex $resp 0]
@@ -331,13 +345,3 @@ proc checkdiff {_ key _} {
         $widget configure -style "Dirty.[winfo class $widget]"
     }
 }
-
-# By default this window is not focused and not even brought to
-# foreground on Windows. I suspect it's because tcl is exec'ed from Go.
-# Minimizing then re-opening it seems to do the trick.
-# This workaround, however, makes the window unfocused on KDE, so
-# let's only use it on Windows.
-if {$tcl_platform(platform) == "windows"} {
-    wm iconify .
-    wm deiconify .
-}