mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-12 14:37:50 +00:00
7222 lines
229 KiB
C++
7222 lines
229 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "cxwin.h"
|
|
|
|
#include "cntritem.h"
|
|
#include "medit.h"
|
|
#include "button.h"
|
|
#include "fmbutton.h"
|
|
#include "gridedge.h"
|
|
#include "cxsave.h"
|
|
#include "netsvw.h"
|
|
#include "shcut.h"
|
|
#include "mainfrm.h"
|
|
#include "dialog.h"
|
|
#include "cxprint.h"
|
|
#include "findrepl.h"
|
|
#include "feembed.h"
|
|
#include "libevent.h"
|
|
#include "np.h"
|
|
#include "nppg.h"
|
|
#include "nppriv.h"
|
|
#include "winclose.h"
|
|
#include "tooltip.h"
|
|
#include "slavewnd.h"
|
|
|
|
#include "intl_csi.h"
|
|
#include "abdefn.h"
|
|
#include "feimage.h"
|
|
#include "edt.h"
|
|
extern char * EDT_NEW_DOC_URL;
|
|
extern char * EDT_NEW_DOC_NAME;
|
|
#define ED_SIZE_FEEDBACK_BORDER 3
|
|
|
|
#define EDT_IS_SIZING ( EDT_IS_EDITOR(GetContext()) && EDT_IsSizing(GetContext()) )
|
|
|
|
#ifdef JAVA
|
|
#include "np.h"
|
|
#include "java.h"
|
|
#include "prlog.h"
|
|
#ifdef DDRAW
|
|
static DDSURFACEDESC ddsd;
|
|
#endif
|
|
extern "C" {
|
|
#ifndef NSPR20
|
|
PR_LOG_DEFINE(APPLET);
|
|
#else
|
|
extern PRLogModuleInfo *APPLET;
|
|
#endif
|
|
|
|
/*
|
|
** API for querying the Navigator's Color Palette from the "outside"...
|
|
**
|
|
** This is used by AWT, when it is first started, to clone the navigator's
|
|
** color palette.
|
|
*/
|
|
PR_PUBLIC_API(HPALETTE) GET_APPLICATION_PALETTE(void)
|
|
{
|
|
HPALETTE hPal = (HPALETTE)NULL;
|
|
CWinCX *pActiveContext;
|
|
CGenericFrame *pFrame;
|
|
|
|
// XXX This is busted/need to move palette in frame -- Hokay?
|
|
pFrame = ((CNetscapeApp *)AfxGetApp())->m_pFrameList;
|
|
if( pFrame ) {
|
|
pActiveContext = pFrame->GetActiveWinContext();
|
|
if( pActiveContext ) {
|
|
hPal = pActiveContext->GetPalette();
|
|
}
|
|
}
|
|
return hPal;
|
|
}
|
|
};
|
|
#endif /* JAVA */
|
|
|
|
// older versions of MFC don't have this #define
|
|
#ifndef DEFAULT_GUI_FONT
|
|
#define DEFAULT_GUI_FONT ANSI_FIXED_FONT
|
|
#endif
|
|
|
|
#define NOT_A_DIALOG(wincx) \
|
|
((wincx) ? \
|
|
(wincx)->GetFrame() ? \
|
|
(wincx)->GetFrame()->GetMainContext() ? \
|
|
(wincx)->GetFrame()->GetMainContext()->GetContext() ? \
|
|
(wincx)->GetFrame()->GetMainContext()->GetContext()->type != MWContextDialog \
|
|
: TRUE : TRUE : TRUE : TRUE)
|
|
|
|
|
|
// An empty frame API so that this code will work without the presence of a frame window.
|
|
CNullFrame *CWinCX::m_pNullFrame = NULL;
|
|
void *CWinCX::m_pExitCookie = NULL;
|
|
|
|
void wincx_exit(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// ExitInstance, clean up if possible.
|
|
if(CWinCX::m_pNullFrame) {
|
|
delete CWinCX::m_pNullFrame;
|
|
CWinCX::m_pNullFrame = NULL;
|
|
}
|
|
if(CWinCX::m_pExitCookie) {
|
|
slavewnd.UnRegister(CWinCX::m_pExitCookie);
|
|
CWinCX::m_pExitCookie = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
CWinCX::CWinCX(CGenericDoc *pDocument, CFrameGlue *pFrame, CGenericView *pView, MWContextType mwType, ContextType cxType) : CPaneCX(pView ? pView->m_hWnd : NULL, FALSE) {
|
|
// Purpose: Construct a window context
|
|
// Arguments: pDocument The document, if NULL, one is created in CDCCX.
|
|
// It should be noted that this has to be a CNetscapeDoc
|
|
// currently, since it handles certain Ole aspects in
|
|
// the Netscape way.
|
|
// pFrame The frame which owns this view. Can be NULL (turns off
|
|
// any frame access).
|
|
// hView The view which this context interacts with. Can not be NULL.
|
|
// Returns: none
|
|
// Comments: Basically set the context type.
|
|
// Revision History:
|
|
// 06-25-95 created GAB
|
|
//
|
|
|
|
// Set the context type.
|
|
m_cxType = cxType;
|
|
GetContext()->type = mwType; // by default only.
|
|
|
|
m_pGenView = pView;
|
|
|
|
// No previous mouse event in this context.
|
|
m_LastMouseEvent = m_None;
|
|
m_bScrollingTimerSet = FALSE;
|
|
m_bMouseMoveTimerSet = FALSE;
|
|
// We start off thinking we have a border when a frame cell.
|
|
m_bHasBorder = TRUE;
|
|
|
|
m_MM = MM_TEXT;
|
|
|
|
// And the frame.
|
|
m_pFrame = pFrame;
|
|
pLastToolTipImg = 0;
|
|
m_pLastToolTipAnchor = NULL;
|
|
|
|
// Set up a callback in exit instance.
|
|
if(NULL == m_pExitCookie) {
|
|
m_pExitCookie = slavewnd.Register(SLAVE_EXITINSTANCE, wincx_exit);
|
|
}
|
|
// If there's no NULL frame yet, create one.
|
|
if(NULL == m_pNullFrame) {
|
|
m_pNullFrame = new CNullFrame;
|
|
}
|
|
|
|
// If there's no frame, use the Null Frame.
|
|
if(m_pFrame == NULL) {
|
|
TRACE("Using the NULL frame\n");
|
|
m_pFrame = m_pNullFrame;
|
|
}
|
|
|
|
// And the document.
|
|
m_pDocument = pDocument;
|
|
#ifdef DDRAW
|
|
m_ScrollWindow = FALSE;
|
|
m_physicWinRect.Empty();
|
|
#endif
|
|
// We're not active.
|
|
m_bActiveState = FALSE;
|
|
|
|
// We're not laying out.
|
|
m_bIsLayingOut = FALSE;
|
|
|
|
// We've not highlighted an anchor.
|
|
m_pLastArmedAnchor = NULL;
|
|
|
|
// No old progress;
|
|
m_lOldPercent = 0;
|
|
|
|
// not doing a drag/drop operation
|
|
m_bDragging = FALSE;
|
|
|
|
// No selected embedded item.
|
|
m_pSelected = NULL;
|
|
|
|
m_bSelectingCells = FALSE;
|
|
m_bInPopupMenu = FALSE;
|
|
|
|
// Inform the view of its new context.
|
|
if(m_pGenView) {
|
|
m_pGenView->SetContext(this);
|
|
}
|
|
|
|
/*__EDITOR__*/
|
|
m_bMouseInSelection = FALSE;
|
|
|
|
// We've not over an image.
|
|
m_pLastImageObject = NULL;
|
|
|
|
m_crWindowRect = CRect(0, 0, 0, 0);
|
|
|
|
// Mouse is up not down.
|
|
m_bLBDown = FALSE;
|
|
m_bLBUp = TRUE;
|
|
m_uMouseFlags = 0;
|
|
m_cpMMove.x = m_cpMMove.y = 0;
|
|
m_ToolTip = 0;
|
|
|
|
|
|
// size is not chrome specified yet.
|
|
m_bSizeIsChrome = FALSE;
|
|
|
|
// Clear those old elements that we will track in the
|
|
// loaded page (see FireMouseOverEvent....)
|
|
m_pLastOverAnchorData = NULL;
|
|
m_pLastOverElement = NULL;
|
|
m_pStartSelectionCell = NULL;
|
|
m_bLastOverTextSet = FALSE;
|
|
|
|
//#ifndef NO_TAB_NAVIGATION
|
|
m_lastTabFocus.pElement = NULL;
|
|
m_lastTabFocus.mapAreaIndex = 0; // 0 means no focus, start with index 1.
|
|
m_lastTabFocus.pAnchor = NULL;
|
|
m_isReEntry_setLastTabFocusElement = 0; // to provent re-entry
|
|
//#endif /* NO_TAB_NAVIGATION */
|
|
|
|
imageToolTip = NULL;
|
|
}
|
|
|
|
CWinCX::~CWinCX() {
|
|
// Purpose: Destroy a window context.
|
|
// Arguments: none
|
|
// Returns: none
|
|
// Comments: Does context instance specific cleanup.
|
|
// Revision History:
|
|
// 06-25-95 created GABby
|
|
//
|
|
|
|
MWContext *pContext = GetContext();
|
|
|
|
if(GetFrame() != NULL) {
|
|
GetFrame()->ClearContext(this);
|
|
}
|
|
|
|
if (m_ToolTip)
|
|
delete m_ToolTip;
|
|
|
|
XP_ListDestroy (imageToolTip);
|
|
|
|
// Netcaster going away
|
|
if (GetContext() == theApp.m_pNetcasterWindow)
|
|
theApp.m_pNetcasterWindow = NULL ;
|
|
}
|
|
|
|
#ifdef DDRAW
|
|
void CWinCX::CalcWinPos()
|
|
{
|
|
RECT tempRect1, tempRect2;
|
|
|
|
::GetWindowRect(GetPane(), &tempRect1);
|
|
::GetClientRect(GetPane(), &tempRect2);
|
|
|
|
int wWidth, cWidth;
|
|
int wHeight, cHeight;
|
|
int width, height;
|
|
|
|
wWidth = tempRect1.right - tempRect1.left;
|
|
cWidth = tempRect2.right - tempRect2.left;
|
|
width = wWidth - cWidth;
|
|
if (IsVScrollBarOn())
|
|
width -= sysInfo.m_iScrollWidth;
|
|
m_physicWinRect.left = tempRect1.left + (width / 2);
|
|
m_physicWinRect.right = tempRect1.right - (width / 2);
|
|
|
|
wHeight = tempRect1.bottom - tempRect1.top;
|
|
cHeight = tempRect2.bottom - tempRect2.top;
|
|
height = wHeight - cHeight;
|
|
if (IsHScrollBarOn())
|
|
height -= sysInfo.m_iScrollHeight;
|
|
m_physicWinRect.top = tempRect1.top + (height / 2);
|
|
m_physicWinRect.bottom = tempRect1.bottom - (width / 2);
|
|
|
|
}
|
|
#endif
|
|
|
|
void CWinCX::Initialize(BOOL bOwnDC, RECT *pRect, BOOL bInitialPalette, BOOL bNewMemDC) {
|
|
// Purpose: Initialize properties of this context.
|
|
// Arguments: void
|
|
// Returns: void
|
|
// Comments: Basically set up the iWidth and iHeight of the context.
|
|
// To be called after initial construction.
|
|
// Revision History:
|
|
// 06-25-95 created GABby
|
|
//
|
|
|
|
CPaneCX::Initialize(bOwnDC, pRect, bInitialPalette, bNewMemDC);
|
|
#ifdef DDRAW
|
|
m_lpDDSPrimary = NULL;
|
|
m_lpDDSBack = NULL;
|
|
mg_pPal = NULL;
|
|
m_pClipper = NULL;
|
|
m_pOffScreenClipper = NULL;
|
|
m_offScreenDC = 0;
|
|
m_lpDD = NULL;
|
|
/*
|
|
* create the main DirectDraw object
|
|
*/
|
|
if (DirectDrawCreate( NULL, &m_lpDD, NULL ) != DD_OK) {
|
|
m_lpDD->Release();
|
|
m_lpDD = NULL;
|
|
}
|
|
// initialize DirectDraw stuff.
|
|
if (m_lpDD && m_lpDD->SetCooperativeLevel( GetPane(), DDSCL_NORMAL )!= DD_OK) {
|
|
ReleaseDrawSurface();
|
|
}
|
|
if (m_lpDD) {
|
|
SetUseDibPalColors(FALSE);
|
|
// DDSURFACEDESC ddsd;
|
|
DDCAPS ddscaps, ddshel;
|
|
ZeroMemory((void*)&ddscaps, sizeof(DDCAPS));
|
|
// Create the primary surface with 1 back buffer
|
|
ddscaps.dwSize = sizeof( DDCAPS );
|
|
ZeroMemory((void*)&ddshel, sizeof(DDCAPS));
|
|
// Create the primary surface with 1 back buffer
|
|
ddshel.dwSize = sizeof( DDCAPS );
|
|
m_lpDD->GetCaps(&ddscaps, &ddshel);
|
|
|
|
ZeroMemory((void*)&ddsd, sizeof(DDSURFACEDESC));
|
|
// Create the primary surface with 1 back buffer
|
|
ddsd.dwSize = sizeof( ddsd );
|
|
ddsd.dwFlags = DDSD_CAPS;
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
|
|
if (m_lpDD->CreateSurface( &ddsd, &m_lpDDSPrimary, NULL ) != DD_OK) {
|
|
ReleaseDrawSurface();
|
|
}
|
|
else { // create Offscreen draw surface.
|
|
CreateAndLockOffscreenSurface(*pRect);
|
|
// now create the palette for direct draw surface.
|
|
if (m_lpDDSPrimary) {
|
|
ZeroMemory(&m_surfDesc, sizeof(ddsd));
|
|
m_surfDesc.dwSize = sizeof(ddsd);
|
|
|
|
m_surfDesc.dwFlags = DDSD_PIXELFORMAT;
|
|
m_lpDDSBack->GetSurfaceDesc(&m_surfDesc);
|
|
DDPIXELFORMAT pFormat;
|
|
m_lpDDSPrimary->GetPixelFormat(&pFormat);
|
|
// If this surface supports a palette, then do it
|
|
|
|
if (m_surfDesc.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
|
|
|
|
PALETTEENTRY palEntry[256];
|
|
::GetPaletteEntries(GetPalette(), 0, 255, palEntry);
|
|
if (m_lpDD->CreatePalette(DDPCAPS_8BIT, palEntry, &mg_pPal, NULL) != DD_OK) {
|
|
ReleaseDrawSurface();
|
|
}
|
|
else {
|
|
if (m_lpDDSPrimary->SetPalette(mg_pPal )!= DD_OK) {
|
|
ReleaseDrawSurface();
|
|
}
|
|
else {
|
|
m_lpDDSBack->SetPalette(mg_pPal );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Use a clipper object for clipping when in windowed mode
|
|
|
|
if (m_lpDD->CreateClipper(0, &m_pClipper, NULL) != DD_OK) {
|
|
ReleaseDrawSurface();
|
|
}
|
|
if (m_pClipper) {
|
|
if (m_pClipper->SetHWnd(0, GetPane()) != DD_OK) {
|
|
ReleaseDrawSurface();
|
|
}
|
|
else {
|
|
if (m_lpDDSPrimary->SetClipper(m_pClipper) != DD_OK) {
|
|
ReleaseDrawSurface();
|
|
}
|
|
}
|
|
}
|
|
if (m_lpDD->CreateClipper(0, &m_pOffScreenClipper, NULL) != DD_OK) {
|
|
ReleaseDrawSurface();
|
|
}
|
|
else {
|
|
if (m_lpDDSBack->SetClipper(m_pOffScreenClipper) != DD_OK) {
|
|
ReleaseDrawSurface();
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef DDRAW
|
|
void CWinCX::SetClipOnDrawSurface(LPDIRECTDRAWSURFACE surface, HRGN hClipRgn)
|
|
{
|
|
if (m_offScreenDC) {
|
|
if (hClipRgn == FE_NULL_REGION) {
|
|
::SelectClipRgn(m_offScreenDC, NULL);
|
|
}
|
|
else {
|
|
::SelectClipRgn(m_offScreenDC, hClipRgn);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CWinCX::RestoreAllDrawSurface()
|
|
{
|
|
#ifdef XP_WIN32
|
|
if( m_lpDDSPrimary->Restore() == DD_OK ) {
|
|
if (m_lpDDSBack->Restore() == DD_OK) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// if the surface can not be restore.
|
|
TRACE("There is something wrong with DirectDraw surface.\n");
|
|
ReleaseDrawSurface();
|
|
#endif
|
|
}
|
|
|
|
void CWinCX::ReleaseDrawSurface()
|
|
{
|
|
#ifdef XP_WIN32
|
|
if (m_offScreenDC) {
|
|
ReleaseOffscreenSurfDC();
|
|
m_offScreenDC = 0;
|
|
}
|
|
if (m_pOffScreenClipper) {
|
|
m_pOffScreenClipper->Release();
|
|
m_pOffScreenClipper = NULL;
|
|
}
|
|
if (m_pClipper) {
|
|
m_pClipper->Release();
|
|
m_pClipper = NULL;
|
|
}
|
|
if (m_lpDDSPrimary) {
|
|
m_lpDDSPrimary->Release();
|
|
m_lpDDSPrimary = NULL;
|
|
}
|
|
if (m_lpDDSBack) {
|
|
m_lpDDSBack->Release();
|
|
m_lpDDSBack = NULL;
|
|
}
|
|
if (mg_pPal) {
|
|
mg_pPal->Release();
|
|
mg_pPal = NULL;
|
|
}
|
|
if (m_lpDD) {
|
|
m_lpDD->Release();
|
|
m_lpDD = NULL;
|
|
}
|
|
HDC hdc = GetContextDC();
|
|
CDCCX::SetUseDibPalColors(!IsPrintContext() && (::GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE));
|
|
ReleaseContextDC(hdc);
|
|
#endif // WIN32
|
|
}
|
|
#endif // DDRAW
|
|
|
|
|
|
|
|
|
|
void CWinCX::ClearFrame() {
|
|
m_pFrame = NULL;
|
|
|
|
// Go through all our immediate children, clearing
|
|
// their frame.
|
|
// They will in turn call thier children, if present.
|
|
MWContext *pChild;
|
|
XP_List *pTraverse = GetContext()->grid_children;
|
|
while (pChild = (MWContext*)XP_ListNextObject(pTraverse)) {
|
|
WINCX(pChild)->ClearFrame();
|
|
}
|
|
}
|
|
// If we're a grid cell, we need to return the parent's palette.
|
|
HPALETTE CWinCX::GetPalette() const {
|
|
if(IsGridCell() == TRUE && GetParentContext() != NULL) {
|
|
ASSERT(ABSTRACTCX(GetParentContext())->IsWindowContext());
|
|
return(WINCX(GetParentContext())->GetPalette());
|
|
}
|
|
// Return the normal stuff.
|
|
return(CDCCX::GetPalette());
|
|
}
|
|
|
|
|
|
void CWinCX::DestroyContext() {
|
|
if(IsDestroyed() == FALSE) {
|
|
ResetToolTipImg();
|
|
|
|
// Deactivate any embedded items.
|
|
OnDeactivateEmbedCX();
|
|
|
|
// Release our modality if any is in effect.
|
|
POSITION rTraverse = m_cplModalOver.GetHeadPosition();
|
|
while(rTraverse) {
|
|
HWND hwndOwner;
|
|
|
|
// We stored the HWND of the window we're being modal over
|
|
// Retrieve it.
|
|
hwndOwner = (HWND)m_cplModalOver.GetNext(rTraverse);
|
|
if (::IsWindow(hwndOwner)) {
|
|
// Must make sure no one else thinks they are modal over the
|
|
// window before we go off and enable it.
|
|
int iTraverse = 1;
|
|
BOOL bEnable = TRUE;
|
|
MWContext *pMW = NULL;
|
|
XP_List *pTraverse = XP_GetGlobalContextList();
|
|
while (pMW = (MWContext *)XP_ListNextObject(pTraverse)) {
|
|
if(ABSTRACTCX(pMW) && ABSTRACTCX(pMW)->IsWindowContext()) {
|
|
CWinCX *pCX = WINCX(pMW);
|
|
if(this == pCX) {
|
|
// Exclude ourselves from the check.
|
|
continue;
|
|
}
|
|
POSITION rInsane = pCX->m_cplModalOver.GetHeadPosition();
|
|
HWND hCheck = NULL;
|
|
while(rInsane) {
|
|
hCheck = (HWND)pCX->m_cplModalOver.GetNext(rInsane);
|
|
if(hCheck == hwndOwner) {
|
|
// Someone else will enable it later.
|
|
bEnable = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if(FALSE == bEnable) {
|
|
// No need to continue if decided already.
|
|
break;
|
|
}
|
|
}
|
|
if(bEnable) {
|
|
::EnableWindow(hwndOwner, TRUE);
|
|
}
|
|
}
|
|
}
|
|
m_cplModalOver.RemoveAll();
|
|
|
|
// Perform our close callbacks.
|
|
if(!m_cplCloseCallbacks.IsEmpty()) {
|
|
POSITION rFuncs = m_cplCloseCallbacks.GetHeadPosition();
|
|
POSITION rArgs = m_cplCloseCallbackArgs.GetHeadPosition();
|
|
void (*pCloseCallback)(void *) = NULL;
|
|
void *pCloseCallbackArg = NULL;
|
|
|
|
while(rFuncs) {
|
|
pCloseCallback = (void (*)(void *))m_cplCloseCallbacks.GetNext(rFuncs);
|
|
pCloseCallbackArg = m_cplCloseCallbackArgs.GetNext(rArgs);
|
|
|
|
if(pCloseCallback != NULL) {
|
|
pCloseCallback(pCloseCallbackArg);
|
|
}
|
|
}
|
|
|
|
m_cplCloseCallbacks.RemoveAll();
|
|
m_cplCloseCallbackArgs.RemoveAll();
|
|
}
|
|
|
|
MWContext *pContext = GetContext();
|
|
|
|
//JavaScript has lifetime-linked windows which must close now too
|
|
if (pContext->js_dependent_list) {
|
|
MWContext *pDepContext;
|
|
XP_List *pTraverse = pContext->js_dependent_list;
|
|
while (pDepContext = (MWContext *)XP_ListNextObject(pTraverse)) {
|
|
pDepContext->js_parent = 0;
|
|
FE_DestroyWindow(pDepContext);
|
|
}
|
|
XP_ListDestroy(pContext->js_dependent_list);
|
|
pContext->js_dependent_list = NULL;
|
|
}
|
|
if (pContext->js_parent) {
|
|
if (XP_ListCount(pContext->js_parent->js_dependent_list) == 1) {
|
|
XP_ListDestroy(pContext->js_parent->js_dependent_list);
|
|
pContext->js_parent->js_dependent_list=NULL;
|
|
}
|
|
else {
|
|
XP_ListRemoveObject(pContext->js_parent->js_dependent_list, pContext);
|
|
}
|
|
|
|
}
|
|
|
|
// Call the base. This will delete the object !!
|
|
// To make sure that m_pPal is not being selected to a dc
|
|
HDC hdc = GetContextDC();
|
|
::SelectPalette(hdc, (HPALETTE)::GetStockObject(DEFAULT_PALETTE), FALSE);
|
|
// Get rid of the home grown DC that we created.
|
|
if(GetPane() != NULL) {
|
|
#ifdef DDRAW
|
|
ReleaseDrawSurface();
|
|
#endif
|
|
ReleaseContextDC(hdc);
|
|
}
|
|
#ifdef JAVA
|
|
//
|
|
// Discard the events pending for the context...
|
|
//
|
|
LJ_DiscardEventsForContext(pContext);
|
|
#endif /* JAVA */
|
|
}
|
|
|
|
|
|
CPaneCX::DestroyContext();
|
|
|
|
}
|
|
|
|
|
|
void CWinCX::OnDeactivateEmbedCX() {
|
|
CGenericView *pView = GetView();
|
|
if(pView != NULL && m_pSelected != NULL) {
|
|
// Obtain the plugin structure.
|
|
NPEmbeddedApp *pPluginShim = (NPEmbeddedApp *)m_pSelected->FE_Data;
|
|
// Make sure it is not a plugin, but an OLE container item.
|
|
if(pPluginShim != NULL && wfe_IsTypePlugin(pPluginShim) == FALSE) {
|
|
// Get the container item, and deactivate it.
|
|
CNetscapeCntrItem *pItem = (CNetscapeCntrItem *)pPluginShim->fe_data;
|
|
if(pItem != NULL && pItem->IsInPlaceActive() == TRUE) {
|
|
TRY {
|
|
pItem->Deactivate();
|
|
|
|
}
|
|
CATCH(CException, e) {
|
|
// Something went wrong in OLE (other app down).
|
|
// No complicated handling here, just keep running.
|
|
}
|
|
END_CATCH
|
|
}
|
|
}
|
|
// Clear that nothing is currently selected.
|
|
m_pSelected = NULL;
|
|
}
|
|
}
|
|
|
|
#ifdef EDITOR
|
|
void CWinCX::Scroll(int iBars, UINT uSBCode, UINT uPos, HWND hCtrl, UINT uTimes)
|
|
{
|
|
int32 lOldOrgY = GetOriginY();
|
|
int32 lOldOrgX = GetOriginX();
|
|
|
|
CPaneCX::Scroll(iBars, uSBCode, uPos, hCtrl, uTimes);
|
|
|
|
if(lOldOrgY != GetOriginY() || lOldOrgX != GetOriginX()) {
|
|
if( EDT_IS_EDITOR(GetContext()) ){
|
|
EDT_WindowScrolled( GetContext() );
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef DDRAW
|
|
void CWinCX::ScrollWindow(int x, int y)
|
|
{
|
|
RECT source, dest;
|
|
dest.top = m_physicWinRect.top;
|
|
dest.bottom = m_physicWinRect.bottom;
|
|
dest.left = m_physicWinRect.left;
|
|
dest.right = m_physicWinRect.right;
|
|
source.top = m_physicWinRect.top;
|
|
source.bottom = m_physicWinRect.bottom;
|
|
source.left = m_physicWinRect.left;
|
|
source.right = m_physicWinRect.right;
|
|
RECT updateRect;
|
|
updateRect.top = m_physicWinRect.top;
|
|
updateRect.bottom = m_physicWinRect.bottom;
|
|
updateRect.left = m_physicWinRect.left;
|
|
updateRect.right = m_physicWinRect.right;
|
|
|
|
if (y == 0) { // scrolling horz
|
|
if (x > 0) {// scroll right.
|
|
dest.left += x;
|
|
source.right -= x;
|
|
}
|
|
else {
|
|
dest.right += x;
|
|
source.left -= x;
|
|
}
|
|
if (m_physicWinRect.left == dest.left) {
|
|
updateRect.left = dest.right;
|
|
}
|
|
else
|
|
updateRect.left = m_physicWinRect.left;
|
|
updateRect.right = updateRect.left + abs(x);
|
|
}
|
|
else if (x == 0) { // scroll vert.
|
|
if (y > 0) {// scroll down.
|
|
dest.top += y;
|
|
source.bottom -= y;
|
|
}
|
|
else {
|
|
dest.bottom += y;
|
|
source.top -= y;
|
|
}
|
|
if (m_physicWinRect.top == dest.top) {
|
|
updateRect.top = dest.bottom;
|
|
}
|
|
else
|
|
updateRect.top = m_physicWinRect.top;
|
|
updateRect.bottom = updateRect.top + abs(y);
|
|
}
|
|
if (y < 0 || x < 0) {
|
|
if(IsVScrollBarOn() ) {
|
|
updateRect.left -= sysInfo.m_iScrollWidth;
|
|
updateRect.right -= sysInfo.m_iScrollWidth;
|
|
}
|
|
if(IsHScrollBarOn()) {
|
|
updateRect.top -= sysInfo.m_iScrollWidth;
|
|
updateRect.bottom -= sysInfo.m_iScrollWidth;
|
|
}
|
|
}
|
|
::OffsetRect(&updateRect, -GetWindowsXPos(), -GetWindowsYPos());
|
|
HRESULT err = m_lpDDSBack->ReleaseDC(m_offScreenDC);
|
|
::OffsetRect(&dest, -GetWindowsXPos(), -GetWindowsYPos());
|
|
err = m_lpDDSBack->Blt(&dest, m_lpDDSPrimary, &source, DDBLT_WAIT, NULL);
|
|
if (err == DDERR_SURFACELOST) {
|
|
RestoreAllDrawSurface();
|
|
err = m_lpDDSBack->Blt(&dest, m_lpDDSPrimary, &source, DDBLT_WAIT, NULL);
|
|
}
|
|
m_lpDDSBack->GetDC(&m_offScreenDC);
|
|
|
|
m_ScrollWindow = TRUE;
|
|
#ifdef DEBUG_mhwang
|
|
TRACE("Scroll Window\n");
|
|
#endif
|
|
m_pAlternateDC = m_offScreenDC;
|
|
RefreshArea(m_offScreenDC, updateRect.left + m_lOrgX, updateRect.top + m_lOrgY,
|
|
updateRect.right - updateRect.left,
|
|
updateRect.bottom - updateRect.top);
|
|
RECT prcUpdate;
|
|
// ::ScrollWindowEx(GetPane(), x, (int) y, NULL, NULL, NULL, &prcUpdate, SW_SCROLLCHILDREN);
|
|
if (m_lpDDSPrimary ) {
|
|
LTRB rect(m_physicWinRect);
|
|
rect.left -= GetWindowsXPos();
|
|
rect.right -= GetWindowsXPos();
|
|
rect.top -= GetWindowsYPos();
|
|
rect.bottom -= GetWindowsYPos();
|
|
FE_Region hCurClip = GetDrawingClip();
|
|
HDC hdc;
|
|
m_lpDDSPrimary->GetDC(&hdc);
|
|
::SelectClipRgn(hdc, NULL);
|
|
m_lpDDSPrimary->ReleaseDC(hdc);
|
|
BltToScreen(rect, NULL);
|
|
}
|
|
m_pAlternateDC = 0;
|
|
m_ScrollWindow = FALSE;
|
|
}
|
|
#endif
|
|
// This function get's called when the window moves around.
|
|
void CWinCX::OnMoveCX() {
|
|
// WARNING:m_crWindowRect will be invalid until next AftWMSize!
|
|
|
|
// Go through all our immediate children, telling them their screen location
|
|
// has changed.
|
|
// They will in turn call thier children, if present.
|
|
MWContext *pChild;
|
|
XP_List *pTraverse = GetContext()->grid_children;
|
|
while (pChild = (MWContext*)XP_ListNextObject(pTraverse)) {
|
|
WINCX(pChild)->OnMoveCX();
|
|
}
|
|
JSEvent *event;
|
|
event = XP_NEW_ZAP(JSEvent);
|
|
event->type = EVENT_MOVE;
|
|
|
|
CFrameWnd *pFWnd = GetFrame()->GetFrameWnd();
|
|
if(pFWnd) {
|
|
CRect crFrame;
|
|
pFWnd->GetWindowRect(crFrame);
|
|
event->x = (int32)crFrame.left;
|
|
event->y = (int32)crFrame.top;
|
|
event->screenx = (int32)crFrame.left;
|
|
event->screeny = (int32)crFrame.top;
|
|
ET_SendEvent(GetContext(), 0, event,
|
|
0, 0);
|
|
}
|
|
#ifdef DDRAW
|
|
CalcWinPos();
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
wfe_ResizeFullPagePlugin(MWContext* pContext, int32 lWidth, int32 lHeight)
|
|
{
|
|
ASSERT(pContext);
|
|
NPWindow* npWindow = pContext->pluginList->wdata;
|
|
|
|
ASSERT(npWindow);
|
|
if (npWindow) {
|
|
npWindow->width = lWidth;
|
|
npWindow->height = lHeight;
|
|
::SetWindowPos((HWND)npWindow->window,
|
|
NULL,
|
|
0,
|
|
0,
|
|
(int)npWindow->width,
|
|
(int)npWindow->height,
|
|
SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
|
|
NPL_EmbedSize(pContext->pluginList);
|
|
}
|
|
}
|
|
|
|
#ifdef DDRAW
|
|
void CWinCX::CreateAndLockOffscreenSurface(RECT& rect)
|
|
{
|
|
// create new offscreen surface.
|
|
if (m_lpDDSPrimary) {
|
|
if (m_lpDDSBack) {
|
|
m_lpDDSBack->ReleaseDC(m_offScreenDC);
|
|
m_offScreenDC = 0;
|
|
m_lpDDSBack->Release();
|
|
}
|
|
m_lpDDSBack = CreateOffscreenSurface(rect);
|
|
RestoreAllDrawSurface();
|
|
if (m_lpDDSBack)
|
|
m_lpDDSBack->GetDC(&m_offScreenDC);
|
|
}
|
|
}
|
|
|
|
LPDIRECTDRAWSURFACE CWinCX::CreateOffscreenSurface(RECT& rect)
|
|
{
|
|
LPDIRECTDRAWSURFACE retval;
|
|
// create new offscreen surface.
|
|
ZeroMemory((void*)&ddsd, sizeof(DDSURFACEDESC));
|
|
ddsd.dwSize = sizeof( ddsd );
|
|
// Create a offscreen bitmap.
|
|
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
|
|
ddsd.dwHeight = rect.bottom - rect.top;
|
|
ddsd.dwWidth = rect.right - rect.left;
|
|
if (m_lpDD->CreateSurface( &ddsd, &retval, NULL )!=DD_OK) {
|
|
ReleaseDrawSurface();
|
|
return NULL;
|
|
}
|
|
else
|
|
return retval;
|
|
}
|
|
#endif
|
|
|
|
void CWinCX::AftWMSize(PaneMessage *pMessage)
|
|
{
|
|
// Purpose: Informs the context that the size of the displayable area has changed.
|
|
// Arguments: As OnSize in MFC
|
|
// Returns: void
|
|
// Comments: Pretty much handles every want of a resizeable window.
|
|
// Revision History:
|
|
// 07-13-95 created GABby
|
|
//
|
|
|
|
// Call the base.
|
|
// Preserve old size for logic in this function.
|
|
int32 lOldWidth = GetWidth();
|
|
int32 lOldHeight = GetHeight();
|
|
CPaneCX::AftWMSize(pMessage);
|
|
|
|
UINT uType = (UINT)pMessage->wParam;
|
|
int iX = LOWORD(pMessage->lParam);
|
|
int iY = HIWORD(pMessage->lParam);
|
|
|
|
// Wether or not we should call NiceReload before we return from this function.
|
|
// We stall the call, as we need to update all of our state size variables
|
|
// before we start a load which may depend upon these state variables
|
|
// to be correct for display purposes and for turning on and off scroll
|
|
// bars etc.
|
|
BOOL bNiceReload = FALSE;
|
|
|
|
// Block flailing random message we receive when a new browser
|
|
// window is opened and we're minimized.
|
|
if(GetFrame() && GetFrame()->GetFrameWnd() &&
|
|
GetFrame()->GetFrameWnd()->IsIconic() &&
|
|
uType == 0 && iX == 0 && iY == 0) {
|
|
// Stop the stupid windows behavior.
|
|
return;
|
|
}
|
|
|
|
// There is no window.
|
|
if(!GetPane() )
|
|
return;
|
|
|
|
// Update our idea of where we exist.
|
|
CRect crNewRect(0, 0, 0, 0);
|
|
::GetWindowRect(GetPane(), crNewRect);
|
|
|
|
#ifdef DDRAW
|
|
// create new offscreen surface.
|
|
if (m_lpDDSPrimary) {
|
|
CreateAndLockOffscreenSurface(crNewRect);
|
|
}
|
|
|
|
// mwh - reset our windows's screen position. so it will be calcuate
|
|
// in DisplayPixmap again.
|
|
m_physicWinRect.Empty();
|
|
#endif
|
|
if(IsGridCell() && !m_crWindowRect.EqualRect(crNewRect)) {
|
|
// NCAPI sizing support.
|
|
CWindowChangeItem::Sizing(GetContextID(), crNewRect.left, crNewRect.top, crNewRect.Width(), crNewRect.Height());
|
|
}
|
|
|
|
// Don't do this on anything but restoration and maximization.
|
|
// We don't care if we're minimized.
|
|
if(uType != SIZE_MAXIMIZED && uType != SIZE_RESTORED) {
|
|
TRACE("Don't handle size messages of type %u\n", uType);
|
|
return;
|
|
}
|
|
|
|
// Update what our document thinks if In Place.
|
|
if(GetDocument() && GetDocument()->IsInPlaceActive() && GetPane()) {
|
|
int32 lIPWidth = Twips2MetricX(iX);
|
|
int32 lIPHeight = Twips2MetricY(iY);
|
|
|
|
// quasi-hack alert.
|
|
// When the scroll bars are on, our twips to metrics conversions
|
|
// are off by 1 pixel in the direction of the scroller.
|
|
// Adjust.
|
|
// This seems reverse logic, but is correct (horiz scroll bar
|
|
// shortens height of window when present).
|
|
if(IsHScrollBarOn()) {
|
|
lIPHeight -= Twips2MetricX(1);
|
|
}
|
|
if(IsVScrollBarOn()) {
|
|
lIPWidth -= Twips2MetricY(1);
|
|
}
|
|
|
|
GetDocument()->m_csViewExtent = CSize(CASTINT(lIPWidth), CASTINT(lIPHeight));
|
|
TRACE("InPlace Document extents now %ld,%ld\n", lIPWidth, lIPHeight);
|
|
}
|
|
|
|
CGenericView *pView = GetView();
|
|
ASSERT(pView);
|
|
|
|
// We can never allow resize when there are frame cells and we are in
|
|
// print preview. The print preview state holds a pointer to
|
|
// one of the views in the frameset. Once print preview is
|
|
// completed, the code will attempt to set that view to be the
|
|
// active view. If deleted (as from a reload/resize), then we crash.
|
|
// Also, if only the Y value changed, then just adjust the iHeight.
|
|
// This doesn't apply to grid parents OR Composer, as they need to reload in
|
|
// all resize cases.
|
|
if( !EDT_IS_EDITOR(GetContext()) &&
|
|
((IsGridParent() && pView->IsInPrintPreview()) ||
|
|
(GetWidth() == lOldWidth && IsGridParent() == FALSE))
|
|
) {
|
|
if(ContainsFullPagePlugin()) {
|
|
wfe_ResizeFullPagePlugin(GetContext(), GetWidth(), GetHeight());
|
|
}
|
|
|
|
{
|
|
MWContext *context = GetContext();
|
|
|
|
/* Mark the entire window dirty and force the compositor to composite now for
|
|
the case when the user resizes the top or bottom edge of the window.
|
|
This can be a potential performance problem!. Be careful.
|
|
*/
|
|
if (context->compositor && GetHeight() != lOldHeight)
|
|
{
|
|
CL_Compositor *compositor = context->compositor;
|
|
XP_Rect rect;
|
|
CL_OffscreenMode save_offscreen_mode;
|
|
|
|
rect.left = 0;
|
|
rect.top = 0;
|
|
rect.right = GetWidth();
|
|
rect.bottom = GetHeight();
|
|
CL_UpdateDocumentRect(compositor,
|
|
&rect, (PRBool)FALSE);
|
|
|
|
/* Temporarily force drawing to use the offscreen buffering area to reduce
|
|
flicker when resizing. (If no offscreen store is allocated, this code will
|
|
have no effect, but it will do no harm.) */
|
|
save_offscreen_mode = CL_GetCompositorOffscreenDrawing(compositor);
|
|
CL_SetCompositorOffscreenDrawing(compositor, CL_OFFSCREEN_ENABLED);
|
|
CL_CompositeNow(compositor);
|
|
CL_SetCompositorOffscreenDrawing(compositor, save_offscreen_mode);
|
|
|
|
/* Call Win32 API call to validate entire windows so that the WM_PAINT message
|
|
that follows a resize does not force a repaint of the window. The repaint
|
|
happens via the compositor in the CL_UpdateDocumentRect call above */
|
|
::ValidateRect( GetPane(), NULL );
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// Check the history to see if what we have is a binary image,
|
|
// or if this is a view-source URL.
|
|
// Don't reload if this is the case.
|
|
History_entry *pEntry = SHIST_GetCurrent(&(GetContext()->hist));
|
|
if(pEntry != NULL &&
|
|
(pEntry->is_binary ||
|
|
(pEntry->address && 0 == strncmp(pEntry->address, "view-source:", 12)))) {
|
|
if(ContainsFullPagePlugin()) {
|
|
// There can be only one plugin if it is full page
|
|
wfe_ResizeFullPagePlugin(GetContext(), GetWidth(), GetHeight());
|
|
}
|
|
return;
|
|
}
|
|
// Have any embedded items update.
|
|
CNetscapeCntrItem *pItem = (CNetscapeCntrItem *)GetDocument()->GetInPlaceActiveItem(pView);
|
|
if(pItem != NULL) {
|
|
pItem->SetItemRects();
|
|
}
|
|
|
|
#ifdef EDITOR
|
|
if( EDT_IS_EDITOR(GetContext()) ){
|
|
EDT_RefreshLayout( GetContext() );
|
|
}
|
|
else
|
|
#endif // EDITOR
|
|
{
|
|
// If this is edit_view_source, then we can't reload because the
|
|
// data didn't come from an acutal URL
|
|
if( !GetContext()->edit_view_source_hack ){
|
|
// Reload, we need to relayout everything to the new dimenstions.
|
|
if(m_crWindowRect.Width() != crNewRect.Width() ||
|
|
m_crWindowRect.Height() != crNewRect.Height()) {
|
|
bNiceReload = TRUE;
|
|
}
|
|
}
|
|
}
|
|
m_crWindowRect = crNewRect;
|
|
|
|
// Now that all variables are updated and in sync, we can call
|
|
// NiceReload if needed.
|
|
if(bNiceReload && XP_DOCID(GetDocumentContext())) {
|
|
/* MWContext *context = GetContext(); */
|
|
|
|
// Instead of re-loading from scratch, we want to pass new width, height of window
|
|
// to the re-layout routine.
|
|
LO_RelayoutOnResize(GetDocumentContext(), GetWidth(), GetHeight(), m_lLeftMargin, m_lTopMargin);
|
|
|
|
/* Call Win32 API call to validate entire window so that the WM_PAINT message
|
|
that follows a resize does not force a repaint of the window. The repaint
|
|
happens in the LO_RelayoutOnResize call above */
|
|
::ValidateRect( GetPane(), NULL );
|
|
|
|
/*
|
|
NiceResizeReload();
|
|
*/
|
|
}
|
|
}
|
|
|
|
#ifdef EDITOR
|
|
void CWinCX::PreWMErasebkgnd(PaneMessage *pMessage)
|
|
{
|
|
MWContext *pMWContext = GetContext();
|
|
if( pMWContext && EDT_IS_EDITOR(pMWContext) ){
|
|
WFE_HideEditCaret(pMWContext);
|
|
}
|
|
|
|
CPaneCX::PreWMErasebkgnd(pMessage);
|
|
|
|
if( pMWContext && EDT_IS_EDITOR(pMWContext) ){
|
|
WFE_ShowEditCaret(pMWContext);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
BOOL CWinCX::EraseTextBkgnd(HDC pDC, RECT& cRect, LO_TextStruct* pText)
|
|
{
|
|
// If there's a background color specified then use it
|
|
return CDCCX::_EraseBkgnd(pDC, cRect, GetOriginX(), GetOriginY(),
|
|
pText->text_attr->no_background ? NULL : &pText->text_attr->bg);
|
|
}
|
|
|
|
#ifdef LAYERS
|
|
BOOL CWinCX::HandleLayerEvent(CL_Layer * pLayer, CL_Event * pEvent)
|
|
{
|
|
XY point(pEvent->x, pEvent->y); // Event location, in layer coordinates
|
|
BOOL bReturn = TRUE;
|
|
fe_EventStruct *pFEEvent = (fe_EventStruct *)pEvent->fe_event;
|
|
UINT uFlags, nFlags, nRepCnt, nChar;
|
|
CPoint cpPoint; // Event location, in screen coordinates
|
|
LO_Element *pElement;
|
|
CFormElement * pFormElement;
|
|
|
|
if (CL_IS_MOUSE_EVENT(pEvent)) {
|
|
if (pFEEvent) {
|
|
uFlags = pFEEvent->uFlags;
|
|
cpPoint.x = pFEEvent->x;
|
|
cpPoint.y = pFEEvent->y;
|
|
}
|
|
else {
|
|
// This is a synthesized event and we need to fill in
|
|
// the FE part. We can just used the uFlags from the
|
|
// previous mouse event. Should we know all the information
|
|
// to create the cpPoint?
|
|
uFlags = m_uMouseFlags;
|
|
int32 layer_x_offset = CL_GetLayerXOrigin(pLayer);
|
|
int32 layer_y_offset = CL_GetLayerYOrigin(pLayer);
|
|
cpPoint.x = CASTINT(pEvent->x + layer_x_offset - m_lOrgX);
|
|
cpPoint.y = CASTINT(pEvent->y + layer_y_offset - m_lOrgY);
|
|
}
|
|
}
|
|
|
|
if (CL_IS_KEY_EVENT(pEvent)) {
|
|
if (pFEEvent) {
|
|
nFlags = HIWORD(pFEEvent->fe_modifiers);
|
|
nRepCnt = LOWORD(pFEEvent->fe_modifiers);
|
|
nChar = pFEEvent->nChar;
|
|
}
|
|
}
|
|
|
|
switch(pEvent->type) {
|
|
case CL_EVENT_MOUSE_BUTTON_DOWN:
|
|
if (pEvent->which == 1)
|
|
OnLButtonDownForLayerCX(uFlags, cpPoint, point, pLayer);
|
|
// The right button is passed to the view for popup stuff
|
|
else if (pEvent->which == 3) {
|
|
if(!OnRButtonDownForLayerCX(uFlags, cpPoint,
|
|
point, pLayer)) {
|
|
CGenericView *pView = GetView();
|
|
if(pView) {
|
|
bReturn = pView->OnRButtonDownForLayer(uFlags, cpPoint,
|
|
point.x, point.y,
|
|
pLayer);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case CL_EVENT_MOUSE_BUTTON_UP:
|
|
if (pEvent->which == 1)
|
|
OnLButtonUpForLayerCX(uFlags, cpPoint, point, pLayer, pFEEvent->pbReturnImmediately);
|
|
else if (pEvent->which == 3)
|
|
OnRButtonUpForLayerCX(uFlags, cpPoint, point, pLayer);
|
|
break;
|
|
case CL_EVENT_MOUSE_MOVE:
|
|
OnMouseMoveForLayerCX(uFlags, cpPoint, point, pLayer, pFEEvent->pbReturnImmediately);
|
|
break;
|
|
case CL_EVENT_MOUSE_BUTTON_MULTI_CLICK:
|
|
if (pEvent->which == 1)
|
|
OnLButtonDblClkForLayerCX(uFlags, cpPoint, point, pLayer);
|
|
else if (pEvent->which == 3)
|
|
OnRButtonDblClkForLayerCX(uFlags, cpPoint, point, pLayer);
|
|
break;
|
|
case CL_EVENT_KEY_FOCUS_GAINED:
|
|
bReturn = TRUE;
|
|
break;
|
|
case CL_EVENT_KEY_UP:
|
|
pElement = GetLayoutElement(point, pLayer);
|
|
// Check for form element and send event back to form element's class.
|
|
if (pElement != NULL && pElement->type == LO_FORM_ELE && pFEEvent->x == 1) {
|
|
switch (pElement->lo_form.element_data->type) {
|
|
case FORM_TYPE_TEXT:
|
|
case FORM_TYPE_PASSWORD:
|
|
case FORM_TYPE_TEXTAREA:
|
|
case FORM_TYPE_FILE:
|
|
pFormElement=(CFormElement *)pElement->lo_form.element_data->ele_minimal.FE_Data;
|
|
((CNetscapeEdit *)CEdit::FromHandlePermanent(pFormElement->GetRaw()))->OnEditKeyEvent(pEvent->type, pEvent->which, nRepCnt, nFlags);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case CL_EVENT_KEY_DOWN:
|
|
pElement = GetLayoutElement(point, pLayer);
|
|
// Check for form element and send event back to form element's class.
|
|
if (pElement != NULL && pElement->type == LO_FORM_ELE && pFEEvent->x == 1) {
|
|
switch (pElement->lo_form.element_data->type) {
|
|
case FORM_TYPE_TEXT:
|
|
case FORM_TYPE_PASSWORD:
|
|
case FORM_TYPE_TEXTAREA:
|
|
case FORM_TYPE_FILE:
|
|
pFormElement=(CFormElement *)pElement->lo_form.element_data->ele_minimal.FE_Data;
|
|
((CNetscapeEdit *)CEdit::FromHandlePermanent(pFormElement->GetRaw()))->OnEditKeyEvent(pEvent->type, pEvent->which, nRepCnt, nFlags);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
switch(nChar) {
|
|
case ' ':
|
|
case VK_NEXT:
|
|
// page down
|
|
Scroll(SB_VERT, SB_PAGEDOWN, 0, NULL);
|
|
break;
|
|
case VK_BACK:
|
|
case VK_PRIOR:
|
|
// page up
|
|
Scroll(SB_VERT, SB_PAGEUP, 0, NULL);
|
|
break;
|
|
case VK_UP:
|
|
// line up
|
|
Scroll(SB_VERT, SB_LINEUP, 0, NULL);
|
|
break;
|
|
case VK_DOWN:
|
|
// line down
|
|
Scroll(SB_VERT, SB_LINEDOWN, 0, NULL);
|
|
break;
|
|
case VK_RIGHT:
|
|
// line right
|
|
Scroll(SB_HORZ, SB_LINERIGHT, 0, NULL);
|
|
break;
|
|
case VK_LEFT:
|
|
// line left
|
|
Scroll(SB_HORZ, SB_LINELEFT, 0, NULL);
|
|
break;
|
|
case VK_HOME:
|
|
if (::GetKeyState(VK_CONTROL) < 0)
|
|
Scroll(SB_VERT, SB_TOP, 0, NULL);
|
|
else
|
|
Scroll(SB_HORZ, SB_TOP, 0, NULL);
|
|
break;
|
|
case VK_END:
|
|
if (::GetKeyState(VK_CONTROL) < 0)
|
|
Scroll(SB_VERT, SB_BOTTOM, 0, NULL);
|
|
else
|
|
Scroll(SB_HORZ, SB_BOTTOM, 0, NULL);
|
|
break;
|
|
|
|
case VK_ESCAPE:
|
|
// escape, kill off any selected items.
|
|
if(m_pSelected != NULL) {
|
|
OnDeactivateEmbedCX();
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case CL_EVENT_KEY_FOCUS_LOST:
|
|
default:
|
|
bReturn = FALSE;
|
|
break;
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
BOOL CWinCX::HandleEmbedEvent(LO_EmbedStruct *embed, CL_Event *pEvent)
|
|
{
|
|
NPEvent npEvent;
|
|
fe_EventStruct *pFEEvent = (fe_EventStruct *)pEvent->fe_event;
|
|
NPEmbeddedApp *pEmbeddedApp = (NPEmbeddedApp *)embed->FE_Data;
|
|
|
|
if (CL_IS_MOUSE_EVENT(pEvent)) {
|
|
if (pFEEvent)
|
|
npEvent.wParam = pFEEvent->uFlags;
|
|
else
|
|
npEvent.wParam = m_uMouseFlags;
|
|
|
|
npEvent.lParam = MAKELONG(pEvent->x, pEvent->y);
|
|
}
|
|
else if (CL_IS_KEY_EVENT(pEvent)) {
|
|
npEvent.wParam = (uint32)pEvent->which;
|
|
npEvent.lParam = (uint32)pEvent->modifiers;
|
|
}
|
|
else if (pEvent->type == CL_EVENT_MOUSE_ENTER) {
|
|
npEvent.wParam = 0;
|
|
npEvent.lParam = MAKELONG(HTCLIENT, 0);
|
|
}
|
|
else {
|
|
npEvent.wParam = 0;
|
|
npEvent.lParam = 0;
|
|
}
|
|
|
|
switch(pEvent->type) {
|
|
case CL_EVENT_MOUSE_BUTTON_DOWN:
|
|
if (pEvent->which == 1) {
|
|
npEvent.event = WM_LBUTTONDOWN;
|
|
}
|
|
else if (pEvent->which == 2)
|
|
npEvent.event = WM_MBUTTONDOWN;
|
|
else
|
|
npEvent.event = WM_RBUTTONDOWN;
|
|
break;
|
|
case CL_EVENT_MOUSE_BUTTON_UP:
|
|
if (pEvent->which == 1)
|
|
npEvent.event = WM_LBUTTONUP;
|
|
else if (pEvent->which == 2)
|
|
npEvent.event = WM_MBUTTONUP;
|
|
else
|
|
npEvent.event = WM_RBUTTONUP;
|
|
break;
|
|
case CL_EVENT_MOUSE_MOVE:
|
|
npEvent.event = WM_MOUSEMOVE;
|
|
break;
|
|
case CL_EVENT_MOUSE_BUTTON_MULTI_CLICK:
|
|
if (pEvent->which == 1)
|
|
npEvent.event = WM_LBUTTONDBLCLK;
|
|
else if (pEvent->which == 2)
|
|
npEvent.event = WM_MBUTTONDBLCLK;
|
|
else
|
|
npEvent.event = WM_RBUTTONDBLCLK;
|
|
break;
|
|
case CL_EVENT_KEY_UP:
|
|
npEvent.event = WM_KEYUP;
|
|
break;
|
|
case CL_EVENT_KEY_DOWN:
|
|
npEvent.event = WM_KEYDOWN;
|
|
break;
|
|
case CL_EVENT_MOUSE_ENTER:
|
|
npEvent.event = WM_SETCURSOR;
|
|
break;
|
|
case CL_EVENT_KEY_FOCUS_GAINED:
|
|
npEvent.event = WM_SETFOCUS;
|
|
break;
|
|
case CL_EVENT_KEY_FOCUS_LOST:
|
|
npEvent.event = WM_KILLFOCUS;
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return (BOOL)NPL_HandleEvent(pEmbeddedApp, &npEvent, (void*)npEvent.wParam);
|
|
}
|
|
#endif /* LAYERS */
|
|
|
|
BOOL CWinCX::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
|
|
// Don't continue if this context is destroyed.
|
|
if(IsDestroyed()) {
|
|
return bReturn;
|
|
}
|
|
|
|
#ifdef LAYERS
|
|
/*
|
|
* If there's a compositor and someone has keyboard focus.
|
|
* Note that if noone has event focus, we set the event focus
|
|
* to the main document.
|
|
*/
|
|
if (GetContext()->compositor) {
|
|
if (CL_IsKeyEventGrabber(GetContext()->compositor, NULL) &&
|
|
CL_GetCompositorRoot(GetContext()->compositor)) {
|
|
|
|
CL_GrabKeyEvents(GetContext()->compositor, CL_GetLayerChildByName(
|
|
CL_GetCompositorRoot(GetContext()->compositor), LO_BODY_LAYER_NAME));
|
|
}
|
|
|
|
if (!CL_IsKeyEventGrabber(GetContext()->compositor, NULL)) {
|
|
|
|
CL_Event event;
|
|
fe_EventStruct fe_event;
|
|
|
|
// Convert the point to something we understand.
|
|
XY Point;
|
|
WORD asciiChar = 0;
|
|
|
|
ResolvePoint(Point, m_cpMMove);
|
|
|
|
if (!EDT_IS_EDITOR(GetContext())) {
|
|
BYTE kbstate[256];
|
|
GetKeyboardState(kbstate);
|
|
#ifdef WIN32
|
|
ToAscii(nChar, nFlags & 0xff, kbstate, &asciiChar, 0);
|
|
#else
|
|
ToAscii(nChar, nFlags & 0xff, kbstate, (DWORD*)&asciiChar, 0);
|
|
#endif
|
|
}
|
|
|
|
fe_event.fe_modifiers = MAKELONG(nRepCnt, nFlags);
|
|
fe_event.nChar = nChar;
|
|
fe_event.x = 0;
|
|
|
|
event.type = CL_EVENT_KEY_UP;
|
|
event.fe_event = (void *)&fe_event;
|
|
event.fe_event_size = sizeof(fe_EventStruct);
|
|
event.which = asciiChar;
|
|
event.modifiers = (GetKeyState(VK_SHIFT) < 0 ? EVENT_SHIFT_MASK : 0)
|
|
| (GetKeyState(VK_CONTROL) < 0 ? EVENT_CONTROL_MASK : 0)
|
|
| (GetKeyState(VK_MENU) < 0 ? EVENT_ALT_MASK : 0);
|
|
event.x = Point.x;
|
|
event.y = Point.y;
|
|
|
|
bReturn = (BOOL)CL_DispatchEvent(GetContext()->compositor, &event);
|
|
}
|
|
}
|
|
#endif /* LAYERS */
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
BOOL CWinCX::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
|
|
// Don't continue if this context is destroyed.
|
|
if(IsDestroyed()) {
|
|
return bReturn;
|
|
}
|
|
|
|
#ifdef LAYERS
|
|
/*
|
|
* If there's a compositor and someone has keyboard focus.
|
|
* Note that if noone has event focus, we set the event focus
|
|
* to the main document.
|
|
*/
|
|
if (GetContext()->compositor) {
|
|
if (CL_IsKeyEventGrabber(GetContext()->compositor, NULL) &&
|
|
CL_GetCompositorRoot(GetContext()->compositor)) {
|
|
|
|
CL_GrabKeyEvents(GetContext()->compositor, CL_GetLayerChildByName(
|
|
CL_GetCompositorRoot(GetContext()->compositor), LO_BODY_LAYER_NAME));
|
|
|
|
}
|
|
|
|
if (!CL_IsKeyEventGrabber(GetContext()->compositor, NULL)) {
|
|
|
|
CL_Event event;
|
|
fe_EventStruct fe_event;
|
|
|
|
// Convert the point to something we understand.
|
|
XY Point;
|
|
WORD asciiChar = 0;
|
|
|
|
ResolvePoint(Point, m_cpMMove);
|
|
|
|
if (!EDT_IS_EDITOR(GetContext())) {
|
|
BYTE kbstate[256];
|
|
GetKeyboardState(kbstate);
|
|
#ifdef WIN32
|
|
ToAscii(nChar, nFlags & 0xff, kbstate, &asciiChar, 0);
|
|
#else
|
|
ToAscii(nChar, nFlags & 0xff, kbstate, (DWORD*)&asciiChar, 0);
|
|
#endif
|
|
}
|
|
|
|
|
|
fe_event.fe_modifiers = MAKELONG(nRepCnt, nFlags);
|
|
fe_event.nChar = nChar;
|
|
fe_event.x = 0;
|
|
|
|
event.type = CL_EVENT_KEY_DOWN;
|
|
event.fe_event = (void *)&fe_event;
|
|
event.fe_event_size = sizeof(fe_EventStruct);
|
|
event.which = asciiChar;
|
|
event.modifiers = (GetKeyState(VK_SHIFT) < 0 ? EVENT_SHIFT_MASK : 0)
|
|
| (GetKeyState(VK_CONTROL) < 0 ? EVENT_CONTROL_MASK : 0)
|
|
| (GetKeyState(VK_MENU) < 0 ? EVENT_ALT_MASK : 0);
|
|
event.x = Point.x;
|
|
event.y = Point.y;
|
|
event.data = nFlags>>14 & 1;//Bit represeting key repetition
|
|
|
|
bReturn = (BOOL)CL_DispatchEvent(GetContext()->compositor, &event);
|
|
}
|
|
}
|
|
#endif /* LAYERS */
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
void CWinCX::OnLButtonDblClkCX(UINT uFlags, CPoint cpPoint) {
|
|
// Only do this if clicking is enabled.
|
|
if(IsClickingEnabled() == FALSE) {
|
|
return;
|
|
}
|
|
|
|
// Don't continue if this context is destroyed.
|
|
if(IsDestroyed()) {
|
|
return;
|
|
}
|
|
|
|
// Remember....
|
|
m_LastMouseEvent = m_LBDClick;
|
|
m_cpLBDClick = cpPoint;
|
|
m_uMouseFlags = uFlags;
|
|
|
|
// Convert the point to something we understand.
|
|
XY Point;
|
|
ResolvePoint(Point, cpPoint);
|
|
|
|
#ifdef LAYERS
|
|
if (GetContext()->compositor) {
|
|
CL_Event event;
|
|
fe_EventStruct fe_event;
|
|
|
|
fe_event.uFlags = uFlags;
|
|
fe_event.x = cpPoint.x;
|
|
fe_event.y = cpPoint.y;
|
|
|
|
event.type = CL_EVENT_MOUSE_BUTTON_MULTI_CLICK;
|
|
event.fe_event = (void *)&fe_event;
|
|
event.fe_event_size = sizeof(fe_EventStruct);
|
|
event.x = Point.x;
|
|
event.y = Point.y;
|
|
event.modifiers = (uFlags & MK_SHIFT ? EVENT_SHIFT_MASK : 0)
|
|
| (uFlags & MK_CONTROL ? EVENT_CONTROL_MASK : 0)
|
|
| (GetKeyState(VK_MENU) < 0 ? EVENT_ALT_MASK : 0);
|
|
event.which = 1;
|
|
event.data = 2;
|
|
|
|
CL_DispatchEvent(GetContext()->compositor,
|
|
&event);
|
|
}
|
|
else
|
|
OnLButtonDblClkForLayerCX(uFlags, cpPoint, Point, NULL);
|
|
|
|
// Have the mouse timer handler do some dirty work.
|
|
MouseTimerData mt(GetContext());
|
|
FEU_MouseTimer(&mt);
|
|
return;
|
|
}
|
|
|
|
void
|
|
CWinCX::OnLButtonDblClkForLayerCX(UINT uFlags, CPoint& cpPoint,
|
|
XY& Point, CL_Layer *layer)
|
|
{
|
|
// With LAYERS turned on, the orginal method
|
|
// OnLButtonDblClkCX is separated into two methods,
|
|
// one of which is a per-layer method.
|
|
#endif /* LAYERS */
|
|
|
|
// Process any embed activation.
|
|
#ifdef LAYERS
|
|
LO_Element *pElement = GetLayoutElement(Point, layer);
|
|
#else
|
|
LO_Element *pElement = GetLayoutElement(Point);
|
|
#endif
|
|
|
|
if (pElement != NULL && pElement->type == LO_FORM_ELE &&
|
|
(Point.x - pElement->lo_form.x - pElement->lo_form.x_offset < pElement->lo_form.width) &&
|
|
(Point.x - pElement->lo_form.x - pElement->lo_form.x_offset > 0) &&
|
|
(Point.y - pElement->lo_form.y - pElement->lo_form.y_offset < pElement->lo_form.height) &&
|
|
(Point.y - pElement->lo_form.y - pElement->lo_form.y_offset > 0)) {
|
|
|
|
CFormElement * pFormElement;
|
|
CNetscapeButton *pButton;
|
|
switch (pElement->lo_form.element_data->type) {
|
|
case FORM_TYPE_BUTTON:
|
|
case FORM_TYPE_RESET:
|
|
case FORM_TYPE_SUBMIT:
|
|
case FORM_TYPE_CHECKBOX:
|
|
case FORM_TYPE_RADIO:
|
|
pFormElement=(CFormElement *)pElement->lo_form.element_data->ele_minimal.FE_Data;
|
|
((CNetscapeButton *)CButton::FromHandlePermanent(pFormElement->GetRaw()))
|
|
->OnButtonEvent(CL_EVENT_MOUSE_BUTTON_MULTI_CLICK, uFlags, cpPoint);
|
|
break;
|
|
case FORM_TYPE_FILE:
|
|
pFormElement=(CFormElement *)pElement->lo_form.element_data->ele_minimal.FE_Data;
|
|
pButton = (CNetscapeButton *)pFormElement->GetSecondaryWidget();
|
|
if (pButton)
|
|
pButton->OnButtonEvent(CL_EVENT_MOUSE_BUTTON_MULTI_CLICK, uFlags, cpPoint);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if(pElement != NULL && pElement->type == LO_EMBED) {
|
|
// Any previous activated embed was deactivated in the button down event.
|
|
// However, we should not reactivate an already active item.
|
|
NPEmbeddedApp* pEmbeddedApp = (NPEmbeddedApp*)pElement->lo_embed.FE_Data;
|
|
ASSERT(pEmbeddedApp);
|
|
CNetscapeCntrItem *pItem = (CNetscapeCntrItem *)pEmbeddedApp->fe_data;
|
|
if(pItem != NULL) {
|
|
if(pItem->m_bBroken == FALSE && pItem->m_bDelayed == FALSE &&
|
|
pItem->m_bLoading == FALSE) {
|
|
if(pItem->IsInPlaceActive() == FALSE) {
|
|
// Set the active item.
|
|
// This value is held in the view for now....
|
|
CGenericView *pView = GetView();
|
|
if(pView) {
|
|
m_pSelected = &(pElement->lo_embed);
|
|
|
|
long lVerb = OLEIVERB_PRIMARY;
|
|
if(uFlags & MK_CONTROL) {
|
|
lVerb = OLEIVERB_OPEN;
|
|
}
|
|
|
|
pView->BeginWaitCursor();
|
|
TRY {
|
|
pItem->Activate(lVerb, pView);
|
|
|
|
}
|
|
CATCH(CException, e) {
|
|
// Object wouldn't activate or something went wrong,
|
|
// and almost caused us to go down with it.
|
|
m_pSelected = NULL;
|
|
}
|
|
END_CATCH
|
|
pView->EndWaitCursor();
|
|
// If it's not in place active at this point, there's no need
|
|
// to keep track of it.
|
|
if(m_pSelected != NULL && pItem->IsInPlaceActive() == FALSE) {
|
|
m_pSelected = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Dbl-click is not the same as holding mouse down
|
|
m_bLBDown = FALSE;
|
|
m_bLBUp = TRUE;
|
|
}
|
|
else {
|
|
if(GetPane()) {
|
|
::SetCapture(GetPane());
|
|
}
|
|
|
|
#ifdef EDITOR
|
|
if ( EDT_IS_EDITOR(GetContext()) )
|
|
{
|
|
// Let the editor handle the double-click
|
|
EDT_DoubleClick(GetContext(), Point.x, Point.y);
|
|
// Dbl-click is NOT the same as holding mouse down
|
|
m_bLBDown = FALSE;
|
|
m_bLBUp = TRUE;
|
|
}
|
|
else
|
|
{
|
|
#ifdef LAYERS
|
|
LO_DoubleClick(GetDocumentContext(), Point.x, Point.y, layer);
|
|
#else
|
|
LO_DoubleClick(GetDocumentContext(), Point.x, Point.y);
|
|
#endif /* LAYERS */
|
|
// Double-click is the same as holding mouse down when
|
|
// we're selecting.
|
|
//cmanske: WHY??? DOES THE BROWSER NEED THIS? BAD FOR EDITOR!
|
|
#endif // EDITOR
|
|
m_bLBDown = TRUE;
|
|
m_bLBUp = FALSE;
|
|
#ifdef EDITOR
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// Have the mouse timer handler do some dirty work.
|
|
// Please don't return in the above code, I'd like this to get called
|
|
// in all cases with the state of the buttons set correctly.
|
|
MouseTimerData mt(GetContext());
|
|
FEU_MouseTimer(&mt);
|
|
}
|
|
|
|
BOOL CWinCX::PtInSelectedCell(CPoint &DocPoint, LO_CellStruct *cell,
|
|
BOOL &bContinue, LO_Element *start_element,
|
|
LO_Element *end_element)
|
|
{
|
|
BOOL bPtInRegion = FALSE;
|
|
|
|
for ( LO_Any_struct * element = (LO_Any_struct *)cell->cell_list; ;
|
|
element = (LO_Any_struct *)(element->next) ) {
|
|
if( element == 0 ){
|
|
bContinue = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
// Linefeed rect is from end of text to right ledge,
|
|
// so lets ignore it
|
|
if ( element->type != LO_LINEFEED ) {
|
|
if ( element->type == LO_TEXT &&
|
|
(element == (LO_Any_struct*)start_element ||
|
|
element == (LO_Any_struct*)end_element) ) {
|
|
// With 1st and last text elements, we need to
|
|
// account for character offsets from start or end of selection
|
|
LO_TextStruct *text = (LO_TextStruct*)element;
|
|
LTRB rect;
|
|
// We may have a null text element in Tables,
|
|
// so use closest non-null text element
|
|
if( text->text == NULL){
|
|
if( text->prev != NULL && text->prev->type == LO_TEXT ){
|
|
text = (LO_TextStruct*)text->prev;
|
|
} else if( text->next != NULL && text->next->type == LO_TEXT ){
|
|
text = (LO_TextStruct*)text->next;
|
|
}
|
|
}
|
|
if( text->text ){
|
|
ResolveElement( rect, text,
|
|
(int)(text->x + text->x_offset), // Start location
|
|
(int32)(text->sel_start),
|
|
(int32)(text->sel_end), FALSE );
|
|
int x = CASTINT(DocPoint.x - GetOriginX());
|
|
int y = CASTINT(DocPoint.y - GetOriginY());
|
|
bPtInRegion = x > rect.left &&
|
|
x < rect.right &&
|
|
y > rect.top &&
|
|
y < rect.bottom;
|
|
} else {
|
|
bPtInRegion = FALSE;
|
|
}
|
|
}
|
|
else if (element->type == LO_CELL) {
|
|
bPtInRegion = PtInSelectedCell(DocPoint,
|
|
(LO_CellStruct *)element,
|
|
bContinue, start_element,
|
|
end_element);
|
|
}
|
|
else if (element->type != LO_TABLE) {
|
|
// Get the rect surrounding selected element,
|
|
CRect cRect;
|
|
cRect.left = CASTINT(element->x + element->x_offset);
|
|
cRect.top = CASTINT(element->y + element->y_offset);
|
|
cRect.right = CASTINT(cRect.left + element->width);
|
|
cRect.bottom = CASTINT(cRect.top + element->height);
|
|
bPtInRegion = cRect.PtInRect( DocPoint );
|
|
}
|
|
}
|
|
// We're done if we are in a rect or finished with last element
|
|
if ( bPtInRegion || !bContinue ||
|
|
element == (LO_Any_struct*)end_element ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
bContinue = FALSE;
|
|
return bPtInRegion;
|
|
}
|
|
|
|
// Test if point, such mouse cursor, is within the selected region
|
|
BOOL CWinCX::PtInSelectedRegion(CPoint cPoint, BOOL bConvertToDocCoordinates,
|
|
CL_Layer *layer)
|
|
{
|
|
BOOL bPtInRegion = FALSE;
|
|
BOOL bContinue = TRUE;
|
|
|
|
CPoint DocPoint;
|
|
if( bConvertToDocCoordinates ){
|
|
XY Point;
|
|
ResolvePoint(Point, cPoint);
|
|
DocPoint.x = CASTINT(Point.x);
|
|
DocPoint.y = CASTINT(Point.y);
|
|
} else {
|
|
DocPoint = cPoint;
|
|
}
|
|
|
|
int32 start_selection, end_selection;
|
|
LO_Element * start_element = NULL;
|
|
LO_Element * end_element = NULL;
|
|
CL_Layer *sel_layer = NULL;
|
|
int32 x_origin, y_origin, old_x_origin, old_y_origin;
|
|
|
|
// Start the search from the current selection location
|
|
LO_GetSelectionEndpoints(GetDocumentContext(),
|
|
&start_element,
|
|
&end_element,
|
|
&start_selection,
|
|
&end_selection,
|
|
&sel_layer);
|
|
|
|
if ( start_element == NULL ) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* If the selection layer is different from the one in which
|
|
* the event occured, there isn't a match.
|
|
*/
|
|
if ( layer && (layer != sel_layer) ) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Temporarily change the drawing origin to that of the selection
|
|
* layer so that resolving the positions of the elements will
|
|
* result in correct coordinate space translation.
|
|
*/
|
|
if ( sel_layer ) {
|
|
x_origin = CL_GetLayerXOrigin(sel_layer);
|
|
y_origin = CL_GetLayerYOrigin(sel_layer);
|
|
}
|
|
else {
|
|
x_origin = 0;
|
|
y_origin = 0;
|
|
}
|
|
|
|
CDrawable *pDrawable = GetDrawable();
|
|
if (pDrawable) {
|
|
pDrawable->GetOrigin(&old_x_origin, &old_y_origin);
|
|
pDrawable->SetOrigin(x_origin, y_origin);
|
|
}
|
|
|
|
for ( LO_Any_struct * element = (LO_Any_struct *)start_element; ;
|
|
element = (LO_Any_struct *)(element->next) ) {
|
|
// KLUDGE: This prevents crashing when multiple selection
|
|
// within cells of a table
|
|
if( element == 0 ){
|
|
if ( pDrawable ) {
|
|
pDrawable->SetOrigin(old_x_origin, old_y_origin);
|
|
}
|
|
return FALSE;
|
|
}
|
|
// Linefeed rect is from end of text to right ledge,
|
|
// so lets ignore it
|
|
if ( element->type != LO_LINEFEED ) {
|
|
if ( element->type == LO_TEXT &&
|
|
(element == (LO_Any_struct*)start_element ||
|
|
element == (LO_Any_struct*)end_element) ) {
|
|
// With 1st and last text elements, we need to
|
|
// account for character offsets from start or end of selection
|
|
LO_TextStruct *text = (LO_TextStruct*)element;
|
|
LTRB rect;
|
|
// We may have a null text element in Tables,
|
|
// so use closest non-null text element
|
|
if( text->text == NULL){
|
|
if( text->prev != NULL && text->prev->type == LO_TEXT ){
|
|
text = (LO_TextStruct*)text->prev;
|
|
} else if( text->next != NULL && text->next->type == LO_TEXT ){
|
|
text = (LO_TextStruct*)text->next;
|
|
}
|
|
}
|
|
if( text->text ){
|
|
ResolveElement( rect, text,
|
|
(int)(text->x + text->x_offset), // Start location
|
|
(int32)(text->sel_start),
|
|
(int32)(text->sel_end), FALSE );
|
|
int x = CASTINT(DocPoint.x - GetOriginX());
|
|
int y = CASTINT(DocPoint.y - GetOriginY());
|
|
bPtInRegion = x > rect.left &&
|
|
x < rect.right &&
|
|
y > rect.top &&
|
|
y < rect.bottom;
|
|
} else {
|
|
bPtInRegion = FALSE;
|
|
}
|
|
}
|
|
else if (element->type == LO_CELL) {
|
|
bPtInRegion = PtInSelectedCell(DocPoint,
|
|
(LO_CellStruct *)element,
|
|
bContinue, start_element,
|
|
end_element);
|
|
}
|
|
else if (element->type != LO_TABLE) {
|
|
// Get the rect surrounding selected element,
|
|
CRect cRect;
|
|
cRect.left = CASTINT(element->x + element->x_offset);
|
|
cRect.top = CASTINT(element->y + element->y_offset);
|
|
cRect.right = CASTINT(cRect.left + element->width);
|
|
cRect.bottom = CASTINT(cRect.top + element->height);
|
|
bPtInRegion = cRect.PtInRect( DocPoint );
|
|
}
|
|
}
|
|
// We're done if we are in a rect or finished with last element
|
|
if ( bPtInRegion || !bContinue ||
|
|
element == (LO_Any_struct*)end_element ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( pDrawable ) {
|
|
pDrawable->SetOrigin(old_x_origin, old_y_origin);
|
|
}
|
|
|
|
return bPtInRegion;
|
|
}
|
|
|
|
void CWinCX::OnLButtonDownCX(UINT uFlags, CPoint cpPoint)
|
|
{
|
|
RelayToolTipEvent(cpPoint, WM_LBUTTONDOWN);
|
|
|
|
// Only do this if clicking is enabled.
|
|
if(IsClickingEnabled() == FALSE) {
|
|
return;
|
|
}
|
|
|
|
// Don't continue if this context is destroyed.
|
|
if(IsDestroyed()) {
|
|
return;
|
|
}
|
|
|
|
// Start capturing all mouse events.
|
|
if(GetPane()) {
|
|
::SetCapture(GetPane());
|
|
}
|
|
|
|
XY Point;
|
|
ResolvePoint(Point, cpPoint);
|
|
|
|
#ifdef LAYERS
|
|
|
|
if (GetContext()->compositor) {
|
|
CL_Event event;
|
|
fe_EventStruct fe_event;
|
|
|
|
fe_event.uFlags = uFlags;
|
|
fe_event.x = cpPoint.x;
|
|
fe_event.y = cpPoint.y;
|
|
|
|
event.type = CL_EVENT_MOUSE_BUTTON_DOWN;
|
|
event.fe_event = (void *)&fe_event;
|
|
event.fe_event_size = sizeof(fe_EventStruct);
|
|
event.modifiers = (uFlags & MK_SHIFT ? EVENT_SHIFT_MASK : 0)
|
|
| (uFlags & MK_CONTROL ? EVENT_CONTROL_MASK : 0)
|
|
| (GetKeyState(VK_MENU) < 0 ? EVENT_ALT_MASK : 0);
|
|
event.x = Point.x;
|
|
event.y = Point.y;
|
|
event.which = 1;
|
|
|
|
CL_DispatchEvent(GetContext()->compositor,
|
|
&event);
|
|
}
|
|
else
|
|
OnLButtonDownForLayerCX(uFlags, cpPoint, Point, NULL);
|
|
|
|
// Have the mouse timer handler do some dirty work.
|
|
MouseTimerData mt(GetContext());
|
|
FEU_MouseTimer(&mt);
|
|
return;
|
|
}
|
|
|
|
void CWinCX::ResetToolTipImg() {
|
|
pLastToolTipImg = 0;
|
|
m_pLastToolTipAnchor = NULL;
|
|
if (m_ToolTip) {
|
|
m_ToolTip->Activate(FALSE);
|
|
delete m_ToolTip;
|
|
m_ToolTip = 0;
|
|
}
|
|
}
|
|
|
|
|
|
void CWinCX::RelayToolTipEvent(POINT pt, UINT message)
|
|
{
|
|
if (m_ToolTip) {
|
|
MSG msg;
|
|
msg.message = message;
|
|
msg.hwnd = GetPane();
|
|
msg.pt = pt;
|
|
::ClientToScreen(msg.hwnd, &msg.pt);
|
|
m_ToolTip->RelayEvent(&msg);
|
|
}
|
|
}
|
|
|
|
void
|
|
CWinCX::OnLButtonDownForLayerCX(UINT uFlags, CPoint &cpPoint, XY& Point,
|
|
CL_Layer *layer)
|
|
{
|
|
MWContext *pMWContext = GetContext();
|
|
XP_ASSERT(pMWContext);
|
|
|
|
// With LAYERS turned on, the orginal method
|
|
// OnLButtonDownCX is separated into two methods,
|
|
// one of which is a per-layer method.
|
|
if (pMWContext->compositor)
|
|
CL_GrabMouseEvents(pMWContext->compositor, layer);
|
|
#endif /* LAYERS */
|
|
|
|
#ifdef LAYERS
|
|
LO_Element *pElement = GetLayoutElement(Point, layer);
|
|
#else
|
|
LO_Element *pElement = GetLayoutElement(Point);
|
|
#endif /* LAYERS */
|
|
|
|
// Check for form element and send event back to form element's class.
|
|
if (pElement != NULL && pElement->type == LO_FORM_ELE &&
|
|
(Point.x - pElement->lo_form.x - pElement->lo_form.x_offset < pElement->lo_form.width) &&
|
|
(Point.x - pElement->lo_form.x - pElement->lo_form.x_offset > 0) &&
|
|
(Point.y - pElement->lo_form.y - pElement->lo_form.y_offset < pElement->lo_form.height) &&
|
|
(Point.y - pElement->lo_form.y - pElement->lo_form.y_offset > 0)) {
|
|
|
|
CFormElement * pFormElement;
|
|
CNetscapeButton * pButton;
|
|
switch (pElement->lo_form.element_data->type) {
|
|
case FORM_TYPE_BUTTON:
|
|
case FORM_TYPE_RESET:
|
|
case FORM_TYPE_SUBMIT:
|
|
case FORM_TYPE_CHECKBOX:
|
|
case FORM_TYPE_RADIO:
|
|
pFormElement=(CFormElement *)pElement->lo_form.element_data->ele_minimal.FE_Data;
|
|
((CNetscapeButton *)CButton::FromHandlePermanent(pFormElement->GetRaw()))
|
|
->OnButtonEvent(CL_EVENT_MOUSE_BUTTON_DOWN, uFlags, cpPoint);
|
|
break;
|
|
case FORM_TYPE_FILE:
|
|
pFormElement=(CFormElement *)pElement->lo_form.element_data->ele_minimal.FE_Data;
|
|
pButton = (CNetscapeButton *)pFormElement->GetSecondaryWidget();
|
|
if (pButton)
|
|
pButton->OnButtonEvent(CL_EVENT_MOUSE_BUTTON_DOWN, uFlags, cpPoint);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Wait to set these until we know the event hasn't be cancelled
|
|
// by JS or really meant for a form element. Remember....
|
|
m_LastMouseEvent = m_LBDown;
|
|
m_cpLBDown = cpPoint;
|
|
m_uMouseFlags = uFlags;
|
|
m_bLBDown = TRUE;
|
|
m_bLBUp = FALSE;
|
|
|
|
|
|
// Deactivate OLE embedded items if active.
|
|
CGenericView *pView = GetView();
|
|
if(pView != NULL && pElement != (LO_Element *)m_pSelected && m_pSelected != NULL) {
|
|
OnDeactivateEmbedCX();
|
|
}
|
|
|
|
#ifdef EDITOR
|
|
ED_HitType iTableHit = ED_HIT_NONE;
|
|
LO_Element * pTableOrCellElement = NULL;
|
|
|
|
if( EDT_IS_EDITOR(pMWContext) )
|
|
{
|
|
m_pStartSelectionCell = NULL;
|
|
|
|
// Check if user pressed down near a sizeable object border
|
|
// and start sizing mode if we are
|
|
// Note: X, Y values are in Document coordinates
|
|
if( !m_bDragging && !EDT_IsSizing(pMWContext) )
|
|
{
|
|
BOOL bSizeTable = FALSE;
|
|
|
|
// Left button down test for selection/sizing/dragging
|
|
iTableHit = EDT_GetTableHitRegion( pMWContext, Point.x, Point.y, &pTableOrCellElement, (uFlags & MK_CONTROL) );
|
|
|
|
// Check if we can select or size a Table or Cell,
|
|
// but not if Alt key is pressed, ignore the table
|
|
// to allow sizing objects tightly surrounded by Cell border
|
|
if( GetAsyncKeyState(VK_MENU) >= 0 &&
|
|
pTableOrCellElement )
|
|
{
|
|
// Save cell we are in
|
|
if( pTableOrCellElement->type == LO_CELL )
|
|
m_pStartSelectionCell = pTableOrCellElement;
|
|
|
|
if( iTableHit == ED_HIT_SIZE_TABLE_WIDTH || iTableHit == ED_HIT_SIZE_TABLE_HEIGHT ||
|
|
iTableHit == ED_HIT_SIZE_COL || iTableHit == ED_HIT_SIZE_ROW ||
|
|
iTableHit == ED_HIT_ADD_ROWS || iTableHit == ED_HIT_ADD_COLS )
|
|
{
|
|
// We are sizing a table, row, or column
|
|
pElement = pTableOrCellElement;
|
|
bSizeTable = TRUE;
|
|
} else if( iTableHit != ED_HIT_NONE && iTableHit != ED_HIT_DRAG_TABLE )
|
|
{
|
|
m_bSelectingCells = TRUE;
|
|
// Mouse is in a selectable region for table, row, column, or cell.
|
|
// If Ctrl key is down and cell is selected, it is appended to other table cells selected
|
|
// Otherwise, any other cell or table selected is cleared before new element is selected.
|
|
// If Shift key is down, then extend selection to new cell
|
|
EDT_SelectTableElement(pMWContext, Point.x, Point.y, pTableOrCellElement, iTableHit,
|
|
(uFlags & MK_CONTROL), (uFlags & MK_SHIFT));
|
|
goto MOUSE_TIMER;
|
|
}
|
|
}
|
|
|
|
if( bSizeTable ||
|
|
(pElement && EDT_CanSizeObject(pMWContext, pElement, Point.x, Point.y)) )
|
|
{
|
|
// Flag to override the normal lock when sizing corners
|
|
BOOL bLock = !(BOOL)(uFlags & MK_CONTROL);
|
|
XP_Rect rect;
|
|
if( EDT_StartSizing(pMWContext, pElement, Point.x, Point.y, bLock, &rect) )
|
|
{
|
|
// Force redraw of table or cells that might have been selected
|
|
// else we have NOT conflicts and garbage at overlaps
|
|
UpdateWindow(GetPane());
|
|
// Save the new rect.
|
|
m_rectSizing.left = rect.left;
|
|
m_rectSizing.right = rect.right;
|
|
m_rectSizing.top = rect.top;
|
|
m_rectSizing.bottom = rect.bottom;
|
|
// Draw the initial feedback -- similar to when selected
|
|
DisplaySelectionFeedback(LO_ELE_SELECTED, m_rectSizing);
|
|
goto MOUSE_TIMER;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Drag Copy/Move - do only if we will not be sizing
|
|
if( GetView()->IsKindOf(RUNTIME_CLASS(CNetscapeView)) &&
|
|
(iTableHit == ED_HIT_DRAG_TABLE || PtInSelectedRegion(cpPoint, TRUE, layer)) )
|
|
{
|
|
// Setup to possibly do Drag Copy/Move
|
|
// Check these flags during mouse move
|
|
// and start drag only if mouse moved enough
|
|
if( iTableHit == ED_HIT_DRAG_TABLE )
|
|
{
|
|
// Setup XP data for possible dragging of table or cells
|
|
EDT_StartDragTable(pMWContext, Point.x, Point.y);
|
|
}
|
|
m_bMouseInSelection = TRUE;
|
|
|
|
} else
|
|
#endif // EDITOR
|
|
if ( ! m_bDragging ) {
|
|
// If the shift key is down, we need to extend the selection.
|
|
if( (uFlags & MK_SHIFT) ) {
|
|
#ifdef EDITOR
|
|
if( EDT_IS_EDITOR(pMWContext) ){
|
|
EDT_ExtendSelection(pMWContext, Point.x, Point.y);
|
|
}
|
|
else
|
|
#endif // EDITOR
|
|
{
|
|
LO_ExtendSelection(GetDocumentContext(), Point.x, Point.y);
|
|
}
|
|
} else {
|
|
// Start a normal selection
|
|
#ifdef EDITOR
|
|
if( EDT_IS_EDITOR(pMWContext) ) {
|
|
EDT_StartSelection(pMWContext, Point.x, Point.y);
|
|
}
|
|
else
|
|
#endif // EDITOR
|
|
{
|
|
#ifdef LAYERS
|
|
LO_StartSelection(GetDocumentContext(), Point.x, Point.y, layer);
|
|
#else
|
|
LO_StartSelection(GetDocumentContext(), Point.x, Point.y);
|
|
#endif /* LAYERS */
|
|
}
|
|
}
|
|
}
|
|
// Highlight an anchor if we are over it.
|
|
|
|
// Save an image element so we can drag into editor
|
|
if ( pElement != NULL && pElement->type == LO_IMAGE ) {
|
|
m_pLastImageObject = (LO_ImageStruct*)pElement;
|
|
}
|
|
|
|
// DON'T drag links when in editor - just highlight the text in the link
|
|
if(!EDT_IS_EDITOR(pMWContext) &&
|
|
pElement != NULL && pElement->type == LO_TEXT && pElement->lo_text.anchor_href != NULL) {
|
|
m_pLastArmedAnchor = pElement;
|
|
LO_HighlightAnchor(GetDocumentContext(), pElement, TRUE);
|
|
}
|
|
|
|
MOUSE_TIMER:
|
|
// Have the mouse timer handler do some dirty work.
|
|
// Please don't return in the above code, I'd like this to get called
|
|
// in all cases with the state of the buttons set correctly.
|
|
MouseTimerData mt(pMWContext);
|
|
FEU_MouseTimer(&mt);
|
|
}
|
|
|
|
typedef struct click_closure {
|
|
char * szRefer;
|
|
int x, y;
|
|
CWinCX * pWin;
|
|
BOOL bCloseOnFail;
|
|
LO_Element * pElement;
|
|
} click_closure;
|
|
|
|
static void
|
|
MapToAnchorAndTarget(MWContext * context, LO_Element * pElement, int x, int y,
|
|
CString& csAnchor, CString& csTarget)
|
|
{
|
|
|
|
switch(pElement->type) {
|
|
|
|
case LO_TEXT:
|
|
if(pElement->lo_text.anchor_href && pElement->lo_text.anchor_href->anchor) {
|
|
csAnchor = (char *) pElement->lo_text.anchor_href->anchor;
|
|
csTarget = (char *) pElement->lo_text.anchor_href->target;
|
|
}
|
|
break;
|
|
|
|
case LO_IMAGE:
|
|
// Check for usemaps (client side ismaps).
|
|
if(pElement->lo_image.image_attr && pElement->lo_image.image_attr->usemap_name != NULL) {
|
|
LO_AnchorData *pAnchorData = LO_MapXYToAreaAnchor(context,
|
|
&pElement->lo_image, x, y);
|
|
if(pAnchorData != NULL) {
|
|
csAnchor = (char *) pAnchorData->anchor;
|
|
csTarget = (char *) pAnchorData->target;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Check for ismaps, normal image anchors
|
|
if(pElement->lo_image.anchor_href != NULL &&
|
|
pElement->lo_image.anchor_href->anchor != NULL) {
|
|
|
|
if(pElement->lo_image.image_attr && pElement->lo_image.image_attr->attrmask & LO_ATTR_ISMAP) {
|
|
|
|
char * pAnchor = PR_smprintf("%s?%d,%d",
|
|
pElement->lo_image.anchor_href->anchor, x, y);
|
|
csAnchor = pAnchor;
|
|
XP_FREE(pAnchor);
|
|
csTarget =(char *)pElement->lo_image.anchor_href->target;
|
|
}
|
|
else {
|
|
csAnchor = (char *)pElement->lo_image.anchor_href->anchor;
|
|
csTarget = (char *)pElement->lo_image.anchor_href->target;
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Mocha has processed a click on an element. If everything is OK
|
|
// we now will do the actual load. If libmocha said to not
|
|
// load and we created a new window explicitly for the load
|
|
// delete the window
|
|
//
|
|
static void
|
|
win_click_callback(MWContext * pContext, LO_Element * pEle, int32 event,
|
|
void * pObj, ETEventStatus status)
|
|
{
|
|
|
|
CString csAnchor, csTarget;
|
|
|
|
// make sure document hasn't gone away
|
|
if(status == EVENT_PANIC) {
|
|
if (((click_closure *)pObj)->pElement && pEle) {
|
|
XP_FREE(pEle);
|
|
}
|
|
XP_FREE(pObj);
|
|
return;
|
|
}
|
|
|
|
// find out who we are
|
|
click_closure * pClose = (click_closure *) pObj;
|
|
CWinCX * pWin = pClose->pWin;
|
|
|
|
// Imagemaps send click pretending to be links. Free the link now and
|
|
// set the element back to the image it is.
|
|
if (pClose->pElement) {
|
|
if(pEle)
|
|
XP_FREE(pEle);
|
|
pEle = pClose->pElement;
|
|
}
|
|
|
|
MapToAnchorAndTarget(pWin->GetContext(), pEle, pClose->x, pClose->y, csAnchor, csTarget);
|
|
|
|
#ifdef EDITOR
|
|
if( EDT_IS_EDITOR(pWin->GetContext()) ){
|
|
// Ctrl Click = edit the URL
|
|
FE_LoadUrl((char*)LPCSTR(csAnchor), LOAD_URL_COMPOSER);
|
|
goto done;
|
|
}
|
|
#endif // EDITOR
|
|
|
|
if(status == EVENT_OK) {
|
|
CWinCX *pLoader = pWin->DetermineTarget(csTarget);
|
|
pLoader->NormalGetUrl(csAnchor, pClose->szRefer, (csTarget.IsEmpty() ? NULL : (LPCSTR)csTarget));
|
|
} else {
|
|
if(pClose->bCloseOnFail)
|
|
// Make it go away if mocha said no.
|
|
FE_DestroyWindow(pContext);
|
|
}
|
|
|
|
done:
|
|
if(pClose->szRefer)
|
|
XP_FREE(pClose->szRefer);
|
|
XP_FREE(pClose);
|
|
|
|
}
|
|
|
|
//
|
|
// The user clicked on a form image. We told mocha about it and now mocha
|
|
// is either going to tell us to submit the form or ignore it
|
|
//
|
|
static void
|
|
image_form_click_callback(MWContext * pContext, LO_Element * pElement, int32 event,
|
|
void * pObj, ETEventStatus status)
|
|
{
|
|
|
|
// only continue if OK
|
|
if(status != EVENT_OK) {
|
|
XP_FREE(pObj);
|
|
return;
|
|
}
|
|
|
|
click_closure * pClose = (click_closure *) pObj;
|
|
CWinCX * pWin = pClose->pWin;
|
|
|
|
LO_FormSubmitData *pSubmit = LO_SubmitImageForm(pContext,
|
|
&pElement->lo_image,
|
|
pClose->x,
|
|
pClose->y);
|
|
|
|
if(pSubmit == NULL) {
|
|
// Nothing to do.
|
|
return;
|
|
}
|
|
|
|
// Have to do a manual load here.
|
|
URL_Struct *pUrl = NET_CreateURLStruct((const char *)pSubmit->action, NET_DONT_RELOAD);
|
|
NET_AddLOSubmitDataToURLStruct(pSubmit, pUrl);
|
|
|
|
// Set the referrer here manually too.
|
|
if(pClose->szRefer)
|
|
pUrl->referer = XP_STRDUP(pClose->szRefer);
|
|
else
|
|
pUrl->referer = NULL;
|
|
|
|
// Request.
|
|
pWin->GetUrl(pUrl, FO_CACHE_AND_PRESENT);
|
|
|
|
// Release.
|
|
LO_FreeSubmitData(pSubmit);
|
|
|
|
}
|
|
|
|
|
|
void CWinCX::OnLButtonUpCX(UINT uFlags, CPoint cpPoint, BOOL &bReturnImmediately)
|
|
{
|
|
RelayToolTipEvent(cpPoint, WM_LBUTTONUP);
|
|
|
|
// Only do this if clicking is enabled.
|
|
if(IsClickingEnabled() == FALSE) {
|
|
return;
|
|
}
|
|
|
|
// Release mouse capture.
|
|
if(GetPane()) {
|
|
::ReleaseCapture();
|
|
}
|
|
|
|
// Don't continue if this context is destroyed.
|
|
if(IsDestroyed()) {
|
|
return;
|
|
}
|
|
|
|
XY Point;
|
|
ResolvePoint(Point, cpPoint);
|
|
|
|
#ifdef LAYERS
|
|
|
|
if (GetContext()->compositor) {
|
|
CL_Event event;
|
|
fe_EventStruct fe_event;
|
|
|
|
fe_event.uFlags = uFlags;
|
|
fe_event.x = cpPoint.x;
|
|
fe_event.y = cpPoint.y;
|
|
fe_event.pbReturnImmediately = bReturnImmediately;
|
|
|
|
event.type = CL_EVENT_MOUSE_BUTTON_UP;
|
|
event.fe_event = (void *)&fe_event;
|
|
event.fe_event_size = sizeof(fe_EventStruct);
|
|
event.x = Point.x;
|
|
event.y = Point.y;
|
|
event.modifiers = (uFlags & MK_SHIFT ? EVENT_SHIFT_MASK : 0)
|
|
| (uFlags & MK_CONTROL ? EVENT_CONTROL_MASK : 0)
|
|
| (GetKeyState(VK_MENU) < 0 ? EVENT_ALT_MASK : 0);
|
|
event.which = 1;
|
|
|
|
CL_DispatchEvent(GetContext()->compositor,
|
|
&event);
|
|
|
|
bReturnImmediately = fe_event.pbReturnImmediately;
|
|
}
|
|
else
|
|
OnLButtonUpForLayerCX(uFlags, cpPoint, Point, NULL, bReturnImmediately);
|
|
|
|
// Have the mouse timer handler do some dirty work.
|
|
MouseTimerData mt(GetContext());
|
|
FEU_MouseTimer(&mt);
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
CWinCX::OnLButtonUpForLayerCX(UINT uFlags, CPoint& cpPoint, XY& Point,
|
|
CL_Layer *layer, BOOL &bReturnImmediately)
|
|
{
|
|
|
|
History_entry *pHist = NULL;
|
|
click_closure * pClosure = NULL;
|
|
|
|
// With LAYERS turned on, the orginal method
|
|
// OnLButtonUpCX is separated into two methods,
|
|
// one of which is a per-layer method.
|
|
if (GetContext()->compositor)
|
|
CL_GrabMouseEvents(GetContext()->compositor, NULL);
|
|
#endif /* LAYERS */
|
|
|
|
#ifdef LAYERS
|
|
LO_Element *pElement = GetLayoutElement(Point, layer);
|
|
#else
|
|
LO_Element *pElement = GetLayoutElement(Point);
|
|
#endif /* LAYERS */
|
|
|
|
if (pElement != NULL && pElement->type == LO_FORM_ELE &&
|
|
(Point.x - pElement->lo_form.x - pElement->lo_form.x_offset < pElement->lo_form.width) &&
|
|
(Point.x - pElement->lo_form.x - pElement->lo_form.x_offset > 0) &&
|
|
(Point.y - pElement->lo_form.y - pElement->lo_form.y_offset < pElement->lo_form.height) &&
|
|
(Point.y - pElement->lo_form.y - pElement->lo_form.y_offset > 0)) {
|
|
|
|
CFormElement * pFormElement;
|
|
CNetscapeButton * pButton;
|
|
switch (pElement->lo_form.element_data->type) {
|
|
case FORM_TYPE_BUTTON:
|
|
case FORM_TYPE_RESET:
|
|
case FORM_TYPE_SUBMIT:
|
|
case FORM_TYPE_CHECKBOX:
|
|
case FORM_TYPE_RADIO:
|
|
pFormElement=(CFormElement *)pElement->lo_form.element_data->ele_minimal.FE_Data;
|
|
((CNetscapeButton *)CButton::FromHandlePermanent(pFormElement->GetRaw()))
|
|
->OnButtonEvent(CL_EVENT_MOUSE_BUTTON_UP, uFlags, cpPoint);
|
|
break;
|
|
case FORM_TYPE_FILE:
|
|
pFormElement=(CFormElement *)pElement->lo_form.element_data->ele_minimal.FE_Data;
|
|
pButton = (CNetscapeButton *)pFormElement->GetSecondaryWidget();
|
|
if (pButton)
|
|
pButton->OnButtonEvent(CL_EVENT_MOUSE_BUTTON_UP, uFlags, cpPoint);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
m_bLBDown = FALSE;
|
|
m_bLBUp = TRUE;
|
|
return;
|
|
|
|
}
|
|
|
|
// Wait to set these until we know the event hasn't be cancelled
|
|
// by JS or really meant for a form element. Remember....
|
|
m_LastMouseEvent = m_LBUp;
|
|
m_cpLBUp = cpPoint;
|
|
m_uMouseFlags = uFlags;
|
|
m_bLBDown = FALSE;
|
|
m_bLBUp = TRUE;
|
|
|
|
// JS needs screen coords for click events.
|
|
CPoint cpScreenPoint(cpPoint);
|
|
ClientToScreen(GetPane(), &cpScreenPoint);
|
|
|
|
#ifdef EDITOR
|
|
|
|
m_pStartSelectionCell = NULL;
|
|
MWContext *pMWContext = GetContext();
|
|
|
|
// Finish sizing an object only if we moved enough
|
|
if( EDT_IS_SIZING ){
|
|
// Remove last sizing feedback
|
|
DisplaySelectionFeedback(LO_ELE_SELECTED, m_rectSizing);
|
|
|
|
// We need this check or it is impossible to place a caret between
|
|
// adjacent objects)
|
|
if(abs(m_cpLBUp.x - m_cpLBDown.x) > CLICK_THRESHOLD ||
|
|
abs(m_cpLBUp.y - m_cpLBDown.y) > CLICK_THRESHOLD) {
|
|
ASSERT(cpPoint.y == Point.y - GetOriginY()); // REMOVEME
|
|
|
|
// Resize the object
|
|
EDT_EndSizing(pMWContext);
|
|
|
|
// See comment at end - shouldn't return here???
|
|
// (many other places below do return!)
|
|
goto MOUSE_TIMER;
|
|
} else {
|
|
EDT_CancelSizing(pMWContext);
|
|
// Move caret to where cursor is
|
|
EDT_StartSelection(pMWContext, Point.x, Point.y);
|
|
}
|
|
} else if(!m_bDragging && !m_bSelectingCells) {
|
|
// If within an existing selection, we didn't trigger StartSelection
|
|
// on MouseDown, so do it now
|
|
if( m_bMouseInSelection ){
|
|
if( EDT_IS_EDITOR(pMWContext) ) {
|
|
EDT_StartSelection(pMWContext, Point.x, Point.y);
|
|
} else {
|
|
#ifdef LAYERS
|
|
LO_StartSelection(GetDocumentContext(), Point.x, Point.y, layer);
|
|
#else
|
|
LO_StartSelection(GetDocumentContext(), Point.x, Point.y);
|
|
#endif /* LAYERS */
|
|
}
|
|
}
|
|
// Cleanup selection - check if start=end
|
|
if( EDT_IS_EDITOR(pMWContext) )
|
|
EDT_EndSelection(pMWContext, Point.x, Point.y);
|
|
|
|
}
|
|
if( EDT_IS_EDITOR(pMWContext) )
|
|
{
|
|
if( EDT_CanPasteStyle(pMWContext) )
|
|
{
|
|
// Apply style if available
|
|
EDT_PasteStyle(pMWContext, TRUE);
|
|
}
|
|
// Cancel any attempt to drag a table or cell
|
|
EDT_StopDragTable(pMWContext);
|
|
}
|
|
#endif // EDITOR
|
|
|
|
m_bMouseInSelection = FALSE;
|
|
m_bDragging = FALSE;
|
|
m_bSelectingCells = FALSE;
|
|
|
|
// If we previously highlighted an anchor in button down, unhighlight it.
|
|
if(m_pLastArmedAnchor != NULL) {
|
|
LO_HighlightAnchor(GetDocumentContext(), m_pLastArmedAnchor, FALSE);
|
|
m_pLastArmedAnchor = NULL;
|
|
}
|
|
|
|
// If the user moved the mouse beyond the clicking threshold, then consider
|
|
// this a text selection operation and don't continue.
|
|
if(abs(m_cpLBUp.x - m_cpLBDown.x) > CLICK_THRESHOLD ||
|
|
abs(m_cpLBUp.y - m_cpLBDown.y) > CLICK_THRESHOLD) {
|
|
return;
|
|
}
|
|
#ifdef EDITOR
|
|
// Done with possible drag image
|
|
m_pLastImageObject = NULL;
|
|
#endif
|
|
|
|
// If there's no element, there's no need to see if we should load something.
|
|
// Just send a JS Click event to the document and return.
|
|
if(pElement == NULL) {
|
|
JSEvent *event;
|
|
event = XP_NEW_ZAP(JSEvent);
|
|
event->type = EVENT_CLICK;
|
|
event->which = 1;
|
|
event->x = Point.x;
|
|
event->y = Point.y;
|
|
event->docx = Point.x + CL_GetLayerXOrigin(layer);
|
|
event->docy = Point.y + CL_GetLayerYOrigin(layer);
|
|
event->screenx = cpScreenPoint.x;
|
|
event->screeny = cpScreenPoint.y;
|
|
event->layer_id = LO_GetIdFromLayer(GetContext(), layer);
|
|
|
|
ET_SendEvent(GetContext(), NULL, event, NULL, NULL);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Control click to chase anchors in the editor
|
|
//
|
|
#ifdef EDITOR
|
|
if((uFlags & MK_CONTROL) == 0 && EDT_IS_EDITOR(GetContext())){
|
|
m_pLastImageObject = NULL;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
// It's probably we're loading.
|
|
// Figure out what we'll be sending as the referrer field.
|
|
pHist = SHIST_GetCurrent(&GetContext()->hist);
|
|
pClosure = XP_NEW_ZAP(click_closure);
|
|
pClosure->pWin = this;
|
|
pClosure->pElement = NULL;
|
|
if(pHist != NULL && pHist->address != NULL)
|
|
pClosure->szRefer = strdup(pHist->origin_url ? pHist->origin_url : pHist->address);
|
|
else
|
|
pClosure->szRefer = NULL;
|
|
|
|
// To find out what to do, switch on the element's type.
|
|
switch(pElement->type)
|
|
{
|
|
case LO_TEXT:
|
|
if(pElement->lo_text.anchor_href && pElement->lo_text.anchor_href->anchor)
|
|
{
|
|
// set tab_focus to this text element with a link.
|
|
//#52932 setFormElementTabFocus( (LO_Element *) pElement );
|
|
|
|
// if the shift-key is down save the object --- don't load it
|
|
if(uFlags & MK_SHIFT && NOT_A_DIALOG(this))
|
|
{
|
|
// Should Mocha block save operations too?
|
|
CSaveCX::SaveAnchorObject((const char *)pElement->lo_text.anchor_href->anchor, NULL);
|
|
XP_FREE(pClosure);
|
|
return;
|
|
}
|
|
|
|
// we are about to follow a link via a user click --
|
|
// tell the mocha library. Don't follow the link
|
|
// until we get to our closure
|
|
JSEvent *event;
|
|
event = XP_NEW_ZAP(JSEvent);
|
|
event->type = EVENT_CLICK;
|
|
event->which = 1;
|
|
event->x = Point.x;
|
|
event->y = Point.y;
|
|
event->docx = Point.x + CL_GetLayerXOrigin(layer);
|
|
event->docy = Point.y + CL_GetLayerYOrigin(layer);
|
|
event->screenx = cpScreenPoint.x;
|
|
event->screeny = cpScreenPoint.y;
|
|
event->layer_id = LO_GetIdFromLayer(GetContext(), layer);
|
|
|
|
ET_SendEvent(GetContext(), pElement, event, win_click_callback, pClosure);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case LO_IMAGE:
|
|
{
|
|
// Glean the FE data.
|
|
|
|
// Figure out where the click occurred.
|
|
LO_ImageStruct* pImage = &pElement->lo_image;
|
|
|
|
// Layout wants this in pixels, not FE units.
|
|
// Point is in layer coordinates, as is the position of the image
|
|
CPoint cpMap((int) (Point.x - Twips2PixX(pImage->x + pImage->x_offset + pImage->border_width)),
|
|
(int) (Point.y - Twips2PixY(pImage->y + pImage->y_offset + pImage->border_width)));
|
|
|
|
pClosure->x = cpMap.x;
|
|
pClosure->y = cpMap.y;
|
|
|
|
// Check for usemaps (client side ismaps).
|
|
if(pElement->lo_image.image_attr->usemap_name != NULL)
|
|
{
|
|
LO_AnchorData *pAnchorData = LO_MapXYToAreaAnchor(GetDocumentContext(),
|
|
&pElement->lo_image, cpMap.x, cpMap.y);
|
|
if(pAnchorData != NULL)
|
|
{
|
|
|
|
// set tab_focus to this image element with a link. todo need to get the area index
|
|
//setFormElementTabFocus( (LO_Element *) pElement );
|
|
|
|
if(uFlags & MK_SHIFT && NOT_A_DIALOG(this)) {
|
|
// Save it.
|
|
CSaveCX::SaveAnchorObject((const char *)pAnchorData->anchor, NULL);
|
|
XP_FREE(pClosure);
|
|
}
|
|
else {
|
|
LO_Element * pDummy;
|
|
|
|
// Imagemap area pretend to be links for JavaScript.
|
|
pDummy = (LO_Element *) XP_NEW_ZAP(LO_Element);
|
|
pDummy->lo_text.type = LO_TEXT;
|
|
pDummy->lo_text.anchor_href = pAnchorData;
|
|
// We use the text of the element to determine if it is still
|
|
// valid later so give the dummy text struct's text a value.
|
|
if (pDummy->lo_text.anchor_href->anchor)
|
|
pDummy->lo_text.text = pDummy->lo_text.anchor_href->anchor;
|
|
|
|
// We'll need the image element later in the callback.
|
|
pClosure->pElement = pElement;
|
|
|
|
// we are about to follow a link via a user click --
|
|
// tell the mocha library. Don't follow the link
|
|
// until we get to our closure
|
|
JSEvent *event;
|
|
event = XP_NEW_ZAP(JSEvent);
|
|
event->type = EVENT_CLICK;
|
|
event->which = 1;
|
|
event->x = Point.x;
|
|
event->y = Point.y;
|
|
event->docx = Point.x + CL_GetLayerXOrigin(layer);
|
|
event->docy = Point.y + CL_GetLayerYOrigin(layer);
|
|
event->screenx = cpScreenPoint.x;
|
|
event->screeny = cpScreenPoint.y;
|
|
event->layer_id = LO_GetIdFromLayer(GetContext(), layer);
|
|
|
|
ET_SendEvent(GetContext(), pDummy, event,
|
|
win_click_callback, pClosure);
|
|
}
|
|
// We're out, don't fall through.
|
|
return;
|
|
}
|
|
}
|
|
// Check for ismaps, normal image anchors
|
|
else if(pElement->lo_image.anchor_href != NULL &&
|
|
pElement->lo_image.anchor_href->anchor != NULL)
|
|
{
|
|
// set tab_focus to this image element with a link.
|
|
//#52932 setFormElementTabFocus( (LO_Element *) pElement );
|
|
|
|
// Ismap?
|
|
if(pElement->lo_image.image_attr->attrmask & LO_ATTR_ISMAP)
|
|
{
|
|
|
|
if(uFlags & MK_SHIFT && NOT_A_DIALOG(this))
|
|
{
|
|
char * pAnchor = PR_smprintf("%s?%d,%d",
|
|
pElement->lo_image.anchor_href->anchor, cpMap.x, cpMap.y);
|
|
CSaveCX::SaveAnchorObject(pAnchor, NULL);
|
|
XP_FREE(pClosure);
|
|
XP_FREE(pAnchor);
|
|
}
|
|
else {
|
|
// set tab_focus to this image element with a link.
|
|
//#52932 setFormElementTabFocus((LO_Element *) pElement);
|
|
|
|
// remember where we are going
|
|
pClosure->x = cpMap.x;
|
|
pClosure->y = cpMap.y;
|
|
|
|
// we are about to follow a link via a user click --
|
|
// tell the mocha library. Don't follow the link
|
|
// until we get to our closure
|
|
JSEvent *event;
|
|
event = XP_NEW_ZAP(JSEvent);
|
|
event->type = EVENT_CLICK;
|
|
event->which = 1;
|
|
event->x = Point.x;
|
|
event->y = Point.y;
|
|
event->docx = Point.x + CL_GetLayerXOrigin(layer);
|
|
event->docy = Point.y + CL_GetLayerYOrigin(layer);
|
|
event->screenx = cpScreenPoint.x;
|
|
event->screeny = cpScreenPoint.y;
|
|
event->layer_id = LO_GetIdFromLayer(GetContext(), layer);
|
|
|
|
ET_SendEvent(GetContext(), pElement, event,
|
|
win_click_callback, pClosure);
|
|
}
|
|
}
|
|
// Anchor.
|
|
else {
|
|
if(uFlags & MK_SHIFT && NOT_A_DIALOG(this)) {
|
|
// Should mocha block save operations too?
|
|
CSaveCX::SaveAnchorObject((const char *)pElement->lo_image.anchor_href->anchor, NULL);
|
|
XP_FREE(pClosure);
|
|
}
|
|
else {
|
|
// we are about to follow a link via a user click --
|
|
// tell the mocha library. Don't follow the link
|
|
// until we get to our closure
|
|
JSEvent *event;
|
|
event = XP_NEW_ZAP(JSEvent);
|
|
event->type = EVENT_CLICK;
|
|
event->which = 1;
|
|
event->x = Point.x;
|
|
event->y = Point.y;
|
|
event->docx = Point.x + CL_GetLayerXOrigin(layer);
|
|
event->docy = Point.y + CL_GetLayerYOrigin(layer);
|
|
event->screenx = cpScreenPoint.x;
|
|
event->screeny = cpScreenPoint.y;
|
|
event->layer_id = LO_GetIdFromLayer(GetContext(), layer);
|
|
|
|
ET_SendEvent(GetContext(), pElement, event,
|
|
win_click_callback, pClosure);
|
|
}
|
|
}
|
|
|
|
// We're out, don't fall through.
|
|
return;
|
|
}
|
|
|
|
// Check for images as submit buttons.
|
|
// Lot's of these on test pages, but in the real world?
|
|
if(pElement->lo_image.image_attr &&
|
|
(pElement->lo_image.image_attr->attrmask & LO_ATTR_ISFORM))
|
|
{
|
|
pClosure->x = cpMap.x;
|
|
pClosure->y = cpMap.y;
|
|
|
|
JSEvent *event;
|
|
event = XP_NEW_ZAP(JSEvent);
|
|
event->type = EVENT_SUBMIT;
|
|
event->layer_id = LO_GetIdFromLayer(GetContext(), layer);
|
|
|
|
ET_SendEvent(GetContext(), (LO_Element *)&pElement->lo_image, event,
|
|
image_form_click_callback, pClosure);
|
|
|
|
return;
|
|
}
|
|
break; // case LO_IMAGE
|
|
}
|
|
|
|
default:
|
|
// nothing doing.
|
|
XP_FREE(pClosure);
|
|
break;
|
|
}
|
|
|
|
MOUSE_TIMER:
|
|
// Have the mouse timer handler do some dirty work.
|
|
// Please don't return in the above code, I'd like this to get called
|
|
// in all cases with the state of the buttons set correctly.
|
|
MouseTimerData mt(GetContext());
|
|
FEU_MouseTimer(&mt);
|
|
}
|
|
|
|
|
|
// convert LO_Text to a bookmark object we can drag into
|
|
// the bookmark window
|
|
PRIVATE HGLOBAL
|
|
wfe_textObjectToBookmarkHandle(LO_TextStruct * text, char * title)
|
|
{
|
|
if(!text)
|
|
return(NULL);
|
|
|
|
HGLOBAL hBookmark = GlobalAlloc(GMEM_DDESHARE | GMEM_ZEROINIT, sizeof(BOOKMARKITEM));
|
|
if(!hBookmark)
|
|
return(NULL);
|
|
|
|
LPBOOKMARKITEM pBookmark = (LPBOOKMARKITEM)GlobalLock(hBookmark);
|
|
|
|
if(text->anchor_href && text->anchor_href->anchor)
|
|
PR_snprintf(pBookmark->szAnchor,sizeof(pBookmark->szAnchor),"%s",text->anchor_href->anchor);
|
|
|
|
if( title ) {
|
|
// First try to use the title supplied,
|
|
// This may contain more text than the text structure has
|
|
PR_snprintf(pBookmark->szText,sizeof(pBookmark->szText),"%s",title);
|
|
} else if(text->text) {
|
|
PR_snprintf(pBookmark->szText,sizeof(pBookmark->szText),"%s",text->text);
|
|
}
|
|
|
|
GlobalUnlock(hBookmark);
|
|
|
|
return hBookmark;
|
|
}
|
|
|
|
// Creates OLE drag data source for selected text
|
|
void CWinCX::DragSelection()
|
|
{
|
|
// Begin the drag and drop operation
|
|
// REMEMBER: OnDrop: Check if end pt is withing selection,
|
|
// if yes, ignore drop
|
|
MWContext * pMWContext = GetContext();
|
|
|
|
#ifdef EDITOR
|
|
// Don't bother if no selection or not allowed in Editor
|
|
if ( EDT_IS_EDITOR(pMWContext) &&
|
|
EDT_COP_OK != EDT_CanCopy(pMWContext, TRUE))
|
|
return;
|
|
#endif // EDITOR
|
|
|
|
// Here's where we put the data
|
|
COleDataSource * pDataSource = new COleDataSource;
|
|
// This is used to override cursors during dragging
|
|
UINT nDragType = FE_DRAG_TEXT;
|
|
#ifdef EDITOR
|
|
if( EDT_IS_EDITOR(pMWContext) )
|
|
{
|
|
nDragType = EDT_IsDraggingTable(pMWContext) ? FE_DRAG_TABLE : FE_DRAG_HTML;
|
|
}
|
|
#endif
|
|
CViewDropSource * pDropSource = new CViewDropSource(nDragType);
|
|
|
|
char* pText = NULL;
|
|
XP_HUGE_CHAR_PTR pGlobal;
|
|
XP_HUGE_CHAR_PTR pHTML;
|
|
int32 textLen = 0;
|
|
int32 htmlLen;
|
|
m_bDragging = FALSE;
|
|
#ifdef EDITOR
|
|
if( EDT_IS_EDITOR(pMWContext) ){
|
|
if( EDT_COP_OK == EDT_CanCopy(pMWContext, TRUE) &&
|
|
EDT_COP_OK == EDT_CopySelection(pMWContext, &pText, &textLen, &pHTML, &htmlLen) ){
|
|
// Put HTML-formated text in OLE data object
|
|
HGLOBAL hHTML = GlobalAlloc(GMEM_DDESHARE | GMEM_ZEROINIT, (int)htmlLen);
|
|
if(hHTML) {
|
|
pGlobal = (char *) GlobalLock(hHTML);
|
|
XP_HUGE_MEMCPY(pGlobal, pHTML, (int) htmlLen);
|
|
XP_HUGE_FREE(pHTML);
|
|
GlobalUnlock(hHTML);
|
|
pDataSource->CacheGlobalData(RegisterClipboardFormat(NETSCAPE_EDIT_FORMAT), hHTML);
|
|
m_bDragging = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
#endif // EDITOR
|
|
{
|
|
// Browser-only
|
|
pText = (char *) LO_GetSelectionText(GetDocumentContext());
|
|
if( pText )
|
|
textLen = XP_STRLEN(pText);
|
|
}
|
|
|
|
// Put unformated text in OLE data object - may be dropped in other containers
|
|
HGLOBAL hText = GlobalAlloc(GMEM_DDESHARE | GMEM_ZEROINIT, (int)textLen+1);
|
|
DROPEFFECT res = 0;
|
|
if( pText && textLen > 0 ){
|
|
#ifdef XP_WIN32
|
|
// Also try to put CF_UNICODETEXT
|
|
int datacsid = INTL_GetCSIWinCSID(LO_GetDocumentCharacterSetInfo( GetDocumentContext() )) & ~CS_AUTO;
|
|
if((CS_USER_DEFINED_ENCODING != datacsid) && (0 != datacsid))
|
|
{
|
|
int len = (INTL_StrToUnicodeLen(datacsid, (unsigned char*)pText)+1) * 2;
|
|
HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE, (DWORD) len);
|
|
if(hData)
|
|
{
|
|
unsigned char* string = (unsigned char *) GlobalLock(hData);
|
|
if(string)
|
|
{
|
|
INTL_StrToUnicode(datacsid, (unsigned char*)pText, (INTL_Unicode*)string, len);
|
|
|
|
GlobalUnlock(hData);
|
|
pDataSource->CacheGlobalData(CF_UNICODETEXT, hData);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
if(hText) {
|
|
pGlobal = (char *) GlobalLock(hText);
|
|
XP_MEMCPY(pGlobal, pText, (int) textLen+1);
|
|
XP_FREE(pText);
|
|
GlobalUnlock(hText);
|
|
pDataSource->CacheGlobalData(CF_TEXT, hText);
|
|
m_bDragging = TRUE;
|
|
}
|
|
}
|
|
|
|
if( m_bDragging ){
|
|
BOOL bWaitingMode = pMWContext->waitingMode;
|
|
// Prevent closing/interaction with source window while dragging
|
|
pMWContext->waitingMode = TRUE;
|
|
|
|
res = pDataSource->DoDragDrop(DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_SCROLL,
|
|
NULL, pDropSource);
|
|
pMWContext->waitingMode = bWaitingMode;
|
|
}
|
|
m_bDragging = FALSE;
|
|
|
|
#ifdef EDITOR
|
|
if( EDT_IS_EDITOR(pMWContext) ){
|
|
EDT_StopDragTable(pMWContext);
|
|
}
|
|
#endif
|
|
// Prevent selection-extension when finished
|
|
m_bLBDown = FALSE;
|
|
m_bLBUp = TRUE;
|
|
|
|
// its over so clean up
|
|
pDataSource->Empty();
|
|
delete pDataSource;
|
|
delete pDropSource;
|
|
}
|
|
|
|
// Triggered on button up on our bitmap on the menu
|
|
void CWinCX::CopyCurrentURL()
|
|
{
|
|
MWContext *pMWContext = GetContext();
|
|
if ( pMWContext == NULL ) {
|
|
return;
|
|
}
|
|
|
|
History_entry * hist_ent = SHIST_GetCurrent(&(pMWContext->hist));
|
|
if ( hist_ent == NULL || hist_ent->address == NULL ){
|
|
return;
|
|
}
|
|
HGLOBAL hData = GlobalAlloc(GMEM_DDESHARE | GMEM_ZEROINIT,
|
|
XP_STRLEN((char *) hist_ent->address) + 2);
|
|
if(!hData) {
|
|
return;
|
|
}
|
|
// lock the string and copy the data over
|
|
char * pString = (char *) GlobalLock(hData);
|
|
strcpy(pString, (char *) hist_ent->address);
|
|
GlobalUnlock(hData);
|
|
|
|
GetFrame()->GetFrameWnd()->OpenClipboard();
|
|
::EmptyClipboard();
|
|
::SetClipboardData(CF_TEXT, hData);
|
|
|
|
// Also copy bookmark-formatted data so we can paste full link,
|
|
// not just text, into the Editor
|
|
hData = GlobalAlloc(GMEM_DDESHARE | GMEM_ZEROINIT, sizeof(BOOKMARKITEM));
|
|
if(hData){
|
|
LPBOOKMARKITEM pBookmark = (LPBOOKMARKITEM)GlobalLock(hData);
|
|
PR_snprintf(pBookmark->szAnchor, sizeof(pBookmark->szAnchor), "%s",
|
|
hist_ent->address);
|
|
PR_snprintf(pBookmark->szText, sizeof(pBookmark->szText), "%s",
|
|
hist_ent->title);
|
|
GlobalUnlock(hData);
|
|
::SetClipboardData(RegisterClipboardFormat(NETSCAPE_BOOKMARK_FORMAT), hData);
|
|
}
|
|
::CloseClipboard();
|
|
}
|
|
|
|
// Drag from the Bitmap Menu item or URL bar icon
|
|
void CWinCX::DragCurrentURL()
|
|
{
|
|
MWContext *pMWContext = GetContext();
|
|
if ( pMWContext == NULL ) {
|
|
return;
|
|
}
|
|
|
|
History_entry * hist_ent = SHIST_GetCurrent(&(pMWContext->hist));
|
|
if ( hist_ent == NULL || hist_ent->address == NULL ){
|
|
return;
|
|
}
|
|
HGLOBAL hAddrString = GlobalAlloc(GMEM_DDESHARE | GMEM_ZEROINIT,
|
|
XP_STRLEN((char *) hist_ent->address) + 2);
|
|
if(!hAddrString) {
|
|
return;
|
|
}
|
|
|
|
// lock the string and copy the data over
|
|
char * pAddrString = (char *) GlobalLock(hAddrString);
|
|
strcpy(pAddrString, (char *) hist_ent->address);
|
|
|
|
GlobalUnlock(hAddrString);
|
|
|
|
HGLOBAL hBookmark = GlobalAlloc(GMEM_DDESHARE | GMEM_ZEROINIT, sizeof(BOOKMARKITEM));
|
|
if(!hBookmark) {
|
|
return;
|
|
}
|
|
LPBOOKMARKITEM pBookmark = (LPBOOKMARKITEM)GlobalLock(hBookmark);
|
|
PR_snprintf(pBookmark->szAnchor,sizeof(pBookmark->szAnchor),"%s",hist_ent->address);
|
|
PR_snprintf(pBookmark->szText,sizeof(pBookmark->szText),"%s",hist_ent->title);
|
|
GlobalUnlock(hBookmark);
|
|
|
|
// Create the DataSourceObject
|
|
COleDataSource * pDataSource = new COleDataSource;
|
|
pDataSource->CacheGlobalData(CF_TEXT, hAddrString);
|
|
pDataSource->CacheGlobalData(RegisterClipboardFormat(NETSCAPE_BOOKMARK_FORMAT), hBookmark);
|
|
// This is used to override cursors during dragging
|
|
CViewDropSource * pDropSource = new CViewDropSource(FE_DRAG_LINK);
|
|
|
|
DragInternetShortcut ( pDataSource,
|
|
(char*)hist_ent->title,
|
|
(char*)hist_ent->address );
|
|
|
|
// do the drag/drop operation.
|
|
// set the m_bDragging flag so that we can prevent ourseleves from dropping on
|
|
// ourselves
|
|
|
|
m_bDragging = TRUE;
|
|
// no saved image for next time
|
|
// Must do this before DoDragDrop to prevent
|
|
// arriving here again!
|
|
m_pLastImageObject = NULL;
|
|
m_pLastArmedAnchor = NULL;
|
|
|
|
// Don't start drag until outside this rect
|
|
RECT rectDragStart = {0,0,20,20};
|
|
|
|
// We supply the DropSource object instead of default behavior
|
|
// This prevents closing source frame during drag and drop
|
|
BOOL bWaitingMode = pMWContext->waitingMode;
|
|
pMWContext->waitingMode = TRUE;
|
|
|
|
pDataSource->DoDragDrop(DROPEFFECT_COPY | DROPEFFECT_LINK | DROPEFFECT_MOVE | DROPEFFECT_SCROLL,
|
|
&rectDragStart, pDropSource);
|
|
|
|
pMWContext->waitingMode = bWaitingMode;
|
|
m_bDragging = FALSE;
|
|
|
|
// After dragging, moving mouse in browser acts like button is down,
|
|
// and ugly selection extension happens. This prevents that.
|
|
m_bLBDown = FALSE;
|
|
m_bLBUp = TRUE;
|
|
|
|
// its over so clean up
|
|
pDataSource->Empty();
|
|
delete pDataSource;
|
|
delete pDropSource;
|
|
}
|
|
|
|
void wfe_Progress(MWContext *pContext, const char *pMessage);
|
|
|
|
void CWinCX::OnMouseMoveCX(UINT uFlags, CPoint cpPoint, BOOL &bReturnImmediately)
|
|
{
|
|
// Must have a view to continue.
|
|
if(GetPane() == NULL) {
|
|
return;
|
|
}
|
|
|
|
// Don't continue if this context is destroyed.
|
|
if(IsDestroyed()) {
|
|
return;
|
|
}
|
|
|
|
// This is set TRUE only by CNetscapeEditView::OnRButtonDown
|
|
// while popup menu is active
|
|
// We ignore this message else it changes cursor to something inappropriate
|
|
if( m_bInPopupMenu )
|
|
return;
|
|
|
|
// Remember....
|
|
m_LastMouseEvent = m_MMove;
|
|
m_cpMMove = cpPoint;
|
|
m_uMouseFlags = uFlags;
|
|
|
|
// Convert from screen to window coordinates
|
|
XY xyPoint;
|
|
ResolvePoint(xyPoint, cpPoint);
|
|
|
|
#ifdef LAYERS
|
|
MWContext * context = GetContext();
|
|
if (context->compositor) {
|
|
CL_Event event;
|
|
fe_EventStruct fe_event;
|
|
|
|
fe_event.uFlags = uFlags;
|
|
fe_event.x = cpPoint.x;
|
|
fe_event.y = cpPoint.y;
|
|
fe_event.pbReturnImmediately = bReturnImmediately;
|
|
|
|
event.type = CL_EVENT_MOUSE_MOVE;
|
|
event.fe_event = (void *)&fe_event;
|
|
event.fe_event_size = sizeof(fe_EventStruct);
|
|
event.x = xyPoint.x;
|
|
event.y = xyPoint.y;
|
|
event.which = 1;
|
|
event.modifiers = 0;
|
|
|
|
CL_DispatchEvent(context->compositor, &event);
|
|
}
|
|
else
|
|
OnMouseMoveForLayerCX(uFlags, cpPoint, xyPoint, NULL, bReturnImmediately);
|
|
|
|
// Have the mouse timer handler do some dirty work.
|
|
MouseTimerData mt(GetContext());
|
|
FEU_MouseTimer(&mt);
|
|
return;
|
|
}
|
|
|
|
void
|
|
CWinCX::OnMouseMoveForLayerCX(UINT uFlags, CPoint& cpPoint,
|
|
XY& xyPoint, CL_Layer *layer, BOOL &bReturnImmediately)
|
|
{
|
|
// With LAYERS turned on, the orginal method
|
|
// OnMouseMoveCX is separated into two methods,
|
|
// one of which is a per-layer method.
|
|
#endif /* LAYERS */
|
|
|
|
MWContext * context = GetContext();
|
|
|
|
BOOL bTextSet = FALSE;
|
|
|
|
LO_Element *pElement = GetLayoutElement(xyPoint, layer);
|
|
if (pElement && (pElement->type == LO_IMAGE)) {
|
|
LO_ImageStruct* pImage = &pElement->lo_image;
|
|
if (pImage) {
|
|
CreateToolTip(pImage, cpPoint, layer);
|
|
RelayToolTipEvent(cpPoint, WM_MOUSEMOVE);
|
|
}
|
|
}
|
|
|
|
int32 xVal = xyPoint.x;
|
|
int32 yVal = xyPoint.y;
|
|
|
|
// don't do anything if we are waiting for the netlib to get
|
|
// into gear
|
|
if (context->waitingMode) {
|
|
// Change cursor only if not doing internal drag
|
|
if( !m_bDragging ){
|
|
SetCursor(theApp.LoadStandardCursor(IDC_WAIT));
|
|
}
|
|
return; // can't load while loading
|
|
}
|
|
|
|
// Note: don't use (uFlags & MK_LBUTTON) because this is
|
|
// reported as TRUE on a mouse move message
|
|
// following a click off of a dialog or popup menu
|
|
//
|
|
if ( m_bLBDown )
|
|
{
|
|
#ifdef EDITOR
|
|
// If we are selecting cells, skip the rest
|
|
if( m_bSelectingCells )
|
|
{
|
|
// We must fire an event to setup CLOSURE struct
|
|
// and call mouse_closure_callback
|
|
FireMouseOverEvent(NULL, xVal, yVal, layer);
|
|
goto MOUSE_TIMER;
|
|
}
|
|
if( EDT_IS_SIZING )
|
|
{
|
|
// We are sizing
|
|
|
|
BOOL bLock = !(BOOL)(uFlags & MK_CONTROL);
|
|
XP_Rect new_rect;
|
|
if( EDT_GetSizingRect(context, xVal, yVal, bLock, &new_rect) )
|
|
{
|
|
// Remove last sizing feedback
|
|
DisplaySelectionFeedback(LO_ELE_SELECTED, m_rectSizing);
|
|
// Save the new rect.
|
|
m_rectSizing.left = new_rect.left;
|
|
m_rectSizing.right = new_rect.right;
|
|
m_rectSizing.top = new_rect.top;
|
|
m_rectSizing.bottom = new_rect.bottom;
|
|
// then draw new feedback
|
|
DisplaySelectionFeedback(LO_ELE_SELECTED, m_rectSizing);
|
|
|
|
}
|
|
// Status text was set by XP code, so set flag here
|
|
bTextSet = TRUE;
|
|
goto MOUSE_TIMER;
|
|
}
|
|
// Check for cell selection only if not starting drag of table cells
|
|
if( !EDT_IsDraggingTable(context) )
|
|
{
|
|
// We are not currently selecting cells, so get the cell we may be over
|
|
// Note: This will return cell and ED_HIT_SIZE_COL if inbetween columns,
|
|
// so check that because we don't want to select cell if just before the left edge
|
|
LO_Element *pCellElement = NULL;
|
|
// Mouse move test with left button down - extend selection to other cells
|
|
ED_HitType iTableHit = EDT_GetTableHitRegion(context, xVal, yVal, &pCellElement, FALSE);
|
|
if( m_pStartSelectionCell && pCellElement &&
|
|
(iTableHit != ED_HIT_SIZE_COL) &&
|
|
pCellElement->type == LO_CELL && (pCellElement != m_pStartSelectionCell) )
|
|
{
|
|
m_bSelectingCells = TRUE;
|
|
if( m_pStartSelectionCell )
|
|
{
|
|
// Mouse is in a different cell then when we started selecting
|
|
// So switch to cell-selection mode.
|
|
// 1st FALSE param means clear any other selection (shouldn't be any)
|
|
// (last param is used to extend selection)
|
|
EDT_SelectTableElement(context, m_pStartSelectionCell->lo_any.x, m_pStartSelectionCell->lo_any.y,
|
|
m_pStartSelectionCell, ED_HIT_SEL_CELL, FALSE, FALSE);
|
|
}
|
|
// Select new cell as well: If previously selecting, last param = TRUE
|
|
// and we append this cell
|
|
EDT_SelectTableElement(context, xVal, yVal, pCellElement, ED_HIT_SEL_CELL,
|
|
FALSE, m_pStartSelectionCell != NULL);
|
|
goto MOUSE_TIMER;
|
|
}
|
|
}
|
|
#endif // EDITOR
|
|
|
|
// Don't bother to do selection or dragging unless we actually moved
|
|
if( (abs(cpPoint.x - m_cpLBDown.x) > 5)
|
|
|| (abs(cpPoint.y - m_cpLBDown.y) > 5) )
|
|
{
|
|
if( m_bMouseInSelection )
|
|
{
|
|
// release the mouse capture
|
|
::ReleaseCapture();
|
|
m_bMouseInSelection = FALSE;
|
|
|
|
// Get and drag the selection
|
|
DragSelection();
|
|
// Don't do anything else if we are dragging!
|
|
goto MOUSE_TIMER;
|
|
}
|
|
// Extend the selection
|
|
#ifdef EDITOR
|
|
if( EDT_IS_EDITOR(context) )
|
|
{
|
|
EDT_ExtendSelection(context, xVal, yVal);
|
|
} else
|
|
#endif // EDITOR
|
|
{
|
|
LO_ExtendSelection(GetDocumentContext(), xVal, yVal);
|
|
}
|
|
}
|
|
|
|
int32 lYPos = GetOriginY();
|
|
int32 lXPos = GetOriginX();
|
|
int32 xCur = xVal;
|
|
int32 yCur = yVal;
|
|
#ifdef LAYERS
|
|
if (layer)
|
|
{
|
|
int32 layer_x_offset = CL_GetLayerXOrigin(layer);
|
|
int32 layer_y_offset = CL_GetLayerYOrigin(layer);
|
|
|
|
xCur += layer_x_offset;
|
|
yCur += layer_y_offset;
|
|
}
|
|
#endif // LAYERS
|
|
if(xCur < GetOriginX()) {
|
|
lXPos = xCur;
|
|
}
|
|
else if(xCur > GetWidth() + GetOriginX()) {
|
|
lXPos = xCur - GetWidth();
|
|
}
|
|
|
|
if(yCur < GetOriginY()) {
|
|
lYPos = yCur;
|
|
}
|
|
else if(yVal > GetHeight() + GetOriginY()) {
|
|
lYPos = yCur - GetHeight();
|
|
}
|
|
|
|
// Validate position recommendations, and reposition if necessary.
|
|
if(lXPos > GetDocumentWidth() - GetWidth()) {
|
|
lXPos = GetDocumentWidth() - GetWidth();
|
|
}
|
|
if(lXPos < 0) {
|
|
lXPos = GetOriginX();
|
|
}
|
|
if(lYPos > GetDocumentHeight() - GetHeight()) {
|
|
lYPos = GetDocumentHeight() - GetHeight();
|
|
}
|
|
if(lYPos < 0) {
|
|
lYPos = GetOriginY();
|
|
}
|
|
|
|
if(lYPos != GetOriginY() || lXPos != GetOriginX()) {
|
|
// Reposition.
|
|
SetDocPosition(context, FE_VIEW, lXPos, lYPos);
|
|
}
|
|
|
|
// We need to unhighlight an anchor if we highlighted it on buttonDown
|
|
// The anchor element is held within the last_armed_xref global
|
|
// If last_armed_xref is non-null then the anchor is highlighted and
|
|
// needs to be unhighlighted and a drag and drop operation started.
|
|
if( m_pLastArmedAnchor && !EDT_IS_EDITOR(context) ) {
|
|
if(abs(m_cpMMove.x - m_cpLBDown.x) > CLICK_THRESHOLD ||
|
|
abs(m_cpMMove.y - m_cpLBDown.y) > CLICK_THRESHOLD) {
|
|
|
|
LO_HighlightAnchor(GetDocumentContext(), m_pLastArmedAnchor, FALSE);
|
|
|
|
// Convert the selection into stuff other people can understand
|
|
|
|
LO_TextStruct * text = (LO_TextStruct *) m_pLastArmedAnchor;
|
|
if(!text)
|
|
goto MOUSE_TIMER;
|
|
|
|
int len = XP_STRLEN((char *) text->anchor_href->anchor) + 2;
|
|
|
|
// make an assumption that will bite us later. Shove everything into
|
|
// global space cuz it will be small
|
|
HGLOBAL hAddrString = GlobalAlloc(GMEM_DDESHARE | GMEM_ZEROINIT, len);
|
|
if(!hAddrString)
|
|
goto MOUSE_TIMER;
|
|
|
|
// lock the string and copy the data over
|
|
char * pAddrString = (char *) GlobalLock(hAddrString);
|
|
strcpy(pAddrString, (char *) text->anchor_href->anchor);
|
|
|
|
GlobalUnlock(hAddrString);
|
|
|
|
//CLM: Select the full link object, which scans neighboring text elements
|
|
// to gather text that may have different formatting but same HREF
|
|
XY Point;
|
|
ResolvePoint(Point, m_cpLBDown);
|
|
#ifdef LAYERS
|
|
LO_SelectObject(GetDocumentContext(), Point.x, Point.y, NULL);
|
|
#else
|
|
LO_SelectObject(GetDocumentContext(), Point.x, Point.y);
|
|
#endif /* LAYERS */
|
|
// check to see if its an address book url. If it is convert it to
|
|
// vcard clipboard format
|
|
COleDataSource * pDataSource = NULL;
|
|
CViewDropSource * pDropSource = NULL;
|
|
char * url = (char*) text->anchor_href->anchor;
|
|
char * path = NET_ParseURL((char *) text->anchor_href->anchor, GET_PATH_PART);
|
|
char * search = NET_ParseURL((char *) text->anchor_href->anchor, GET_SEARCH_PART);
|
|
if (!XP_STRNCASECMP(path,"add",3)) {
|
|
if (!XP_STRNCASECMP (search, "?vcard=", 7)) {
|
|
// Create the DataSourceObject
|
|
CLIPFORMAT mVcardClipboardFormat = (CLIPFORMAT)RegisterClipboardFormat(vCardClipboardFormat);
|
|
char * escVcard = XP_STRDUP (search+7);
|
|
if (escVcard) {
|
|
escVcard = NET_UnEscape(escVcard);
|
|
HANDLE hString = 0;
|
|
hString = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE|GMEM_ZEROINIT,strlen(escVcard)+1);
|
|
LPSTR lpszString = (LPSTR)GlobalLock(hString);
|
|
strcpy(lpszString, escVcard);
|
|
GlobalUnlock(hString);
|
|
XP_FREEIF (escVcard);
|
|
pDataSource = new COleDataSource;
|
|
pDataSource->CacheGlobalData(mVcardClipboardFormat, hString);
|
|
pDataSource->CacheGlobalData(CF_TEXT, hString);
|
|
pDropSource = new CViewDropSource(FE_DRAG_VCARD);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
|
|
char *pFullLink = (char *) LO_GetSelectionText(GetDocumentContext());
|
|
|
|
HGLOBAL hBookmark = wfe_textObjectToBookmarkHandle(text, pFullLink);
|
|
|
|
// make sure we have a bookmark format defined
|
|
CLIPFORMAT mBookmarkClipboardFormat = (CLIPFORMAT)RegisterClipboardFormat(NETSCAPE_BOOKMARK_FORMAT);
|
|
|
|
// Create the DataSourceObject
|
|
pDataSource = new COleDataSource;
|
|
pDataSource->CacheGlobalData(CF_TEXT, hAddrString);
|
|
pDataSource->CacheGlobalData(mBookmarkClipboardFormat, hBookmark);
|
|
|
|
// This is used to override cursors during dragging
|
|
pDropSource = new CViewDropSource(FE_DRAG_LINK);
|
|
|
|
DragInternetShortcut ( pDataSource,
|
|
pFullLink ? pFullLink : (char*)text->text,
|
|
(char*)text->anchor_href->anchor );
|
|
}
|
|
|
|
// do the drag/drop operation.
|
|
// set the m_bDragging flag so that we can prevent ourseleves from dropping on
|
|
// ourselves
|
|
m_bDragging = TRUE;
|
|
// Must do this before DoDragDrop to prevent
|
|
// arriving here again!
|
|
m_pLastArmedAnchor = NULL;
|
|
m_pLastImageObject = NULL;
|
|
|
|
// This prevents closing source frame during drag and drop
|
|
BOOL bWaitingMode = context->waitingMode;
|
|
context->waitingMode = TRUE;
|
|
|
|
// We supply the DropSource object instead of default behavior
|
|
// (we don't need return value, do we?)
|
|
pDataSource->DoDragDrop(DROPEFFECT_COPY | DROPEFFECT_LINK | DROPEFFECT_MOVE | DROPEFFECT_SCROLL,
|
|
NULL, pDropSource);
|
|
|
|
context->waitingMode = bWaitingMode;
|
|
m_bDragging = FALSE;
|
|
|
|
// After dragging, moving mouse in browser acts like button is down,
|
|
// and ugly selection extension happens. This prevents that.
|
|
m_bLBDown = FALSE;
|
|
m_bLBUp = TRUE;
|
|
|
|
// its over so clean up
|
|
pDataSource->Empty();
|
|
delete pDataSource;
|
|
delete pDropSource;
|
|
}
|
|
}
|
|
#ifdef EDITOR
|
|
// Drag image from an Editor or Browser
|
|
else if ( m_pLastImageObject &&
|
|
(abs(m_cpMMove.x - m_cpLBDown.x) > CLICK_THRESHOLD ||
|
|
abs(m_cpMMove.y - m_cpLBDown.y) > CLICK_THRESHOLD) ) {
|
|
|
|
LO_ImageStruct *pImage = (LO_ImageStruct *)m_pLastImageObject;
|
|
char *pImageURL = NULL;
|
|
|
|
HGLOBAL hImageData = WFE_CreateCopyImageData(context, pImage);
|
|
if ( hImageData ) {
|
|
|
|
// make sure we have a clipboard format defined
|
|
CLIPFORMAT mImageFormat = (CLIPFORMAT)RegisterClipboardFormat(
|
|
NETSCAPE_IMAGE_FORMAT);
|
|
|
|
// Create the DataSourceObject
|
|
COleDataSource * pDataSource = new COleDataSource;
|
|
pDataSource->CacheGlobalData(mImageFormat, hImageData);
|
|
|
|
// This is used to override cursors during dragging
|
|
CViewDropSource * pDropSource = new CViewDropSource(FE_DRAG_IMAGE);
|
|
|
|
// do the drag/drop operation.
|
|
// set the m_bDragging flag so that we can prevent ourseleves from dropping on
|
|
// ourselves
|
|
m_bDragging = TRUE;
|
|
// no saved image for next time
|
|
m_pLastImageObject = NULL;
|
|
m_pLastArmedAnchor = NULL;
|
|
|
|
//Weird problem:
|
|
// Return from dropping after InsertImage
|
|
// sometimes results in hourglass cursor
|
|
// So save and restore after DoDragDrop
|
|
HCURSOR hCursor = GetCursor();
|
|
|
|
// This prevents closing source frame during drag and drop
|
|
BOOL bWaitingMode = context->waitingMode;
|
|
context->waitingMode = TRUE;
|
|
|
|
pDataSource->DoDragDrop(DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_SCROLL,
|
|
NULL, pDropSource);
|
|
|
|
context->waitingMode = bWaitingMode;
|
|
SetCursor(hCursor);
|
|
m_bDragging = FALSE;
|
|
|
|
// Prevent selection mode when returning to browser
|
|
m_bLBDown = FALSE;
|
|
m_bLBUp = TRUE;
|
|
|
|
// its over so clean up
|
|
pDataSource->Empty();
|
|
delete pDataSource;
|
|
delete pDropSource;
|
|
}
|
|
}
|
|
#endif // EDITOR
|
|
}
|
|
else { // Left button is not down...
|
|
|
|
// If there are connections being initiated (i.e. the watch
|
|
// cursor is up) don't blow away the text so that the netlib
|
|
// messages persist in the status bar
|
|
if(context->waitingMode)
|
|
goto MOUSE_TIMER;
|
|
|
|
#ifdef LAYERS
|
|
LO_Element *lo_element = LO_XYToElement(GetDocumentContext(), xVal, yVal, layer);
|
|
#else
|
|
LO_Element *lo_element = LO_XYToElement(GetDocumentContext(), xVal, yVal);
|
|
#endif /* LAYERS */
|
|
|
|
// Handle mouse over event processing with back end libs.
|
|
if(!bTextSet) {
|
|
// Let the backend take a crack at handling the text
|
|
FireMouseOverEvent(lo_element,xVal, yVal, layer);
|
|
|
|
// if the backend didn't set the text we will set the
|
|
// text in our closure --- don't do anything else
|
|
// in this routine
|
|
}
|
|
}
|
|
|
|
MOUSE_TIMER:
|
|
// Have the mouse timer handler do some dirty work.
|
|
// Please don't return in the above code, I'd like this to get called
|
|
// in all cases with the state of the buttons set correctly.
|
|
MouseTimerData mt(context);
|
|
FEU_MouseTimer(&mt);
|
|
|
|
}
|
|
|
|
void CWinCX::OnRButtonDblClkCX(UINT uFlags, CPoint cpPoint) {
|
|
// Only do this if clicking is enabled.
|
|
if(IsClickingEnabled() == FALSE) {
|
|
return;
|
|
}
|
|
|
|
// Don't continue if this context is destroyed.
|
|
if(IsDestroyed()) {
|
|
return;
|
|
}
|
|
|
|
XY xyPoint;
|
|
ResolvePoint(xyPoint, cpPoint);
|
|
|
|
if (GetContext()->compositor) {
|
|
CL_Event event;
|
|
fe_EventStruct fe_event;
|
|
|
|
fe_event.uFlags = uFlags;
|
|
fe_event.x = cpPoint.x;
|
|
fe_event.y = cpPoint.y;
|
|
|
|
event.type = CL_EVENT_MOUSE_BUTTON_MULTI_CLICK;
|
|
event.fe_event = (void *)&fe_event;
|
|
event.fe_event_size = sizeof(fe_EventStruct);
|
|
event.x = xyPoint.x;
|
|
event.y = xyPoint.y;
|
|
event.modifiers = (uFlags & MK_SHIFT ? EVENT_SHIFT_MASK : 0)
|
|
| (uFlags & MK_CONTROL ? EVENT_CONTROL_MASK : 0)
|
|
| (GetKeyState(VK_MENU) < 0 ? EVENT_ALT_MASK : 0);
|
|
event.which = 3;
|
|
event.data = 2;
|
|
|
|
CL_DispatchEvent(GetContext()->compositor, &event);
|
|
}
|
|
else
|
|
OnRButtonDblClkForLayerCX(uFlags, cpPoint, xyPoint, NULL);
|
|
|
|
|
|
// Have the mouse timer handler do some dirty work.
|
|
// Please don't return in the above code, I'd like this to get called
|
|
// in all cases with the state of the buttons set correctly.
|
|
MouseTimerData mt(GetContext());
|
|
FEU_MouseTimer(&mt);
|
|
}
|
|
|
|
void
|
|
CWinCX::OnRButtonDblClkForLayerCX(UINT uFlags, CPoint& cpPoint,
|
|
XY& Point, CL_Layer *layer)
|
|
{
|
|
// With LAYERS turned on, the orginal method
|
|
// OnRButtonDblClkCX is separated into two methods,
|
|
// one of which is a per-layer method.
|
|
|
|
// Remember....
|
|
m_LastMouseEvent = m_RBDClick;
|
|
m_cpRBDClick = cpPoint;
|
|
m_uMouseFlags = uFlags;
|
|
}
|
|
|
|
void CWinCX::OnRButtonDownCX(UINT uFlags, CPoint cpPoint)
|
|
{
|
|
RelayToolTipEvent(cpPoint, WM_RBUTTONDOWN);
|
|
|
|
MWContext * pMWContext = GetContext();
|
|
|
|
// Only do this if clicking is enabled, we have a context,
|
|
// or context is not destoyed
|
|
if(IsClickingEnabled() == FALSE ||
|
|
pMWContext == NULL ||
|
|
IsDestroyed()) {
|
|
return;
|
|
}
|
|
|
|
XY xyPoint;
|
|
ResolvePoint(xyPoint, cpPoint);
|
|
|
|
#ifdef LAYERS
|
|
if (pMWContext->compositor) {
|
|
CL_Event event;
|
|
fe_EventStruct fe_event;
|
|
|
|
fe_event.uFlags = uFlags;
|
|
fe_event.x = cpPoint.x;
|
|
fe_event.y = cpPoint.y;
|
|
|
|
event.type = CL_EVENT_MOUSE_BUTTON_DOWN;
|
|
event.fe_event = (void *)&fe_event;
|
|
event.fe_event_size = sizeof(fe_EventStruct);
|
|
event.x = xyPoint.x;
|
|
event.y = xyPoint.y;
|
|
event.modifiers = (uFlags & MK_SHIFT ? EVENT_SHIFT_MASK : 0)
|
|
| (uFlags & MK_CONTROL ? EVENT_CONTROL_MASK : 0)
|
|
| (GetKeyState(VK_MENU) < 0 ? EVENT_ALT_MASK : 0);
|
|
event.which = 3;
|
|
|
|
CL_DispatchEvent(pMWContext->compositor, &event);
|
|
}
|
|
else
|
|
OnRButtonDownForLayerCX(uFlags, cpPoint, xyPoint, NULL);
|
|
|
|
// Have the mouse timer handler do some dirty work.
|
|
MouseTimerData mt(pMWContext);
|
|
FEU_MouseTimer(&mt);
|
|
return;
|
|
}
|
|
|
|
BOOL
|
|
CWinCX::OnRButtonDownForLayerCX(UINT uFlags, CPoint& cpPoint,
|
|
XY& Point, CL_Layer *layer)
|
|
{
|
|
// With LAYERS turned on, the orginal method
|
|
// OnRButtonDownCX is separated into two methods,
|
|
// one of which is a per-layer method.
|
|
#endif /* LAYERS */
|
|
// Remember....
|
|
m_LastMouseEvent = m_RBDown;
|
|
m_cpRBDown = cpPoint;
|
|
m_uMouseFlags = uFlags;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void CWinCX::OnRButtonUpCX(UINT uFlags, CPoint cpPoint)
|
|
{
|
|
RelayToolTipEvent(cpPoint, WM_RBUTTONUP);
|
|
|
|
// Only do this if clicking is enabled.
|
|
if(IsClickingEnabled() == FALSE) {
|
|
return;
|
|
}
|
|
|
|
// Don't continue if this context is destroyed.
|
|
if(IsDestroyed()) {
|
|
return;
|
|
}
|
|
|
|
XY xyPoint;
|
|
ResolvePoint(xyPoint, cpPoint);
|
|
|
|
if (GetContext()->compositor) {
|
|
CL_Event event;
|
|
fe_EventStruct fe_event;
|
|
|
|
fe_event.uFlags = uFlags;
|
|
fe_event.x = cpPoint.x;
|
|
fe_event.y = cpPoint.y;
|
|
|
|
event.type = CL_EVENT_MOUSE_BUTTON_UP;
|
|
event.fe_event = (void *)&fe_event;
|
|
event.fe_event_size = sizeof(fe_EventStruct);
|
|
event.x = xyPoint.x;
|
|
event.y = xyPoint.y;
|
|
event.modifiers = (uFlags & MK_SHIFT ? EVENT_SHIFT_MASK : 0)
|
|
| (uFlags & MK_CONTROL ? EVENT_CONTROL_MASK : 0)
|
|
| (GetKeyState(VK_MENU) < 0 ? EVENT_ALT_MASK : 0);
|
|
event.which = 3;
|
|
|
|
CL_DispatchEvent(GetContext()->compositor, &event);
|
|
}
|
|
else
|
|
OnRButtonUpForLayerCX(uFlags, cpPoint, xyPoint, NULL);
|
|
|
|
// Have the mouse timer handler do some dirty work.
|
|
// Please don't return in the above code, I'd like this to get called
|
|
// in all cases with the state of the buttons set correctly.
|
|
MouseTimerData mt(GetContext());
|
|
FEU_MouseTimer(&mt);
|
|
}
|
|
|
|
void
|
|
CWinCX::OnRButtonUpForLayerCX(UINT uFlags, CPoint& cpPoint,
|
|
XY& Point, CL_Layer *layer)
|
|
{
|
|
// With LAYERS turned on, the orginal method
|
|
// OnRButtonUpCX is separated into two methods,
|
|
// one of which is a per-layer method.
|
|
|
|
// Remember....
|
|
m_LastMouseEvent = m_RBUp;
|
|
m_cpLBUp = cpPoint;
|
|
m_uMouseFlags = uFlags;
|
|
}
|
|
|
|
CWnd *CWinCX::GetDialogOwner() const {
|
|
CGenericView *pView = m_pGenView;
|
|
CWnd *pOwner = NULL;
|
|
CWnd *pWnd;
|
|
|
|
if(pView) {
|
|
pOwner = pView->GetOwner();
|
|
}
|
|
|
|
if(pOwner == NULL) {
|
|
// No owner, we must take it.
|
|
CWnd * pWnd = pView->GetParentFrame();
|
|
if (pWnd)
|
|
pOwner = pWnd;
|
|
pOwner = (CWnd *)pView;
|
|
}
|
|
pWnd = pOwner->GetParentFrame();
|
|
if (pWnd)
|
|
pOwner = pWnd;
|
|
|
|
// When a modal dialog (usually a preference dialog) is active,
|
|
// it should be the message diaolg's parent,
|
|
// else user can loose alert message behind it and user can interact
|
|
// with preference dialog with bad consequences!
|
|
return(pOwner->GetLastActivePopup());
|
|
}
|
|
|
|
int CWinCX::GetUrl(URL_Struct *pUrl, FO_Present_Types iFormatOut, BOOL bReallyLoading, BOOL bForceNew)
|
|
{
|
|
// If we are POSTing data (publishing), or forcing a new page, don't ask user to save current page first
|
|
// If user cancels when being prompted to save current document, return without action
|
|
#ifdef EDITOR
|
|
if ( !bForceNew && pUrl->method != URL_POST_METHOD
|
|
&& !FE_CheckAndSaveDocument(GetContext())
|
|
) {
|
|
return( MK_NO_ACTION );
|
|
}
|
|
#endif // EDITOR
|
|
// ResetToolTipImg();
|
|
|
|
#ifdef EDITOR
|
|
#ifdef XP_WIN32
|
|
// If we are talking to LiveWire communications system,
|
|
// tell Site Manager we are about to load a new URL
|
|
// if we are NOT simply creating a new document
|
|
if ( GetContext() &&
|
|
pUrl && pUrl->address &&
|
|
0 != XP_STRCMP(pUrl->address, EDT_NEW_DOC_URL) &&
|
|
bSiteMgrIsActive ) {
|
|
pITalkSMClient->LoadingURL(pUrl->address);
|
|
}
|
|
#endif // XP_WIN32
|
|
#endif // EDITOR
|
|
|
|
// Enable the wait cursor.
|
|
SetCursor(theApp.LoadStandardCursor(IDC_WAIT));
|
|
|
|
// We need to disable/deactivate any embedded items.
|
|
OnDeactivateEmbedCX();
|
|
|
|
#ifdef EDITOR
|
|
if( EDT_IS_EDITOR(GetContext()) ){
|
|
FE_DestroyCaret(GetContext());
|
|
}
|
|
#endif
|
|
//Caret will be shown automatically after new URL is loaded
|
|
// Save the frame's URL bar text.
|
|
// We use this to determine wether or not the user has
|
|
// changed the URL bar since the new load began, if
|
|
// if so, we won't blow away what they've typed.
|
|
|
|
if(GetContext()->type == MWContextBrowser && !EDT_IS_EDITOR(GetContext())){
|
|
IChrome *pChrome = GetFrame()->GetChrome();
|
|
CWnd *pWnd = pChrome ? pChrome->GetToolbar(ID_LOCATION_TOOLBAR) : NULL;
|
|
|
|
if (pWnd && pWnd->IsKindOf(RUNTIME_CLASS(CURLBar))){
|
|
CURLBar *pUrlBar = (CURLBar *) pWnd;
|
|
|
|
if(pUrlBar != NULL)
|
|
pUrlBar->m_pBox->GetWindowText(m_csSaveLocationBarText);
|
|
else
|
|
m_csSaveLocationBarText.Empty();
|
|
}
|
|
else
|
|
m_csSaveLocationBarText.Empty();
|
|
}
|
|
else
|
|
m_csSaveLocationBarText.Empty();
|
|
// For dialog context's, we want to raise them to the top when they
|
|
// begin a load (view source, doc info, html dialogs).
|
|
if(GetContext()->type == MWContextDialog && GetFrame()->GetFrameWnd() != NULL &&
|
|
GetFrame()->GetFrameWnd()->IsWindowEnabled()) {
|
|
// Bring it to the front.
|
|
GetFrame()->GetFrameWnd()->BringWindowToTop();
|
|
|
|
// Now if it was an icon, bring it back up.
|
|
if(GetFrame()->GetFrameWnd()->IsIconic()) {
|
|
GetFrame()->GetFrameWnd()->ShowWindow(SW_RESTORE);
|
|
}
|
|
}
|
|
|
|
|
|
// Call the base.
|
|
return(CPaneCX::GetUrl(pUrl, iFormatOut, bReallyLoading, bForceNew));
|
|
}
|
|
|
|
CNSToolTip* CWinCX::CreateToolTip(LO_ImageStruct* pImage, CPoint& cpPoint, CL_Layer *layer)
|
|
{
|
|
// Added tool tip to the image.
|
|
if ((!pImage || !pImage->image_attr) ) return NULL; // image is not ready yet.
|
|
|
|
// Layout wants this in pixels, not FE units.
|
|
LTRB Rect;
|
|
ResolveElement(Rect, IL_GetImagePixmap(pImage->image_req), pImage->x_offset, pImage->y_offset,
|
|
pImage->x, pImage->y, pImage->width, pImage->height, 0, 0);
|
|
CPoint cpMap((int) (cpPoint.x - Twips2PixX(Rect.left)),
|
|
(int) (cpPoint.y - Twips2PixY(Rect.top)));
|
|
char* alt_text;
|
|
lo_MapRec *map;
|
|
lo_MapAreaRec_struct* loMapRec;
|
|
LO_AnchorData *pAnchorData = LO_MapXYToAreaAnchor(GetDocumentContext(), pImage,
|
|
cpMap.x, cpMap.y);
|
|
|
|
if(pImage == pLastToolTipImg && m_pLastToolTipAnchor == pAnchorData)
|
|
{
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if(pAnchorData != NULL)
|
|
PA_LOCK(alt_text, char *, pAnchorData->alt);
|
|
else
|
|
PA_LOCK(alt_text, char *, pImage->alt);
|
|
|
|
pLastToolTipImg = pImage;
|
|
m_pLastToolTipAnchor = pAnchorData;
|
|
delete m_ToolTip;
|
|
|
|
if (alt_text && (*alt_text)) {
|
|
|
|
m_ToolTip = new CNSToolTip();
|
|
|
|
m_ToolTip->Create(CWnd::FromHandle(GetPane()), TTS_ALWAYSTIP);
|
|
if (::IsWindow(m_ToolTip->GetSafeHwnd())){
|
|
m_ToolTip->SetCSID( INTL_GetCSIWinCSID(LO_GetDocumentCharacterSetInfo( GetDocumentContext() )));
|
|
CRect rect(0, 0, 30, 10);
|
|
m_ToolTip->AddTool(CWnd::FromHandle(GetPane()), "", &rect, 1);
|
|
m_ToolTip->Activate(TRUE);
|
|
m_ToolTip->SetDelayTime(250);
|
|
if(pAnchorData != NULL) {
|
|
map = (lo_MapRec*)pImage->image_attr->usemap_ptr;
|
|
loMapRec = map->areas;
|
|
BOOL done = FALSE;
|
|
int tempPoint[4];
|
|
|
|
while (loMapRec != map->areas_last) {
|
|
if (loMapRec->anchor == pAnchorData && loMapRec->coords) {
|
|
tempPoint[0] = *(loMapRec->coords);
|
|
tempPoint[1] = *(loMapRec->coords+1);
|
|
tempPoint[2] = *(loMapRec->coords+2);
|
|
tempPoint[3] = *(loMapRec->coords+3);
|
|
m_ToolTip->SetBounding(tempPoint, loMapRec->coord_cnt, pImage->x, pImage->y);
|
|
break;
|
|
}
|
|
loMapRec = loMapRec->next;
|
|
}
|
|
if ((loMapRec == map->areas_last) && (loMapRec->anchor == pAnchorData) &&
|
|
loMapRec->coords) {
|
|
tempPoint[0] = *(loMapRec->coords);
|
|
tempPoint[1] = *(loMapRec->coords+1);
|
|
tempPoint[2] = *(loMapRec->coords+2);
|
|
tempPoint[3] = *(loMapRec->coords+3);
|
|
m_ToolTip->SetBounding(tempPoint, loMapRec->coord_cnt, pImage->x, pImage->y);
|
|
}
|
|
}
|
|
else {
|
|
RECT rect;
|
|
::SetRect(&rect, CASTINT(pImage->x - GetOriginX()),
|
|
CASTINT(pImage->y - GetOriginY()),
|
|
CASTINT(pImage->x - GetOriginX() + pImage->width),
|
|
CASTINT(pImage->y - GetOriginY() + pImage->height));
|
|
int32 x_offset = CL_GetLayerXOrigin(layer);
|
|
int32 y_offset = CL_GetLayerYOrigin(layer);
|
|
|
|
::OffsetRect(&rect, (int)x_offset, (int)y_offset);
|
|
m_ToolTip->SetBounding((int*)&rect, 4);
|
|
}
|
|
m_ToolTip->UpdateTipText(alt_text, CWnd::FromHandle(GetPane()), 1);
|
|
}
|
|
else {
|
|
delete m_ToolTip;
|
|
m_ToolTip = NULL;
|
|
}
|
|
}
|
|
else
|
|
m_ToolTip = NULL;
|
|
if(pAnchorData != NULL)
|
|
PA_UNLOCK(pAnchorData->alt);
|
|
else
|
|
PA_UNLOCK(pImage->alt);
|
|
return m_ToolTip;
|
|
}
|
|
|
|
void CWinCX::ClipChildren(CWnd *pWnd, BOOL bSet)
|
|
{
|
|
CFrameGlue *pGlue = GetFrame();
|
|
if (pGlue) {
|
|
pGlue->ClipChildren(pWnd, bSet);
|
|
}
|
|
}
|
|
#ifdef DDRAW
|
|
void CWinCX::BltToScreen(LTRB& rect, DDBLTFX* fx)
|
|
{
|
|
if (m_physicWinRect.IsEmpty())
|
|
CalcWinPos();
|
|
|
|
if (m_lpDDSPrimary) {
|
|
RECT destRect;
|
|
RECT rcRect;
|
|
destRect.left = rect.left + GetWindowsXPos();
|
|
destRect.top = rect.top + GetWindowsYPos();
|
|
destRect.right = rect.right + GetWindowsXPos();
|
|
destRect.bottom = rect.bottom + GetWindowsYPos();
|
|
if (destRect.bottom > m_physicWinRect.bottom) {
|
|
destRect.bottom = m_physicWinRect.bottom;
|
|
}
|
|
if (destRect.right > m_physicWinRect.right) {
|
|
destRect.right = m_physicWinRect.right;
|
|
}
|
|
if (destRect.top > destRect.bottom) { // for scrolling case
|
|
destRect.top = destRect.top % (destRect.bottom - destRect.top);
|
|
}
|
|
if (destRect.left > destRect.right) { // for scrolling case
|
|
destRect.left = destRect.left % (destRect.right - destRect.left);
|
|
}
|
|
rcRect.left = rect.left;
|
|
rcRect.top = rect.top;
|
|
rcRect.right = rect.right;
|
|
rcRect.bottom = rect.bottom;
|
|
HRESULT err;
|
|
err = m_lpDDSBack->ReleaseDC(m_offScreenDC);
|
|
err = m_lpDDSPrimary->Blt(&destRect, m_lpDDSBack, &rcRect, DDBLT_WAIT, NULL);
|
|
if (err == DDERR_SURFACELOST) {
|
|
RestoreAllDrawSurface();
|
|
err = m_lpDDSPrimary->Blt(&destRect, m_lpDDSBack, &rcRect, DDBLT_WAIT, NULL);
|
|
}
|
|
#ifdef DEBUG_mhwang
|
|
if ( err != DD_OK) {
|
|
TRACE("CWinCX::BlttoScreen err = %x\n",
|
|
err);
|
|
}
|
|
#endif
|
|
m_lpDDSBack->GetDC(&m_offScreenDC);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef DDRAW
|
|
int CWinCX::DisplayPixmap(NI_Pixmap* image, NI_Pixmap* mask, int32 x, int32 y, int32 x_offset, int32 y_offset, int32 width, int32 height, LTRB& rect)
|
|
{
|
|
SetClipOnDrawSurface(m_lpDDSBack, (HRGN)m_pDrawable->GetClip());
|
|
CDCCX::DisplayPixmap(image, mask, x, y, x_offset, y_offset, width, height, rect);
|
|
BOOL offScreenDrawing = m_pDrawable && (m_pDrawable == m_pOffscreenDrawable);
|
|
if (m_lpDDSPrimary && !offScreenDrawing && !m_ScrollWindow) {
|
|
BltToScreen(rect, NULL);
|
|
}
|
|
return (1);
|
|
}
|
|
#endif
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Embedded Stuff
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
/*
|
|
* Front-end callback from lib/plugin that creates the window for a
|
|
* brand new plugin
|
|
*/
|
|
void CWinCX::CreateEmbedWindow(MWContext *pContext, NPEmbeddedApp *pApp)
|
|
{
|
|
if (XP_FAIL_ASSERT(pContext != NULL && pApp != NULL && pApp->np_data != NULL))
|
|
return;
|
|
|
|
LO_EmbedStruct *pEmbed = ((np_data *) pApp->np_data)->lo_struct;
|
|
if (XP_FAIL_ASSERT(pEmbed != NULL))
|
|
return;
|
|
|
|
// Register the window class
|
|
HINSTANCE hinst = AfxGetInstanceHandle();
|
|
char szClassName[] = "aPluginWinClass";
|
|
WNDCLASS wc;
|
|
|
|
if(! GetClassInfo(hinst, szClassName, &wc)) {
|
|
wc.style = 0;
|
|
wc.lpfnWndProc = DefWindowProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = hinst;
|
|
wc.hIcon = NULL;
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
|
|
wc.lpszMenuName = (LPCSTR) NULL;
|
|
wc.lpszClassName = szClassName;
|
|
|
|
if (XP_FAIL_ASSERT(RegisterClass(&wc) != 0))
|
|
return;
|
|
}
|
|
|
|
// get the current view for param 5 of CreateWindow() below
|
|
HWND cView = PANECX(pContext)->GetPane();
|
|
|
|
// Determine location of plugin rect in PIXELS
|
|
RECT rect;
|
|
|
|
// XXX This is a hack to get stuff working. The iLocation
|
|
// parameter is passed to FE_GetEmbedSize(); unfortunately, I
|
|
// don't yet pass it down through to NPL_CreatePlugin(). As far as
|
|
// I can tell, it's always set to FE_VIEW, so I'll just hack it
|
|
// for now.
|
|
//
|
|
//GetPluginRect(pContext, pEmbed, rect, iLocation, TRUE);
|
|
GetPluginRect(pContext, pEmbed, rect, FE_VIEW, TRUE);
|
|
|
|
HWND hWnd = ::CreateWindow(szClassName,
|
|
"a Plugin Window",
|
|
WS_CHILD | (pEmbed->ele_attrmask & LO_ELE_INVISIBLE ? 0 : WS_VISIBLE),
|
|
rect.left,
|
|
rect.top,
|
|
rect.right - rect.left,
|
|
rect.bottom - rect.top,
|
|
cView,
|
|
NULL,
|
|
hinst,
|
|
NULL);
|
|
|
|
if (XP_FAIL_ASSERT(hWnd != NULL))
|
|
return;
|
|
|
|
// Allocate a new NPWindow structure to hold the plugin's window
|
|
// information.
|
|
NPWindow* pAppWin = XP_NEW(NPWindow);
|
|
if (XP_FAIL_ASSERT(pAppWin != NULL)) {
|
|
::DestroyWindow(hWnd);
|
|
return;
|
|
}
|
|
|
|
pAppWin->window = (void*)hWnd;
|
|
|
|
// set the NPWindow rect
|
|
pAppWin->x = rect.left;
|
|
pAppWin->y = rect.top;
|
|
pAppWin->width = rect.right - rect.left;
|
|
pAppWin->height = rect.bottom - rect.top;
|
|
pAppWin->type = NPWindowTypeWindow;
|
|
|
|
// Adobe hack. Turn on clip children
|
|
CFrameGlue *pGlue = WINCX(pContext)->GetFrame();
|
|
if (pGlue)
|
|
pGlue->ClipChildren(CWnd::FromHandle((HWND)pAppWin->window), TRUE);
|
|
|
|
pApp->wdata = pAppWin;
|
|
}
|
|
|
|
/*
|
|
* Front-end callback from lib/plugin that saves a plug-in's window in
|
|
* a safe place to be restored (or destroyed) later.
|
|
*/
|
|
void CWinCX::SaveEmbedWindow(MWContext *pContext, NPEmbeddedApp *pApp)
|
|
{
|
|
if (XP_FAIL_ASSERT(pContext != NULL && pApp != NULL))
|
|
return;
|
|
|
|
NPWindow* pAppWin = pApp->wdata;
|
|
if (XP_FAIL_ASSERT(pAppWin != NULL))
|
|
return;
|
|
|
|
// If this isn't a windowed plugin, we've got nothing to do...
|
|
if (pAppWin->type != NPWindowTypeWindow)
|
|
return;
|
|
|
|
// Find the first non-grid parent of the applet window
|
|
MWContext* pSafeContext = XP_GetNonGridContext(pContext);
|
|
if (XP_FAIL_ASSERT(pSafeContext != NULL))
|
|
return;
|
|
|
|
HWND parent = PANECX(pSafeContext)->GetPane();
|
|
if (XP_FAIL_ASSERT(parent != NULL))
|
|
return;
|
|
|
|
// Hide and re-parent the window. We'll restore it in GetEmbedSize()
|
|
::ShowWindow((HWND)pAppWin->window, SW_HIDE);
|
|
::SetParent((HWND)pAppWin->window, parent);
|
|
}
|
|
|
|
/*
|
|
* Front-end callback from lib/plugin that tells us to restore a
|
|
* previously saved window and reparent it to the current context.
|
|
*/
|
|
void CWinCX::RestoreEmbedWindow(MWContext *pContext, NPEmbeddedApp *pApp)
|
|
{
|
|
if (XP_FAIL_ASSERT(pContext != NULL && pApp != NULL))
|
|
return;
|
|
|
|
NPWindow* pAppWin = pApp->wdata;
|
|
if (XP_FAIL_ASSERT(pAppWin != NULL))
|
|
return;
|
|
|
|
HWND parent = WINCX(pContext)->GetPane();
|
|
if (XP_FAIL_ASSERT(parent != NULL))
|
|
return;
|
|
|
|
::SetParent((HWND)pAppWin->window, parent);
|
|
::ShowWindow((HWND)pAppWin->window, SW_SHOW);
|
|
}
|
|
|
|
/*
|
|
* Front-end callback from lib/plugin that tells us to destroy
|
|
* an embedded window
|
|
*/
|
|
void CWinCX::DestroyEmbedWindow(MWContext *pContext, NPEmbeddedApp *pApp)
|
|
{
|
|
if (XP_FAIL_ASSERT(pContext != NULL && pApp != NULL))
|
|
return;
|
|
|
|
NPWindow* pAppWin = pApp->wdata;
|
|
if (XP_FAIL_ASSERT(pAppWin != NULL))
|
|
return;
|
|
|
|
if((pAppWin->window != NULL) && (pAppWin->type == NPWindowTypeWindow)) {
|
|
// the Shockwave and WebFX plugins have bugs that set
|
|
// WS_CLIPCHILDREN without clearing it so do it for them
|
|
HWND hWndParent = ::GetParent((HWND)(DWORD)pAppWin->window);
|
|
::SetWindowLong(hWndParent, GWL_STYLE,
|
|
::GetWindowLong(hWndParent, GWL_STYLE) & ~WS_CLIPCHILDREN);
|
|
|
|
// Clear the WS_CLIPCHILDREN style for all parent windows. This
|
|
// was set to satify the Adobe wankers who create a child window that's
|
|
// in a separate process
|
|
if (! IsPrintContext()) {
|
|
CWinCX *pGCX = WINCX(pContext);
|
|
if(pGCX) {
|
|
CFrameGlue *pGlue = pGCX->GetFrame();
|
|
if(pGlue) {
|
|
pGlue->ClipChildren(CWnd::FromHandle((HWND)pAppWin->window), FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
// destroy the plugin client area
|
|
DestroyWindow((HWND)(DWORD)pAppWin->window);
|
|
pAppWin->window = NULL;
|
|
}
|
|
XP_FREE(pAppWin);
|
|
|
|
// turn scrollbars back on
|
|
if(pApp->pagePluginType == NP_FullPage)
|
|
FE_ShowScrollBars(pContext, TRUE);
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Java Stuff
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef JAVA
|
|
|
|
void PR_CALLBACK
|
|
FE_DisplayNoJavaIcon(MWContext *pContext, LO_JavaAppStruct *java_struct)
|
|
{
|
|
/* write me */
|
|
}
|
|
|
|
void* PR_CALLBACK
|
|
FE_CreateJavaWindow(MWContext *pContext, LO_JavaAppStruct *java_struct,
|
|
int32 xp, int32 yp, int32 xs, int32 ys)
|
|
{
|
|
CWinCX* ctxt = WINCX(pContext);
|
|
LJAppletData* ad = (LJAppletData*)java_struct->session_data;
|
|
HWND parent;
|
|
|
|
PR_ASSERT(ad);
|
|
|
|
// get the current view
|
|
parent = ctxt->GetPane();
|
|
|
|
/* Adjust xp and yp for their offsets within the window */
|
|
xp -= ctxt->m_lOrgX;
|
|
yp -= ctxt->m_lOrgY;
|
|
|
|
// Register the window class
|
|
HINSTANCE hinst = AfxGetInstanceHandle();
|
|
HWND hWnd = NULL;
|
|
char szClassName[] = "aJavaAppletWinClass";
|
|
WNDCLASS wc;
|
|
BOOL result = FALSE;
|
|
|
|
if((result = GetClassInfo(hinst, szClassName, &wc)) == FALSE)
|
|
{
|
|
wc.style = 0;
|
|
wc.lpfnWndProc = DefWindowProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = hinst;
|
|
wc.hIcon = NULL;
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
|
|
wc.lpszMenuName = (LPCSTR) NULL;
|
|
wc.lpszClassName = szClassName;
|
|
result = RegisterClass(&wc);
|
|
}
|
|
if(result != FALSE) {
|
|
hWnd = ::CreateWindow(szClassName,
|
|
"a JavaApplet Window",
|
|
WS_CHILD | WS_CLIPCHILDREN,
|
|
xp,
|
|
yp,
|
|
xs,
|
|
ys,
|
|
parent,
|
|
NULL,
|
|
hinst,
|
|
NULL);
|
|
}
|
|
/* set the default naviagtor palette for use by awt */
|
|
ad->fe_data = (void*)ctxt->GetPalette();
|
|
|
|
return (void*)hWnd;
|
|
}
|
|
|
|
void* PR_CALLBACK
|
|
FE_GetAwtWindow(MWContext *pContext, LJAppletData* ad)
|
|
{
|
|
if (::GetWindow((HWND)ad->window,GW_CHILD)==NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
/* Above was added as an interim fix just so we can release 4.02.
|
|
The problem was that GetWindow is returning a near pointer and
|
|
this routine is simply putting DS into DX so it can return a far
|
|
pointer to its caller. But if GetWindow returns null (AX=0), it
|
|
is still putting DS into DX so it returns DS:0 to it s caller
|
|
rather than 0:0. Probably a casting bug but it needs further
|
|
investigation before a final fix is made -- Steve Morse */
|
|
|
|
return (void*)::GetWindow((HWND)ad->window, GW_CHILD);
|
|
}
|
|
|
|
void PR_CALLBACK
|
|
FE_RestoreJavaWindow(MWContext *pContext, LJAppletData* ad,
|
|
int32 xp, int32 yp, int32 xs, int32 ys)
|
|
{
|
|
CWinCX* ctxt = WINCX(pContext);
|
|
|
|
/* Adjust xp and yp for their offsets within the window */
|
|
xp -= ctxt->m_lOrgX;
|
|
yp -= ctxt->m_lOrgY;
|
|
|
|
XP_TRACE(("Restore: win=%x isWin=%d\n", ad->window, ::IsWindow((HWND)ad->window)));
|
|
|
|
if (pContext->is_grid_cell) {
|
|
/*
|
|
** Reparent the window onto the current window in case it got
|
|
** moved from a grid cell when stopped.
|
|
*/
|
|
HWND parent = ctxt->GetPane();
|
|
PR_ASSERT( ::IsWindow( (HWND)ad->window) );
|
|
::SetParent( (HWND)ad->window, parent );
|
|
}
|
|
/*
|
|
** Set the CLIPCHILDREN style for the parent window to prevent
|
|
** EraseBackground events from obliterating the java window
|
|
*/
|
|
ctxt->ClipChildren(CWnd::FromHandle((HWND)ad->window), TRUE);
|
|
|
|
::SetWindowPos((HWND)ad->window, NULL, xp, yp, xs, ys, SWP_NOZORDER);
|
|
}
|
|
|
|
void PR_CALLBACK
|
|
FE_SetJavaWindowPos(MWContext *pContext, void* window,
|
|
int32 xp, int32 yp, int32 xs, int32 ys)
|
|
{
|
|
CWinCX* ctxt = WINCX(pContext);
|
|
|
|
/* Adjust xp and yp for their offsets within the window */
|
|
xp -= ctxt->m_lOrgX;
|
|
yp -= ctxt->m_lOrgY;
|
|
|
|
::SetWindowPos((HWND)window, NULL, xp, yp, xs, ys, SWP_NOZORDER);
|
|
}
|
|
|
|
void PR_CALLBACK
|
|
FE_SetJavaWindowVisibility(MWContext *context, void* window, PRBool visible)
|
|
{
|
|
if (visible && !::IsWindowVisible((HWND)window))
|
|
::ShowWindow((HWND)window, SW_SHOW);
|
|
else if (!visible && ::IsWindowVisible((HWND)window))
|
|
::ShowWindow((HWND)window, SW_HIDE);
|
|
}
|
|
|
|
void PR_CALLBACK
|
|
FE_SaveJavaWindow(MWContext *pContext, LJAppletData* ad, void* pWindow)
|
|
{
|
|
CWinCX* ctxt = WINCX(pContext);
|
|
HWND window = (HWND)pWindow;
|
|
|
|
if (window == NULL || 0 == ::IsWindow(window)) return;
|
|
|
|
/* Hide the java applet window */
|
|
::ShowWindow( window, SW_HIDE );
|
|
|
|
/*
|
|
** Clear the WS_CLIPCHILDREN style for all parent windows. This
|
|
** was set to prevent EraseBackground events from obliterating
|
|
** the java window...
|
|
*/
|
|
ctxt->ClipChildren(CWnd::FromHandle(window), FALSE);
|
|
|
|
if (pContext->is_grid_cell) {
|
|
/*
|
|
** Reparent the applet window to the first non-grid window
|
|
** if it was on a grid cell because the grid will be
|
|
** destroyed.
|
|
**
|
|
** Note: The ad->context contains the non-grid context at this point.
|
|
*/
|
|
PR_ASSERT(!ad->context->is_grid_cell);
|
|
HWND parent = PANECX(ad->context)->GetPane();
|
|
|
|
::SetParent( window, parent );
|
|
}
|
|
|
|
/* Move the java applet window off screen - for now */
|
|
::SetWindowPos(window, NULL, -100, -100, 10, 10,
|
|
SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOZORDER);
|
|
}
|
|
|
|
void PR_CALLBACK
|
|
FE_FreeJavaWindow(MWContext *context, struct LJAppletData *appletData,
|
|
void* window)
|
|
{
|
|
HWND hwndFrame = (HWND)(DWORD)window;
|
|
if( hwndFrame ) {
|
|
DestroyWindow(hwndFrame);
|
|
}
|
|
}
|
|
|
|
#endif /* JAVA */
|
|
|
|
void CWinCX::DisplayJavaApp(MWContext *pContext, int iLocation, LO_JavaAppStruct *java_struct)
|
|
{
|
|
#ifdef JAVA
|
|
LJ_DisplayJavaApp(pContext, java_struct,
|
|
FE_DisplayNoJavaIcon,
|
|
FE_GetFullWindowSize,
|
|
FE_CreateJavaWindow,
|
|
FE_GetAwtWindow,
|
|
FE_RestoreJavaWindow,
|
|
FE_SetJavaWindowPos,
|
|
FE_SetJavaWindowVisibility);
|
|
#endif /* JAVA */
|
|
}
|
|
|
|
void CWinCX::HideJavaAppElement(MWContext *pContext, LJAppletData * session_data)
|
|
{
|
|
#ifdef JAVA
|
|
LJ_HideJavaAppElement(pContext, session_data, FE_SaveJavaWindow);
|
|
#endif /* JAVA */
|
|
}
|
|
|
|
void CWinCX::FreeJavaAppElement(MWContext *pContext, LJAppletData *ad)
|
|
{
|
|
#ifdef JAVA
|
|
LJ_FreeJavaAppElement(pContext, ad,
|
|
FE_SaveJavaWindow,
|
|
FE_FreeJavaWindow);
|
|
#endif /* JAVA */
|
|
}
|
|
|
|
void CWinCX::GetJavaAppSize(MWContext *pContext, LO_JavaAppStruct *java_struct,
|
|
NET_ReloadMethod reloadMethod)
|
|
{
|
|
#ifdef JAVA
|
|
LJ_GetJavaAppSize(pContext, java_struct, reloadMethod);
|
|
#else
|
|
// jevering: should this be inside ifdef JAVA?
|
|
// FE_DisplayNoJavaIcon(pContext, java_struct);
|
|
java_struct->width = 1;
|
|
java_struct->height = 1;
|
|
#endif /* ! JAVA */
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// End of Java Stuff
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void CWinCX::HandleClippingView(MWContext *pContext, LJAppletData *appletD, int x, int y, int width, int height)
|
|
{
|
|
}
|
|
|
|
void CWinCX::LayoutNewDocument(MWContext *pContext, URL_Struct *pURL, int32 *pWidth, int32 *pHeight, int32 *pmWidth, int32 *pmHeight)
|
|
{
|
|
// Call the base.
|
|
CPaneCX::LayoutNewDocument(pContext, pURL, pWidth, pHeight, pmWidth, pmHeight);
|
|
|
|
// Set our security indicators.
|
|
if(GetFrame()->GetMainContext() != NULL) {
|
|
GetFrame()->SetSecurityStatus(XP_GetSecurityStatus(GetFrame()->GetMainContext()->GetContext()));
|
|
}
|
|
|
|
// We're beginning to layout.
|
|
m_bIsLayingOut = TRUE;
|
|
|
|
// Make sure we have our normal arrow cursor loaded (we loaded the wait
|
|
// in GetUrl).
|
|
SetCursor(theApp.LoadStandardCursor(IDC_ARROW));
|
|
|
|
// No old progress;
|
|
m_lOldPercent = 0;
|
|
|
|
// Update the Frame's URL bar,
|
|
// only if what is currently there hasn't changed, and only
|
|
// if we're not a grid cell.
|
|
CString csText;
|
|
|
|
if(GetContext()->type == MWContextBrowser && !EDT_IS_EDITOR(GetContext())) {
|
|
LPCHROME pChrome = GetFrame()->GetChrome();
|
|
if(pChrome) {
|
|
CWnd *pWnd = pChrome->GetToolbar(ID_LOCATION_TOOLBAR);
|
|
|
|
if (pWnd && pWnd->IsKindOf(RUNTIME_CLASS(CURLBar))){
|
|
CURLBar *pUrlBar = (CURLBar *) pWnd;
|
|
|
|
if(pUrlBar != NULL) {
|
|
pUrlBar->m_pBox->GetWindowText(csText);
|
|
if(m_csSaveLocationBarText == csText && IsGridCell() == FALSE) {
|
|
pUrlBar->UpdateFields(pURL->address);
|
|
}
|
|
}
|
|
else
|
|
csText.Empty();
|
|
}
|
|
else
|
|
csText.Empty();
|
|
}
|
|
}
|
|
else
|
|
csText.Empty();
|
|
|
|
// Clear those old elements that we tracked in the previously
|
|
// loaded page (see FireMouseOverEvent....)
|
|
m_pLastOverAnchorData = NULL;
|
|
m_pLastOverElement = NULL;
|
|
m_pStartSelectionCell = NULL;
|
|
m_bLastOverTextSet = FALSE;
|
|
m_pLastImageObject = NULL;
|
|
|
|
//#ifndef NO_TAB_NAVIGATION
|
|
m_lastTabFocus.pElement = NULL;
|
|
m_lastTabFocus.mapAreaIndex = 0; // 0 means no focus, start with index 1.
|
|
m_lastTabFocus.pAnchor = NULL;
|
|
m_isReEntry_setLastTabFocusElement = 0; // to prevent re-entry
|
|
|
|
ClearMainFrmTabFocusFlag();
|
|
|
|
//#endif /* NO_TAB_NAVIGATION */
|
|
::SetTextAlign(GetContextDC(),TA_NOUPDATECP);
|
|
} // LayoutNewDocument()
|
|
|
|
void CWinCX::SetMainFrmTabFocusFlag( int nn )
|
|
{
|
|
|
|
CFrameGlue * pFrame = GetFrame();
|
|
if( pFrame ) {
|
|
CFrameWnd * pFrameWindow = pFrame->GetFrameWnd();
|
|
if( pFrameWindow && pFrameWindow->IsKindOf(RUNTIME_CLASS(CMainFrame))) {
|
|
((CMainFrame *)pFrameWindow)->SetTabFocusFlag( nn );
|
|
}
|
|
}
|
|
}
|
|
|
|
/* A specialized form of SetMainFrmTabFocusFlag used for setting that flag
|
|
to a generic state (outside of any frames). This is intended for use
|
|
when loading new contents into this CWinCX. It only clears the flag
|
|
if we are the main frame's current active view (or if the current
|
|
active view can't be identified). This prevents the loading of one frame's
|
|
contents from affecting a tab focus currently within another frame.
|
|
*/
|
|
void CWinCX::ClearMainFrmTabFocusFlag(void) {
|
|
|
|
CFrameGlue * pFrame = GetFrame();
|
|
if( pFrame ) {
|
|
CFrameWnd * pFrameWindow = pFrame->GetFrameWnd();
|
|
if( pFrameWindow && pFrameWindow->IsKindOf(RUNTIME_CLASS(CMainFrame))) {
|
|
CMainFrame * pWin = (CMainFrame *) pFrameWindow;
|
|
CWinCX * pActiveContext = pWin->GetActiveWinContext();
|
|
if( pActiveContext == NULL || pActiveContext == this )
|
|
pWin->SetTabFocusFlag(CMainFrame::TAB_FOCUS_IN_NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CWinCX::FinishedLayout(MWContext *pContext) {
|
|
// Call the base.
|
|
CPaneCX::FinishedLayout(pContext);
|
|
|
|
// We're no longer laying out.
|
|
m_bIsLayingOut = FALSE;
|
|
|
|
// Progress should be maxed.
|
|
m_lOldPercent = 100;
|
|
}
|
|
|
|
void CWinCX::AllConnectionsComplete(MWContext *pContext)
|
|
{
|
|
// Call the base.
|
|
CDCCX::AllConnectionsComplete(pContext);
|
|
|
|
// Stop our frame's animation, if the main context of the frame is no longer busy.
|
|
if(GetFrame()->GetMainContext()) {
|
|
if(XP_IsContextBusy(GetFrame()->GetMainContext()->GetContext()) == FALSE) {
|
|
// Okay, stop the animation.
|
|
StopAnimation();
|
|
|
|
// Also, we can clear the progress bar now.
|
|
LPCHROME pChrome = GetFrame()->GetChrome();
|
|
if(pChrome) {
|
|
LPNSSTATUSBAR pIStatusBar = NULL;
|
|
pChrome->QueryInterface( IID_INSStatusBar, (LPVOID *) &pIStatusBar );
|
|
if ( pIStatusBar ) {
|
|
pIStatusBar->SetProgress(0);
|
|
pIStatusBar->Release();
|
|
}
|
|
}
|
|
|
|
// We need to make sure the toolbar buttons are correctly updated. If we
|
|
// don't force it now it won't happen until the app goes idle (which could
|
|
// be when the user moves the mouse over the window, for example)
|
|
CGenericView *pView = GetView();
|
|
ASSERT(pView);
|
|
|
|
CFrameWnd* pFrameWnd = pView->GetParentFrame();
|
|
|
|
ASSERT(pFrameWnd);
|
|
if (pFrameWnd) {
|
|
pFrameWnd->SendMessageToDescendants(WM_IDLEUPDATECMDUI, (WPARAM)TRUE, (LPARAM)0);
|
|
}
|
|
}
|
|
}
|
|
|
|
if( theGlobalNSFont.WebfontsNeedReload( pContext ) )
|
|
{
|
|
// need to remove all font cache before reload.
|
|
ClearFontCache();
|
|
int usePassInType = 1;
|
|
NiceReload(usePassInType, NET_RESIZE_RELOAD );
|
|
}
|
|
}
|
|
|
|
void CWinCX::UpdateStopState(MWContext *pContext)
|
|
{
|
|
#ifdef XP_WIN32
|
|
// Force the toolbar buttons to be correctly updated. If we
|
|
// don't force it now it won't happen until the app goes idle (which could
|
|
// be when the user moves the mouse over the window, for example)
|
|
CGenericView *pView = GetView();
|
|
if(pView) {
|
|
CFrameGlue *pGlue = GetFrame();
|
|
CFrameWnd *pFWnd = pGlue->GetFrameWnd();
|
|
if(pFWnd) {
|
|
pFWnd->SendMessageToDescendants(WM_IDLEUPDATECMDUI, (WPARAM)TRUE, (LPARAM)0);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// Note: We now use pTitle = NULL to clear an existing title
|
|
void CWinCX::SetDocTitle(MWContext *pContext, char *pTitle)
|
|
{
|
|
// Call the base.
|
|
CDCCX::SetDocTitle(pContext, pTitle);
|
|
MWContext * pMWContext = GetContext();
|
|
BOOL bIsPageComposer = EDT_IS_EDITOR(pMWContext) && (pMWContext->type != MWContextMessageComposition);
|
|
|
|
// Guard against the case where our window has gone away and the
|
|
// closing of the window causes the stream to complete which
|
|
// causes us to get back in here with a half torn down window
|
|
if( GetDocumentContext() == NULL )
|
|
return;
|
|
|
|
// We need to be the main context in order to set a
|
|
// frames title.
|
|
if( GetFrame()->GetMainContext() == this ) {
|
|
// Munge the title string.
|
|
CString csTitle;
|
|
|
|
CString csUrlTitle = pTitle;
|
|
// This should be set at end of GetUrl so we
|
|
// don't have to depend on history
|
|
CString csBaseURL = LO_GetBaseURL( GetDocumentContext() );
|
|
|
|
BOOL bTitleIsSameAsUrl = (csBaseURL == csUrlTitle);
|
|
|
|
if(!csUrlTitle.IsEmpty()) {
|
|
if ( bTitleIsSameAsUrl ) {
|
|
// We won't be adding on the URL after this,
|
|
// so make a bigger title
|
|
// If we are a URL, cut from the middle
|
|
WFE_CondenseURL(csUrlTitle, 50, FALSE);
|
|
} else {
|
|
if ( bIsPageComposer ) {
|
|
// Use just left portion of title
|
|
csUrlTitle = csUrlTitle.Left(30);
|
|
} else {
|
|
// We won't add URL to Browser, so use more
|
|
csUrlTitle = csUrlTitle.Left(100);
|
|
}
|
|
}
|
|
csTitle += csUrlTitle;
|
|
}
|
|
|
|
if( bIsPageComposer && !bTitleIsSameAsUrl ){
|
|
// Append URL if we didn't already use it as the title
|
|
// Limit text inside of ( )
|
|
if( !csUrlTitle.IsEmpty() ){
|
|
csTitle += " : ";
|
|
}
|
|
// Strip off username and password from URL
|
|
char * pStripped = NULL;
|
|
NET_ParseUploadURL( (char*)LPCSTR(csBaseURL), &pStripped, NULL, NULL );
|
|
csBaseURL = pStripped;
|
|
XP_FREEIF(pStripped);
|
|
WFE_CondenseURL(csBaseURL, 50 - (min(csUrlTitle.GetLength(),20)), FALSE);
|
|
csTitle += csBaseURL;
|
|
}
|
|
|
|
LPCHROME pChrome = GetFrame()->GetChrome();
|
|
if(pChrome) {
|
|
pChrome->SetDocumentTitle(csTitle);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CWinCX::ClearView(MWContext *pContext, int iView) {
|
|
// Call the base.
|
|
CDCCX::ClearView(pContext, iView);
|
|
|
|
// Have the view erase it's background to clear.
|
|
RECT crClear;
|
|
::SetRect(&crClear, 0, 0, (int) GetWidth(), (int) GetHeight());
|
|
if(GetPane()) {
|
|
// Must first update the window, to get rid of any
|
|
// queud erase backgrounds and stuff which will
|
|
// cause the display to become corrupted.
|
|
RECT tempRect;
|
|
::SetRect(&tempRect,0, 0, CASTINT(GetWidth()), CASTINT(GetHeight()));
|
|
::InvalidateRect(GetPane(), &tempRect, FALSE);
|
|
// ::UpdateWindow(GetPane());
|
|
}
|
|
else {
|
|
// Tell layout to specifically refresh our area.
|
|
RefreshArea(GetOriginX(), GetOriginY(), GetWidth(), GetHeight());
|
|
}
|
|
}
|
|
|
|
void CWinCX::SetDocDimension(MWContext *pContext, int iLocation, int32 lWidth, int32 lLength) {
|
|
// This saves old Y, which changes under certain delete situations...
|
|
int32 iOriginY = GetOriginY();
|
|
|
|
// Make sure that the origin is still visible. (This case only matters when the document
|
|
// height shrinks, which currently only happens when editing.)
|
|
m_lOrgY = max(0, min(m_lOrgY, lLength - m_lHeight));
|
|
|
|
// Anytime we change the scrolling origin, we have to tell the compositor.
|
|
if ( GetContext()->compositor)
|
|
CL_ScrollCompositorWindow(GetContext()->compositor, m_lOrgX, m_lOrgY);
|
|
|
|
// Call the base.
|
|
CPaneCX::SetDocDimension(pContext, iLocation, lWidth, lLength);
|
|
|
|
#ifdef EDITOR
|
|
if(EDT_IS_EDITOR(pContext) &&
|
|
GetOriginY() != iOriginY ) {
|
|
// Redraw entire view
|
|
// This is needed instead to be sure caret is moved to correct location
|
|
// after doc size has changed, like after a deletion
|
|
// at bottom of doc (bug 65199)
|
|
EDT_RefreshLayout(pContext);
|
|
}
|
|
#endif /* EDITOR */
|
|
}
|
|
|
|
//
|
|
// Fake scroll messages so that we use scrollwindowex() to move the window
|
|
// so that our form elements actually move
|
|
//
|
|
void CWinCX::SetDocPosition(MWContext *pContext, int iLocation, int32 lX, int32 lY)
|
|
{
|
|
int iPos;
|
|
|
|
// If we're (the window) wider than the document (layout),
|
|
// then don't use the X value.
|
|
if(GetDocumentWidth() <= GetWidth()) {
|
|
lX = GetOriginX();
|
|
}
|
|
|
|
int32 lRemY = GetOriginY();
|
|
int32 lRemX = GetOriginX();
|
|
|
|
// Call the base.
|
|
CDCCX::SetDocPosition(pContext, iLocation, lX, lY);
|
|
|
|
// LTNOTE: in the editor documents can shrink. Editor contexts therefor
|
|
// must always scroll.
|
|
|
|
// Scrolling in On?ScrollCX is lossy, and causes wild results
|
|
// (scrolling right will cause to scroll right and up).
|
|
// Make sure there is a need to scroll before attempting to scroll.
|
|
|
|
// scroll to the correct Y location
|
|
if((m_lDocHeight - m_lHeight > 0) && lRemY != lY) {
|
|
iPos = (int) ((double) lY * (double) GetPageY() / (double) (m_lDocHeight - m_lHeight));
|
|
Scroll(SB_VERT, SB_THUMBTRACK, iPos, NULL);
|
|
}
|
|
else if ( EDT_IS_EDITOR( pContext ) ){
|
|
if((m_lDocHeight - m_lHeight > 0)) {
|
|
iPos = (int) ((double) lY * (double) GetPageY() / (double) (m_lDocHeight - m_lHeight));
|
|
Scroll(SB_VERT, SB_THUMBTRACK, iPos, NULL);
|
|
}
|
|
else {
|
|
Scroll(SB_VERT, SB_THUMBTRACK, 0, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
// now do X
|
|
if((m_lDocWidth - m_lWidth > 0) && lRemX != lX) {
|
|
iPos = (int) ((double) lX * (double) GetPageX() / (double) (m_lDocWidth - m_lWidth));
|
|
Scroll(SB_HORZ, SB_THUMBTRACK, iPos, NULL);
|
|
}
|
|
else if( EDT_IS_EDITOR(pContext) ){
|
|
if((m_lDocWidth - m_lWidth > 0)) {
|
|
iPos = (int) ((double) lX * (double) GetPageX() / (double) (m_lDocWidth - m_lWidth));
|
|
Scroll(SB_HORZ, SB_THUMBTRACK, iPos, NULL);
|
|
}
|
|
else {
|
|
Scroll(SB_HORZ, SB_THUMBTRACK, 0, NULL);
|
|
}
|
|
}
|
|
// realize scrollbars will have been called by the scrolling routines
|
|
}
|
|
|
|
//#ifndef NO_TAB_NAVIGATION
|
|
// CWinCX::DisplayFeedback() is called by CFE_DisplayFeedback() to draw image selection feedback,
|
|
// and tab focus.
|
|
//
|
|
// For clear calling relation, CDCCX::DisplayFeedback() is renamed to CDCCX::DisplayImageFeedback()
|
|
// and added theArea, drawFlag parameters.
|
|
void CWinCX::DisplayFeedback(MWContext *pContext, int iLocation, LO_Element *pElement)
|
|
{
|
|
if( pElement->lo_any.type == LO_IMAGE ) {
|
|
// Only if the pImage has the tab focus, can we get the tab focus area.
|
|
// otherwise it will return NULL.
|
|
lo_MapAreaRec * theArea = NULL;
|
|
uint32 drawFlag = 0;
|
|
getImageDrawFlag(pContext, (LO_ImageStruct *)pElement, &theArea, &drawFlag);
|
|
|
|
CDCCX::DisplayImageFeedback(pContext, iLocation, pElement, theArea, drawFlag );
|
|
}
|
|
// do nothing if it is not image.
|
|
}
|
|
//#endif /* NO_TAB_NAVIGATION */
|
|
|
|
void CWinCX::SetProgressBarPercent(MWContext *pContext, int32 lPercent) {
|
|
// Enusre the safety of the value.
|
|
lPercent = lPercent < -1 ? 0 : ( lPercent > 100 ? 100 : lPercent );
|
|
|
|
if ( m_lOldPercent == lPercent ) {
|
|
return;
|
|
}
|
|
|
|
m_lOldPercent = lPercent;
|
|
if (GetFrame()) {
|
|
LPCHROME pChrome = GetFrame()->GetChrome();
|
|
if(pChrome) {
|
|
LPNSSTATUSBAR pIStatusBar = NULL;
|
|
pChrome->QueryInterface( IID_INSStatusBar, (LPVOID *) &pIStatusBar );
|
|
if ( pIStatusBar ) {
|
|
pIStatusBar->SetProgress(CASTINT(lPercent));
|
|
pIStatusBar->Release();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CWinCX::Progress(MWContext *pContext, const char *pMessage) {
|
|
if (GetFrame()) {
|
|
LPCHROME pChrome = GetFrame()->GetChrome();
|
|
if(pChrome) {
|
|
LPNSSTATUSBAR pIStatusBar = NULL;
|
|
pChrome->QueryInterface( IID_INSStatusBar, (LPVOID *) &pIStatusBar );
|
|
if ( pIStatusBar ) {
|
|
pIStatusBar->SetStatusText(pMessage);
|
|
pIStatusBar->Release();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CWinCX::DisplayEdge(MWContext *pContext, int iLocation, LO_EdgeStruct *pEdge) {
|
|
// Create an edge window if none currently exists.
|
|
if(pEdge->FE_Data == NULL) {
|
|
CGridEdge *pNewEdge = new CGridEdge(pEdge, this);
|
|
pEdge->FE_Data = pNewEdge;
|
|
}
|
|
else {
|
|
// Update the object's idea of it's owner in case layout is swapping objects on us,
|
|
// this in turn causes the edge to display in a possibly new location.
|
|
((CGridEdge *)pEdge->FE_Data)->UpdateEdge(pEdge);
|
|
}
|
|
}
|
|
|
|
void CWinCX::FreeEdgeElement(MWContext *pContext, LO_EdgeStruct *pEdge) {
|
|
// Get rid of the Edge.
|
|
if(pEdge && pEdge->FE_Data) {
|
|
delete((CGridEdge *)(pEdge->FE_Data));
|
|
pEdge->FE_Data = NULL;
|
|
}
|
|
}
|
|
|
|
CWinCX *CWinCX::DetermineTarget(const char *pTargetName) {
|
|
// This function decides what target will load a URL.
|
|
// This is to facilitate grids loading into targeted locations.
|
|
|
|
// Ensure the target name exists.
|
|
if(pTargetName == NULL || *pTargetName == '\0') {
|
|
// If we're a dialog, and we can not close ourselves, and we're modal over another
|
|
// window context, send the url to that context instead.
|
|
if(GetContext()->type == MWContextDialog &&
|
|
m_cplModalOver.IsEmpty() == FALSE &&
|
|
GetDocument() &&
|
|
GetDocument()->CanClose() == FALSE) {
|
|
HWND hDestination = (HWND)m_cplModalOver.GetHead();
|
|
if(IsWindow(hDestination)) {
|
|
CWnd *pDestination = CWnd::FromHandlePermanent(hDestination);
|
|
if(pDestination && pDestination->IsKindOf(RUNTIME_CLASS(CGenericFrame))) {
|
|
CGenericFrame *pFrame = (CGenericFrame *)pDestination;
|
|
if(pFrame->GetActiveContext() &&
|
|
pFrame->GetActiveContext()->IsWindowContext() &&
|
|
pFrame->GetActiveContext()->IsDestroyed() == FALSE) {
|
|
// GARRETT: This needs to support PANECX
|
|
return(VOID2CX(pFrame->GetActiveContext(), CWinCX)->DetermineTarget(pTargetName));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return(this);
|
|
}
|
|
|
|
// Attempt to find the context already in existance.
|
|
MWContext *pCandidate = XP_FindNamedContextInList(GetContext(), (char *)pTargetName);
|
|
if(pCandidate != NULL) {
|
|
if(ABSTRACTCX(pCandidate)->IsWindowContext() == FALSE) {
|
|
// Don't allow anything but windows to take this burden.
|
|
return(this);
|
|
}
|
|
else {
|
|
return(VOID2CX(pCandidate->fe.cx, CWinCX));
|
|
}
|
|
}
|
|
|
|
// Create a new one, dammit.
|
|
pCandidate = FE_MakeBlankWindow(GetContext(), NULL, (char *)pTargetName);
|
|
if(pCandidate == NULL) {
|
|
// Just use ourselves, I see no way out.
|
|
return(this);
|
|
}
|
|
return(VOID2CX(pCandidate->fe.cx, CWinCX));
|
|
}
|
|
|
|
int32 CWinCX::QueryProgressPercent() {
|
|
// If we've no children, return our percentage.
|
|
if(IsGridParent() == FALSE) {
|
|
return(m_lOldPercent);
|
|
}
|
|
|
|
// It's not empty.
|
|
// We need to return the sum of each of our grid children, divided by the number
|
|
// of the grid children.
|
|
int32 lCount = XP_ListCount(GetContext()->grid_children);
|
|
int32 lSum = 0;
|
|
|
|
// Go through each child.
|
|
MWContext *pChild;
|
|
XP_List *pTraverse = GetContext()->grid_children;
|
|
while (pChild = (MWContext *)XP_ListNextObject(pTraverse)) {
|
|
ASSERT(ABSTRACTCX(pChild)->IsWindowContext());
|
|
lSum += WINCX(pChild)->QueryProgressPercent();
|
|
}
|
|
|
|
// just in case...
|
|
if (lCount < 1)
|
|
return(m_lOldPercent);
|
|
|
|
// Return the sum divided by the count.
|
|
return(lSum / lCount);
|
|
}
|
|
|
|
void CWinCX::StopAnimation()
|
|
{
|
|
LPCHROME pChrome = GetFrame()->GetChrome();
|
|
if(pChrome) {
|
|
pChrome->StopAnimation();
|
|
}
|
|
}
|
|
|
|
void CWinCX::StartAnimation()
|
|
{
|
|
LPCHROME pChrome = GetFrame()->GetChrome();
|
|
if(pChrome) {
|
|
pChrome->StartAnimation();
|
|
}
|
|
}
|
|
|
|
void CWinCX::OpenFile() {
|
|
// If we've a parent context, let them deal with this.
|
|
if(GetParentContext()) {
|
|
if(ABSTRACTCX(GetParentContext())->IsWindowContext()) {
|
|
WINCX(GetParentContext())->OpenFile();
|
|
}
|
|
else {
|
|
ASSERT(0);
|
|
}
|
|
}
|
|
else if(IsDestroyed() == FALSE) {
|
|
// Have the frame bring up the open file dialog.
|
|
if(GetFrame()->GetFrameWnd()) {
|
|
MWContext * pMWContext = GetContext();
|
|
|
|
// Restrict opening to only HTML files if initiated from Composer frame
|
|
BOOL bOpenIntoEditor = EDT_IS_EDITOR(pMWContext) && (pMWContext->type == MWContextBrowser);
|
|
CWnd * cWnd = GetFrame()->GetFrameWnd();
|
|
|
|
char * pName = wfe_GetExistingFileName(
|
|
cWnd->m_hWnd,
|
|
szLoadString(IDS_OPEN), bOpenIntoEditor ? HTM_ONLY : HTM, TRUE);
|
|
|
|
if(pName == NULL) {
|
|
// Canceled.
|
|
return;
|
|
}
|
|
#ifdef EDITOR
|
|
if( bOpenIntoEditor ){
|
|
FE_LoadUrl(pName, LOAD_URL_COMPOSER);
|
|
} else {
|
|
if( EDT_IS_EDITOR(pMWContext) ){
|
|
// Open a file into a new browse window from an Editor
|
|
FE_LoadUrl(pName, LOAD_URL_NAVIGATOR);
|
|
} else {
|
|
// Load URL into existing Browser window
|
|
NormalGetUrl(pName);
|
|
}
|
|
}
|
|
#else
|
|
NormalGetUrl(pName);
|
|
#endif // EDITOR
|
|
XP_FREE(pName);
|
|
}
|
|
else {
|
|
ASSERT(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL CWinCX::CanOpenFile() {
|
|
// If we've a parent context, let them deal with this.
|
|
if(GetParentContext()) {
|
|
if(ABSTRACTCX(GetParentContext())->IsWindowContext()) {
|
|
return(WINCX(GetParentContext())->CanOpenFile());
|
|
}
|
|
else {
|
|
ASSERT(0);
|
|
return(FALSE);
|
|
}
|
|
}
|
|
else if(IsDestroyed() == TRUE) {
|
|
return(FALSE);
|
|
}
|
|
else {
|
|
// Can always open a file.
|
|
// Perhaps not if we're in some kiosk mode.
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
BOOL CWinCX::SaveOleDocument() {
|
|
CGenericDoc * pDoc = GetDocument();
|
|
|
|
return pDoc->OnSaveDocument(NULL);
|
|
|
|
}
|
|
void CWinCX::SaveAs() {
|
|
if (!SaveOleDocument()) {
|
|
if(IsDestroyed() == FALSE && IsGridParent() == FALSE) {
|
|
// Make sure we have a history entry.
|
|
History_entry *pHist = SHIST_GetCurrent(&(GetContext()->hist));
|
|
if(pHist != NULL && pHist->address != NULL) {
|
|
// Can save.
|
|
// Don't care if GetFrameWnd returns NULL.
|
|
CSaveCX::SaveAnchorObject((const char *)pHist->address,
|
|
pHist, GetFrame()->m_iCSID, GetFrame()->GetFrameWnd());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL CWinCX::CanSaveAs() {
|
|
|
|
// if there is only 1 ole item there, don't save the documant.
|
|
CGenericDoc * pDoc = GetDocument();
|
|
POSITION pos = pDoc->GetStartPosition();
|
|
CNetscapeCntrItem *pItem;
|
|
CDocItem* item = pDoc->GetNextItem(pos );
|
|
// If the current embed item is full page OLE and is not in-placed actived, return FALSE
|
|
// so the saveAs menu item will be disabled.
|
|
while (item && item->IsKindOf(RUNTIME_CLASS(CNetscapeCntrItem))) {
|
|
pItem = (CNetscapeCntrItem*)item;
|
|
if (pItem->m_isFullPage && !pItem->IsInPlaceActive( ))
|
|
return FALSE;
|
|
item = pDoc->GetNextItem(pos );
|
|
}
|
|
pItem = (CNetscapeCntrItem *)pDoc->GetInPlaceActiveItem(CWnd::FromHandle(GetPane()));
|
|
if (pItem) {
|
|
if (pItem->m_bCanSavedByOLE) // see can this item be saved.
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
if(IsDestroyed() == TRUE || IsGridParent() == TRUE) {
|
|
return(FALSE);
|
|
}
|
|
else {
|
|
// Can't save if there's no history entry.
|
|
History_entry *pHist = SHIST_GetCurrent(&(GetContext()->hist));
|
|
if(pHist == NULL) {
|
|
return(FALSE);
|
|
}
|
|
else if(pHist->address == NULL) {
|
|
return(FALSE);
|
|
}
|
|
else {
|
|
return(TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CWinCX::PrintContext() {
|
|
//Abstraction layer has context type print which
|
|
//conflicts with abstracting the Print() function
|
|
Print();
|
|
}
|
|
|
|
void CWinCX::Print() {
|
|
if(IsDestroyed() == TRUE || CanPrint() == FALSE) {
|
|
return;
|
|
}
|
|
MWContext *pMWContext = GetContext();
|
|
if( !pMWContext )
|
|
return;
|
|
// Note: We no longer have to force saving a page
|
|
// before printing because we use a temporary file instead
|
|
|
|
// Always pass the WYSIWYG attribute for printing URLs (javascript).
|
|
SHIST_SavedData SavedData;
|
|
URL_Struct *pUrl = CreateUrlFromHist(TRUE, &SavedData, TRUE);
|
|
|
|
char *pDisplayUrl = NULL;
|
|
#ifdef EDITOR
|
|
if( EDT_IS_EDITOR(pMWContext) )
|
|
{
|
|
// Save actual address we want to show in header or footer
|
|
// to pass on to print context
|
|
if( pUrl->address )
|
|
pDisplayUrl = XP_STRDUP(pUrl->address);
|
|
|
|
// Save current contents to a temporary file if
|
|
// we are a Mail Message, a New Document, or there are changes to current page
|
|
// This will change pUrl->address to temp filename
|
|
if( !FE_PrepareTempFileUrl(pMWContext, pUrl) )
|
|
{
|
|
XP_FREEIF(pDisplayUrl);
|
|
// Failed to save to the temp file - abort
|
|
return;
|
|
}
|
|
}
|
|
#endif //EDITOR
|
|
|
|
// Copy the necessary information into the URL's saved data so that we don't
|
|
// make a copy of the plug-ins when printing
|
|
NPL_PreparePrint(pMWContext, &pUrl->savedData);
|
|
|
|
CGenericView *pView = GetView();
|
|
if(pView) {
|
|
CPrintCX::PrintAnchorObject(pUrl, pView, &SavedData, pDisplayUrl);
|
|
}
|
|
XP_FREEIF(pDisplayUrl);
|
|
}
|
|
|
|
BOOL CWinCX::CanPrint(BOOL bPreview) {
|
|
// Can't print if we're destroyed, if there's no view, or if we've no
|
|
// history or we're a grid parent.
|
|
BOOL bRetval = TRUE;
|
|
if(FALSE == sysInfo.m_bPrinter) {
|
|
bRetval = FALSE;
|
|
}
|
|
else if(IsDestroyed()) {
|
|
bRetval = FALSE;
|
|
}
|
|
else if(GetPane() == NULL) {
|
|
bRetval = FALSE;
|
|
}
|
|
else if(CanCreateUrlFromHist() == FALSE) {
|
|
bRetval = FALSE;
|
|
}
|
|
else if(IsGridParent() == TRUE) {
|
|
bRetval = FALSE;
|
|
}
|
|
|
|
// Lastly, we only allow one print context at a time.
|
|
// There can be multiple print preview context's however.
|
|
if(bRetval && bPreview == FALSE) {
|
|
MWContext *pTraverseContext = NULL;
|
|
CAbstractCX *pTraverseCX = NULL;
|
|
XP_List *pTraverse = XP_GetGlobalContextList();
|
|
while (pTraverseContext = (MWContext *)XP_ListNextObject(pTraverse)) {
|
|
if(pTraverseContext != NULL && ABSTRACTCX(pTraverseContext) != NULL) {
|
|
pTraverseCX = ABSTRACTCX(pTraverseContext);
|
|
if(pTraverseCX->IsPrintContext() == TRUE) {
|
|
CPrintCX *pPrintCX = VOID2CX(pTraverseCX, CPrintCX);
|
|
if(pPrintCX->IsPrintPreview() == FALSE) {
|
|
// Already a print job in progress.
|
|
bRetval = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return(bRetval);
|
|
}
|
|
|
|
void CWinCX::AllFind(MWContext *pSearchContext) {
|
|
// If we've got a parent context, let it deal.
|
|
if(GetParentContext()) {
|
|
if(ABSTRACTCX(GetParentContext())->IsWindowContext()) {
|
|
WINCX(GetParentContext())->AllFind(pSearchContext);
|
|
}
|
|
else {
|
|
ASSERT(0);
|
|
}
|
|
}
|
|
else if(CanAllFind()) {
|
|
if(GetFrame()->GetFrameWnd()) {
|
|
CNetscapeFindReplaceDialog *dlg;
|
|
|
|
dlg = new CNetscapeFindReplaceDialog();
|
|
UINT flags = FR_DOWN | FR_NOWHOLEWORD | FR_HIDEWHOLEWORD;
|
|
BOOL bBrowser = TRUE;
|
|
#ifdef EDITOR
|
|
if( pSearchContext )
|
|
{
|
|
bBrowser = !EDT_IS_EDITOR(pSearchContext);
|
|
} else {
|
|
bBrowser = !EDT_IS_EDITOR(GetContext());
|
|
}
|
|
#endif
|
|
dlg->Create(bBrowser,
|
|
theApp.m_csFindString,
|
|
bBrowser ? NULL : (LPCTSTR)theApp.m_csReplaceString,
|
|
flags,
|
|
GetFrame()->GetFrameWnd());
|
|
|
|
// Let them know who the frame is.
|
|
dlg->SetFrameGlue(GetFrame());
|
|
// If a frame was specified as a search context then perform
|
|
// the search there. If no context was specified or if
|
|
// the search context is a top level window then don't set
|
|
// the search context and we'll search normally on the focused frame.
|
|
if (pSearchContext && pSearchContext->grid_parent)
|
|
dlg->SetSearchContext(pSearchContext);
|
|
}
|
|
else {
|
|
ASSERT(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL CWinCX::CanAllFind() {
|
|
// If we've a parent context, let them deal with this.
|
|
if(GetParentContext()) {
|
|
if(ABSTRACTCX(GetParentContext())->IsWindowContext()) {
|
|
return(WINCX(GetParentContext())->CanAllFind());
|
|
}
|
|
else {
|
|
ASSERT(0);
|
|
return(FALSE);
|
|
}
|
|
}
|
|
else if(IsDestroyed() == TRUE) {
|
|
return(FALSE);
|
|
}
|
|
else {
|
|
BOOL bRetval = TRUE;
|
|
// Can't find if there's no history entry.
|
|
History_entry *pHist = SHIST_GetCurrent(&(GetContext()->hist));
|
|
if(pHist == NULL) {
|
|
bRetval = FALSE;
|
|
}
|
|
else if(pHist->address == NULL) {
|
|
bRetval = FALSE;
|
|
}
|
|
else if(GetFrame()->CanFindReplace() == FALSE) {
|
|
// Frame already is finding/replacing.
|
|
bRetval = FALSE;
|
|
}
|
|
else {
|
|
bRetval = TRUE;
|
|
}
|
|
|
|
return(bRetval);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Find again using the settings from last time
|
|
//
|
|
void CWinCX::FindAgain()
|
|
{
|
|
DoFind(NULL, (const char *) theApp.m_csFindString, theApp.m_bMatchCase,
|
|
theApp.m_bSearchDown, TRUE);
|
|
}
|
|
|
|
//
|
|
// Actually do the find operation
|
|
//
|
|
BOOL CWinCX::DoFind(CWnd * pWnd, const char * pFindString, BOOL bMatchCase,
|
|
BOOL bSearchDown, BOOL bAlertOnNotFound)
|
|
{
|
|
|
|
int32 start_position, end_position;
|
|
LO_Element * start_ele_loc = NULL;
|
|
LO_Element * end_ele_loc = NULL;
|
|
CL_Layer *sel_layer = NULL;
|
|
|
|
// Start the search from the current selection location
|
|
LO_GetSelectionEndpoints(GetDocumentContext(),
|
|
&start_ele_loc,
|
|
&end_ele_loc,
|
|
&start_position,
|
|
&end_position,
|
|
&sel_layer);
|
|
|
|
// look for the text
|
|
if (LO_FindText(GetDocumentContext(),
|
|
(char *) pFindString,
|
|
&start_ele_loc,
|
|
&start_position,
|
|
&end_ele_loc,
|
|
&end_position,
|
|
bMatchCase,
|
|
bSearchDown) == 1)
|
|
{
|
|
int32 x, y;
|
|
|
|
LO_SelectText(GetDocumentContext(),
|
|
start_ele_loc,
|
|
start_position,
|
|
end_ele_loc,
|
|
end_position,
|
|
&x,
|
|
&y);
|
|
|
|
// TODO: This is not correct - it scrolls over unnecessarily
|
|
//FE_SetDocPosition(GetContext(), FE_VIEW, x, y);
|
|
|
|
// Get current location and scroll only as necessary
|
|
int32 iViewLeft, iViewTop, iViewWidth, iViewHeight;
|
|
|
|
FE_GetDocAndWindowPosition(GetContext(), &iViewLeft, &iViewTop, &iViewWidth, &iViewHeight);
|
|
int32 iViewBottom = iViewTop + iViewHeight;
|
|
int32 iViewRight = iViewLeft + iViewWidth;
|
|
BOOL bScroll = FALSE;
|
|
if( x < iViewLeft || x > iViewRight )
|
|
{
|
|
iViewLeft = max(0,(x - iViewWidth/4));
|
|
bScroll = TRUE;
|
|
}
|
|
// Place found text at 1/4 of window height
|
|
if( y < iViewTop || y > iViewBottom )
|
|
{
|
|
iViewTop = max(0,(y - iViewHeight/4));
|
|
bScroll = TRUE;
|
|
}
|
|
if( bScroll )
|
|
FE_SetDocPosition(GetContext(), FE_VIEW, iViewLeft, iViewTop);
|
|
|
|
//
|
|
// Ensure the Find/Replace dlg doesn't cover the selection
|
|
//
|
|
CNetscapeFindReplaceDialog *pDlg = GetFrame() ? GetFrame()->GetFindReplace() : NULL;
|
|
if( pDlg )
|
|
{
|
|
RECT rcDlg;
|
|
pDlg->GetWindowRect( &rcDlg );
|
|
|
|
RECT rcView;
|
|
::GetWindowRect( GetPane(), &rcView );
|
|
|
|
int32 iTextY = rcView.top + (y - GetOriginY());
|
|
|
|
if( (rcDlg.top < iTextY) && (rcDlg.bottom > iTextY) )
|
|
{
|
|
CRect rcDlgNew( rcDlg );
|
|
|
|
rcDlgNew.OffsetRect( 0, iTextY - rcDlgNew.top + 20 );
|
|
if( rcDlgNew.bottom > GetSystemMetrics( SM_CYSCREEN ) )
|
|
{
|
|
rcDlgNew.CopyRect( &rcDlg );
|
|
rcDlgNew.OffsetRect( 0, iTextY - rcDlgNew.bottom - 1 );
|
|
}
|
|
pDlg->SetWindowPos( NULL, rcDlgNew.left, rcDlgNew.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
else if(bAlertOnNotFound){
|
|
HWND hBox = NULL;
|
|
if(NULL == pWnd) {
|
|
hBox = GetPane();
|
|
}
|
|
else {
|
|
hBox = pWnd->m_hWnd;
|
|
}
|
|
|
|
if(hBox)
|
|
::MessageBox(hBox, szLoadString(IDS_FIND_NOT_FOUND), szLoadString(AFX_IDS_APP_TITLE), MB_ICONEXCLAMATION | MB_OK);
|
|
|
|
}
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// cause the form containing the given element to be submitted
|
|
//
|
|
void FE_SubmitInputElement(MWContext * pContext, LO_Element * pElement)
|
|
{
|
|
|
|
LO_FormSubmitData * submit;
|
|
URL_Struct * URL_s;
|
|
|
|
if(!pContext || !pElement)
|
|
return;
|
|
|
|
submit = LO_SubmitForm(ABSTRACTCX(pContext)->GetDocumentContext(), (LO_FormElementStruct *) pElement);
|
|
if(!submit)
|
|
return;
|
|
|
|
// Create the URL to load
|
|
URL_s = NET_CreateURLStruct((char *)submit->action, NET_DONT_RELOAD);
|
|
|
|
#if defined(SingleSignon)
|
|
// Check for a password submission and remember the data if so
|
|
SI_RememberSignonData(pContext, submit);
|
|
#endif
|
|
|
|
// attach form data to the URL
|
|
NET_AddLOSubmitDataToURLStruct(submit, URL_s);
|
|
|
|
// add referer field if we've got it
|
|
{
|
|
History_entry *he = SHIST_GetCurrent (&pContext->hist);
|
|
if(he && he->address)
|
|
URL_s->referer = XP_STRDUP(he->address);
|
|
else
|
|
URL_s->referer = NULL;
|
|
}
|
|
|
|
// start the spinning icon
|
|
// Load up.
|
|
ABSTRACTCX(pContext)->GetUrl(URL_s, FO_CACHE_AND_PRESENT);
|
|
|
|
LO_FreeSubmitData(submit);
|
|
|
|
}
|
|
|
|
// Say wether or not view source is allowed.
|
|
BOOL CWinCX::CanViewSource()
|
|
{
|
|
// If we've got a parent context, we need to pass it on up the chain.
|
|
if(GetParentContext() != NULL) {
|
|
return(WINCX(GetParentContext())->CanViewSource());
|
|
}
|
|
|
|
// We're the top level context, make sure we're not destroyed.
|
|
if(IsDestroyed()) {
|
|
return(FALSE);
|
|
}
|
|
|
|
// Don't let this happen while a context is loading otherwise,
|
|
// not all the document source is present, and we interrupt
|
|
// the load.
|
|
if(XP_IsContextBusy(GetContext()) == TRUE) {
|
|
return(FALSE);
|
|
}
|
|
|
|
// All that matters now is wether or not we can create a URL struct from
|
|
// our history.
|
|
return(CanCreateUrlFromHist());
|
|
}
|
|
|
|
// View the source.
|
|
void CWinCX::ViewSource()
|
|
{
|
|
// If we've a parent context, we need to pass it on up the chain.
|
|
if(GetParentContext() != NULL) {
|
|
WINCX(GetParentContext())->ViewSource();
|
|
return;
|
|
}
|
|
|
|
if(CanViewSource()) {
|
|
// Clear the state data.
|
|
URL_Struct *pUrl = CreateUrlFromHist(TRUE);
|
|
|
|
if(pUrl != NULL) {
|
|
#ifdef EDITOR
|
|
if( EDT_IS_EDITOR(GetContext()) ){
|
|
EDT_DisplaySource(GetContext()); // Make sure that it's okay to do this.
|
|
return;
|
|
}
|
|
#endif //EDITOR
|
|
// Load up.
|
|
GetUrl(pUrl, FO_CACHE_AND_VIEW_SOURCE);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL CWinCX::CanDocumentInfo()
|
|
{
|
|
// If we've got a parent context, we need to pass it on up the chain.
|
|
if(GetParentContext() != NULL) {
|
|
return(WINCX(GetParentContext())->CanDocumentInfo());
|
|
}
|
|
|
|
// We're the top level context, make sure we're not destroyed.
|
|
if(IsDestroyed()) {
|
|
return(FALSE);
|
|
}
|
|
|
|
// Don't allow this while we're loading.
|
|
// They won't be able to view the entire document's tree.
|
|
// Also, this won't interrupt the current load.
|
|
if(XP_IsContextBusy(GetContext()) == TRUE) {
|
|
return(FALSE);
|
|
}
|
|
|
|
// All that matters now is wether or not we can create a URL struct from
|
|
// our history.
|
|
return(CanCreateUrlFromHist());
|
|
}
|
|
|
|
void CWinCX::DocumentInfo()
|
|
{
|
|
// If we've got a parent context, we need to pass it on up the chain.
|
|
if(GetParentContext() != NULL) {
|
|
WINCX(GetParentContext())->DocumentInfo();
|
|
return;
|
|
}
|
|
|
|
// Make sure it's okay to try this.
|
|
if(CanDocumentInfo()) {
|
|
// Do it.
|
|
NormalGetUrl("about:document");
|
|
}
|
|
}
|
|
|
|
BOOL CWinCX::CanFrameSource()
|
|
{
|
|
if(IsDestroyed()) {
|
|
return(FALSE);
|
|
}
|
|
|
|
if(IsGridCell() == FALSE) {
|
|
return(FALSE);
|
|
}
|
|
|
|
// Don't let this happen while a context is loading otherwise,
|
|
// not all the document source is present, and we interrupt
|
|
// the load.
|
|
if(XP_IsContextBusy(GetContext()) == TRUE) {
|
|
return(FALSE);
|
|
}
|
|
|
|
// All that matters now is wether or not we can create a URL struct from
|
|
// our history.
|
|
return(CanCreateUrlFromHist());
|
|
}
|
|
|
|
void CWinCX::FrameSource()
|
|
{
|
|
if(CanFrameSource()) {
|
|
// Clear the state data.
|
|
URL_Struct *pUrl = CreateUrlFromHist(TRUE);
|
|
|
|
if(pUrl != NULL) {
|
|
#ifdef EDITOR
|
|
if( EDT_IS_EDITOR(GetContext()) ){
|
|
EDT_DisplaySource(GetContext()); // Make sure that it's okay to do this.
|
|
return;
|
|
}
|
|
#endif
|
|
// Load up.
|
|
GetUrl(pUrl, FO_CACHE_AND_VIEW_SOURCE);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL CWinCX::CanFrameInfo()
|
|
{
|
|
if(IsDestroyed()) {
|
|
return(FALSE);
|
|
}
|
|
|
|
if(IsGridCell() == FALSE) {
|
|
return(FALSE);
|
|
}
|
|
|
|
// Don't allow this while we're loading.
|
|
// They won't be able to view the entire document's tree.
|
|
// Also, this won't interrupt the current load.
|
|
if(XP_IsContextBusy(GetContext()) == TRUE) {
|
|
return(FALSE);
|
|
}
|
|
|
|
// All that matters now is wether or not we can create a URL struct from
|
|
// our history.
|
|
return(CanCreateUrlFromHist());
|
|
}
|
|
|
|
void CWinCX::FrameInfo()
|
|
{
|
|
// Make sure it's okay to try this.
|
|
if(CanFrameInfo()) {
|
|
// Do it.
|
|
NormalGetUrl("about:document");
|
|
}
|
|
}
|
|
|
|
BOOL CWinCX::CanGoHome()
|
|
{
|
|
// Have the parent handle.
|
|
if(GetParentContext() != NULL) {
|
|
return(WINCX(GetParentContext())->CanGoHome());
|
|
}
|
|
|
|
// We can't be destroyed.
|
|
if(IsDestroyed()) {
|
|
return(FALSE);
|
|
}
|
|
|
|
// We need to have a home page defined.
|
|
if(theApp.m_pHomePage.IsEmpty()) {
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
void CWinCX::GoHome()
|
|
{
|
|
// Have the parent handle.
|
|
if(GetParentContext() != NULL) {
|
|
WINCX(GetParentContext())->GoHome();
|
|
return;
|
|
}
|
|
|
|
// Make sure we can go home.
|
|
if(CanGoHome()) {
|
|
// Load it.
|
|
NormalGetUrl(theApp.m_pHomePage);
|
|
}
|
|
}
|
|
|
|
// This function get's called to size the non client area.
|
|
// On grid cells, we like to put a pixel border on the outsize so we can show activation.
|
|
void CWinCX::OnNcCalcSizeCX(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)
|
|
{
|
|
if(IsGridCell() == TRUE &&
|
|
IsGridParent() == FALSE &&
|
|
GetPane() != NULL &&
|
|
IsIconic(GetPane()) == FALSE &&
|
|
IsDestroyed() == FALSE &&
|
|
m_bHasBorder == TRUE
|
|
) {
|
|
if(lpncsp) {
|
|
lpncsp->rgrc[0].left += 1;
|
|
lpncsp->rgrc[0].top += 1;
|
|
lpncsp->rgrc[0].right -= 1;
|
|
lpncsp->rgrc[0].bottom -= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// This function get's called to draw the area surrounding the client area of
|
|
// the view, if anything special needs be done.
|
|
void CWinCX::OnNcPaintCX() {
|
|
if(IsGridCell() == TRUE &&
|
|
IsGridParent() == FALSE &&
|
|
GetPane() != NULL &&
|
|
IsDestroyed() == FALSE
|
|
#ifdef XP_WIN16
|
|
&& GetFrame()->GetFrameWnd() != NULL
|
|
#endif
|
|
&& m_bHasBorder == TRUE ) {
|
|
|
|
|
|
// Get a DC from our true window, we'll be using it to do the deed, as
|
|
// we're drawing outside of our client region.
|
|
HDC hDC;
|
|
#ifdef XP_WIN16
|
|
CDC *pDC = GetFrame()->GetFrameWnd()->GetDC();
|
|
hDC = pDC->GetSafeHdc();
|
|
#else
|
|
hDC = ::GetWindowDC(GetPane());
|
|
#endif
|
|
if(hDC != NULL) {
|
|
RECT crWindowRect;
|
|
::GetWindowRect(GetPane(), &crWindowRect);
|
|
|
|
RECT crBorder;
|
|
::SetRect(
|
|
&crBorder,
|
|
0,
|
|
0,
|
|
crWindowRect.right - crWindowRect.left,
|
|
crWindowRect.bottom - crWindowRect.top);
|
|
|
|
#ifdef XP_WIN16
|
|
// 16 bit working in frame coordinates.
|
|
::MapWindowPoints(
|
|
GetPane(),
|
|
GetFrame()->GetFrameWnd()->m_hWnd,
|
|
(POINT *)&crBorder,
|
|
2);
|
|
|
|
// Need to shift up and left one pixel.
|
|
crBorder.left -= 1;
|
|
crBorder.right -= 1;
|
|
crBorder.top -= 1;
|
|
crBorder.bottom -= 1;
|
|
#endif
|
|
|
|
// Figure out what colors we are drawing with.
|
|
COLORREF rgbOuter = m_rgbBackgroundColor;
|
|
|
|
// We need to change these if we're active.
|
|
if(m_bActiveState == TRUE) {
|
|
int iSum =
|
|
(int)GetRValue(rgbOuter) +
|
|
(int)GetGValue(rgbOuter) +
|
|
(int)GetBValue(rgbOuter);
|
|
|
|
if(iSum > (127 * 3)) {
|
|
// Bright, use black.
|
|
rgbOuter = RGB(0, 0, 0);
|
|
}
|
|
else {
|
|
// Dark, use white.
|
|
rgbOuter = RGB(255, 255, 255);
|
|
}
|
|
}
|
|
|
|
HPEN hpO = ::CreatePen(PS_SOLID, 0, rgbOuter);
|
|
HPEN pOldPen = (HPEN)::SelectObject(hDC, hpO);
|
|
|
|
// Careful to avoid scrollers NC paints on NT and 3.1.
|
|
// We'll be detecting this by deciding how wide the window borders are,
|
|
// these systems report 1, but 95 reports 2 (and probably future versions
|
|
// of NT with a the 95 UI).
|
|
BOOL bFullPaint = FALSE;
|
|
if(sysInfo.m_iBorderWidth != 1) {
|
|
bFullPaint = TRUE;
|
|
}
|
|
|
|
// Draw left side.
|
|
::MoveToEx(hDC, crBorder.left, crBorder.top, NULL);
|
|
if(bFullPaint) {
|
|
::LineTo(hDC, crBorder.left, crBorder.bottom);
|
|
}
|
|
else if(IsHScrollBarOn()) {
|
|
::LineTo(hDC, crBorder.left, crBorder.bottom - sysInfo.m_iScrollHeight);
|
|
}
|
|
else {
|
|
::LineTo(hDC, crBorder.left, crBorder.bottom);
|
|
}
|
|
|
|
// Draw bottom side.
|
|
if(bFullPaint) {
|
|
::MoveToEx(hDC, crBorder.left, crBorder.bottom - 1, NULL);
|
|
::LineTo(hDC, crBorder.right, crBorder.bottom - 1);
|
|
}
|
|
else if(!IsHScrollBarOn()) {
|
|
::MoveToEx(hDC, crBorder.left, crBorder.bottom - 1, NULL);
|
|
|
|
if(IsVScrollBarOn()) {
|
|
::LineTo(hDC, crBorder.right - sysInfo.m_iScrollWidth, crBorder.bottom - 1);
|
|
}
|
|
else {
|
|
::LineTo(hDC, crBorder.right, crBorder.bottom - 1);
|
|
}
|
|
}
|
|
else if(IsHScrollBarOn() && IsVScrollBarOn()) {
|
|
::MoveToEx(hDC, crBorder.right - sysInfo.m_iScrollWidth + 1, crBorder.bottom - 1, NULL);
|
|
::LineTo(hDC, crBorder.right, crBorder.bottom - 1);
|
|
}
|
|
|
|
// Draw right side.
|
|
if(bFullPaint) {
|
|
::MoveToEx(hDC, crBorder.right- 1, crBorder.top, NULL);
|
|
::LineTo(hDC, crBorder.right - 1, crBorder.bottom);
|
|
}
|
|
else if(!IsVScrollBarOn()) {
|
|
::MoveToEx(hDC, crBorder.right - 1, crBorder.top, NULL);
|
|
|
|
if(IsHScrollBarOn()) {
|
|
::LineTo(hDC, crBorder.right - 1, crBorder.bottom - sysInfo.m_iScrollHeight);
|
|
}
|
|
else {
|
|
::LineTo(hDC, crBorder.right - 1, crBorder.bottom);
|
|
}
|
|
}
|
|
else if(IsVScrollBarOn() && IsHScrollBarOn()) {
|
|
::MoveToEx(hDC, crBorder.right - 1, crBorder.bottom - sysInfo.m_iScrollHeight + 1, NULL);
|
|
::LineTo(hDC, crBorder.right - 1, crBorder.bottom);
|
|
}
|
|
|
|
// Draw top side.
|
|
::MoveToEx(hDC, crBorder.left, crBorder.top, NULL);
|
|
if(bFullPaint) {
|
|
::LineTo(hDC, crBorder.right, crBorder.top);
|
|
}
|
|
else if(IsVScrollBarOn()) {
|
|
::LineTo(hDC, crBorder.right - sysInfo.m_iScrollWidth, crBorder.top);
|
|
}
|
|
else {
|
|
::LineTo(hDC, crBorder.right, crBorder.top);
|
|
}
|
|
|
|
::SelectObject(hDC, pOldPen);
|
|
::DeleteObject(hpO);
|
|
// Done with the DC.
|
|
#ifndef XP_WIN16
|
|
::ReleaseDC(GetPane(), hDC);
|
|
#else
|
|
GetFrame()->GetFrameWnd()->ReleaseDC(pDC);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
// Tells the context wether it is made active, or inactive.
|
|
// This function mainly used to give a visual indication of the currently
|
|
// selected frame cell.
|
|
void CWinCX::ActivateCX(BOOL bNowActive) {
|
|
// Update our active state.
|
|
BOOL bOldState = m_bActiveState;
|
|
m_bActiveState = bNowActive;
|
|
|
|
// In either event, see if we should update the non client area.
|
|
if(m_bActiveState != bOldState) {
|
|
OnNcPaintCX();
|
|
}
|
|
}
|
|
|
|
// Clicking is allowed again.
|
|
// Act as though the mouse moved, so that the correct cursor is put back up.
|
|
void CWinCX::EnableClicking(MWContext *pContext)
|
|
{
|
|
BOOL bReturnImmediately = FALSE;
|
|
OnMouseMoveCX(m_uMouseFlags, m_cpMMove, bReturnImmediately);
|
|
if(bReturnImmediately) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Function to get the view's offset into the frame's top left position.
|
|
void CWinCX::GetViewOffsetInFrame(CPoint& cpRetval) const {
|
|
// Init.
|
|
cpRetval = CPoint(0, 0);
|
|
|
|
if(GetFrame()->GetFrameWnd() != NULL && GetPane() != NULL) {
|
|
CRect cr;
|
|
::GetWindowRect(GetPane(), cr);
|
|
GetFrame()->GetFrameWnd()->ScreenToClient(cr);
|
|
cpRetval = CPoint(cr.left, cr.top);
|
|
}
|
|
}
|
|
|
|
// Attempt to act modal over the other context.
|
|
// This is assumming that this is being called from FE_MakeNewWindow after
|
|
// the popup window is created as a modal dialog.
|
|
void CWinCX::GoModal(MWContext *pParent)
|
|
{
|
|
// See if the other context can be told to disable it's UI.
|
|
if(pParent == NULL || ABSTRACTCX(pParent) == NULL ||
|
|
ABSTRACTCX(pParent)->IsWindowContext() == FALSE ||
|
|
WINCX(pParent)->GetFrame()->GetFrameWnd() == NULL) {
|
|
|
|
// No way, no UI to deactivate.
|
|
return;
|
|
}
|
|
|
|
// Okay, we can do this.
|
|
CWinCX *pDisableCX = WINCX(pParent);
|
|
|
|
// Disable their window.
|
|
// If the frame has an owned window, e.g. a modal property sheet, disable that
|
|
HWND popup = ::GetLastActivePopup(pDisableCX->GetFrame()->GetFrameWnd()->m_hWnd);
|
|
HWND popupOwner = NULL;
|
|
// Because of the order in which this takes place, the modal dialog has already been added
|
|
// in FE_MakeNewWindow, therefore it will be the last active popup. So we need to get its
|
|
// parent.
|
|
if(popup)
|
|
popupOwner = ::GetParent(popup);
|
|
if(popupOwner)
|
|
::EnableWindow(popupOwner, FALSE);
|
|
// The above call will also disable the popup since it is a child of popupOwner. Therefore
|
|
// we need to enable the popup.
|
|
::EnableWindow(popup, TRUE);
|
|
|
|
// Mark that we need to re enable the other context when we're destroyed.
|
|
// We support modality over any number of context's (in case we need to
|
|
// go modal over the application, this allows it).
|
|
if(popupOwner)
|
|
m_cplModalOver.AddTail((void *)popupOwner);
|
|
}
|
|
|
|
// Register a function to be called when the DestroyContext is called.
|
|
// We only support one at a time, so a list implementation will have to
|
|
// be provided if more than one is needed.
|
|
void CWinCX::CloseCallback(void (*pFunc)(void *), void *pArg)
|
|
{
|
|
// Just assign them in.
|
|
if(pFunc) {
|
|
m_cplCloseCallbacks.AddTail((void *)pFunc);
|
|
m_cplCloseCallbackArgs.AddTail(pArg);
|
|
}
|
|
}
|
|
|
|
// This simply tells the frame if it should do anything special in it's min max handler.
|
|
// If you really need each context to not resize (such as in Frames), then you'll have to
|
|
// redisign this.
|
|
void CWinCX::EnableResize(BOOL bEnable)
|
|
{
|
|
// Must have a frame, a CGenericFrame.
|
|
if(GetFrame()->GetFrameWnd() != NULL &&
|
|
GetFrame()->GetFrameWnd()->IsKindOf(RUNTIME_CLASS(CGenericFrame))) {
|
|
CGenericFrame *pFrame = (CGenericFrame *)GetFrame()->GetFrameWnd();
|
|
pFrame->EnableResize(bEnable);
|
|
}
|
|
}
|
|
|
|
// Don't allow the frame to close.
|
|
// This can't really work on a view by view basis (frames).
|
|
// Also, this assumes the CWinCX resides in a CFrameWnd, which will
|
|
// before handling close call CanCloseDocument on the document.
|
|
void CWinCX::EnableClose(BOOL bEnable)
|
|
{
|
|
// Get our document, and tell it wether or not it will allow the frame to close.
|
|
if(GetDocument()) {
|
|
GetDocument()->EnableClose(bEnable);
|
|
}
|
|
}
|
|
|
|
void CWinCX::DisableHotkeys(BOOL bDisable)
|
|
{
|
|
// Must have a frame, a CGenericFrame.
|
|
if(GetFrame()->GetFrameWnd() != NULL &&
|
|
GetFrame()->GetFrameWnd()->IsKindOf(RUNTIME_CLASS(CGenericFrame))) {
|
|
CGenericFrame *pFrame = (CGenericFrame *)GetFrame()->GetFrameWnd();
|
|
pFrame->DisableHotkeys(bDisable);
|
|
}
|
|
}
|
|
|
|
// Do not allow window to change z-ordering
|
|
void CWinCX::SetZOrder(BOOL bZLock, BOOL bBottommost)
|
|
{
|
|
// Must have a frame, a CGenericFrame.
|
|
if(GetFrame()->GetFrameWnd() != NULL &&
|
|
GetFrame()->GetFrameWnd()->IsKindOf(RUNTIME_CLASS(CGenericFrame))) {
|
|
CGenericFrame *pFrame = (CGenericFrame *)GetFrame()->GetFrameWnd();
|
|
pFrame->SetZOrder(bZLock, bBottommost);
|
|
}
|
|
}
|
|
|
|
// Determine wether or not we can upload files.
|
|
BOOL CWinCX::CanUploadFile()
|
|
{
|
|
BOOL bRetval = TRUE;
|
|
|
|
if(IsDestroyed()) {
|
|
bRetval = FALSE;
|
|
}
|
|
else if(GetPane() == NULL) {
|
|
bRetval = FALSE;
|
|
}
|
|
else if(CanCreateUrlFromHist() == FALSE) {
|
|
bRetval = FALSE;
|
|
}
|
|
else {
|
|
// Must check to make sure we're on the correct type of FTP
|
|
// directory.
|
|
History_entry *pHistoryEntry = SHIST_GetCurrent(&(GetContext()->hist));
|
|
if(pHistoryEntry == NULL || pHistoryEntry->address == NULL) {
|
|
bRetval = FALSE;
|
|
}
|
|
else if(strnicmp(pHistoryEntry->address, "ftp://", 6)) {
|
|
bRetval = FALSE;
|
|
}
|
|
else if(pHistoryEntry->address[strlen(pHistoryEntry->address) - 1] != '/') {
|
|
bRetval = FALSE;
|
|
}
|
|
}
|
|
|
|
return(bRetval);
|
|
}
|
|
|
|
// Upload files.
|
|
void CWinCX::UploadFile()
|
|
{
|
|
if(CanUploadFile() == FALSE) {
|
|
return;
|
|
}
|
|
|
|
// Get the files from the user.
|
|
char *pFileName = wfe_GetExistingFileName(GetPane(), szLoadString(IDS_FILE_UPLOAD), HTM, TRUE);
|
|
|
|
// Null if user hit cancel.
|
|
if(pFileName != NULL) {
|
|
URL_Struct *pUrl = CreateUrlFromHist(TRUE);
|
|
if(pUrl != NULL) {
|
|
// Set this to super reload (per montulli).
|
|
pUrl->force_reload = NET_SUPER_RELOAD;
|
|
|
|
size_t stAlloc = 2 * sizeof(char *);
|
|
pUrl->files_to_post = (char **)XP_ALLOC(stAlloc);
|
|
if(pUrl->files_to_post != NULL) {
|
|
// Clear the array.
|
|
memset(pUrl->files_to_post, 0, stAlloc);
|
|
|
|
// Put in the name.
|
|
// It's already been allocated by the prompt routine, no need to free
|
|
// it in this case.
|
|
pUrl->files_to_post[0] = pFileName;
|
|
|
|
// Ask for it.
|
|
GetUrl(pUrl, FO_CACHE_AND_PRESENT);
|
|
}
|
|
else {
|
|
NET_FreeURLStruct(pUrl);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
typedef struct mouse_over_closure{
|
|
int32 xVal, yVal;
|
|
BOOL bDeleteLO_Element; // in case we created a fake one
|
|
CWinCX * pWin;
|
|
} mouse_over_closure;
|
|
|
|
//
|
|
// The backend just had a chance at a mouse-over event. If it
|
|
// didn't set the status bar text take care of setting it now
|
|
//
|
|
static void
|
|
mouse_over_callback(MWContext * context, LO_Element * lo_element, int32 event,
|
|
void * pObj, ETEventStatus status)
|
|
{
|
|
// keep track of what we have done already so that we
|
|
// don't thrash
|
|
BOOL bTextSet = FALSE;
|
|
BOOL bCursorSet = FALSE;
|
|
LO_EmbedStruct *pEmbed = NULL;
|
|
LO_ImageStruct * image_struct = NULL;
|
|
LO_TextStruct * text_struct = NULL;
|
|
|
|
// get our stashed data
|
|
mouse_over_closure * pClose = (mouse_over_closure *) pObj;
|
|
CWinCX * pWin = pClose->pWin;
|
|
|
|
// make sure the document didn't disappear
|
|
if(status == EVENT_PANIC) {
|
|
XP_FREE(pClose);
|
|
return;
|
|
}
|
|
|
|
// if the status is OK then that means the backend set the
|
|
// status bar text
|
|
if(status == EVENT_OK)
|
|
bTextSet = TRUE;
|
|
|
|
CPoint DocPoint(CASTINT(pClose->xVal), CASTINT(pClose->yVal));
|
|
BOOL bMouseInSelection = pClose->pWin->PtInSelectedRegion( DocPoint );
|
|
|
|
#ifdef EDITOR
|
|
// First check for Table mouse-over events - we don't need the current element
|
|
// since we will look for closest table hit region
|
|
// Don't do this if ALT key is pressed - this allows sizing images (and other objects)
|
|
// which are tightly surrounded by a cell boundary.
|
|
// TODO: Alt key leaves menu select mode on - how do we defeat that behavior?
|
|
|
|
if( EDT_IS_EDITOR(context) && !EDT_IsSizing(context) )
|
|
{
|
|
ED_HitType iTableHit = ED_HIT_NONE;
|
|
if( pWin->m_bSelectingCells )
|
|
{
|
|
// User is dragging mouse to select table cells
|
|
// Return value tells us what kind of cursor to use
|
|
iTableHit = EDT_ExtendTableCellSelection(context, pClose->xVal, pClose->yVal);
|
|
}
|
|
else if( GetAsyncKeyState(VK_MENU) >= 0 ) // Alt key test
|
|
{
|
|
// See if we are over a table or cell "hit" region and need a special cursor
|
|
// Get hit region - we don't need to know element, so use NULL for 4th param
|
|
// If 5th param is TRUE, then select all cells if in upper left corner of table,
|
|
// or select/unselect cell if mouse is ANYWHERE inside of the cell
|
|
iTableHit = EDT_GetTableHitRegion(context, pClose->xVal, pClose->yVal, NULL, GetAsyncKeyState(VK_CONTROL));
|
|
}
|
|
if( iTableHit )
|
|
{
|
|
bCursorSet = TRUE;
|
|
switch( iTableHit )
|
|
{
|
|
case ED_HIT_SEL_TABLE: // Upper left corner
|
|
SetCursor(theApp.LoadCursor(IDC_TABLE_SEL));
|
|
break;
|
|
case ED_HIT_SEL_ALL_CELLS: // Upper left corner with Ctrl pressed
|
|
SetCursor(theApp.LoadCursor(IDC_ALL_CELLS_SEL));
|
|
break;
|
|
case ED_HIT_SEL_COL: // Near Top table border
|
|
SetCursor(theApp.LoadCursor(IDC_COL_SEL));
|
|
break;
|
|
case ED_HIT_SEL_ROW: // Near left table border
|
|
SetCursor(theApp.LoadCursor(IDC_ROW_SEL));
|
|
break;
|
|
case ED_HIT_SEL_CELL: // Not sure - remaining cell border not matching other regions
|
|
SetCursor(theApp.LoadCursor(IDC_CELL_SEL));
|
|
break;
|
|
case ED_HIT_SIZE_TABLE_WIDTH: // Right edge of table
|
|
SetCursor(theApp.LoadCursor(IDC_TABLE_SIZE));
|
|
break;
|
|
case ED_HIT_SIZE_TABLE_HEIGHT: // Bottom edge of table
|
|
SetCursor(theApp.LoadCursor(IDC_TABLE_VSIZE));
|
|
break;
|
|
case ED_HIT_SIZE_COL: // Right border of a cell
|
|
SetCursor(theApp.LoadCursor(IDC_COL_SIZE));
|
|
break;
|
|
case ED_HIT_SIZE_ROW: // Right border of a cell
|
|
SetCursor(theApp.LoadCursor(IDC_ROW_SIZE));
|
|
break;
|
|
case ED_HIT_ADD_ROWS: // Lower left corner
|
|
SetCursor(theApp.LoadCursor(IDC_ADD_ROWS));
|
|
break;
|
|
case ED_HIT_ADD_COLS: // Lower right corner
|
|
SetCursor(theApp.LoadCursor(IDC_ADD_COLS));
|
|
break;
|
|
case ED_HIT_DRAG_TABLE: // Near bottom
|
|
SetCursor(theApp.LoadCursor(IDC_ARROW_HAND));
|
|
break;
|
|
}
|
|
goto FINISH_MOUSE_OVER;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// See if we are over some text that is a link
|
|
text_struct = (LO_TextStruct *) lo_element;
|
|
|
|
// Imagemaps send their mouseover events as dummy text structs. Be very careful
|
|
// about what you try to use from this text struct as many of the fields are
|
|
// invalid.
|
|
if(text_struct && text_struct->type == LO_TEXT && text_struct->text)
|
|
{
|
|
BOOL bIsLink = (text_struct->anchor_href && text_struct->anchor_href->anchor);
|
|
if(bIsLink && !bTextSet)
|
|
{
|
|
wfe_Progress(context, (char *) text_struct->anchor_href->anchor);
|
|
bTextSet = TRUE;
|
|
}
|
|
if( EDT_IS_EDITOR(context) )
|
|
{
|
|
#ifdef EDITOR
|
|
if( EDT_CanPasteStyle(context) )
|
|
{
|
|
SetCursor(theApp.LoadCursor(IDC_COPY_STYLE));
|
|
bCursorSet = TRUE;
|
|
}
|
|
else if( bMouseInSelection )
|
|
{
|
|
// Indicate that user can drag selected text with special cursor
|
|
SetCursor(theApp.LoadCursor(IDC_IBEAM_HAND));
|
|
bCursorSet = TRUE;
|
|
}
|
|
#else
|
|
XP_ASSERT(0);
|
|
#endif
|
|
} else if( bIsLink )
|
|
{
|
|
// Set anchor cursor only if not in editor
|
|
SetCursor(theApp.LoadCursor(IDC_SELECTANCHOR));
|
|
bCursorSet = TRUE;
|
|
}
|
|
if( !bCursorSet )
|
|
{
|
|
// We have 2 text cursor sizes -- more visible for large fonts
|
|
SetCursor( theApp.LoadCursor(
|
|
text_struct->height > 20 ? IDC_EDIT_IBEAM_LARGE : IDC_EDIT_IBEAM) );
|
|
bCursorSet = TRUE;
|
|
}
|
|
}
|
|
#ifdef EDITOR
|
|
else if( EDT_IS_EDITOR(context) &&
|
|
lo_element &&
|
|
!EDT_IsSizing(context) )
|
|
{
|
|
|
|
// Test for proximity to border of sizeable objects
|
|
// This sets the cursor to system sizing cursor
|
|
// Note: X, Y are in View coordinates
|
|
|
|
int sizing = EDT_CanSizeObject(context, lo_element, pClose->xVal, pClose->yVal);
|
|
if( sizing )
|
|
{
|
|
switch ( sizing )
|
|
{
|
|
case ED_SIZE_TOP:
|
|
case ED_SIZE_BOTTOM:
|
|
SetCursor(theApp.LoadStandardCursor(IDC_SIZENS));
|
|
break;
|
|
case ED_SIZE_RIGHT:
|
|
// Tables and cells can only size from the right border
|
|
if( lo_element->type == LO_TABLE )
|
|
{
|
|
SetCursor(theApp.LoadCursor(IDC_TABLE_SIZE));
|
|
break;
|
|
}
|
|
if( lo_element->type == LO_CELL )
|
|
{
|
|
SetCursor(theApp.LoadCursor(IDC_COL_SIZE));
|
|
break;
|
|
}
|
|
// If not Table or Cell, fall through
|
|
// to set horizontal sizing cursor
|
|
case ED_SIZE_LEFT:
|
|
SetCursor(theApp.LoadStandardCursor(IDC_SIZEWE));
|
|
break;
|
|
case ED_SIZE_TOP_RIGHT:
|
|
case ED_SIZE_BOTTOM_LEFT:
|
|
SetCursor(theApp.LoadStandardCursor(IDC_SIZENESW));
|
|
break;
|
|
case ED_SIZE_TOP_LEFT:
|
|
case ED_SIZE_BOTTOM_RIGHT:
|
|
SetCursor(theApp.LoadStandardCursor(IDC_SIZENWSE));
|
|
break;
|
|
}
|
|
bCursorSet = TRUE;
|
|
}
|
|
}
|
|
#endif // EDITOR
|
|
// NOTE: We set the imagemap and status line stuff even if we set a "sizing" cursor
|
|
|
|
// See if we are over an image that is a link
|
|
image_struct = (LO_ImageStruct *) lo_element;
|
|
if(image_struct && image_struct->type == LO_IMAGE && image_struct->image_attr) {
|
|
if(image_struct->image_attr->usemap_name != NULL) {
|
|
CPoint image_offset;
|
|
image_offset.x = CASTINT(pClose->xVal - (image_struct->x + image_struct->x_offset + image_struct->border_width));
|
|
image_offset.y = CASTINT(pClose->yVal - (image_struct->y + image_struct->y_offset + image_struct->border_width));
|
|
|
|
LO_AnchorData *pAnchorData = LO_MapXYToAreaAnchor(pWin->GetDocumentContext(), image_struct,
|
|
image_offset.x, image_offset.y);
|
|
if(pAnchorData != NULL) {
|
|
if( !EDT_IS_EDITOR(context) && !bMouseInSelection ){
|
|
SetCursor(theApp.LoadCursor(IDC_SELECTANCHOR));
|
|
bCursorSet = TRUE;
|
|
}
|
|
if( pAnchorData->anchor && !bTextSet ) {
|
|
wfe_Progress(context, (char *) pAnchorData->anchor);
|
|
bTextSet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else if((image_struct->image_attr->attrmask & LO_ATTR_ISMAP) && image_struct->anchor_href) {
|
|
// if its an ismap print the coordinates too
|
|
char buf[32];
|
|
CPoint point;
|
|
|
|
point.x = (int) (pClose->xVal - (image_struct->x + image_struct->x_offset));
|
|
point.y = (int) (pClose->yVal - (image_struct->y + image_struct->y_offset));
|
|
|
|
sprintf(buf, "?%d,%d", point.x, point.y);
|
|
|
|
CString anchor;
|
|
anchor = (char *) image_struct->anchor_href->anchor;
|
|
anchor += buf;
|
|
|
|
if( !EDT_IS_EDITOR(context) && !bMouseInSelection ){
|
|
SetCursor(theApp.LoadCursor(IDC_SELECTANCHOR));
|
|
bCursorSet = TRUE;
|
|
}
|
|
// Set progress text if mocha allows it.
|
|
if(!bTextSet) {
|
|
wfe_Progress(context, (const char *)anchor);
|
|
bTextSet = TRUE;
|
|
}
|
|
}
|
|
else if(image_struct->anchor_href) {
|
|
// Set anchor cursor only if not in editor and not in a selection
|
|
if( !EDT_IS_EDITOR(context) && !bMouseInSelection ) {
|
|
SetCursor(theApp.LoadCursor(IDC_SELECTANCHOR));
|
|
bCursorSet = TRUE;
|
|
}
|
|
if (image_struct->anchor_href->anchor && !bTextSet) {
|
|
wfe_Progress(context, (char *) image_struct->anchor_href->anchor);
|
|
bTextSet = TRUE;
|
|
}
|
|
}
|
|
else if(image_struct->image_attr->attrmask & LO_ATTR_INTERNAL_IMAGE
|
|
&& EDT_IS_EDITOR(context)
|
|
&& image_struct->alt != NULL ){
|
|
|
|
char *str;
|
|
if(!bTextSet) {
|
|
PA_LOCK(str, char *, image_struct->alt);
|
|
if( str != 0 ){
|
|
wfe_Progress( context, str );
|
|
bTextSet = TRUE;
|
|
}
|
|
PA_UNLOCK(image_struct->alt);
|
|
}
|
|
}
|
|
if( EDT_IS_EDITOR(context) && !bCursorSet ){
|
|
// Experimental: Image can be dragged, so if no cursor set above,
|
|
// use Open Hand with arrow to indicate "draggability" of the image
|
|
SetCursor(theApp.LoadCursor(IDC_ARROW_HAND));
|
|
bCursorSet = TRUE;
|
|
}
|
|
}
|
|
|
|
// See if we are over an embedded item.
|
|
pEmbed = (LO_EmbedStruct *)lo_element;
|
|
if(pEmbed && pEmbed->type == LO_EMBED && pEmbed->FE_Data) {
|
|
NPEmbeddedApp *pPluginShim = (NPEmbeddedApp *)pEmbed->FE_Data;
|
|
if(pPluginShim != NULL && wfe_IsTypePlugin(pPluginShim) == FALSE) {
|
|
CNetscapeCntrItem *pItem = (CNetscapeCntrItem *)pPluginShim->fe_data;
|
|
if(pItem != NULL && pItem->m_bLoading == FALSE && pItem->m_bBroken == FALSE &&
|
|
pItem->m_bDelayed == FALSE && pItem->m_lpObject != NULL)
|
|
{
|
|
if( !bMouseInSelection ){
|
|
SetCursor(theApp.LoadCursor(IDC_ACTIVATE_EMBED));
|
|
bCursorSet = TRUE;
|
|
}
|
|
|
|
if(!bTextSet) {
|
|
CString csEmbed;
|
|
csEmbed.LoadString(IDS_ACTIVATE_EMBED_STATUS);
|
|
CString csDescrip;
|
|
pItem->GetUserType(USERCLASSTYPE_FULL, csDescrip);
|
|
csEmbed += csDescrip;
|
|
|
|
wfe_Progress(context, (char *)(const char *)csEmbed);
|
|
bTextSet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
FINISH_MOUSE_OVER:
|
|
// If nothing set yet blank it out and make sure we have the
|
|
// normal cursor. Do we really want to reset the cursor
|
|
// here????
|
|
// We want to show link text but keep edit cursor in Editor
|
|
if(!bCursorSet){
|
|
SetCursor(theApp.LoadStandardCursor(IDC_ARROW));
|
|
}
|
|
if(!bTextSet) {
|
|
wfe_Progress(context, "");
|
|
bTextSet = TRUE;
|
|
}
|
|
|
|
// For mouse overs on anchors we may have created a fake
|
|
// LO_Element structure. If so, blow it away now
|
|
if(pClose->bDeleteLO_Element)
|
|
XP_FREE(lo_element);
|
|
|
|
XP_FREE(pClose);
|
|
|
|
// Have the mouse timer handler do some dirty work.
|
|
// Please don't return in the above code, I'd like this to get called
|
|
// in all cases with the state of the buttons set correctly.
|
|
MouseTimerData mt(context);
|
|
FEU_MouseTimer(&mt);
|
|
|
|
}
|
|
|
|
// Function to handle the details of the cursor being over an element
|
|
// and telling the back end about it. If the backend doesn't
|
|
// set the text, the text will get set in our clallback routine
|
|
void CWinCX::FireMouseOverEvent(LO_Element *pElement, int32 xVal, int32 yVal,
|
|
CL_Layer *layer)
|
|
{
|
|
mouse_over_closure * pClose = NULL;
|
|
LO_Element * pDummy;
|
|
BOOL bEventSent = FALSE;
|
|
|
|
#define CREATE_CLOSURE() { pClose = XP_NEW_ZAP(mouse_over_closure); \
|
|
pClose->xVal = xVal; pClose->yVal = yVal; \
|
|
pClose->pWin = this; }
|
|
|
|
// The mouse is over nothing, fire an out message for the last element.
|
|
if(pElement == NULL) {
|
|
FireMouseOutEvent(TRUE, TRUE, xVal, yVal, layer);
|
|
}
|
|
// If a different element, fire an out message for the last element,
|
|
// and then fire an over message for the new element.
|
|
else if(pElement != m_pLastOverElement) {
|
|
FireMouseOutEvent(TRUE, TRUE, xVal, yVal, layer);
|
|
|
|
m_pLastOverElement = pElement;
|
|
m_pLastOverAnchorData = GetAreaAnchorData(m_pLastOverElement);
|
|
|
|
// JS needs screen coords for click events.
|
|
CPoint cpScreenPoint(xVal, yVal);
|
|
ClientToScreen(GetPane(), &cpScreenPoint);
|
|
|
|
// Fire over messages.
|
|
if(m_pLastOverAnchorData)
|
|
{
|
|
CREATE_CLOSURE();
|
|
// need to make a fake wrapper for m_pLastOverAnchorData
|
|
pDummy = (LO_Element *) XP_NEW_ZAP(LO_Element);
|
|
pDummy->lo_text.type = LO_TEXT;
|
|
pDummy->lo_text.anchor_href = m_pLastOverAnchorData;
|
|
// We use the text of the element to determine if it is still
|
|
// valid later so give the dummy text struct's text a value.
|
|
if (pDummy->lo_text.anchor_href->anchor)
|
|
pDummy->lo_text.text = pDummy->lo_text.anchor_href->anchor;
|
|
|
|
// need to free fake wrapper for m_pLastOverAnchorData
|
|
pClose->bDeleteLO_Element = TRUE;
|
|
|
|
// its safe to send the event now
|
|
JSEvent *event;
|
|
event = XP_NEW_ZAP(JSEvent);
|
|
event->type = EVENT_MOUSEOVER;
|
|
event->x = xVal;
|
|
event->y = yVal;
|
|
event->docx = xVal + CL_GetLayerXOrigin(layer);
|
|
event->docy = yVal + CL_GetLayerYOrigin(layer);
|
|
event->screenx = cpScreenPoint.x;
|
|
event->screeny = cpScreenPoint.y;
|
|
|
|
event->layer_id = LO_GetIdFromLayer(GetContext(), layer);
|
|
|
|
ET_SendEvent(GetContext(), pDummy, event,
|
|
mouse_over_callback, pClose);
|
|
bEventSent = TRUE;
|
|
}
|
|
else if(m_pLastOverElement && (m_pLastOverElement->type == LO_IMAGE ||
|
|
m_pLastOverElement->type == LO_FORM_ELE ||
|
|
(m_pLastOverElement->type == LO_TEXT
|
|
&& m_pLastOverElement->lo_text.anchor_href)
|
|
#ifdef DOM
|
|
|| LO_IsWithinSpan(m_pLastOverElement)
|
|
#endif
|
|
))
|
|
{
|
|
CREATE_CLOSURE();
|
|
JSEvent *event;
|
|
event = XP_NEW_ZAP(JSEvent);
|
|
event->type = EVENT_MOUSEOVER;
|
|
event->x = xVal;
|
|
event->y = yVal;
|
|
event->docx = xVal + CL_GetLayerXOrigin(layer);
|
|
event->docy = yVal + CL_GetLayerYOrigin(layer);
|
|
event->screenx = cpScreenPoint.x;
|
|
event->screeny = cpScreenPoint.y;
|
|
event->layer_id = LO_GetIdFromLayer(GetContext(), layer);
|
|
|
|
ET_SendEvent(GetContext(), m_pLastOverElement, event,
|
|
mouse_over_callback, pClose);
|
|
bEventSent = TRUE;
|
|
}
|
|
}
|
|
// If the same element, they have possibly traversed into a new
|
|
// AnchorData AREA, fire an out message, and then fire an
|
|
// over message if so.
|
|
// DO NOT send redundant over messages.
|
|
else if(pElement == m_pLastOverElement) {
|
|
LO_AnchorData *pAnchorData = GetAreaAnchorData(pElement);
|
|
if(pAnchorData != m_pLastOverAnchorData) {
|
|
if(m_pLastOverAnchorData) {
|
|
// Only do this if there is last anchor data, or we
|
|
// fire mouse out on the element and not the data.
|
|
FireMouseOutEvent(FALSE, TRUE, xVal, yVal, layer);
|
|
}
|
|
m_pLastOverAnchorData = pAnchorData;
|
|
if(m_pLastOverAnchorData) {
|
|
// JS needs screen coords for click events.
|
|
CPoint cpScreenPoint(xVal, yVal);
|
|
ClientToScreen(GetPane(), &cpScreenPoint);
|
|
|
|
CREATE_CLOSURE();
|
|
// need to make a fake wrapper for m_pLastOverAnchorData
|
|
pDummy = (LO_Element *) XP_NEW_ZAP(LO_Element);
|
|
pDummy->lo_text.type = LO_TEXT;
|
|
pDummy->lo_text.anchor_href = m_pLastOverAnchorData;
|
|
|
|
// We use the text of the element to determine if it is still
|
|
// valid later so give the dummy text struct's text a value.
|
|
if (pDummy->lo_text.anchor_href->anchor)
|
|
pDummy->lo_text.text = pDummy->lo_text.anchor_href->anchor;
|
|
|
|
// need to free fake wrapper for m_pLastOverAnchorData
|
|
pClose->bDeleteLO_Element = TRUE;
|
|
|
|
// its safe to send the event now
|
|
JSEvent *event;
|
|
event = XP_NEW_ZAP(JSEvent);
|
|
event->type = EVENT_MOUSEOVER;
|
|
event->x = xVal;
|
|
event->y = yVal;
|
|
event->docx = xVal + CL_GetLayerXOrigin(layer);
|
|
event->docy = yVal + CL_GetLayerYOrigin(layer);
|
|
event->screenx = cpScreenPoint.x;
|
|
event->screeny = cpScreenPoint.y;
|
|
event->layer_id = LO_GetIdFromLayer(GetContext(), layer);
|
|
|
|
ET_SendEvent(GetContext(), pDummy, event,
|
|
mouse_over_callback, pClose);
|
|
bEventSent = TRUE;
|
|
}
|
|
}
|
|
// If this is an ismap and we've moved within it, we need to
|
|
// change status without firing off a mouse over.
|
|
else if(pElement->lo_any.type == LO_IMAGE) {
|
|
LO_ImageStruct *image_struct = (LO_ImageStruct *)pElement;
|
|
if((image_struct->image_attr->usemap_name == NULL) && (image_struct->image_attr->attrmask & LO_ATTR_ISMAP) && image_struct->anchor_href) {
|
|
// if its an ismap print the coordinates too
|
|
char buf[32];
|
|
CPoint point;
|
|
|
|
point.x = (int) (xVal - (image_struct->x + image_struct->x_offset));
|
|
point.y = (int) (yVal - (image_struct->y + image_struct->y_offset));
|
|
|
|
sprintf(buf, "?%d,%d", point.x, point.y);
|
|
|
|
CString anchor;
|
|
anchor = (char *) image_struct->anchor_href->anchor;
|
|
anchor += buf;
|
|
|
|
if (!EDT_IS_EDITOR(GetContext())) {
|
|
SetCursor(theApp.LoadCursor(IDC_SELECTANCHOR));
|
|
}
|
|
|
|
// Set progress text
|
|
wfe_Progress(GetContext(), (const char *)anchor);
|
|
}
|
|
if (!EDT_IS_EDITOR(GetContext()))
|
|
bEventSent = TRUE;
|
|
}
|
|
// Editor wants callback to be callled every time, the Browser does not. If
|
|
// we're over the same element it may have set the status bar message when we
|
|
// entered it. Don't let the Browser set the status bar again until we leave it.
|
|
// If the element didn't want to set the status bar, the Browser will have already
|
|
// set it correctly anyway.
|
|
else if (!EDT_IS_EDITOR(GetContext()))
|
|
bEventSent = TRUE;
|
|
}
|
|
|
|
// In the Editor, ALWAYS call the final callback
|
|
// so we can monitor mouse location for dynamic resizing of elements
|
|
if( !bEventSent ) {
|
|
CREATE_CLOSURE();
|
|
// Note: param 3 ("event") isn't used in mouse_over_callback
|
|
mouse_over_callback(GetContext(), pElement, 0, (void*)pClose, EVENT_CANCEL);
|
|
}
|
|
|
|
|
|
// We're using a timer to deal with the lack of a Windows call for entrance
|
|
// and exit for a window. Deal with it here.
|
|
|
|
if (!m_bMouseMoveTimerSet) {
|
|
// This is our first time into the document or our last. Start the timer to check
|
|
// for our exit and fire a mouseover for the window.
|
|
POINT mp;
|
|
// get mouse position
|
|
::GetCursorPos(&mp);
|
|
|
|
if (::WindowFromPoint(mp) == GetPane()) {
|
|
MouseMoveTimerData mt(GetContext());
|
|
FEU_MouseMoveTimer(&mt);
|
|
}
|
|
}
|
|
|
|
/* Unix and Mac are not up to spec on these and won't be for 4.0 Commenting
|
|
* them out for future use later */
|
|
|
|
/*JSEvent *event;
|
|
event = XP_NEW_ZAP(JSEvent);
|
|
event->type = EVENT_MOUSEOVER;
|
|
event->x = xVal;
|
|
event->y = yVal;
|
|
event->layer_id = LO_DOCUMENT_LAYER_ID;
|
|
|
|
ET_SendEvent(GetContext(), 0, event, 0, 0);
|
|
}
|
|
else {
|
|
// We may have left the document. If so, send a mouseout to the window.
|
|
POINT mp;
|
|
// get mouse position
|
|
::GetCursorPos(&mp);
|
|
|
|
if ((::WindowFromPoint(mp) != GetPane()) && !m_bLBDown) {
|
|
//Yup, we left.
|
|
JSEvent *event;
|
|
event = XP_NEW_ZAP(JSEvent);
|
|
event->type = EVENT_MOUSEOUT;
|
|
event->x = xVal;
|
|
event->y = yVal;
|
|
event->layer_id = LO_DOCUMENT_LAYER_ID;
|
|
|
|
ET_SendEvent(GetContext(), 0, event, 0, 0);
|
|
}
|
|
} */
|
|
return;
|
|
|
|
#undef CREATE_CLOSURE
|
|
}
|
|
|
|
// Retrieve anchor data out of areas only (usemaps)
|
|
// Use last known mouse move coordinates to do so.
|
|
LO_AnchorData *CWinCX::GetAreaAnchorData(LO_Element *pElement) {
|
|
LO_AnchorData *pRetval = NULL;
|
|
|
|
// Make sure this is an image element.
|
|
if(pElement && pElement->lo_any.type == LO_IMAGE) {
|
|
// Determine coordinates in pixels with image as origin and
|
|
// ask layout for area anchor data, will return NULL if none.
|
|
LTRB Rect;
|
|
LO_ImageStruct *pLOImage = (LO_ImageStruct *)pElement;
|
|
|
|
// Use the returned value to convert the mouse coordinates
|
|
// to be image relative.
|
|
ResolveElement(Rect, pLOImage->x, pLOImage->y,
|
|
pLOImage->x_offset + pLOImage->border_width,
|
|
pLOImage->y_offset + pLOImage->border_width,
|
|
0, 0);
|
|
if (pLOImage->layer) {
|
|
CL_Layer *parent;
|
|
int32 x_offset, y_offset;
|
|
|
|
parent = CL_GetLayerParent(pLOImage->layer);
|
|
|
|
if (parent) {
|
|
x_offset = CL_GetLayerXOrigin(parent);
|
|
y_offset = CL_GetLayerYOrigin(parent);
|
|
|
|
Rect.left += x_offset;
|
|
Rect.right += x_offset;
|
|
Rect.top += y_offset;
|
|
Rect.bottom += y_offset;
|
|
}
|
|
}
|
|
|
|
pRetval = LO_MapXYToAreaAnchor(GetDocumentContext(), pLOImage,
|
|
m_cpMMove.x - Rect.left, m_cpMMove.y - Rect.top);
|
|
}
|
|
|
|
return(pRetval);
|
|
}
|
|
|
|
static void
|
|
free_this_callback(MWContext * context, LO_Element * lo_element, int32 event,
|
|
void * pObj, ETEventStatus status)
|
|
{
|
|
XP_FREE(pObj);
|
|
}
|
|
|
|
// Fire mouse out events for cached element types.
|
|
void CWinCX::FireMouseOutEvent(BOOL bClearElement, BOOL bClearAnchor, int32 xVal,
|
|
int32 yVal, CL_Layer *layer)
|
|
{
|
|
// JS needs screen coords for click events.
|
|
CPoint cpScreenPoint(xVal, yVal);
|
|
ClientToScreen(GetPane(), &cpScreenPoint);
|
|
|
|
// Determine if we're sending an anchor out or an element out.
|
|
if(m_pLastOverAnchorData)
|
|
{
|
|
// Anchor data.
|
|
// Create a fake holder element here since we didn't save enough
|
|
// information and Win16 won't let us pass stack variables
|
|
LO_Element * element = XP_NEW_ZAP(LO_Element);
|
|
element->lo_text.type = LO_TEXT;
|
|
element->lo_text.anchor_href = m_pLastOverAnchorData;
|
|
|
|
// We use the text of the element to determine if it is still
|
|
// valid later so give the dummy text struct's text a value.
|
|
if (element->lo_text.anchor_href->anchor)
|
|
element->lo_text.text = element->lo_text.anchor_href->anchor;
|
|
|
|
JSEvent *event;
|
|
event = XP_NEW_ZAP(JSEvent);
|
|
event->type = EVENT_MOUSEOUT;
|
|
event->x = xVal;
|
|
event->y = yVal;
|
|
event->docx = xVal + CL_GetLayerXOrigin(layer);
|
|
event->docy = yVal + CL_GetLayerYOrigin(layer);
|
|
event->screenx = cpScreenPoint.x;
|
|
event->screeny = cpScreenPoint.y;
|
|
|
|
event->layer_id = LO_GetIdFromLayer(GetContext(), layer);
|
|
|
|
ET_SendEvent(GetContext(), element, event,
|
|
free_this_callback, element);
|
|
}
|
|
else if(m_pLastOverElement && (m_pLastOverElement->type == LO_IMAGE
|
|
|| m_pLastOverElement->type == LO_FORM_ELE ||
|
|
(m_pLastOverElement->type == LO_TEXT &&
|
|
m_pLastOverElement->lo_text.anchor_href)
|
|
#ifdef DOM
|
|
|| LO_IsWithinSpan(m_pLastOverElement)
|
|
#endif
|
|
))
|
|
{
|
|
// Element.
|
|
JSEvent *event;
|
|
event = XP_NEW_ZAP(JSEvent);
|
|
event->type = EVENT_MOUSEOUT;
|
|
event->x = xVal;
|
|
event->y = yVal;
|
|
event->docx = xVal + CL_GetLayerXOrigin(layer);
|
|
event->docy = yVal + CL_GetLayerYOrigin(layer);
|
|
event->screenx = cpScreenPoint.x;
|
|
event->screeny = cpScreenPoint.y;
|
|
|
|
event->layer_id = LO_GetIdFromLayer(GetContext(), layer);
|
|
|
|
ET_SendEvent(GetContext(), m_pLastOverElement, event,
|
|
NULL, this);
|
|
}
|
|
|
|
//
|
|
// Mocha may have trashed the docuemnt, but it will still be safe
|
|
// to set the following elements to NULL. Mocha can't have
|
|
// destroyed our context yet
|
|
//
|
|
|
|
if(bClearElement) {
|
|
m_pLastOverElement = NULL;
|
|
}
|
|
if(bClearAnchor) {
|
|
m_pLastOverAnchorData = NULL;
|
|
}
|
|
|
|
// Clean up, these can now be empty.
|
|
m_bLastOverTextSet = FALSE;
|
|
}
|
|
|
|
CFrameGlue *CWinCX::GetFrame() const
|
|
{
|
|
// If we're a grid cell, return the
|
|
// parent's frame (one in the same)
|
|
// This allows those scary times when we're
|
|
// a grid in an OLE server to work better
|
|
// when the frame's switch.
|
|
MWContext *pParent = GetParentContext();
|
|
if(IsGridCell() && pParent) {
|
|
if(ABSTRACTCX(pParent)->IsFrameContext()) {
|
|
return(WINCX(pParent)->GetFrame());
|
|
}
|
|
}
|
|
|
|
// Make sure our frame isn't NULL.
|
|
// If so, go with the NULL frame.
|
|
// Could happen if the frame is destroyed, but the
|
|
// context lives.
|
|
if(m_pFrame == NULL) {
|
|
return(m_pNullFrame);
|
|
}
|
|
return m_pFrame;
|
|
}
|
|
|
|
void CWinCX::ClearView()
|
|
{
|
|
// Tell the view and frame that we're no more.
|
|
if(m_pGenView != NULL) {
|
|
// Also, if we're selecting text, clear our capture of the mouse.
|
|
if(m_bLBDown == TRUE) {
|
|
::ReleaseCapture();
|
|
}
|
|
m_pGenView->ClearContext();
|
|
m_pGenView = NULL;
|
|
}
|
|
}
|
|
|
|
BOOL CWinCX::IsClickingEnabled() const
|
|
{
|
|
#ifdef EDITOR
|
|
return(GetContext()->waitingMode == FALSE && GetContext()->edit_saving_url == FALSE);
|
|
#else
|
|
return(GetContext()->waitingMode == FALSE);
|
|
#endif
|
|
}
|
|
|
|
//#ifndef NO_TAB_NAVIGATION
|
|
LO_TabFocusData * CWinCX::getLastTabFocusData()
|
|
{
|
|
return( &m_lastTabFocus );
|
|
}
|
|
|
|
LO_Element * CWinCX::getLastTabFocusElement()
|
|
{
|
|
return( m_lastTabFocus.pElement );
|
|
}
|
|
|
|
int32 CWinCX::getLastFocusAreaIndex()
|
|
{
|
|
return( m_lastTabFocus.mapAreaIndex ); // 0 means no focus, start with index 1.
|
|
}
|
|
|
|
LO_AnchorData *CWinCX::getLastFocusAnchorPointer()
|
|
{
|
|
return( m_lastTabFocus.pAnchor );
|
|
}
|
|
|
|
char *CWinCX::getLastFocusAnchorStr()
|
|
{
|
|
if( m_lastTabFocus.pAnchor == NULL)
|
|
return( NULL );
|
|
|
|
return( (char *)m_lastTabFocus.pAnchor->anchor );
|
|
}
|
|
|
|
// When an element gets or losts Tab Focus, we need to invalidate it and hence to redraw it.
|
|
// check if(GetPane() && CanBlockDisplay() ) before calling invalidateElement().
|
|
void CWinCX::invalidateElement( LO_Element *pElement )
|
|
{
|
|
if( pElement == NULL )
|
|
return;
|
|
|
|
// find out which element needs refresh.
|
|
LTRB Rect;
|
|
BOOL rectEmpty;
|
|
LO_ImageStruct *pImage;
|
|
LO_Any *pp = (LO_Any *)pElement;
|
|
|
|
rectEmpty = TRUE;
|
|
|
|
switch( pElement->lo_any.type ) {
|
|
case LO_FORM_ELE :
|
|
if( LO_isFormElementNeedTextTabFocus( (LO_FormElementStruct *)pElement) ) {
|
|
// for Form element type FORM_TYPE_RADIO and FORM_TYPE_CHECKBOX,
|
|
// it is the next Text element, with dotted box, needs refresh.
|
|
pp = (LO_Any *)pElement->lo_any.next;
|
|
}
|
|
// for other Form element type( button, text input...), the widget handles the focus.
|
|
if (pp)
|
|
{
|
|
ResolveElement(Rect, pp->x, pp->y, pp->x_offset,pp->y_offset, pp->width, pp->height);
|
|
rectEmpty = FALSE;
|
|
}
|
|
break;
|
|
case LO_TEXT :
|
|
// for a text(link), the element itself has a dotted box as focus.
|
|
ResolveElement(Rect, pp->x, pp->y, pp->x_offset,pp->y_offset, pp->width, pp->height);
|
|
rectEmpty = FALSE;
|
|
break;
|
|
case LO_IMAGE :
|
|
// TODO only invalidate the area, not the whole map image.
|
|
pImage = &pElement->lo_image;
|
|
ResolveElement(Rect, IL_GetImagePixmap(pImage->image_req),
|
|
pImage->x_offset + pImage->border_width,
|
|
pImage->y_offset + pImage->border_width,
|
|
pImage->x, pImage->y, pImage->width, pImage->height, 0, 0);
|
|
|
|
rectEmpty = FALSE;
|
|
break;
|
|
default :
|
|
rectEmpty = TRUE;
|
|
break;
|
|
}
|
|
|
|
if( rectEmpty )
|
|
return;
|
|
|
|
// no background erase
|
|
::InvalidateRect(GetPane(), CRect(CASTINT(Rect.left), CASTINT(Rect.top), CASTINT(Rect.right), CASTINT(Rect.bottom)), FALSE);
|
|
|
|
}
|
|
|
|
void CWinCX::SetActiveWindow()
|
|
{
|
|
// Set my view to be the active view, so I will get keyboard input.
|
|
// SetFocus cannot get keyboard, and it would grab focus from
|
|
// Form elements. They need focus to process SpaceBar etc.
|
|
CFrameGlue * pFrame = GetFrame();
|
|
if( pFrame ) {
|
|
CFrameWnd * pFrameWindow = pFrame->GetFrameWnd();
|
|
if( pFrameWindow && pFrameWindow->IsKindOf(RUNTIME_CLASS(CGenericFrame))) {
|
|
CGenericView *pView = GetView();
|
|
if( pView )
|
|
pFrameWindow->SetActiveView( (CView *)pView );
|
|
}
|
|
} // else something wrong.
|
|
|
|
}
|
|
|
|
// this function is trigered by clicking in a form element, or link,
|
|
// the form element has set focus to itself. we need to clear old focus only.
|
|
// for clicking on link, we don't need to call Windows' setFocus().
|
|
void CWinCX::setFormElementTabFocus( LO_Element * pFormElement )
|
|
{
|
|
LO_TabFocusData newTabFocus;
|
|
|
|
if(pFormElement == getLastTabFocusElement() ) // clicking on the focused element.
|
|
return;
|
|
|
|
newTabFocus.pElement = pFormElement;
|
|
MWContext *pContext = GetContext();
|
|
|
|
// for clicking area.
|
|
newTabFocus.mapAreaIndex = 0; // 0 means no area.
|
|
newTabFocus.pAnchor = NULL;
|
|
|
|
// double check tab-able, and fill in pAnchor
|
|
if( LO_isTabableElement(pContext, &newTabFocus ) ) {
|
|
setLastTabFocusElement( &newTabFocus, 0 ); // clicked, 0 means don't needSetFocus
|
|
SetMainFrmTabFocusFlag(CMainFrame::TAB_FOCUS_IN_GRID); // I have tab focus.
|
|
}
|
|
|
|
}
|
|
|
|
// text element may be fragmented in multiple lines, for Tab_focus, they
|
|
// need to be treated as one tab stop.
|
|
int CWinCX::invalidateSegmentedTextElement(LO_TabFocusData *pNextTabFocus, int forward )
|
|
{
|
|
int count = 0;
|
|
LO_Element *pElement;
|
|
pElement = pNextTabFocus->pElement;
|
|
while( pElement &&
|
|
(pElement->lo_any.type == LO_TEXT || pElement->lo_any.type == LO_LINEFEED) ) {
|
|
// skip LO_LINEFEED
|
|
if( pElement->lo_any.type == LO_TEXT ) {
|
|
if( pElement->lo_text.anchor_href
|
|
&& pElement->lo_text.anchor_href == pNextTabFocus->pAnchor ) {
|
|
FEU_MakeElementVisible( GetContext(), (LO_Any *) pElement );
|
|
count++;
|
|
invalidateElement( pElement );
|
|
if( ! forward )
|
|
pNextTabFocus->pElement = pElement; // move the current focus pointer to the first segment.
|
|
} else {
|
|
break; // stop searching ;
|
|
}
|
|
} // if( pElement->lo_any.type == LO_TEXT )
|
|
|
|
if( forward)
|
|
pElement = pElement->lo_any.next;
|
|
else
|
|
pElement = pElement->lo_any.prev;
|
|
|
|
} // while( pElement &&
|
|
return count;
|
|
}
|
|
|
|
// this function is trigered by TAB key
|
|
// or called from setFormElementTabFocus() with byClickFormElement = 0, in such case
|
|
// the form element is visible and has the fucos already.
|
|
void CWinCX::setLastTabFocusElement( LO_TabFocusData *pNextTabFocus, int needSetFocus )
|
|
{
|
|
LO_Element *pElement;
|
|
|
|
// both old and new element can be NULL.
|
|
|
|
// avoid setting focus on the same element.
|
|
// For image map, the element may be the same, but the mapAreaIndex
|
|
// increase for each Tab.
|
|
|
|
if( pNextTabFocus
|
|
&& m_lastTabFocus.pElement == pNextTabFocus->pElement
|
|
&& m_lastTabFocus.mapAreaIndex == pNextTabFocus->mapAreaIndex )
|
|
return;
|
|
|
|
if( m_isReEntry_setLastTabFocusElement )
|
|
return;
|
|
m_isReEntry_setLastTabFocusElement = 1;
|
|
|
|
// need to redraw those 2 elements for visual feedback.
|
|
if(GetPane() && CanBlockDisplay() ) {
|
|
// the new element gets the focus.
|
|
pElement = pNextTabFocus->pElement;
|
|
if( NULL != pElement) {
|
|
if( needSetFocus ) {
|
|
SetActiveWindow();
|
|
// FEU_MakeElementVisible must happen before invalidate
|
|
FEU_MakeElementVisible( GetContext(), (LO_Any *) pElement );
|
|
invalidateElement( pElement );
|
|
|
|
if( pElement->lo_any.type == LO_FORM_ELE) {
|
|
// Form elements need focus to get keyboard input.
|
|
// this will loop back to setFormElementTabFocus(), That
|
|
// is why we need the re-entry protection.
|
|
FE_FocusInputElement(GetContext(), pElement );
|
|
} else {
|
|
CGenericFrame * pFrame = (CGenericFrame * )FEU_GetLastActiveFrame();
|
|
if( pFrame )
|
|
pFrame->SetFocus(); // set focus to the window.
|
|
}
|
|
}
|
|
|
|
if( pElement->lo_any.type == LO_TEXT // defined_as 1
|
|
|| pElement->lo_any.type == LO_FORM_ELE // defined_as 6
|
|
&& LO_isFormElementNeedTextTabFocus( (LO_FormElementStruct *)pElement) ) {
|
|
|
|
// first trace back for the first segmented text.
|
|
// need to do this when: tab backward, and click on not-first segment.
|
|
invalidateSegmentedTextElement(pNextTabFocus, 1); // forward
|
|
|
|
// trace down the fragmented text for a link.
|
|
invalidateSegmentedTextElement(pNextTabFocus, 0); // backward, set to first
|
|
}
|
|
} // if( NULL != pElement) , the new element
|
|
|
|
// the old element losts the focus
|
|
pElement = getLastTabFocusElement();
|
|
if( NULL != pElement) {
|
|
|
|
invalidateElement( pElement );
|
|
|
|
if( pElement->lo_any.type == LO_FORM_ELE) {
|
|
FE_BlurInputElement(GetContext(), pElement );
|
|
}
|
|
|
|
if( pElement->lo_any.type == LO_TEXT
|
|
|| pElement->lo_any.type == LO_FORM_ELE
|
|
&& LO_isFormElementNeedTextTabFocus( (LO_FormElementStruct *)pElement) ) {
|
|
// remove focus box for all continnuios text fragments.
|
|
// because it is always pointing to the first segment, no need to go backward.
|
|
invalidateSegmentedTextElement(getLastTabFocusData(), 1); // forward
|
|
}
|
|
|
|
} // if( NULL != pElement), the old element
|
|
|
|
} // if(GetPane() && CanBlockDisplay() )
|
|
|
|
m_lastTabFocus.pElement = pNextTabFocus->pElement;
|
|
m_lastTabFocus.mapAreaIndex = pNextTabFocus->mapAreaIndex; // 0 means no focus, start with index 1.
|
|
m_lastTabFocus.pAnchor = pNextTabFocus->pAnchor ;
|
|
|
|
// update the status bar.
|
|
// For all LO_ types which update status bar, see CWinCX::OnMouseMoveForLayerCX(UINT uFlags, CPoint& cpPoint,
|
|
|
|
if( getLastFocusAnchorStr() != NULL )
|
|
wfe_Progress(GetContext(), getLastFocusAnchorStr() );
|
|
else
|
|
wfe_Progress(GetContext(), "");
|
|
|
|
m_isReEntry_setLastTabFocusElement = 0;
|
|
return;
|
|
} // CWinCX::setLastTabFocusElement()
|
|
|
|
// try to set Tab Focus in this CWinCX only.
|
|
BOOL CWinCX::setNextTabFocusInWin( int forward )
|
|
{
|
|
BOOL found;
|
|
LO_TabFocusData newTabFocus;
|
|
|
|
newTabFocus.pElement = m_lastTabFocus.pElement;
|
|
newTabFocus.mapAreaIndex = m_lastTabFocus.mapAreaIndex; // 0 means no area
|
|
newTabFocus.pAnchor = m_lastTabFocus.pAnchor ;
|
|
|
|
found = LO_getNextTabableElement( GetContext(), &newTabFocus, forward );
|
|
|
|
// even new element is NULL, need to clear the old focus
|
|
setLastTabFocusElement( &newTabFocus, 1 ); // key, not click, needSetFocus
|
|
|
|
return( found );
|
|
} // BOOL CWinCX::setNextTabFocusInWin( int forward )
|
|
|
|
// this function searchs for sibling CWinCX, and set Tab focus.
|
|
// See MWContext * XP_FindNamedContextInList(MWContext * context, char *name)
|
|
// in ns\lib\xp\xp_cntxt.c for navigating grid_parent - grid_children tree.
|
|
BOOL CWinCX::setTabFocusNext( int forward )
|
|
{
|
|
BOOL ret;
|
|
|
|
// First try myself and my children.
|
|
ret = setTabFocusNextChild( NULL, forward ) ; // no exclusive child
|
|
if( ret )
|
|
return( TRUE ); // all done
|
|
|
|
// TODO loop to search up all parents
|
|
// now try to set focus to siblings
|
|
|
|
// if I am on the top, I cannot have sibling.
|
|
if( IsGridCell() != TRUE )
|
|
return( FALSE );
|
|
|
|
MWContext *pParent = GetParentContext();
|
|
if( pParent == NULL)
|
|
return( FALSE );
|
|
|
|
if( ! ABSTRACTCX(pParent)->IsWindowContext() )
|
|
return( FALSE );
|
|
|
|
ret = WINCX(pParent)->setTabFocusNextChild( GetContext(), forward ) ;
|
|
if ( ret )
|
|
return( TRUE );
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOL CWinCX::setTabFocusNextChild( MWContext *currentChildContext, int forward )
|
|
{
|
|
BOOL ret;
|
|
XP_List *gridListHead, *gridList;
|
|
MWContext *pChild;
|
|
// MWContext *pCurrent = ( MWContext *) currentChild;
|
|
|
|
// try myself first
|
|
ret = setNextTabFocusInWin( forward ) ;
|
|
if( ret ) {
|
|
return( TRUE );
|
|
}
|
|
|
|
// If not a parent, return. over kill?
|
|
if( IsGridParent() == FALSE)
|
|
return( FALSE );
|
|
|
|
// see ns\lib\xp\xp_list.c for navigating the list.
|
|
gridListHead = GetContext()->grid_children;
|
|
if( currentChildContext )
|
|
gridList = XP_ListFindObject( gridListHead, currentChildContext );
|
|
else
|
|
gridList = gridListHead; // , start from head, The head node is always empty(no data).
|
|
|
|
if( gridList != NULL ) // revers order??
|
|
gridList = forward ? gridList->prev : gridList->next ; // the list is in revers order
|
|
|
|
while( gridList != NULL ) {
|
|
pChild = (MWContext *) gridList->object ;
|
|
if( ABSTRACTCX(pChild)->IsWindowContext() ) {
|
|
TRACE0("recursive setTabFocusNextChild()\n");
|
|
ret = WINCX(pChild)->setTabFocusNextChild( NULL, forward ) ; // no exlusive child.
|
|
if( ret )
|
|
return( ret );
|
|
}
|
|
gridList = forward ? gridList->prev : gridList->next ; // the list is in revers order
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOL CWinCX::fireTabFocusElement( UINT nChar)
|
|
{
|
|
int32 mapAreaIndex, xx, yy;
|
|
lo_MapAreaRec *theArea;
|
|
|
|
LO_Element *pFocusElement = getLastTabFocusElement();
|
|
if( pFocusElement == NULL )
|
|
return( FALSE );
|
|
|
|
// SpaceBar Return are handled by Form itself for
|
|
// all Form elements, including checkbox and radio.
|
|
// Here we only take care of the links
|
|
|
|
if( pFocusElement->lo_any.type == LO_IMAGE ) {
|
|
mapAreaIndex = getLastFocusAreaIndex();
|
|
if( mapAreaIndex > 0 ) {
|
|
// the focus is in a map area
|
|
theArea = LO_getTabableMapArea( GetContext(), (LO_ImageStruct *)pFocusElement, mapAreaIndex );
|
|
if( theArea && LO_findApointInArea( theArea, &xx, &yy ) ) {
|
|
// Area coordinates are relative to the image, add the left-top of the image.
|
|
xx += pFocusElement->lo_any.x;
|
|
yy += pFocusElement->lo_any.y;
|
|
if ( FE_ClickAnyElement( GetContext(), pFocusElement, 1, xx, yy ) ) // click the center
|
|
return( TRUE );
|
|
}
|
|
return( FALSE );
|
|
}
|
|
// else mapAreaIndex not > 0, it is a link for the whole image, fall through.
|
|
}
|
|
|
|
if( pFocusElement->lo_any.type == LO_TEXT
|
|
|| pFocusElement->lo_any.type == LO_IMAGE ) {
|
|
// it is a link
|
|
if ( FE_ClickAnyElement( GetContext(), pFocusElement, 0, 0, 0 ) ) // click the center
|
|
return( TRUE );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
int CWinCX::getImageDrawFlag( MWContext *pContext, LO_ImageStruct *pImage, lo_MapAreaRec **ppArea, uint32 *pFlag )
|
|
{
|
|
LO_Element *pFocusElement;
|
|
int32 lastAreaIndex;
|
|
lo_MapAreaRec *theArea;
|
|
|
|
// clear the flag first
|
|
*pFlag &= ~FE_DRAW_TAB_FOCUS ;
|
|
|
|
|
|
if( pImage == NULL )
|
|
return( 0 );
|
|
|
|
pFocusElement = getLastTabFocusElement();
|
|
if( pFocusElement == NULL)
|
|
return( 0 );
|
|
|
|
if( pFocusElement != (LO_Element *) pImage )
|
|
return( 0 );
|
|
|
|
lastAreaIndex = getLastFocusAreaIndex();
|
|
if( lastAreaIndex < 0 ) // error
|
|
return(0);
|
|
|
|
if( lastAreaIndex == 0 ) { // no area, the whole image is focused.
|
|
LO_AnchorData *pLastAnchor = getLastFocusAnchorPointer();
|
|
if (pLastAnchor && !(pLastAnchor->flags & ANCHOR_SUPPRESS_FEEDBACK)) {
|
|
*pFlag |= FE_DRAW_TAB_FOCUS;
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
theArea = LO_getTabableMapArea( pContext, pImage, lastAreaIndex );
|
|
|
|
// Don't draw selection rectangle if it's been disabled
|
|
if(theArea && !(theArea->anchor && (theArea->anchor->flags & ANCHOR_SUPPRESS_FEEDBACK))) {
|
|
*pFlag |= FE_DRAW_TAB_FOCUS ;
|
|
*ppArea = theArea; // only the area is focused.
|
|
return( 1 );
|
|
}
|
|
|
|
return( 0 );
|
|
|
|
}
|
|
|
|
int CWinCX::setTextTabFocusDrawFlag( LO_TextStruct *pText, uint32 *pFlag )
|
|
{
|
|
// Visual feedback for Tab Focus is a dotted box around text or image.
|
|
// For 2 Form elements, check box and radio button, the box is on
|
|
// the text following the button.
|
|
//
|
|
// The text may have been fragmented into multiple lines because the line folding.
|
|
// When line width changes, fragments can be generated, or merged. It can happen
|
|
// anytime when the width of Navigator is changed. So, it cannot be handled
|
|
// when Tab key is pressed.
|
|
//
|
|
// When searching for next Tabable element, focus is moved to next different anchor.
|
|
// Continuious text fragments are skipped.
|
|
// See LO_getNextTabableElement() in lib\layout\laysel.c file.
|
|
//
|
|
// To find all focus text fragments, the Anchor data is checked. Every fragment has
|
|
// its own copy of duplicated Anchor pointer. If it is the same as the Focused element,
|
|
// the text will be drawn as focused.
|
|
//
|
|
// When an element losts Tab focus, all dotted fragments need redraw to erase the focus.
|
|
//
|
|
|
|
// assuming no focus and clear the flag first.
|
|
*pFlag &= ~FE_DRAW_TAB_FOCUS ;
|
|
|
|
if( pText == NULL )
|
|
return(0);
|
|
|
|
LO_Element *pCurrentElement, *pPreviousElement, *pFocusElement;
|
|
|
|
pFocusElement = getLastTabFocusElement();
|
|
if( pFocusElement == NULL)
|
|
return(0);
|
|
|
|
// Don't draw selection rectangle if it's been disabled
|
|
if ( pText->anchor_href
|
|
&& pText->anchor_href->flags & ANCHOR_SUPPRESS_FEEDBACK)
|
|
return(0);
|
|
|
|
pCurrentElement = (LO_Element *) pText;
|
|
|
|
// return focus if it is a link and it has Tab focus
|
|
if( pFocusElement == pCurrentElement ) {
|
|
*pFlag |= FE_DRAW_TAB_FOCUS;
|
|
return( 1 );
|
|
}
|
|
|
|
// test fragmented text for a link.
|
|
// is one fragmented element.
|
|
if( pFocusElement->lo_any.type == LO_TEXT // fix for bug #45111
|
|
&& pText->anchor_href
|
|
&& pText->anchor_href == getLastFocusAnchorPointer() ) {
|
|
*pFlag |= FE_DRAW_TAB_FOCUS ;
|
|
return( 1 );
|
|
}
|
|
|
|
// Test if it is a text element following a Form element checkBox(or radio button),
|
|
// which has focus. If it is, the text(not the button) needs to draw the focus box.
|
|
//todo in html, two separated element may have the same link. need to make sure it
|
|
pPreviousElement = pCurrentElement->lo_any.prev;
|
|
if( pPreviousElement != NULL && pPreviousElement == pFocusElement ) {
|
|
if( LO_isFormElementNeedTextTabFocus( (LO_FormElementStruct *)pPreviousElement ) ) {
|
|
*pFlag |= FE_DRAW_TAB_FOCUS ;
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
return(0);
|
|
|
|
} // isTabFocusText()
|
|
//#endif /* NO_TAB_NAVIGATION */
|
|
|
|
void CWinCX::CancelSizing()
|
|
{
|
|
#ifdef EDITOR
|
|
ASSERT(EDT_IS_EDITOR(GetContext()));
|
|
// Remove last sizing feedback
|
|
DisplaySelectionFeedback(LO_ELE_SELECTED, m_rectSizing);
|
|
EDT_CancelSizing(GetContext());
|
|
#endif // EDITOR
|
|
}
|
|
|
|
|