5555import com .codename1 .ui .events .ActionEvent ;
5656import com .codename1 .ui .events .ActionListener ;
5757import com .codename1 .ui .events .MessageEvent ;
58+ import com .codename1 .ui .events .WindowEvent ;
5859import com .codename1 .ui .geom .Dimension ;
5960import com .codename1 .ui .geom .Rectangle ;
6061import 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