Skip to content

Commit a7dbab5

Browse files
authored
Add support for Windowing API in Desktop Applications
Fixed #4145
1 parent ae6330d commit a7dbab5

File tree

8 files changed

+576
-7
lines changed

8 files changed

+576
-7
lines changed

CodenameOne/src/com/codename1/impl/CodenameOneImplementation.java

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ public abstract class CodenameOneImplementation {
174174
*/
175175
private final Rectangle paintDirtyTmpRect = new Rectangle();
176176
private BrowserComponent sharedJavascriptContext;
177+
private Dimension initialWindowSizeHintPercent;
177178

178179
static void setOnCurrentFormChange(Runnable on) {
179180
onCurrentFormChange = on;
@@ -467,6 +468,54 @@ public int getActualDisplayHeight() {
467468
return getDisplayHeight();
468469
}
469470

471+
/**
472+
* Returns the size of the desktop area hosting the application window when running on a desktop
473+
* platform. Implementations that do not support windows may return {@code null}.
474+
*
475+
* @return the desktop size or {@code null}
476+
*/
477+
public Dimension getDesktopSize() {
478+
return null;
479+
}
480+
481+
/**
482+
* Returns the bounds of the application window when running on a desktop platform.
483+
*
484+
* @return the window bounds, defaults to the current display size
485+
*/
486+
public Rectangle getWindowBounds() {
487+
return new Rectangle(0, 0, getDisplayWidth(), getDisplayHeight());
488+
}
489+
490+
/**
491+
* Requests a resize of the application window when supported by the platform.
492+
*
493+
* @param width the desired window width in pixels
494+
* @param height the desired window height in pixels
495+
*/
496+
public void setWindowSize(int width, int height) {
497+
}
498+
499+
/**
500+
* Stores an optional window size hint (in percent values) for desktop environments. Implementations
501+
* that do not support windows may ignore this value.
502+
*
503+
* @param hint a {@link Dimension} whose width/height represent percentages of the desktop to use for
504+
* the initial window size, or {@code null} to clear a previously stored hint
505+
*/
506+
public void setInitialWindowSizeHintPercent(Dimension hint) {
507+
initialWindowSizeHintPercent = hint;
508+
}
509+
510+
/**
511+
* Returns the optional desktop window size hint provided by the first form.
512+
*
513+
* @return the stored hint or {@code null}
514+
*/
515+
public Dimension getInitialWindowSizeHintPercent() {
516+
return initialWindowSizeHintPercent;
517+
}
518+
470519
/**
471520
* Invoked when an exception occurs on the EDT, allows the implementation to
472521
* take control of the device to produce testing information.

CodenameOne/src/com/codename1/ui/CN.java

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
import com.codename1.plugin.PluginSupport;
3434
import com.codename1.ui.events.ActionListener;
3535
import com.codename1.ui.events.MessageEvent;
36+
import com.codename1.ui.events.WindowEvent;
37+
import com.codename1.ui.geom.Dimension;
3638
import com.codename1.ui.geom.Rectangle;
3739
import com.codename1.ui.plaf.Style;
3840
import com.codename1.util.RunnableWithResultSync;
@@ -813,6 +815,78 @@ public static boolean isDesktop() {
813815
return Display.impl.isDesktop();
814816
}
815817

818+
/**
819+
* Returns the size of the desktop hosting the application window when running on a desktop platform.
820+
*
821+
* @return the desktop size
822+
*/
823+
public static Dimension getDesktopSize() {
824+
return Display.getInstance().getDesktopSize();
825+
}
826+
827+
/**
828+
* Returns the number of monitors attached to the desktop environment when available.
829+
*
830+
* @return the number of monitors
831+
*/
832+
/**
833+
* Returns the current bounds of the application window when supported by the platform.
834+
*
835+
* @return the window bounds
836+
*/
837+
public static Rectangle getWindowBounds() {
838+
return Display.getInstance().getWindowBounds();
839+
}
840+
841+
/**
842+
* Requests a resize of the application window when supported by the platform.
843+
*
844+
* @param width the desired window width
845+
* @param height the desired window height
846+
*/
847+
public static void setWindowSize(int width, int height) {
848+
Display.getInstance().setWindowSize(width, height);
849+
}
850+
851+
/**
852+
* Returns the initial desktop window size hint provided by the first shown form, when available.
853+
*
854+
* @return the stored hint or {@code null}
855+
*/
856+
public static Dimension getInitialWindowSizeHintPercent() {
857+
return Display.getInstance().getInitialWindowSizeHintPercent();
858+
}
859+
860+
/**
861+
* Sets the initial desktop window size hint (percent of the desktop) that should be used when the
862+
* first form is shown. This is primarily useful for desktop environments where the Codename One
863+
* application is hosted in a window rather than full-screen.
864+
*
865+
* @param hint a {@link Dimension} whose width/height represent percentages of the desktop to use for
866+
* the initial window size, or {@code null} to clear a previously stored hint
867+
*/
868+
public static void setInitialWindowSizeHintPercent(Dimension hint) {
869+
Display.getInstance().setInitialWindowSizeHintPercent(hint);
870+
}
871+
872+
/**
873+
* Adds a listener for window events such as resize or move.
874+
*
875+
* @param l the listener to add
876+
*/
877+
public static void addWindowListener(ActionListener<WindowEvent> l) {
878+
Display.getInstance().addWindowListener(l);
879+
}
880+
881+
/**
882+
* Removes a previously registered window listener.
883+
*
884+
* @param l the listener to remove
885+
*/
886+
public static void removeWindowListener(ActionListener<WindowEvent> l) {
887+
Display.getInstance().removeWindowListener(l);
888+
}
889+
816890
/**
817891
* Returns true if the device has dialing capabilities
818892
*

CodenameOne/src/com/codename1/ui/Display.java

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import com.codename1.ui.events.ActionEvent;
5656
import com.codename1.ui.events.ActionListener;
5757
import com.codename1.ui.events.MessageEvent;
58+
import com.codename1.ui.events.WindowEvent;
5859
import com.codename1.ui.geom.Dimension;
5960
import com.codename1.ui.geom.Rectangle;
6061
import com.codename1.ui.plaf.Style;
@@ -261,6 +262,12 @@ public final class Display extends CN1Constants {
261262
* Indicates that commands should try to add themselves to the native menus
262263
*/
263264
public static final int COMMAND_BEHAVIOR_NATIVE = 10;
265+
/**
266+
* Client property key used on the first shown {@link Form} to indicate the desired initial
267+
* window size as a percentage of the available desktop. The value should be a {@link com.codename1.ui.geom.Dimension}
268+
* whose width and height represent percentages.
269+
*/
270+
public static final String WINDOW_SIZE_HINT_PERCENT = "cn1.windowSizePercent";
264271
static final Display INSTANCE = new Display();
265272
static final Object lock = new Object();
266273
private static final int POINTER_PRESSED = 1;
@@ -293,6 +300,11 @@ public final class Display extends CN1Constants {
293300
private boolean inNativeUI;
294301
private Runnable bookmark;
295302
private EventDispatcher messageListeners;
303+
private EventDispatcher windowListeners;
304+
/**
305+
* Tracks whether the initial window size hint has already been consumed for the first shown form.
306+
*/
307+
private boolean initialWindowSizeApplied;
296308
private boolean disableInvokeAndBlock;
297309
/**
298310
* Enable Async stack traces. This is disabled by default, but will cause
@@ -430,6 +442,7 @@ private Display() {
430442
public static void init(Object m) {
431443
if (!INSTANCE.codenameOneRunning) {
432444
INSTANCE.codenameOneRunning = true;
445+
INSTANCE.initialWindowSizeApplied = false;
433446
INSTANCE.pluginSupport = new PluginSupport();
434447
INSTANCE.displayInitTime = System.currentTimeMillis();
435448

@@ -1648,6 +1661,9 @@ void setCurrentForm(Form newForm) {
16481661
} else {
16491662
forceShow = true;
16501663
}
1664+
if (!initialWindowSizeApplied) {
1665+
initialWindowSizeApplied = applyInitialWindowSize(newForm);
1666+
}
16511667
keyRepeatCharged = false;
16521668
longPressCharged = false;
16531669
longPointerCharged = false;
@@ -1669,6 +1685,18 @@ void setCurrentForm(Form newForm) {
16691685
newForm.onShowCompletedImpl();
16701686
}
16711687

1688+
private boolean applyInitialWindowSize(Form form) {
1689+
if (form == null) {
1690+
return false;
1691+
}
1692+
Object hint = form.getClientProperty(WINDOW_SIZE_HINT_PERCENT);
1693+
if (!(hint instanceof Dimension)) {
1694+
return false;
1695+
}
1696+
impl.setInitialWindowSizeHintPercent((Dimension) hint);
1697+
return true;
1698+
}
1699+
16721700
/**
16731701
* Indicates whether a delay should exist between calls to flush graphics during
16741702
* transition. In some devices flushGraphics is asynchronious causing it to be
@@ -2552,6 +2580,63 @@ public int getDisplayHeight() {
25522580
return impl.getDisplayHeight();
25532581
}
25542582

2583+
/**
2584+
* Returns the size of the desktop hosting the application window when running on a desktop platform.
2585+
*
2586+
* @return the desktop size or the current display size if not supported
2587+
*/
2588+
public Dimension getDesktopSize() {
2589+
Dimension desktopSize = impl.getDesktopSize();
2590+
if (desktopSize != null) {
2591+
return desktopSize;
2592+
}
2593+
return new Dimension(getDisplayWidth(), getDisplayHeight());
2594+
}
2595+
2596+
/**
2597+
* Returns the current window bounds when running on a desktop platform.
2598+
*
2599+
* @return the bounds of the application window
2600+
*/
2601+
public Rectangle getWindowBounds() {
2602+
Rectangle bounds = impl.getWindowBounds();
2603+
if (bounds == null) {
2604+
return new Rectangle(0, 0, getDisplayWidth(), getDisplayHeight());
2605+
}
2606+
return bounds;
2607+
}
2608+
2609+
/**
2610+
* Requests a resize of the application window when supported by the platform.
2611+
*
2612+
* @param width the desired window width
2613+
* @param height the desired window height
2614+
*/
2615+
public void setWindowSize(int width, int height) {
2616+
impl.setWindowSize(width, height);
2617+
}
2618+
2619+
/**
2620+
* Returns the initial desktop window size hint provided by the first shown form, when available.
2621+
*
2622+
* @return the stored hint or {@code null}
2623+
*/
2624+
public Dimension getInitialWindowSizeHintPercent() {
2625+
return impl.getInitialWindowSizeHintPercent();
2626+
}
2627+
2628+
/**
2629+
* Sets the initial desktop window size hint (percent of the desktop) that should be used when the
2630+
* first form is shown. This is primarily useful for desktop environments where the Codename One
2631+
* application is hosted in a window rather than full-screen.
2632+
*
2633+
* @param hint a {@link Dimension} whose width/height represent percentages of the desktop to use for
2634+
* the initial window size, or {@code null} to clear a previously stored hint
2635+
*/
2636+
public void setInitialWindowSizeHintPercent(Dimension hint) {
2637+
impl.setInitialWindowSizeHintPercent(hint);
2638+
}
2639+
25552640
/**
25562641
* Causes the given component to repaint, used internally by Form
25572642
*
@@ -3320,6 +3405,54 @@ public void dispatchMessage(MessageEvent evt) {
33203405
}
33213406
}
33223407

3408+
/**
3409+
* Adds a listener to receive notifications about native window changes such as resize or movement.
3410+
*
3411+
* @param l the listener to add
3412+
*/
3413+
public synchronized void addWindowListener(ActionListener<WindowEvent> l) {
3414+
if (windowListeners == null) {
3415+
windowListeners = new EventDispatcher();
3416+
}
3417+
windowListeners.addListener(l);
3418+
}
3419+
3420+
/**
3421+
* Removes a previously registered window listener.
3422+
*
3423+
* @param l the listener to remove
3424+
*/
3425+
public synchronized void removeWindowListener(ActionListener<WindowEvent> l) {
3426+
if (windowListeners != null) {
3427+
windowListeners.removeListener(l);
3428+
}
3429+
}
3430+
3431+
/**
3432+
* Dispatches a window change event to registered listeners. This method is intended to be invoked by
3433+
* platform implementations.
3434+
*
3435+
* @param evt the window event to dispatch
3436+
*/
3437+
public void fireWindowEvent(WindowEvent evt) {
3438+
if (evt == null || windowListeners == null || !windowListeners.hasListeners()) {
3439+
return;
3440+
}
3441+
if (isEdt()) {
3442+
windowListeners.fireActionEvent(evt);
3443+
} else {
3444+
final WindowEvent windowEvent = evt;
3445+
callSerially(new Runnable() {
3446+
@Override
3447+
public void run() {
3448+
if (windowListeners != null && windowListeners.hasListeners()) {
3449+
windowListeners.fireActionEvent(windowEvent);
3450+
}
3451+
}
3452+
});
3453+
}
3454+
}
3455+
33233456
/**
33243457
* Returns the property from the underlying platform deployment or the default
33253458
* value if no deployment values are supported. This is equivalent to the

0 commit comments

Comments
 (0)