Repository navigation
bpo-37039: Make IDLE's Zoom Height adjust to users' screens #13678
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
dd16ea5
aaa873b
9aeb031
c9f77d1
9a88520
f64ff40
2add7ee
2e91cb9
7cf228c
a6183f4
6b05d1e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,42 +2,121 @@ | |
|
|
||
| import re | ||
| import sys | ||
| import tkinter | ||
|
|
||
| from idlelib import macosx | ||
|
|
||
| class WmInfoGatheringError(Exception): | ||
| pass | ||
|
|
||
|
|
||
| class ZoomHeight: | ||
|
|
||
| def __init__(self, editwin): | ||
| self.editwin = editwin | ||
|
|
||
| # Cached values for maximized window dimensions, one for each set | ||
| # of screen dimensions. | ||
| self._max_height_and_y_coords = {} | ||
|
|
||
| @property | ||
|
terryjreedy marked this conversation as resolved.
Outdated
|
||
| def top(self): | ||
| return self.editwin.top | ||
|
|
||
| def zoom_height_event(self, event=None): | ||
| top = self.editwin.top | ||
| zoomed = zoom_height(top) | ||
| menu_status = 'Restore' if zoomed else 'Zoom' | ||
| self.editwin.update_menu_label(menu='options', index='* Height', | ||
| label=f'{menu_status} Height') | ||
| zoomed = self.zoom_height() | ||
|
|
||
| if zoomed is not None: | ||
| menu_status = 'Restore' if zoomed else 'Zoom' | ||
| self.editwin.update_menu_label(menu='options', index='* Height', | ||
| label=f'{menu_status} Height') | ||
|
|
||
| return "break" | ||
|
|
||
| def zoom_height(self): | ||
| width, height, x, y = get_window_geometry(self.top) | ||
|
terryjreedy marked this conversation as resolved.
Outdated
|
||
|
|
||
| if self.top.wm_state() != 'normal': | ||
| # Can't zoom/restore window height for windows not in the 'normal' | ||
| # state, e.g. maximized and full-screen windows. | ||
| return None | ||
|
terryjreedy marked this conversation as resolved.
|
||
|
|
||
| try: | ||
| maxheight, maxy = self.get_max_height_and_y_coord() | ||
| except WmInfoGatheringError: | ||
| return None | ||
|
|
||
| if height != maxheight: | ||
| # Maximize the window's height. | ||
| set_window_geometry(self.top, (width, maxheight, x, maxy)) | ||
| return True | ||
| else: | ||
| # Restore the window's height. | ||
| # | ||
| # .wm_geometry('') makes the window revert to the size requested | ||
| # by the widgets it contains. | ||
| self.top.wm_geometry('') | ||
| return False | ||
|
|
||
| def get_max_height_and_y_coord(self): | ||
| screen_dimensions = (self.top.winfo_screenwidth(), | ||
| self.top.winfo_screenheight()) | ||
| if screen_dimensions not in self._max_height_and_y_coords: | ||
| orig_state = self.top.wm_state() | ||
|
|
||
| def zoom_height(top): | ||
| # Get window geometry info for maximized windows. | ||
| try: | ||
| self.top.wm_state('zoomed') | ||
| except tkinter.TclError: | ||
| # The 'zoomed' state is not supported by some esoteric WMs, | ||
| # such as Xvfb. | ||
| raise WmInfoGatheringError( | ||
| 'Failed getting geometry of maximized windows, because ' + | ||
| 'the "zoomed" window state is unavailable.') | ||
| self.top.update() | ||
| maxwidth, maxheight, maxx, maxy = get_window_geometry(self.top) | ||
| if sys.platform == 'win32': | ||
| # On Windows, the returned Y coordinate is the one before | ||
| # maximizing, so we use 0 which is correct unless a user puts | ||
| # their dock on the top of the screen (very rare). | ||
| maxy = 0 | ||
| maxrooty = self.top.winfo_rooty() | ||
|
|
||
| # Get the "root y" coordinate for non-maximized windows with their | ||
| # y coordinate set to that of maximized windows. This is needed | ||
| # to properly handle different title bar heights for non-maximized | ||
| # vs. maximized windows, as seen e.g. in Windows 10. | ||
| self.top.wm_state('normal') | ||
| self.top.update() | ||
| orig_geom = get_window_geometry(self.top) | ||
| max_y_geom = orig_geom[:3] + (maxy,) | ||
| set_window_geometry(self.top, max_y_geom) | ||
| self.top.update() | ||
| max_y_geom_rooty = self.top.winfo_rooty() | ||
|
|
||
| # Adjust the maximum window height to account for the different | ||
| # title bar heights of non-maximized vs. maximized windows. | ||
| maxheight += maxrooty - max_y_geom_rooty | ||
|
|
||
| self._max_height_and_y_coords[screen_dimensions] = maxheight, maxy | ||
|
|
||
| set_window_geometry(self.top, orig_geom) | ||
| self.top.wm_state(orig_state) | ||
|
|
||
| return self._max_height_and_y_coords[screen_dimensions] | ||
|
|
||
|
|
||
| def get_window_geometry(top): | ||
| geom = top.wm_geometry() | ||
| m = re.match(r"(\d+)x(\d+)\+(-?\d+)\+(-?\d+)", geom) | ||
| if not m: | ||
| top.bell() | ||
| return | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By PEP 8, this should be https://www.tcl.tk/man/tcl8.6/TkCmd/tkvars.htm says idlelib, including tests, is loaded with unguarded geometry calls, so IDLE and the test suite would fail on any tk without geometry. So there must be none on systems Python and IDLE currently run on.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that this part of the code is unchanged... If the existing norm is not guarding against |
||
| width, height, x, y = map(int, m.groups()) | ||
| newheight = top.winfo_screenheight() | ||
|
|
||
| # The constants below for Windows and Mac Aqua are visually determined | ||
| # to avoid taskbar or menubar and app icons. | ||
| newy, bot_y = ((0, 72) if sys.platform == 'win32' else | ||
| (22, 88) if macosx.isAquaTk() else | ||
| (0, 88) ) # Guess for anything else. | ||
| newheight = newheight - newy - bot_y | ||
| newgeom = '' if height >= newheight else f"{width}x{newheight}+{x}+{newy}" | ||
| top.wm_geometry(newgeom) | ||
| return newgeom != "" | ||
| return width, height, x, y | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just return |
||
|
|
||
|
|
||
| def set_window_geometry(top, geometry): | ||
| top.wm_geometry("{:d}x{:d}{:+d}{:+d}".format(*geometry)) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Fix incorrect behavior of IDLE's "Zoom Height" command across platforms. |
Uh oh!
There was an error while loading. Please reload this page.