aboutsummaryrefslogtreecommitdiffstats
path: root/src/newt/native/Window.h
Commit message (Collapse)AuthorAgeFilesLines
* Fix Bug 600 and Bug 721: Adding support for multiple monitors w/ NEWTSven Gothel2013-05-061-8/+9
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | - Support for all monitor devices and their available modes - X11: Use RandR 1.3 if available - Retrieve information - Changing a monitor device's mode - Support for dedicated and spannig fullscreen - See <http://jogamp.org/files/screenshots/newt-mmonitor/html/> - TODO: - X11 RandR does _not_ relayout the virtual screen size and neither the CRT's viewport. We may need to relayout them if they were covering a seamless region to achieve same experience! - OSX: No machine to attach a secondary CRT -> TEST! - Tested Manually for Regressions - Linux ARMv6hf (Rasp-Pi/BCM, Panda/X11) - Android (Huawei, Kindle) - Tested Manually and junit: - X11/Linux - NV, ATI-Catalyst w/ 2 CRTs - VBox w/ 4 CRTs - Win/Windows - NV, w/ 2 CRTs - VBox w/ 4 CRTs - X11/OpenIndiana, NV, 1 CRT
* NEWT Multi-Monitor 1/2: Allow negative window position; Validate Screen-Index;Sven Gothel2011-12-231-0/+27
| | | | | | | | | | | | | | | | - Allow negative window position, using flag 'autoPosition' to mark a custom user position. This impacts Windows and X11 window creation code, which supports native auto positioning. - Screen: Validate Screen-Index. In 'big-desktop' mode the Screen index is always 0. This is true for X11 with Xinerama enabled and MS-Windows in general. Platforms w/o multiple Screen support always use index 0. - X11: Separate X11 Display/Screen/Window native code in their respective C files - Windows test scripts: use '%*' to catch all arguments - Add missing (c)
* NEWT setAlwaysOnTop(): Allow windows to stay permanent on top; TODO: X11/WindowsSven Gothel2011-09-141-12/+18
|
* NEWT/Window/Insets: Implement proper Inset usage ; Cleanup ↵Sven Gothel2011-09-061-0/+24
WindowImpl::reconfigureWindowImpl Implement proper Inset usage (window decoration size) - Insets are either polled (updateInsets()) or event driven (insetsChanged()) - Insets are used for size/pos calculations from Java side - Natural size/pos in NEWT is client-area, ie w/o Insets - Adding setTopLevelPosition()/setTopLevelSize() for top-level values, ie including insets WindowImpl::reconfigureWindowImpl - Use flags to pass down the requested action to the native implementation - Impl. all native actions: visible, decoration, reparent, resize, fullscreen - Always use size/pos in client-area space, impl. shall use Insets to tranform them - Remove double-setting of (reparent/fullscreen), which where introduced due to buggy impl. code - Fix return from fullscreen position: Was overwritten with FS position (0/0) - Fix decoration change: Remove visible toggle - not required, and actually disturbing X11Windows/WindowsWindow: Added/Fixed Insets impl. Tests (manual): - TestSharedContextVBOES2NEWT utilizies proper window layout using Insets - TestParenting03bAWT uses window layout for reparenting
f='#n218'>218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
/*
 * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 * - Redistribution of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * 
 * - Redistribution in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * 
 * Neither the name of Sun Microsystems, Inc. or the names of
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * 
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
 * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
 * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
 * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
 * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
 * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
 * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * 
 */

#include <windows.h>
#include <tchar.h>
#include <stdlib.h>
// NOTE: it looks like SHFullScreen and/or aygshell.dll is not available on the APX 2500 any more
// #ifdef UNDER_CE
// #include "aygshell.h"
// #endif

/* This typedef is apparently needed for Microsoft compilers before VC8,
   and on Windows CE */
#if (_MSC_VER < 1400) || defined(UNDER_CE)
#ifdef _WIN64
typedef long long intptr_t;
#else
typedef int intptr_t;
#endif
#endif

#include "com_sun_javafx_newt_windows_WindowsWindow.h"

#include "EventListener.h"
#include "MouseEvent.h"
#include "KeyEvent.h"

static jmethodID sizeChangedID = NULL;
static jmethodID positionChangedID = NULL;
static jmethodID windowClosedID = NULL;
static jmethodID windowDestroyedID = NULL;
static jmethodID sendMouseEventID = NULL;
static jmethodID sendKeyEventID = NULL;

// This is set by DispatchMessages, below, and cleared when it exits
static JNIEnv* env = NULL;

// Really need to factor this out in to a separate run-time file
static jchar* GetNullTerminatedStringChars(JNIEnv* env, jstring str)
{
    jchar* strChars = NULL;
    strChars = calloc((*env)->GetStringLength(env, str) + 1, sizeof(jchar));
    if (strChars != NULL) {
        (*env)->GetStringRegion(env, str, 0, (*env)->GetStringLength(env, str), strChars);
    }
    return strChars;
}

static LRESULT CALLBACK wndProc(HWND wnd, UINT message,
                                WPARAM wParam, LPARAM lParam)
{
    RECT rc;
    int useDefWindowProc = 0;
    jobject window = NULL;
    BOOL isKeyDown = FALSE;

#ifdef UNDER_CE
    window = (jobject) GetWindowLong(wnd, GWL_USERDATA);
#else
    window = (jobject) GetWindowLongPtr(wnd, GWLP_USERDATA);
#endif
    if (window == NULL || env == NULL) {
        // Shouldn't happen
        return DefWindowProc(wnd, message, wParam, lParam);
    }
    
    switch (message) {
    case WM_CLOSE:
        (*env)->CallVoidMethod(env, window, windowClosedID);
        DestroyWindow(wnd);
        break;

    case WM_DESTROY:
        (*env)->CallVoidMethod(env, window, windowDestroyedID);
        break;

    // Windows does the translation between key codes and key chars by
    // producing synthetic WM_CHAR messages in response to WM_KEYDOWN
    // messages. The Java level contains the state machine to assemble
    // these multiple events into a single event.
    case WM_CHAR:
        // NOTE that the (1 << 31) bit is meaningless regardless of
        // what the docs for WM_CHAR say; we never receive a WM_CHAR
        // message in response to translating a WM_KEYUP message
        (*env)->CallVoidMethod(env, window, sendKeyEventID,
                               (jint) EVENT_KEY_PRESSED,
                               // FIXME: need to interpret the key events in order to compute the modifiers
                               (jint) 0,
                               (jint) -1,
                               (jchar) wParam);
        useDefWindowProc = 1;
        break;

    case WM_KEYDOWN:
        // FIXME: need to interpret the key events in order to compute the modifiers
        (*env)->CallVoidMethod(env, window, sendKeyEventID, (jint) EVENT_KEY_PRESSED,
                               (jint) 0, (jint) wParam, (jchar) -1);
        useDefWindowProc = 1;
        break;

    case WM_KEYUP:
        // FIXME: need to interpret the key events in order to compute the modifiers
        (*env)->CallVoidMethod(env, window, sendKeyEventID, (jint) EVENT_KEY_RELEASED,
                               (jint) 0, (jint) wParam, (jchar) -1);
        useDefWindowProc = 1;
        break;

    case WM_SIZE:
        GetClientRect(wnd, &rc);
        (*env)->CallVoidMethod(env, window, sizeChangedID, (jint) rc.right, (jint) rc.bottom);
        break;

    // FIXME: define constants for the mouse buttons and modifiers
    case WM_LBUTTONDOWN:
        (*env)->CallVoidMethod(env, window, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED,
                               (jint) wParam, (jint) LOWORD(lParam), (jint) HIWORD(lParam), (jint) 1);
        useDefWindowProc = 1;
        break;

    case WM_LBUTTONUP:
        (*env)->CallVoidMethod(env, window, sendMouseEventID, (jint) EVENT_MOUSE_RELEASED,
                               (jint) wParam, (jint) LOWORD(lParam), (jint) HIWORD(lParam), (jint) 1);
        useDefWindowProc = 1;
        break;

    case WM_MBUTTONDOWN:
        (*env)->CallVoidMethod(env, window, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED,
                               (jint) wParam, (jint) LOWORD(lParam), (jint) HIWORD(lParam), (jint) 2);
        useDefWindowProc = 1;
        break;

    case WM_MBUTTONUP:
        (*env)->CallVoidMethod(env, window, sendMouseEventID, (jint) EVENT_MOUSE_RELEASED,
                               (jint) wParam, (jint) LOWORD(lParam), (jint) HIWORD(lParam), (jint) 2);
        useDefWindowProc = 1;
        break;

    case WM_RBUTTONDOWN:
        (*env)->CallVoidMethod(env, window, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED,
                               (jint) wParam, (jint) LOWORD(lParam), (jint) HIWORD(lParam), (jint) 3);
        useDefWindowProc = 1;
        break;

    case WM_RBUTTONUP:
        (*env)->CallVoidMethod(env, window, sendMouseEventID, (jint) EVENT_MOUSE_RELEASED,
                               (jint) wParam, (jint) LOWORD(lParam), (jint) HIWORD(lParam), (jint) 3);
        useDefWindowProc = 1;
        break;

    case WM_MOUSEMOVE:
        (*env)->CallVoidMethod(env, window, sendMouseEventID, (jint) EVENT_MOUSE_MOVED,
                               (jint) wParam, (jint) LOWORD(lParam), (jint) HIWORD(lParam), (jint) 0);
        useDefWindowProc = 1;
        break;

    // FIXME: generate EVENT_MOUSE_ENTERED, EVENT_MOUSE_EXITED
    default:
        useDefWindowProc = 1;
    }

    if (useDefWindowProc)
        return DefWindowProc(wnd, message, wParam, lParam);
    return 0;
}

/*
 * Class:     com_sun_javafx_newt_windows_WindowsWindow
 * Method:    initIDs
 * Signature: ()Z
 */
JNIEXPORT jboolean JNICALL Java_com_sun_javafx_newt_windows_WindowsWindow_initIDs
  (JNIEnv *env, jclass clazz)
{
    sizeChangedID = (*env)->GetMethodID(env, clazz, "sizeChanged", "(II)V");
    positionChangedID = (*env)->GetMethodID(env, clazz, "positionChanged", "(II)V");
    windowClosedID    = (*env)->GetMethodID(env, clazz, "windowClosed",    "()V");
    windowDestroyedID = (*env)->GetMethodID(env, clazz, "windowDestroyed", "()V");
    sendMouseEventID = (*env)->GetMethodID(env, clazz, "sendMouseEvent", "(IIIII)V");
    sendKeyEventID = (*env)->GetMethodID(env, clazz, "sendKeyEvent", "(IIIC)V");
    if (sizeChangedID == NULL ||
        positionChangedID == NULL ||
        windowClosedID == NULL ||
        windowDestroyedID == NULL ||
        sendMouseEventID == NULL ||
        sendKeyEventID == NULL) {
        return JNI_FALSE;
    }
    return JNI_TRUE;
}

/*
 * Class:     com_sun_javafx_newt_windows_WindowsWindow
 * Method:    LoadLibraryW
 * Signature: (Ljava/lang/String;)J
 */
JNIEXPORT jlong JNICALL Java_com_sun_javafx_newt_windows_WindowsWindow_LoadLibraryW
  (JNIEnv *env, jclass clazz, jstring dllName)
{
    jchar* _dllName = GetNullTerminatedStringChars(env, dllName);
    HMODULE lib = LoadLibraryW(_dllName);
    free(_dllName);
    return (jlong) (intptr_t) lib;
}

/*
 * Class:     com_sun_javafx_newt_windows_WindowsWindow
 * Method:    RegisterWindowClass
 * Signature: (Ljava/lang/String;J)J
 */
JNIEXPORT jlong JNICALL Java_com_sun_javafx_newt_windows_WindowsWindow_RegisterWindowClass
  (JNIEnv *env, jclass clazz, jstring appName, jlong hInstance)
{
    WNDCLASS* wc;
#ifndef UNICODE
    const char* _appName = NULL;
#endif

    wc = calloc(1, sizeof(WNDCLASS));
    /* register class */
    wc->style = CS_HREDRAW | CS_VREDRAW;
    wc->lpfnWndProc = (WNDPROC)wndProc;
    wc->cbClsExtra = 0;
    wc->cbWndExtra = 0;
    /* This cast is legal because the HMODULE for a DLL is the same as
       its HINSTANCE -- see MSDN docs for DllMain */
    wc->hInstance = (HINSTANCE) hInstance;
    wc->hIcon = NULL;
    wc->hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
    wc->hbrBackground = GetStockObject(BLACK_BRUSH);
    wc->lpszMenuName = NULL;
#ifdef UNICODE
    wc->lpszClassName = GetNullTerminatedStringChars(env, appName);
#else
    _appName = (*env)->GetStringUTFChars(env, appName, NULL);
    wc->lpszClassName = strdup(_appName);
    (*env)->ReleaseStringUTFChars(env, appName, _appName);
#endif
    if (!RegisterClass(wc)) {
        free(wc);
        return 0;
    }
    return (jlong) (intptr_t) wc;
}

/*
 * Class:     com_sun_javafx_newt_windows_WindowsWindow
 * Method:    CreateWindow
 * Signature: (Ljava/lang/String;JJIIII)J
 */
JNIEXPORT jlong JNICALL Java_com_sun_javafx_newt_windows_WindowsWindow_CreateWindow
  (JNIEnv *env, jobject obj, jstring windowClassName, jlong hInstance, jlong visualID,
                             jint jx, jint jy, jint defaultWidth, jint defaultHeight)
{
    const TCHAR* wndClassName = NULL;
    DWORD windowStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
    int x=(int)jx, y=(int)jy;
    int width=(int)defaultWidth, height=(int)defaultHeight;
    HWND window = NULL;

#ifdef UNICODE
    wndClassName = GetNullTerminatedStringChars(env, windowClassName);
#else
    wndClassName = (*env)->GetStringUTFChars(env, windowClassName, NULL);
#endif

    // FIXME: until we have valid values coming down from the
    // application code, use some default values
#ifdef UNDER_CE
    // Prefer to not have any surprises in the initial window sizing or placement
    width = GetSystemMetrics(SM_CXSCREEN);
    height = GetSystemMetrics(SM_CYSCREEN);
    x = y = 0;
#else
    x = CW_USEDEFAULT;
    y = 0;
    windowStyle |= WS_OVERLAPPEDWINDOW;
#endif

    (void) visualID; // FIXME: use the visualID ..

    window = CreateWindow(wndClassName, wndClassName, windowStyle,
                          x, y, width, height,
                          NULL, NULL,
                          (HINSTANCE) hInstance,
                          NULL);
#ifdef UNICODE
    free((void*) wndClassName);
#else
    (*env)->ReleaseStringUTFChars(env, windowClassName, wndClassName);
#endif
    
    if (window != NULL) {
#ifdef UNDER_CE
        SetWindowLong(window, GWL_USERDATA, (intptr_t) (*env)->NewGlobalRef(env, obj));
#else
        SetWindowLongPtr(window, GWLP_USERDATA, (intptr_t) (*env)->NewGlobalRef(env, obj));
#endif
        ShowWindow(window, SW_SHOWNORMAL);
    }
    return (jlong) (intptr_t) window;
}

/*
 * Class:     com_sun_javafx_newt_windows_WindowsWindow
 * Method:    DestroyWindow
 * Signature: (J)V
 */
JNIEXPORT void JNICALL Java_com_sun_javafx_newt_windows_WindowsWindow_DestroyWindow
  (JNIEnv *env, jobject obj, jlong window)
{
    DestroyWindow((HWND) window);
}

/*
 * Class:     com_sun_javafx_newt_windows_WindowsWindow
 * Method:    GetDC
 * Signature: (J)J
 */
JNIEXPORT jlong JNICALL Java_com_sun_javafx_newt_windows_WindowsWindow_GetDC
  (JNIEnv *env, jobject obj, jlong window)
{
    return (jlong) GetDC((HWND) window);
}

/*
 * Class:     com_sun_javafx_newt_windows_WindowsWindow
 * Method:    ReleaseDC
 * Signature: (JJ)V
 */
JNIEXPORT void JNICALL Java_com_sun_javafx_newt_windows_WindowsWindow_ReleaseDC
  (JNIEnv *env, jobject obj, jlong window, jlong dc)
{
    ReleaseDC((HWND) window, (HDC) dc);
}

/*
 * Class:     com_sun_javafx_newt_windows_WindowsWindow
 * Method:    setVisible0
 * Signature: (JZ)V
 */
JNIEXPORT void JNICALL Java_com_sun_javafx_newt_windows_WindowsWindow_setVisible0
  (JNIEnv *_env, jclass clazz, jlong window, jboolean visible)
{
    HWND hWnd = (HWND) (intptr_t) window;
    if (visible) {
        ShowWindow(hWnd, SW_SHOW);
    } else {
        ShowWindow(hWnd, SW_HIDE);
    }
}

/*
 * Class:     com_sun_javafx_newt_windows_WindowsWindow
 * Method:    DispatchMessages
 * Signature: (JI)V
 */
JNIEXPORT void JNICALL Java_com_sun_javafx_newt_windows_WindowsWindow_DispatchMessages
  (JNIEnv *_env, jclass clazz, jlong window, jint eventMask)
{
    int i = 0;
    MSG msg;
    BOOL gotOne;

    env = _env;

    if(eventMask<0) {
        eventMask *= -1;
        /* FIXME: re-select input mask 
            long xevent_mask_key = 0;
            long xevent_mask_ptr = 0;
            long xevent_mask_win = 0;
            if( 0 != ( eventMask & EVENT_MOUSE ) ) {
                xevent_mask_ptr |= ButtonPressMask|ButtonReleaseMask|PointerMotionMask;
            }
            if( 0 != ( eventMask & EVENT_KEY ) ) {
                xevent_mask_key |= KeyPressMask|KeyReleaseMask;
            }
            if( 0 != ( eventMask & EVENT_WINDOW ) ) {
                xevent_mask_win |= ExposureMask;
            }

            XSelectInput(dpy, w, xevent_mask_win|xevent_mask_key|xevent_mask_ptr);
        */
    }

    // Periodically take a break
    do {
        gotOne = PeekMessage(&msg, (HWND) window, 0, 0, PM_REMOVE);
        if (gotOne) {
            ++i;
            switch (msg.message) {
                case WM_CLOSE:
                case WM_DESTROY:
                case WM_SIZE:
                    if( ! ( eventMask & EVENT_WINDOW ) ) {
                        continue;
                    }
                    break;

                case WM_CHAR:
                case WM_KEYDOWN:
                case WM_KEYUP:
                    if( ! ( eventMask & EVENT_KEY ) ) {
                        continue;
                    }
                    break;

                case WM_LBUTTONDOWN:
                case WM_LBUTTONUP:
                case WM_MBUTTONDOWN:
                case WM_MBUTTONUP:
                case WM_RBUTTONDOWN:
                case WM_RBUTTONUP:
                case WM_MOUSEMOVE:
                    if( ! ( eventMask & EVENT_MOUSE ) ) {
                        continue;
                    }
                    break;
            }
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    } while (gotOne && i < 100);

    env = NULL;
}

/*
 * Class:     com_sun_javafx_newt_windows_WindowsWindow
 * Method:    setSize0
 * Signature: (JII)V
 */
JNIEXPORT void JNICALL Java_com_sun_javafx_newt_windows_WindowsWindow_setSize0
  (JNIEnv *env, jobject obj, jlong window, jint width, jint height)
{
    RECT r;
    HWND w = (HWND) window;
    GetWindowRect(w, &r);
    MoveWindow(w, r.left, r.top, width, height, TRUE);
    (*env)->CallVoidMethod(env, obj, sizeChangedID, (jint) width, (jint) height);
}

/*
 * Class:     com_sun_javafx_newt_windows_WindowsWindow
 * Method:    setFullScreen0
 * Signature: (JZ)Z
 */
JNIEXPORT jboolean JNICALL Java_com_sun_javafx_newt_windows_WindowsWindow_setFullScreen0
  (JNIEnv *env, jobject obj, jlong window, jboolean fullscreen)
{
#ifdef UNDER_CE
    int screenWidth;
    int screenHeight;
    HWND win = (HWND) window;

    if (fullscreen) {
        screenWidth  = GetSystemMetrics(SM_CXSCREEN);
        screenHeight = GetSystemMetrics(SM_CYSCREEN);
        // NOTE: looks like SHFullScreen and/or aygshell.dll is not available on the APX 2500 any more
        // First, hide all of the shell parts
        // SHFullScreen(win,
        //              SHFS_HIDETASKBAR | SHFS_HIDESIPBUTTON | SHFS_HIDESTARTICON);
        MoveWindow(win, 0, 0, screenWidth, screenHeight, TRUE);
        (*env)->CallVoidMethod(env, obj, sizeChangedID, (jint) screenWidth, (jint) screenHeight);
    } else {
        RECT rc;
        int width, height;

        // First, show all of the shell parts
        // SHFullScreen(win,
        //              SHFS_SHOWTASKBAR | SHFS_SHOWSIPBUTTON | SHFS_SHOWSTARTICON);
        // Now resize the window to the size of the work area
        SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, FALSE);
        width = rc.right - rc.left;
        height = rc.bottom - rc.top;
        MoveWindow(win, rc.left, rc.top, width, height, TRUE);
        (*env)->CallVoidMethod(env, obj, sizeChangedID, (jint) width, (jint) height);
    }
    return JNI_TRUE;
#else
    /* For the time being, full-screen not supported on the desktop */
    return JNI_FALSE;
#endif
}