Skip to content

Conversation

@Valer100
Copy link
Contributor

@Valer100 Valer100 commented Jan 17, 2026

I found out why the crash in #59 was happening while experimenting with window procedures in a project of mine: it is because the code stores the window procedures (the old and the new ones) in the same variables, regardless of the window. When storing the second window's procedures, the procedures of the first one are lost and that's why the crash is happening. This PR addresses this issue by storing the window procedures in unique variables for every window. Fixes #59.

Summary by Sourcery

Ensure window procedure hooks are stored and restored per-window to prevent crashes when manipulating multiple windows.

Bug Fixes:

  • Store old and new window procedures under hwnd-specific identifiers so each window maintains its own procedures.
  • Restore the original window procedure using the hwnd-specific stored value when unhiding a window.

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Jan 17, 2026

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

This PR fixes a crash when hiding the title bar on multiple windows by making the stored window procedure callbacks unique per window handle and updating the restore logic accordingly.

File-Level Changes

Change Details Files
Make stored window procedure callbacks unique per window to avoid overwriting between different windows.
  • Compute hwnd earlier via module_find(window) before defining the window procedure names.
  • Derive old/new window procedure keys from the hwnd (e.g., old_wndproc_, new_wndproc_) instead of using shared global names.
  • Keep the prototype definition unchanged but tied to the per-window procedure names.
hPyT/hPyT.py
Update unhide logic to restore the correct original window procedure for each window.
  • Look up old window procedure in globals() using the per-window key based on hwnd.
  • Restore the window procedure from the per-window stored value and then clear only that specific entry.
hPyT/hPyT.py

Assessment against linked issues

Issue Objective Addressed Explanation
#59 Prevent Python from crashing when hiding the title bar on multiple windows (e.g., main Tk window and one or more Toplevels) by correctly handling per-window window procedures.
#59 Ensure that restoring (unhiding) the title bar for any window correctly reinstalls that specific window’s original window procedure instead of a shared/global one.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • Instead of dynamically creating per-window global names like old_wndproc_{hwnd}, consider keeping a dedicated dict keyed by hwnd (e.g. _wndprocs[hwnd] = {...}) to avoid polluting the global namespace and make lifecycle management clearer.
  • When storing per-window procedures in globals keyed by hwnd, think about cleanup for windows that are never unhided (or that are destroyed) to avoid leaking entries if this code is used with many short-lived windows.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Instead of dynamically creating per-window global names like `old_wndproc_{hwnd}`, consider keeping a dedicated dict keyed by `hwnd` (e.g. `_wndprocs[hwnd] = {...}`) to avoid polluting the global namespace and make lifecycle management clearer.
- When storing per-window procedures in globals keyed by `hwnd`, think about cleanup for windows that are never `unhide`d (or that are destroyed) to avoid leaking entries if this code is used with many short-lived windows.

## Individual Comments

### Comment 1
<location> `hPyT/hPyT.py:209-211` </location>
<code_context>
-        if globals().get("old_wndproc") is not None:
-            set_window_long(hwnd, GWL_WNDPROC, globals()["old_wndproc"])
-            globals()["old_wndproc"] = None
+        if globals().get(f"old_wndproc_{hwnd}") is not None:
+            set_window_long(hwnd, GWL_WNDPROC, globals()[f"old_wndproc_{hwnd}"])
+            globals()[f"old_wndproc_{hwnd}"] = None

         # Restore the original height if no_span was used
</code_context>

<issue_to_address>
**issue (bug_risk):** `new_wndproc_*` entries are never cleared, which can leak per-window state.

In `unhide`, you reset `old_wndproc_{hwnd}` but leave any `new_wndproc_{hwnd}` entry in `globals()`. This leaves stale wndproc references for windows that are no longer hooked. When unhooking, please also clear or delete the corresponding `new_wndproc_{hwnd}` entry so per-window state is fully released.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@Zingzy
Copy link
Owner

Zingzy commented Jan 19, 2026

Hi, @Valer100 nice work! Just a question, why cant we use dictionaries instead of dynamic vars?

@Valer100
Copy link
Contributor Author

Valer100 commented Jan 19, 2026

We can use dictionaries too, but I didn't think about it first, because I've seen that the procs were stored inside dynamically created global variables before. If you want, I can modify the code to store them in 2 separate dictionaries, one for the old ones and another one for the new ones.

@Valer100 Valer100 force-pushed the titlebar-hide-crash-fix branch from 6c91b1e to 0c782bd Compare January 19, 2026 17:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Python crashes when trying to hide the titlebar of a Toplevel while the main window's titlebar is also hidden

2 participants