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

native-glass.lens.wm.screen.fbdevScreen.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 "LensCommon.h"
#include "input/LensInput.h"
#include "wm/LensWindowManager.h"
#include "com_sun_glass_events_ViewEvent.h"
#include "com_sun_glass_events_WindowEvent.h"

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define FB_DEVICE "/dev/fb0"

extern int useDispman;
extern void load_bcm_symbols();
static int loadedBcm = 0;
#ifdef USE_DISPMAN
extern jboolean dispman_glass_robot_screen_capture(jint x, jint y,
                                                   jint width, jint height,
                                                   jint *pixels);
#endif


static struct _NativeScreen fbScreen;

/* fbScanLine is a buffer large enough to hold a row of pixels in the
 * framebuffer format. It is only used in the final blit to the framebuffer,
 * but is pre-allocated at startup in mat_initialize. */
static unsigned char *fbScanLine = NULL;
static int fbScanLineSize = 0;

#define FB_DEVICE "/dev/fb0"
static int windowIndex = 1;


jboolean glass_application_initialize(JNIEnv *env) {
    //nothing to do
    return JNI_TRUE;
}

LensResult glass_window_PlatformWindowData_create(JNIEnv *env,
                                                  NativeWindow window) {

    window->id = windowIndex++;
    window->data = NULL; //no platform specific data

    return LENS_OK;
}

LensResult glass_view_PlatformViewData_create(NativeView view) {
    view->data = NULL;
    return LENS_OK;
}

LensResult glass_view_PlatformViewRelease(JNIEnv *env, NativeView view) {
    // No data to free
    return LENS_OK;
}

LensResult glass_window_PlatformWindowRelease(JNIEnv *env, NativeWindow window) {

    // No data to free
    return LENS_OK;
}

jboolean glass_window_setAlpha(JNIEnv *env, NativeWindow window, float alpha) {    
    lens_wm_repaint(env, window);
    return JNI_TRUE;
}

void glass_pixel_attachIntBuffer(JNIEnv *env,
                                 jint *srcPixels,
                                 NativeWindow fbWindow,
                                 jint width,
                                 jint height, int offset) {
    FILE *fb;
    NativeScreen fbScreen = glass_screen_getMainScreen();
    
    GLASS_LOG_FINE("fopen(%s, \"w\") to write %ix%i pixels at depth %i",
                   FB_DEVICE, width, height, fbScreen->depth);
    fb = fopen(FB_DEVICE, "w");
    if (fb == NULL) {
        GLASS_LOG_SEVERE("FB: Cannot open framebuffer for writing");
        return;
    }
    switch (fbScreen->depth) {
            /* To draw a window:
             * 1. Blit blank lines above the window.
             * 2. Blit the window
             * 3. Blit blank lines below the window
             * All blitting is done with a scan line buffer, that can in the
             * future be used to compose multiple windows before the final
             * write to the framebuffer device.
             */
        case 32: {
            int y;
            memset(fbScanLine, 0, fbScanLineSize);
            for (y = 0; y < fbWindow->currentBounds.y; y++) {
                fwrite(fbScanLine, 4, fbScanLineSize >> 2, fb);
            }
            for (y = 0; y < fbWindow->currentBounds.height; y++) {
                // pixels are written unmodified to a 32-bit framebuffer
                memcpy(
                    fbScanLine + (fbWindow->currentBounds.x << 2),
                    srcPixels + fbWindow->currentBounds.width * y,
                    fbWindow->currentBounds.width << 2);
                fwrite(fbScanLine, 4, fbScanLineSize >> 2, fb);
            }
            memset(fbScanLine, 0, fbScanLineSize);
            for (y = fbWindow->currentBounds.x + fbWindow->currentBounds.height; y < fbScreen->height; y++) {
                fwrite(fbScanLine, 4, fbScanLineSize >> 2, fb);
            }
            break;
        }
        case 16: {
            int y;
            memset(fbScanLine, 0, fbScanLineSize);
            for (y = 0; y < fbWindow->currentBounds.y; y++) {
                fwrite(fbScanLine, 2, fbScanLineSize >> 1, fb);
            }
            for (y = 0; y < fbWindow->currentBounds.height; y++) {
                // pixels are packed from 32-bit to 16-bit before writing
                int x;
                jchar *destPixels = (jchar *)
                                    (fbScanLine + (fbWindow->currentBounds.x << 1));

                for (x = 0; x < fbWindow->currentBounds.width; x++) {
                    jint pixel = *srcPixels++;
                    *destPixels++ = ((pixel >> 8) & 0xf800)
                                    | ((pixel >> 5) & 0x7e0)
                                    | ((pixel >> 3) & 0x1f);
                }
                fwrite(fbScanLine, 2, fbScanLineSize >> 1, fb);
            }
            memset(fbScanLine, 0, fbScanLineSize);
            for (y = fbWindow->currentBounds.y + fbWindow->currentBounds.height; y < fbScreen->height; y++) {
                fwrite(fbScanLine, 2, fbScanLineSize >> 1, fb);
            }
            break;
        }
        default:
            GLASS_LOG_SEVERE("Cannot write to screen of depth %i", fbScreen->depth);
    }
    GLASS_LOG_FINE("fclose(%s)", FB_DEVICE);
    fclose(fb);
}


void glass_screen_clear() {
#ifdef ISEGLFB
    //noop for eglfb as screen is managed in prism
    return;
#else
    FILE *fb;
    int y;
    NativeScreen fbScreen = glass_screen_getMainScreen();

    GLASS_LOG_FINE("fopen(%s, \"w\") to clear the background",
                   FB_DEVICE);
    fb = fopen(FB_DEVICE, "w");
    if (fb == NULL) {
        GLASS_LOG_SEVERE("FB: Cannot open framebuffer for writing");
        return;
    }

    memset(fbScanLine, 0, fbScanLineSize);
    switch (fbScreen->depth) {
        case 32: 
            for (y = 0; y < fbScreen->height; y++) {
                fwrite(fbScanLine, 4, fbScanLineSize >> 2, fb);
            }
            GLASS_LOG_FINE("Screen cleared (32bit mode)");
        
            break;
        case 16: 
            for (y = 0; y < fbScreen->height; y++) {
                fwrite(fbScanLine, 2, fbScanLineSize >> 1, fb);
            }
            GLASS_LOG_FINE("Screen cleared (16bit mode)");
        
            break;
        default:
            GLASS_LOG_SEVERE("Cannot write to screen of depth %i", fbScreen->depth);
    }

    GLASS_LOG_FINE("fclose(%s)", FB_DEVICE);
    fclose(fb);
#endif
}


void lens_platform_shutdown(JNIEnv *env) {
    //nothing to do;
}


NativeScreen lens_screen_initialize(JNIEnv *env) {
    int fbFileHandle;
    struct fb_var_screeninfo screenInfo;
    GLASS_LOG_FINE("open(%s, O_RDONLY)", FB_DEVICE);
    fbFileHandle = open(FB_DEVICE, O_RDONLY);
    if (fbFileHandle < 0) {
        GLASS_LOG_SEVERE("Cannot open framebuffer (%s)", strerror(errno));
        return NULL;
    }
    GLASS_LOG_FINE("ioctl(%s, FBIOGET_VSCREENINFO)", FB_DEVICE);
    if (ioctl(fbFileHandle, FBIOGET_VSCREENINFO, &screenInfo)) {
        GLASS_LOG_SEVERE("Cannot get screen info");
        close(fbFileHandle);
        return NULL;
    }

    //print screen properties
    GLASS_IF_LOG_CONFIG {
        GLASS_LOG_CONFIG("%s configuration:", FB_DEVICE);
        GLASS_LOG_CONFIG("xres=%u", screenInfo.xres);
        GLASS_LOG_CONFIG("yres=%u", screenInfo.yres);
        GLASS_LOG_CONFIG("xres_virtual=%u", screenInfo.xres_virtual);
        GLASS_LOG_CONFIG("yres_virtual=%u", screenInfo.yres_virtual);
        GLASS_LOG_CONFIG("xoffset=%u", screenInfo.xoffset);
        GLASS_LOG_CONFIG("yoffset=%u", screenInfo.yoffset);
        GLASS_LOG_CONFIG("bits_per_pixel=%u", screenInfo.bits_per_pixel);
        GLASS_LOG_CONFIG("grayscale=%u", screenInfo.grayscale);
        // width and height are supposed to be unsigned
        // but can return -1 as a signed integer
        GLASS_LOG_CONFIG("width=%imm", screenInfo.width);
        GLASS_LOG_CONFIG("height=%imm", screenInfo.height);
        GLASS_LOG_CONFIG("sync=%u", screenInfo.sync);
        GLASS_LOG_CONFIG("vmode=%u", screenInfo.vmode);
        GLASS_LOG_CONFIG("rotate=%u", screenInfo.rotate);
    }

    /* In screenInfo:
     * xres = physical width in pixels
     * xres_virtual = virtual width in pixels
     * xoffset = X offset of physical display into virtual display
     * width = physical width of display in millimeters
     */
    fbScreen.width = screenInfo.xres;
    fbScreen.height = screenInfo.yres;
    fbScreen.visibleWidth = screenInfo.xres;
    fbScreen.visibleHeight = screenInfo.yres;
    fbScreen.x = screenInfo.xoffset;
    fbScreen.y = screenInfo.yoffset;
    fbScreen.depth = screenInfo.bits_per_pixel;
    if (screenInfo.width > 0) {
        // convert pixels/mm to pixels/inch
        fbScreen.resolutionX = (fbScreen.visibleWidth * 254)
                               / (fbScreen.width * 10);
    } else {
        // take a guess at pixel density
        fbScreen.resolutionX = 96;
    }
    if (screenInfo.height > 0) {
        fbScreen.resolutionY = (fbScreen.visibleHeight * 254)
                               / (fbScreen.height * 10);
    } else {
        fbScreen.resolutionY = 96;
    }

    GLASS_LOG_CONFIG("Set resolution to %ix%i dots per inch",
                     fbScreen.resolutionX, fbScreen.resolutionY);

    if (fbScanLine == NULL) {
        int bytesPerPixel = 0;
        switch (fbScreen.depth) {
            case 16:
                bytesPerPixel = 2;
                break;
            case 24:
            case 32:
                bytesPerPixel = 4;
                break;
            default:
                GLASS_LOG_SEVERE("Cannot write to screen of depth %i", fbScreen.depth);
                return NULL;
        }
        fbScanLineSize = fbScreen.width * bytesPerPixel;
        fbScanLine = malloc(fbScanLineSize);
        if (fbScanLine == NULL) {
            GLASS_LOG_SEVERE("Cannot allocate scan line of size %i", fbScanLineSize);
            return NULL;
        }
    }

    close(fbFileHandle);

    return &fbScreen;

}

void *glass_window_getPlatformWindow(JNIEnv *env, NativeWindow window) {
    return window;
}

char *lens_screen_getFrameBuffer() {
    return NULL;
}


jboolean glass_screen_capture(jint x, jint y,
                                    jint width, jint height,
                                    jint *pixels) {

    if (!loadedBcm) {
        load_bcm_symbols();
        loadedBcm = 1;
    }

    if (useDispman) {
#ifdef USE_DISPMAN
        return dispman_glass_robot_screen_capture(x, y, width, height, pixels);
#else
        return JNI_FALSE; // cannot reach here
#endif
    } else {
        FILE *fb;
        unsigned char *pixelBuffer = NULL;
        unsigned char *dst = (unsigned char *) pixels;
        unsigned int dstByteStride = width * 4;
        int i = 0;
        int fbFileHandle;
        struct fb_var_screeninfo screenInfo;
        int depth; // pixel size in bytes

        GLASS_LOG_FINE("Capture %i,%i+%ix%i", x, y, width, height);
        jboolean result = JNI_FALSE;

        if (width < 1 || height < 1) {
            GLASS_LOG_SEVERE("Failed. width/height values must be at least = 1");
            return JNI_FALSE;
        }

        GLASS_LOG_FINE("open(%s, O_RDONLY)", FB_DEVICE);
        fbFileHandle = open(FB_DEVICE, O_RDONLY);
        if (fbFileHandle < 0) {
            GLASS_LOG_SEVERE("Cannot open framebuffer");
            return JNI_FALSE;
        }
        GLASS_LOG_FINE("ioctl(%s, FBIOGET_VSCREENINFO)", FB_DEVICE);
        if (ioctl(fbFileHandle, FBIOGET_VSCREENINFO, &screenInfo)) {
            GLASS_LOG_SEVERE("Cannot get screen info");
            return JNI_FALSE;
        }
        GLASS_LOG_FINE("Read screen info: res=%ix%i, offset=%ix%i",
                       screenInfo.xres, screenInfo.yres,
                       screenInfo.xoffset, screenInfo.yoffset);
        GLASS_LOG_FINE("close(%s)", FB_DEVICE);
        close(fbFileHandle);
        depth = screenInfo.bits_per_pixel / 8;
        int pixelBufferLength = screenInfo.xres * screenInfo.yres * depth;
        pixelBuffer = (unsigned char *) malloc(pixelBufferLength);
        if (pixelBuffer == NULL) {
            GLASS_LOG_SEVERE("Failed to allocate temporary pixel buffer");
            return JNI_FALSE;
        }

        GLASS_LOG_FINE("fopen(%s, \"r\") to read %ix%i pixels at bit depth %i",
                       FB_DEVICE, width, height, screenInfo.bits_per_pixel);
        fb = fopen(FB_DEVICE, "r");
        if (fb == NULL) {
            GLASS_LOG_SEVERE("FB: Cannot open framebuffer for reading");
            free(pixelBuffer);
            return JNI_FALSE;
        }

        fseek(fb, screenInfo.yoffset * screenInfo.xres * depth, SEEK_SET);
        int numRead = fread(pixelBuffer, 1,
                            pixelBufferLength,
                            fb);

        if (x < 0) {
            dst += -x * 4;
            width += x;
            x = 0;
        }
        if (y < 0) {
            dst += -y * dstByteStride;
            height += y;
            y = 0;
        }

        int widthLimit = width;
        int heightLimit = height;

        // Required height is larger than screen's height
        if ((int) screenInfo.yres < height) {
            heightLimit = (int) screenInfo.yres;
        }
        // Required width is larger than screen's width
        if ((int) screenInfo.xres < width) {
            widthLimit = (int) screenInfo.xres;
        }
        // Required height is out of range
        if (((int) screenInfo.yres - y) < height) {
            heightLimit = (int) screenInfo.yres - y;
        }
        // Required width is out of range
        if (((int) screenInfo.xres - x) < width) {
            widthLimit = (int) screenInfo.xres - x;
        }

        if (widthLimit > 0 && heightLimit > 0) {
            // copy the relevant portion of the screen to the supplied pixel array
            int offset = y * screenInfo.xres * depth + x * depth;
            for (i = 0; i < heightLimit; i++) {
                memcpy(dst + i * dstByteStride, pixelBuffer + offset, widthLimit * depth);
                offset += screenInfo.xres * depth;
            }
        } else {
            free(pixelBuffer);
            fclose(fb);
            GLASS_LOG_FINE("fclose(%s)", FB_DEVICE);
            GLASS_LOG_SEVERE("Failed to take a snapshot, some of parameters are illegal");
            return JNI_FALSE;
        }

        free(pixelBuffer);
        GLASS_LOG_FINE("fclose(%s)", FB_DEVICE);
        fclose(fb);
        return JNI_TRUE;
    }
}

LensResult lens_platform_windowMinimize(JNIEnv *env,
                                        NativeWindow window,
                                        jboolean toMinimize) {
    //noop for fb
    return LENS_OK;
}

LensResult lens_platform_windowSetVisible(JNIEnv *env,
                                        NativeWindow window,
                                        jboolean visible) {
    //noop for fb
    return LENS_OK;
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy