gecko/widget/src/beos/nsWindow.cpp

3310 lines
91 KiB
C++

/* -*- Mode: C++; tab-width: 2; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Paul Ashford <arougthopher@lizardland.net>
* Sergei Dolgov <sergei_d@fi.tartu.ee>
* Fredrik Holmqvist <thesuckiestemail@yahoo.se>
* Mats Palmgren <mats.palmgren@bredband.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDebug.h"
#include "nsWindow.h"
#include "nsIAppShell.h"
#include "nsIFontMetrics.h"
#include "nsFont.h"
#include "nsGUIEvent.h"
#include "nsWidgetsCID.h"
#include "nsIDragService.h"
#include "nsIDragSessionBeOS.h"
#include "nsIDeviceContext.h"
#include "nsRect.h"
#include "nsIRegion.h"
#include "nsTransform2D.h"
#include "nsGfxCIID.h"
#include "resource.h"
#include "prtime.h"
#include "nsReadableUtils.h"
#include "nsVoidArray.h"
#include "nsIProxyObjectManager.h"
#include <Application.h>
#include <InterfaceDefs.h>
#include <Region.h>
#include <ScrollBar.h>
#include <app/Message.h>
#include <support/String.h>
#include <Screen.h>
#include <nsBeOSCursors.h>
#if defined(BeIME)
#include <Input.h>
#include <InputServerMethod.h>
#include <String.h>
#endif
#include "nsIRollupListener.h"
#include "nsIMenuRollup.h"
#include "gfxBeOSSurface.h"
#include "gfxContext.h"
// See comments in nsWindow.h as to why we override these calls from nsBaseWidget
NS_IMPL_THREADSAFE_ADDREF(nsWindow)
NS_IMPL_THREADSAFE_RELEASE(nsWindow)
static NS_DEFINE_IID(kIWidgetIID, NS_IWIDGET_IID);
static NS_DEFINE_IID(kRegionCID, NS_REGION_CID);
static NS_DEFINE_IID(kCDragServiceCID, NS_DRAGSERVICE_CID);
//-------------------------------------------------------------------------
// Global Definitions
//-------------------------------------------------------------------------
// Rollup Listener - static variable defintions
static nsIRollupListener * gRollupListener = nsnull;
static nsIWidget * gRollupWidget = nsnull;
static PRBool gRollupConsumeRollupEvent = PR_FALSE;
// Tracking last activated BWindow
static BWindow * gLastActiveWindow = NULL;
// BCursor objects can't be created until they are used. Some mozilla utilities,
// such as regxpcom, do not create a BApplication object, and therefor fail to run.,
// since a BCursor requires a vaild BApplication (see Bug#129964). But, we still want
// to cache them for performance. Currently, there are 17 cursors available;
static nsVoidArray gCursorArray(21);
// Used in contrain position. Specifies how much of a window must remain on screen
#define kWindowPositionSlop 20
// BeOS does not provide this information, so we must hard-code it
#define kWindowBorderWidth 5
#define kWindowTitleBarHeight 24
// TODO: make a #def for using OutLine view or not (see TODO below)
#if defined(BeIME)
#include "nsUTF8Utils.h"
static inline uint32 utf8_str_len(const char* ustring, int32 length)
{
CalculateUTF8Length cutf8;
cutf8.write(ustring, length);
return cutf8.Length();
}
nsIMEBeOS::nsIMEBeOS()
: imeTarget(NULL)
, imeState(NS_COMPOSITION_END), imeWidth(14)
{
}
/* placeholder for possible cleanup
nsIMEBeOS::~nsIMEBeOS()
{
}
*/
void nsIMEBeOS::RunIME(uint32 *args, nsWindow *target, BView *fView)
{
BMessage msg;
msg.Unflatten((const char*)args);
switch (msg.FindInt32("be:opcode"))
{
case B_INPUT_METHOD_CHANGED:
if (msg.HasString("be:string"))
{
const char* src = msg.FindString("be:string");
CopyUTF8toUTF16(src, imeText);
if (msg.FindBool("be:confirmed"))
{
if (imeState != NS_COMPOSITION_END)
DispatchText(imeText, 0, NULL);
}
else
{
nsTextRange txtRuns[2];
PRUint32 txtCount = 2;
int32 select[2];
select[0] = msg.FindInt32("be:selection", int32(0));
select[1] = msg.FindInt32("be:selection", 1);
txtRuns[0].mStartOffset = (select[0] == select[1]) ? 0 : utf8_str_len(src, select[1]);
txtRuns[0].mEndOffset = imeText.Length();
txtRuns[0].mRangeType = NS_TEXTRANGE_CONVERTEDTEXT;
if (select[0] == select[1])
txtCount = 1;
else
{
txtRuns[1].mStartOffset = utf8_str_len(src, select[0]);
txtRuns[1].mEndOffset = utf8_str_len(src, select[1]);
txtRuns[1].mRangeType = NS_TEXTRANGE_SELECTEDCONVERTEDTEXT;
}
imeTarget = target;
DispatchText(imeText, txtCount, txtRuns);
}
}
break;
case B_INPUT_METHOD_LOCATION_REQUEST:
if (fView && fView->LockLooper())
{
BPoint caret(imeCaret);
DispatchIME(NS_COMPOSITION_QUERY);
if (caret.x > imeCaret.x)
caret.x = imeCaret.x - imeWidth * imeText.Length(); /* back */
BMessage reply(B_INPUT_METHOD_EVENT);
reply.AddInt32("be:opcode", B_INPUT_METHOD_LOCATION_REQUEST);
for (int32 s= 0; imeText[s]; s++)
{
reply.AddPoint("be:location_reply", fView->ConvertToScreen(caret));
reply.AddFloat("be:height_reply", imeHeight);
caret.x += imeWidth;
}
imeMessenger.SendMessage(&reply);
fView->UnlockLooper();
}
break;
case B_INPUT_METHOD_STARTED:
imeTarget = target;
DispatchIME(NS_COMPOSITION_START);
DispatchIME(NS_COMPOSITION_QUERY);
msg.FindMessenger("be:reply_to", &imeMessenger);
break;
case B_INPUT_METHOD_STOPPED:
if (imeState != NS_COMPOSITION_END)
DispatchIME(NS_COMPOSITION_END);
imeText.Truncate();
break;
};
}
void nsIMEBeOS::DispatchText(nsString &text, PRUint32 txtCount, nsTextRange* txtRuns)
{
nsTextEvent textEvent(PR_TRUE,NS_TEXT_TEXT, imeTarget);
textEvent.time = 0;
textEvent.isShift =
textEvent.isControl =
textEvent.isAlt =
textEvent.isMeta = PR_FALSE;
textEvent.refPoint.x =
textEvent.refPoint.y = 0;
textEvent.theText = text.get();
textEvent.isChar = PR_TRUE;
textEvent.rangeCount= txtCount;
textEvent.rangeArray= txtRuns;
DispatchWindowEvent(&textEvent);
}
void nsIMEBeOS::DispatchCancelIME()
{
if (imeText.Length() && imeState != NS_COMPOSITION_END)
{
BMessage reply(B_INPUT_METHOD_EVENT);
reply.AddInt32("be:opcode", B_INPUT_METHOD_STOPPED);
imeMessenger.SendMessage(&reply);
DispatchText(imeText, 0, NULL);
DispatchIME(NS_COMPOSITION_END);
imeText.Truncate();
}
}
void nsIMEBeOS::DispatchIME(PRUint32 what)
{
nsCompositionEvent compEvent(PR_TRUE, what, imeTarget);
compEvent.refPoint.x =
compEvent.refPoint.y = 0;
compEvent.time = 0;
DispatchWindowEvent(&compEvent);
imeState = what;
if (what == NS_COMPOSITION_QUERY)
{
imeCaret.Set(compEvent.theReply.mCursorPosition.x,
compEvent.theReply.mCursorPosition.y);
imeHeight = compEvent.theReply.mCursorPosition.height+4;
}
}
PRBool nsIMEBeOS::DispatchWindowEvent(nsGUIEvent* event)
{
nsEventStatus status;
imeTarget->DispatchEvent(event, status);
return PR_FALSE;
}
// There is only one IME instance per app, actually it may be set as global
nsIMEBeOS *nsIMEBeOS::GetIME()
{
if(beosIME == 0)
beosIME = new nsIMEBeOS();
return beosIME;
}
nsIMEBeOS *nsIMEBeOS::beosIME = 0;
#endif
//-------------------------------------------------------------------------
//
// nsWindow constructor
//
//-------------------------------------------------------------------------
nsWindow::nsWindow() : nsBaseWidget()
{
mView = 0;
mPreferredWidth = 0;
mPreferredHeight = 0;
mFontMetrics = nsnull;
mIsVisible = PR_FALSE;
mEnabled = PR_TRUE;
mIsScrolling = PR_FALSE;
mParent = nsnull;
mWindowParent = nsnull;
mUpdateArea = do_CreateInstance(kRegionCID);
mForeground = NS_RGBA(0xFF,0xFF,0xFF,0xFF);
mBackground = mForeground;
mBWindowFeel = B_NORMAL_WINDOW_FEEL;
mBWindowLook = B_NO_BORDER_WINDOW_LOOK;
if (mUpdateArea)
{
mUpdateArea->Init();
mUpdateArea->SetTo(0, 0, 0, 0);
}
}
//-------------------------------------------------------------------------
//
// nsWindow destructor
//
//-------------------------------------------------------------------------
nsWindow::~nsWindow()
{
mIsDestroying = PR_TRUE;
// If the widget was released without calling Destroy() then the native
// window still exists, and we need to destroy it
if (NULL != mView)
{
Destroy();
}
NS_IF_RELEASE(mFontMetrics);
}
NS_METHOD nsWindow::BeginResizingChildren(void)
{
// HideKids(PR_TRUE) may be used here
NS_NOTYETIMPLEMENTED("BeginResizingChildren not yet implemented"); // to be implemented
return NS_OK;
}
NS_METHOD nsWindow::EndResizingChildren(void)
{
// HideKids(PR_FALSE) may be used here
NS_NOTYETIMPLEMENTED("EndResizingChildren not yet implemented"); // to be implemented
return NS_OK;
}
NS_METHOD nsWindow::WidgetToScreen(const nsRect& aOldRect, nsRect& aNewRect)
{
BPoint point;
point.x = aOldRect.x;
point.y = aOldRect.y;
if (mView && mView->LockLooper())
{
mView->ConvertToScreen(&point);
mView->UnlockLooper();
}
aNewRect.x = nscoord(point.x);
aNewRect.y = nscoord(point.y);
aNewRect.width = aOldRect.width;
aNewRect.height = aOldRect.height;
return NS_OK;
}
NS_METHOD nsWindow::ScreenToWidget(const nsRect& aOldRect, nsRect& aNewRect)
{
BPoint point;
point.x = aOldRect.x;
point.y = aOldRect.y;
if (mView && mView->LockLooper())
{
mView->ConvertFromScreen(&point);
mView->UnlockLooper();
}
aNewRect.x = nscoord(point.x);
aNewRect.y = nscoord(point.y);
aNewRect.width = aOldRect.width;
aNewRect.height = aOldRect.height;
return NS_OK;
}
//-------------------------------------------------------------------------
//
// Initialize an event to dispatch
//
//-------------------------------------------------------------------------
void nsWindow::InitEvent(nsGUIEvent& event, nsPoint* aPoint)
{
NS_ADDREF(event.widget);
if (nsnull == aPoint) // use the point from the event
{
// get the message position in client coordinates and in twips
event.refPoint.x = 0;
event.refPoint.y = 0;
}
else // use the point override if provided
{
event.refPoint.x = aPoint->x;
event.refPoint.y = aPoint->y;
}
event.time = PR_IntervalNow();
}
//-------------------------------------------------------------------------
//
// Invokes callback and ProcessEvent method on Event Listener object
//
//-------------------------------------------------------------------------
NS_IMETHODIMP nsWindow::DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus)
{
aStatus = nsEventStatus_eIgnore;
nsCOMPtr <nsIWidget> mWidget = event->widget;
if (mEventCallback)
aStatus = (*mEventCallback)(event);
if ((aStatus != nsEventStatus_eIgnore) && (mEventListener))
aStatus = mEventListener->ProcessEvent(*event);
return NS_OK;
}
//-------------------------------------------------------------------------
//
// Dispatch Window Event
//
//-------------------------------------------------------------------------
PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event)
{
nsEventStatus status;
DispatchEvent(event, status);
return ConvertStatus(status);
}
//-------------------------------------------------------------------------
//
// Dispatch standard event
//
//-------------------------------------------------------------------------
PRBool nsWindow::DispatchStandardEvent(PRUint32 aMsg)
{
nsGUIEvent event(PR_TRUE, aMsg, this);
InitEvent(event);
PRBool result = DispatchWindowEvent(&event);
NS_RELEASE(event.widget);
return result;
}
NS_IMETHODIMP nsWindow::PreCreateWidget(nsWidgetInitData *aInitData)
{
if ( nsnull == aInitData)
return NS_ERROR_FAILURE;
SetWindowType(aInitData->mWindowType);
SetBorderStyle(aInitData->mBorderStyle);
return NS_OK;
}
//-------------------------------------------------------------------------
//
// Utility method for implementing both Create(nsIWidget ...) and
// Create(nsNativeWidget...)
//-------------------------------------------------------------------------
nsresult nsWindow::StandardWindowCreate(nsIWidget *aParent,
const nsRect &aRect,
EVENT_CALLBACK aHandleEventFunction,
nsIDeviceContext *aContext,
nsIAppShell *aAppShell,
nsIToolkit *aToolkit,
nsWidgetInitData *aInitData,
nsNativeWidget aNativeParent)
{
//Do as little as possible for invisible windows, why are these needed?
if (aInitData->mWindowType == eWindowType_invisible)
return NS_ERROR_FAILURE;
NS_ASSERTION(aInitData->mWindowType == eWindowType_dialog
|| aInitData->mWindowType == eWindowType_toplevel,
"The windowtype is not handled by this class.");
mIsTopWidgetWindow = PR_TRUE;
BaseCreate(nsnull, aRect, aHandleEventFunction, aContext,
aAppShell, aToolkit, aInitData);
mListenForResizes = aNativeParent ? PR_TRUE : aInitData->mListenForResizes;
mParent = aParent;
// Useful shortcut, wondering if we can use it also in GetParent() instead
// nsIWidget* type mParent.
mWindowParent = (nsWindow *)aParent;
SetBounds(aRect);
// Default mode for window, everything switched off.
uint32 flags = B_NOT_RESIZABLE | B_NOT_MINIMIZABLE | B_NOT_ZOOMABLE
| B_NOT_CLOSABLE | B_ASYNCHRONOUS_CONTROLS;
//eBorderStyle_default is to ask the OS to handle it as it sees best.
//eBorderStyle_all is same as top_level window default.
if (eBorderStyle_default == mBorderStyle || eBorderStyle_all & mBorderStyle)
{
//(Firefox prefs doesn't go this way, so apparently it wants titlebar, zoom,
//resize and close.)
//Look and feel for others are set ok at init.
if (eWindowType_toplevel==mWindowType)
{
mBWindowLook = B_TITLED_WINDOW_LOOK;
flags = B_ASYNCHRONOUS_CONTROLS;
}
}
else
{
if (eBorderStyle_border & mBorderStyle)
mBWindowLook = B_MODAL_WINDOW_LOOK;
if (eBorderStyle_resizeh & mBorderStyle)
{
//Resize demands at least border
mBWindowLook = B_MODAL_WINDOW_LOOK;
flags &= !B_NOT_RESIZABLE;
}
//We don't have titlebar menus, so treat like title as it demands titlebar.
if (eBorderStyle_title & mBorderStyle || eBorderStyle_menu & mBorderStyle)
mBWindowLook = B_TITLED_WINDOW_LOOK;
if (eBorderStyle_minimize & mBorderStyle)
flags &= !B_NOT_MINIMIZABLE;
if (eBorderStyle_maximize & mBorderStyle)
flags &= !B_NOT_ZOOMABLE;
if (eBorderStyle_close & mBorderStyle)
flags &= !B_NOT_CLOSABLE;
}
nsWindowBeOS * w = new nsWindowBeOS(this,
BRect(aRect.x, aRect.y, aRect.x + aRect.width - 1, aRect.y + aRect.height - 1),
"", mBWindowLook, mBWindowFeel, flags);
if (!w)
return NS_ERROR_OUT_OF_MEMORY;
mView = new nsViewBeOS(this, w->Bounds(), "Toplevel view", B_FOLLOW_ALL, 0);
if (!mView)
return NS_ERROR_OUT_OF_MEMORY;
w->AddChild(mView);
// I'm wondering if we can move part of that code to above
if (eWindowType_dialog == mWindowType && mWindowParent)
{
nsWindow *topparent = mWindowParent;
while (topparent->mWindowParent)
topparent = topparent->mWindowParent;
// may be got via mView and mView->Window() of topparent explicitly
BWindow* subsetparent = (BWindow *)
topparent->GetNativeData(NS_NATIVE_WINDOW);
if (subsetparent)
{
mBWindowFeel = B_FLOATING_SUBSET_WINDOW_FEEL;
w->SetFeel(mBWindowFeel);
w->AddToSubset(subsetparent);
}
}
// Run Looper. No proper destroy without it.
w->Run();
DispatchStandardEvent(NS_CREATE);
return NS_OK;
}
//-------------------------------------------------------------------------
//
// Create the proper widget
//
//-------------------------------------------------------------------------
NS_METHOD nsWindow::Create(nsIWidget *aParent,
const nsRect &aRect,
EVENT_CALLBACK aHandleEventFunction,
nsIDeviceContext *aContext,
nsIAppShell *aAppShell,
nsIToolkit *aToolkit,
nsWidgetInitData *aInitData)
{
// Switch to the "main gui thread" if necessary... This method must
// be executed on the "gui thread"...
nsToolkit* toolkit = (nsToolkit *)mToolkit;
if (toolkit && !toolkit->IsGuiThread())
{
nsCOMPtr<nsIWidget> widgetProxy;
nsresult rv = NS_GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
NS_GET_IID(nsIWidget),
this,
NS_PROXY_SYNC | NS_PROXY_ALWAYS,
getter_AddRefs(widgetProxy));
if (NS_FAILED(rv))
return rv;
return widgetProxy->Create(aParent, aRect, aHandleEventFunction, aContext,
aAppShell, aToolkit, aInitData);
}
return(StandardWindowCreate(aParent, aRect, aHandleEventFunction,
aContext, aAppShell, aToolkit, aInitData,
nsnull));
}
//-------------------------------------------------------------------------
//
// create with a native parent
//
//-------------------------------------------------------------------------
NS_METHOD nsWindow::Create(nsNativeWidget aParent,
const nsRect &aRect,
EVENT_CALLBACK aHandleEventFunction,
nsIDeviceContext *aContext,
nsIAppShell *aAppShell,
nsIToolkit *aToolkit,
nsWidgetInitData *aInitData)
{
// Switch to the "main gui thread" if necessary... This method must
// be executed on the "gui thread"...
nsToolkit* toolkit = (nsToolkit *)mToolkit;
if (toolkit && !toolkit->IsGuiThread())
{
nsCOMPtr<nsIWidget> widgetProxy;
nsresult rv = NS_GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
NS_GET_IID(nsIWidget),
this,
NS_PROXY_SYNC | NS_PROXY_ALWAYS,
getter_AddRefs(widgetProxy));
if (NS_FAILED(rv))
return rv;
return widgetProxy->Create(aParent, aRect, aHandleEventFunction, aContext,
aAppShell, aToolkit, aInitData);
}
return(StandardWindowCreate(nsnull, aRect, aHandleEventFunction,
aContext, aAppShell, aToolkit, aInitData,
aParent));
}
gfxASurface*
nsWindow::GetThebesSurface()
{
mThebesSurface = nsnull;
if (!mThebesSurface) {
mThebesSurface = new gfxBeOSSurface(mView);
}
return mThebesSurface;
}
//-------------------------------------------------------------------------
//
// Close this nsWindow
//
//-------------------------------------------------------------------------
NS_METHOD nsWindow::Destroy()
{
// Switch to the "main gui thread" if necessary... This method must
// be executed on the "gui thread"...
nsToolkit* toolkit = (nsToolkit *)mToolkit;
if (toolkit != nsnull && !toolkit->IsGuiThread())
{
nsCOMPtr<nsIWidget> widgetProxy;
nsresult rv = NS_GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
NS_GET_IID(nsIWidget),
this,
NS_PROXY_SYNC | NS_PROXY_ALWAYS,
getter_AddRefs(widgetProxy));
if (NS_FAILED(rv))
return rv;
return widgetProxy->Destroy();
}
// Ok, now tell the nsBaseWidget class to clean up what it needs to
if (!mIsDestroying)
{
nsBaseWidget::Destroy();
}
//our windows can be subclassed by
//others and these namless, faceless others
//may not let us know about WM_DESTROY. so,
//if OnDestroy() didn't get called, just call
//it now.
if (PR_FALSE == mOnDestroyCalled)
OnDestroy();
// Destroy the BView, if no mView, it is probably destroyed before
// automatically with BWindow::Quit()
if (mView)
{
// prevent the widget from causing additional events
mEventCallback = nsnull;
if (mView->LockLooper())
{
while(mView->ChildAt(0))
mView->RemoveChild(mView->ChildAt(0));
// destroy from inside
BWindow *w = mView->Window();
// if no window, it was destroyed as result of B_QUIT_REQUESTED and
// took also all its children away
if (w)
{
w->Sync();
if (mView->Parent())
{
mView->Parent()->RemoveChild(mView);
if (eWindowType_child != mWindowType)
w->Quit();
else
w->Unlock();
}
else
{
w->RemoveChild(mView);
w->Quit();
}
}
else
mView->RemoveSelf();
delete mView;
}
// window is already gone
mView = NULL;
}
mParent = nsnull;
mWindowParent = nsnull;
return NS_OK;
}
//-------------------------------------------------------------------------
//
// Get this nsWindow parent
//
//-------------------------------------------------------------------------
nsIWidget* nsWindow::GetParent(void)
{
//We cannot addref mParent directly
nsIWidget *widget = 0;
if (mIsDestroying || mOnDestroyCalled)
return nsnull;
widget = (nsIWidget *)mParent;
return widget;
}
//-------------------------------------------------------------------------
//
// Hide or show this component
//
//-------------------------------------------------------------------------
NS_METHOD nsWindow::Show(PRBool bState)
{
if (!mEnabled)
return NS_OK;
if (!mView || !mView->LockLooper())
return NS_OK;
//We need to do the IsHidden() checks
//because BeOS counts no of Hide()
//and Show() checks. BeBook:
// If Hide() is called more than once, you'll need to call Show()
// an equal number of times for the window to become visible again.
if (bState == PR_FALSE)
{
if (mView->Window() && !mView->Window()->IsHidden())
mView->Window()->Hide();
}
else
{
if (mView->Window() && mView->Window()->IsHidden())
mView->Window()->Show();
}
mView->UnlockLooper();
mIsVisible = bState;
return NS_OK;
}
//-------------------------------------------------------------------------
// Set/unset mouse capture
//-------------------------------------------------------------------------
NS_METHOD nsWindow::CaptureMouse(PRBool aCapture)
{
if (mView && mView->LockLooper())
{
if (PR_TRUE == aCapture)
mView->SetEventMask(B_POINTER_EVENTS);
else
mView->SetEventMask(0);
mView->UnlockLooper();
}
return NS_OK;
}
//-------------------------------------------------------------------------
// Capture Roolup Events
//-------------------------------------------------------------------------
NS_METHOD nsWindow::CaptureRollupEvents(nsIRollupListener * aListener, PRBool aDoCapture, PRBool aConsumeRollupEvent)
{
if (!mEnabled)
return NS_OK;
if (aDoCapture)
{
// we haven't bothered carrying a weak reference to gRollupWidget because
// we believe lifespan is properly scoped. this next assertion helps
// assure that remains true.
NS_ASSERTION(!gRollupWidget, "rollup widget reassigned before release");
gRollupConsumeRollupEvent = aConsumeRollupEvent;
NS_IF_RELEASE(gRollupListener);
NS_IF_RELEASE(gRollupWidget);
gRollupListener = aListener;
NS_ADDREF(aListener);
gRollupWidget = this;
NS_ADDREF(this);
}
else
{
NS_IF_RELEASE(gRollupListener);
NS_IF_RELEASE(gRollupWidget);
}
return NS_OK;
}
//-------------------------------------------------------------------------
// Check if event happened inside the given nsWindow
//-------------------------------------------------------------------------
PRBool nsWindow::EventIsInsideWindow(nsWindow* aWindow, nsPoint pos)
{
BRect r;
BWindow *window = (BWindow *)aWindow->GetNativeData(NS_NATIVE_WINDOW);
if (window)
{
r = window->Frame();
}
else
{
// Bummer!
return PR_FALSE;
}
if (pos.x < r.left || pos.x > r.right ||
pos.y < r.top || pos.y > r.bottom)
{
return PR_FALSE;
}
return PR_TRUE;
}
//-------------------------------------------------------------------------
// DealWithPopups
//
// Handle events that may cause a popup (combobox, XPMenu, etc) to need to rollup.
//-------------------------------------------------------------------------
PRBool
nsWindow::DealWithPopups(uint32 methodID, nsPoint pos)
{
if (gRollupListener && gRollupWidget)
{
// Rollup if the event is outside the popup.
PRBool rollup = !nsWindow::EventIsInsideWindow((nsWindow*)gRollupWidget, pos);
// If we're dealing with menus, we probably have submenus and we don't
// want to rollup if the click is in a parent menu of the current submenu.
if (rollup)
{
nsCOMPtr<nsIMenuRollup> menuRollup ( do_QueryInterface(gRollupListener) );
if ( menuRollup )
{
nsAutoTArray<nsIWidget*, 5> widgetChain;
menuRollup->GetSubmenuWidgetChain(&widgetChain);
for ( PRUint32 i = 0; i < widgetChain.Length(); ++i )
{
nsIWidget* widget = widgetChain[i];
if ( nsWindow::EventIsInsideWindow((nsWindow*)widget, pos) )
{
rollup = PR_FALSE;
break;
}
} // foreach parent menu widget
} // if rollup listener knows about menus
} // if rollup
if (rollup)
{
gRollupListener->Rollup();
if (gRollupConsumeRollupEvent)
{
return PR_TRUE;
}
}
} // if rollup listeners registered
return PR_FALSE;
}
//-------------------------------------------------------------------------
//
// IsVisible
//
// Return PR_TRUE if the whether the component is visible, PR_FALSE otherwise
//-------------------------------------------------------------------------
NS_METHOD nsWindow::IsVisible(PRBool & bState)
{
bState = mIsVisible && mView && mView->Visible();
return NS_OK;
}
//-------------------------------------------------------------------------
//
// Hide window borders/decorations for this widget
//
//-------------------------------------------------------------------------
NS_METHOD nsWindow::HideWindowChrome(PRBool aShouldHide)
{
if(mWindowType == eWindowType_child || mView == 0 || mView->Window() == 0)
return NS_ERROR_FAILURE;
// B_BORDERED
if (aShouldHide)
mView->Window()->SetLook(B_NO_BORDER_WINDOW_LOOK);
else
mView->Window()->SetLook(mBWindowLook);
return NS_OK;
}
//-------------------------------------------------------------------------
//
// Sanity check potential move coordinates
//
//-------------------------------------------------------------------------
NS_METHOD nsWindow::ConstrainPosition(PRBool aAllowSlop, PRInt32 *aX, PRInt32 *aY)
{
if (mIsTopWidgetWindow && mView->Window())
{
BScreen screen;
// If no valid screen, just return
if (! screen.IsValid()) return NS_OK;
BRect screen_rect = screen.Frame();
BRect win_bounds = mView->Window()->Frame();
#ifdef DEBUG_CONSTRAIN_POSITION
printf("ConstrainPosition: allowSlop=%s, x=%d, y=%d\n\tScreen :", (aAllowSlop?"T":"F"),*aX,*aY);
screen_rect.PrintToStream();
printf("\tWindow: ");
win_bounds.PrintToStream();
#endif
if (aAllowSlop)
{
if (*aX < kWindowPositionSlop - win_bounds.IntegerWidth() + kWindowBorderWidth)
*aX = kWindowPositionSlop - win_bounds.IntegerWidth() + kWindowBorderWidth;
else if (*aX > screen_rect.IntegerWidth() - kWindowPositionSlop - kWindowBorderWidth)
*aX = screen_rect.IntegerWidth() - kWindowPositionSlop - kWindowBorderWidth;
if (*aY < kWindowPositionSlop - win_bounds.IntegerHeight() + kWindowTitleBarHeight)
*aY = kWindowPositionSlop - win_bounds.IntegerHeight() + kWindowTitleBarHeight;
else if (*aY > screen_rect.IntegerHeight() - kWindowPositionSlop - kWindowBorderWidth)
*aY = screen_rect.IntegerHeight() - kWindowPositionSlop - kWindowBorderWidth;
}
else
{
if (*aX < kWindowBorderWidth)
*aX = kWindowBorderWidth;
else if (*aX > screen_rect.IntegerWidth() - win_bounds.IntegerWidth() - kWindowBorderWidth)
*aX = screen_rect.IntegerWidth() - win_bounds.IntegerWidth() - kWindowBorderWidth;
if (*aY < kWindowTitleBarHeight)
*aY = kWindowTitleBarHeight;
else if (*aY > screen_rect.IntegerHeight() - win_bounds.IntegerHeight() - kWindowBorderWidth)
*aY = screen_rect.IntegerHeight() - win_bounds.IntegerHeight() - kWindowBorderWidth;
}
}
return NS_OK;
}
void nsWindow::HideKids(PRBool state)
{
for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling())
{
nsWindow *childWidget = static_cast<nsWindow*>(kid);
nsRect kidrect = ((nsWindow *)kid)->mBounds;
//Don't bother about invisible
if (mBounds.Intersects(kidrect))
{
childWidget->Show(!state);
}
}
}
//-------------------------------------------------------------------------
//
// Move this component
//
//-------------------------------------------------------------------------
nsresult nsWindow::Move(PRInt32 aX, PRInt32 aY)
{
// Only perform this check for non-popup windows, since the positioning can
// in fact change even when the x/y do not. We always need to perform the
// check. See bug #97805 for details.
if (mWindowType != eWindowType_popup && (mBounds.x == aX) && (mBounds.y == aY))
{
// Nothing to do, since it is already positioned correctly.
return NS_OK;
}
// Set cached value for lightweight and printing
mBounds.x = aX;
mBounds.y = aY;
// We may reset children visibility here, but it needs special care
// - see comment 18 in Bug 311651. More sofisticated code needed.
// until we lack separate window and widget, we "cannot" move BWindow without BView
if (mView && mView->LockLooper())
{
if (mView->Parent() || !mView->Window())
mView->MoveTo(aX, aY);
else
((nsWindowBeOS *)mView->Window())->MoveTo(aX, aY);
mView->UnlockLooper();
}
OnMove(aX,aY);
return NS_OK;
}
//-------------------------------------------------------------------------
//
// Resize this component
//
//-------------------------------------------------------------------------
NS_METHOD nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
{
if (aWidth < 0 || aHeight < 0)
return NS_OK;
mBounds.width = aWidth;
mBounds.height = aHeight;
// until we lack separate window and widget, we "cannot" resize BWindow without BView
if (mView && mView->LockLooper())
{
if (mView->Parent() || !mView->Window())
mView->ResizeTo(aWidth - 1, aHeight - 1);
else
((nsWindowBeOS *)mView->Window())->ResizeTo(aWidth - 1, aHeight - 1);
mView->UnlockLooper();
}
OnResize(mBounds);
if (aRepaint)
Update();
return NS_OK;
}
//-------------------------------------------------------------------------
//
// Resize this component
//
//-------------------------------------------------------------------------
NS_METHOD nsWindow::Resize(PRInt32 aX,
PRInt32 aY,
PRInt32 aWidth,
PRInt32 aHeight,
PRBool aRepaint)
{
Move(aX,aY);
Resize(aWidth,aHeight,aRepaint);
return NS_OK;
}
NS_METHOD nsWindow::SetModal(PRBool aModal)
{
if(!(mView && mView->Window()))
return NS_ERROR_FAILURE;
if(aModal)
{
window_feel newfeel;
switch(mBWindowFeel)
{
case B_FLOATING_SUBSET_WINDOW_FEEL:
newfeel = B_MODAL_SUBSET_WINDOW_FEEL;
break;
case B_FLOATING_APP_WINDOW_FEEL:
newfeel = B_MODAL_APP_WINDOW_FEEL;
break;
case B_FLOATING_ALL_WINDOW_FEEL:
newfeel = B_MODAL_ALL_WINDOW_FEEL;
break;
default:
return NS_OK;
}
mView->Window()->SetFeel(newfeel);
}
else
{
mView->Window()->SetFeel(mBWindowFeel);
}
return NS_OK;
}
//-------------------------------------------------------------------------
//
// Enable/disable this component
//
//-------------------------------------------------------------------------
NS_METHOD nsWindow::Enable(PRBool aState)
{
//TODO: Needs real corect implementation in future
mEnabled = aState;
return NS_OK;
}
NS_METHOD nsWindow::IsEnabled(PRBool *aState)
{
NS_ENSURE_ARG_POINTER(aState);
// looks easy enough, but...
*aState = mEnabled;
return NS_OK;
}
//-------------------------------------------------------------------------
//
// Give the focus to this component
//
//-------------------------------------------------------------------------
NS_METHOD nsWindow::SetFocus(PRBool aRaise)
{
//
// Switch to the "main gui thread" if necessary... This method must
// be executed on the "gui thread"...
//
nsToolkit* toolkit = (nsToolkit *)mToolkit;
if (toolkit && !toolkit->IsGuiThread())
{
nsCOMPtr<nsIWidget> widgetProxy;
nsresult rv = NS_GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
NS_GET_IID(nsIWidget),
this,
NS_PROXY_SYNC | NS_PROXY_ALWAYS,
getter_AddRefs(widgetProxy));
if (NS_FAILED(rv))
return rv;
return widgetProxy->SetFocus(aRaise);
}
// Don't set focus on disabled widgets or popups
if (!mEnabled || eWindowType_popup == mWindowType)
return NS_OK;
if (mView && mView->LockLooper())
{
if (mView->Window() &&
aRaise == PR_TRUE &&
eWindowType_popup != mWindowType &&
!mView->Window()->IsActive() &&
gLastActiveWindow != mView->Window())
mView->Window()->Activate(true);
mView->MakeFocus(true);
mView->UnlockLooper();
DispatchFocus(NS_GOTFOCUS);
}
return NS_OK;
}
//-------------------------------------------------------------------------
//
// Get this component size and position in screen coordinates
//
//-------------------------------------------------------------------------
NS_IMETHODIMP nsWindow::GetScreenBounds(nsRect &aRect)
{
// A window's Frame() value is cached, so locking is not needed
if (mView && mView->Window())
{
BRect r = mView->Window()->Frame();
aRect.x = nscoord(r.left);
aRect.y = nscoord(r.top);
aRect.width = r.IntegerWidth()+1;
aRect.height = r.IntegerHeight()+1;
}
else
{
aRect = mBounds;
}
return NS_OK;
}
//-------------------------------------------------------------------------
//
// Set the background/foreground color
//
//-------------------------------------------------------------------------
NS_METHOD nsWindow::SetBackgroundColor(const nscolor &aColor)
{
nsBaseWidget::SetBackgroundColor(aColor);
// We set the background of toplevel windows so that resizing doesn't show thru
// to Desktop and resizing artifacts. Child windows has transparent background.
if (!mIsTopWidgetWindow)
return NS_OK;
if (mView && mView->LockLooper())
{
mView->SetViewColor(NS_GET_R(aColor), NS_GET_G(aColor), NS_GET_B(aColor), NS_GET_A(aColor));
mView->UnlockLooper();
}
return NS_OK;
}
//-------------------------------------------------------------------------
//
// Set this component cursor
//
//-------------------------------------------------------------------------
NS_METHOD nsWindow::SetCursor(nsCursor aCursor)
{
if (!mView)
return NS_ERROR_FAILURE;
// Only change cursor if it's changing
if (aCursor != mCursor)
{
BCursor const *newCursor = B_CURSOR_SYSTEM_DEFAULT;
if (be_app->IsCursorHidden())
be_app->ShowCursor();
// Check to see if the array has been loaded, if not, do it.
if (gCursorArray.Count() == 0)
{
gCursorArray.InsertElementAt((void*) new BCursor(cursorHyperlink),0);
gCursorArray.InsertElementAt((void*) new BCursor(cursorHorizontalDrag),1);
gCursorArray.InsertElementAt((void*) new BCursor(cursorVerticalDrag),2);
gCursorArray.InsertElementAt((void*) new BCursor(cursorUpperLeft),3);
gCursorArray.InsertElementAt((void*) new BCursor(cursorLowerRight),4);
gCursorArray.InsertElementAt((void*) new BCursor(cursorUpperRight),5);
gCursorArray.InsertElementAt((void*) new BCursor(cursorLowerLeft),6);
gCursorArray.InsertElementAt((void*) new BCursor(cursorCrosshair),7);
gCursorArray.InsertElementAt((void*) new BCursor(cursorHelp),8);
gCursorArray.InsertElementAt((void*) new BCursor(cursorGrab),9);
gCursorArray.InsertElementAt((void*) new BCursor(cursorGrabbing),10);
gCursorArray.InsertElementAt((void*) new BCursor(cursorCopy),11);
gCursorArray.InsertElementAt((void*) new BCursor(cursorAlias),12);
gCursorArray.InsertElementAt((void*) new BCursor(cursorWatch2),13);
gCursorArray.InsertElementAt((void*) new BCursor(cursorCell),14);
gCursorArray.InsertElementAt((void*) new BCursor(cursorZoomIn),15);
gCursorArray.InsertElementAt((void*) new BCursor(cursorZoomOut),16);
gCursorArray.InsertElementAt((void*) new BCursor(cursorLeft),17);
gCursorArray.InsertElementAt((void*) new BCursor(cursorRight),18);
gCursorArray.InsertElementAt((void*) new BCursor(cursorTop),19);
gCursorArray.InsertElementAt((void*) new BCursor(cursorBottom),20);
}
switch (aCursor)
{
case eCursor_standard:
case eCursor_move:
newCursor = B_CURSOR_SYSTEM_DEFAULT;
break;
case eCursor_select:
newCursor = B_CURSOR_I_BEAM;
break;
case eCursor_hyperlink:
newCursor = (BCursor *)gCursorArray.SafeElementAt(0);
break;
case eCursor_n_resize:
newCursor = (BCursor *)gCursorArray.SafeElementAt(19);
break;
case eCursor_s_resize:
newCursor = (BCursor *)gCursorArray.SafeElementAt(20);
break;
case eCursor_w_resize:
newCursor = (BCursor *)gCursorArray.SafeElementAt(17);
break;
case eCursor_e_resize:
newCursor = (BCursor *)gCursorArray.SafeElementAt(18);
break;
case eCursor_nw_resize:
newCursor = (BCursor *)gCursorArray.SafeElementAt(3);
break;
case eCursor_se_resize:
newCursor = (BCursor *)gCursorArray.SafeElementAt(4);
break;
case eCursor_ne_resize:
newCursor = (BCursor *)gCursorArray.SafeElementAt(5);
break;
case eCursor_sw_resize:
newCursor = (BCursor *)gCursorArray.SafeElementAt(6);
break;
case eCursor_crosshair:
newCursor = (BCursor *)gCursorArray.SafeElementAt(7);
break;
case eCursor_help:
newCursor = (BCursor *)gCursorArray.SafeElementAt(8);
break;
case eCursor_copy:
newCursor = (BCursor *)gCursorArray.SafeElementAt(11);
break;
case eCursor_alias:
newCursor = (BCursor *)gCursorArray.SafeElementAt(12);
break;
case eCursor_context_menu:
// XXX: No suitable cursor, needs implementing
break;
case eCursor_cell:
newCursor = (BCursor *)gCursorArray.SafeElementAt(14);
break;
case eCursor_grab:
newCursor = (BCursor *)gCursorArray.SafeElementAt(9);
break;
case eCursor_grabbing:
newCursor = (BCursor *)gCursorArray.SafeElementAt(10);
break;
case eCursor_wait:
case eCursor_spinning:
newCursor = (BCursor *)gCursorArray.SafeElementAt(13);
break;
case eCursor_zoom_in:
newCursor = (BCursor *)gCursorArray.SafeElementAt(15);
break;
case eCursor_zoom_out:
newCursor = (BCursor *)gCursorArray.SafeElementAt(16);
break;
case eCursor_not_allowed:
case eCursor_no_drop:
// XXX: No suitable cursor, needs implementing
break;
case eCursor_col_resize:
// XXX not 100% appropriate perhaps
newCursor = (BCursor *)gCursorArray.SafeElementAt(1);
break;
case eCursor_row_resize:
// XXX not 100% appropriate perhaps
newCursor = (BCursor *)gCursorArray.SafeElementAt(2);
break;
case eCursor_vertical_text:
// XXX not 100% appropriate perhaps
newCursor = B_CURSOR_I_BEAM;
break;
case eCursor_all_scroll:
// XXX: No suitable cursor, needs implementing
break;
case eCursor_nesw_resize:
// XXX not 100% appropriate perhaps
newCursor = (BCursor *)gCursorArray.SafeElementAt(1);
break;
case eCursor_nwse_resize:
// XXX not 100% appropriate perhaps
newCursor = (BCursor *)gCursorArray.SafeElementAt(1);
break;
case eCursor_ns_resize:
newCursor = (BCursor *)gCursorArray.SafeElementAt(2);
break;
case eCursor_ew_resize:
newCursor = (BCursor *)gCursorArray.SafeElementAt(1);
break;
case eCursor_none:
be_app->HideCursor();
break;
default:
NS_ASSERTION(0, "Invalid cursor type");
break;
}
NS_ASSERTION(newCursor != nsnull, "Cursor not stored in array properly!");
mCursor = aCursor;
be_app->SetCursor(newCursor, true);
}
return NS_OK;
}
//-------------------------------------------------------------------------
//
// Invalidate this component visible area
//
//-------------------------------------------------------------------------
NS_METHOD nsWindow::Invalidate(PRBool aIsSynchronous)
{
nsresult rv = NS_ERROR_FAILURE;
// Asynchronous painting is performed with via nsViewBeOS::Draw() call and its message queue.
// All update rects are collected in nsViewBeOS member "paintregion".
// Flushing of paintregion happens in nsViewBeOS::GetPaintRegion(),
// cleanup - in nsViewBeOS::Validate(), called in OnPaint().
BRegion reg;
reg.MakeEmpty();
if (mView && mView->LockLooper())
{
if (PR_TRUE == aIsSynchronous)
{
mView->paintregion.Include(mView->Bounds());
reg.Include(mView->Bounds());
}
else
{
mView->Draw(mView->Bounds());
rv = NS_OK;
}
mView->UnlockLooper();
}
// Instant repaint.
if (PR_TRUE == aIsSynchronous)
rv = OnPaint(&reg);
return rv;
}
//-------------------------------------------------------------------------
//
// Invalidate this component visible area
//
//-------------------------------------------------------------------------
NS_METHOD nsWindow::Invalidate(const nsRect & aRect, PRBool aIsSynchronous)
{
nsresult rv = NS_ERROR_FAILURE;
// Very temporary region for double accounting.
BRegion reg;
reg.MakeEmpty();
if (mView && mView->LockLooper())
{
BRect r(aRect.x,
aRect.y,
aRect.x + aRect.width - 1,
aRect.y + aRect.height - 1);
if (PR_TRUE == aIsSynchronous)
{
mView->paintregion.Include(r);
reg.Include(r);
}
else
{
// we use Draw() instead direct addition to paintregion,
// as it sets queue of notification messages for painting.
mView->Draw(r);
rv = NS_OK;
}
mView->UnlockLooper();
}
// Instant repaint - for given rect only.
// Don't repaint area which isn't marked here for synchronous repaint explicitly.
// BRegion "reg" (equal to aRect) will be substracted from paintregion in OnPaint().
if (PR_TRUE == aIsSynchronous)
rv = OnPaint(&reg);
return rv;
}
//-------------------------------------------------------------------------
//
// Invalidate this component visible area
//
//-------------------------------------------------------------------------
NS_IMETHODIMP nsWindow::InvalidateRegion(const nsIRegion *aRegion, PRBool aIsSynchronous)
{
nsRegionRectSet *rectSet = nsnull;
if (!aRegion)
return NS_ERROR_FAILURE;
nsresult rv = ((nsIRegion *)aRegion)->GetRects(&rectSet);
if (NS_FAILED(rv))
return rv;
BRegion reg;
reg.MakeEmpty();
if (mView && mView->LockLooper())
{
for (PRUint32 i=0; i< rectSet->mRectsLen; ++i)
{
BRect br(rectSet->mRects[i].x, rectSet->mRects[i].y,
rectSet->mRects[i].x + rectSet->mRects[i].width-1,
rectSet->mRects[i].y + rectSet->mRects[i].height -1);
if (PR_TRUE == aIsSynchronous)
{
mView->paintregion.Include(br);
reg.Include(br);
}
else
{
mView->Draw(br);
rv = NS_OK;
}
}
mView->UnlockLooper();
}
// Instant repaint - for given region only.
// BRegion "reg"(equal to aRegion) will be substracted from paintregion in OnPaint().
if (PR_TRUE == aIsSynchronous)
rv = OnPaint(&reg);
return rv;
}
//-------------------------------------------------------------------------
//
// Force a synchronous repaint of the window
//
//-------------------------------------------------------------------------
NS_IMETHODIMP nsWindow::Update()
{
nsresult rv = NS_ERROR_FAILURE;
//Switching scrolling trigger off
mIsScrolling = PR_FALSE;
if (mWindowType == eWindowType_child)
return NS_OK;
BRegion reg;
reg.MakeEmpty();
if(mView && mView->LockLooper())
{
//Flushing native pending updates if any
if (mView->Window())
mView->Window()->UpdateIfNeeded();
// Let app_server to invalidate
mView->Invalidate();
bool nonempty = mView->GetPaintRegion(&reg);
mView->UnlockLooper();
// Look if native update calls above filled update region and paint it
if (nonempty)
rv = OnPaint(&reg);
}
return rv;
}
//-------------------------------------------------------------------------
//
// Return some native data according to aDataType
//
//-------------------------------------------------------------------------
void* nsWindow::GetNativeData(PRUint32 aDataType)
{
if (!mView)
return NULL;
switch(aDataType)
{
case NS_NATIVE_WINDOW:
return (void *)(mView->Window());
case NS_NATIVE_WIDGET:
case NS_NATIVE_PLUGIN_PORT:
return (void *)((nsViewBeOS *)mView);
case NS_NATIVE_GRAPHIC:
return (void *)((BView *)mView);
case NS_NATIVE_COLORMAP:
default:
break;
}
return NULL;
}
//-------------------------------------------------------------------------
//
// Set the colormap of the window
//
//-------------------------------------------------------------------------
NS_METHOD nsWindow::SetColorMap(nsColorMap *aColorMap)
{
NS_WARNING("nsWindow::SetColorMap - not implemented");
return NS_OK;
}
//-------------------------------------------------------------------------
//
// Scroll the bits of a window
//
//-------------------------------------------------------------------------
NS_METHOD nsWindow::Scroll(PRInt32 aDx, PRInt32 aDy, nsRect *aClipRect)
{
// Switching trigger on
mIsScrolling = PR_TRUE;
//Preventing main view invalidation loop-chain when children are moving
//by by hiding children nsWidgets.
//Maybe this method must be used wider, in move and resize chains
// and implemented in BeginResizingChildren or in Reset*Visibility() methods
//Children will be unhidden in ::Update() when called by other than gkview::Scroll() method.
HideKids(PR_TRUE);
if (mView && mView->LockLooper())
{
// Kill any attempt to invalidate until scroll is finished
mView->SetVisible(false);
BRect src;
BRect b = mView->Bounds();
if (aClipRect)
{
src.left = aClipRect->x;
src.top = aClipRect->y;
src.right = aClipRect->XMost() - 1;
src.bottom = aClipRect->YMost() - 1;
}
else
{
src = b;
}
// Restricting source by on-screen part of BView
if (mView->Window())
{
BRect screenframe = mView->ConvertFromScreen(BScreen(mView->Window()).Frame());
src = src & screenframe;
if (mView->Parent())
{
BRect parentframe = mView->ConvertFromParent(mView->Parent()->Frame());
src = src & parentframe;
}
}
BRegion invalid;
invalid.Include(src);
// Next source clipping check, for same level siblings
if ( BView *v = mView->Parent() )
{
for (BView *child = v->ChildAt(0); child; child = child->NextSibling() )
{
BRect siblingframe = mView->ConvertFromParent(child->Frame());
if (child != mView && child->Parent() != mView)
{
invalid.Exclude(siblingframe);
mView->paintregion.Exclude(siblingframe);
}
}
src = invalid.Frame();
}
// make sure we only reference visible bits
// so we don't trigger a BView invalidate
if (src.left + aDx < 0)
src.left = -aDx;
if (src.right + aDx > b.right)
src.right = b.right - aDx;
if (src.top + aDy < 0)
src.top = -aDy;
if (src.bottom + aDy > b.bottom)
src.bottom = b.bottom - aDy;
BRect dest = src.OffsetByCopy(aDx, aDy);
mView->ConstrainClippingRegion(&invalid);
// Moving visible content
if (src.IsValid() && dest.IsValid())
mView->CopyBits(src, dest);
invalid.Exclude(dest);
// Native paintregion needs shifting too, it is very important action
// (as app_server doesn't know about Mozilla viewmanager tricks) -
// it allows proper update after scroll for areas covered by other windows.
mView->paintregion.OffsetBy(aDx, aDy);
mView->ConstrainClippingRegion(&invalid);
// Time to silently move now invisible children
for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling())
{
nsWindow *childWidget = static_cast<nsWindow*>(kid);
// No need to Lock/UnlockLooper with GetBounds() and Move() methods
// using cached values and native MoveBy() instead
nsRect bounds = childWidget->mBounds;
bounds.x += aDx;
bounds.y += aDy;
childWidget->Move(bounds.x, bounds.y);
BView *child = ((BView *)kid->GetNativeData(NS_NATIVE_WIDGET));
if (child)
mView->paintregion.Exclude(child->Frame());
}
// Painting calculated region now,
// letting Update() to paint remaining content of paintregion
OnPaint(&invalid);
HideKids(PR_FALSE);
// re-allow updates
mView->SetVisible(true);
mView->UnlockLooper();
}
return NS_OK;
}
//-------------------------------------------------------------------------
//
// Every function that needs a thread switch goes through this function
// by calling SendMessage (..WM_CALLMETHOD..) in nsToolkit::CallMethod.
//
//-------------------------------------------------------------------------
bool nsWindow::CallMethod(MethodInfo *info)
{
bool bRet = TRUE;
switch (info->methodId)
{
case nsSwitchToUIThread::CLOSEWINDOW :
{
NS_ASSERTION(info->nArgs == 0, "Wrong number of arguments to CallMethod");
if (eWindowType_popup != mWindowType && eWindowType_child != mWindowType)
DealWithPopups(nsSwitchToUIThread::CLOSEWINDOW,nsPoint(0,0));
// Bit more Kung-fu. We do care ourselves about children destroy notofication.
// Including those floating dialogs we added to Gecko hierarchy in StandardWindowCreate()
for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling())
{
nsWindow *childWidget = static_cast<nsWindow*>(kid);
BWindow* kidwindow = (BWindow *)kid->GetNativeData(NS_NATIVE_WINDOW);
if (kidwindow)
{
// PostMessage() is unsafe, so using BMessenger
BMessenger bm(kidwindow);
bm.SendMessage(B_QUIT_REQUESTED);
}
}
DispatchStandardEvent(NS_DESTROY);
}
break;
#ifdef DEBUG_FOCUS
case nsSwitchToUIThread::GOT_FOCUS:
NS_ASSERTION(info->nArgs == 1, "Wrong number of arguments to CallMethod");
if (!mEnabled)
return false;
if ((uint32)info->args[0] != (uint32)mView)
printf("Wrong view to get focus\n");*/
break;
#endif
case nsSwitchToUIThread::KILL_FOCUS:
NS_ASSERTION(info->nArgs == 1, "Wrong number of arguments to CallMethod");
if ((uint32)info->args[0] == (uint32)mView)
DispatchFocus(NS_LOSTFOCUS);
#ifdef DEBUG_FOCUS
else
printf("Wrong view to de-focus\n");
#endif
#if defined BeIME
nsIMEBeOS::GetIME()->DispatchCancelIME();
if (mView && mView->LockLooper())
{
mView->SetFlags(mView->Flags() & ~B_NAVIGABLE);
mView->UnlockLooper();
}
#endif
break;
case nsSwitchToUIThread::BTNCLICK :
{
NS_ASSERTION(info->nArgs == 6, "Wrong number of arguments to CallMethod");
if (!mEnabled)
return false;
// close popup when clicked outside of the popup window
uint32 eventID = ((int32 *)info->args)[0];
PRBool rollup = PR_FALSE;
if (eventID == NS_MOUSE_BUTTON_DOWN &&
mView && mView->LockLooper())
{
BPoint p(((int32 *)info->args)[1], ((int32 *)info->args)[2]);
mView->ConvertToScreen(&p);
rollup = DealWithPopups(nsSwitchToUIThread::ONMOUSE, nsPoint(p.x, p.y));
mView->UnlockLooper();
}
// Drop click event - bug 314330
if (rollup)
return false;
DispatchMouseEvent(((int32 *)info->args)[0],
nsPoint(((int32 *)info->args)[1], ((int32 *)info->args)[2]),
((int32 *)info->args)[3],
((int32 *)info->args)[4],
((int32 *)info->args)[5]);
if (((int32 *)info->args)[0] == NS_MOUSE_BUTTON_DOWN &&
((int32 *)info->args)[5] == nsMouseEvent::eRightButton)
{
DispatchMouseEvent (NS_CONTEXTMENU,
nsPoint(((int32 *)info->args)[1], ((int32 *)info->args)[2]),
((int32 *)info->args)[3],
((int32 *)info->args)[4],
((int32 *)info->args)[5]);
}
}
break;
case nsSwitchToUIThread::ONWHEEL :
{
NS_ASSERTION(info->nArgs == 1, "Wrong number of arguments to CallMethod");
// avoid mistargeting
if ((uint32)info->args[0] != (uint32)mView)
return false;
BPoint cursor(0,0);
uint32 buttons;
BPoint delta;
if (mView && mView->LockLooper())
{
mView->GetMouse(&cursor, &buttons, false);
delta = mView->GetWheel();
mView->UnlockLooper();
}
else
return false;
// BeOS TwoWheel input-filter is bit buggy atm, generating sometimes X-wheel with no reason,
// so we're setting priority for Y-wheel.
// Also hardcoding here _system_ scroll-step value to 3 lines.
if (nscoord(delta.y) != 0)
{
OnWheel(nsMouseScrollEvent::kIsVertical, buttons, cursor, nscoord(delta.y)*3);
}
else if(nscoord(delta.x) != 0)
OnWheel(nsMouseScrollEvent::kIsHorizontal, buttons, cursor, nscoord(delta.x)*3);
}
break;
case nsSwitchToUIThread::ONKEY :
NS_ASSERTION(info->nArgs == 6, "Wrong number of arguments to CallMethod");
if (((int32 *)info->args)[0] == NS_KEY_DOWN)
{
OnKeyDown(((int32 *)info->args)[0],
(const char *)(&((uint32 *)info->args)[1]), ((int32 *)info->args)[2],
((uint32 *)info->args)[3], ((uint32 *)info->args)[4], ((int32 *)info->args)[5]);
}
else
{
if (((int32 *)info->args)[0] == NS_KEY_UP)
{
OnKeyUp(((int32 *)info->args)[0],
(const char *)(&((uint32 *)info->args)[1]), ((int32 *)info->args)[2],
((uint32 *)info->args)[3], ((uint32 *)info->args)[4], ((int32 *)info->args)[5]);
}
}
break;
case nsSwitchToUIThread::ONPAINT :
NS_ASSERTION(info->nArgs == 1, "Wrong number of arguments to CallMethod");
{
if ((uint32)mView != ((uint32 *)info->args)[0])
return false;
BRegion reg;
reg.MakeEmpty();
if(mView && mView->LockLooper())
{
bool nonempty = mView->GetPaintRegion(&reg);
mView->UnlockLooper();
if (nonempty)
OnPaint(&reg);
}
}
break;
case nsSwitchToUIThread::ONRESIZE :
{
NS_ASSERTION(info->nArgs == 0, "Wrong number of arguments to CallMethod");
if (eWindowType_popup != mWindowType && eWindowType_child != mWindowType)
DealWithPopups(nsSwitchToUIThread::ONRESIZE,nsPoint(0,0));
// This should be called only from BWindow::FrameResized()
if (!mIsTopWidgetWindow || !mView || !mView->Window())
return false;
nsRect r(mBounds);
if (mView->LockLooper())
{
BRect br = mView->Frame();
r.x = nscoord(br.left);
r.y = nscoord(br.top);
r.width = br.IntegerWidth() + 1;
r.height = br.IntegerHeight() + 1;
((nsWindowBeOS *)mView->Window())->fJustGotBounds = true;
mView->UnlockLooper();
}
OnResize(r);
}
break;
case nsSwitchToUIThread::ONMOUSE :
{
NS_ASSERTION(info->nArgs == 4, "Wrong number of arguments to CallMethod");
if (!mEnabled)
return false;
DispatchMouseEvent(((int32 *)info->args)[0],
nsPoint(((int32 *)info->args)[1], ((int32 *)info->args)[2]),
0,
((int32 *)info->args)[3]);
}
break;
case nsSwitchToUIThread::ONDROP :
{
NS_ASSERTION(info->nArgs == 4, "Wrong number of arguments to CallMethod");
nsDragEvent event(PR_TRUE, (int32) info->args[0], this);
nsPoint point(((int32 *)info->args)[1], ((int32 *)info->args)[2]);
InitEvent (event, &point);
uint32 mod = (uint32) info->args[3];
event.isShift = mod & B_SHIFT_KEY;
event.isControl = mod & B_CONTROL_KEY;
event.isAlt = mod & B_COMMAND_KEY;
event.isMeta = mod & B_OPTION_KEY;
// Setting drag action, must be done before event dispatch
nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
if (dragService)
{
nsCOMPtr<nsIDragSession> dragSession;
dragService->GetCurrentSession(getter_AddRefs(dragSession));
if (dragSession)
{
// Original action mask stored in dragsession.
// For native events such mask must be set in nsDragServiceBeOS::UpdateDragMessageIfNeeded()
PRUint32 action_mask = 0;
dragSession->GetDragAction(&action_mask);
PRUint32 action = nsIDragService::DRAGDROP_ACTION_MOVE;
if (mod & B_OPTION_KEY)
{
if (mod & B_COMMAND_KEY)
action = nsIDragService::DRAGDROP_ACTION_LINK & action_mask;
else
action = nsIDragService::DRAGDROP_ACTION_COPY & action_mask;
}
dragSession->SetDragAction(action);
}
}
DispatchWindowEvent(&event);
NS_RELEASE(event.widget);
if (dragService)
dragService->EndDragSession(PR_TRUE);
}
break;
case nsSwitchToUIThread::ONACTIVATE:
NS_ASSERTION(info->nArgs == 2, "Wrong number of arguments to CallMethod");
if (!mEnabled || eWindowType_popup == mWindowType || 0 == mView->Window())
return false;
if ((BWindow *)info->args[1] != mView->Window())
return false;
if (mEventCallback || eWindowType_child == mWindowType )
{
bool active = (bool)info->args[0];
if (!active)
{
if (eWindowType_dialog == mWindowType ||
eWindowType_toplevel == mWindowType)
DealWithPopups(nsSwitchToUIThread::ONACTIVATE,nsPoint(0,0));
//Testing if BWindow is really deactivated.
if (!mView->Window()->IsActive())
{
// BeOS is poor in windows hierarchy and variations support. In lot of aspects.
// Here is workaround for flacky Activate() handling for B_FLOATING windows.
// We should force parent (de)activation to allow main window to regain control after closing floating dialog.
if (mWindowParent && mView->Window()->IsFloating())
mWindowParent->DispatchFocus(NS_ACTIVATE);
DispatchFocus(NS_DEACTIVATE);
#if defined(BeIME)
nsIMEBeOS::GetIME()->DispatchCancelIME();
#endif
}
}
else
{
if (mView->Window()->IsActive())
{
// See comment above.
if (mWindowParent && mView->Window()->IsFloating())
mWindowParent->DispatchFocus(NS_DEACTIVATE);
DispatchFocus(NS_ACTIVATE);
if (mView && mView->Window())
gLastActiveWindow = mView->Window();
}
}
}
break;
case nsSwitchToUIThread::ONMOVE:
{
NS_ASSERTION(info->nArgs == 0, "Wrong number of arguments to CallMethod");
nsRect r;
// We use this only for tracking whole window moves
GetScreenBounds(r);
if (eWindowType_popup != mWindowType && eWindowType_child != mWindowType)
DealWithPopups(nsSwitchToUIThread::ONMOVE,nsPoint(0,0));
OnMove(r.x, r.y);
}
break;
case nsSwitchToUIThread::ONWORKSPACE:
{
NS_ASSERTION(info->nArgs == 2, "Wrong number of arguments to CallMethod");
if (eWindowType_popup != mWindowType && eWindowType_child != mWindowType)
DealWithPopups(nsSwitchToUIThread::ONWORKSPACE,nsPoint(0,0));
}
break;
#if defined(BeIME)
case nsSwitchToUIThread::ONIME:
//No assertion used, as number of arguments varies here
if (mView && mView->LockLooper())
{
mView->SetFlags(mView->Flags() | B_NAVIGABLE);
mView->UnlockLooper();
}
nsIMEBeOS::GetIME()->RunIME(info->args, this, mView);
break;
#endif
default:
bRet = FALSE;
break;
}
return bRet;
}
//-------------------------------------------------------------------------
//
// Key code translation related data
//
//-------------------------------------------------------------------------
struct nsKeyConverter {
int vkCode; // Platform independent key code
char bekeycode; // BeOS key code
};
//
// Netscape keycodes are defined in widget/public/nsGUIEvent.h
// BeOS keycodes can be viewd at
// http://www.be.com/documentation/be_book/Keyboard/KeyboardKeyCodes.html
//
struct nsKeyConverter nsKeycodesBeOS[] = {
// { NS_VK_CANCEL, GDK_Cancel },
{ NS_VK_BACK, 0x1e },
{ NS_VK_TAB, 0x26 },
// { NS_VK_TAB, GDK_ISO_Left_Tab },
// { NS_VK_CLEAR, GDK_Clear },
{ NS_VK_RETURN, 0x47 },
{ NS_VK_SHIFT, 0x4b },
{ NS_VK_SHIFT, 0x56 },
{ NS_VK_CONTROL, 0x5c },
{ NS_VK_CONTROL, 0x60 },
{ NS_VK_ALT, 0x5d },
{ NS_VK_ALT, 0x5f },
{ NS_VK_PAUSE, 0x22 },
{ NS_VK_CAPS_LOCK, 0x3b },
{ NS_VK_ESCAPE, 0x1 },
{ NS_VK_SPACE, 0x5e },
{ NS_VK_PAGE_UP, 0x21 },
{ NS_VK_PAGE_DOWN, 0x36 },
{ NS_VK_END, 0x35 },
{ NS_VK_HOME, 0x20 },
{ NS_VK_LEFT, 0x61 },
{ NS_VK_UP, 0x57 },
{ NS_VK_RIGHT, 0x63 },
{ NS_VK_DOWN, 0x62 },
{ NS_VK_PRINTSCREEN, 0xe },
{ NS_VK_INSERT, 0x1f },
{ NS_VK_DELETE, 0x34 },
// The "Windows Key"
{ NS_VK_META, 0x66 },
{ NS_VK_META, 0x67 },
// keypad keys (constant keys)
{ NS_VK_MULTIPLY, 0x24 },
{ NS_VK_ADD, 0x3a },
// { NS_VK_SEPARATOR, }, ???
{ NS_VK_SUBTRACT, 0x25 },
{ NS_VK_DIVIDE, 0x23 },
{ NS_VK_RETURN, 0x5b },
{ NS_VK_COMMA, 0x53 },
{ NS_VK_PERIOD, 0x54 },
{ NS_VK_SLASH, 0x55 },
{ NS_VK_BACK_SLASH, 0x33 },
{ NS_VK_BACK_SLASH, 0x6a }, // got this code on japanese keyboard
{ NS_VK_BACK_SLASH, 0x6b }, // got this code on japanese keyboard
{ NS_VK_BACK_QUOTE, 0x11 },
{ NS_VK_OPEN_BRACKET, 0x31 },
{ NS_VK_CLOSE_BRACKET, 0x32 },
{ NS_VK_SEMICOLON, 0x45 },
{ NS_VK_QUOTE, 0x46 },
// NS doesn't have dash or equals distinct from the numeric keypad ones,
// so we'll use those for now. See bug 17008:
{ NS_VK_SUBTRACT, 0x1c },
{ NS_VK_EQUALS, 0x1d },
{ NS_VK_F1, B_F1_KEY },
{ NS_VK_F2, B_F2_KEY },
{ NS_VK_F3, B_F3_KEY },
{ NS_VK_F4, B_F4_KEY },
{ NS_VK_F5, B_F5_KEY },
{ NS_VK_F6, B_F6_KEY },
{ NS_VK_F7, B_F7_KEY },
{ NS_VK_F8, B_F8_KEY },
{ NS_VK_F9, B_F9_KEY },
{ NS_VK_F10, B_F10_KEY },
{ NS_VK_F11, B_F11_KEY },
{ NS_VK_F12, B_F12_KEY },
{ NS_VK_1, 0x12 },
{ NS_VK_2, 0x13 },
{ NS_VK_3, 0x14 },
{ NS_VK_4, 0x15 },
{ NS_VK_5, 0x16 },
{ NS_VK_6, 0x17 },
{ NS_VK_7, 0x18 },
{ NS_VK_8, 0x19 },
{ NS_VK_9, 0x1a },
{ NS_VK_0, 0x1b },
{ NS_VK_A, 0x3c },
{ NS_VK_B, 0x50 },
{ NS_VK_C, 0x4e },
{ NS_VK_D, 0x3e },
{ NS_VK_E, 0x29 },
{ NS_VK_F, 0x3f },
{ NS_VK_G, 0x40 },
{ NS_VK_H, 0x41 },
{ NS_VK_I, 0x2e },
{ NS_VK_J, 0x42 },
{ NS_VK_K, 0x43 },
{ NS_VK_L, 0x44 },
{ NS_VK_M, 0x52 },
{ NS_VK_N, 0x51 },
{ NS_VK_O, 0x2f },
{ NS_VK_P, 0x30 },
{ NS_VK_Q, 0x27 },
{ NS_VK_R, 0x2a },
{ NS_VK_S, 0x3d },
{ NS_VK_T, 0x2b },
{ NS_VK_U, 0x2d },
{ NS_VK_V, 0x4f },
{ NS_VK_W, 0x28 },
{ NS_VK_X, 0x4d },
{ NS_VK_Y, 0x2c },
{ NS_VK_Z, 0x4c }
};
// keycode of keypad when num-locked
struct nsKeyConverter nsKeycodesBeOSNumLock[] = {
{ NS_VK_NUMPAD0, 0x64 },
{ NS_VK_NUMPAD1, 0x58 },
{ NS_VK_NUMPAD2, 0x59 },
{ NS_VK_NUMPAD3, 0x5a },
{ NS_VK_NUMPAD4, 0x48 },
{ NS_VK_NUMPAD5, 0x49 },
{ NS_VK_NUMPAD6, 0x4a },
{ NS_VK_NUMPAD7, 0x37 },
{ NS_VK_NUMPAD8, 0x38 },
{ NS_VK_NUMPAD9, 0x39 },
{ NS_VK_DECIMAL, 0x65 }
};
// keycode of keypad when not num-locked
struct nsKeyConverter nsKeycodesBeOSNoNumLock[] = {
{ NS_VK_LEFT, 0x48 },
{ NS_VK_RIGHT, 0x4a },
{ NS_VK_UP, 0x38 },
{ NS_VK_DOWN, 0x59 },
{ NS_VK_PAGE_UP, 0x39 },
{ NS_VK_PAGE_DOWN, 0x5a },
{ NS_VK_HOME, 0x37 },
{ NS_VK_END, 0x58 },
{ NS_VK_INSERT, 0x64 },
{ NS_VK_DELETE, 0x65 }
};
//-------------------------------------------------------------------------
//
// Translate key code
// Input is BeOS keyboard key-code; output is in NS_VK format
//
//-------------------------------------------------------------------------
static int TranslateBeOSKeyCode(int32 bekeycode, bool isnumlock)
{
#ifdef KB_DEBUG
printf("TranslateBeOSKeyCode: bekeycode = 0x%x\n",bekeycode);
#endif
int i;
int length = sizeof(nsKeycodesBeOS) / sizeof(struct nsKeyConverter);
int length_numlock = sizeof(nsKeycodesBeOSNumLock) / sizeof(struct nsKeyConverter);
int length_nonumlock = sizeof(nsKeycodesBeOSNoNumLock) / sizeof(struct nsKeyConverter);
// key code conversion
for (i = 0; i < length; i++)
{
if (nsKeycodesBeOS[i].bekeycode == bekeycode)
return(nsKeycodesBeOS[i].vkCode);
}
// numpad keycode vary with numlock
if (isnumlock)
{
for (i = 0; i < length_numlock; i++)
{
if (nsKeycodesBeOSNumLock[i].bekeycode == bekeycode)
return(nsKeycodesBeOSNumLock[i].vkCode);
}
}
else
{
for (i = 0; i < length_nonumlock; i++)
{
if (nsKeycodesBeOSNoNumLock[i].bekeycode == bekeycode)
return(nsKeycodesBeOSNoNumLock[i].vkCode);
}
}
#ifdef KB_DEBUG
printf("TranslateBeOSKeyCode: ####### Translation not Found #######\n");
#endif
return((int)0);
}
//-------------------------------------------------------------------------
//
// OnKeyDown
//
//-------------------------------------------------------------------------
PRBool nsWindow::OnKeyDown(PRUint32 aEventType, const char *bytes,
int32 numBytes, PRUint32 mod, PRUint32 bekeycode, int32 rawcode)
{
PRUint32 aTranslatedKeyCode;
PRBool noDefault = PR_FALSE;
mIsShiftDown = (mod & B_SHIFT_KEY) ? PR_TRUE : PR_FALSE;
mIsControlDown = (mod & B_CONTROL_KEY) ? PR_TRUE : PR_FALSE;
mIsAltDown = ((mod & B_COMMAND_KEY) && !(mod & B_RIGHT_OPTION_KEY))? PR_TRUE : PR_FALSE;
mIsMetaDown = (mod & B_LEFT_OPTION_KEY) ? PR_TRUE : PR_FALSE;
bool IsNumLocked = ((mod & B_NUM_LOCK) != 0);
aTranslatedKeyCode = TranslateBeOSKeyCode(bekeycode, IsNumLocked);
if (numBytes <= 1)
{
noDefault = DispatchKeyEvent(NS_KEY_DOWN, 0, aTranslatedKeyCode);
}
else
{
// non ASCII chars
}
// ------------ On Char ------------
PRUint32 uniChar;
if ((mIsControlDown || mIsAltDown || mIsMetaDown) && rawcode >= 'a' && rawcode <= 'z')
{
if (mIsShiftDown)
uniChar = rawcode + 'A' - 'a';
else
uniChar = rawcode;
aTranslatedKeyCode = 0;
}
else
{
if (numBytes == 0) // deal with unmapped key
return noDefault;
switch((unsigned char)bytes[0])
{
case 0xc8://System Request
case 0xca://Break
return noDefault;// do not send 'KEY_PRESS' message
case B_INSERT:
case B_ESCAPE:
case B_FUNCTION_KEY:
case B_HOME:
case B_PAGE_UP:
case B_END:
case B_PAGE_DOWN:
case B_UP_ARROW:
case B_LEFT_ARROW:
case B_DOWN_ARROW:
case B_RIGHT_ARROW:
case B_TAB:
case B_DELETE:
case B_BACKSPACE:
case B_ENTER:
uniChar = 0;
break;
default:
// UTF-8 to unicode conversion
if (numBytes >= 1 && (bytes[0] & 0x80) == 0)
{
// 1 byte utf-8 char
uniChar = bytes[0];
}
else
{
if (numBytes >= 2 && (bytes[0] & 0xe0) == 0xc0)
{
// 2 byte utf-8 char
uniChar = ((uint16)(bytes[0] & 0x1f) << 6) | (uint16)(bytes[1] & 0x3f);
}
else
{
if (numBytes >= 3 && (bytes[0] & 0xf0) == 0xe0)
{
// 3 byte utf-8 char
uniChar = ((uint16)(bytes[0] & 0x0f) << 12) | ((uint16)(bytes[1] & 0x3f) << 6)
| (uint16)(bytes[2] & 0x3f);
}
else
{
//error
uniChar = 0;
NS_WARNING("nsWindow::OnKeyDown() error: bytes[] has not enough chars.");
}
}
}
aTranslatedKeyCode = 0;
break;
}
}
// If prevent default set for onkeydown, do the same for onkeypress
PRUint32 extraFlags = (noDefault ? NS_EVENT_FLAG_NO_DEFAULT : 0);
return DispatchKeyEvent(NS_KEY_PRESS, uniChar, aTranslatedKeyCode, extraFlags) && noDefault;
}
//-------------------------------------------------------------------------
//
// OnKeyUp
//
//-------------------------------------------------------------------------
PRBool nsWindow::OnKeyUp(PRUint32 aEventType, const char *bytes,
int32 numBytes, PRUint32 mod, PRUint32 bekeycode, int32 rawcode)
{
PRUint32 aTranslatedKeyCode;
bool IsNumLocked = ((mod & B_NUM_LOCK) != 0);
mIsShiftDown = (mod & B_SHIFT_KEY) ? PR_TRUE : PR_FALSE;
mIsControlDown = (mod & B_CONTROL_KEY) ? PR_TRUE : PR_FALSE;
mIsAltDown = ((mod & B_COMMAND_KEY) && !(mod & B_RIGHT_OPTION_KEY))? PR_TRUE : PR_FALSE;
mIsMetaDown = (mod & B_LEFT_OPTION_KEY) ? PR_TRUE : PR_FALSE;
aTranslatedKeyCode = TranslateBeOSKeyCode(bekeycode, IsNumLocked);
PRBool result = DispatchKeyEvent(NS_KEY_UP, 0, aTranslatedKeyCode);
return result;
}
//-------------------------------------------------------------------------
//
// DispatchKeyEvent
//
//-------------------------------------------------------------------------
PRBool nsWindow::DispatchKeyEvent(PRUint32 aEventType, PRUint32 aCharCode,
PRUint32 aKeyCode, PRUint32 aFlags)
{
nsKeyEvent event(PR_TRUE, aEventType, this);
nsPoint point;
point.x = 0;
point.y = 0;
InitEvent(event, &point); // this add ref's event.widget
event.flags |= aFlags;
event.charCode = aCharCode;
event.keyCode = aKeyCode;
#ifdef KB_DEBUG
static int cnt=0;
printf("%d DispatchKE Type: %s charCode 0x%x keyCode 0x%x ", cnt++,
(NS_KEY_PRESS == aEventType)?"PRESS":(aEventType == NS_KEY_UP?"Up":"Down"),
event.charCode, event.keyCode);
printf("Shift: %s Control %s Alt: %s Meta: %s\n",
(mIsShiftDown?"D":"U"),
(mIsControlDown?"D":"U"),
(mIsAltDown?"D":"U"),
(mIsMetaDown?"D":"U"));
#endif
event.isShift = mIsShiftDown;
event.isControl = mIsControlDown;
event.isMeta = mIsMetaDown;
event.isAlt = mIsAltDown;
PRBool result = DispatchWindowEvent(&event);
NS_RELEASE(event.widget);
return result;
}
//-------------------------------------------------------------------------
//
// WM_DESTROY has been called
//
//-------------------------------------------------------------------------
void nsWindow::OnDestroy()
{
mOnDestroyCalled = PR_TRUE;
// release references to children, device context, toolkit, and app shell
nsBaseWidget::OnDestroy();
// dispatch the event
if (!mIsDestroying)
{
// dispatching of the event may cause the reference count to drop to 0
// and result in this object being destroyed. To avoid that, add a reference
// and then release it after dispatching the event
AddRef();
DispatchStandardEvent(NS_DESTROY);
Release();
}
}
//-------------------------------------------------------------------------
//
// Move
//
//-------------------------------------------------------------------------
PRBool nsWindow::OnMove(PRInt32 aX, PRInt32 aY)
{
nsGUIEvent event(PR_TRUE, NS_MOVE, this);
InitEvent(event);
event.refPoint.x = aX;
event.refPoint.y = aY;
PRBool result = DispatchWindowEvent(&event);
NS_RELEASE(event.widget);
return result;
}
void nsWindow::OnWheel(PRInt32 aDirection, uint32 aButtons, BPoint aPoint, nscoord aDelta)
{
// we don't use the mIsXDown bools because
// they get reset on Gecko reload (makes it harder
// to use stuff like Alt+Wheel)
nsMouseScrollEvent scrollEvent(PR_TRUE, NS_MOUSE_SCROLL, this);
uint32 mod (modifiers());
scrollEvent.isControl = mod & B_CONTROL_KEY;
scrollEvent.isShift = mod & B_SHIFT_KEY;
scrollEvent.isAlt = mod & B_COMMAND_KEY;
scrollEvent.isMeta = mod & B_OPTION_KEY;
scrollEvent.scrollFlags = aDirection;
scrollEvent.delta = aDelta;
scrollEvent.time = PR_IntervalNow();
scrollEvent.refPoint.x = nscoord(aPoint.x);
scrollEvent.refPoint.y = nscoord(aPoint.y);
nsEventStatus rv;
DispatchEvent (&scrollEvent, rv);
}
//-------------------------------------------------------------------------
//
// Paint
//
//-------------------------------------------------------------------------
nsresult nsWindow::OnPaint(BRegion *breg)
{
nsresult rv = NS_ERROR_FAILURE;
if (mView && mView->LockLooper())
{
// Substracting area from paintregion
mView->Validate(breg);
// looks like it should be done by Mozilla via nsRenderingContext methods,
// but we saw in some cases how it follows Win32 ideas and don't care about clipping there
mView->ConstrainClippingRegion(breg);
mView->UnlockLooper();
}
else
return rv;
BRect br = breg->Frame();
if (!br.IsValid() || !mEventCallback || !mView || (eWindowType_child != mWindowType && eWindowType_popup != mWindowType))
return rv;
nsRect nsr(nscoord(br.left), nscoord(br.top),
nscoord(br.IntegerWidth() + 1), nscoord(br.IntegerHeight() + 1));
mUpdateArea->SetTo(0,0,0,0);
int numrects = breg->CountRects();
for (int i = 0; i< numrects; i++)
{
BRect br = breg->RectAt(i);
mUpdateArea->Union(int(br.left), int(br.top),
br.IntegerWidth() + 1, br.IntegerHeight() + 1);
}
nsIRenderingContext* rc = GetRenderingContext();
if (NS_UNLIKELY(!rc)) {
return NS_ERROR_FAILURE;
}
// Double buffering for cairo builds is done here
nsRefPtr<gfxContext> ctx = rc->ThebesContext();
ctx->Save();
// Clip
ctx->NewPath();
for (int i = 0; i< numrects; i++)
{
BRect br = breg->RectAt(i);
ctx->Rectangle(gfxRect(int(br.left), int(br.top),
br.IntegerWidth() + 1, br.IntegerHeight() + 1));
}
ctx->Clip();
// double buffer
ctx->PushGroup(gfxContext::CONTENT_COLOR);
nsPaintEvent event(PR_TRUE, NS_PAINT, this);
InitEvent(event);
event.region = mUpdateArea;
event.rect = &nsr;
event.renderingContext = rc;
if (event.renderingContext != nsnull)
{
// TODO: supply nsRenderingContextBeOS with font, colors and other state variables here.
// It will help toget rid of some hacks in LockAndUpdateView and
// allow non-permanent nsDrawingSurface for BeOS - currently it fails for non-bitmapped BViews/widgets.
// Something like this:
//if (mFontMetrics)
// event.renderingContext->SetFont(mFontMetrics);
rv = DispatchWindowEvent(&event) ? NS_OK : NS_ERROR_FAILURE;
NS_RELEASE(event.renderingContext);
}
NS_RELEASE(event.widget);
// The second half of double buffering
if (rv == NS_OK) {
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->PopGroupToSource();
ctx->Paint();
} else {
// ignore
ctx->PopGroup();
}
ctx->Restore();
return rv;
}
//-------------------------------------------------------------------------
//
// Send a resize message to the listener
//
//-------------------------------------------------------------------------
PRBool nsWindow::OnResize(nsRect &aWindowRect)
{
// call the event callback
if (mEventCallback)
{
nsSizeEvent event(PR_TRUE, NS_SIZE, this);
InitEvent(event);
event.windowSize = &aWindowRect;
// We have same size for windows rect and "client area" rect
event.mWinWidth = aWindowRect.width;
event.mWinHeight = aWindowRect.height;
PRBool result = DispatchWindowEvent(&event);
NS_RELEASE(event.widget);
return result;
}
return PR_FALSE;
}
//-------------------------------------------------------------------------
//
// Deal with all sort of mouse event
//
//-------------------------------------------------------------------------
PRBool nsWindow::DispatchMouseEvent(PRUint32 aEventType, nsPoint aPoint, PRUint32 clicks, PRUint32 mod,
PRUint16 aButton)
{
PRBool result = PR_FALSE;
if (nsnull != mEventCallback)
{
nsMouseEvent event(PR_TRUE, aEventType, this, nsMouseEvent::eReal);
InitEvent (event, &aPoint);
event.isShift = mod & B_SHIFT_KEY;
event.isControl = mod & B_CONTROL_KEY;
event.isAlt = mod & B_COMMAND_KEY;
event.isMeta = mod & B_OPTION_KEY;
event.clickCount = clicks;
event.button = aButton;
// call the event callback
result = DispatchWindowEvent(&event);
NS_RELEASE(event.widget);
return result;
}
return PR_FALSE;
}
//-------------------------------------------------------------------------
//
// Deal with focus messages
//
//-------------------------------------------------------------------------
PRBool nsWindow::DispatchFocus(PRUint32 aEventType)
{
// call the event callback
if (mEventCallback)
return(DispatchStandardEvent(aEventType));
return PR_FALSE;
}
NS_METHOD nsWindow::SetTitle(const nsAString& aTitle)
{
if (mView && mView->LockLooper())
{
mView->Window()->SetTitle(NS_ConvertUTF16toUTF8(aTitle).get());
mView->UnlockLooper();
}
return NS_OK;
}
//----------------------------------------------------
//
// Get/Set the preferred size
//
//----------------------------------------------------
NS_METHOD nsWindow::GetPreferredSize(PRInt32& aWidth, PRInt32& aHeight)
{
// TODO: Check to see how often this is called. If too much, leave as is,
// otherwise, call mView->GetPreferredSize
aWidth = mPreferredWidth;
aHeight = mPreferredHeight;
return NS_ERROR_FAILURE;
}
NS_METHOD nsWindow::SetPreferredSize(PRInt32 aWidth, PRInt32 aHeight)
{
mPreferredWidth = aWidth;
mPreferredHeight = aHeight;
return NS_OK;
}
//----------------------------------------------------
// Special Sub-Class
//----------------------------------------------------
nsIWidgetStore::nsIWidgetStore( nsIWidget *aWidget )
: mWidget( aWidget )
{
// NS_ADDREF/NS_RELEASE is not needed here.
// This class is used as internal (BeOS native) object of nsWindow,
// so it must not addref/release nsWindow here.
// Otherwise, nsWindow object will leak. (Makoto Hamanaka)
}
nsIWidgetStore::~nsIWidgetStore()
{
}
nsIWidget *nsIWidgetStore::GetMozillaWidget(void)
{
return mWidget;
}
//----------------------------------------------------
// BeOS Sub-Class Window
//----------------------------------------------------
nsWindowBeOS::nsWindowBeOS( nsIWidget *aWidgetWindow, BRect aFrame, const char *aName, window_look aLook,
window_feel aFeel, int32 aFlags, int32 aWorkspace )
: BWindow( aFrame, aName, aLook, aFeel, aFlags, aWorkspace ),
nsIWidgetStore( aWidgetWindow )
{
fJustGotBounds = true;
}
nsWindowBeOS::~nsWindowBeOS()
{
//placeholder for clean up
}
bool nsWindowBeOS::QuitRequested( void )
{
if (CountChildren() != 0)
{
nsWindow *w = (nsWindow *)GetMozillaWidget();
nsToolkit *t;
if (w && (t = w->GetToolkit()) != 0)
{
MethodInfo *info = nsnull;
if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::CLOSEWINDOW)))
t->CallMethodAsync(info);
}
}
return true;
}
void nsWindowBeOS::MessageReceived(BMessage *msg)
{
// Temp replacement for real DnD. Supports file drop onto window.
if (msg->what == B_SIMPLE_DATA)
{
printf("BWindow::SIMPLE_DATA\n");
be_app_messenger.SendMessage(msg);
}
BWindow::MessageReceived(msg);
}
// This function calls KeyDown() for Alt+whatever instead of app_server,
// also used for Destroy workflow
void nsWindowBeOS::DispatchMessage(BMessage *msg, BHandler *handler)
{
if (msg->what == B_KEY_DOWN && modifiers() & B_COMMAND_KEY)
{
BString bytes;
if (B_OK == msg->FindString("bytes", &bytes))
{
BView *view = this->CurrentFocus();
if (view)
view->KeyDown(bytes.String(), bytes.Length());
}
if (strcmp(bytes.String(),"w") && strcmp(bytes.String(),"W"))
BWindow::DispatchMessage(msg, handler);
}
// In some cases the message don't reach QuitRequested() hook,
// so do it here
else if(msg->what == B_QUIT_REQUESTED)
{
// tells nsWindow to kill me
nsWindow *w = (nsWindow *)GetMozillaWidget();
nsToolkit *t;
if (w && (t = w->GetToolkit()) != 0)
{
MethodInfo *info = nsnull;
if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::CLOSEWINDOW)))
t->CallMethodAsync(info);
}
}
else
BWindow::DispatchMessage(msg, handler);
}
//This method serves single purpose here - allows Mozilla to save current window position,
//and restore position on new start.
void nsWindowBeOS::FrameMoved(BPoint origin)
{
//determine if the window position actually changed
if (origin.x == lastWindowPoint.x && origin.x == lastWindowPoint.x)
{
//it didn't - don't bother
return;
}
lastWindowPoint = origin;
nsWindow *w = (nsWindow *)GetMozillaWidget();
nsToolkit *t;
if (w && (t = w->GetToolkit()) != 0)
{
MethodInfo *info = nsnull;
if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::ONMOVE)))
t->CallMethodAsync(info);
}
}
void nsWindowBeOS::WindowActivated(bool active)
{
// Calls method ONACTIVATE to dispatch focus ACTIVATE messages
nsWindow *w = (nsWindow *)GetMozillaWidget();
nsToolkit *t;
if (w && (t = w->GetToolkit()) != 0)
{
uint32 args[2];
args[0] = (uint32)active;
args[1] = (uint32)this;
MethodInfo *info = nsnull;
if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::ONACTIVATE, 2, args)))
t->CallMethodAsync(info);
}
}
void nsWindowBeOS::WorkspacesChanged(uint32 oldworkspace, uint32 newworkspace)
{
if (oldworkspace == newworkspace)
return;
nsWindow *w = (nsWindow *)GetMozillaWidget();
nsToolkit *t;
if (w && (t = w->GetToolkit()) != 0)
{
uint32 args[2];
args[0] = newworkspace;
args[1] = oldworkspace;
MethodInfo *info = nsnull;
if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::ONWORKSPACE, 2, args)))
t->CallMethodAsync(info);
}
}
void nsWindowBeOS::FrameResized(float width, float height)
{
// We have send message already, and Mozilla still didn't get it
// so don't poke it endlessly with no reason
if (!fJustGotBounds)
return;
nsWindow *w = (nsWindow *)GetMozillaWidget();
nsToolkit *t;
if (w && (t = w->GetToolkit()) != 0)
{
MethodInfo *info = nsnull;
if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::ONRESIZE)))
{
//Memorize fact of sending message
if (t->CallMethodAsync(info))
fJustGotBounds = false;
}
}
}
//----------------------------------------------------
// BeOS Sub-Class View
//----------------------------------------------------
nsViewBeOS::nsViewBeOS(nsIWidget *aWidgetWindow, BRect aFrame, const char *aName, uint32 aResizingMode, uint32 aFlags)
: BView(aFrame, aName, aResizingMode, aFlags), nsIWidgetStore(aWidgetWindow), wheel(.0,.0)
{
SetViewColor(B_TRANSPARENT_COLOR);
paintregion.MakeEmpty();
buttons = 0;
fRestoreMouseMask = false;
fJustValidated = true;
fWheelDispatched = true;
fVisible = true;
}
void nsViewBeOS::SetVisible(bool visible)
{
if (visible)
SetFlags(Flags() | B_WILL_DRAW);
else
SetFlags(Flags() & ~B_WILL_DRAW);
fVisible = visible;
}
inline bool nsViewBeOS::Visible()
{
return fVisible;
}
void nsViewBeOS::Draw(BRect updateRect)
{
// Ignore all, we are scrolling.
if (!fVisible)
return;
paintregion.Include(updateRect);
// We have send message already, and Mozilla still didn't get it
// so don't poke it endlessly with no reason. Also don't send message
// if update region is empty.
if (paintregion.CountRects() == 0 || !paintregion.Frame().IsValid() || !fJustValidated)
return;
uint32 args[1];
args[0] = (uint32)this;
nsWindow *w = (nsWindow *)GetMozillaWidget();
nsToolkit *t;
if (w && (t = w->GetToolkit()) != 0)
{
MethodInfo *info = nsnull;
info = new MethodInfo(w, w, nsSwitchToUIThread::ONPAINT, 1, args);
if (info)
{
//Memorize fact of sending message
if (t->CallMethodAsync(info))
fJustValidated = false;
}
}
}
// Method to get update rects for asynchronous drawing.
bool nsViewBeOS::GetPaintRegion(BRegion *r)
{
// Mozilla got previous ONPAINT message,
// ready for next event.
fJustValidated = true;
if (paintregion.CountRects() == 0)
return false;
r->Include(&paintregion);
return true;
}
// Method to remove painted rects from pending update region
void nsViewBeOS::Validate(BRegion *reg)
{
paintregion.Exclude(reg);
}
BPoint nsViewBeOS::GetWheel()
{
BPoint retvalue = wheel;
// Mozilla got wheel event, so setting flag and cleaning delta storage
fWheelDispatched = true;
wheel.x = 0;
wheel.y = 0;
return retvalue;
}
void nsViewBeOS::MouseDown(BPoint point)
{
if (!fRestoreMouseMask)
mouseMask = SetMouseEventMask(B_POINTER_EVENTS);
fRestoreMouseMask = true;
//To avoid generating extra mouseevents when there is no change in pos.
mousePos = point;
uint32 clicks = 0;
BMessage *msg = Window()->CurrentMessage();
msg->FindInt32("buttons", (int32 *) &buttons);
msg->FindInt32("clicks", (int32 *) &clicks);
if (0 == buttons)
return;
nsWindow *w = (nsWindow *) GetMozillaWidget();
if (w == NULL)
return;
nsToolkit *t = w->GetToolkit();
if (t == NULL)
return;
PRUint16 eventButton =
(buttons & B_PRIMARY_MOUSE_BUTTON) ? nsMouseEvent::eLeftButton :
((buttons & B_SECONDARY_MOUSE_BUTTON) ? nsMouseEvent::eRightButton :
nsMouseEvent::eMiddleButton);
uint32 args[6];
args[0] = NS_MOUSE_BUTTON_DOWN;
args[1] = (uint32) point.x;
args[2] = (uint32) point.y;
args[3] = clicks;
args[4] = modifiers();
args[5] = eventButton;
MethodInfo *info = nsnull;
if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::BTNCLICK, 6, args)))
t->CallMethodAsync(info);
}
void nsViewBeOS::MouseMoved(BPoint point, uint32 transit, const BMessage *msg)
{
//To avoid generating extra mouseevents when there is no change in pos.
//and not entering exiting view.
if (mousePos == point && (transit == B_INSIDE_VIEW || transit == B_OUTSIDE_VIEW))
return;
mousePos = point;
//We didn't start the mouse down and there is no drag in progress, so ignore.
if (NULL == msg && !fRestoreMouseMask && buttons)
return;
nsWindow *w = (nsWindow *)GetMozillaWidget();
if (w == NULL)
return;
nsToolkit *t = w->GetToolkit();
if (t == NULL)
return;
uint32 args[4];
args[1] = (int32) point.x;
args[2] = (int32) point.y;
args[3] = modifiers();
switch (transit)
{
case B_ENTERED_VIEW:
{
args[0] = NULL != msg ? NS_DRAGDROP_ENTER : NS_MOUSE_ENTER;
if (msg == NULL)
break;
nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
dragService->StartDragSession();
//As it may have come from the outside we need to update this.
nsCOMPtr<nsIDragSessionBeOS> dragSessionBeOS = do_QueryInterface(dragService);
dragSessionBeOS->UpdateDragMessageIfNeeded(new BMessage(*msg));
}
break;
case B_EXITED_VIEW:
{
args[0] = NULL != msg ? NS_DRAGDROP_EXIT : NS_MOUSE_EXIT;
if (msg == NULL)
break;
nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
dragService->EndDragSession(PR_FALSE);
}
break;
default:
args[0]= msg == NULL ? NS_MOUSE_MOVE : NS_DRAGDROP_OVER;
// fire the drag event at the source
if (msg != NULL) {
nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
dragService->FireDragEventAtSource(NS_DRAGDROP_DRAG);
}
}
MethodInfo *moveInfo = nsnull;
if (nsnull != (moveInfo = new MethodInfo(w, w, nsSwitchToUIThread::ONMOUSE, 4, args)))
t->CallMethodAsync(moveInfo);
}
void nsViewBeOS::MouseUp(BPoint point)
{
if (fRestoreMouseMask)
{
SetMouseEventMask(mouseMask);
fRestoreMouseMask = false;
}
//To avoid generating extra mouseevents when there is no change in pos.
mousePos = point;
PRUint16 eventButton =
(buttons & B_PRIMARY_MOUSE_BUTTON) ? nsMouseEvent::eLeftButton :
((buttons & B_SECONDARY_MOUSE_BUTTON) ? nsMouseEvent::eRightButton :
nsMouseEvent::eMiddleButton);
nsWindow *w = (nsWindow *)GetMozillaWidget();
if (w == NULL)
return;
nsToolkit *t = w->GetToolkit();
if (t == NULL)
return;
uint32 args[6];
args[0] = NS_MOUSE_BUTTON_UP;
args[1] = (uint32) point.x;
args[2] = (int32) point.y;
args[3] = 0;
args[4] = modifiers();
args[5] = eventButton;
MethodInfo *info = nsnull;
if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::BTNCLICK, 6, args)))
t->CallMethodAsync(info);
}
void nsViewBeOS::MessageReceived(BMessage *msg)
{
if(msg->WasDropped())
{
nsWindow *w = (nsWindow *)GetMozillaWidget();
if (w == NULL)
return;
nsToolkit *t = w->GetToolkit();
if (t == NULL)
return;
uint32 args[4];
args[0] = NS_DRAGDROP_DROP;
//Drop point is in screen-cordinates
BPoint aPoint = ConvertFromScreen(msg->DropPoint());
args[1] = (uint32) aPoint.x;
args[2] = (uint32) aPoint.y;
args[3] = modifiers();
MethodInfo *info = new MethodInfo(w, w, nsSwitchToUIThread::ONDROP, 4, args);
t->CallMethodAsync(info);
BView::MessageReceived(msg);
return;
}
switch(msg->what)
{
//Native drag'n'drop negotiation
case B_COPY_TARGET:
case B_MOVE_TARGET:
case B_LINK_TARGET:
case B_TRASH_TARGET:
{
nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
nsCOMPtr<nsIDragSessionBeOS> dragSessionBeOS = do_QueryInterface(dragService);
dragSessionBeOS->TransmitData(new BMessage(*msg));
}
break;
case B_UNMAPPED_KEY_DOWN:
//printf("unmapped_key_down\n");
KeyDown(NULL, 0);
break;
case B_UNMAPPED_KEY_UP:
//printf("unmapped_key_up\n");
KeyUp(NULL, 0);
break;
case B_MOUSE_WHEEL_CHANGED:
{
float wheel_y;
float wheel_x;
msg->FindFloat ("be:wheel_delta_y", &wheel_y);
msg->FindFloat ("be:wheel_delta_x", &wheel_x);
wheel.x += wheel_x;
wheel.y += wheel_y;
if(!fWheelDispatched || (nscoord(wheel_x) == 0 && nscoord(wheel_y) == 0))
return;
uint32 args[1];
args[0] = (uint32)this;
nsWindow *w = (nsWindow *)GetMozillaWidget();
nsToolkit *t;
if (w && (t = w->GetToolkit()) != 0)
{
MethodInfo *info = nsnull;
if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::ONWHEEL, 1, args)))
{
if (t->CallMethodAsync(info))
fWheelDispatched = false;
}
}
}
break;
#if defined(BeIME)
case B_INPUT_METHOD_EVENT:
DoIME(msg);
break;
#endif
default :
BView::MessageReceived(msg);
break;
}
}
void nsViewBeOS::KeyDown(const char *bytes, int32 numBytes)
{
nsWindow *w = (nsWindow *)GetMozillaWidget();
nsToolkit *t;
int32 keycode = 0;
int32 rawcode = 0;
BMessage *msg = this->Window()->CurrentMessage();
if (msg)
{
msg->FindInt32("key", &keycode);
msg->FindInt32("raw_char", &rawcode);
}
if (w && (t = w->GetToolkit()) != 0)
{
uint32 bytebuf = 0;
uint8 *byteptr = (uint8 *)&bytebuf;
for(int32 i = 0; i < numBytes; i++)
byteptr[i] = bytes[i];
uint32 args[6];
args[0] = NS_KEY_DOWN;
args[1] = bytebuf;
args[2] = numBytes;
args[3] = modifiers();
args[4] = keycode;
args[5] = rawcode;
MethodInfo *info = nsnull;
if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::ONKEY, 6, args)))
t->CallMethodAsync(info);
}
}
void nsViewBeOS::KeyUp(const char *bytes, int32 numBytes)
{
nsWindow *w = (nsWindow *)GetMozillaWidget();
nsToolkit *t;
int32 keycode = 0;
int32 rawcode = 0;
BMessage *msg = this->Window()->CurrentMessage();
if (msg)
{
msg->FindInt32("key", &keycode);
msg->FindInt32("raw_char", &rawcode);
}
if (w && (t = w->GetToolkit()) != 0)
{
uint32 bytebuf = 0;
uint8 *byteptr = (uint8 *)&bytebuf;
for(int32 i = 0; i < numBytes; i++)
byteptr[i] = bytes[i];
uint32 args[6];
args[0] = NS_KEY_UP;
args[1] = (int32)bytebuf;
args[2] = numBytes;
args[3] = modifiers();
args[4] = keycode;
args[5] = rawcode;
MethodInfo *info = nsnull;
if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::ONKEY, 6, args)))
t->CallMethodAsync(info);
}
}
void nsViewBeOS::MakeFocus(bool focused)
{
if (!IsFocus() && focused)
BView::MakeFocus(focused);
uint32 args[1];
args[0] = (uint32)this;
nsWindow *w = (nsWindow *)GetMozillaWidget();
nsToolkit *t;
if (w && (t = w->GetToolkit()) != 0)
{
MethodInfo *info = nsnull;
if (!focused)
{
if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::KILL_FOCUS, 1, args)))
t->CallMethodAsync(info);
}
#ifdef DEBUG_FOCUS
else
{
if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::GOT_FOCUS, 1, args)))
t->CallMethodAsync(info);
}
#endif
}
}
#if defined(BeIME)
// Inline Input Method implementation
void nsViewBeOS::DoIME(BMessage *msg)
{
nsWindow *w = (nsWindow *)GetMozillaWidget();
nsToolkit *t;
if(w && (t = w->GetToolkit()) != 0)
{
ssize_t size = msg->FlattenedSize();
int32 argc = (size+3)/4;
uint32 *args = new uint32[argc];
if (args)
{
msg->Flatten((char*)args, size);
MethodInfo *info = new MethodInfo(w, w, nsSwitchToUIThread::ONIME, argc, args);
if (info)
{
t->CallMethodAsync(info);
NS_RELEASE(t);
}
delete[] args;
}
}
}
#endif