Skip to content

Commit ba9c8fc

Browse files
committed
reworking EditorState so that the Editor window better handles multiple display setups (fixes https://github.com/processing/processing/issues/1566)
1 parent 64e5929 commit ba9c8fc

File tree

5 files changed

+118
-89
lines changed

5 files changed

+118
-89
lines changed

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,18 @@ We don't have a schedule for a final release. This work is being done by a [tiny
1515
As with all releases, we'll do everything possible to avoid breaking API. However, there will still be tweaks that have to be made. We'll try to keep them minor. Our goal is stability, and keeping everyone's code running.
1616

1717

18+
### alpha 4
19+
20+
* `EditorState(List<Editor> editors)` changed to `EditorState.nextEditor(List<Editor> editors)`, reflecting its nature as closer to a factory method (that makes use of the Editor list) than a constructor that will also be storing information about the list of Editor objects in the created object.
21+
1822
### alpha 2
1923

2024
* See `changes.md` if you're using `surface.setResizable()` with this release on macOS and with P2D or P3D renderers.
2125
* The `static` versions of `selectInput()`, `selectOutput()`, and `selectFolder()` in `PApplet` have been removed. These were not documented, hopefully were not in use anywhere.
22-
* The `frame` object has been removed from `PApplet`. We've been warning folks to use `surface` since 2015, but we still should [warn users](https://github.com/processing/processing4/issues/59)
26+
* The `frame` object has been removed from `PApplet`. We've been warning folks to use `surface` since 2015, but we still should [warn users](https://github.com/processing/processing4/issues/59) or maybe provide an easy way to update code.
2327
* `PImage.checkAlpha()` is now `public` instead of `protected`
2428
* All AWT calls have been moved out of `PImage`, which may be a problem for anything that was relying on those internals
25-
* For instance, `new PImage(java.awt.Image)` is no longer available. It was an undocumented method that was `public` only because it was required by subclasses.
29+
* ~~For instance, `new PImage(java.awt.Image)` is no longer available. It was an undocumented method that was `public` only because it was required by subclasses.~~ As of alpha 4, this is back, because it wasn't deprecated in 3.x, and is likely to break too many things.
2630
* Removed `MouseEvent.getClickCount()` and `MouseEvent.getAmount()`. These had been deprecated, not clear they were used anywhere.
2731

2832
### alpha 1

app/src/processing/app/Base.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1296,7 +1296,7 @@ public Editor handleOpen(String path) {
12961296
* can be set by the caller
12971297
*/
12981298
public Editor handleOpen(String path, boolean untitled) {
1299-
return handleOpen(path, untitled, new EditorState(editors));
1299+
return handleOpen(path, untitled, EditorState.nextEditor(editors));
13001300
}
13011301

13021302

app/src/processing/app/ui/Editor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ public abstract class Editor extends JFrame implements RunnerListener {
163163

164164
protected Editor(final Base base, String path, final EditorState state,
165165
final Mode mode) throws EditorException {
166-
super("Processing", state.checkConfig());
166+
super("Processing", state.getConfig());
167167
this.base = base;
168168
this.state = state;
169169
this.mode = mode;

app/src/processing/app/ui/EditorState.java

Lines changed: 104 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/*
44
Part of the Processing project - http://processing.org
55
6-
Copyright (c) 2012-19 The Processing Foundation
6+
Copyright (c) 2012-21 The Processing Foundation
77
Copyright (c) 2011-12 Ben Fry and Casey Reas
88
99
This program is free software; you can redistribute it and/or modify
@@ -27,61 +27,79 @@
2727
import java.awt.GraphicsDevice;
2828
import java.awt.GraphicsEnvironment;
2929
import java.awt.Rectangle;
30-
import java.io.*;
3130
import java.util.List;
3231

3332
import processing.app.Preferences;
34-
import processing.core.PApplet;
35-
36-
//import processing.core.PApplet;
37-
38-
39-
// scenarios:
40-
// 1) new untitled sketch (needs device, needs bounds)
41-
// 2) restoring sketch from recent menu
42-
// - device cannot be found
43-
// - device is found but it's a different size
44-
// - device is found and size is correct
45-
// 3) re-opening sketch in a new mode
4633

4734

35+
/**
36+
* Stores state information (location, size, display device) for an Editor window.
37+
* Originally was used to restore sketch windows on startup, though that was removed
38+
* at some point (3.0?) because it was unreliable and not always appreciated.
39+
*
40+
* This version is primarily just used to get the location (and display) to open
41+
* a new Editor window, though some of the vestigial bits are still in there in case
42+
* we want to restore the ability to restore windows on startup.
43+
*
44+
* Previous scenarios:
45+
* <ul>
46+
* <li>new untitled sketch (needs device, needs bounds)</li>
47+
* <li>restoring sketch from recent menu
48+
* <ul>
49+
* <li>device is found and size matches</li>
50+
* <li>device cannot be found</li>
51+
* <li>device is found but its size has changed</li>
52+
* </ul>
53+
* </li>
54+
* <li>re-opening sketch in a new mode</li>
55+
* </ul>
56+
*/
4857
public class EditorState {
49-
// path to the main .pde file for the sketch
50-
// String path;
51-
// placement of the window
52-
// int windowX, windowY, windowW, windowH;
5358
Rectangle editorBounds;
5459
int dividerLocation;
55-
// width/height of the screen on which this window was placed
56-
// int displayW, displayH;
57-
// String deviceName; // not really useful b/c it's more about bounds anyway
58-
Rectangle deviceBounds;
5960
boolean isMaximized;
61+
GraphicsConfiguration deviceConfig;
6062

61-
// how far to offset a new window from the previous window
63+
/** How far to offset a new window from the previous window */
6264
static final int WINDOW_OFFSET = 28;
6365

66+
/**
67+
* Keep a reference to the last device config so we know which display to
68+
* use when creating a new window after all windows have been closed.
69+
*/
70+
static GraphicsConfiguration lastConfig;
71+
6472

6573
/**
6674
* Create a fresh editor state object from the default screen device and
6775
* set its placement relative to the last opened window.
6876
* @param editors List of active editor objects
6977
*/
70-
public EditorState(List<Editor> editors) {
71-
defaultConfig();
72-
defaultLocation(editors);
78+
static public EditorState nextEditor(List<Editor> editors) {
79+
Editor lastEditor = null;
80+
int editorCount = editors.size();
81+
if (editorCount > 0) {
82+
lastEditor = editors.get(editorCount-1);
83+
}
84+
85+
// update lastConfig so it can be set for this Editor and
86+
// for the next Editor created if the last window is closed.
87+
if (lastEditor != null) {
88+
lastConfig = lastEditor.getGraphicsConfiguration();
89+
}
90+
if (lastConfig == null) {
91+
lastConfig = getDefaultConfig();
92+
}
93+
94+
EditorState outgoing = new EditorState();
95+
outgoing.initLocation(lastConfig, lastEditor);
96+
return outgoing;
7397
}
7498

7599

76-
// EditorState(BufferedReader reader) throws IOException {
77-
// String line = reader.readLine();
78-
// EditorState(String[] pieces) throws IOException {
100+
/*
79101
EditorState(String info) throws IOException {
80-
// String line = reader.readLine();
81-
// String[] pieces = PApplet.split(line, '\t');
82-
String[] pieces = PApplet.split(info, ',');
83-
// path = pieces[0];
84-
102+
String[] pieces = PApplet.split(info, ',');
85103
editorBounds = new Rectangle(Integer.parseInt(pieces[0]),
86104
Integer.parseInt(pieces[1]),
87105
Integer.parseInt(pieces[2]),
@@ -93,15 +111,8 @@ public EditorState(List<Editor> editors) {
93111
Integer.parseInt(pieces[6]),
94112
Integer.parseInt(pieces[7]),
95113
Integer.parseInt(pieces[8]));
96-
97-
// windowX = Integer.parseInt(pieces[1]);
98-
// windowY = Integer.parseInt(pieces[2]);
99-
// windowW = Integer.parseInt(pieces[3]);
100-
// windowH = Integer.parseInt(pieces[4]);
101-
102-
// displayW = Integer.parseInt(pieces[5]);
103-
// displayH = Integer.parseInt(pieces[6]);
104114
}
115+
*/
105116

106117

107118
public String toString() {
@@ -110,19 +121,14 @@ public String toString() {
110121
editorBounds.width + "," +
111122
editorBounds.height + "," +
112123
dividerLocation + "," +
113-
deviceBounds.x + "," +
114-
deviceBounds.y + "," +
115-
deviceBounds.width + "," +
116-
deviceBounds.height);
124+
deviceConfig);
117125
}
118126

119-
120-
/**
121-
* Returns a GraphicsConfiguration so that a new Editor Frame can be
122-
* constructed. First tries to match the bounds for this state information
123-
* to an existing config (nominally, a display) and if that doesn't work,
124-
* then returns the default configuration/default display.
125-
*/
127+
/*
128+
// * Returns a GraphicsConfiguration so that a new Editor Frame can be
129+
// * constructed. First tries to match the bounds for this state information
130+
// * to an existing config (nominally, a display) and if that doesn't work,
131+
// * then returns the default configuration/default display.
126132
GraphicsConfiguration checkConfig() {
127133
if (deviceBounds != null) {
128134
GraphicsEnvironment graphicsEnvironment =
@@ -133,42 +139,53 @@ GraphicsConfiguration checkConfig() {
133139
for (GraphicsConfiguration config : configurations) {
134140
// if (config.getDevice().getIDstring().equals(deviceName)) {
135141
if (config.getBounds().equals(deviceBounds)) {
142+
System.out.println("found config " + config + " " + deviceBounds);
143+
System.out.println("device name is " + config.getDevice().getIDstring());
136144
return config;
137145
}
138146
}
139147
}
140148
}
149+
System.out.println("using default config");
141150
// otherwise go to the default config
142151
return defaultConfig();
143152
}
153+
*/
144154

145155

146-
GraphicsConfiguration defaultConfig() {
156+
public GraphicsConfiguration getConfig() {
157+
return deviceConfig;
158+
}
159+
160+
161+
static GraphicsConfiguration getDefaultConfig() {
147162
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
148163
GraphicsDevice device = ge.getDefaultScreenDevice();
149164
GraphicsConfiguration config = device.getDefaultConfiguration();
150-
// deviceName = device.getIDstring();
151-
deviceBounds = config.getBounds();
165+
// deviceName = device.getIDstring();
166+
// deviceBounds = config.getBounds();
152167
return config;
153168
}
154169

155170

156171
/**
157172
* Figure out the next location by sizing up the last editor in the list.
158173
* If no editors are opened, it'll just open on the main screen.
159-
* @param editors List of editors currently opened
174+
* @param lastOpened The last Editor opened, used to determine display and location
160175
*/
161-
void defaultLocation(List<Editor> editors) {
176+
void initLocation(GraphicsConfiguration lastConfig, Editor lastOpened) {
177+
deviceConfig = lastConfig;
178+
Rectangle deviceBounds = deviceConfig.getBounds();
179+
162180
int defaultWidth =
163181
Toolkit.zoom(Preferences.getInteger("editor.window.width.default"));
164182
int defaultHeight =
165183
Toolkit.zoom(Preferences.getInteger("editor.window.height.default"));
166184

167185
defaultWidth = Math.min(defaultWidth, deviceBounds.width);
168186
defaultHeight = Math.min(defaultHeight, deviceBounds.height);
169-
//System.out.println("default w/h = " + defaultWidth + "/" + defaultHeight);
170187

171-
if (editors.size() == 0) {
188+
if (lastOpened == null) {
172189
// If no current active editor, use default placement.
173190
// Center the window on ths screen, taking into account that the
174191
// upper-left corner of the device may have a non (0, 0) origin.
@@ -183,39 +200,40 @@ void defaultLocation(List<Editor> editors) {
183200
} else {
184201
// With a currently active editor, open the new window using the same
185202
// dimensions and divider location, but offset slightly.
186-
synchronized (editors) {
187-
Editor lastOpened = editors.get(editors.size() - 1);
188-
isMaximized = (lastOpened.getExtendedState() == Frame.MAXIMIZED_BOTH);
189-
editorBounds = lastOpened.getBounds();
190-
editorBounds.x += WINDOW_OFFSET;
191-
editorBounds.y += WINDOW_OFFSET;
192-
dividerLocation = lastOpened.getDividerLocation();
193-
194-
if (!deviceBounds.contains(editorBounds)) {
195-
// Warp the next window to a randomish location on screen.
196-
editorBounds.x = deviceBounds.x +
197-
(int) (Math.random() * (deviceBounds.width - defaultWidth));
198-
editorBounds.y = deviceBounds.y +
199-
(int) (Math.random() * (deviceBounds.height - defaultHeight));
200-
}
201-
if (isMaximized) {
202-
editorBounds.width = defaultWidth;
203-
editorBounds.height = defaultHeight;
204-
}
203+
//GraphicsDevice device = lastOpened.getGraphicsConfiguration().getDevice();
204+
//System.out.println("last opened device is " + device);
205+
206+
isMaximized = (lastOpened.getExtendedState() == Frame.MAXIMIZED_BOTH);
207+
editorBounds = lastOpened.getBounds();
208+
editorBounds.x += WINDOW_OFFSET;
209+
editorBounds.y += WINDOW_OFFSET;
210+
dividerLocation = lastOpened.getDividerLocation();
211+
212+
if (!deviceBounds.contains(editorBounds)) {
213+
// Warp the next window to a randomish location on screen.
214+
editorBounds.x = deviceBounds.x +
215+
(int) (Math.random() * (deviceBounds.width - defaultWidth));
216+
editorBounds.y = deviceBounds.y +
217+
(int) (Math.random() * (deviceBounds.height - defaultHeight));
218+
}
219+
if (isMaximized) {
220+
editorBounds.width = defaultWidth;
221+
editorBounds.height = defaultHeight;
205222
}
206223
}
207224
}
208225

209226

227+
/*
210228
void update(Editor editor) {
211-
// path = editor.getSketch().getMainFilePath();
212229
editorBounds = editor.getBounds();
213230
dividerLocation = editor.getDividerLocation();
214231
GraphicsConfiguration config = editor.getGraphicsConfiguration();
215-
// GraphicsDevice device = config.getDevice();
216232
deviceBounds = config.getBounds();
217-
// deviceName = device.getIDstring();
233+
// GraphicsDevice device = config.getDevice();
234+
deviceName = config.getDevice().getIDstring();
218235
}
236+
*/
219237

220238

221239
void apply(Editor editor) {
@@ -229,6 +247,10 @@ void apply(Editor editor) {
229247
if (isMaximized) {
230248
editor.setExtendedState(Frame.MAXIMIZED_BOTH);
231249
}
250+
251+
// note: doesn't do anything with the device, though that could be
252+
// added if it's something that would be necessary (i.e. to store windows and
253+
// re-open them on when re-opening Processing)
232254
}
233255

234256

todo.txt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ X https://github.com/processing/processing/issues/5781
3131
X store -1 as display number when using the default
3232
X ran into weird situation where '1' was renumbered by adding a screen
3333
X so the default was now the external display
34+
X a little modernizing/cleanup in Base, converting things to lambda functions
35+
X editor windows always open on display 1
36+
X https://github.com/processing/processing/issues/1566
37+
X rewrote EditorState to better handle devices and clean it up
3438

3539
earlier
3640
o further streamline the downloader
@@ -48,8 +52,6 @@ X https://github.com/processing/processing4/issues/201
4852
X https://github.com/processing/processing/pull/4097
4953

5054

51-
_ editor windows always open on display 1
52-
_ https://github.com/processing/processing/issues/1566
5355

5456

5557
may be fixed
@@ -112,7 +114,8 @@ _ demo: https://github.com/jcodec/jcodec/blob/master/samples/main/java/org/jco
112114
decisions before final 4.0 release
113115
_ Add ability to move ~/.processing directory
114116
_ use ~/.config as parent, or $XDG_CONFIG_HOME
115-
_ https://github.com/processing/processing/issues/6115
117+
o https://github.com/processing/processing/issues/6115 (moved)
118+
_ https://github.com/processing/processing4/issues/203
116119
X Shutting off VAqua due to interface ugliness and Contribution Manager freezing
117120
_ https://github.com/processing/processing4/issues/129
118121
_ now with a release 9 to cover Big Sur

0 commit comments

Comments
 (0)