/*
 * Copyright (c) 1996, 2011, 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 "awt_Toolkit.h"
#include "awt_Frame.h"
#include "awt_MenuBar.h"
#include "awt_Dialog.h"
#include "awt_IconCursor.h"
#include "awt_Win32GraphicsDevice.h"
#include "ComCtl32Util.h"

#include <windowsx.h>

#include <java_lang_Integer.h>
#include <sun_awt_EmbeddedFrame.h>
#include <sun_awt_windows_WEmbeddedFrame.h>
#include <sun_awt_windows_WEmbeddedFramePeer.h>


/* IMPORTANT! Read the README.JNI file for notes on JNI converted AWT code.
 */

/***********************************************************************/
// Struct for _SetState() method
struct SetStateStruct {
    jobject frame;
    jint state;
};
// Struct for _SetMaximizedBounds() method
struct SetMaximizedBoundsStruct {
    jobject frame;
    jint x, y;
    jint width, height;
};
// Struct for _SetMenuBar() method
struct SetMenuBarStruct {
    jobject frame;
    jobject menubar;
};

// Struct for _SetIMMOption() method
struct SetIMMOptionStruct {
    jobject frame;
    jstring option;
};
// Struct for _SynthesizeWmActivate() method
struct SynthesizeWmActivateStruct {
    jobject frame;
    jboolean doActivate;
};
// Struct for _NotifyModalBlocked() method
struct NotifyModalBlockedStruct {
    jobject frame;
    jobject peer;
    jobject blockerPeer;
    jboolean blocked;
};
// Information about thread containing modal blocked embedded frames
struct BlockedThreadStruct {
    int framesCount;
    HHOOK mouseHook;
    HHOOK modalHook;
};
/************************************************************************
 * AwtFrame fields
 */

jfieldID AwtFrame::handleID;

jfieldID AwtFrame::undecoratedID;
jmethodID AwtFrame::getExtendedStateMID;
jmethodID AwtFrame::setExtendedStateMID;

jmethodID AwtFrame::activateEmbeddingTopLevelMID;

Hashtable AwtFrame::sm_BlockedThreads("AWTBlockedThreads");

/************************************************************************
 * AwtFrame methods
 */

AwtFrame::AwtFrame() {
    m_parentWnd = NULL;
    menuBar = NULL;
    m_isEmbedded = FALSE;
    m_ignoreWmSize = FALSE;
    m_isMenuDropped = FALSE;
    m_isInputMethodWindow = FALSE;
    m_isUndecorated = FALSE;
    m_imeTargetComponent = NULL;
    m_actualFocusedWindow = NULL;
    m_iconic = FALSE;
    m_zoomed = FALSE;
    m_maxBoundsSet = FALSE;
    m_forceResetZoomed = FALSE;

    isInManualMoveOrSize = FALSE;
    grabbedHitTest = 0;
}

AwtFrame::~AwtFrame()
{
}

void AwtFrame::Dispose()
{
    AwtWindow::Dispose();
}

LPCTSTR AwtFrame::GetClassName() {
    return AWT_FRAME_WINDOW_CLASS_NAME;
}

/*
 * Create a new AwtFrame object and window.
 */
AwtFrame* AwtFrame::Create(jobject self, jobject parent)
{
    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
    if (env->EnsureLocalCapacity(1) < 0) {
        return NULL;
    }

    PDATA pData;
    HWND hwndParent = NULL;
    AwtFrame* frame;
    jclass cls = NULL;
    jclass inputMethodWindowCls = NULL;
    jobject target = NULL;

    try {
        target = env->GetObjectField(self, AwtObject::targetID);
        JNI_CHECK_NULL_GOTO(target, "target", done);

        if (parent != NULL) {
            JNI_CHECK_PEER_GOTO(parent, done);
            {
                AwtFrame* parent = (AwtFrame *)pData;
                hwndParent = parent->GetHWnd();
            }
        }

        frame = new AwtFrame();

        {
            /*
             * A variation on Netscape's hack for embedded frames: the client
             * area of the browser is a Java Frame for parenting purposes, but
             * really a Windows child window
             */
            cls = env->FindClass("sun/awt/EmbeddedFrame");
            if (cls == NULL) {
                return NULL;
            }
            INT_PTR handle;
            jboolean isEmbeddedInstance = env->IsInstanceOf(target, cls);
            jboolean isEmbedded = FALSE;

            if (isEmbeddedInstance) {
                handle = static_cast<INT_PTR>(env->GetLongField(target, AwtFrame::handleID));
                if (handle != 0) {
                    isEmbedded = TRUE;
                }
            }
            frame->m_isEmbedded = isEmbedded;

            if (isEmbedded) {
                hwndParent = (HWND)handle;
                RECT rect;
                ::GetClientRect(hwndParent, &rect);
                //Fix for 6328675: SWT_AWT.new_Frame doesn't occupy client area under JDK6
                frame->m_isUndecorated = true;
                /*
                 * Fix for BugTraq ID 4337754.
                 * Initialize m_peerObject before the first call
                 * to AwtFrame::GetClassName().
                 */
                frame->m_peerObject = env->NewGlobalRef(self);
                frame->RegisterClass();
                DWORD exStyle = WS_EX_NOPARENTNOTIFY;

                if (GetRTL()) {
                    exStyle |= WS_EX_RIGHT | WS_EX_LEFTSCROLLBAR;
                    if (GetRTLReadingOrder())
                        exStyle |= WS_EX_RTLREADING;
                }

                frame->m_hwnd = ::CreateWindowEx(exStyle,
                                                 frame->GetClassName(), TEXT(""),
                                                 WS_CHILD | WS_CLIPCHILDREN,
                                                 0, 0,
                                                 rect.right, rect.bottom,
                                                 hwndParent, NULL,
                                                 AwtToolkit::GetInstance().GetModuleHandle(),
                                                 NULL);
                frame->LinkObjects(env, self);
                frame->SubclassHWND();

                // Update target's dimensions to reflect this embedded window.
                ::GetClientRect(frame->m_hwnd, &rect);
                ::MapWindowPoints(frame->m_hwnd, hwndParent, (LPPOINT)&rect, 2);

                env->SetIntField(target, AwtComponent::xID, rect.left);
                env->SetIntField(target, AwtComponent::yID, rect.top);
                env->SetIntField(target, AwtComponent::widthID,
                                 rect.right-rect.left);
                env->SetIntField(target, AwtComponent::heightID,
                                 rect.bottom-rect.top);
                frame->InitPeerGraphicsConfig(env, self);
                AwtToolkit::GetInstance().RegisterEmbedderProcessId(hwndParent);
            } else {
                jint state = env->CallIntMethod(self, AwtFrame::getExtendedStateMID);
                DWORD exStyle;
                DWORD style;

               // for input method windows, use minimal decorations
               inputMethodWindowCls = env->FindClass("sun/awt/im/InputMethodWindow");
               if ((inputMethodWindowCls != NULL) && env->IsInstanceOf(target, inputMethodWindowCls)) {
                   //for below-the-spot composition window, use no decoration
                   if (env->GetBooleanField(target, AwtFrame::undecoratedID) == JNI_TRUE){
                        exStyle = 0;
                        style = WS_POPUP|WS_CLIPCHILDREN;
                        frame->m_isUndecorated = TRUE;
                   } else {
                        exStyle = WS_EX_PALETTEWINDOW;
                        style = WS_CLIPCHILDREN;
                   }
                   frame->m_isInputMethodWindow = TRUE;
                } else if (env->GetBooleanField(target, AwtFrame::undecoratedID) == JNI_TRUE) {
                    exStyle = 0;
                    style = WS_POPUP | WS_SYSMENU | WS_CLIPCHILDREN |
                        WS_MAXIMIZEBOX | WS_MINIMIZEBOX;
                  if (state & java_awt_Frame_ICONIFIED) {
                      frame->setIconic(TRUE);
                  }
                    frame->m_isUndecorated = TRUE;
                } else {
                    exStyle = WS_EX_WINDOWEDGE;
                    style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
                  if (state & java_awt_Frame_ICONIFIED) {
                      frame->setIconic(TRUE);
                  }
                }

                if (GetRTL()) {
                    exStyle |= WS_EX_RIGHT | WS_EX_LEFTSCROLLBAR;
                    if (GetRTLReadingOrder())
                        exStyle |= WS_EX_RTLREADING;
                }

                jint x = env->GetIntField(target, AwtComponent::xID);
                jint y = env->GetIntField(target, AwtComponent::yID);
                jint width = env->GetIntField(target, AwtComponent::widthID);
                jint height = env->GetIntField(target, AwtComponent::heightID);

                frame->CreateHWnd(env, L"",
                                  style,
                                  exStyle,
                                  0, 0, 0, 0,
                                  hwndParent,
                                  NULL,
                                  ::GetSysColor(COLOR_WINDOWTEXT),
                                  ::GetSysColor(COLOR_WINDOWFRAME),
                                  self);
                /*
                 * Reshape here instead of during create, so that a
                 * WM_NCCALCSIZE is sent.
                 */
                frame->Reshape(x, y, width, height);
            }
        }
    } catch (...) {
        env->DeleteLocalRef(target);
        env->DeleteLocalRef(cls);
        env->DeleteLocalRef(inputMethodWindowCls);
        throw;
    }

done:
    env->DeleteLocalRef(target);
    env->DeleteLocalRef(cls);
    env->DeleteLocalRef(inputMethodWindowCls);

    return frame;
}

LRESULT AwtFrame::ProxyWindowProc(UINT message, WPARAM wParam, LPARAM lParam, MsgRouting &mr)
{
    LRESULT retValue = 0L;

    AwtComponent *focusOwner = NULL;
    AwtComponent *imeTargetComponent = NULL;

    // IME and input language related messages need to be sent to a window
    // which has the Java input focus
    switch (message) {
        case WM_IME_STARTCOMPOSITION:
        case WM_IME_ENDCOMPOSITION:
        case WM_IME_COMPOSITION:
        case WM_IME_SETCONTEXT:
        case WM_IME_NOTIFY:
        case WM_IME_CONTROL:
        case WM_IME_COMPOSITIONFULL:
        case WM_IME_SELECT:
        case WM_IME_CHAR:
        case WM_IME_REQUEST:
        case WM_IME_KEYDOWN:
        case WM_IME_KEYUP:
        case WM_INPUTLANGCHANGEREQUEST:
        case WM_INPUTLANGCHANGE:
            if (message == WM_IME_STARTCOMPOSITION) {
                SetImeTargetComponent(sm_focusOwner);
            }
            imeTargetComponent = AwtComponent::GetComponent(GetImeTargetComponent());
            if (imeTargetComponent != NULL &&
                imeTargetComponent != this) // avoid recursive calls
            {
                retValue = imeTargetComponent->WindowProc(message, wParam, lParam);
                mr = mrConsume;
            }
            if (message == WM_IME_ENDCOMPOSITION) {
                SetImeTargetComponent(NULL);
            }
            break;
        case WM_SETFOCUS:
            if (sm_inSynthesizeFocus) break; // pass it up the WindowProc chain

            if (!sm_suppressFocusAndActivation && IsEmbeddedFrame()) {
                AwtSetActiveWindow();
            }
            mr = mrConsume;
            break;
        case WM_KILLFOCUS:
            if (sm_inSynthesizeFocus) break; // pass it up the WindowProc chain

            if (!sm_suppressFocusAndActivation && IsEmbeddedFrame()) {
                AwtWindow::SynthesizeWmActivate(FALSE, GetHWnd(), NULL);

            } else if (sm_restoreFocusAndActivation) {
                if (AwtComponent::GetFocusedWindow() != NULL) {
                    AwtWindow *focusedWindow = (AwtWindow*)GetComponent(AwtComponent::GetFocusedWindow());
                    if (focusedWindow != NULL) {
                        // Will just silently restore native focus & activation.
                        focusedWindow->AwtSetActiveWindow();
                    }
                }
            }
            mr = mrConsume;
            break;
        case 0x0127: // WM_CHANGEUISTATE
        case 0x0128: // WM_UPDATEUISTATE
            mr = mrConsume;
            break;
    }

    return retValue;
}

LRESULT AwtFrame::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
    MsgRouting mr = mrDoDefault;
    LRESULT retValue = 0L;

    retValue = ProxyWindowProc(message, wParam, lParam, mr);

    if (mr != mrConsume) {
        retValue = AwtWindow::WindowProc(message, wParam, lParam);
    }
    return retValue;
}

MsgRouting AwtFrame::WmShowWindow(BOOL show, UINT status)
{
    /*
     * Fix for 6492970.
     * When a non-focusable toplevel is shown alone the Java process
     * is not foreground. If one shows another (focusable) toplevel
     * the native platform not always makes it foreground (see the CR).
     * Even worse, sometimes it sends the newly shown toplevel WM_ACTIVATE
     * message. This breaks Java focus. To workaround the problem we
     * set the toplevel being shown foreground programmatically.
     * The fix is localized to non-foreground process case only.
     * (See also: 6599270)
     */
    if (!IsEmbeddedFrame() && show == TRUE && status == 0) {
        HWND fgHWnd = ::GetForegroundWindow();
        if (fgHWnd != NULL) {
            DWORD fgProcessID;
            ::GetWindowThreadProcessId(fgHWnd, &fgProcessID);

            if (fgProcessID != ::GetCurrentProcessId()) {
                AwtWindow* window = (AwtWindow*)GetComponent(GetHWnd());

                if (window != NULL && window->IsFocusableWindow() && window->IsAutoRequestFocus() &&
                    !::IsWindow(GetModalBlocker(GetHWnd())))
                {
                    // When the Java process is not allowed to set the foreground window
                    // (see MSDN) the request below will just have no effect.
                    ::SetForegroundWindow(GetHWnd());
                }
            }
        }
    }
    return AwtWindow::WmShowWindow(show, status);
}

MsgRouting AwtFrame::WmMouseUp(UINT flags, int x, int y, int button) {
    if (isInManualMoveOrSize) {
        isInManualMoveOrSize = FALSE;
        ::ReleaseCapture();
        return mrConsume;
    }
    return AwtWindow::WmMouseUp(flags, x, y, button);
}

MsgRouting AwtFrame::WmMouseMove(UINT flags, int x, int y) {
    /**
     * If this Frame is non-focusable then we should implement move and size operation for it by
     * ourselfves because we don't dispatch appropriate mouse messages to default window procedure.
     */
    if (!IsFocusableWindow() && isInManualMoveOrSize) {
        DWORD curPos = ::GetMessagePos();
        x = GET_X_LPARAM(curPos);
        y = GET_Y_LPARAM(curPos);
        RECT r;
        ::GetWindowRect(GetHWnd(), &r);
        POINT mouseLoc = {x, y};
        mouseLoc.x -= savedMousePos.x;
        mouseLoc.y -= savedMousePos.y;
        savedMousePos.x = x;
        savedMousePos.y = y;
        if (grabbedHitTest == HTCAPTION) {
            ::SetWindowPos(GetHWnd(), NULL, r.left+mouseLoc.x, r.top+mouseLoc.y,
                           r.right-r.left, r.bottom-r.top,
                           SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
        } else {
            switch (grabbedHitTest) {
            case HTTOP:
                r.top += mouseLoc.y;
                break;
            case HTBOTTOM:
                r.bottom += mouseLoc.y;
                break;
            case HTRIGHT:
                r.right += mouseLoc.x;
                break;
            case HTLEFT:
                r.left += mouseLoc.x;
                break;
            case HTTOPLEFT:
                r.left += mouseLoc.x;
                r.top += mouseLoc.y;
                break;
            case HTTOPRIGHT:
                r.top += mouseLoc.y;
                r.right += mouseLoc.x;
                break;
            case HTBOTTOMLEFT:
                r.left += mouseLoc.x;
                r.bottom += mouseLoc.y;
                break;
            case HTBOTTOMRIGHT:
            case HTSIZE:
                r.right += mouseLoc.x;
                r.bottom += mouseLoc.y;
                break;
            }

            ::SetWindowPos(GetHWnd(), NULL, r.left, r.top,
                           r.right-r.left, r.bottom-r.top,
                           SWP_NOACTIVATE | SWP_NOZORDER |
                           SWP_NOCOPYBITS | SWP_DEFERERASE);
        }
        return mrConsume;
    } else {
        return AwtWindow::WmMouseMove(flags, x, y);
    }
}

MsgRouting AwtFrame::WmNcMouseUp(WPARAM hitTest, int x, int y, int button) {
    if (!IsFocusableWindow() && (button & LEFT_BUTTON)) {
        /*
         * Fix for 6399659.
         * The native system shouldn't activate the next window in z-order
         * when minimizing non-focusable window.
         */
        if (hitTest == HTMINBUTTON) {
            ::ShowWindow(GetHWnd(), SW_SHOWMINNOACTIVE);
            return mrConsume;
        }
        /**
         * If this Frame is non-focusable then we should implement move and size operation for it by
         * ourselfves because we don't dispatch appropriate mouse messages to default window procedure.
         */
        if ((button & DBL_CLICK) && hitTest == HTCAPTION) {
            // Double click on caption - maximize or restore Frame.
            if (IsResizable()) {
                if (::IsZoomed(GetHWnd())) {
                    ::ShowWindow(GetHWnd(), SW_SHOWNOACTIVATE);
                } else {
                    ::ShowWindow(GetHWnd(), SW_MAXIMIZE);
                }
            }
            return mrConsume;
        }
        switch (hitTest) {
        case HTMAXBUTTON:
            if (IsResizable()) {
                if (::IsZoomed(GetHWnd())) {
                    ::ShowWindow(GetHWnd(), SW_SHOWNOACTIVATE);
                } else {
                    ::ShowWindow(GetHWnd(), SW_MAXIMIZE);
                }
            }
            return mrConsume;
        default:
            return mrDoDefault;
        }
    }
    return AwtWindow::WmNcMouseUp(hitTest, x, y, button);
}

MsgRouting AwtFrame::WmNcMouseDown(WPARAM hitTest, int x, int y, int button) {
    // By Swing request, click on the Frame's decorations (even on
    // grabbed Frame) should generate UngrabEvent
    if (m_grabbedWindow != NULL/* && !m_grabbedWindow->IsOneOfOwnersOf(this)*/) {
        m_grabbedWindow->Ungrab();
    }
    if (!IsFocusableWindow() && (button & LEFT_BUTTON)) {
        switch (hitTest) {
        case HTTOP:
        case HTBOTTOM:
        case HTLEFT:
        case HTRIGHT:
        case HTTOPLEFT:
        case HTTOPRIGHT:
        case HTBOTTOMLEFT:
        case HTBOTTOMRIGHT:
        case HTSIZE:
            // Zoomed or non-resizable unfocusable frames should not be resizable.
            if (isZoomed() || !IsResizable()) {
                return mrConsume;
            }
        case HTCAPTION:
            // We are going to perform default mouse action on non-client area of this window
            // Grab mouse for this purpose and store coordinates for motion vector calculation
            savedMousePos.x = x;
            savedMousePos.y = y;
            ::SetCapture(GetHWnd());
            isInManualMoveOrSize = TRUE;
            grabbedHitTest = hitTest;
            return mrConsume;
        default:
            return mrDoDefault;
        }
    }
    return AwtWindow::WmNcMouseDown(hitTest, x, y, button);
}

// Override AwtWindow::Reshape() to handle minimized/maximized
// frames (see 6525850, 4065534)
void AwtFrame::Reshape(int x, int y, int width, int height)
{
    if (isIconic()) {
    // normal AwtComponent::Reshape will not work for iconified windows so...
        WINDOWPLACEMENT wp;
        POINT       ptMinPosition = {x,y};
        POINT       ptMaxPosition = {0,0};
        RECT        rcNormalPosition = {x,y,x+width,y+height};
        RECT        rcWorkspace;
        HWND        hWndDesktop = GetDesktopWindow();
        HWND        hWndSelf = GetHWnd();

        // SetWindowPlacement takes workspace coordinates, but
        // if taskbar is at top of screen, workspace coords !=
        // screen coords, so offset by workspace origin
        VERIFY(::SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID)&rcWorkspace, 0));
        ::OffsetRect(&rcNormalPosition, -rcWorkspace.left, -rcWorkspace.top);

        // set the window size for when it is not-iconified
        wp.length = sizeof(wp);
        wp.flags = WPF_SETMINPOSITION;
        wp.showCmd = IsVisible() ? SW_SHOWMINIMIZED : SW_HIDE;
        wp.ptMinPosition = ptMinPosition;
        wp.ptMaxPosition = ptMaxPosition;
        wp.rcNormalPosition = rcNormalPosition;

        // If the call is not guarded with ignoreWmSize,
        // a regression for bug 4851435 appears.
        // Having this call guarded also prevents
        // changing the iconified state of the frame
        // while calling the Frame.setBounds() method.
        m_ignoreWmSize = TRUE;
        ::SetWindowPlacement(hWndSelf, &wp);
        m_ignoreWmSize = FALSE;

        return;
    }

    if (isZoomed()) {
    // setting size of maximized window, we remove the
    // maximized state bit (matches Motif behaviour)
    // (calling ShowWindow(SW_RESTORE) would fire an
    //  activation event which we don't want)
        LONG    style = GetStyle();
        DASSERT(style & WS_MAXIMIZE);
        style ^= WS_MAXIMIZE;
        SetStyle(style);
    }

    AwtWindow::Reshape(x, y, width, height);
}


/* Show the frame in it's current state */
void
AwtFrame::Show()
{
    m_visible = true;
    HWND hwnd = GetHWnd();
    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);

    DTRACE_PRINTLN3("AwtFrame::Show:%s%s%s",
                  m_iconic ? " iconic" : "",
                  m_zoomed ? " zoomed" : "",
                  m_iconic || m_zoomed ? "" : " normal");

    BOOL locationByPlatform = env->GetBooleanField(GetTarget(env), AwtWindow::locationByPlatformID);

    if (locationByPlatform) {
         moveToDefaultLocation();
    }
    EnableTranslucency(TRUE);

    BOOL autoRequestFocus = IsAutoRequestFocus();

    if (m_iconic) {
        if (m_zoomed) {
            // This whole function could probably be rewritten to use
            // ::SetWindowPlacement but MS docs doesn't tell if
            // ::SetWindowPlacement is a proper superset of
            // ::ShowWindow.  So let's be conservative and only use it
            // here, where we really do need it.
            DTRACE_PRINTLN("AwtFrame::Show(SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED");
            WINDOWPLACEMENT wp;
            ::ZeroMemory(&wp, sizeof(WINDOWPLACEMENT));
            wp.length = sizeof(WINDOWPLACEMENT);
            ::GetWindowPlacement(hwnd, &wp);
            if (!IsFocusableWindow() || !autoRequestFocus) {
                wp.showCmd = SW_SHOWMINNOACTIVE;
            } else {
                wp.showCmd = SW_SHOWMINIMIZED;
            }
            wp.flags |= WPF_RESTORETOMAXIMIZED;
            ::SetWindowPlacement(hwnd, &wp);
        }
        else {
            DTRACE_PRINTLN("AwtFrame::Show(SW_SHOWMINIMIZED)");
            if (!IsFocusableWindow() || !autoRequestFocus) {
                ::ShowWindow(hwnd, SW_SHOWMINNOACTIVE);
            } else {
                ::ShowWindow(hwnd, SW_SHOWMINIMIZED);
            }
        }
    }
    else if (m_zoomed) {
        DTRACE_PRINTLN("AwtFrame::Show(SW_SHOWMAXIMIZED)");
        if (!autoRequestFocus) {

            m_filterFocusAndActivation = TRUE;
            ::ShowWindow(hwnd, SW_MAXIMIZE);
            m_filterFocusAndActivation = FALSE;

        } else if (!IsFocusableWindow()) {
            ::ShowWindow(hwnd, SW_MAXIMIZE);
        } else {
            ::ShowWindow(hwnd, SW_SHOWMAXIMIZED);
        }
    }
    else if (m_isInputMethodWindow) {
        // Don't activate input methow window
        DTRACE_PRINTLN("AwtFrame::Show(SW_SHOWNA)");
        ::ShowWindow(hwnd, SW_SHOWNA);

        // After the input method window shown, we have to adjust the
        // IME candidate window position. Here is why.
        // Usually, when IMM opens the candidate window, it sends WM_IME_NOTIFY w/
        // IMN_OPENCANDIDATE message to the awt component window. The
        // awt component makes a Java call to acquire the text position
        // in order to show the candidate window just below the input method window.
        // However, by the time it acquires the position, the input method window
        // hasn't been displayed yet, the position returned is just below
        // the composed text and when the input method window is shown, it
        // will hide part of the candidate list. To fix this, we have to
        // adjust the candidate window position after the input method window
        // is shown. See bug 5012944.
        AdjustCandidateWindowPos();
    }
    else {
        // Nor iconic, nor zoomed (handled above) - so use SW_RESTORE
        // to show in "normal" state regardless of whatever stale
        // state might the invisible window still has.
        DTRACE_PRINTLN("AwtFrame::Show(SW_RESTORE)");
        if (!IsFocusableWindow() || !autoRequestFocus) {
            ::ShowWindow(hwnd, SW_SHOWNOACTIVATE);
        } else {
            ::ShowWindow(hwnd, SW_RESTORE);
        }
    }
}

void
AwtFrame::SendWindowStateEvent(int oldState, int newState)
{
    SendWindowEvent(java_awt_event_WindowEvent_WINDOW_STATE_CHANGED,
                    NULL, oldState, newState);
}

void
AwtFrame::ClearMaximizedBounds()
{
    m_maxBoundsSet = FALSE;
}

void AwtFrame::AdjustCandidateWindowPos()
{
    // This method should only be called if the current frame
    // is the input method window frame.
    if (!m_isInputMethodWindow) {
        return;
    }

    RECT inputWinRec, focusWinRec;
    AwtComponent *comp = AwtComponent::GetComponent(AwtComponent::sm_focusOwner);
    if (comp == NULL) {
        return;
    }

    ::GetWindowRect(GetHWnd(), &inputWinRec);
    ::GetWindowRect(sm_focusOwner, &focusWinRec);

    LPARAM candType = comp->GetCandidateType();
    HWND defaultIMEWnd = ::ImmGetDefaultIMEWnd(GetHWnd());
    if (defaultIMEWnd == NULL) {
        return;
    }
    UINT bits = 1;
    // adjusts the candidate window position
    for (int iCandType = 0; iCandType < 32; iCandType++, bits<<=1) {
        if (candType & bits) {
            CANDIDATEFORM cf;
            cf.dwIndex = iCandType;
            cf.dwStyle = CFS_CANDIDATEPOS;
            // Since the coordinates are relative to the containing window,
            // we have to calculate the coordinates as below.
            cf.ptCurrentPos.x = inputWinRec.left - focusWinRec.left;
            cf.ptCurrentPos.y = inputWinRec.bottom - focusWinRec.top;

            // sends IMC_SETCANDIDATEPOS to IMM to move the candidate window.
            ::SendMessage(defaultIMEWnd, WM_IME_CONTROL, IMC_SETCANDIDATEPOS, (LPARAM)&cf);
        }
    }
}

void
AwtFrame::SetMaximizedBounds(int x, int y, int w, int h)
{
    m_maxPos.x  = x;
    m_maxPos.y  = y;
    m_maxSize.x = w;
    m_maxSize.y = h;
    m_maxBoundsSet = TRUE;
}

MsgRouting AwtFrame::WmGetMinMaxInfo(LPMINMAXINFO lpmmi)
{
    //Firstly call AwtWindow's function
    MsgRouting r = AwtWindow::WmGetMinMaxInfo(lpmmi);

    //Then replace maxPos & maxSize if necessary
    if (!m_maxBoundsSet) {
        return r;
    }

    if (m_maxPos.x != java_lang_Integer_MAX_VALUE)
        lpmmi->ptMaxPosition.x = m_maxPos.x;
    if (m_maxPos.y != java_lang_Integer_MAX_VALUE)
        lpmmi->ptMaxPosition.y = m_maxPos.y;
    if (m_maxSize.x != java_lang_Integer_MAX_VALUE)
        lpmmi->ptMaxSize.x = m_maxSize.x;
    if (m_maxSize.y != java_lang_Integer_MAX_VALUE)
        lpmmi->ptMaxSize.y = m_maxSize.y;
    return mrConsume;
}

MsgRouting AwtFrame::WmSize(UINT type, int w, int h)
{
    currentWmSizeState = type;
    if (currentWmSizeState == SIZE_MINIMIZED) {
        UpdateSecurityWarningVisibility();
    }

    if (m_ignoreWmSize) {
        return mrDoDefault;
    }

    DTRACE_PRINTLN6("AwtFrame::WmSize: %dx%d,%s visible, state%s%s%s",
                  w, h,
                  ::IsWindowVisible(GetHWnd()) ? "" : " not",
                  m_iconic ? " iconic" : "",
                  m_zoomed ? " zoomed" : "",
                  m_iconic || m_zoomed ? "" : " normal");

    BOOL iconify = type == SIZE_MINIMIZED;

    // Note that zoom may be set to TRUE in several cases:
    //    1. type == SIZE_MAXIMIZED means that either the user or
    //       the developer (via setExtendedState(MAXIMIZED_BOTH)
    //       maximizes the frame.
    //    2. type == SIZE_MINIMIZED && isZoomed() means that a maximized
    //       frame is to be minimized. If the user minimizes a maximized
    //       frame, we need to keep the zoomed property TRUE. However,
    //       if the developer calls setExtendedState(ICONIFIED), i.e.
    //       w/o combining the ICONIFIED state with the MAXIMIZED state,
    //       we MUST RESET the zoomed property.
    //       The flag m_forceResetZoomed identifies the latter case.
    BOOL zoom =
        (
         type == SIZE_MAXIMIZED
         ||
         (type == SIZE_MINIMIZED && isZoomed())
        )
        && !m_forceResetZoomed;

    // Set the new state and send appropriate Java event
    jint oldState = java_awt_Frame_NORMAL;
    if (isIconic()) {
        oldState |= java_awt_Frame_ICONIFIED;
    }
    if (isZoomed()) {
        oldState |= java_awt_Frame_MAXIMIZED_BOTH;
    }

    jint newState = java_awt_Frame_NORMAL;
    if (iconify) {
        newState |= java_awt_Frame_ICONIFIED;
    }
    if (zoom) {
        newState |= java_awt_Frame_MAXIMIZED_BOTH;
    }

    setIconic(iconify);
    setZoomed(zoom);

    jint changed = oldState ^ newState;
    if (changed != 0) {
        DTRACE_PRINTLN2("AwtFrame::WmSize: reporting state change %x -> %x",
                oldState, newState);

        // sync target with peer
        JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
        env->CallVoidMethod(GetPeer(env), AwtFrame::setExtendedStateMID, newState);

        // report (de)iconification to old clients
        if (changed & java_awt_Frame_ICONIFIED) {
            if (newState & java_awt_Frame_ICONIFIED) {
                SendWindowEvent(java_awt_event_WindowEvent_WINDOW_ICONIFIED);
            } else {
                SendWindowEvent(java_awt_event_WindowEvent_WINDOW_DEICONIFIED);
            }
        }

        // New (since 1.4) state change event
        SendWindowStateEvent(oldState, newState);
    }

    // If window is in iconic state, do not send COMPONENT_RESIZED event
    if (isIconic()) {
        return mrDoDefault;
    }

    return AwtWindow::WmSize(type, w, h);
}

MsgRouting AwtFrame::WmActivate(UINT nState, BOOL fMinimized, HWND opposite)
{
    jint type;

    if (nState != WA_INACTIVE) {
        if (::IsWindow(AwtWindow::GetModalBlocker(GetHWnd())) ||
            CheckActivateActualFocusedWindow(opposite))
        {
            return mrConsume;
        }
        type = java_awt_event_WindowEvent_WINDOW_GAINED_FOCUS;
        AwtComponent::SetFocusedWindow(GetHWnd());

    } else {
        if (!::IsWindow(AwtWindow::GetModalBlocker(opposite))) {
            // If deactivation happens because of press on grabbing
            // window - this is nonsense, since grabbing window is
            // assumed to have focus and watch for deactivation.  But
            // this can happen - if grabbing window is proxied Window,
            // with Frame keeping real focus for it.
            if (m_grabbedWindow != NULL) {
                if (m_grabbedWindow->GetHWnd() == opposite) {
                    // Do nothing
                } else {
                    // Normally, we would rather check that this ==
                    // grabbed window, and focus is leaving it -
                    // ungrab.  But since we know about proxied
                    // windows, we simply assume this is one of the
                    // known cases.
                    if (!m_grabbedWindow->IsOneOfOwnersOf((AwtWindow*)AwtComponent::GetComponent(opposite))) {
                        m_grabbedWindow->Ungrab();
                    }
                }
            }
            CheckRetainActualFocusedWindow(opposite);

            type = java_awt_event_WindowEvent_WINDOW_LOST_FOCUS;
            AwtComponent::SetFocusedWindow(NULL);
            sm_focusOwner = NULL;
        }
    }

    SendWindowEvent(type, opposite);
    return mrConsume;
}

BOOL AwtFrame::CheckActivateActualFocusedWindow(HWND deactivatedOpositeHWnd)
{
    if (m_actualFocusedWindow != NULL) {
        HWND hwnd = m_actualFocusedWindow->GetHWnd();
        if (hwnd != NULL && ::IsWindowVisible(hwnd)) {
            SynthesizeWmActivate(TRUE, hwnd, deactivatedOpositeHWnd);
            return TRUE;
        }
        m_actualFocusedWindow = NULL;
    }
    return FALSE;
}

void AwtFrame::CheckRetainActualFocusedWindow(HWND activatedOpositeHWnd)
{
    // If actual focused window is not this Frame
    if (AwtComponent::GetFocusedWindow() != GetHWnd()) {
        // Make sure the actual focused window is an owned window of this frame
        AwtWindow *focusedWindow = (AwtWindow *)AwtComponent::GetComponent(AwtComponent::GetFocusedWindow());
        if (focusedWindow != NULL && focusedWindow->GetOwningFrameOrDialog() == this) {

            // Check that the opposite window is not this frame, nor an owned window of this frame
            if (activatedOpositeHWnd != NULL) {
                AwtWindow *oppositeWindow = (AwtWindow *)AwtComponent::GetComponent(activatedOpositeHWnd);
                if (oppositeWindow && oppositeWindow != this &&
                    oppositeWindow->GetOwningFrameOrDialog() != this)
                {
                    m_actualFocusedWindow = focusedWindow;
                }
            } else {
                 m_actualFocusedWindow = focusedWindow;
            }
        }
    }
}

BOOL AwtFrame::AwtSetActiveWindow(BOOL isMouseEventCause, UINT hittest)
{
    if (hittest == HTCLIENT) {
        // Don't let the actualFocusedWindow to steal focus if:
        // a) the frame is clicked in its client area;
        // b) focus is requested to some of the frame's child.
        m_actualFocusedWindow = NULL;
    }
    return AwtWindow::AwtSetActiveWindow(isMouseEventCause);
}

MsgRouting AwtFrame::WmEnterMenuLoop(BOOL isTrackPopupMenu)
{
    if ( !isTrackPopupMenu ) {
        m_isMenuDropped = TRUE;
    }
    return mrDoDefault;
}

MsgRouting AwtFrame::WmExitMenuLoop(BOOL isTrackPopupMenu)
{
    if ( !isTrackPopupMenu ) {
        m_isMenuDropped = FALSE;
    }
    return mrDoDefault;
}

AwtMenuBar* AwtFrame::GetMenuBar()
{
    return menuBar;
}

void AwtFrame::SetMenuBar(AwtMenuBar* mb)
{
    menuBar = mb;
    if (mb == NULL) {
        // Remove existing menu bar, if any.
        ::SetMenu(GetHWnd(), NULL);
    } else {
        if (menuBar->GetHMenu() != NULL) {
            ::SetMenu(GetHWnd(), menuBar->GetHMenu());
        }
    }
}

MsgRouting AwtFrame::WmDrawItem(UINT ctrlId, DRAWITEMSTRUCT& drawInfo)
{
    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);

    // if the item to be redrawn is the menu bar, then do it
    AwtMenuBar* awtMenubar = GetMenuBar();
    if (drawInfo.CtlType == ODT_MENU && (awtMenubar != NULL) &&
        (::GetMenu( GetHWnd() ) == (HMENU)drawInfo.hwndItem) )
        {
                awtMenubar->DrawItem(drawInfo);
                return mrConsume;
    }

        return AwtComponent::WmDrawItem(ctrlId, drawInfo);
}

MsgRouting AwtFrame::WmMeasureItem(UINT ctrlId, MEASUREITEMSTRUCT& measureInfo)
{
        JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
        AwtMenuBar* awtMenubar = GetMenuBar();
        if ((measureInfo.CtlType == ODT_MENU) && (awtMenubar != NULL))
        {
                // AwtMenu instance is stored in itemData. Use it to check if this
                // menu is the menu bar.
                AwtMenu * pMenu = (AwtMenu *) measureInfo.itemData;
                DASSERT(pMenu != NULL);
                if ( pMenu == awtMenubar )
                {
                        HWND hWnd = GetHWnd();
                        HDC hDC = ::GetDC(hWnd);
                        DASSERT(hDC != NULL);
                        awtMenubar->MeasureItem(hDC, measureInfo);
                        VERIFY(::ReleaseDC(hWnd, hDC));
                        return mrConsume;
                }
        }

        return AwtComponent::WmMeasureItem(ctrlId, measureInfo);
}

MsgRouting AwtFrame::WmGetIcon(WPARAM iconType, LRESULT& retVal)
{
    //Workaround windows bug:
    //when reseting from specific icon to class icon
    //taskbar is not updated
    if (iconType <= 2 /*ICON_SMALL2*/) {
        retVal = (LRESULT)GetEffectiveIcon(iconType);
        return mrConsume;
    } else {
        return mrDoDefault;
    }
}

void AwtFrame::DoUpdateIcon()
{
    //Workaround windows bug:
    //when reseting from specific icon to class icon
    //taskbar is not updated
    HICON hIcon = GetEffectiveIcon(ICON_BIG);
    HICON hIconSm = GetEffectiveIcon(ICON_SMALL);
    SendMessage(WM_SETICON, ICON_BIG,   (LPARAM)hIcon);
    SendMessage(WM_SETICON, ICON_SMALL, (LPARAM)hIconSm);
}

HICON AwtFrame::GetEffectiveIcon(int iconType)
{
    BOOL smallIcon = ((iconType == ICON_SMALL) || (iconType == 2/*ICON_SMALL2*/));
    HICON hIcon = (smallIcon) ? GetHIconSm() : GetHIcon();
    if (hIcon == NULL) {
        hIcon = (smallIcon) ? AwtToolkit::GetInstance().GetAwtIconSm() :
            AwtToolkit::GetInstance().GetAwtIcon();
    }
    return hIcon;
}

static BOOL keepOnMinimize(jobject peer) {
    static BOOL checked = FALSE;
    static BOOL keep = FALSE;
    if (!checked) {
        keep = (JNU_GetStaticFieldByName(AwtToolkit::GetEnv(), NULL,
            "sun/awt/windows/WFramePeer", "keepOnMinimize", "Z").z) == JNI_TRUE;
        checked = TRUE;
    }
    return keep;
}

MsgRouting AwtFrame::WmSysCommand(UINT uCmdType, int xPos, int yPos)
{
    // ignore any WM_SYSCOMMAND if this window is blocked by modal dialog
    if (::IsWindow(AwtWindow::GetModalBlocker(GetHWnd()))) {
        return mrConsume;
    }

    if (uCmdType == (SYSCOMMAND_IMM & 0xFFF0)){
        JNIEnv* env = AwtToolkit::GetEnv();
        JNU_CallMethodByName(env, NULL, m_peerObject,
            "notifyIMMOptionChange", "()V");
        DASSERT(!safe_ExceptionOccurred(env));
        return mrConsume;
    }
    if ((uCmdType == SC_MINIMIZE) && keepOnMinimize(m_peerObject)) {
        ::ShowWindow(GetHWnd(),SW_SHOWMINIMIZED);
        return mrConsume;
    }
    return AwtWindow::WmSysCommand(uCmdType, xPos, yPos);
}

LRESULT AwtFrame::WinThreadExecProc(ExecuteArgs * args)
{
    switch( args->cmdId ) {
        case FRAME_SETMENUBAR:
        {
            jobject  mbPeer = (jobject)args->param1;

            // cancel any currently dropped down menus
            if (m_isMenuDropped) {
                SendMessage(WM_CANCELMODE);
            }

            if (mbPeer == NULL) {
                // Remove existing menu bar, if any
                SetMenuBar(NULL);
            } else {
                JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
                AwtMenuBar* menuBar = (AwtMenuBar *)JNI_GET_PDATA(mbPeer);
                SetMenuBar(menuBar);
            }
            DrawMenuBar();
            break;
        }

        default:
            AwtWindow::WinThreadExecProc(args);
            break;
    }

    return 0L;
}

void AwtFrame::_SynthesizeWmActivate(void *param)
{
    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);

    SynthesizeWmActivateStruct *sas = (SynthesizeWmActivateStruct *)param;
    jobject self = sas->frame;
    jboolean doActivate = sas->doActivate;

    AwtFrame *frame = NULL;

    PDATA pData;
    JNI_CHECK_PEER_GOTO(self, ret);
    frame = (AwtFrame *)pData;

    SynthesizeWmActivate(doActivate, frame->GetHWnd(), NULL);
ret:
    env->DeleteGlobalRef(self);

    delete sas;
}

jobject AwtFrame::_GetBoundsPrivate(void *param)
{
    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);

    jobject self = (jobject)param;

    jobject result = NULL;
    AwtFrame *f = NULL;

    PDATA pData;
    JNI_CHECK_PEER_GOTO(self, ret);
    f = (AwtFrame *)pData;
    if (::IsWindow(f->GetHWnd()))
    {
        RECT rect;
        ::GetWindowRect(f->GetHWnd(), &rect);
        HWND parent = ::GetParent(f->GetHWnd());
        if (::IsWindow(parent))
        {
            POINT zero;
            zero.x = 0;
            zero.y = 0;
            ::ClientToScreen(parent, &zero);
            ::OffsetRect(&rect, -zero.x, -zero.y);
        }

        result = JNU_NewObjectByName(env, "java/awt/Rectangle", "(IIII)V",
            rect.left, rect.top, rect.bottom-rect.top, rect.right-rect.left);
    }
ret:
    env->DeleteGlobalRef(self);

    if (result != NULL)
    {
        jobject resultGlobalRef = env->NewGlobalRef(result);
        env->DeleteLocalRef(result);
        return resultGlobalRef;
    }
    else
    {
        return NULL;
    }
}

void AwtFrame::_SetState(void *param)
{
    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);

    SetStateStruct *sss = (SetStateStruct *)param;
    jobject self = sss->frame;
    jint state = sss->state;

    AwtFrame *f = NULL;

    PDATA pData;
    JNI_CHECK_PEER_GOTO(self, ret);
    f = (AwtFrame *)pData;
    HWND hwnd = f->GetHWnd();
    if (::IsWindow(hwnd))
    {
        DASSERT(!IsBadReadPtr(f, sizeof(AwtFrame)));

        BOOL iconify = (state & java_awt_Frame_ICONIFIED) != 0;
        BOOL zoom = (state & java_awt_Frame_MAXIMIZED_BOTH)
                        == java_awt_Frame_MAXIMIZED_BOTH;

        DTRACE_PRINTLN4("WFramePeer.setState:%s%s ->%s%s",
                  f->isIconic() ? " iconic" : "",
                  f->isZoomed() ? " zoomed" : "",
                  iconify       ? " iconic" : "",
                  zoom          ? " zoomed" : "");

        if (::IsWindowVisible(hwnd)) {
            BOOL focusable = f->IsFocusableWindow();

            WINDOWPLACEMENT wp;
            ::ZeroMemory(&wp, sizeof(wp));
            wp.length = sizeof(wp);
            ::GetWindowPlacement(hwnd, &wp);

            // Iconify first.
            // If both iconify & zoom are TRUE, handle this case
            // with wp.flags field below.
            if (iconify) {
                wp.showCmd = focusable ? SW_MINIMIZE : SW_SHOWMINNOACTIVE;
            } else if (zoom) {
                wp.showCmd = focusable ? SW_SHOWMAXIMIZED : SW_MAXIMIZE;
            } else { // zoom == iconify == FALSE
                wp.showCmd = focusable ? SW_RESTORE : SW_SHOWNOACTIVATE;
            }

            if (zoom && iconify) {
                wp.flags |= WPF_RESTORETOMAXIMIZED;
            } else {
                wp.flags &= ~WPF_RESTORETOMAXIMIZED;
            }

            if (!zoom) {
                f->m_forceResetZoomed = TRUE;
            }

            // The SetWindowPlacement() causes the WmSize() invocation
            //  which, in turn, actually updates the m_iconic & m_zoomed flags
            //  as well as sends Java event (WINDOW_STATE_CHANGED.)
            ::SetWindowPlacement(hwnd, &wp);

            f->m_forceResetZoomed = FALSE;
        } else {
            DTRACE_PRINTLN("  not visible, just recording the requested state");

            f->setIconic(iconify);
            f->setZoomed(zoom);
        }
    }
ret:
    env->DeleteGlobalRef(self);

    delete sss;
}

jint AwtFrame::_GetState(void *param)
{
    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);

    jobject self = (jobject)param;

    jint result = java_awt_Frame_NORMAL;
    AwtFrame *f = NULL;

    PDATA pData;
    JNI_CHECK_PEER_GOTO(self, ret);
    f = (AwtFrame *)pData;
    if (::IsWindow(f->GetHWnd()))
    {
        DASSERT(!::IsBadReadPtr(f, sizeof(AwtFrame)));
        if (f->isIconic()) {
            result |= java_awt_Frame_ICONIFIED;
        }
        if (f->isZoomed()) {
            result |= java_awt_Frame_MAXIMIZED_BOTH;
        }

        DTRACE_PRINTLN2("WFramePeer.getState:%s%s",
                  f->isIconic() ? " iconic" : "",
                  f->isZoomed() ? " zoomed" : "");
    }
ret:
    env->DeleteGlobalRef(self);

    return result;
}

void AwtFrame::_SetMaximizedBounds(void *param)
{
    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);

    SetMaximizedBoundsStruct *smbs = (SetMaximizedBoundsStruct *)param;
    jobject self = smbs->frame;
    int x = smbs->x;
    int y = smbs->y;
    int width = smbs->width;
    int height = smbs->height;

    AwtFrame *f = NULL;

    PDATA pData;
    JNI_CHECK_PEER_GOTO(self, ret);
    f = (AwtFrame *)pData;
    if (::IsWindow(f->GetHWnd()))
    {
        DASSERT(!::IsBadReadPtr(f, sizeof(AwtFrame)));
        f->SetMaximizedBounds(x, y, width, height);
    }
ret:
    env->DeleteGlobalRef(self);

    delete smbs;
}

void AwtFrame::_ClearMaximizedBounds(void *param)
{
    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);

    jobject self = (jobject)param;

    AwtFrame *f = NULL;

    PDATA pData;
    JNI_CHECK_PEER_GOTO(self, ret);
    f = (AwtFrame *)pData;
    if (::IsWindow(f->GetHWnd()))
    {
        DASSERT(!::IsBadReadPtr(f, sizeof(AwtFrame)));
        f->ClearMaximizedBounds();
    }
ret:
    env->DeleteGlobalRef(self);
}

void AwtFrame::_SetMenuBar(void *param)
{
    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);

    SetMenuBarStruct *smbs = (SetMenuBarStruct *)param;
    jobject self = smbs->frame;
    jobject menubar = smbs->menubar;

    AwtFrame *f = NULL;

    PDATA pData;
    JNI_CHECK_PEER_GOTO(self, ret);
    f = (AwtFrame *)pData;
    if (::IsWindow(f->GetHWnd()))
    {
        ExecuteArgs args;
        args.cmdId = FRAME_SETMENUBAR;
        args.param1 = (LPARAM)menubar;
        f->WinThreadExecProc(&args);
    }
ret:
    env->DeleteGlobalRef(self);
    env->DeleteGlobalRef(menubar);

    delete smbs;
}

void AwtFrame::_SetIMMOption(void *param)
{
    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);

    SetIMMOptionStruct *sios = (SetIMMOptionStruct *)param;
    jobject self = sios->frame;
    jstring option = sios->option;

    int badAlloc = 0;
    LPCTSTR coption;
    LPCTSTR empty = TEXT("InputMethod");
    AwtFrame *f = NULL;

    PDATA pData;
    JNI_CHECK_PEER_GOTO(self, ret);
    JNI_CHECK_NULL_GOTO(option, "IMMOption argument", ret);

    f = (AwtFrame *)pData;
    if (::IsWindow(f->GetHWnd()))
    {
        coption = JNU_GetStringPlatformChars(env, option, NULL);
        if (coption == NULL)
        {
            badAlloc = 1;
        }
        if (!badAlloc)
        {
            HMENU hSysMenu = ::GetSystemMenu(f->GetHWnd(), FALSE);
            ::AppendMenu(hSysMenu,  MF_STRING, SYSCOMMAND_IMM, coption);

            if (coption != empty)
            {
                JNU_ReleaseStringPlatformChars(env, option, coption);
            }
        }
    }
ret:
    env->DeleteGlobalRef(self);
    env->DeleteGlobalRef(option);

    delete sios;

    if (badAlloc)
    {
        throw std::bad_alloc();
    }
}

void AwtFrame::_NotifyModalBlocked(void *param)
{
    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);

    NotifyModalBlockedStruct *nmbs = (NotifyModalBlockedStruct *)param;
    jobject self = nmbs->frame;
    jobject peer = nmbs->peer;
    jobject blockerPeer = nmbs->blockerPeer;
    jboolean blocked = nmbs->blocked;

    PDATA pData;

    pData = JNI_GET_PDATA(peer);
    AwtFrame *f = (AwtFrame *)pData;

    // dialog here may be NULL, for example, if the blocker is a native dialog
    // however, we need to install/unistall modal hooks anyway
    pData = JNI_GET_PDATA(blockerPeer);
    AwtDialog *d = (AwtDialog *)pData;

    if ((f != NULL) && ::IsWindow(f->GetHWnd()))
    {
        // get an HWND of the toplevel window this embedded frame is within
        HWND fHWnd = f->GetHWnd();
        while (::GetParent(fHWnd) != NULL) {
            fHWnd = ::GetParent(fHWnd);
        }
        // we must get a toplevel hwnd here, however due to some strange
        // behaviour of Java Plugin (a bug?) when running in IE at
        // this moment the embedded frame hasn't been placed into the
        // browser yet and fHWnd is not a toplevel, so we shouldn't install
        // the hook here
        if ((::GetWindowLong(fHWnd, GWL_STYLE) & WS_CHILD) == 0) {
            // if this toplevel is created in another thread, we should install
            // the modal hook into it to track window activation and mouse events
            DWORD fThread = ::GetWindowThreadProcessId(fHWnd, NULL);
            if (fThread != AwtToolkit::GetInstance().MainThread()) {
                // check if this thread has been already blocked
                BlockedThreadStruct *blockedThread = (BlockedThreadStruct *)sm_BlockedThreads.get((void *)fThread);
                if (blocked) {
                    if (blockedThread == NULL) {
                        blockedThread = new BlockedThreadStruct;
                        blockedThread->framesCount = 1;
                        blockedThread->modalHook = ::SetWindowsHookEx(WH_CBT, (HOOKPROC)AwtDialog::ModalFilterProc,
                                                                      0, fThread);
                        blockedThread->mouseHook = ::SetWindowsHookEx(WH_MOUSE, (HOOKPROC)AwtDialog::MouseHookProc_NonTT,
                                                                      0, fThread);
                        sm_BlockedThreads.put((void *)fThread, blockedThread);
                    } else {
                        blockedThread->framesCount++;
                    }
                } else {
                    // see the comment above: if Java Plugin behaviour when running in IE
                    // was right, blockedThread would be always not NULL here
                    if (blockedThread != NULL) {
                        DASSERT(blockedThread->framesCount > 0);
                        if ((blockedThread->framesCount) == 1) {
                            ::UnhookWindowsHookEx(blockedThread->modalHook);
                            ::UnhookWindowsHookEx(blockedThread->mouseHook);
                            sm_BlockedThreads.remove((void *)fThread);
                            delete blockedThread;
                        } else {
                            blockedThread->framesCount--;
                        }
                    }
                }
            }
        }
    }

    env->DeleteGlobalRef(self);
    env->DeleteGlobalRef(peer);
    env->DeleteGlobalRef(blockerPeer);

    delete nmbs;
}

/************************************************************************
 * WFramePeer native methods
 */

extern "C" {

/*
 * Class:     java_awt_Frame
 * Method:    initIDs
 * Signature: ()V
 */
JNIEXPORT void JNICALL
Java_java_awt_Frame_initIDs(JNIEnv *env, jclass cls)
{
    TRY;

    AwtFrame::undecoratedID = env->GetFieldID(cls,"undecorated","Z");
    DASSERT(AwtFrame::undecoratedID != NULL);

    CATCH_BAD_ALLOC;
}

/*
 * Class:     sun_awt_windows_WFramePeer
 * Method:    initIDs
 * Signature: ()V
 */
JNIEXPORT void JNICALL
Java_sun_awt_windows_WFramePeer_initIDs(JNIEnv *env, jclass cls)
{
    TRY;

    AwtFrame::setExtendedStateMID = env->GetMethodID(cls, "setExtendedState", "(I)V");
    AwtFrame::getExtendedStateMID = env->GetMethodID(cls, "getExtendedState", "()I");

    DASSERT(AwtFrame::setExtendedStateMID);
    DASSERT(AwtFrame::getExtendedStateMID);

    CATCH_BAD_ALLOC;
}

/*
 * Class:     sun_awt_windows_WFramePeer
 * Method:    setState
 * Signature: (I)V
 */
JNIEXPORT void JNICALL
Java_sun_awt_windows_WFramePeer_setState(JNIEnv *env, jobject self,
    jint state)
{
    TRY;

    SetStateStruct *sss = new SetStateStruct;
    sss->frame = env->NewGlobalRef(self);
    sss->state = state;

    AwtToolkit::GetInstance().SyncCall(AwtFrame::_SetState, sss);
    // global ref and sss are deleted in _SetState()

    CATCH_BAD_ALLOC;
}

/*
 * Class:     sun_awt_windows_WFramePeer
 * Method:    getState
 * Signature: ()I
 */
JNIEXPORT jint JNICALL
Java_sun_awt_windows_WFramePeer_getState(JNIEnv *env, jobject self)
{
    TRY;

    jobject selfGlobalRef = env->NewGlobalRef(self);

    return static_cast<jint>(reinterpret_cast<INT_PTR>(AwtToolkit::GetInstance().SyncCall(
        (void*(*)(void*))AwtFrame::_GetState,
        (void *)selfGlobalRef)));
    // selfGlobalRef is deleted in _GetState()

    CATCH_BAD_ALLOC_RET(java_awt_Frame_NORMAL);
}


/*
 * Class:     sun_awt_windows_WFramePeer
 * Method:    setMaximizedBounds
 * Signature: (IIII)V
 */
JNIEXPORT void JNICALL
Java_sun_awt_windows_WFramePeer_setMaximizedBounds(JNIEnv *env, jobject self,
    jint x, jint y, jint width, jint height)
{
    TRY;

    SetMaximizedBoundsStruct *smbs = new SetMaximizedBoundsStruct;
    smbs->frame = env->NewGlobalRef(self);
    smbs->x = x;
    smbs->y = y;
    smbs->width = width;
    smbs->height = height;

    AwtToolkit::GetInstance().SyncCall(AwtFrame::_SetMaximizedBounds, smbs);
    // global ref and smbs are deleted in _SetMaximizedBounds()

    CATCH_BAD_ALLOC;
}


/*
 * Class:     sun_awt_windows_WFramePeer
 * Method:    clearMaximizedBounds
 * Signature: ()V
 */
JNIEXPORT void JNICALL
Java_sun_awt_windows_WFramePeer_clearMaximizedBounds(JNIEnv *env, jobject self)
{
    TRY;

    jobject selfGlobalRef = env->NewGlobalRef(self);

    AwtToolkit::GetInstance().SyncCall(AwtFrame::_ClearMaximizedBounds,
        (void *)selfGlobalRef);
    // selfGlobalRef is deleted in _ClearMaximizedBounds()

    CATCH_BAD_ALLOC;
}


/*
 * Class:     sun_awt_windows_WFramePeer
 * Method:    setMenuBar0
 * Signature: (Lsun/awt/windows/WMenuBarPeer;)V
 */
JNIEXPORT void JNICALL
Java_sun_awt_windows_WFramePeer_setMenuBar0(JNIEnv *env, jobject self,
                                            jobject mbPeer)
{
    TRY;

    SetMenuBarStruct *smbs = new SetMenuBarStruct;
    smbs->frame = env->NewGlobalRef(self);
    smbs->menubar = env->NewGlobalRef(mbPeer);

    AwtToolkit::GetInstance().SyncCall(AwtFrame::_SetMenuBar, smbs);
    // global refs ans smbs are deleted in _SetMenuBar()

    CATCH_BAD_ALLOC;
}

/*
 * Class:     sun_awt_windows_WFramePeer
 * Method:    create
 * Signature: (Lsun/awt/windows/WComponentPeer;)V
 */
JNIEXPORT void JNICALL
Java_sun_awt_windows_WFramePeer_createAwtFrame(JNIEnv *env, jobject self,
                                               jobject parent)
{
    TRY;

    AwtToolkit::CreateComponent(self, parent,
                                (AwtToolkit::ComponentFactory)
                                AwtFrame::Create);
    PDATA pData;
    JNI_CHECK_PEER_CREATION_RETURN(self);

    CATCH_BAD_ALLOC;
}

/*
 * Class:     sun_awt_windows_WFramePeer
 * Method:    getSysMenuHeight
 * Signature: ()I
 */
JNIEXPORT jint JNICALL
Java_sun_awt_windows_WFramePeer_getSysMenuHeight(JNIEnv *env, jclass self)
{
    TRY;

    return ::GetSystemMetrics(SM_CYMENUSIZE);

    CATCH_BAD_ALLOC_RET(0);
}

/*
 * Class:     sun_awt_windows_WFramePeer
 * Method:    pSetIMMOption
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL
Java_sun_awt_windows_WFramePeer_pSetIMMOption(JNIEnv *env, jobject self,
                                               jstring option)
{
    TRY;

    SetIMMOptionStruct *sios = new SetIMMOptionStruct;
    sios->frame = env->NewGlobalRef(self);
    sios->option = (jstring)env->NewGlobalRef(option);

    AwtToolkit::GetInstance().SyncCall(AwtFrame::_SetIMMOption, sios);
    // global refs and sios are deleted in _SetIMMOption()

    CATCH_BAD_ALLOC;
}

} /* extern "C" */


/************************************************************************
 * EmbeddedFrame native methods
 */

extern "C" {

/*
 * Class:     sun_awt_EmbeddedFrame
 * Method:    setPeer
 * Signature: (Ljava/awt/peer/ComponentPeer;)V
 */
JNIEXPORT void JNICALL
Java_sun_awt_EmbeddedFrame_setPeer(JNIEnv *env, jobject self, jobject lpeer)
{
    TRY;

    jclass cls;
    jfieldID fid;

    cls = env->GetObjectClass(self);
    fid = env->GetFieldID(cls, "peer", "Ljava/awt/peer/ComponentPeer;");
    env->SetObjectField(self, fid, lpeer);

    CATCH_BAD_ALLOC;
}

} /* extern "C" */


/************************************************************************
 * WEmbeddedFrame native methods
 */

extern "C" {

/*
 * Class:     sun_awt_windows_WFramePeer
 * Method:    initIDs
 * Signature: (Lsun/awt/windows/WMenuBarPeer;)V
 */
JNIEXPORT void JNICALL
Java_sun_awt_windows_WEmbeddedFrame_initIDs(JNIEnv *env, jclass cls)
{
    TRY;

    AwtFrame::handleID = env->GetFieldID(cls, "handle", "J");
    DASSERT(AwtFrame::handleID != NULL);

    AwtFrame::activateEmbeddingTopLevelMID = env->GetMethodID(cls, "activateEmbeddingTopLevel", "()V");
    DASSERT(AwtFrame::activateEmbeddingTopLevelMID != NULL);

    CATCH_BAD_ALLOC;
}

JNIEXPORT void JNICALL
Java_sun_awt_windows_WEmbeddedFrame_notifyModalBlockedImpl(JNIEnv *env,
                                                           jobject self,
                                                           jobject peer,
                                                           jobject blockerPeer,
                                                           jboolean blocked)
{
    TRY;

    NotifyModalBlockedStruct *nmbs = new NotifyModalBlockedStruct;
    nmbs->frame = env->NewGlobalRef(self);
    nmbs->peer = env->NewGlobalRef(peer);
    nmbs->blockerPeer = env->NewGlobalRef(blockerPeer);
    nmbs->blocked = blocked;

    AwtToolkit::GetInstance().SyncCall(AwtFrame::_NotifyModalBlocked, nmbs);
    // global refs and nmbs are deleted in _NotifyModalBlocked()

    CATCH_BAD_ALLOC;
}

} /* extern "C" */


/************************************************************************
 * WEmbeddedFramePeer native methods
 */

extern "C" {

JNIEXPORT void JNICALL
Java_sun_awt_windows_WEmbeddedFramePeer_create(JNIEnv *env, jobject self,
                                               jobject parent)
{
    TRY;

    JNI_CHECK_NULL_RETURN(self, "peer");
    AwtToolkit::CreateComponent(self, parent,
                                (AwtToolkit::ComponentFactory)
                                AwtFrame::Create);
    PDATA pData;
    JNI_CHECK_PEER_CREATION_RETURN(self);

    CATCH_BAD_ALLOC;
}

JNIEXPORT jobject JNICALL
Java_sun_awt_windows_WEmbeddedFramePeer_getBoundsPrivate(JNIEnv *env, jobject self)
{
    TRY;

    jobject result = (jobject)AwtToolkit::GetInstance().SyncCall(
        (void *(*)(void *))AwtFrame::_GetBoundsPrivate,
        env->NewGlobalRef(self));
    // global ref is deleted in _GetBoundsPrivate

    if (result != NULL)
    {
        jobject resultLocalRef = env->NewLocalRef(result);
        env->DeleteGlobalRef(result);
        return resultLocalRef;
    }
    else
    {
        return NULL;
    }

    CATCH_BAD_ALLOC_RET(NULL);
}

JNIEXPORT void JNICALL
Java_sun_awt_windows_WEmbeddedFramePeer_synthesizeWmActivate(JNIEnv *env, jobject self, jboolean doActivate)
{
    TRY;

    SynthesizeWmActivateStruct *sas = new SynthesizeWmActivateStruct;
    sas->frame = env->NewGlobalRef(self);
    sas->doActivate = doActivate;

    /*
     * WARNING: invoking this function without synchronization by m_Sync CriticalSection.
     * Taking this lock results in a deadlock.
     */
    AwtToolkit::GetInstance().InvokeFunction(AwtFrame::_SynthesizeWmActivate, sas);
    // global ref and sas are deleted in _SynthesizeWmActivate()

    CATCH_BAD_ALLOC;
}

} /* extern "C" */
