Milán Major

netscape-revival

1 branch
Code

sun-java/awt.bad/win/awt_toolkit.cpp

#include "awt_palette.h"
#include "awt_toolkit.h"
#include "awt_component.h"
#include "awt_image.h"

#include "prlink.h" // PR_LoadStaticLibrary() 


// All java header files are extern "C"
extern "C" {
#include "java_awt_Event.h"
#include "java_awt_image_ColorModel.h"

#include "sun_awt_windows_WToolkit.h"
#include "sun_awt_windows_WComponentPeer.h"
};

//
// Definitions of int64 constants 
//
#ifndef HAVE_LONG_LONG

#ifdef IS_LITTLE_ENDIAN
int64 ll_zero_const = { 0, 0 };
int64 ll_one_const  = { 1, 0 };
#else
int64 ll_zero_const = { 0, 0 };
int64 ll_one_const  = { 0, 1 };
#endif

#endif  /* ! HAVE_LONG_LONG */

//
// Maximum delay in milliseconds before the Awt Event Queue is 
// flushed, and all the events are delivered to java
//
#define MAX_AWT_EVENT_DELAY     100

//
// Private Windows message used to force method calls to be made on the
// "Main Gui thread"...
//
#define WM_AWT_CALLMETHOD   (WM_USER+1)

AwtToolkit *AwtToolkit::theToolkit = NULL;
HDC         AwtToolkit::m_hDC      = NULL;

AwtWindow* AwtToolkit::m_HoldMouse = 0;
UINT AwtToolkit::m_TimerId = 0;

HINSTANCE AwtToolkit::m_hDllInstance = 0;

#ifdef DEBUG_CONSOLE
AwtDebug* AwtToolkit::m_pDebug = 0;
#endif

#if !defined(_WIN32)

extern "C" PRStaticLinkTable FAR awt_nodl_tab[];

/*
** This routine returns the nodl_table containing ALL java native methods.
** This table is used by NSPR when looking up symbols in the DLL.
**
** Since Win16 GetProcAddress() is NOT case-sensitive, it is necessary to
** use the nodl table to maintain the case-sensitive java native method names...
*/
extern "C" PRStaticLinkTable * CALLBACK __export __loadds NODL_TABLE(void)
{
    return awt_nodl_tab;
}

//
//
// Dll entry point. Keep the dll instance
//
//
int CALLBACK LibMain( HINSTANCE hModule, WORD wDataSeg, 
                      WORD cbHeapSize, LPSTR lpszCmdLine )
{
    AwtToolkit::m_hDllInstance = hModule;
    return TRUE;
}

extern "C" BOOL CALLBACK __loadds WEP(BOOL fSystemExit)
{
    // Delete any remaining AwtObjects
    AwtObject::DeleteAllObjects();

    AwtCachedBrush::DeleteCache();
    AwtCachedPen::DeleteCache();
    AwtPalette::DeleteCache();

    // Delete the AwtToolkit object
    AwtToolkit::theToolkit->Dispose();

    return TRUE;
}


#else /* WIN32 */

//
//
// Dll entry point. Keep the dll instance
//
//
BOOL APIENTRY DllMain(  HINSTANCE hModule, 
                        DWORD reason, 
                        LPVOID lpReserved )
{
    switch( reason ) {
        case DLL_PROCESS_ATTACH:
			AwtToolkit::m_hDllInstance = hModule;
        case DLL_THREAD_ATTACH:
    
        case DLL_THREAD_DETACH:
    
        case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

#endif // _WIN32

//-------------------------------------------------------------------------
//
//
//-------------------------------------------------------------------------
AwtToolkit::AwtToolkit() : AwtObject(NULL)
{
    WNDCLASS wc;

#if !defined(_WIN32) && defined(DEBUG)
	__asm{ int 3}
#endif
    //
    // Remove from the chain of allocated AwtObjects...
    // The AwtToolkit instance is global and MUST have a longer 
    // lifetime than any other AwtObject.
    //
    // Since the AwtToolkit is the FIRST object to be created, 
    // the liveChain does not need to be locked...
    //
    m_link.Remove();

    //
    // Store the thread ID of the current thread.  
    // The AwtToolkit MUST be created on the "main GUI thread" of 
    // the application.
    //
    m_GuiThreadId  = PR_GetCurrentThreadID();

    m_bShutdown    = FALSE;
    m_eventInQueue = NULL;
    m_eventTimeout = NULL;

    wc.style            = 0;
    wc.lpfnWndProc      = AwtToolkit::WindowProc;
    wc.cbClsExtra       = 0;
    wc.cbWndExtra       = 0;
    wc.hInstance        = ::GetModuleHandle(__awt_dllName);
    wc.hIcon            = ::LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor          = ::LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground    = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName     = NULL;
    wc.lpszClassName    = "AwtToolkitClass";
    
    ::RegisterClass(&wc);

    //
    // Create the Awt Dispatch Window
    //
    m_hAwtDispatchWnd = ::CreateWindow("AwtToolkitClass",
                                       "AwtDispatchWnd",
                                       WS_DISABLED,
                                       -50, -50,
                                       10, 10,
                                       NULL,
                                       NULL,
                                       ::GetModuleHandle(__awt_dllName),
                                       NULL);

    ASSERT( ::IsWindow(m_hAwtDispatchWnd) );

#ifdef DEBUG_CONSOLE
    //AwtToolkit::m_pDebug = new AwtDebug();
#endif

}

#ifdef _WIN32
#define GET_APP_PALETTE_API "GET_APPLICATION_PALETTE"
#else
#define GET_APP_PALETTE_API "_GET_APPLICATION_PALETTE"
#endif

typedef HPALETTE (*GetApplicationPalette)(void);

AwtPalette *AwtToolkit::GetImagePalette(void)
{
   AwtPalette *pAwtPalette=NULL;
   HWND hWnd = ::GetDesktopWindow();
   HDC  hDC  = ::GetDC(hWnd);
   pAwtPalette = AwtPalette::Create(hDC);
   VERIFY( ::ReleaseDC(hWnd, hDC) );
   return pAwtPalette;
}


AwtPalette *AwtToolkit::GetToolkitDefaultPalette(void)
{
    HPALETTE hPal = (HPALETTE)NULL;
    AwtPalette *pAwtPalette=NULL;
    GetApplicationPalette pfGetAppPalette;

    //
    // Look for the exported entry point in the EXE which returns the
    // correct palette...
    //
    // NOTE:
    //    To locate an entry point in an EXE in Win16, NULL must be passed
    //    as the Task Handle...
    //
    pfGetAppPalette = (GetApplicationPalette)::GetProcAddress( 
#ifdef _WIN32
            ::GetModuleHandle(NULL), 
#else
            NULL,
#endif
            GET_APP_PALETTE_API);

    if( pfGetAppPalette ) {
        hPal = (*pfGetAppPalette)();
    }

    if( hPal ) {
        pAwtPalette = AwtPalette::Create(hPal);
    } 
    
    if(pAwtPalette == NULL) {
        if(m_hDC == NULL) {
            HWND hWnd = ::GetDesktopWindow();

            m_hDC=::GetDC(hWnd);
            pAwtPalette = AwtPalette::Create(m_hDC);
            VERIFY( ::ReleaseDC(hWnd, m_hDC) );
        } else {
            pAwtPalette = AwtPalette::Create(m_hDC);
        }
    }
   return pAwtPalette;
}


AwtToolkit::~AwtToolkit()
{
    ASSERT( ::IsWindow(m_hAwtDispatchWnd) );

    //
    // Destroy the Awt Dispatch Window
    //    
    ::DestroyWindow(m_hAwtDispatchWnd);
    m_hAwtDispatchWnd = NULL;

    ::UnregisterClass("AwtToolkitClass", ::GetModuleHandle(__awt_dllName));

    AwtToolkit::theToolkit = NULL;

#ifdef DEBUG_CONSOLE
    //delete AwtToolkit::m_pDebug;
#endif

}


//-------------------------------------------------------------------------
//
//
//-------------------------------------------------------------------------
BOOL AwtToolkit::CreateToolkit(void)
{
    if (AwtToolkit::theToolkit == NULL) {
        AwtToolkit::theToolkit = new AwtToolkit();
        return TRUE;
    }
            
    return FALSE;
}


//-------------------------------------------------------------------------
//
//
//-------------------------------------------------------------------------
BOOL AwtToolkit::CallMethod(AwtMethodInfo *info)
{
    return FALSE;
}


//-------------------------------------------------------------------------
//
//
//-------------------------------------------------------------------------
void AwtToolkit::SetAwtColorPalette(AwtPalette* pAwtPal)
{
    m_pAwtImagePalette = pAwtPal;
}


//-------------------------------------------------------------------------
//
//
//-------------------------------------------------------------------------
HPALETTE AwtToolkit::GetDefaultPalette(void)
{
   return NULL;
}



//-------------------------------------------------------------------------
//
//
//-------------------------------------------------------------------------
BOOL AwtToolkit::CallAwtMethod(AwtMethodInfo *info)
{
    if (! IsGuiThread()) {
        ASSERT( ::IsWindow(m_hAwtDispatchWnd) );

        return ::SendMessage(m_hAwtDispatchWnd, WM_AWT_CALLMETHOD, 0, 
                             (LPARAM)info);
    }

    return info->Invoke();
}


//-------------------------------------------------------------------------
//
// Call an event handler in the java Peer object. (ie. handleXXX(...))
//
//-------------------------------------------------------------------------
void AwtToolkit::RaiseJavaEvent(JHandle *obj, 
                                AwtEventDescription::EventId id,
                                int64 timestamp, 
                                MSG *pMsg, 
                                long arg1, long arg2, long arg3, long arg4,
                                long arg5)

{
    JavaEventInfo *pInfo;

    pInfo = JavaEventInfo::Create();
    if (pInfo != NULL) {
        pInfo->Initialize(obj, id,
                          timestamp, pMsg,
                          arg1, arg2, arg3, arg4, arg5);

        theToolkit->PostEvent(pInfo);
    }
}


//-------------------------------------------------------------------------
//
//
//-------------------------------------------------------------------------
void AwtToolkit::FlushEventQueue(void)
{
#ifdef _WIN32
    ::SetEvent(m_eventInQueue);
    ::SetEvent(m_eventTimeout);
#else
#pragma message("AwtToolkit::FlushEventQueue(...) unimplemented")
#endif
}


//-------------------------------------------------------------------------
//
//
//-------------------------------------------------------------------------
void AwtToolkit::RemoveEventsForObject(JHandle *obj)
{
    AwtCList *qp;
    JavaEventInfo *pInfo;

    // Lock the event queue...
    m_eventMutex.Lock();

    if (!m_eventQueue.IsEmpty()) {
        qp = m_eventQueue.next;
        while (qp != &m_eventQueue) {
            pInfo = (JavaEventInfo *)JAVA_EVENT_PTR(qp);

            qp = qp->next;
            if (pInfo->m_object == obj) {
                //
                // Remove the event from the event queue and place it
                // back on the free chain
                //
                pInfo->Delete();
            }
        }
    }

    // Unlock the event queue...
    m_eventMutex.Unlock();
}


//-------------------------------------------------------------------------
//
//
//-------------------------------------------------------------------------
void AwtToolkit::PostEvent(JavaEventInfo *pNewEvent)
{
    BOOL bEventCombined;
    JavaEventInfo *pInfo;
    int id;

    //
    // If the event queue is no longer running do not post the
    // event
    if (m_bShutdown) {
        return;
    }


    // Lock the event object...
    m_eventMutex.Lock();

    //
    // First try to combine the event with an already pending event.
    //
    // An event may be combined if an event mangler exists for its
    // event type...
    //
    bEventCombined = FALSE;
    id = pNewEvent->m_eventId;
    if (!m_eventQueue.IsEmpty() && (id < AwtEventDescription::MaxEvent)) {
        AwtCList *qp;
        EventMangler *p;

         //
         // If a mangler exists, then walk through the pending events
         // trying to combine...
         //
        p = AwtEventDescription::m_AwtEventMap[id].m_mangler;
        if (p != NULL) {

            qp = m_eventQueue.next;
            while (qp != &m_eventQueue) {
                pInfo = (JavaEventInfo *)JAVA_EVENT_PTR(qp);
                if (pInfo->m_eventId == id) {
                    if (p->Combine(pInfo, pNewEvent)) {
                        bEventCombined = TRUE;
                        break;
                    }
                }
                qp = qp->next;
            }
        }
    }

    //
    // If the event could not be combined with a pending event, then
    // add the event to the event queue..
    //
    if (!bEventCombined) {
        // Add the event to the event queue
        pNewEvent->AddToQueue(m_eventQueue);

        //
        // Notify the callback thread that an event is waiting to
        // be dispatched...
        //
#ifdef _WIN32
        ::SetEvent(m_eventInQueue);

        if (pNewEvent->DispatchEventNow()) {
            ::SetEvent(m_eventTimeout);
        }
#endif
    } 
    //
    // The event was combined with an existing event.  So free the new
    // event now...
    //
    else {
        pNewEvent->Delete();
    }

    // Unlock the event object...
    m_eventMutex.Unlock();
}


//-------------------------------------------------------------------------
//
// Dispatch events to Java.
//
// This method is called by the thread that is responsible for delivering
// Awt events to Java components.
//
//-------------------------------------------------------------------------
void AwtToolkit::CallbackLoop(void)
{
    JavaEventInfo *pInfo;

    //
    // Initialize the events...
    //
#if defined(_WIN32)
    m_eventInQueue = ::CreateEvent(NULL, TRUE, FALSE, NULL);
    m_eventTimeout = ::CreateEvent(NULL, TRUE, FALSE, NULL);
#endif

    CallbackLoop(&m_bShutdown);

    //
    // The AwtCallback thread is terminating...
    //     1. Free the event objects created on entry
    //     2. Move any pending events onto the free chain.  Then clean up
    //        the free chain.
    //
#if defined(_WIN32)
    ::CloseHandle(m_eventInQueue);
    ::CloseHandle(m_eventTimeout);
#endif
    m_eventInQueue = m_eventTimeout = NULL;

    m_eventMutex.Lock();

    while (!m_eventQueue.IsEmpty()) {
        pInfo = (JavaEventInfo *)JAVA_EVENT_PTR( m_eventQueue.next );

        // Place the event back on the free chain...
        pInfo->Delete();
    }

    JavaEventInfo::DeleteFreeChain();
    m_eventMutex.Unlock();
}


//-------------------------------------------------------------------------
//
// Callback loop which delivers Awt events to java cmponents...
//
//-------------------------------------------------------------------------
void AwtToolkit::CallbackLoop(BOOL* pExitCodition)
{
    JavaEventInfo *pInfo;
    DWORD dwLastMS, dwNowMS;

#if !defined(_WIN32)
    int64 sleepTime;
#endif

    dwLastMS = 0;
    dwNowMS  = 0;

    while (!*pExitCodition) {
        //
        // Wait until there is work to do...
        //
        // The callback thread empties the event queue when the following
        // conditions have been met:
        //     1. At least one event in the queue
        //     2. It has been at least MAX_AWT_EVENT_DELAY milliseconds
        //        since events were last processed.
        //
        // If the m_eventTimeout Event is explicitly signaled, this 
        // indicates that there is an event in the queue that MUST be
        // processed immediately !
        //
#if defined(_WIN32)
        dwLastMS = ::GetTickCount();
        (void)::WaitForSingleObject(m_eventInQueue, INFINITE);
        
        dwNowMS  = ::GetTickCount();
        if( (dwNowMS - dwLastMS) < MAX_AWT_EVENT_DELAY ) {
            (void)::WaitForSingleObject(m_eventTimeout, MAX_AWT_EVENT_DELAY);
        }
#else
#pragma message("AwtToolkit::EventLoop() needs work!!")
        LL_UI2L(sleepTime, 100000L);
        PR_Sleep(sleepTime);
#endif
        //
        // Process ALL events in the queue...
        //
        while (!m_eventQueue.IsEmpty()) {
            // Remove the next event from the queue...
            m_eventMutex.Lock();
            
            pInfo = (JavaEventInfo *)JAVA_EVENT_PTR( m_eventQueue.next );
            pInfo->m_link.Remove();

            m_eventMutex.Unlock();

            //
            // Dispatch the event to Java...
            //
            // While the event is being processed, the event queue is 
            // unlocked.  This allows other threads to post events
            // (and possibly combine events) while the callback thread
            // is running...
            //
            pInfo->Dispatch();
            pInfo->Delete();
#if !defined(_WIN32)
            LL_UI2L(sleepTime, 100L);
            PR_Sleep(sleepTime);
#endif
        }
#if defined(_WIN32)
        ::ResetEvent(m_eventInQueue);
        ::ResetEvent(m_eventTimeout);
#endif
    }
}


#if !defined(_WIN32)
//-------------------------------------------------------------------------
//
// GdiFlush is not available in Windows 3.1.  
// 
//
//-------------------------------------------------------------------------
BOOL GdiFlush(void)
{
    return TRUE;
}

#endif



//-------------------------------------------------------------------------
//
// AwtToolkit Window Procedure.  This is used to call methods of AwtObject
// on the "main GUI thread"...
//
//-------------------------------------------------------------------------
LRESULT AWT_CALLBACK AwtToolkit::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, 
                                            LPARAM lParam)
{
    if (msg == WM_AWT_CALLMETHOD) {
        AwtMethodInfo *info = (AwtMethodInfo *)lParam;

        return info->Invoke();
    }

    return ::DefWindowProc(hWnd, msg, wParam, lParam);
}


//-------------------------------------------------------------------------
//
//
//-------------------------------------------------------------------------
UINT AwtToolkit::CreateTimer()
{
    if (!AwtToolkit::m_TimerId)
        AwtToolkit::m_TimerId = ::SetTimer(NULL, 0, 200, AwtToolkit::TimerProc);

    return AwtToolkit::m_TimerId;
}


//-------------------------------------------------------------------------
//
//
//-------------------------------------------------------------------------
void AwtToolkit::DestroyTimer()
{
    if (AwtToolkit::m_TimerId) {
        ::KillTimer(NULL, AwtToolkit::m_TimerId);
        AwtToolkit::m_TimerId = 0;
    }

}


//-------------------------------------------------------------------------
//
//
//-------------------------------------------------------------------------
void AWT_CALLBACK AwtToolkit::TimerProc(HWND hWnd, UINT msg, UINT event, DWORD time)
{
    AwtToolkit::ProcessMouseTimer();
}


//-------------------------------------------------------------------------
//
//
//-------------------------------------------------------------------------
void AwtToolkit::ProcessMouseTimer()
{
    
    if (AwtToolkit::m_HoldMouse && ::IsWindow(AwtToolkit::m_HoldMouse->GetWindowHandle())) {
        POINT mp;

        // get mouse position
        ::GetCursorPos(&mp);

        if (::WindowFromPoint(mp) != AwtToolkit::m_HoldMouse->GetWindowHandle()) {
            int64 time = PR_NowMS(); // time in milliseconds

            ::ScreenToClient(AwtToolkit::m_HoldMouse->GetWindowHandle(), &mp);

            AwtToolkit::RaiseJavaEvent(AwtToolkit::m_HoldMouse->GetPeer(), 
                                        AwtEventDescription::MouseExit,
                                        time, 
                                        NULL,
                                        mp.x,
                                        mp.y);

            // we are out of this window and of any awt window, destroy timer
            AwtToolkit::DestroyTimer();
            AwtToolkit::m_HoldMouse = 0;
        }

        //AwtToolkit::m_HoldMouse->Unlock();
    }
    else {
        AwtToolkit::DestroyTimer();
        AwtToolkit::m_HoldMouse = 0;
    }
}


//-------------------------------------------------------------------------
//
// Native method implementations for netscape.awt.WToolkit
//
//-------------------------------------------------------------------------

extern "C" {

void
sun_awt_windows_WToolkit_init(HWToolkit *self, Hjava_lang_Thread *)
{
    CHECK_OBJECT(self);

    AwtToolkit::CreateToolkit();
}



void
sun_awt_windows_WToolkit_callbackLoop(HWToolkit *self)
{
    CHECK_OBJECT(self);

    AwtToolkit::theToolkit->CallbackLoop();
}


void
sun_awt_windows_WToolkit_eventLoop(HWToolkit *self)
{
    MSG msg;
    CHECK_OBJECT(self);

    //
    // Notify the peer object that the AwtToolkit object is initialized
    //
    monitorEnter(obj_monitor(self));
    monitorNotify(obj_monitor(self));
    monitorExit(obj_monitor(self));
#if defined(_WIN32)
    while (::GetMessage(&msg, NULL, 0, 0)) {
        ::TranslateMessage(&msg);
        ::DispatchMessage (&msg);
    }
#else
	/*
	** Delegate Windows input event queueing to another message loop
	** Hopefully, the browser is pumping messages, and that is what will
	** trigger entry into the various AWT WndProcs.
	*/
#endif

}



Hjava_awt_image_ColorModel *
sun_awt_windows_WToolkit_makeColorModel(HWToolkit *self)
{
    //CHECK_OBJECT_AND_RETURN(self, NULL);

    Hjava_awt_image_ColorModel *model = NULL;


    RGBQUAD *pRGBQuad = (RGBQUAD*)malloc(256*sizeof(RGBQUAD));

    // Initialize the palette colors to BLACK (ie. RGB(0,0,0))
    AwtPalette *pAwtPalette = AwtToolkit::GetToolkitDefaultPalette();
    pAwtPalette->AddRef();

    if(pAwtPalette != NULL) 
    {
        pAwtPalette->GetRGBQUADS(pRGBQuad); 
    }
    model = AwtImage::getColorModel(pRGBQuad);
    free(pRGBQuad);
    pAwtPalette->Release();

    return model;
}


void
sun_awt_windows_WToolkit_sync(HWToolkit *self)
{
    CHECK_OBJECT(self);

    VERIFY( ::GdiFlush() );
}



long 
sun_awt_windows_WToolkit_getScreenHeight(HWToolkit *self)
{
    HDC hDCDesktop;
    HWND hWndDesktop;
    long height;

    hWndDesktop = ::GetDesktopWindow();
    hDCDesktop  = ::GetDC(hWndDesktop);

    height = ::GetDeviceCaps(hDCDesktop, VERTRES);

    VERIFY( ::ReleaseDC(hWndDesktop, hDCDesktop) );

    return height;
}

long 
sun_awt_windows_WToolkit_getScreenWidth(HWToolkit *self)
{
    HDC hDCDesktop;
    HWND hWndDesktop;
    long width;

    hWndDesktop = ::GetDesktopWindow();
    hDCDesktop  = ::GetDC(hWndDesktop);

    width = ::GetDeviceCaps(hDCDesktop, HORZRES);

    VERIFY( ::ReleaseDC(hWndDesktop, hDCDesktop) );

    return width;
}


long 
sun_awt_windows_WToolkit_getScreenResolution(HWToolkit *self)
{
    HDC hDCDesktop;
    HWND hWndDesktop;
    long resolution;

    hWndDesktop = ::GetDesktopWindow();
    hDCDesktop  = ::GetDC(hWndDesktop);

    resolution  = ::GetDeviceCaps(hDCDesktop, LOGPIXELSX);

    VERIFY( ::ReleaseDC(hWndDesktop, hDCDesktop) );

    return resolution;
}


void 
sun_awt_windows_WToolkit_notImplemented(HWToolkit *self)
{
    CHECK_OBJECT(self);

    BREAK_TO_DEBUGGER;
}


}; // end of extern "C"

#if !defined(_WIN32)
//
// new() and delete() customizations so that we don't pull in the
// rtl's _malloc/_free routines in WIN16.
//

void  __far *operator new( size_t size )
{
	return malloc(size);
}

void operator delete( void __far *ptr )
{
	free(ptr);
}

#endif