Skip to content

Commit 5bff3c8

Browse files
taleinatterryjreedy
authored andcommitted
bpo-37039: Make IDLE's Zoom Height adjust to users' screens (pythonGH-13678)
Measure required height by quickly maximizing once per screen. A search for a better method failed.
1 parent a268edd commit 5bff3c8

File tree

5 files changed

+125
-29
lines changed

5 files changed

+125
-29
lines changed

Doc/library/idle.rst

+4-1
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,10 @@ Show/Hide Code Context (Editor Window only)
289289
Zoom/Restore Height
290290
Toggles the window between normal size and maximum height. The initial size
291291
defaults to 40 lines by 80 chars unless changed on the General tab of the
292-
Configure IDLE dialog.
292+
Configure IDLE dialog. The maximum height for a screen is determined by
293+
momentarily maximizing a window the first time one is zoomed on the screen.
294+
Changing screen settings may invalidate the saved height. This toogle has
295+
no effect when a window is maximized.
293296

294297
Window menu (Shell and Editor)
295298
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Lib/idlelib/NEWS.txt

+8
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@ Released on 2019-10-20?
33
======================================
44

55

6+
bpo-37039: Adjust "Zoom Height" to individual screens by momemtarily
7+
maximizing the window on first use with a particular screen. Changing
8+
screen settings may invalidate the saved height. While a window is
9+
maximized, "Zoom Height" has no effect.
10+
11+
bpo-35763: Make calltip reminder about '/' meaning positional-only less
12+
obtrusive by only adding it when there is room on the first line.
13+
614
bpo-35610: Replace now redundant editor.context_use_ps1 with
715
.prompt_last_line. This finishes change started in bpo-31858.
816

Lib/idlelib/help.html

+10-6
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<head>
77
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
88
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
9-
<title>IDLE &#8212; Python 3.8.0a4 documentation</title>
9+
<title>IDLE &#8212; Python 3.9.0a0 documentation</title>
1010
<link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" />
1111
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
1212

@@ -19,7 +19,7 @@
1919
<script type="text/javascript" src="../_static/sidebar.js"></script>
2020

2121
<link rel="search" type="application/opensearchdescription+xml"
22-
title="Search within Python 3.8.0a4 documentation"
22+
title="Search within Python 3.9.0a0 documentation"
2323
href="../_static/opensearch.xml"/>
2424
<link rel="author" title="About these documents" href="../about.html" />
2525
<link rel="index" title="Index" href="../genindex.html" />
@@ -50,6 +50,7 @@
5050

5151

5252
</head><body>
53+
5354
<div class="related" role="navigation" aria-label="related navigation">
5455
<h3>Navigation</h3>
5556
<ul>
@@ -72,7 +73,7 @@ <h3>Navigation</h3>
7273

7374

7475
<li>
75-
<a href="../index.html">3.8.0a4 Documentation</a> &#187;
76+
<a href="../index.html">3.9.0a0 Documentation</a> &#187;
7677
</li>
7778

7879
<li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> &#187;</li>
@@ -320,7 +321,10 @@ <h3>Options menu (Shell and Editor)<a class="headerlink" href="#options-menu-she
320321
<dt>Zoom/Restore Height</dt>
321322
<dd>Toggles the window between normal size and maximum height. The initial size
322323
defaults to 40 lines by 80 chars unless changed on the General tab of the
323-
Configure IDLE dialog.</dd>
324+
Configure IDLE dialog. The maximum height for a screen is determined by
325+
momentarily maximizing a window the first time one is zoomed on the screen.
326+
Changing screen settings may invalidate the saved height. This toogle has
327+
no effect when a window is maximized.</dd>
324328
</dl>
325329
</div>
326330
<div class="section" id="window-menu-shell-and-editor">
@@ -912,7 +916,7 @@ <h3>Navigation</h3>
912916

913917

914918
<li>
915-
<a href="../index.html">3.8.0a4 Documentation</a> &#187;
919+
<a href="../index.html">3.9.0a0 Documentation</a> &#187;
916920
</li>
917921

918922
<li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> &#187;</li>
@@ -943,7 +947,7 @@ <h3>Navigation</h3>
943947
<br />
944948
<br />
945949

946-
Last updated on May 25, 2019.
950+
Last updated on Jun 17, 2019.
947951
<a href="https://docs.python.org/3/bugs.html">Found a bug</a>?
948952
<br />
949953

Lib/idlelib/zoomheight.py

+99-22
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,119 @@
22

33
import re
44
import sys
5+
import tkinter
56

6-
from idlelib import macosx
7+
8+
class WmInfoGatheringError(Exception):
9+
pass
710

811

912
class ZoomHeight:
13+
# Cached values for maximized window dimensions, one for each set
14+
# of screen dimensions.
15+
_max_height_and_y_coords = {}
1016

1117
def __init__(self, editwin):
1218
self.editwin = editwin
19+
self.top = self.editwin.top
1320

1421
def zoom_height_event(self, event=None):
15-
top = self.editwin.top
16-
zoomed = zoom_height(top)
17-
menu_status = 'Restore' if zoomed else 'Zoom'
18-
self.editwin.update_menu_label(menu='options', index='* Height',
19-
label=f'{menu_status} Height')
22+
zoomed = self.zoom_height()
23+
24+
if zoomed is None:
25+
self.top.bell()
26+
else:
27+
menu_status = 'Restore' if zoomed else 'Zoom'
28+
self.editwin.update_menu_label(menu='options', index='* Height',
29+
label=f'{menu_status} Height')
30+
2031
return "break"
2132

33+
def zoom_height(self):
34+
top = self.top
35+
36+
width, height, x, y = get_window_geometry(top)
37+
38+
if top.wm_state() != 'normal':
39+
# Can't zoom/restore window height for windows not in the 'normal'
40+
# state, e.g. maximized and full-screen windows.
41+
return None
42+
43+
try:
44+
maxheight, maxy = self.get_max_height_and_y_coord()
45+
except WmInfoGatheringError:
46+
return None
47+
48+
if height != maxheight:
49+
# Maximize the window's height.
50+
set_window_geometry(top, (width, maxheight, x, maxy))
51+
return True
52+
else:
53+
# Restore the window's height.
54+
#
55+
# .wm_geometry('') makes the window revert to the size requested
56+
# by the widgets it contains.
57+
top.wm_geometry('')
58+
return False
59+
60+
def get_max_height_and_y_coord(self):
61+
top = self.top
62+
63+
screen_dimensions = (top.winfo_screenwidth(),
64+
top.winfo_screenheight())
65+
if screen_dimensions not in self._max_height_and_y_coords:
66+
orig_state = top.wm_state()
2267

23-
def zoom_height(top):
68+
# Get window geometry info for maximized windows.
69+
try:
70+
top.wm_state('zoomed')
71+
except tkinter.TclError:
72+
# The 'zoomed' state is not supported by some esoteric WMs,
73+
# such as Xvfb.
74+
raise WmInfoGatheringError(
75+
'Failed getting geometry of maximized windows, because ' +
76+
'the "zoomed" window state is unavailable.')
77+
top.update()
78+
maxwidth, maxheight, maxx, maxy = get_window_geometry(top)
79+
if sys.platform == 'win32':
80+
# On Windows, the returned Y coordinate is the one before
81+
# maximizing, so we use 0 which is correct unless a user puts
82+
# their dock on the top of the screen (very rare).
83+
maxy = 0
84+
maxrooty = top.winfo_rooty()
85+
86+
# Get the "root y" coordinate for non-maximized windows with their
87+
# y coordinate set to that of maximized windows. This is needed
88+
# to properly handle different title bar heights for non-maximized
89+
# vs. maximized windows, as seen e.g. in Windows 10.
90+
top.wm_state('normal')
91+
top.update()
92+
orig_geom = get_window_geometry(top)
93+
max_y_geom = orig_geom[:3] + (maxy,)
94+
set_window_geometry(top, max_y_geom)
95+
top.update()
96+
max_y_geom_rooty = top.winfo_rooty()
97+
98+
# Adjust the maximum window height to account for the different
99+
# title bar heights of non-maximized vs. maximized windows.
100+
maxheight += maxrooty - max_y_geom_rooty
101+
102+
self._max_height_and_y_coords[screen_dimensions] = maxheight, maxy
103+
104+
set_window_geometry(top, orig_geom)
105+
top.wm_state(orig_state)
106+
107+
return self._max_height_and_y_coords[screen_dimensions]
108+
109+
110+
def get_window_geometry(top):
24111
geom = top.wm_geometry()
25112
m = re.match(r"(\d+)x(\d+)\+(-?\d+)\+(-?\d+)", geom)
26-
if not m:
27-
top.bell()
28-
return
29-
width, height, x, y = map(int, m.groups())
30-
newheight = top.winfo_screenheight()
31-
32-
# The constants below for Windows and Mac Aqua are visually determined
33-
# to avoid taskbar or menubar and app icons.
34-
newy, bot_y = ((0, 72) if sys.platform == 'win32' else
35-
(22, 88) if macosx.isAquaTk() else
36-
(0, 88) ) # Guess for anything else.
37-
newheight = newheight - newy - bot_y
38-
newgeom = '' if height >= newheight else f"{width}x{newheight}+{x}+{newy}"
39-
top.wm_geometry(newgeom)
40-
return newgeom != ""
113+
return tuple(map(int, m.groups()))
114+
115+
116+
def set_window_geometry(top, geometry):
117+
top.wm_geometry("{:d}x{:d}+{:d}+{:d}".format(*geometry))
41118

42119

43120
if __name__ == "__main__":
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Adjust "Zoom Height" to individual screens by momemtarily maximizing the
2+
window on first use with a particular screen. Changing screen settings
3+
may invalidate the saved height. While a window is maximized,
4+
"Zoom Height" has no effect.

0 commit comments

Comments
 (0)