Package org.apache.harmony.awt.wtk.windows

Source Code of org.apache.harmony.awt.wtk.windows.WinEventQueue$Preprocessor

/*
*  Licensed to the Apache Software Foundation (ASF) under one or more
*  contributor license agreements.  See the NOTICE file distributed with
*  this work for additional information regarding copyright ownership.
*  The ASF licenses this file to You under the Apache License, Version 2.0
*  (the "License"); you may not use this file except in compliance with
*  the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
/**
* @author Dmitry A. Durnev, Pavel Dolgov
* @version $Revision$
*/
package org.apache.harmony.awt.wtk.windows;

import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;

import org.apache.harmony.awt.nativebridge.Int16Pointer;
import org.apache.harmony.awt.nativebridge.NativeBridge;
import org.apache.harmony.awt.nativebridge.windows.Win32;
import org.apache.harmony.awt.nativebridge.windows.WindowsDefs;
import org.apache.harmony.awt.wtk.NativeEvent;
import org.apache.harmony.awt.wtk.NativeEventQueue;
import org.apache.harmony.awt.wtk.NativeWindow;
import org.apache.harmony.misc.accessors.AccessorFactory;
import org.apache.harmony.misc.accessors.ObjectAccessor;

/**
* Handler of Windows messages
*/
public class WinEventQueue extends NativeEventQueue {
   
    static final NativeBridge bridge = NativeBridge.getInstance();
    static final Win32 win32 = Win32.getInstance();
    static final ObjectAccessor objAccessor = AccessorFactory.getObjectAccessor();

    /**
     * Invisible auxiliary window for service messages
     */
    private final long javaWindow;
    /**
     * Theme handles currently open
     */
    private final ThemeMap themeMap = new ThemeMap();

    /**
     * The message being processed
     */
    private final Win32.MSG lastMsg = win32.createMSG(false);

    final int dispatchThreadID = win32.GetCurrentThreadId();
    final WinSystemProperties systemProperties;

    /**
     * The last keyboard message
     */
    private final Win32.MSG charMsg = win32.createMSG(false);
    /**
     * Accumulated typed characters
     */
    private final StringBuffer lastTranslation = new StringBuffer();
    /**
     * Recently typed character
     */
    private char lastChar;
    /**
     * Keycodes and characters stored
     * until WM_KEYUP or WM_SYSKEYUP message is received
     */
    private final HashMap<Integer, Character> keyCodeToChar = new HashMap<Integer, Character>();

    final WinWindowFactory factory;

    private long utcOffset = -1;
    /**
     * Return value for the Windows message being processed
     */
    private final long[] result = new long[1];

    public static final int WM_PERFORM_TASK = WindowsDefs.WM_USER + 1;
    public static final int WM_PERFORM_LATER = WindowsDefs.WM_USER + 2;

    private final LinkedList<Preprocessor> preprocessors = new LinkedList<Preprocessor>();

    /**
     * Initialize message pump, create auxiliary window for service messages
     * @param systemProperties
     */
    public WinEventQueue(WinSystemProperties systemProperties) {
        this.systemProperties = systemProperties;

        WindowProcHandler.registerCallback();
        factory = new WinWindowFactory(this);

        javaWindow = createJavaWindow();
    }

    public void addPreprocessor(Preprocessor preprocessor) {
        preprocessors.add(preprocessor);
    }

    /**
     * Wait for next Windows messages. The re-entrant calls to windowProc()
     * may occur while waiting
     * @return false when WM_QUIT received
     */
    @Override
    public boolean waitEvent() {
        win32.GetMessageW(lastMsg, 0, 0, 0);

        return lastMsg.get_message() != WindowsDefs.WM_QUIT;
    }

    /**
     * Post the service message to the auxiliary window to ensure
     * the method waitEvent() will leave the waiting state
     */
    @Override
    public void awake() {
        if (win32.GetCurrentThreadId() != dispatchThreadID) {
            win32.PostThreadMessageW(dispatchThreadID, WinEvent.WM_AWAKE, 0, 0);
        }
    }

    /**
     * Handle the service message posted to event dispatch thread
     * @param msg - the Windows message
     */
    private void processThreadMessage(Win32.MSG msg) {
        handleEvent(0, msg.get_message(), msg.get_wParam(), msg.get_lParam());
    }
   
    /**
     * Translate key code to typed character for keyboard messages,
     * do nothing for all other messages
     * @param msg - the Windows message to translate
     */
    private void translateMessage(Win32.MSG msg) {
        if (win32.TranslateMessage(msg) == 0) {
            return;
        }

        lastChar = KeyEvent.CHAR_UNDEFINED;
        lastTranslation.setLength(0);

        switch (msg.get_message()) {
        case WindowsDefs.WM_KEYDOWN:
            peekChar(msg, WindowsDefs.WM_CHAR, WindowsDefs.WM_DEADCHAR);
            break;
        case WindowsDefs.WM_SYSKEYDOWN:
            peekChar(msg, WindowsDefs.WM_SYSCHAR, WindowsDefs.WM_SYSDEADCHAR);
            break;
        default:
            peekChar(msg, WindowsDefs.WM_CHAR, WindowsDefs.WM_DEADCHAR);
        }
    }

    /**
     * Determine typed character for WM_KEYDOWN or WM_SYSKEYDOWN message,
     * and store the translation for decoding of subsequent
     * WM_KEYUP or WM_SYSKEYUP messages
     * @param msg - message to find the typed character for
     * @param min - the low bound of range of messages to peek
     * @param max - the high bound of range of messages to peek
     */
    private void peekChar(Win32.MSG msg, int min, int max) {
        while (win32.PeekMessageW(charMsg, msg.get_hwnd(),
                min, max, WindowsDefs.PM_REMOVE) != 0) {

            int msgId = charMsg.get_message();
            int vKey = (int)msg.get_wParam();
            lastChar = (char)charMsg.get_wParam();

            if (msgId == WindowsDefs.WM_CHAR || msgId == WindowsDefs.WM_SYSCHAR) {
                lastTranslation.append(lastChar);
            }

            keyCodeToChar.put(new Integer(vKey), new Character(lastChar));
        }
    }

    /**
     * The callback called by Windows framework to handle the messages
     * @param hwnd - window handle
     * @param msg - message code
     * @param wParam - first message-dependent parameter
     * @param lParam - second message-dependent parameter
     * @return - message-dependent value
     */
    public long windowProc(long hwnd, int msg, long wParam, long lParam) {
        if ((utcOffset < 0) && (lastMsg.get_time() != 0l)) {
            utcOffset = System.currentTimeMillis() - lastMsg.get_time();
        }

        if (preProcessMessage(hwnd, msg,  wParam, lParam, result)) {
            return result[0];
        }
        if (handleEvent(hwnd, msg,  wParam, lParam)) {
            return 0;
        }

        if (msg == WindowsDefs.WM_MOUSEACTIVATE) {
            return WindowsDefs.MA_NOACTIVATE;
        }
        return win32.DefWindowProcW(hwnd, msg, wParam, lParam);
    }

    private boolean handleEvent(long hwnd, int msg, long wParam, long lParam) {
        if (msg == WindowsDefs.WM_KEYUP || msg == WindowsDefs.WM_SYSKEYUP) {
            Character ch = keyCodeToChar.remove(new Integer((int)wParam));
            if (ch != null) {
                lastChar = ch.charValue();
            } else {
                lastChar = KeyEvent.CHAR_UNDEFINED;
            }
        }

        WinEvent event = new WinEvent(hwnd, msg, wParam,
                lParam, utcOffset + lastMsg.get_time(),
                lastTranslation, lastChar, factory);
        if (event.getEventId() != NativeEvent.ID_PLATFORM) {
            addEvent(event);
            return !isKeyUpOrKeyDownMessage(msg);
        }
        return false;
    }

    private boolean isKeyUpOrKeyDownMessage(int msg) {
        return msg == WindowsDefs.WM_KEYDOWN
            || msg == WindowsDefs.WM_KEYUP
            || msg == WindowsDefs.WM_SYSKEYDOWN
            || msg == WindowsDefs.WM_SYSKEYUP;
    }

    /**
     * Call the message preprocessors, handle the Windows messages that
     * should not be passed to the default Windows handler
     * 
     * @param hwnd - window handle
     * @param msg - message code
     * @param wParam - first message-dependent parameter
     * @param lParam - second message-dependent parameter
     * @param result - result[0] is the return value of the message
     * @return - false if the default Windows handler should be called;
     */
    private boolean preProcessMessage(long hwnd, int msg, long wParam, long lParam, long[] result) {
        if (msg == WM_PERFORM_TASK && hwnd == javaWindow) {
            Task t = (Task)objAccessor.getObjectFromReference(lParam);
            t.perform();
            return true;
        }
       
        if (msg == WM_PERFORM_LATER && hwnd == javaWindow) {
            Task t = (Task)objAccessor.getObjectFromReference(lParam);
            t.perform();
            objAccessor.releaseGlobalReference(lParam);
            return true;
        }
        for (Iterator<Preprocessor> i = preprocessors.iterator(); i.hasNext(); ) {
            if (i.next().preprocess(hwnd, msg, wParam, lParam, result)) {
                return true;
            }
        }

        switch (msg) {
        case WindowsDefs.WM_CREATE:
            factory.onCreateWindow(hwnd);
            break;

        case WindowsDefs.WM_NCACTIVATE:
            // prevent non-focusable window's non-client area from being
            // changed to indicate its active state
            long hwndOther = lParam;
            NativeWindow wnd = factory.getWindowById(hwnd);
            NativeWindow otherWnd = factory.getWindowById(hwndOther);
            if (wParam != 0 && !wnd.isFocusable() ||
                    wParam == 0 && wnd.isFocusable() &&
                    otherWnd != null && !otherWnd.isFocusable() ) {

                result[0] = 0;
                return true;
            }
            break;
           
        case WindowsDefs.WM_ACTIVATE:
            if (wParam == WindowsDefs.WA_ACTIVE) {
                // while activation of Frame/Dialog
                // [actually focus transfer to focusProxy] is in progress
                // skip all focus events related to windows being activated/deactivated,
                // such spurious events are sometimes generated by Win32
                WinWindow ownd = (WinWindow) factory.getWindowById(lParam);
                long hOwner = lParam;
                // find nearest decorated ancestor window of
                // the window being deactivated
                while ((ownd != null) && ownd.undecorated) {
                    hOwner = win32.GetParent(hOwner);
                    ownd = (WinWindow) factory.getWindowById(hOwner);
                }
                // cancel focus only if
                // this is the window found
                if ((ownd != null) && (hOwner == hwnd)) {
                    result[0] = 0;
                    return true;
                }
            }
            break;

        case WindowsDefs.WM_SETCURSOR:
            short htCode = (short) lParam;
            if (htCode == WindowsDefs.HTCLIENT) {
                result[0] = 0;
                return true;
            }
            break;

        case WindowsDefs.WM_GETMINMAXINFO:
            if (processGetMinMaxInfo(hwnd, lParam)) {
                result[0] = 0;
                return true;
            }
            break;

        case WindowsDefs.WM_ERASEBKGND:
            result[0] = 1;
            return true;

        case WindowsDefs.WM_SYSCOMMAND:
            // suppress system menu activation on F10 key
            if ( (wParam & 0xFFF0) == WindowsDefs.SC_KEYMENU) {
                result[0] = 0;
                return true;
            }
            break;

        case WindowsDefs.WM_SYSCOLORCHANGE:
            result[0] = 0;
            if (hwnd == javaWindow) {
                systemProperties.resetSystemColors();
            }
            break;
           
        case WindowsDefs.WM_SETTINGCHANGE:
            systemProperties.processSettingChange(wParam);
            break;
        case WindowsDefs.WM_IME_STARTCOMPOSITION:           
            return WinIM.onStartComposition(hwnd);
        case WindowsDefs.WM_IME_SETCONTEXT:
            if (wParam != 0l) {
                return WinIM.onActivateContext(hwnd);
            }
            break;
        case WindowsDefs.WM_IME_COMPOSITION:
            WinIM.onComposition(hwnd, lParam);
            break;
        }

       
        return false;
    }

    public ThemeMap getThemeMap() {
        return themeMap;
    }

    /**
     * create invisible auxlitary window to listen to the service messages
     * @return HWND of created window
     */
    private static long createJavaWindow() {
        long hwnd = win32.CreateWindowExW(0,
                WindowProcHandler.windowClassName, "JavaWindow",
                0, 0, 0, 0, 0, 0, 0, 0, null);
        int winError = win32.GetLastError();

        if (hwnd == 0) {
            throw new InternalError("Failure to create JavaWindow "
                    + "GetLastError returned " + winError);
        }

        return hwnd;
    }

    /**
     * Apply window's maximized bounds
     * @param hwnd
     */
    private boolean processGetMinMaxInfo(long hwnd, long ptrMinMaxInfo) {
        WinWindow win = factory.getWinWindowById(hwnd);
        if (win == null) {
            return false;
        }
        Rectangle maxBounds = win.maximizedBounds;
        final int MAX = Integer.MAX_VALUE;
        if (maxBounds == null) {
            return false;
        }
        Win32.MINMAXINFO info = win32.createMINMAXINFO(ptrMinMaxInfo);

        if (maxBounds.width < MAX) {
            info.get_ptMaxSize().set_x(maxBounds.width);
        }
        if (maxBounds.height < MAX) {
            info.get_ptMaxSize().set_y(maxBounds.height);
        }
        if (maxBounds.x < MAX) {
            info.get_ptMaxPosition().set_x(maxBounds.x);
        }
        if (maxBounds.y < MAX) {
            info.get_ptMaxPosition().set_y(maxBounds.y);
        }
        return true;
    }

    @Override
    public long getJavaWindow() {
        return javaWindow;
    }

    /**
     * Interface for message pre-processing
     */
    public interface Preprocessor {

        public boolean preprocess(long hwnd, int msg, long wParam, long lParam, long[] result);

    }

    /**
     * The Windows theme handles currently open, and their names
     */
    public class ThemeMap {
        private final HashMap<String, Long> themes = new HashMap<String, Long>();
        private boolean enabled;

        ThemeMap() {
            enabled = (win32.IsThemeActive() != 0);
        }

        public long get(String name) {
            Long obj = themes.get(name);
            if (obj != null) {
                return obj.longValue();
            }
            long hTheme = open(name);
            themes.put(name, new Long(hTheme));
            return hTheme;
        }

        private long open(String name) {
            Int16Pointer namePtr = bridge.createInt16Pointer(name, false);
            long hTheme = win32.OpenThemeData(javaWindow, namePtr.lock());
            namePtr.unlock();
            return hTheme;
        }

        public boolean isEnabled() {
            return enabled;
        }

        void refresh() {
            enabled = (win32.IsThemeActive() != 0);

            for (Iterator<Map.Entry<String, Long>> it = themes.entrySet().iterator(); it.hasNext();) {
                Map.Entry<String, Long> e = it.next();
                long hTheme = e.getValue().longValue();
                if (hTheme != 0) {
                    win32.CloseThemeData(hTheme);
                }
                if (enabled) {
                    hTheme = open(e.getKey());
                } else {
                    hTheme = 0;
                }
                e.setValue(new Long(hTheme));
            }
        }
    }

    @Override
    public void dispatchEvent() {
        if (lastMsg.get_hwnd() == 0) {
            processThreadMessage(lastMsg);
        }
       
        translateMessage(lastMsg);
        win32.DispatchMessageW(lastMsg);
    }

    @Override
    public void performTask(Task task) {
        long ref = objAccessor.getGlobalReference(task);
        win32.SendMessageW(javaWindow, WM_PERFORM_TASK, 0, ref);
        objAccessor.releaseGlobalReference(ref);
    }

    @Override
    public void performLater(Task task) {
        long ref = objAccessor.getGlobalReference(task);
        win32.PostMessageW(javaWindow, WM_PERFORM_LATER, 0, ref);
    }
}
TOP

Related Classes of org.apache.harmony.awt.wtk.windows.WinEventQueue$Preprocessor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.