All Downloads are FREE. Search and download functionalities are using the official Maven repository.

native-glass.lens.wm.LensWindowManager.c Maven / Gradle / Ivy

/*
 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
 
#include "input/LensInput.h"
#include "wm/LensWindowManager.h"
#include "com_sun_glass_events_ViewEvent.h"
#include "com_sun_glass_events_WindowEvent.h"
#include "com_sun_glass_events_MouseEvent.h"
#include "com_sun_glass_events_TouchEvent.h"
#include "lensRFB/lensRFB.h"

#include 
#include 
#include 

static pthread_mutex_t renderMutex = PTHREAD_MUTEX_INITIALIZER;

static int _mousePosX;
static int _mousePosY;

static jboolean _mousePressed = JNI_FALSE;
static jboolean _onDraggingAction = JNI_FALSE;
static NativeWindow _dragGrabbingWindow = NULL;

static jboolean isDnDStarted = JNI_FALSE;

static inline void render_lock() {
    pthread_mutex_lock(&renderMutex);
}

static inline void render_unlock() {
    pthread_mutex_unlock(&renderMutex);
}


static NativeScreen mainScreen;

static void lens_wm_rfbNotifyClearScreen();
static void lens_wm_clearScreen();
static void lens_wm_initRFB(JNIEnv *env);
static void lens_wm_rfbNotifyWindowUpdate(NativeWindow window,
                                          int width, int height);
static void lens_wm_windowCacheBounds(NativeWindow window);
static void lens_wm_windowUncacheBounds(NativeWindow window);
NativeWindow lens_wm_unsetFocusedWindow(JNIEnv *env, NativeWindow window);

//service functions to handle window state
static void lens_wm_windowMinimize(JNIEnv *env,
                                   NativeWindow window);
static void lens_wm_windowRestore(JNIEnv *env,
                                  NativeWindow window);
static void lens_wm_windowMaximize(JNIEnv *env,
                                   NativeWindow window);
static void lens_wm_windowEnterFullscreen(JNIEnv *env,
                                          NativeWindow window);

jboolean lens_wm_initialize(JNIEnv *env) {

    jboolean result;

    GLASS_LOG_FINE("Init device");
    result = glass_application_initialize(env);
    if (result) {
        GLASS_LOG_FINE("Init screen");
        mainScreen = lens_screen_initialize(env);
        if (mainScreen) {
            GLASS_LOG_FINE("Clearing screen");
            lens_wm_clearScreen();

            GLASS_LOG_FINE("Cursor init");
            fbCursorInitialize();

            lens_wm_initRFB(env);
            GLASS_LOG_FINE("Init input devices");
            result =  lens_input_initialize(env);
            if (!result) {
                GLASS_LOG_SEVERE("lens_input_initialize failed");
            }
        } else {
            GLASS_LOG_SEVERE("lens_screen_initialize() failed");
            result = JNI_FALSE;
        }
    } else {
        GLASS_LOG_SEVERE("glass_application_initialize() failed");
    }

    return result;
}

NativeScreen glass_screen_getMainScreen() {
    return mainScreen;
}

void lens_wm_getPointerPosition(int *pX, int *pY) {
    *pX = _mousePosX;
    *pY = _mousePosY;
}

void lens_wm_setPointerPosition(int x, int y) {
    _mousePosX = x;
    _mousePosY = y;
    fbCursorSetPosition(_mousePosX, _mousePosY);
}

LensResult lens_wm_notifyPlatformWindowRelease(JNIEnv *env, NativeWindow window) {

    GLASS_LOG_FINE("WM Window Relase window [%i]%p", window->id, window);

    if (window == lens_wm_getMouseWindow()) {
        // allow the next mouse motion to generate the ENTER
        lens_wm_setMouseWindow(NULL);
    }
    if (window == lens_wm_getGrabbedWindow()) {

        lens_wm_setGrabbedWindow(NULL); // don't bother with an event
    }
    if (window == glass_window_getFocusedWindow()) {
        glass_window_setFocusedWindow(NULL);
    }

    NativeWindow head = glass_window_list_getHead();
    if (head && head->view) {
        lens_wm_repaint(env, head);
    }

    return LENS_OK;
}

void lens_wm_repaint(JNIEnv *env, NativeWindow window) {
    render_lock();

    // remember clear could actually write pixels...
    lens_wm_clearScreen();

    if (window && window->view) {
        glass_application_notifyViewEvent(env,
                                          window->view,
                                          com_sun_glass_events_ViewEvent_REPAINT,
                                          window->currentBounds.x, window->currentBounds.y,
                                          window->currentBounds.width, window->currentBounds.height);
    }

    render_unlock();
}

//////////////////////////// WINDOW STATE MACHINE //////////////////////
static void lens_wm_windowMinimize(JNIEnv *env,
                                   NativeWindow window) {


    //"undo" previous state, if needed
    switch (window->state) {
        case NWS_MINIMIZED:
            GLASS_LOG_FINE("Nothing to do, skipping");
            return;
        case NWS_NORMAL:            
        case NWS_MAXIMIZED:
            //NOOP
            break;
        case NWS_FULLSCREEN:
            lens_wm_windowRestore(env, window);
            break;
        default:
            GLASS_LOG_SEVERE("Window is in unsupported NativeWindowState (%i)",
                              window->state);
    }

    //cache window bounds for restoration
    lens_wm_windowCacheBounds(window);

    //if supported let platform do the minimization 
    lens_platform_windowMinimize(env, window, JNI_TRUE);

    //update state
    window->state = NWS_MINIMIZED;

    //if window hold the focus, release it
    lens_wm_unsetFocusedWindow(env, window);


    //Stop rendering this window, because its minimized
    glass_application_RemoveWindowFromVisibleWindowList(env,window);

    //notify
    glass_application_notifyWindowEvent_resize(env,
                                               window,
                                               com_sun_glass_events_WindowEvent_MINIMIZE,
                                               window->cachedBounds.width,
                                               window->cachedBounds.height);
}


static void lens_wm_windowRestore(JNIEnv *env,
                                  NativeWindow window){

        
    //"undo" previous state, if needed
    switch (window->state) {
        case NWS_MINIMIZED:
            GLASS_LOG_FINE("Window is minimized -notifying platform minimize(false)");

            //notify platform
            lens_platform_windowMinimize(env, window, JNI_FALSE);
            if (window->isVisible) {
                //the window is restored and visible, add it to the window list
                //to resume rendering
                glass_application_addWindowToVisibleWindowList(env,window);
            }
            break;

        case NWS_NORMAL:
            GLASS_LOG_FINE("Nothing to do, skipping");
            return;
        case NWS_MAXIMIZED:
            //NOOP
            break;
        case NWS_FULLSCREEN:
            GLASS_LOG_FINE("Window in full screen notify FULLSCREEN_EXIT"
                           " (x=%i, y=%i, w=%i, h=%i)",
                           window->cachedBounds.x,
                           window->cachedBounds.y,
                           window->cachedBounds.width,
                           window->cachedBounds.height);

            //notify view it has existed full screen
            glass_application_notifyViewEvent(env,
                                              window->view,
                                              com_sun_glass_events_ViewEvent_FULLSCREEN_EXIT,
                                              window->cachedBounds.x,    
                                              window->cachedBounds.y,    
                                              window->cachedBounds.width,
                                              window->cachedBounds.height);
            break;
        default:
            GLASS_LOG_SEVERE("Window is in unsupported NativeWindowState (%i)",
                              window->state);
    }    

    //update state
    window->state = NWS_NORMAL;        
    

    //resize and relocate window to previous bounds
    glass_window_setBoundsImpl(env,
                               window,
                               window->cachedBounds.x,    
                               window->cachedBounds.y,    
                               window->cachedBounds.width,
                               window->cachedBounds.height,
                               JNI_TRUE,
                               JNI_TRUE,
                               JNI_FALSE);

    //restore bounds
    lens_wm_windowUncacheBounds(window);

    GLASS_LOG_FINE("notify window it has been restored");
    glass_application_notifyWindowEvent_resize(env,
                                               window,
                                               com_sun_glass_events_WindowEvent_RESTORE,
                                               window->currentBounds.width,
                                               window->currentBounds.height);

    GLASS_LOG_FINE("make sure window has the focus");
    lens_wm_setFocusedWindow(env, window);
}

static void lens_wm_windowMaximize(JNIEnv *env,
                                   NativeWindow window){

    //"undo" previous state, if needed
    switch (window->state) {
        case NWS_MINIMIZED:
            lens_wm_windowRestore(env, window);
            break;
        case NWS_NORMAL:
            //NOOP
            break;
        case NWS_MAXIMIZED:
            GLASS_LOG_FINE("Nothing to do, skipping");
            return;
        case NWS_FULLSCREEN:
            lens_wm_windowRestore(env, window);
            break;
        default:
            GLASS_LOG_SEVERE("Window is in unsupported NativeWindowState (%i)",
                              window->state);
    }

    /**
    * Window's max size can be limited, so try to extend the window 
    * to the buttom right corner of the screen from the current x,y 
    * coordinates. If the window will be extended beyond the screen 
    * boundaries, push the window towards the top left corner of the
    * screen. If no limits applied to the window it will capture the 
    * entire screen. 
    */

    //cache current window bounds for restoration
    lens_wm_windowCacheBounds(window);

    //get screen size
    NativeScreen screen = glass_screen_getMainScreen();
    int width = screen->width;
    int height = screen->height;
    int x = window->currentBounds.x;
    int y = window->currentBounds.y;    

    //check if window can occupy the entire screen
    if (glass_window_check_bounds(window, &width, &height)) {
        //window can be fully maximized, so we need to move it to
        //the top left corner
        x = 0;
        y = 0;
    } else {
       //window is restricted, check if new bounds are bigger
       //from current bounds
       if (width > window->currentBounds.width || 
           height > window->currentBounds.height){
           //calculate new x,y
           x = screen->width - width -1;
           y = screen->height - height -1;

       } 
    }

    GLASS_LOG_FINE("Maximized window bounds x=%i, y=%i, width =%i, height=%i",
                   x, y, width, height);

    //notify for bounds update
    glass_window_setBoundsImpl(env, window,
                               x, y,width, height,
                               JNI_TRUE, //update location
                               JNI_TRUE, // update size
                               JNI_FALSE /* update content */);

    //update state
    window->state = NWS_MAXIMIZED;

    //notify
    glass_application_notifyWindowEvent_resize(env,
                                               window,
                                               com_sun_glass_events_WindowEvent_MAXIMIZE,
                                               width,
                                               height);
    //make sure window has the focus
    lens_wm_setFocusedWindow(env, window);

}
static void lens_wm_windowEnterFullscreen(JNIEnv *env,
                                          NativeWindow window){
    //"undo" previous state, if needed
    switch (window->state) {
        case NWS_MINIMIZED:
            GLASS_LOG_FINE("Window is minimized - restoring");
            lens_wm_windowRestore(env, window);
            break;
        case NWS_NORMAL:
        case NWS_MAXIMIZED:
            //NOOP
            break;
        case NWS_FULLSCREEN:
            GLASS_LOG_FINE("Nothing to do, skipping");
            return;
        default:
            GLASS_LOG_SEVERE("Window is in unsupported NativeWindowState (%i)",
                              window->state);
    }

    //get screen
    NativeScreen screen = glass_screen_getMainScreen();

    //cache current window bounds for restoration
    lens_wm_windowCacheBounds(window);




    //set full screen dimensions 
    glass_window_setBoundsImpl(env,window,
                               0, 0,
                               screen->width,
                               screen->height,
                               JNI_TRUE, // update position
                               JNI_TRUE, // update size
                               JNI_FALSE); // update content

    GLASS_LOG_FINE("Notifying FULLSCREEN_ENTER on view[%p] window %i[%p]"
                   " x=%i, y=%i, w=%i, h=%i",
                   window->view,
                   window->id,
                   window,
                   window->currentBounds.x,
                   window->currentBounds.y,
                   window->currentBounds.width,
                   window->currentBounds.height);

    //notify view  
    glass_application_notifyViewEvent(env,
                                      window->view,
                                      com_sun_glass_events_ViewEvent_FULLSCREEN_ENTER,
                                      window->currentBounds.x,
                                      window->currentBounds.y,
                                      window->currentBounds.width,
                                      window->currentBounds.height);

    //make sure window has the focus
    lens_wm_setFocusedWindow(env, window);

    window->state = NWS_FULLSCREEN;


}


void glass_window_setBoundsImpl(JNIEnv *env,
                                NativeWindow window,
                                jint x, jint y, jint width, jint height,
                                jboolean needToUpdatePostion,
                                jboolean needToUpdateSize,
                                jboolean isContentSize) {


    jboolean windowHasBeenUpdated = JNI_FALSE;

    GLASS_LOG_FINE("setBoundsImpl on window %i[%p] x=%i y=%i w=%i h=%i"
                   " needToUpdatePostion=%s needToUpdateSize=%s isContentSize=%s"
                   " state=%s",
                   window->id, window,
                   x, y, width, height,
                   (needToUpdatePostion)?"true":"false",
                   (needToUpdateSize)?"true":"false",
                   (isContentSize)?"true":"false",
                   lens_window_getNativeStateName(window->state));

    if (isContentSize && !needToUpdateSize) {
        GLASS_LOG_FINE("Treating content size change as window size change");
        needToUpdateSize = isContentSize;
    }

    GLASS_LOG_FINER("currentW(%i) != newW(%i) || currentH(%i)!=newH(%i)",
                    window->currentBounds.width,
                    width,
                    window->currentBounds.height,
                    height );
    //handle resize if needed
    if (needToUpdateSize &&
        (window->currentBounds.width != width || window->currentBounds.height != height)) {

        GLASS_LOG_FINE("Updatating window %i[%p] size from %iX%i to %iX%i",
                       window->id,
                       window,
                       window->currentBounds.width,
                       window->currentBounds.height,
                       width,
                       height);

        window->currentBounds.width = width;
        window->currentBounds.height = height;

        glass_application_notifyWindowEvent_resize(env,window,
                                                   com_sun_glass_events_WindowEvent_RESIZE,
                                                   width,
                                                   height);
        
        windowHasBeenUpdated = JNI_TRUE;

    }

    GLASS_LOG_FINER("curentX(%i) != newX(%i) || currentY(%i)!=newY(%i)",
                    window->currentBounds.x,
                    x,
                    window->currentBounds.y,
                    y);
    //handle move if needed
    if (needToUpdatePostion && 
        (window->currentBounds.x != x || window->currentBounds.y != y)) {
        GLASS_LOG_FINE("Updating window %i[%p] location from %iX%i to %iX%i",
                       window->id,
                       window,
                       window->currentBounds.x,
                       window->currentBounds.y,
                       x,
                       y);
        window->currentBounds.x = x;
        window->currentBounds.y = y;

        glass_application_notifyWindowEvent_move(env,
                                                 window,
                                                 x,
                                                 y);

        windowHasBeenUpdated = JNI_TRUE;
    }

    if (!windowHasBeenUpdated) {
        //if function got the same sizes as the current ones, it means that
        //window have been restored.
        //happens when swapping stages with same params, for example.
        GLASS_LOG_FINE("Notifying window restore");
        glass_application_notifyWindowEvent_resize(env,window,
                                                   com_sun_glass_events_WindowEvent_RESTORE,
                                                   window->currentBounds.width,
                                                   window->currentBounds.height);
    }

    //some time the order of the window rendering concluded by the events is wrong.
    //so force repaint.
   lens_wm_repaint(env, window);
}


jboolean glass_window_setVisible(JNIEnv *env, NativeWindow window, jboolean visible) {

    GLASS_LOG_FINE("Setting window %i[%p](owner %i[%p]) from %s, to %s",
                   window->id,
                   window,
                   window->owner? window->owner->id : -1,
                   window->owner,
                   (window->isVisible)?"visible":"invisible",
                   (visible)?"visible":"invisible");


    lens_platform_windowSetVisible(env, window, visible);

    window->isVisible = visible;

    if (!visible) {
        //lose focus and grab
        lens_wm_unsetFocusedWindow(env, window);        
    } else {
        if (!window->owner) {
            //window become visible, grant it the focus if not a pop-up
            lens_wm_setFocusedWindow(env, window);
        }

        GLASS_LOG_FINE("notify window it has been restored");
        glass_application_notifyWindowEvent_resize(env,
                                                   window,
                                                   com_sun_glass_events_WindowEvent_RESTORE,
                                                   window->currentBounds.width,
                                                   window->currentBounds.height);
    }

    return JNI_TRUE;
}

jboolean glass_view_drawBegin(NativeView view) {
    GLASS_LOG_FINER("glass_view_drawBegin");
    render_lock();
    return JNI_TRUE;
}

void glass_view_drawEnd(NativeView view) {
    GLASS_LOG_FINER("glass_view_drawEnd");
    render_unlock();
}

jboolean glass_window_requestFocus(JNIEnv *env, NativeWindow window, jint focusType) {

    jboolean result;

    NativeWindow focusWindow;

    if (lens_wm_getGrabbedWindow()) {
        // no changing focus in a grab
        return JNI_FALSE;
    }

    focusWindow = glass_window_getFocusedWindow();

    if (!window) {
        GLASS_LOG_WARNING("null window passes the glass_window_requestFocus");
        return JNI_FALSE;
    }

    if (window == focusWindow) {
        // no change, no notification ?
        GLASS_LOG_WARNING("Focus requested on current focus window");
        return JNI_TRUE;
    }

    if (!window->isFocusable) {
        GLASS_LOG_WARNING("Focus requested on isFocusable=false");
        return JNI_FALSE;
    }

    if (!window->isEnabled) {
        GLASS_LOG_WARNING("Focus requested on isEnabled=false");
        return JNI_FALSE;
    }

    lens_wm_setFocusedWindow(env, window);

    return JNI_TRUE;
}

jboolean glass_window_setFocusable(JNIEnv *env,
                                   NativeWindow window,
                                   jboolean isFocusable) {

    NativeWindow focusWindow;

    if (window->isFocusable == isFocusable) {
        // no change, so we can punt
        return JNI_TRUE;
    }

    focusWindow = glass_window_getFocusedWindow();
    if (!isFocusable && focusWindow == window) {
        lens_wm_setFocusedWindow(env, NULL);
        GLASS_LOG_WARNING("isFocusable(false) on focus owner, cascade ?");
    }

    window->isFocusable = isFocusable;

    return JNI_TRUE;
}

jboolean glass_window_setBackground(NativeWindow window,
                                    jfloat red,
                                    jfloat green,
                                    jfloat blue) {
    GLASS_LOG_WARNING("unimplemented glass_window_setBackground\n");
    return JNI_TRUE;
}

void glass_window_toFront(JNIEnv *env, NativeWindow window) {
    if (glass_window_list_toFront(window)) {
        lens_wm_repaint(env, window);
    }
}

void glass_window_toBack(JNIEnv *env, NativeWindow window) {
    if (glass_window_list_toBack(window)) {
        lens_wm_repaint(env, window);
    }
}

jboolean glass_window_grabFocus(JNIEnv *env, NativeWindow window) {

    if (window == lens_wm_getGrabbedWindow()) {
        //this is OK per spec
        GLASS_LOG_FINE("RE-GRAB on %p root %p\n", window, window->root);
        return JNI_TRUE;
    }
    
    if (NULL == lens_wm_getGrabbedWindow() &&
            window == glass_window_getFocusedWindow()) {
        // we allow the grab, note: focus is also checked in Java.
        GLASS_LOG_FINE("GRAB on %p root %p\n", window, window->root);
        lens_wm_setGrabbedWindow(window);
        return JNI_TRUE;
    }

    // should not be able to happen
    GLASS_LOG_FINE("ERROR NO-GRAB on %p\n", window);
    return JNI_FALSE;
}

/**
 * This functions will check if the given window is grabbed and
 * ungrab it if necessary. Note: may also be called from mouse 
 * handling 
 */
void glass_window_ungrabFocus(JNIEnv *env, NativeWindow window) {

    if (window == NULL) {
        GLASS_LOG_FINER("window=NULL - Nothing to do");
        return;
    }

    if (window != lens_wm_getGrabbedWindow()) {
        GLASS_LOG_FINE("Given window is not grabbed, ignore");
        return;
    }

    GLASS_LOG_FINE("Ungrabbing window %i[%p]",
                   window?window->id : -1,
                   window);

    lens_wm_setGrabbedWindow(NULL);

    //notify the UNGRAB
    glass_application_notifyWindowEvent(env,
                                        window,
                                        com_sun_glass_events_WindowEvent_FOCUS_UNGRAB);
}

void glass_view_setParent(JNIEnv *env,
                          NativeWindow parent,
                          NativeView view) {
    NativeWindow oldParent = view->parent;

    if (oldParent && oldParent->view) {
        GLASS_LOG_FINE("Notifying old view removed");
        glass_application_notifyViewEvent(env,
                                          oldParent->view,
                                          com_sun_glass_events_ViewEvent_REMOVE,
                                          0, 0, 0, 0);
        view->parent = NULL;
    }

    GLASS_LOG_FINE("Setting new owner, window %d [%p], for view %p",
                   parent ? (signed int)parent->id : - 1,
                   parent,
                   view);
    view->parent = parent; //may be null

    if (parent && parent->view) {
        GLASS_LOG_FINE("Notifying view it has been added %p", parent->view);
        glass_application_notifyViewEvent(env,
                                          parent->view,
                                          com_sun_glass_events_ViewEvent_ADD,
                                          0, 0, 0, 0);
    }
}

void lens_wm_shutdown(JNIEnv *env) {
    lens_platform_shutdown(env);
}

jboolean glass_window_setLevel(NativeWindow window, int level) {
    GLASS_LOG_WARNING("unimplemented glass_window_setLevel\n");
    return JNI_TRUE;
}

jboolean glass_window_setMinimumSize(JNIEnv *env,
                                     NativeWindow window,
                                     jint width, jint height) {
    window->minWidth  = width;
    window->minHeight = height;

    width = window->currentBounds.width;
    height = window->currentBounds.height;

    glass_window_check_bounds(window, &width, &height);

    if (width != window->currentBounds.width ||
            height != window->currentBounds.height) {
        glass_window_setBoundsImpl(env,
                                   window,
                                   0, 0, width, height,
                                   JNI_FALSE,  // position
                                   JNI_TRUE,   // size
                                   JNI_FALSE); // contentSize
    }

    return JNI_TRUE;
}

jboolean glass_window_setMaximumSize(JNIEnv *env,
                                     NativeWindow window,
                                     jint width, jint height) {
    window->maxWidth  = width;
    window->maxHeight = height;

    width = window->currentBounds.width;
    height = window->currentBounds.height;

    glass_window_check_bounds(window, &width, &height);

    if (width != window->currentBounds.width ||
            height != window->currentBounds.height) {
        glass_window_setBoundsImpl(env,
                                   window,
                                   0, 0, width, height,
                                   JNI_FALSE, // position
                                   JNI_TRUE,  // size
                                   JNI_FALSE);// contentSize
    }

    return JNI_TRUE;
}

jboolean glass_view_enterFullscreen(JNIEnv *env,
                                    NativeView view,
                                    jboolean animate,
                                    jboolean keepRatio,
                                    jboolean hideCursor) {

    NativeWindow window = view->parent;

    if (window == NULL) {
        GLASS_LOG_WARNING("Full screen request on a view(%p) with no parent window, abort",
                          view);
        return JNI_FALSE;
    }

    GLASS_LOG_FINE("Enter full screen request on view %p, window %i[%p]",
                   view, window->id, window);

   /**
    * animate, keepRatio ration and hideCursor are currently stubbed
    * to false in WindowStage.java, which is the only caller for 
    * this API. 
    * Ignoring them for now 
    */
    lens_wm_windowEnterFullscreen(env, window);

    return JNI_TRUE;

}

jboolean glass_view_exitFullscreen(JNIEnv *env,
                                   NativeView view,
                                   jboolean animate) {

    NativeWindow window = view->parent;

    if (window == NULL) {
        GLASS_LOG_WARNING("Exit full screen request on a view(%p) with no parent"
                          " window, abort",
                          view);
        return JNI_FALSE;
    }

    GLASS_LOG_FINE("Exit full screen request on view %p, window %i[%p]",
                   view, window->id, window);

    /**
    * WindowStage.applyFullScreen() always sets the animate 
    * parameter to false when calling enterFullScreen on its View, 
    * in WindowStage.java, which is the only caller for this API. 
    * Ignoring it for now.
    */

    lens_wm_windowRestore(env, window);

    return JNI_TRUE;
}

jboolean glass_window_minimize(JNIEnv *env,
                               NativeWindow window,
                               jboolean toMinimize) {
    
    GLASS_LOG_FINE("Minimize window %i[%p] toMinimize=%s",
                   window->id,
                   window,
                   (toMinimize)?"true":"false");

    if (toMinimize) {
        lens_wm_windowMinimize(env, window);
    } else {
        lens_wm_windowRestore(env, window);
    }
    
    return JNI_TRUE;

}

jboolean glass_window_maximize(JNIEnv *env,
                               NativeWindow window,
                               jboolean toMaximize,
                               jboolean isMaximized) {
    GLASS_LOG_FINE("Maximize window %i[%p] toMaximize=%s isMaximized=%s",
                   window->id,
                   window,
                   (toMaximize)?"true":"false",
                   (isMaximized)?"true":"false");
    jboolean result = JNI_TRUE;

    if (toMaximize && !isMaximized) {
        lens_wm_windowMaximize(env, window);
    } else if (!toMaximize && isMaximized) {
        lens_wm_windowRestore(env, window);
    } else {
        GLASS_LOG_WARNING("Maximize request with bad arguments");
        result = JNI_FALSE;
    }
    return result;
}

NativeWindow glass_window_findWindowAtLocation(int absX, int absY,
                                               int *pRelX, int *pRelY) {

    NativeWindow w = glass_window_list_getTail();
    while (w) {
        GLASS_LOG_FINEST("Window %d[%p] isVisible=%s, state=%s",
                       w->id, w,
                       w->isVisible?"true" : "false",
                       lens_window_getNativeStateName(w->state));
        if (w->isVisible && w->state != NWS_MINIMIZED) {
            if (absX >= w->currentBounds.x &&
                    absX < w->currentBounds.x + w->currentBounds.width &&
                    absY >= w->currentBounds.y &&
                    absY < w->currentBounds.y + w->currentBounds.height &&
                    w->isEnabled) {

                *pRelX = absX - w->currentBounds.x;
                *pRelY = absY - w->currentBounds.y;
                GLASS_LOG_FINER(
                    "Absolute coordinates %i,%i are on window %i[%p] "
                    "as relative coordinates %i,%i",
                    absX, absY, w->id, w, *pRelX, *pRelY);
                return w;
            }
        } else {
            GLASS_LOG_FINER("Skipping invisible window %i[%p]",
                           w->id, w);
        }
        w = w->previousWindow;
    }
    GLASS_LOG_FINER("Absolute coordinates %i,%i are not on a window",
                    absX, absY);
    return NULL;
}

NativeWindow grabbedWindow = NULL;

NativeWindow lens_wm_getGrabbedWindow() {
    return grabbedWindow;
}

void lens_wm_setGrabbedWindow(NativeWindow window) {
    grabbedWindow = window;
}


static void handleClickOrTouchEvent(JNIEnv *env, int xabs, int yabs) {

    int relX, relY;
    NativeWindow window = glass_window_findWindowAtLocation(xabs, yabs,
                          &relX, &relY);

    // if we have a grabbed window, check to see if this breaks the grab
    if (grabbedWindow != NULL) {
        if ((window == NULL) ||
                (window->root != grabbedWindow->root)) {
            glass_window_ungrabFocus(env, grabbedWindow);
        }
    }

    if (window != NULL) {
        NativeWindow focusedWindow = glass_window_getFocusedWindow();
        // Will this cause a focus change ?
        if (focusedWindow && window->root != focusedWindow->root) {
            lens_wm_setFocusedWindow(env, window);
        }
    }
}

void lens_wm_notifyScrollEvent(JNIEnv *env, int xabs, int yabs, int step) {

    int relX, relY;
    NativeWindow window = glass_window_findWindowAtLocation(xabs, yabs,
                          &relX, &relY);
    if (window != NULL) {
        glass_application_notifyScrollEvent(env, window, relX, relY,
                                            xabs, yabs, 0.0, step);
    }

}

// check for window grab then forward event to application.
// check for focus changes and handle them.
void lens_wm_notifyButtonEvent(JNIEnv *env,
                               jboolean pressed,
                               int button,
                               int xabs, int yabs) {

    int relX, relY;
    NativeWindow window;

    //cache new coordinates
    _mousePosX = xabs;
    _mousePosY = yabs;

    window = glass_window_findWindowAtLocation(xabs, yabs,
                          &relX, &relY);

    _mousePressed = pressed;

    if (_onDraggingAction) {
        if (pressed) {
            GLASS_LOG_SEVERE("Press event while on drag !");
        }

        if (_dragGrabbingWindow != NULL) {

            relX = xabs - _dragGrabbingWindow->currentBounds.x;
            relY = yabs - _dragGrabbingWindow->currentBounds.y;
            glass_application_notifyMouseEvent(env,
                                               _dragGrabbingWindow,
                                               com_sun_glass_events_MouseEvent_UP,
                                               relX, relY, xabs, yabs,
                                               button);

        }

        _onDraggingAction = JNI_FALSE;
        _dragGrabbingWindow = NULL;

    } else {
        if (window != NULL) {
            GLASS_LOG_FINEST("glass_wm_notifyButtonEvent sending to  %p pressed=%d, button=%d  %d,%d, %d, %d ",
                             window,
                             pressed, button,
                             relX, relY, xabs, yabs);

            // pass on the event to Java.
            glass_application_notifyMouseEvent(env,
                                               window,
                                               pressed ? com_sun_glass_events_MouseEvent_DOWN :
                                               com_sun_glass_events_MouseEvent_UP,
                                               relX, relY, xabs, yabs,
                                               button);
        }
    }

    handleClickOrTouchEvent(env, xabs, yabs);

}


// check for window grab then forward event to application.
// check for focus changes and handle them.
void lens_wm_notifyTouchEvent(JNIEnv *env,
                              jint state,
                              int id,
                              int xabs, int yabs) {

    int relX, relY;
    NativeWindow window;

    //cache new coordinates
    _mousePosX = xabs;
    _mousePosY = yabs;

    window = glass_window_findWindowAtLocation(xabs, yabs,
                          &relX, &relY);

    lens_wm_setMouseWindow(window);

    if (state == com_sun_glass_events_TouchEvent_TOUCH_PRESSED) {
        _mousePressed = JNI_TRUE;
    } else if (state == com_sun_glass_events_TouchEvent_TOUCH_RELEASED) {
        _mousePressed = JNI_FALSE;
    } else {
        GLASS_LOG_SEVERE("Unexpected state %d", state);
    }

    if (_mousePressed && window) {
        // Pressed on window
        glass_application_notifyMouseEvent(env,
                                           window,
                                           com_sun_glass_events_MouseEvent_ENTER,
                                           relX, relY, xabs, yabs,
                                           com_sun_glass_events_MouseEvent_BUTTON_NONE);
        glass_application_notifyTouchEvent(env,
                                           window,
                                           com_sun_glass_events_TouchEvent_TOUCH_PRESSED,
                                           id,
                                           relX, relY, xabs, yabs);
    }


    if (!_mousePressed) {
        if (!_onDraggingAction && window) {
            //Press-release on a window without a move in between.
            glass_application_notifyTouchEvent(env,
                                               window,
                                               com_sun_glass_events_TouchEvent_TOUCH_RELEASED,
                                               id,
                                               relX, relY, xabs, yabs);

        } else if (_onDraggingAction && _dragGrabbingWindow != NULL) {
            //Finished drag that started on actual window.
            relX = xabs - _dragGrabbingWindow->currentBounds.x;
            relY = yabs - _dragGrabbingWindow->currentBounds.y;
            glass_application_notifyTouchEvent(env,
                                               _dragGrabbingWindow,
                                               com_sun_glass_events_TouchEvent_TOUCH_RELEASED,
                                               id,
                                               relX, relY, xabs, yabs);
        }

        _onDraggingAction = JNI_FALSE;
        _dragGrabbingWindow = NULL;

    }

    handleClickOrTouchEvent(env, xabs, yabs);

}


void lens_wm_notifyMotionEvent(JNIEnv *env, int mousePosX, int mousePosY, int isTouch, int touchId) {

    int relX, relY;
    int reportMove = 0;
    GLASS_LOG_FINEST("Motion event: x=%03d, y=%03d", mousePosX, mousePosY);
    //cache new coordinates
    _mousePosX = mousePosX;
    _mousePosY = mousePosY;

    //update cursor if event came from pointer device
    if (!isTouch) {
        fbCursorSetPosition(mousePosX, mousePosY);
    }


    if (_mousePressed && !_onDraggingAction && !isDnDStarted) {
        GLASS_LOG_FINE("Starting native mouse drag");
        _onDraggingAction = JNI_TRUE;
        _dragGrabbingWindow = lens_wm_getMouseWindow();
    }
    
    NativeWindow window = glass_window_findWindowAtLocation(
                              _mousePosX, _mousePosY, &relX, &relY);

    GLASS_LOG_FINER("Motion event on window %i[%p] absX=%i absY=%i, relX=%i, relY=%i",
                    (window)?window->id:-1,
                    window,
                    _mousePosX, _mousePosY, relX, relY);


    NativeWindow lastMouseWindow = lens_wm_getMouseWindow();

    GLASS_LOG_FINER("lastMouseWindow = %i[%p]",
                    (lastMouseWindow)?lastMouseWindow->id:-1,
                    lastMouseWindow);

    //Send EXIT/ENTER events
    if (_onDraggingAction && _dragGrabbingWindow != NULL) {
        if (window != _dragGrabbingWindow &&
                _dragGrabbingWindow == lastMouseWindow) {
            relX = _mousePosX - _dragGrabbingWindow->currentBounds.x;
            relY = _mousePosY - _dragGrabbingWindow->currentBounds.y;
            GLASS_LOG_FINER("MouseEvent_EXIT on dragGrabbingWindow %i[%p]",
                            (_dragGrabbingWindow)?_dragGrabbingWindow->id:-1,
                            _dragGrabbingWindow);

            glass_application_notifyMouseEvent(env,
                                               _dragGrabbingWindow,
                                               com_sun_glass_events_MouseEvent_EXIT,
                                               relX, relY, _mousePosX, _mousePosY,
                                               com_sun_glass_events_MouseEvent_BUTTON_NONE);
        }

        if (window == _dragGrabbingWindow &&
                window != lastMouseWindow) {
            GLASS_LOG_FINER("MouseEvent_ENTER on dragGrabbingWindow %i[%p]",
                            (_dragGrabbingWindow)?_dragGrabbingWindow->id:-1,
                            _dragGrabbingWindow);
            glass_application_notifyMouseEvent(env,
                                               _dragGrabbingWindow,
                                               com_sun_glass_events_MouseEvent_ENTER,
                                               relX, relY, _mousePosX, _mousePosY,
                                               com_sun_glass_events_MouseEvent_BUTTON_NONE);
        }
    }

    if (!_onDraggingAction) {
        if (window != lastMouseWindow) {
            if (lastMouseWindow) {
                // Exited from lastMouseWindow
                relX = _mousePosX - lastMouseWindow->currentBounds.x;
                relY = _mousePosY - lastMouseWindow->currentBounds.y;

                GLASS_LOG_FINER("MouseEvent_EXIT on lastMouseWindow %i[%p]",
                               (lastMouseWindow)?lastMouseWindow->id:-1,
                               lastMouseWindow);

                glass_application_notifyMouseEvent(env,
                                                   lastMouseWindow,
                                                   com_sun_glass_events_MouseEvent_EXIT,
                                                   relX, relY, _mousePosX, _mousePosY,
                                                   com_sun_glass_events_MouseEvent_BUTTON_NONE);
            }
            if (window) {
                // Enter into window
                GLASS_LOG_FINER("MouseEvent_ENTER on window %i[%p]",
                               (window)?window->id:-1,
                               window);

                glass_application_notifyMouseEvent(env,
                                                   window,
                                                   com_sun_glass_events_MouseEvent_ENTER,
                                                   relX, relY, _mousePosX, _mousePosY,
                                                   com_sun_glass_events_MouseEvent_BUTTON_NONE);

            }

        }
    }

    lens_wm_setMouseWindow(window);

    //Send the move event
    if (_onDraggingAction && _dragGrabbingWindow != NULL) {

        relX = _mousePosX - _dragGrabbingWindow->currentBounds.x;
        relY = _mousePosY - _dragGrabbingWindow->currentBounds.y;

        if (isTouch) {
            glass_application_notifyTouchEvent(env,
                                               _dragGrabbingWindow,
                                               com_sun_glass_events_TouchEvent_TOUCH_MOVED,
                                               touchId , relX, relY, _mousePosX, _mousePosY);
        }

        GLASS_LOG_FINEST("MouseEvent_MOVE on window %i[%p]",
                       (_dragGrabbingWindow)?_dragGrabbingWindow->id:-1,
                       _dragGrabbingWindow);
        glass_application_notifyMouseEvent(env,
                                           _dragGrabbingWindow,
                                           com_sun_glass_events_MouseEvent_MOVE,
                                           relX, relY, _mousePosX, _mousePosY,
                                           com_sun_glass_events_MouseEvent_BUTTON_NONE);


    } else if (!_onDraggingAction && window != NULL) {

        if (isTouch) {
            glass_application_notifyTouchEvent(env,
                                               window,
                                               com_sun_glass_events_TouchEvent_TOUCH_MOVED,
                                               touchId , relX, relY, _mousePosX, _mousePosY);
        }

         GLASS_LOG_FINEST("MouseEvent_MOVE on window %i[%p]",
                       (window)?window->id:-1,
                       window);
        glass_application_notifyMouseEvent(env,
                                           window,
                                           com_sun_glass_events_MouseEvent_MOVE,
                                           relX, relY, _mousePosX, _mousePosY,
                                           com_sun_glass_events_MouseEvent_BUTTON_NONE);

    }

}




/*
 * set focus to the specified window,
 * providing FOCUS_LOST as needed to previous
 */
void lens_wm_setFocusedWindow(JNIEnv *env, NativeWindow window) {

    NativeWindow _focusedWindow = glass_window_getFocusedWindow();    
 
    if (window != _focusedWindow) {

      GLASS_LOG_FINE("Window %i[%p] is focused. Window %i[%p] requesting focus",
             (_focusedWindow)?_focusedWindow->id:-1,
             _focusedWindow,
             (window)?window->id:-1,
             window);

        if (_focusedWindow) {

            //Release the grab if window holds it
            glass_window_ungrabFocus(env, window); /* function will print the result*/

            GLASS_LOG_FINE("Notifying window %i[%p] focus lost ",
                           _focusedWindow->id,
                           _focusedWindow);

            glass_application_notifyWindowEvent(env,
                                                _focusedWindow,
                                                com_sun_glass_events_WindowEvent_FOCUS_LOST);
        }

        glass_window_setFocusedWindow(window);

        if (window != NULL) {
            GLASS_LOG_FINE("Notifying window %i[%p] focus gained ",
                           window->id,
                           window);

            glass_application_notifyWindowEvent(env,
                                                window,
                                                com_sun_glass_events_WindowEvent_FOCUS_GAINED);
        }
    } else {
        GLASS_LOG_FINE("Window %i[%p] is already focused - ignore",
                       (window)?window->id:-1,
                       window);
    }

}

/**
 * Check if this window hold the focus or the grab. Loose them 
 * if required and give focus to the next focusable and visible
 * window 
 * 
 * @param env 
 * @param window the window to unset 
 * @return the new focused window (may be NULL) 
 */
NativeWindow lens_wm_unsetFocusedWindow(JNIEnv *env, NativeWindow window){

    GLASS_LOG_FINE("unsetting focus for window %i[%p]",
                   window->id, window);
    

    NativeWindow _focusedWindow = glass_window_getFocusedWindow();

    if (window == _focusedWindow) {
        //if this window hold the grab, release it
        GLASS_LOG_FINE("Check if this window holds the grab");
        glass_window_ungrabFocus(env, window); /* function will print the result*/

        GLASS_LOG_FINE("Releasing the focus");
        lens_wm_setFocusedWindow(env, NULL);

        _focusedWindow = NULL;

        //search for the next focusable window
        NativeWindow w = glass_window_list_getTail();

        while (w) {
            if (w->isVisible && w->state != NWS_MINIMIZED) {
                if (!w->owner && w->isFocusable) {
                    GLASS_LOG_FINE("Granting window %i[%p] the focus",
                                   w->id, w);

                    lens_wm_setFocusedWindow(env, w);
                    _focusedWindow = w;
                    break;
                }
            }
            w = w->previousWindow;
        }
    }else {
        GLASS_LOG_FINE("Window %i[%p] doesn't have the focus",
                       window?window->id : -1,
                       window);
    }

    return _focusedWindow;
}

/*
 * MouseWindow
 * The window that currently has the mouse in it.
 * Note, this may be NULL.
 */
static NativeWindow mouseWindow = NULL;

NativeWindow lens_wm_getMouseWindow() {
    return mouseWindow;
}

LensResult lens_wm_setMouseWindow(NativeWindow window) {
    mouseWindow = window;
    return LENS_OK;
}


static void lens_wm_clearScreen() {
    glass_screen_clear();
    lens_wm_rfbNotifyClearScreen();
}

void lens_wm_notifyWindowUpdate(NativeWindow window, int width, int height) {
    lens_wm_rfbNotifyWindowUpdate(window, width, height);
}


static void lens_wm_windowCacheBounds(NativeWindow window) {
    window->cachedBounds.x = window->currentBounds.x;
    window->cachedBounds.y = window->currentBounds.y;
    window->cachedBounds.width = window->currentBounds.width;
    window->cachedBounds.height = window->currentBounds.height;
}

static void lens_wm_windowUncacheBounds(NativeWindow window) {
    window->currentBounds.x = window->cachedBounds.x;
    window->currentBounds.y = window->cachedBounds.y;
    window->currentBounds.width = window->cachedBounds.width;
    window->currentBounds.height = window->cachedBounds.height;

}


void notify_lens_wm_DnDStarted() {
    isDnDStarted = JNI_TRUE;
    GLASS_LOG_FINE("DnD is active");

    //reset mouse drag as DnD events has higher priority
    _onDraggingAction = JNI_FALSE;
    _dragGrabbingWindow = NULL;
}

void notify_lens_wm_DnDEnded() {
    isDnDStarted = JNI_FALSE;
    GLASS_LOG_FINE("DnD has ended");
}

//// RFB support
static void lens_wm_initRFB(JNIEnv *env) {
#ifdef USE_RFB
    lens_rfb_init(env);
#endif
}
static void lens_wm_rfbNotifyClearScreen() {
#ifdef USE_RFB
    NativeScreen screen = glass_screen_getMainScreen();
    lens_rfb_notifyDirtyRegion(0, 0, screen->width, screen->height);
#endif
}
static void lens_wm_rfbNotifyWindowUpdate(NativeWindow window,
                                          int width, int height) {
#ifdef USE_RFB
    NativeScreen screen = glass_screen_getMainScreen();
    int x = window->currentBounds.x;
    int y = window->currentBounds.y;

    width = x + width > screen->width ? screen->width - x : width;
    height = y + height > screen->height ? screen->height - y : height;

    lens_rfb_notifyDirtyRegion(x, y, width, height);
#endif
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy