1538 lines
41 KiB
C++
1538 lines
41 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; 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):
|
|
* Peter Hartshorn <peter@igelaus.com.au>
|
|
* Ken Faulkner <faulkner@igelaus.com.au>
|
|
* Quy Tonthat <quy@igelaus.com.au>
|
|
* B.J. Rossiter <bj@igelaus.com.au>
|
|
* Tony Tsui <tony@igelaus.com.au>
|
|
* L. David Baron <dbaron@dbaron.org>
|
|
* Tim Copperfield <timecop@network.email.ne.jp>
|
|
* Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
|
|
*
|
|
* 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 ***** */
|
|
|
|
#undef DEBUG_CURSORCACHE
|
|
|
|
#include "nsWidget.h"
|
|
#include "nsIServiceManager.h"
|
|
#include "nsAppShell.h"
|
|
|
|
#include <X11/Xatom.h>
|
|
#include <X11/cursorfont.h>
|
|
#include "nsXlibCursors.h"
|
|
|
|
#include "nsIEventListener.h"
|
|
#include "nsIMenuListener.h"
|
|
#include "nsIMouseListener.h"
|
|
#include "nsIRollupListener.h"
|
|
#include "nsGfxCIID.h"
|
|
#include "nsIMenuRollup.h"
|
|
#include "nsIRenderingContext.h"
|
|
#include "nsToolkit.h"
|
|
|
|
#include "xlibrgb.h"
|
|
|
|
static NS_DEFINE_CID(kRegionCID, NS_REGION_CID);
|
|
|
|
PRLogModuleInfo *XlibWidgetsLM = PR_NewLogModule("XlibWidgets");
|
|
PRLogModuleInfo *XlibScrollingLM = PR_NewLogModule("XlibScrolling");
|
|
|
|
// set up our static members here.
|
|
nsHashtable *nsWidget::gsWindowList = nsnull; // WEAK references to nsWidget*
|
|
|
|
// cursors hash table
|
|
Cursor nsWidget::gsXlibCursorCache[eCursorCount];
|
|
|
|
// this is for implemention the WM_PROTOCOL code
|
|
PRBool nsWidget::WMProtocolsInitialized = PR_FALSE;
|
|
Atom nsWidget::WMDeleteWindow = 0;
|
|
Atom nsWidget::WMTakeFocus = 0;
|
|
Atom nsWidget::WMSaveYourself = 0;
|
|
|
|
// this is the window that has the focus
|
|
Window nsWidget::mFocusWindow = 0;
|
|
|
|
// For popup handling
|
|
nsCOMPtr<nsIRollupListener> nsWidget::gRollupListener;
|
|
nsWeakPtr nsWidget::gRollupWidget;
|
|
PRBool nsWidget::gRollupConsumeRollupEvent = PR_FALSE;
|
|
|
|
class nsWindowKey : public nsHashKey {
|
|
protected:
|
|
Window mKey;
|
|
|
|
public:
|
|
nsWindowKey(Window key) {
|
|
mKey = key;
|
|
}
|
|
~nsWindowKey(void) {
|
|
}
|
|
PRUint32 HashCode(void) const {
|
|
return (PRUint32)mKey;
|
|
}
|
|
|
|
PRBool Equals(const nsHashKey *aKey) const {
|
|
return (mKey == ((nsWindowKey *)aKey)->mKey);
|
|
}
|
|
|
|
nsHashKey *Clone(void) const {
|
|
return new nsWindowKey(mKey);
|
|
}
|
|
};
|
|
|
|
nsWidget::nsWidget() // : nsBaseWidget()
|
|
{
|
|
mPreferredWidth = 0;
|
|
mPreferredHeight = 0;
|
|
|
|
mDisplay = 0;
|
|
mScreen = 0;
|
|
mVisual = 0;
|
|
mDepth = 0;
|
|
|
|
mBaseWindow = 0;
|
|
mBackground = NS_RGB(192, 192, 192);
|
|
mBorderRGB = NS_RGB(192, 192, 192);
|
|
/* |xxlib_find_handle(XXLIBRGB_DEFAULT_HANDLE)| would be the official
|
|
* way - but |nsAppShell::GetXlibRgbHandle()| one is little bit faster...*/
|
|
mXlibRgbHandle = nsAppShell::GetXlibRgbHandle();
|
|
mBackgroundPixel = xxlib_rgb_xpixel_from_rgb(mXlibRgbHandle, mBackground);
|
|
mBackground = NS_RGB(192, 192, 192);
|
|
mBorderPixel = xxlib_rgb_xpixel_from_rgb(mXlibRgbHandle, mBorderRGB);
|
|
mParentWidget = nsnull;
|
|
mName.AssignLiteral("unnamed");
|
|
mIsShown = PR_FALSE;
|
|
mIsToplevel = PR_FALSE;
|
|
mVisibility = VisibilityFullyObscured; // this is an X constant.
|
|
mWindowType = eWindowType_child;
|
|
mBorderStyle = eBorderStyle_default;
|
|
|
|
// added KenF
|
|
mIsDestroying = PR_FALSE;
|
|
mOnDestroyCalled = PR_FALSE;
|
|
mListenForResizes = PR_FALSE; // If we're native we need to listen.
|
|
mMapped = PR_FALSE;
|
|
|
|
|
|
mUpdateArea = do_CreateInstance(kRegionCID);
|
|
if (mUpdateArea) {
|
|
mUpdateArea->Init();
|
|
mUpdateArea->SetTo(0, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
// FIXME:
|
|
// Heavily modifying so functionally similar as gtk version. KenF
|
|
nsWidget::~nsWidget()
|
|
{
|
|
//mIsDestroying = TRUE;
|
|
|
|
if (mBaseWindow)
|
|
Destroy();
|
|
}
|
|
|
|
// Borrowed heavily from GTK. This should go through heirarchy of XWindow
|
|
// windows, and destroy the appropriate children.
|
|
// KenF
|
|
void
|
|
nsWidget::DestroyNativeChildren(Display *aDisplay, Window aWindow)
|
|
{
|
|
Window root_return;
|
|
Window parent_return;
|
|
Window *children_return = nsnull;
|
|
unsigned int nchildren_return = 0;
|
|
unsigned int i = 0;
|
|
|
|
XQueryTree(aDisplay, aWindow, &root_return, &parent_return,
|
|
&children_return, &nchildren_return);
|
|
// walk the list of children
|
|
for (i=0; i < nchildren_return; i++) {
|
|
nsWidget *thisWidget = GetWidgetForWindow(children_return[i]);
|
|
if (thisWidget) {
|
|
thisWidget->Destroy();
|
|
}
|
|
}
|
|
|
|
// free up this struct
|
|
if (children_return)
|
|
XFree(children_return);
|
|
}
|
|
|
|
void
|
|
nsWidget::DestroyNative()
|
|
{
|
|
NS_ASSERTION(mBaseWindow, "no native window");
|
|
|
|
// We have to destroy the children ourselves before we call XDestroyWindow
|
|
// because otherwise XDestroyWindow will destroy the windows and leave us
|
|
// with dangling references.
|
|
DestroyNativeChildren(mDisplay, mBaseWindow);
|
|
|
|
XDestroyWindow(mDisplay, mBaseWindow);
|
|
DeleteWindowCallback(mBaseWindow);
|
|
}
|
|
|
|
// Stub in nsWidget, real in nsWindow. KenF
|
|
void * nsWidget::CheckParent(long ThisWindow)
|
|
{
|
|
return (void*)-1;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::Create(nsIWidget *aParent,
|
|
const nsRect &aRect,
|
|
EVENT_CALLBACK aHandleEventFunction,
|
|
nsIDeviceContext *aContext,
|
|
nsIAppShell *aAppShell,
|
|
nsIToolkit *aToolkit,
|
|
nsWidgetInitData *aInitData)
|
|
{
|
|
// Do adding in SWC() KenF
|
|
//mParentWidget = aParent;
|
|
//NS_IF_ADDREF(mParentWidget); // KenF FIXME
|
|
|
|
return StandardWidgetCreate(aParent, aRect, aHandleEventFunction,
|
|
aContext, aAppShell, aToolkit, aInitData,
|
|
nsnull);
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::Create(nsNativeWidget aParent,
|
|
const nsRect &aRect,
|
|
EVENT_CALLBACK aHandleEventFunction,
|
|
nsIDeviceContext *aContext,
|
|
nsIAppShell *aAppShell,
|
|
nsIToolkit *aToolkit,
|
|
nsWidgetInitData *aInitData)
|
|
{
|
|
return(StandardWidgetCreate(nsnull, aRect, aHandleEventFunction,
|
|
aContext, aAppShell, aToolkit, aInitData,
|
|
aParent));
|
|
}
|
|
|
|
nsresult
|
|
nsWidget::StandardWidgetCreate(nsIWidget *aParent,
|
|
const nsRect &aRect,
|
|
EVENT_CALLBACK aHandleEventFunction,
|
|
nsIDeviceContext *aContext,
|
|
nsIAppShell *aAppShell,
|
|
nsIToolkit *aToolkit,
|
|
nsWidgetInitData *aInitData,
|
|
nsNativeWidget aNativeParent)
|
|
{
|
|
unsigned long attr_mask;
|
|
XSetWindowAttributes attr;
|
|
Window parent=nsnull;
|
|
|
|
NS_ASSERTION(!mBaseWindow, "already initialized");
|
|
if (mBaseWindow) return NS_ERROR_ALREADY_INITIALIZED;
|
|
|
|
mDisplay = xxlib_rgb_get_display(mXlibRgbHandle);
|
|
mScreen = xxlib_rgb_get_screen(mXlibRgbHandle);
|
|
mVisual = xxlib_rgb_get_visual(mXlibRgbHandle);
|
|
mDepth = xxlib_rgb_get_depth(mXlibRgbHandle);
|
|
|
|
mParentWidget = aParent;
|
|
|
|
NS_IF_ADDREF(mParentWidget);
|
|
|
|
mBounds = aRect;
|
|
|
|
if (mBounds.width <= 0)
|
|
mBounds.width = 1;
|
|
if (mBounds.height <= 0)
|
|
mBounds.height = 1;
|
|
|
|
BaseCreate(mParentWidget, mBounds, aHandleEventFunction, aContext,
|
|
aAppShell, aToolkit, aInitData);
|
|
|
|
if (aNativeParent) {
|
|
parent = (Window)aNativeParent;
|
|
mListenForResizes = PR_TRUE;
|
|
} else if (aParent) {
|
|
parent = (Window)aParent->GetNativeData(NS_NATIVE_WINDOW);
|
|
} else {
|
|
parent = XRootWindowOfScreen(mScreen);
|
|
}
|
|
|
|
if (nsnull != aInitData) {
|
|
mWindowType = aInitData->mWindowType;
|
|
}
|
|
|
|
mParentWindow = parent;
|
|
|
|
attr.bit_gravity = NorthWestGravity;
|
|
attr.event_mask = GetEventMask();
|
|
attr.colormap = xxlib_rgb_get_cmap(mXlibRgbHandle);
|
|
attr.background_pixel = mBackgroundPixel;
|
|
attr.border_pixel = mBorderPixel;
|
|
attr_mask = CWBitGravity | CWEventMask | CWBorderPixel | CWBackPixel;
|
|
|
|
if (attr.colormap)
|
|
attr_mask |= CWColormap;
|
|
|
|
switch (mWindowType) {
|
|
case eWindowType_dialog:
|
|
mIsToplevel = PR_TRUE;
|
|
parent = XRootWindowOfScreen(mScreen);
|
|
mBaseWindow = XCreateWindow(mDisplay, parent, mBounds.x, mBounds.y,
|
|
mBounds.width, mBounds.height, 0,
|
|
mDepth, InputOutput, mVisual,
|
|
attr_mask, &attr);
|
|
XSetWindowBackgroundPixmap(mDisplay, mBaseWindow, None);
|
|
AddWindowCallback(mBaseWindow, this);
|
|
SetUpWMHints();
|
|
XSetTransientForHint(mDisplay, mBaseWindow, mParentWindow);
|
|
break;
|
|
|
|
case eWindowType_popup:
|
|
mIsToplevel = PR_TRUE;
|
|
attr_mask |= CWOverrideRedirect | CWSaveUnder;
|
|
attr.save_under = True;
|
|
attr.override_redirect = True;
|
|
parent = XRootWindowOfScreen(mScreen);
|
|
mBaseWindow = XCreateWindow(mDisplay, parent,
|
|
mBounds.x, mBounds.y,
|
|
mBounds.width, mBounds.height, 0,
|
|
mDepth, InputOutput, mVisual,
|
|
attr_mask, &attr);
|
|
XSetWindowBackgroundPixmap(mDisplay, mBaseWindow, None);
|
|
AddWindowCallback(mBaseWindow, this);
|
|
SetUpWMHints();
|
|
XSetTransientForHint(mDisplay, mBaseWindow, mParentWindow);
|
|
break;
|
|
|
|
case eWindowType_toplevel:
|
|
case eWindowType_invisible:
|
|
mIsToplevel = PR_TRUE;
|
|
parent = XRootWindowOfScreen(mScreen);
|
|
mBaseWindow = XCreateWindow(mDisplay, parent, mBounds.x, mBounds.y,
|
|
mBounds.width, mBounds.height, 0,
|
|
mDepth, InputOutput, mVisual,
|
|
attr_mask, &attr);
|
|
XSetWindowBackgroundPixmap(mDisplay, mBaseWindow, None);
|
|
AddWindowCallback(mBaseWindow, this);
|
|
SetUpWMHints();
|
|
break;
|
|
|
|
case eWindowType_child:
|
|
mIsToplevel = PR_FALSE;
|
|
// for some reason I need to do this, as opposed to the other cases. FIXME
|
|
CreateNative(parent, mBounds);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
// FIXME: Being heavily modified so functionally similar to gtk version.
|
|
// (just a test) KenF
|
|
NS_IMETHODIMP nsWidget::Destroy()
|
|
{
|
|
|
|
// Dont reenter.
|
|
if (mIsDestroying)
|
|
return NS_OK;
|
|
|
|
mIsDestroying = PR_TRUE;
|
|
|
|
nsBaseWidget::Destroy();
|
|
NS_IF_RELEASE(mParentWidget); //????
|
|
|
|
|
|
if (mBaseWindow) {
|
|
DestroyNative();
|
|
//mBaseWindow = nsnull;
|
|
if (PR_FALSE == mOnDestroyCalled)
|
|
OnDestroy();
|
|
mBaseWindow = nsnull;
|
|
mEventCallback = nsnull;
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::ConstrainPosition(PRBool aAllowSlop,
|
|
PRInt32 *aX, PRInt32 *aY)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::Move(PRInt32 aX, PRInt32 aY)
|
|
{
|
|
//printf("nsWidget::Move aX=%i, aY=%i\n", aX, aY);
|
|
PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("nsWidget::Move(x, y)\n"));
|
|
PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("Moving window 0x%lx to %d, %d\n", mBaseWindow, aX, aY));
|
|
|
|
if((aX == mBounds.x) && (aY == mBounds.y) && !mIsToplevel) {
|
|
//printf("discard this move\n");
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
mBounds.x = aX;
|
|
mBounds.y = aY;
|
|
|
|
if (mWindowType == eWindowType_popup) {
|
|
nsRect aRect, transRect;
|
|
PRInt32 screenWidth = WidthOfScreen(mScreen);
|
|
PRInt32 screenHeight = HeightOfScreen(mScreen);
|
|
|
|
if (aX >= screenWidth)
|
|
aX = screenWidth - mBounds.width;
|
|
if (aY >= screenHeight)
|
|
aY = screenHeight - mBounds.height;
|
|
|
|
aRect.x = aX;
|
|
aRect.y = aY;
|
|
|
|
if (mParentWidget) {
|
|
mParentWidget->WidgetToScreen(aRect, transRect);
|
|
} else if (mParentWindow) {
|
|
Window child;
|
|
XTranslateCoordinates(mDisplay, mParentWindow,
|
|
XRootWindowOfScreen(mScreen),
|
|
aX, aY, &transRect.x, &transRect.y,
|
|
&child);
|
|
}
|
|
aX = transRect.x;
|
|
aY = transRect.y;
|
|
}
|
|
|
|
mRequestedSize.x = aX;
|
|
mRequestedSize.y = aY;
|
|
if (mParentWidget) {
|
|
((nsWidget*)mParentWidget)->WidgetMove(this);
|
|
} else {
|
|
/* Workaround for bug 77344. I am not sure whether this is mandatory or not. */
|
|
if (mDisplay)
|
|
XMoveWindow(mDisplay, mBaseWindow, aX, aY);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::Resize(PRInt32 aWidth,
|
|
PRInt32 aHeight,
|
|
PRBool aRepaint)
|
|
{
|
|
//printf("nsWidget::Resize aWidth=%i, Height=%i\n",aWidth, aHeight);
|
|
PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("nsWidget::Resize(width, height)\n"));
|
|
|
|
if (aWidth <= 0) {
|
|
PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("*** width is %d, fixing.\n", aWidth));
|
|
aWidth = 1;
|
|
|
|
}
|
|
if (aHeight <= 0) {
|
|
PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("*** height is %d, fixing.\n", aHeight));
|
|
aHeight = 1;
|
|
}
|
|
|
|
PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("Resizing window 0x%lx to %d, %d\n", mBaseWindow, aWidth, aHeight));
|
|
mRequestedSize.width = mBounds.width = aWidth;
|
|
mRequestedSize.height = mBounds.height = aHeight;
|
|
|
|
if (mParentWidget) {
|
|
((nsWidget *)mParentWidget)->WidgetResize(this);
|
|
} else {
|
|
/* Workaround for bug 77344. I am not sure whether this is mandatory or not. */
|
|
if (mDisplay)
|
|
XResizeWindow(mDisplay, mBaseWindow, aWidth, aHeight);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::Resize(PRInt32 aX,
|
|
PRInt32 aY,
|
|
PRInt32 aWidth,
|
|
PRInt32 aHeight,
|
|
PRBool aRepaint)
|
|
{
|
|
//printf("nsWidget::Resize aX=%i, aY=%i, aWidth=%i, aHeight=%i\n", aX, aY, aWidth, aHeight);
|
|
PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("nsWidget::Resize(x, y, width, height)\n"));
|
|
|
|
if (aWidth <= 0) {
|
|
PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("*** width is %d, fixing.\n", aWidth));
|
|
aWidth = 1;
|
|
}
|
|
if (aHeight <= 0) {
|
|
PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("*** height is %d, fixing.\n", aHeight));
|
|
aHeight = 1;
|
|
}
|
|
if (aX < 0) {
|
|
PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("*** x is %d, fixing.\n", aX));
|
|
aX = 0;
|
|
}
|
|
if (aY < 0) {
|
|
PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("*** y is %d, fixing.\n", aY));
|
|
aY = 0;
|
|
}
|
|
PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG,
|
|
("Resizing window 0x%lx to %d, %d\n", mBaseWindow, aWidth, aHeight));
|
|
PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG,
|
|
("Moving window 0x%lx to %d, %d\n", mBaseWindow, aX, aY));
|
|
mRequestedSize.x = aX;
|
|
mRequestedSize.y = aY;
|
|
mRequestedSize.width = mBounds.width = aWidth;
|
|
mRequestedSize.height = mBounds.height = aHeight;
|
|
if (mParentWidget) {
|
|
((nsWidget *)mParentWidget)->WidgetMoveResize(this);
|
|
} else {
|
|
XMoveResizeWindow(mDisplay, mBaseWindow, aX, aY, aWidth, aHeight);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::Enable(PRBool aState)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::IsEnabled(PRBool *aState)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aState);
|
|
*aState = PR_TRUE;
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::SetFocus(PRBool aRaise)
|
|
{
|
|
|
|
if (mBaseWindow) {
|
|
PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("nsWidget::SetFocus() setting focus to 0x%lx\n", mBaseWindow));
|
|
mFocusWindow = mBaseWindow;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::SetName(const char * aName)
|
|
{
|
|
mName.AssignWithConversion(aName);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
Window
|
|
nsWidget::GetFocusWindow(void)
|
|
{
|
|
return mFocusWindow;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::Invalidate(PRBool aIsSynchronous)
|
|
{
|
|
PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("nsWidget::Invalidate(sync)\n"));
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::Invalidate(const nsRect & aRect, PRBool aIsSynchronous)
|
|
{
|
|
PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("nsWidget::Invalidate(rect, sync)\n"));
|
|
return NS_OK;
|
|
}
|
|
|
|
nsIFontMetrics* nsWidget::GetFont(void)
|
|
{
|
|
return nsnull;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::GetPreferredSize(PRInt32& aWidth, PRInt32& aHeight)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::SetMenuBar(nsIMenuBar * aMenuBar)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::ShowMenuBar(PRBool aShow)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
void * nsWidget::GetNativeData(PRUint32 aDataType)
|
|
{
|
|
switch (aDataType) {
|
|
case NS_NATIVE_WIDGET:
|
|
case NS_NATIVE_WINDOW:
|
|
case NS_NATIVE_PLUGIN_PORT:
|
|
return (void *)mBaseWindow;
|
|
break;
|
|
case NS_NATIVE_DISPLAY:
|
|
return (void *)mDisplay;
|
|
break;
|
|
case NS_NATIVE_GRAPHIC:
|
|
NS_ASSERTION(nsnull != mToolkit, "NULL toolkit, unable to get a GC");
|
|
return (void *)NS_STATIC_CAST(nsToolkit*,mToolkit)->GetSharedGC();
|
|
break;
|
|
default:
|
|
fprintf(stderr, "nsWidget::GetNativeData(%d) called with crap value.\n",
|
|
aDataType);
|
|
return nsnull;
|
|
break;
|
|
}
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::SetTooltips(PRUint32 aNumberOfTips,
|
|
nsRect* aTooltipAreas[])
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::UpdateTooltips(nsRect* aNewTips[])
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::RemoveTooltips()
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::SetFont(const nsFont &aFont)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::BeginResizingChildren(void)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::EndResizingChildren(void)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::SetColorMap(nsColorMap *aColorMap)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::Show(PRBool bState)
|
|
{
|
|
PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("nsWidget::Show()\n"));
|
|
PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("state is %d\n", bState));
|
|
|
|
if (bState) {
|
|
Map();
|
|
} else {
|
|
Unmap();
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::IsVisible(PRBool &aState)
|
|
{
|
|
if (mVisibility != VisibilityFullyObscured) {
|
|
PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("nsWidget::IsVisible: yes\n"));
|
|
aState = PR_TRUE;
|
|
}
|
|
else {
|
|
PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("nsWidget::IsVisible: no\n"));
|
|
aState = PR_FALSE;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::SetPreferredSize(PRInt32 aWidth, PRInt32 aHeight)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::Update()
|
|
{
|
|
PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("nsWidget::Update()\n"));
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::SetBackgroundColor(const nscolor &aColor)
|
|
{
|
|
PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("nsWidget::SetBackgroundColor()\n"));
|
|
|
|
nsBaseWidget::SetBackgroundColor(aColor);
|
|
mBackgroundPixel = xxlib_rgb_xpixel_from_rgb(mXlibRgbHandle, mBackground);
|
|
// set the window attrib
|
|
XSetWindowBackground(mDisplay, mBaseWindow, mBackgroundPixel);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::Scroll(PRInt32 aDx, PRInt32 aDy, nsRect *aClipRect)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMPL_ISUPPORTS_INHERITED1(nsWidget, nsBaseWidget, nsISupportsWeakReference)
|
|
|
|
NS_IMETHODIMP nsWidget::WidgetToScreen(const nsRect& aOldRect,
|
|
nsRect& aNewRect)
|
|
{
|
|
Window child;
|
|
XTranslateCoordinates(mDisplay,
|
|
mBaseWindow,
|
|
XRootWindowOfScreen(mScreen),
|
|
aOldRect.x, aOldRect.y,
|
|
&aNewRect.x, &aNewRect.y,
|
|
&child);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::ScreenToWidget(const nsRect& aOldRect,
|
|
nsRect& aNewRect)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::SetCursor(nsCursor aCursor)
|
|
{
|
|
|
|
if (!mBaseWindow)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
/* don't bother setting if it it isnt mapped, duh */
|
|
if (!mMapped)
|
|
return NS_OK;
|
|
|
|
// Only change cursor if it's changing
|
|
if (aCursor != mCursor) {
|
|
Cursor newCursor = None;
|
|
|
|
newCursor = XlibCreateCursor(aCursor);
|
|
|
|
if (None != newCursor) {
|
|
mCursor = aCursor;
|
|
XDefineCursor(mDisplay, mBaseWindow, newCursor);
|
|
XFlush(mDisplay);
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::PreCreateWidget(nsWidgetInitData *aInitData)
|
|
{
|
|
if (nsnull != aInitData) {
|
|
SetWindowType(aInitData->mWindowType);
|
|
SetBorderStyle(aInitData->mBorderStyle);
|
|
|
|
return NS_OK;
|
|
}
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsIWidget *nsWidget::GetParent(void)
|
|
{
|
|
if (nsnull != mParentWidget) {
|
|
NS_ADDREF(mParentWidget);
|
|
}
|
|
return mParentWidget;
|
|
}
|
|
|
|
void nsWidget::CreateNative(Window aParent, nsRect aRect)
|
|
{
|
|
XSetWindowAttributes attr;
|
|
unsigned long attr_mask;
|
|
|
|
attr.bit_gravity = NorthWestGravity;
|
|
attr.event_mask = GetEventMask();
|
|
attr.colormap = xxlib_rgb_get_cmap(mXlibRgbHandle);
|
|
attr.background_pixel = mBackgroundPixel;
|
|
attr.border_pixel = mBorderPixel;
|
|
attr_mask = CWBitGravity | CWEventMask | CWBorderPixel | CWBackPixel;
|
|
|
|
if (attr.colormap)
|
|
attr_mask |= CWColormap;
|
|
|
|
CreateNativeWindow(aParent, mBounds, attr, attr_mask);
|
|
}
|
|
|
|
/* virtual */ long
|
|
nsWidget::GetEventMask()
|
|
{
|
|
long event_mask;
|
|
|
|
event_mask =
|
|
ButtonMotionMask |
|
|
Button1MotionMask |
|
|
ButtonPressMask |
|
|
ButtonReleaseMask |
|
|
EnterWindowMask |
|
|
ExposureMask |
|
|
KeyPressMask |
|
|
KeyReleaseMask |
|
|
LeaveWindowMask |
|
|
PointerMotionMask |
|
|
StructureNotifyMask |
|
|
VisibilityChangeMask |
|
|
FocusChangeMask |
|
|
OwnerGrabButtonMask;
|
|
|
|
return event_mask;
|
|
}
|
|
|
|
void nsWidget::CreateNativeWindow(Window aParent, nsRect aRect,
|
|
XSetWindowAttributes aAttr, unsigned long aMask)
|
|
{
|
|
NS_ASSERTION(!mBaseWindow, "already initialized");
|
|
if (mBaseWindow) return;
|
|
|
|
mBaseWindow = XCreateWindow(mDisplay,
|
|
aParent,
|
|
aRect.x, aRect.y,
|
|
aRect.width, aRect.height,
|
|
0, // border width
|
|
mDepth, // depth
|
|
InputOutput, // class
|
|
mVisual, // visual
|
|
aMask,
|
|
&aAttr);
|
|
XSetWindowBackgroundPixmap(mDisplay, mBaseWindow, None);
|
|
|
|
mRequestedSize.height = mBounds.height = aRect.height;
|
|
mRequestedSize.width = mBounds.width = aRect.width;
|
|
AddWindowCallback(mBaseWindow, this);
|
|
}
|
|
|
|
nsWidget *
|
|
nsWidget::GetWidgetForWindow(Window aWindow)
|
|
{
|
|
if (gsWindowList == nsnull) {
|
|
return nsnull;
|
|
}
|
|
nsWindowKey window_key(aWindow);
|
|
nsWidget *retval = (nsWidget *)gsWindowList->Get(&window_key);
|
|
return retval;
|
|
}
|
|
|
|
void
|
|
nsWidget::AddWindowCallback(Window aWindow, nsWidget *aWidget)
|
|
{
|
|
// make sure that the list has been initialized
|
|
if (gsWindowList == nsnull) {
|
|
gsWindowList = new nsHashtable();
|
|
}
|
|
nsWindowKey window_key(aWindow);
|
|
gsWindowList->Put(&window_key, aWidget);
|
|
}
|
|
|
|
void
|
|
nsWidget::DeleteWindowCallback(Window aWindow)
|
|
{
|
|
nsWindowKey window_key(aWindow);
|
|
gsWindowList->Remove(&window_key);
|
|
|
|
if (gsWindowList->Count() == 0) {
|
|
delete gsWindowList;
|
|
gsWindowList = nsnull;
|
|
|
|
/* clear out the cursor cache */
|
|
#ifdef DEBUG_CURSORCACHE
|
|
printf("freeing cursor cache\n");
|
|
#endif
|
|
for (int i = 0; i < eCursorCount; i++)
|
|
if (gsXlibCursorCache[i])
|
|
XFreeCursor(nsAppShell::mDisplay, gsXlibCursorCache[i]);
|
|
}
|
|
}
|
|
|
|
#undef TRACE_PAINT
|
|
#undef TRACE_PAINT_FLASH
|
|
|
|
#ifdef TRACE_PAINT_FLASH
|
|
#include "nsXUtils.h" // for nsXUtils::XFlashWindow()
|
|
#endif
|
|
|
|
PRBool
|
|
nsWidget::OnPaint(nsPaintEvent &event)
|
|
{
|
|
nsresult result = PR_FALSE;
|
|
if (mEventCallback) {
|
|
event.renderingContext = GetRenderingContext();
|
|
if (event.renderingContext) {
|
|
result = DispatchWindowEvent(event);
|
|
NS_RELEASE(event.renderingContext);
|
|
}
|
|
}
|
|
|
|
#ifdef TRACE_PAINT
|
|
static PRInt32 sPrintCount = 0;
|
|
|
|
if (event.rect)
|
|
{
|
|
printf("%4d nsWidget::OnPaint (this=%p,name=%s,xid=%p,rect=%d,%d,%d,%d)\n",
|
|
sPrintCount++,
|
|
(void *) this,
|
|
(const char *) nsCAutoString(mName),
|
|
(void *) mBaseWindow,
|
|
event.rect->x,
|
|
event.rect->y,
|
|
event.rect->width,
|
|
event.rect->height);
|
|
}
|
|
else
|
|
{
|
|
printf("%4d nsWidget::OnPaint (this=%p,name=%s,xid=%p,rect=none)\n",
|
|
sPrintCount++,
|
|
(void *) this,
|
|
(const char *) nsCAutoString(mName),
|
|
(void *) mBaseWindow);
|
|
}
|
|
#endif
|
|
|
|
#ifdef TRACE_PAINT_FLASH
|
|
XRectangle ar;
|
|
XRectangle * area = nsnull;
|
|
|
|
if (event.rect)
|
|
{
|
|
ar.x = event.rect->x;
|
|
ar.y = event.rect->y;
|
|
|
|
ar.width = event.rect->width;
|
|
ar.height = event.rect->height;
|
|
|
|
area = &ar;
|
|
}
|
|
|
|
nsXUtils::XFlashWindow(mDisplay,mBaseWindow,1,100000,area);
|
|
#endif
|
|
|
|
|
|
return result;
|
|
}
|
|
|
|
PRBool nsWidget::IsMouseInWindow(Window window, PRInt32 inMouseX, PRInt32 inMouseY)
|
|
{
|
|
XWindowAttributes inWindowAttributes;
|
|
|
|
/* sometimes we get NULL window */
|
|
if (!window)
|
|
return PR_FALSE;
|
|
|
|
/* Get the origin (top left corner) coordinate and window's size */
|
|
if (XGetWindowAttributes(mDisplay, window, &inWindowAttributes) == 0) {
|
|
fprintf(stderr, "Failed calling XGetWindowAttributes in nsWidget::IsMouseInWindow");
|
|
return PR_FALSE;
|
|
}
|
|
|
|
// Note: These coordinates are now relative to the root window as popups are now created
|
|
// with the root window as parent
|
|
|
|
// Must get mouse click coordinates relative to root window
|
|
int root_inMouse_x,
|
|
root_inMouse_y;
|
|
Window returnedChild;
|
|
Window rootWindow;
|
|
rootWindow = XRootWindow(mDisplay, XDefaultScreen(mDisplay));
|
|
if (!XTranslateCoordinates(mDisplay, mBaseWindow, rootWindow,
|
|
inMouseX, inMouseY,
|
|
&root_inMouse_x, &root_inMouse_y, &returnedChild)){
|
|
fprintf(stderr, "Could not get coordinates for origin coordinates for mouseclick\n");
|
|
// should we return true or false??????
|
|
return PR_FALSE;
|
|
}
|
|
//fprintf(stderr, "Here are the mouse click coordinates x:%i y%i\n", root_inMouse_x, root_inMouse_y);
|
|
|
|
// Test using coordinates relative to root window if click was inside passed popup window
|
|
if (root_inMouse_x > inWindowAttributes.x &&
|
|
root_inMouse_x < (inWindowAttributes.x + inWindowAttributes.width) &&
|
|
root_inMouse_y > inWindowAttributes.y &&
|
|
root_inMouse_y < (inWindowAttributes.y + inWindowAttributes.height)) {
|
|
#ifdef DEBUG_whoemeveraddedthatprintforginally
|
|
//fprintf(stderr, "Mouse click INSIDE passed popup\n");
|
|
#endif
|
|
return PR_TRUE;
|
|
}
|
|
|
|
#ifdef DEBUG_whoemeveraddedthatprintforginally
|
|
//fprintf(stderr, "Mouse click OUTSIDE of passed popup\n");
|
|
#endif
|
|
return PR_FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// HandlePopup
|
|
//
|
|
// Deal with rollup of popups (xpmenus, etc)
|
|
//
|
|
PRBool nsWidget::HandlePopup ( PRInt32 inMouseX, PRInt32 inMouseY )
|
|
{
|
|
PRBool retVal = PR_FALSE;
|
|
PRBool rollup = PR_FALSE;
|
|
|
|
// The gRollupListener and gRollupWidget are both set to nsnull when a popup is no
|
|
// longer visible
|
|
|
|
nsCOMPtr<nsIWidget> rollupWidget = do_QueryReferent(gRollupWidget);
|
|
|
|
if (rollupWidget && gRollupListener) {
|
|
Window currentPopup = (Window)rollupWidget->GetNativeData(NS_NATIVE_WINDOW);
|
|
|
|
if (!IsMouseInWindow(currentPopup, inMouseX, inMouseY)) {
|
|
rollup = PR_TRUE;
|
|
nsCOMPtr<nsIMenuRollup> menuRollup ( do_QueryInterface(gRollupListener) );
|
|
|
|
if ( menuRollup ) {
|
|
nsCOMPtr<nsISupportsArray> widgetChain;
|
|
menuRollup->GetSubmenuWidgetChain ( getter_AddRefs(widgetChain) );
|
|
if ( widgetChain ) {
|
|
PRUint32 count = 0;
|
|
widgetChain->Count ( &count );
|
|
for ( PRUint32 i = 0; i < count; ++i ) {
|
|
nsCOMPtr<nsISupports> genericWidget;
|
|
widgetChain->GetElementAt ( i, getter_AddRefs(genericWidget) );
|
|
nsCOMPtr<nsIWidget> widget ( do_QueryInterface(genericWidget) );
|
|
if ( widget ) {
|
|
Window currWindow = (Window)widget->GetNativeData(NS_NATIVE_WINDOW);
|
|
if ( IsMouseInWindow(currWindow, inMouseX, inMouseY) ) {
|
|
rollup = PR_FALSE;
|
|
break;
|
|
}
|
|
}
|
|
} // foreach parent menu widget
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (rollup) {
|
|
gRollupListener->Rollup();
|
|
retVal = PR_TRUE;
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
|
|
// Added KenF FIXME
|
|
void nsWidget::OnDestroy()
|
|
{
|
|
mOnDestroyCalled = PR_TRUE;
|
|
nsBaseWidget::OnDestroy();
|
|
|
|
// M14/GTK creates a widget which is called kungFuDeathGrip
|
|
// and assigns it "this". This might be because its making sure that this
|
|
// widget isn't destroyed? (still has a reference to it?)
|
|
// Check into it. FIXME KenF
|
|
DispatchDestroyEvent();
|
|
}
|
|
|
|
PRBool nsWidget::OnDeleteWindow(void)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("nsWidget::OnDeleteWindow()\n");
|
|
#endif /* DEBUUG */
|
|
nsBaseWidget::OnDestroy();
|
|
// emit a destroy signal
|
|
return DispatchDestroyEvent();
|
|
}
|
|
|
|
PRBool nsWidget::DispatchDestroyEvent(void) {
|
|
PRBool result = PR_FALSE;
|
|
if (nsnull != mEventCallback) {
|
|
nsGUIEvent event(PR_TRUE, NS_DESTROY, this);
|
|
AddRef();
|
|
result = DispatchWindowEvent(event);
|
|
Release();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
PRBool nsWidget::DispatchMouseEvent(nsMouseEvent& aEvent)
|
|
{
|
|
PRBool result = PR_FALSE;
|
|
if (nsnull == mEventCallback && nsnull == mMouseListener) {
|
|
return result;
|
|
}
|
|
|
|
/* If there was a mouse down event, check if any popups need to be notified */
|
|
switch (aEvent.message) {
|
|
case NS_MOUSE_LEFT_BUTTON_DOWN:
|
|
case NS_MOUSE_MIDDLE_BUTTON_DOWN:
|
|
case NS_MOUSE_RIGHT_BUTTON_DOWN:
|
|
if (HandlePopup(aEvent.point.x, aEvent.point.y)){
|
|
// Should we return here as GTK does?
|
|
return PR_TRUE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (nsnull != mEventCallback) {
|
|
result = DispatchWindowEvent(aEvent);
|
|
return result;
|
|
}
|
|
if (nsnull != mMouseListener) {
|
|
switch (aEvent.message) {
|
|
case NS_MOUSE_MOVE:
|
|
// XXX this isn't handled in gtk for some reason.
|
|
break;
|
|
case NS_MOUSE_LEFT_BUTTON_DOWN:
|
|
case NS_MOUSE_MIDDLE_BUTTON_DOWN:
|
|
case NS_MOUSE_RIGHT_BUTTON_DOWN:
|
|
result = ConvertStatus(mMouseListener->MousePressed(aEvent));
|
|
break;
|
|
case NS_MOUSE_LEFT_BUTTON_UP:
|
|
case NS_MOUSE_MIDDLE_BUTTON_UP:
|
|
case NS_MOUSE_RIGHT_BUTTON_UP:
|
|
result = ConvertStatus(mMouseListener->MouseReleased(aEvent));
|
|
result = ConvertStatus(mMouseListener->MouseClicked(aEvent));
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
PRBool
|
|
nsWidget::OnResize(nsSizeEvent &event)
|
|
{
|
|
mBounds.width = event.mWinWidth;
|
|
mBounds.height = event.mWinHeight;
|
|
|
|
nsresult result = PR_FALSE;
|
|
if (mEventCallback) {
|
|
result = DispatchWindowEvent(event);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
PRBool nsWidget::DispatchWindowEvent(nsGUIEvent & aEvent)
|
|
{
|
|
nsEventStatus status;
|
|
DispatchEvent(&aEvent, status);
|
|
return ConvertStatus(status);
|
|
}
|
|
|
|
PRBool nsWidget::DispatchKeyEvent(nsKeyEvent & aKeyEvent)
|
|
{
|
|
if (mEventCallback)
|
|
{
|
|
return DispatchWindowEvent(aKeyEvent);
|
|
}
|
|
|
|
return PR_FALSE;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
//
|
|
// Turning TRACE_EVENTS on will cause printfs for all
|
|
// mouse events that are dispatched.
|
|
//
|
|
// These are extra noisy, and thus have their own switch:
|
|
//
|
|
// NS_MOUSE_MOVE
|
|
// NS_PAINT
|
|
// NS_MOUSE_ENTER, NS_MOUSE_EXIT
|
|
//
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
#undef TRACE_EVENTS
|
|
#undef TRACE_EVENTS_MOTION
|
|
#undef TRACE_EVENTS_PAINT
|
|
#undef TRACE_EVENTS_CROSSING
|
|
#undef DEBUG
|
|
|
|
#ifdef DEBUG
|
|
void
|
|
nsWidget::DebugPrintEvent(nsGUIEvent & aEvent,
|
|
Window aWindow)
|
|
{
|
|
#ifndef TRACE_EVENTS_MOTION
|
|
if (aEvent.message == NS_MOUSE_MOVE)
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#ifndef TRACE_EVENTS_PAINT
|
|
if (aEvent.message == NS_PAINT)
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#ifndef TRACE_EVENTS_CROSSING
|
|
if (aEvent.message == NS_MOUSE_ENTER || aEvent.message == NS_MOUSE_EXIT)
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
static int sPrintCount=0;
|
|
|
|
nsCAutoString eventString;
|
|
eventString.AssignWithConversion(debug_GuiEventToString(&aEvent));
|
|
printf("%4d %-26s(this=%-8p , window=%-8p",
|
|
sPrintCount++,
|
|
(const char *) eventString,
|
|
(void *) this,
|
|
(void *) aWindow);
|
|
|
|
printf(" , x=%-3d, y=%d)",aEvent.point.x,aEvent.point.y);
|
|
|
|
printf("\n");
|
|
}
|
|
#endif // DEBUG
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
|
|
NS_IMETHODIMP nsWidget::DispatchEvent(nsGUIEvent * aEvent,
|
|
nsEventStatus &aStatus)
|
|
{
|
|
#ifdef TRACE_EVENTS
|
|
DebugPrintEvent(*aEvent,mBaseWindow);
|
|
#endif
|
|
|
|
NS_ADDREF(aEvent->widget);
|
|
|
|
if (nsnull != mMenuListener) {
|
|
if (NS_MENU_EVENT == aEvent->eventStructType)
|
|
aStatus = mMenuListener->MenuSelected(NS_STATIC_CAST(nsMenuEvent&, *aEvent));
|
|
}
|
|
|
|
aStatus = nsEventStatus_eIgnore;
|
|
if (nsnull != mEventCallback) {
|
|
aStatus = (*mEventCallback)(aEvent);
|
|
}
|
|
|
|
// Dispatch to event listener if event was not consumed
|
|
if ((aStatus != nsEventStatus_eIgnore) && (nsnull != mEventListener)) {
|
|
aStatus = mEventListener->ProcessEvent(*aEvent);
|
|
}
|
|
|
|
NS_IF_RELEASE(aEvent->widget);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
PRBool nsWidget::ConvertStatus(nsEventStatus aStatus)
|
|
{
|
|
switch(aStatus) {
|
|
case nsEventStatus_eIgnore:
|
|
return(PR_FALSE);
|
|
case nsEventStatus_eConsumeNoDefault:
|
|
return(PR_TRUE);
|
|
case nsEventStatus_eConsumeDoDefault:
|
|
return(PR_FALSE);
|
|
default:
|
|
NS_WARNING("Illegal nsEventStatus enumeration value\n");
|
|
break;
|
|
}
|
|
return(PR_FALSE);
|
|
}
|
|
|
|
void nsWidget::WidgetPut(nsWidget *aWidget)
|
|
{
|
|
}
|
|
|
|
void nsWidget::WidgetMove(nsWidget *aWidget)
|
|
{
|
|
PR_LOG(XlibScrollingLM, PR_LOG_DEBUG, ("nsWidget::WidgetMove()\n"));
|
|
XMoveWindow(aWidget->mDisplay, aWidget->mBaseWindow,
|
|
aWidget->mRequestedSize.x, aWidget->mRequestedSize.y);
|
|
}
|
|
|
|
void nsWidget::WidgetResize(nsWidget *aWidget)
|
|
{
|
|
PR_LOG(XlibScrollingLM, PR_LOG_DEBUG, ("nsWidget::WidgetResize()\n"));
|
|
XResizeWindow(aWidget->mDisplay, aWidget->mBaseWindow,
|
|
aWidget->mRequestedSize.width,
|
|
aWidget->mRequestedSize.height);
|
|
}
|
|
|
|
void nsWidget::WidgetMoveResize(nsWidget *aWidget)
|
|
{
|
|
PR_LOG(XlibScrollingLM, PR_LOG_DEBUG, ("nsWidget::WidgetMoveResize()\n"));
|
|
XMoveResizeWindow(aWidget->mDisplay,
|
|
aWidget->mBaseWindow,
|
|
aWidget->mRequestedSize.x,
|
|
aWidget->mRequestedSize.y,
|
|
aWidget->mRequestedSize.width,
|
|
aWidget->mRequestedSize.height);
|
|
}
|
|
|
|
void nsWidget::WidgetShow(nsWidget *aWidget)
|
|
{
|
|
aWidget->Map();
|
|
}
|
|
|
|
PRBool nsWidget::WidgetVisible(nsRect &aBounds)
|
|
{
|
|
nsRect scrollArea;
|
|
scrollArea.x = 0;
|
|
scrollArea.y = 0;
|
|
scrollArea.width = mRequestedSize.width + 1;
|
|
scrollArea.height = mRequestedSize.height + 1;
|
|
if (scrollArea.Intersects(aBounds)) {
|
|
PR_LOG(XlibScrollingLM, PR_LOG_DEBUG, ("nsWidget::WidgetVisible(): widget is visible\n"));
|
|
return PR_TRUE;
|
|
}
|
|
PR_LOG(XlibScrollingLM, PR_LOG_DEBUG, ("nsWidget::WidgetVisible(): widget is not visible\n"));
|
|
return PR_FALSE;
|
|
}
|
|
|
|
void nsWidget::Map(void)
|
|
{
|
|
if (!mMapped) {
|
|
/* Workaround for bug 77344. I am not sure whether this is mandatory or not. */
|
|
if (mDisplay)
|
|
XMapWindow(mDisplay, mBaseWindow);
|
|
mMapped = PR_TRUE;
|
|
}
|
|
}
|
|
|
|
void nsWidget::Unmap(void)
|
|
{
|
|
if (mMapped) {
|
|
/* Workaround for bug 77344. I am not sure whether this is mandatory or not. */
|
|
if (mDisplay)
|
|
XUnmapWindow(mDisplay, mBaseWindow);
|
|
mMapped = PR_FALSE;
|
|
}
|
|
}
|
|
|
|
void nsWidget::SetVisibility(int aState)
|
|
{
|
|
mVisibility = aState;
|
|
}
|
|
|
|
// create custom pixmap cursor from cursors in nsXlibCursors.h
|
|
Cursor nsWidget::XlibCreateCursor(nsCursor aCursorType)
|
|
{
|
|
Pixmap cursor = None;
|
|
Pixmap mask = None;
|
|
XColor fg, bg;
|
|
Cursor xcursor = None;
|
|
PRUint8 newType = 0xff;
|
|
|
|
fg.pixel = 0;
|
|
fg.red = 0;
|
|
fg.green = 0;
|
|
fg.blue = 0;
|
|
fg.flags = 0xf;
|
|
|
|
bg.pixel = 0xffffffff;
|
|
bg.red = 0xffff;
|
|
bg.green = 0xffff;
|
|
bg.blue = 0xffff;
|
|
bg.flags = 0xf;
|
|
|
|
/* lookup the cursor in cache */
|
|
if ((xcursor = gsXlibCursorCache[aCursorType])) {
|
|
#ifdef DEBUG_CURSORCACHE
|
|
printf("cached cursor found: %lx\n", xcursor);
|
|
#endif
|
|
return xcursor;
|
|
}
|
|
|
|
/* handle cursor type */
|
|
switch (aCursorType) {
|
|
case eCursor_select:
|
|
xcursor = XCreateFontCursor(mDisplay, XC_xterm);
|
|
break;
|
|
case eCursor_wait:
|
|
xcursor = XCreateFontCursor(mDisplay, XC_watch);
|
|
break;
|
|
case eCursor_hyperlink:
|
|
xcursor = XCreateFontCursor(mDisplay, XC_hand2);
|
|
break;
|
|
case eCursor_standard:
|
|
xcursor = XCreateFontCursor(mDisplay, XC_left_ptr);
|
|
break;
|
|
case eCursor_n_resize:
|
|
xcursor = XCreateFontCursor(mDisplay, XC_top_side);
|
|
break;
|
|
case eCursor_s_resize:
|
|
xcursor = XCreateFontCursor(mDisplay, XC_bottom_side);
|
|
break;
|
|
case eCursor_w_resize:
|
|
xcursor = XCreateFontCursor(mDisplay, XC_left_side);
|
|
break;
|
|
case eCursor_e_resize:
|
|
xcursor = XCreateFontCursor(mDisplay, XC_right_side);
|
|
break;
|
|
case eCursor_nw_resize:
|
|
xcursor = XCreateFontCursor(mDisplay, XC_top_left_corner);
|
|
break;
|
|
case eCursor_se_resize:
|
|
xcursor = XCreateFontCursor(mDisplay, XC_bottom_right_corner);
|
|
break;
|
|
case eCursor_ne_resize:
|
|
xcursor = XCreateFontCursor(mDisplay, XC_top_right_corner);
|
|
break;
|
|
case eCursor_sw_resize:
|
|
xcursor = XCreateFontCursor(mDisplay, XC_bottom_left_corner);
|
|
break;
|
|
case eCursor_crosshair:
|
|
xcursor = XCreateFontCursor(mDisplay, XC_crosshair);
|
|
break;
|
|
case eCursor_move:
|
|
xcursor = XCreateFontCursor(mDisplay, XC_fleur);
|
|
break;
|
|
case eCursor_help:
|
|
newType = XLIB_QUESTION_ARROW;
|
|
break;
|
|
case eCursor_copy:
|
|
newType = XLIB_COPY;
|
|
break;
|
|
case eCursor_alias:
|
|
newType = XLIB_ALIAS;
|
|
break;
|
|
case eCursor_context_menu:
|
|
newType = XLIB_CONTEXT_MENU;
|
|
break;
|
|
case eCursor_cell:
|
|
xcursor = XCreateFontCursor(mDisplay, XC_plus);
|
|
break;
|
|
case eCursor_grab:
|
|
newType = XLIB_HAND_GRAB;
|
|
break;
|
|
case eCursor_grabbing:
|
|
newType = XLIB_HAND_GRABBING;
|
|
break;
|
|
case eCursor_spinning:
|
|
newType = XLIB_SPINNING;
|
|
break;
|
|
case eCursor_zoom_in:
|
|
newType = XLIB_ZOOM_IN;
|
|
break;
|
|
case eCursor_zoom_out:
|
|
newType = XLIB_ZOOM_OUT;
|
|
break;
|
|
case eCursor_not_allowed:
|
|
case eCursor_no_drop:
|
|
newType = XLIB_NOT_ALLOWED;
|
|
break;
|
|
case eCursor_col_resize:
|
|
newType = XLIB_COL_RESIZE;
|
|
break;
|
|
case eCursor_row_resize:
|
|
newType = XLIB_ROW_RESIZE;
|
|
break;
|
|
case eCursor_vertical_text:
|
|
newType = XLIB_VERTICAL_TEXT;
|
|
break;
|
|
case eCursor_all_scroll:
|
|
xcursor = XCreateFontCursor(mDisplay, XC_fleur);
|
|
break;
|
|
case eCursor_nesw_resize:
|
|
newType = XLIB_NESW_RESIZE;
|
|
break;
|
|
case eCursor_nwse_resize:
|
|
newType = XLIB_NWSE_RESIZE;
|
|
break;
|
|
case eCursor_ns_resize:
|
|
xcursor = XCreateFontCursor(mDisplay, XC_sb_v_double_arrow);
|
|
break;
|
|
case eCursor_ew_resize:
|
|
xcursor = XCreateFontCursor(mDisplay, XC_sb_h_double_arrow);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* if by now we dont have a xcursor, this means we have to make a custom one */
|
|
if (!xcursor) {
|
|
NS_ASSERTION(newType != 0xff, "Unknown cursor type and no standard cursor");
|
|
|
|
/* we can use mBaseWindow for the pixmaps because SetCursor checks this
|
|
* before calling here */
|
|
cursor = XCreatePixmapFromBitmapData(mDisplay, mBaseWindow,
|
|
(char *)XlibCursors[newType].bits,
|
|
32, 32, 0xffffffff, 0x0, 1);
|
|
|
|
mask = XCreatePixmapFromBitmapData(mDisplay, mBaseWindow,
|
|
(char *)XlibCursors[newType].mask_bits,
|
|
32, 32, 0xffffffff, 0x0, 1);
|
|
|
|
xcursor = XCreatePixmapCursor(mDisplay, cursor, mask, &fg, &bg,
|
|
XlibCursors[newType].hot_x,
|
|
XlibCursors[newType].hot_y);
|
|
|
|
XFreePixmap(mDisplay, mask);
|
|
XFreePixmap(mDisplay, cursor);
|
|
}
|
|
|
|
#ifdef DEBUG_CURSORCACHE
|
|
printf("inserting cursor into the cache: %lx\n", xcursor);
|
|
#endif
|
|
gsXlibCursorCache[aCursorType] = xcursor;
|
|
|
|
return xcursor;
|
|
}
|
|
|
|
void
|
|
nsWidget::SetUpWMHints(void) {
|
|
// check to see if we need to get the atoms for the protocols
|
|
if (WMProtocolsInitialized == PR_FALSE) {
|
|
WMDeleteWindow = XInternAtom(mDisplay, "WM_DELETE_WINDOW", True);
|
|
WMTakeFocus = XInternAtom(mDisplay, "WM_TAKE_FOCUS", True);
|
|
WMSaveYourself = XInternAtom(mDisplay, "WM_SAVE_YOURSELF", True);
|
|
WMProtocolsInitialized = PR_TRUE;
|
|
}
|
|
Atom WMProtocols[2];
|
|
WMProtocols[0] = WMDeleteWindow;
|
|
WMProtocols[1] = WMTakeFocus;
|
|
// note that we only set two of the above protocols
|
|
PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("Setting up wm hints for window 0x%lx\n",
|
|
mBaseWindow));
|
|
XSetWMProtocols(mDisplay, mBaseWindow, WMProtocols, 2);
|
|
}
|
|
|
|
NS_METHOD nsWidget::SetBounds(const nsRect &aRect)
|
|
{
|
|
mRequestedSize = aRect;
|
|
return nsBaseWidget::SetBounds(aRect);
|
|
}
|
|
|
|
NS_METHOD nsWidget::GetRequestedBounds(nsRect &aRect)
|
|
{
|
|
aRect = mRequestedSize;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsWidget::SetTitle(const nsAString& title)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsWidget::CaptureRollupEvents(nsIRollupListener * aListener, PRBool aDoCapture, PRBool aConsumeRollupEvent)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|