diff --git a/mozilla/gfx/src/os2/Makefile.in b/mozilla/gfx/src/os2/Makefile.in new file mode 100644 index 00000000000..bb7643a2cbc --- /dev/null +++ b/mozilla/gfx/src/os2/Makefile.in @@ -0,0 +1,75 @@ +# +# The contents of this file are subject to the Mozilla Public License +# Version 1.1 (the "License"); you may not use this file except in +# compliance with the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +# License for the specific language governing rights and limitations +# under the License. +# +# The Original Code is the Mozilla OS/2 libraries. +# +# The Initial Developer of the Original Code is John Fairhurst, +# . Portions created by John Fairhurst are +# Copyright (C) 1999 John Fairhurst. All Rights Reserved. +# +# Contributor(s): +# +# Makefile for gfx/src/os2 + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +OS2_IMPLIB = 1 +OS2_LIBRARYNAME = gfxos2 + +MODULE = raptor + +REQUIRES = util img xpcom raptor dom netlib java dbm js + +DEFINES += -D_IMPL_NS_GFXONXP + +OS2_LIBS = nggfx img mozjs mozutil netlib xpcom +OS_LIBS += $(NSPR_LIBS) -luconv + +CPPSRCS = \ + nsDeviceContextOS2.cpp \ + nsRenderingContextOS2.cpp \ + nsFontMetricsOS2.cpp \ + nsImageOS2.cpp \ + nsPaletteOS2.cpp \ + nsRegionOS2.cpp \ + nsDeviceContextSpecFactoryO.cpp \ + nsDeviceContextSpecOS2.cpp \ + nsDrawingSurfaceOS2.cpp \ + nsGfxFactoryOS2.cpp \ + nsTimerOS2.cpp \ + $(NULL) + +CSRCS = libprint.c + +RES_FILE = $(srcdir)/libprint.res + +include $(topsrcdir)/config/rules.mk + +INCLUDES += -I$(topsrcdir)/gfx/src + +# This adds the resources for the print dialog to the gfxos2 dll. +# I guess eventually we ought to use an xml dialog... +# XXX Have to copy files because rc is too stupid for an objdir build + +$(SHARED_LIBRARY): $(OBJS) $(RES_FILE) + +$(RES_FILE): $(srcdir)/libprint.rc + cp $(srcdir)/libprint.ico ./libprint.ico + cp $(srcdir)/libprres.h ./libprres.h + rc -r $(srcdir)/libprint.rc + diff --git a/mozilla/gfx/src/os2/libprint.c b/mozilla/gfx/src/os2/libprint.c new file mode 100644 index 00000000000..b4f76fd7998 --- /dev/null +++ b/mozilla/gfx/src/os2/libprint.c @@ -0,0 +1,445 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +/* Simple printing API. I've not done this before, so bear with me... */ + +#define INCL_PM +#define INCL_DOS +#define INCL_DOSERRORS +#define INCL_SPLDOSPRINT +#include +#include +#include + +#include "libprint.h" +#include "libprres.h" + +/* print-queue structure, opaque so I can change it. */ +struct _PRTQUEUE +{ + PRQINFO3 q; +}; + +/* local functions */ +static PRTQUEUE *prnGetDefaultPrinter( void); +static PRQINFO3 *prnGetAllQueues( PULONG pNumQueues); +static BOOL prnEscape( HDC hdc, long lEscape); +static PRTQUEUE *prnCreatePRTQUEUE( PRQINFO3 *pInfo); + +MRESULT EXPENTRY prnDlgProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2); + +/****************************************************************************/ +/* Library-level data and functions */ +/****************************************************************************/ + +static HMODULE hmodRes; + +BOOL PrnInitialize( HMODULE hmodResources) +{ + hmodRes = hmodResources; + return TRUE; +} + +BOOL PrnTerminate() +{ + /* nop for now, may do something eventually */ + return TRUE; +} + +/****************************************************************************/ +/* Printer Selection */ +/****************************************************************************/ + +/* Main work function - run a dialog to pick a printer */ +PRTQUEUE *PrnSelectPrinter( HWND hwndOwner, BOOL bQuiet) +{ + PRTQUEUE *pQueue = 0; + + if( bQuiet) + pQueue = prnGetDefaultPrinter(); + else + { + ULONG rc = WinDlgBox( HWND_DESKTOP, hwndOwner, + prnDlgProc, + hmodRes, IDD_PICKPRINTER, + &pQueue); + if( rc == DID_CANCEL) + pQueue = 0; + } + + return pQueue; +} + +BOOL PrnClosePrinter( PRTQUEUE *pPrintQueue) +{ + BOOL rc = FALSE; + + if( pPrintQueue) + { + free( pPrintQueue); + rc = TRUE; + } + + return rc; +} + +PRTQUEUE *prnGetDefaultPrinter() +{ + ULONG ulQueues = 0; + PRQINFO3 *pInfo = prnGetAllQueues( &ulQueues); + PRTQUEUE *pq = 0; + + if( ulQueues > 0) + { + /* find the default one */ + ULONG i; + for( i = 0; i < ulQueues; i++) + if( pInfo[ i].fsType & PRQ3_TYPE_APPDEFAULT) + break; + + /* must have a default printer... */ + if( i == ulQueues) + i = 0; + + pq = prnCreatePRTQUEUE( pInfo + i); + + free( pInfo); + } + + return pq; +} + +PRTQUEUE *prnCreatePRTQUEUE( PRQINFO3 *pInfo) +{ + PRTQUEUE *pq = (PRTQUEUE *) malloc( sizeof( PRTQUEUE)); + memcpy( &pq->q, pInfo, sizeof( PRQINFO3)); + return pq; +} + +PRQINFO3 *prnGetAllQueues( PULONG pNumQueues) +{ + ULONG ulReturned = 0, ulNeeded = 0, ulTotal = 0; + PBYTE pBuffer = NULL; + SPLERR rc = 0; + + /* first work out how much space we need */ + rc = SplEnumQueue( NULL, 3, pBuffer, 0, &ulReturned, + &ulTotal, &ulNeeded, NULL); + + pBuffer = (PBYTE) malloc( ulNeeded); + + /* now get the queue-infos */ + rc = SplEnumQueue( NULL, 3, pBuffer, ulNeeded, &ulReturned, + &ulTotal, &ulNeeded, NULL); + + *pNumQueues = ulReturned; + + return (PRQINFO3 *) pBuffer; +} + +BOOL PrnDoJobProperties( PRTQUEUE *pInfo) +{ + BOOL rc = FALSE; + + if( pInfo) + { + char *pszPrinter = strdup( pInfo->q.pszPrinters); + char *pszDriverName = strdup( pInfo->q.pszDriverName); + char *pszDeviceName = 0; + char *c; + long lRC; + + if( 0 != (c = strchr( pszPrinter, ','))) + *c = '\0'; + + if( 0 != (c = strchr( pszDriverName, '.'))) + { + *c = '\0'; + pszDeviceName = c + 1; + } + + lRC = DevPostDeviceModes( 0 /*hab*/, + pInfo->q.pDriverData, + pszDriverName, + pszDeviceName, + pszPrinter, + DPDM_POSTJOBPROP); + free( pszPrinter); + free( pszDriverName); + + rc = (lRC != DPDM_ERROR); + } + + return rc; +} + +/****************************************************************************/ +/* Job management */ +/****************************************************************************/ + +HDC PrnOpenDC( PRTQUEUE *pInfo, PSZ pszApplicationName) +{ + HDC hdc = 0; + + if( pInfo && pszApplicationName) + { + char *pszDriverName = strdup( pInfo->q.pszDriverName), *c; + DEVOPENSTRUC dop = { pInfo->q.pszName, + pszDriverName, + pInfo->q.pDriverData, + "PM_Q_STD", + pszApplicationName, + pInfo->q.pszPrProc, + 0, 0, 0 }; + + if( 0 != (c = strchr( pszDriverName, '.'))) + *c = '\0'; + + hdc = DevOpenDC( 0 /*hab*/, + OD_QUEUED, + "*", + 6, + (PDEVOPENDATA) &dop, + NULLHANDLE); + + free( pszDriverName); + } + + return hdc; +} + +BOOL PrnCloseDC( HDC hdc) +{ + return (hdc != 0 && DEV_OK == DevCloseDC( hdc)); +} + +BOOL PrnStartJob( HDC hdc, PSZ pszJobName) +{ + BOOL rc = FALSE; + + if( hdc && pszJobName) + { + long lDummy = 0; + long lResult = DevEscape( hdc, DEVESC_STARTDOC, + (long) strlen( pszJobName) + 1, pszJobName, + &lDummy, NULL); + rc = (lResult == DEV_OK); + } + + return rc; +} + +BOOL PrnNewPage( HDC hdc) +{ + return prnEscape( hdc, DEVESC_NEWFRAME); +} + +BOOL prnEscape( HDC hdc, long lEscape) +{ + BOOL rc = FALSE; + + if( hdc) + { + long lDummy = 0; + long lResult = DevEscape( hdc, lEscape, + 0, NULL, &lDummy, NULL); + rc = (lResult == DEV_OK); + } + + return rc; +} + +BOOL PrnAbortJob( HDC hdc) +{ + return prnEscape( hdc, DEVESC_ABORTDOC); +} + +BOOL PrnEndJob( HDC hdc) +{ + BOOL rc = FALSE; + + if( hdc) + { + long lOutCount = 2; + USHORT usJobID = 0; + long lResult = DevEscape( hdc, DEVESC_ENDDOC, + 0, NULL, &lOutCount, (PBYTE) &usJobID); + rc = (lResult == DEV_OK); + } + + return rc; +} + +/* find the selected form */ +BOOL PrnQueryHardcopyCaps( HDC hdc, PHCINFO pHCInfo) +{ + BOOL rc = FALSE; + + if( hdc && pHCInfo) + { + PHCINFO pBuffer; + long lAvail, i; + + /* query how many forms are available */ + lAvail = DevQueryHardcopyCaps( hdc, 0, 0, NULL); + + pBuffer = (PHCINFO) malloc( lAvail * sizeof(HCINFO)); + + DevQueryHardcopyCaps( hdc, 0, lAvail, pBuffer); + + for( i = 0; i < lAvail; i++) + if( pBuffer[ i].flAttributes & HCAPS_CURRENT) + { + memcpy( pHCInfo, pBuffer + i, sizeof(HCINFO)); + rc = TRUE; + break; + } + + free( pBuffer); + } + + return rc; +} + +/****************************************************************************/ +/* Print dialog stuff */ +/****************************************************************************/ + +typedef struct _PRNDLG +{ + HWND hwndLbox; + PRQINFO3 *pQueues; + ULONG ulQueues; + HPOINTER hPointer; + PRTQUEUE **ppQueue; +} PRNDLG, *PPRNDLG; + +#define PRM_QUERYQUEUE (WM_USER) /* returns PRQINFO3* */ +#define PRM_JOBPROPERTIES (WM_USER + 1) + +MRESULT EXPENTRY prnDlgProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + PPRNDLG pData = (PPRNDLG) WinQueryWindowPtr( hwnd, 0); + + switch( msg) + { + case WM_INITDLG: + /* set up our data structure */ + pData = (PPRNDLG) malloc( sizeof( PRNDLG)); + pData->pQueues = prnGetAllQueues( &pData->ulQueues); + pData->hwndLbox = WinWindowFromID( hwnd, IDLB_QUEUES); + pData->hPointer = WinLoadPointer( HWND_DESKTOP, hmodRes, IDICO_PRINTER); + pData->ppQueue = (PRTQUEUE**) mp2; + WinSetWindowPtr( hwnd, 0, pData); + + /* set up the dialog */ + WinSetPresParam( hwnd, PP_FONTNAMESIZE, 7, "8.Helv"); + WinEnableWindow( WinWindowFromID( hwnd, IDB_HELP), FALSE); + WinSendMsg( hwnd, WM_SETICON, MPFROMLONG(pData->hPointer), 0); + + /* populate listbox */ + if( pData->ulQueues == 0) + { + WinEnableWindow( WinWindowFromID( hwnd, DID_OK), FALSE); + WinSendMsg( pData->hwndLbox, LM_INSERTITEM, MPFROMSHORT(0), + MPFROMP("(no printers available)")); + WinEnableWindow( pData->hwndLbox, FALSE); + WinEnableWindow( WinWindowFromID( hwnd, IDB_JOBPROPERTIES), FALSE); + } + else + { + ULONG i; + + for( i = 0; i < pData->ulQueues; i++) + { + WinSendMsg( pData->hwndLbox, LM_INSERTITEM, MPFROMSHORT(i), + MPFROMP( pData->pQueues[i].pszComment)); + WinSendMsg( pData->hwndLbox, LM_SETITEMHANDLE, MPFROMSHORT(i), + MPFROMP( pData->pQueues + i)); + if( pData->pQueues[i].fsType & PRQ3_TYPE_APPDEFAULT) + WinSendMsg( pData->hwndLbox, LM_SELECTITEM, + MPFROMSHORT(i), MPFROMSHORT(TRUE)); + } + } + // Center over owner + { + RECTL rclMe, rclOwner; + LONG lX, lY; + BOOL rc; + WinQueryWindowRect( WinQueryWindow( hwnd, QW_PARENT), &rclOwner); + WinQueryWindowRect( hwnd, &rclMe); + lX = (rclOwner.xRight - rclMe.xRight) / 2; + lY = (rclOwner.yTop - rclMe.yTop) / 2; + rc = WinSetWindowPos( hwnd, 0, lX, lY, 0, 0, SWP_MOVE); + } + break; + + case PRM_QUERYQUEUE: + { + /* find which lbox item is selected & return its handle */ + MRESULT sel; + sel = WinSendMsg( pData->hwndLbox, LM_QUERYSELECTION, 0, 0); + return WinSendMsg( pData->hwndLbox, LM_QUERYITEMHANDLE, sel, 0); + } + + case PRM_JOBPROPERTIES: + { + /* do job properties dialog for selected printer */ + PPRQINFO3 pInfo; + pInfo = (PPRQINFO3) WinSendMsg( hwnd, PRM_QUERYQUEUE, 0, 0); + PrnDoJobProperties( (PRTQUEUE*) pInfo); /* !! */ + return 0; + } + + case WM_CONTROL: + if( SHORT2FROMMP(mp1) == LN_ENTER) + return WinSendMsg( hwnd, PRM_JOBPROPERTIES, 0, 0); + break; + + case WM_COMMAND: + switch( SHORT1FROMMP(mp1)) + { + case IDB_JOBPROPERTIES: + WinSendMsg( hwnd, PRM_JOBPROPERTIES, 0, 0); + return 0; + + case DID_OK: + { + /* set return value */ + PPRQINFO3 pInfo; + pInfo = (PPRQINFO3) WinSendMsg( hwnd, PRM_QUERYQUEUE, 0, 0); + *(pData->ppQueue) = prnCreatePRTQUEUE( pInfo); + break; /* dismiss dialog normally */ + } + } + break; + + case WM_DESTROY: + { + if( pData->pQueues) + free( pData->pQueues); + free( pData); + break; + } + } + + return WinDefDlgProc( hwnd, msg, mp1, mp2); +} diff --git a/mozilla/gfx/src/os2/libprint.h b/mozilla/gfx/src/os2/libprint.h new file mode 100644 index 00000000000..61d91437d10 --- /dev/null +++ b/mozilla/gfx/src/os2/libprint.h @@ -0,0 +1,98 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +/* (Over?) Simple printing API */ + +/****************************************************************************/ +/* Example usage: */ +/* */ +/* PRTQUEUE *pq = PrnSelectPrinter(...) */ +/* HDC dcPrint = PrnOpenDC( pq, ...) */ +/* */ +/* GpiAssociate( hps, dcPrint) */ +/* */ +/* PrnStartJob( dcPrint, ...) */ +/* . */ +/* . */ +/* Gpi calls to `hps' */ +/* . */ +/* . */ +/* PrnEndJob( dcPrint) */ +/* */ +/* GpiAssociate( hps, NULLHANDLE) */ +/* */ +/* PrnCloseDC( dcPrint) */ +/* PrnClosePrinter( pq) */ +/****************************************************************************/ + +#ifndef _libprint_h +#define _libprint_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* Library init and term; job properties per queue are cached during run. */ +BOOL PrnInitialize( HMODULE hmodResources); +BOOL PrnTerminate( void); + +/* opaque type to describe a print queue (printer) */ +typedef struct _PRTQUEUE PRTQUEUE; + +/* Select a printer. If bQuiet is set, the default one is used; otherwise, */ +/* a dialog is popped up to allow the user to choose. Job properties */ +/* configuration can be done at this stage, from the dialog. */ +/* Returns null if use cancels. */ +PRTQUEUE *PrnSelectPrinter( HWND hwndOwner, BOOL bQuiet); + +/* Release app. resources associated with a printer */ +BOOL PrnClosePrinter( PRTQUEUE *pPrintQueue); + +/* Display job-properties dialog. Returns success. */ +BOOL PrnDoJobProperties( PRTQUEUE *pPrintQueue); + +/* Get a DC for the selected printer. Must supply the application name. */ +HDC PrnOpenDC( PRTQUEUE *pPrintQueue, PSZ pszApplicationName); + +/* Close the print DC; your PS should have been disassociated. */ +BOOL PrnCloseDC( HDC hdc); + +/* Get the hardcopy caps for the selected form */ +BOOL PrnQueryHardcopyCaps( HDC hdc, PHCINFO pHCInfo); + +/* Begin a print job. A PS should have been associated with the dc */ +/* (returned from PrnOpenDC()), a job name is required. */ +BOOL PrnStartJob( HDC hdc, PSZ pszJobName); + +/* End a print job previously started with PrnStartJob(). */ +BOOL PrnEndJob( HDC hdc); + +/* Abort the current job started with PrnStartJob(). */ +BOOL PrnAbortJob( HDC hdc); + +/* Make a page-break. */ +BOOL PrnNewPage( HDC hdc); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mozilla/gfx/src/os2/libprint.ico b/mozilla/gfx/src/os2/libprint.ico new file mode 100644 index 00000000000..98ce1984dfa Binary files /dev/null and b/mozilla/gfx/src/os2/libprint.ico differ diff --git a/mozilla/gfx/src/os2/libprint.rc b/mozilla/gfx/src/os2/libprint.rc new file mode 100644 index 00000000000..ffb4226e6d3 --- /dev/null +++ b/mozilla/gfx/src/os2/libprint.rc @@ -0,0 +1,45 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include +#include "libprres.h" + +#ifndef FCF_CLOSEBUTTON +/* no merlin toolkit */ +#define FCF_CLOSEBUTTON 0x04000000L +#endif + +DLGTEMPLATE ID_PRINTER_BASE LOADONCALL MOVEABLE DISCARDABLE +BEGIN + DIALOG "Print", ID_PRINTER_BASE, 12, 27, 170, 82, WS_VISIBLE, + FCF_SYSMENU | FCF_TITLEBAR | FCF_CLOSEBUTTON + BEGIN + DEFPUSHBUTTON "~OK", DID_OK, 2, 2, 36, 12 + PUSHBUTTON "~Cancel", DID_CANCEL, 42, 2, 36, 12 + PUSHBUTTON "~Help", 101, 82, 2, 36, 12, BS_HELP | + BS_NOPOINTERFOCUS + GROUPBOX "Print Queue", 0, 2, 16, 163, 65 + LISTBOX 102, 6, 31, 155, 42, LS_NOADJUSTPOS + PUSHBUTTON "~Job properties", 103, 97, 18, 64, 12 + END +END + +ICON IDICO_PRINTER "libprint.ico" diff --git a/mozilla/gfx/src/os2/libprres.h b/mozilla/gfx/src/os2/libprres.h new file mode 100644 index 00000000000..943e7eeb0ba --- /dev/null +++ b/mozilla/gfx/src/os2/libprres.h @@ -0,0 +1,35 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +/* resource definitions for printer dialog */ + +#ifndef _printres_h +#define _printres_h + +#define ID_PRINTER_BASE 100 /* you can change this as needed */ + +#define IDD_PICKPRINTER (ID_PRINTER_BASE) +#define IDB_HELP (ID_PRINTER_BASE + 1) +#define IDLB_QUEUES (ID_PRINTER_BASE + 2) +#define IDB_JOBPROPERTIES (ID_PRINTER_BASE + 3) +#define IDICO_PRINTER (ID_PRINTER_BASE + 4) + +#endif diff --git a/mozilla/gfx/src/os2/nsDeviceContextOS2.cpp b/mozilla/gfx/src/os2/nsDeviceContextOS2.cpp new file mode 100644 index 00000000000..53075f80dd4 --- /dev/null +++ b/mozilla/gfx/src/os2/nsDeviceContextOS2.cpp @@ -0,0 +1,648 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// ToDo: +#include "nsGfxDefs.h" +#include "libprint.h" + +#include "nsDeviceContextSpecOS2.h" +#include "nsDeviceContextOS2.h" +#include "nsDrawingSurfaceOS2.h" +#include "nsPaletteOS2.h" +#include "nsHashtable.h" +#include "nsString.h" +#include "nsFont.h" +#include "il_util.h" + +// nsDeviceContextOS2 - The graphics state associated with a window. +// Keep the colour palette for all rendering contexts here; they share +// it and the widget can do palette-y things. +// +// Remember that this thing can be fairly long-lived, linked to a window. +// +// It's a bit schizophrenic - really there should be a nsIPrintDC <: nsIDC ... + +// Init/Term ----------------------------------------------------------------- + +nsDeviceContextOS2::nsDeviceContextOS2() : DeviceContextImpl() +{ + // Default for now + mSurface = nsnull; + mDepth = 0; + mPaletteInfo.isPaletteDevice = PR_FALSE; + mPaletteInfo.sizePalette = 0; + mPaletteInfo.numReserved = 0; + mPaletteInfo.palette = nsnull; + mPalette = nsnull; + mPixelsToTwips = 0; + mTwipsToPixels = 0; + mPixelScale = 1.0f; + mWidth = 0; + mHeight = 0; + mDC = 0; + mPrintState = nsPrintState_ePreBeginDoc; + + // Init module if necessary (XXX find a better way of doing this!) + if( !gModuleData.lDisplayDepth) + gModuleData.Init(); +} + +nsDeviceContextOS2::~nsDeviceContextOS2() +{ + NS_IF_RELEASE( mSurface); + NS_IF_RELEASE( mPalette); + + if( mDC) + { + GpiAssociate( mPS, 0); + GpiDestroyPS( mPS); + PrnCloseDC( mDC); + } +} + +nsresult nsDeviceContextOS2::Init( nsNativeWidget aWidget) +{ + HWND hwnd = aWidget ? (HWND)aWidget : HWND_DESKTOP; + HDC hdc = WinOpenWindowDC( hwnd); + + CommonInit( hdc); + + // Get size - don't know if this is needed for non-print DCs + long lCaps[2]; + DevQueryCaps( hdc, CAPS_WIDTH, 2, lCaps); + mWidth = lCaps[0]; // these are in device units... + mHeight = lCaps[1]; + + // Don't need to close HDCs obtained from WinOpenWindowDC + + return DeviceContextImpl::Init( aWidget); +} + +// This version of Init() is called when creating a print DC +nsresult nsDeviceContextOS2::Init( nsNativeDeviceContext aContext, + nsIDeviceContext *aOrigContext) +{ + // These calcs are from the windows version & I'm not 100% + // sure what's going on... + + float origscale, newscale; + float t2d, a2d; + + mDC = (HDC)aContext; // we are print dc... + + // Create a print PS now. This is necessary 'cos we need it from + // odd places to do font-y things, where the only common reference + // point is this DC. We can't just create a new PS because only one + // PS can be associated with a given DC, and we can't get that PS from + // the DC (really?). And it would be slow :-) + SIZEL sizel = { 0 , 0 }; + mPS = GpiCreatePS( 0/*hab*/, mDC, &sizel, + PU_PELS | GPIT_MICRO | GPIA_ASSOC); + + CommonInit( mDC); + // yech: we can't call nsDeviceContextImpl::Init() 'cos no widget. + DeviceContextImpl::CommonInit(); + + GetTwipsToDevUnits( newscale); + aOrigContext->GetTwipsToDevUnits( origscale); + + mPixelScale = newscale / origscale; + + aOrigContext->GetTwipsToDevUnits( t2d); + aOrigContext->GetAppUnitsToDevUnits( a2d); + + mAppUnitsToDevUnits = (a2d / t2d) * mTwipsToPixels; + mDevUnitsToAppUnits = 1.0f / mAppUnitsToDevUnits; + + HCINFO hcinfo; + PrnQueryHardcopyCaps( mDC, &hcinfo); + mWidth = hcinfo.xPels; + mHeight = hcinfo.yPels; + // XXX hsb says there are margin problems, must be from here... + printf( "Got surface of size %d x %d pixels\n", mWidth, mHeight); + printf( "mPixelScale = %f\n", mPixelScale); + + // We need to begin a document now, because the client is entitled at + // this point to do stuff like create fonts, which required the PS to + // be associated with a DC which has been DEVESC_STARTDOC'd. + BeginDocument(); + + return NS_OK; +} + +void nsDeviceContextOS2::CommonInit( HDC aDC) +{ + // Record palette-potential of device even if it is >8bpp + long lCap = 0; + DevQueryCaps( aDC, CAPS_ADDITIONAL_GRAPHICS, 1, &lCap); + mPaletteInfo.isPaletteDevice = !!(lCap & CAPS_PALETTE_MANAGER); + + // Work out the pels-to-twips conversion + DevQueryCaps( aDC, CAPS_VERTICAL_FONT_RES, 1, &lCap); + mTwipsToPixels = ((float) lCap) / (float)NSIntPointsToTwips(72); + mPixelsToTwips = 1.0f / mTwipsToPixels; + + // max palette size: level out at COLOR_CUBE_SIZE + // (or CAPS_COLORS ?) + DevQueryCaps( aDC, CAPS_PHYS_COLORS, 1, &lCap); + mPaletteInfo.sizePalette = (PRUint8) (min( lCap, COLOR_CUBE_SIZE)); + + // erm? + mPaletteInfo.numReserved = 0; + + DevQueryCaps( aDC, CAPS_COLOR_BITCOUNT, 1, &lCap); + mDepth = lCap; +} + +// Creation of other gfx objects malarky ------------------------------------- + +nsresult nsDeviceContextOS2::GetDrawingSurface( nsIRenderingContext &aContext, nsDrawingSurface &aSurface) +{ + if( !mSurface) + { + nsDrawingSurface tSurface; + aContext.CreateDrawingSurface( nsnull, 0, tSurface); + mSurface = (nsDrawingSurfaceOS2 *) tSurface; + NS_ADDREF(mSurface); + } + + printf("Dodgy nsDeviceContext::GetDrawingContext() called\n"); + + aSurface = mSurface; + return NS_OK; +} + +nsresult nsDeviceContextOS2::GetDeviceContextFor( nsIDeviceContextSpec *aDevice, + nsIDeviceContext *&aContext) +{ + // Prolly want to clean this up xpCom-wise... + nsDeviceContextOS2 *newCX = new nsDeviceContextOS2; + nsDeviceContextSpecOS2 *spec = (nsDeviceContextSpecOS2*) aDevice; + + aContext = newCX; + NS_ADDREF(aContext); + + PRTQUEUE *pq; + spec->GetPRTQUEUE( pq); + + HDC hdcPrint = PrnOpenDC( pq, "Mozilla"); + + return newCX->Init( (nsNativeDeviceContext) hdcPrint, this); +} + +// Create a rendering context against our hdc for a printer +nsresult nsDeviceContextOS2::CreateRenderingContext( nsIRenderingContext *&aContext) +{ + NS_ASSERTION( mDC, "CreateRenderingContext for non-print DC"); + + nsIRenderingContext *pContext = new nsRenderingContextOS2; + NS_ADDREF(pContext); + + nsPrintSurface *surf = new nsPrintSurface; + NS_ADDREF(surf); + + surf->Init( mPS, mWidth, mHeight); + + nsresult rc = pContext->Init( this, (void*)((nsDrawingSurfaceOS2 *) surf)); + + if( NS_OK != rc) + { + NS_IF_RELEASE(surf); + NS_IF_RELEASE(pContext); + } + + aContext = pContext; + + return rc; +} + +HPS nsDeviceContextOS2::GetRepresentativePS() const +{ + HPS hps; + + if( mDC == 0) + { + HWND hwnd = mWidget ? (HWND)mWidget : HWND_DESKTOP; + hps = WinGetPS( hwnd); + } + else + hps = mPS; + + return hps; +} + +void nsDeviceContextOS2::ReleaseRepresentativePS( HPS aPS) +{ + if( mDC == 0) + if( !WinReleasePS( aPS)) + PMERROR( "WinReleasePS (DC)"); + else + /* nop */ ; +} + +// Metrics ------------------------------------------------------------------- + +// Note that this returns values in app units, as opposed to GetSystemAttr(), +// which uses device units. +nsresult nsDeviceContextOS2::GetScrollBarDimensions( float &aWidth, float &aHeight) const +{ + aWidth = (float) WinQuerySysValue( HWND_DESKTOP, SV_CXVSCROLL) * + mDevUnitsToAppUnits; + aHeight = (float) WinQuerySysValue( HWND_DESKTOP, SV_CYHSCROLL) * + mDevUnitsToAppUnits; + return NS_OK; +} + +// Utility function to query a logical font, from the ini file if possible +// but with os-dependent defaults. If there's no appropriate inikey, just +// supply a null for that parameter. +static void FindSystemFont( nsFont *aFont, const char *aIniKey, + const char *aWarp3Default, + const char *aWarp4Default) +{ + static int bIsWarp4 = -1; // XXX MT + char fontNameSize[100]; + + NS_ASSERTION( aWarp3Default && aWarp4Default, "Bad params to FindSystemFont"); + if( !aWarp3Default || !aWarp4Default) return; + + if( bIsWarp4 == -1) + { + ULONG ulValues[2]; + DosQuerySysInfo( QSV_VERSION_MAJOR, QSV_VERSION_MINOR, + ulValues, sizeof ulValues); + bIsWarp4 = (ulValues[0] >= 20) && (ulValues[1] >= 40); + } + + if( aIniKey) + PrfQueryProfileString( HINI_USERPROFILE, "PM_SystemFonts", aIniKey, + bIsWarp4 ? aWarp4Default : aWarp3Default, + fontNameSize, 100); + else + strcpy( fontNameSize, bIsWarp4 ? aWarp4Default : aWarp3Default); + + // Parse font description into face and pointage + int iPoints = 0; + char facename[ 100]; + if( 2 == sscanf( fontNameSize, "%d.%s", &iPoints, facename)) + { + // XXX This isn't quite `right', but I can't be bothered to go + // XXX through the rigamarole of working out precisely what's going + // XXX on. Just ensure that the right thing happens when this font + // XXX gets passed to nsFontMetricsOS2 or nsWindow. + aFont->name = facename; + aFont->style = NS_FONT_STYLE_NORMAL; + aFont->variant = NS_FONT_VARIANT_NORMAL; + aFont->weight = NS_FONT_WEIGHT_NORMAL; + aFont->decorations = NS_FONT_DECORATION_NONE; + + // XXX Windows sets the size in points... +#if 1 + aFont->size = iPoints; +#else + // XXX ..but it should probably be in app units + float twip2dev, twip2app; + nscoord nsTwips = NSIntPointsToTwips( iPoints); + GetDevUnitsToAppUnits( twip2app); + GetTwipsToDevUnits( twip2dev); + twip2app *= twip2dev; + + aFont->size = NSToCoordFloor( nsTwips * twip2app); +#endif + } + else + NS_ASSERTION( 0, "Malformed fontnamesize string"); +} + +nsresult nsDeviceContextOS2::GetSystemAttribute( nsSystemAttrID anID, + SystemAttrStruct *aInfo) const +{ + int sysclr = 0, sysval = 0; + + switch( anID) + { + // Colors + // !! Any of these could be wrong... + case eSystemAttr_Color_WindowBackground: + sysclr = SYSCLR_BACKGROUND; + break; + case eSystemAttr_Color_WindowForeground: + sysclr = SYSCLR_WINDOWTEXT; + break; + case eSystemAttr_Color_WidgetBackground: + sysclr = SYSCLR_BUTTONMIDDLE; + break; + case eSystemAttr_Color_WidgetForeground: + sysclr = SYSCLR_WINDOWTEXT; + break; + case eSystemAttr_Color_WidgetSelectBackground: + sysclr = SYSCLR_HILITEBACKGROUND; + break; + case eSystemAttr_Color_WidgetSelectForeground: + sysclr = SYSCLR_HILITEFOREGROUND; + break; + case eSystemAttr_Color_Widget3DHighlight: + sysclr = SYSCLR_BUTTONLIGHT; + break; + case eSystemAttr_Color_Widget3DShadow: + sysclr = SYSCLR_BUTTONDARK; + break; + case eSystemAttr_Color_TextBackground: + sysclr = SYSCLR_ENTRYFIELD; + break; + case eSystemAttr_Color_TextForeground: + sysclr = SYSCLR_WINDOWTEXT; + break; + case eSystemAttr_Color_TextSelectBackground: + sysclr = SYSCLR_HILITEBACKGROUND; + break; + case eSystemAttr_Color_TextSelectForeground: + sysclr = SYSCLR_HILITEFOREGROUND; + break; + // Size (these seem to be required in device units) + // !! These could well be wrong & need to be arbitrarily changed... + case eSystemAttr_Size_WindowTitleHeight: + sysval = SV_CYTITLEBAR; + break; + case eSystemAttr_Size_WindowBorderWidth: + sysval = SV_CXSIZEBORDER; + break; + case eSystemAttr_Size_WindowBorderHeight: + sysval = SV_CYSIZEBORDER; + break; + case eSystemAttr_Size_Widget3DBorder: + sysval = SV_CXBORDER; + break; + case eSystemAttr_Size_ScrollbarHeight: + sysval = SV_CYHSCROLL; + break; + case eSystemAttr_Size_ScrollbarWidth: + sysval = SV_CXVSCROLL; + break; + // Fonts + // + // !! Again, these are up for grabs & spec-less. + // !! If it looks crazy, change it here. + // + case eSystemAttr_Font_Caption: + case eSystemAttr_Font_SmallCaption: + FindSystemFont( aInfo->mFont, "WindowTitles", + "10.Helv", "9.WarpSans Bold"); + break; + case eSystemAttr_Font_Icon: + FindSystemFont( aInfo->mFont, "IconText", + "8.Helv", "9.WarpSans"); + break; + case eSystemAttr_Font_Menu: + FindSystemFont( aInfo->mFont, "Menus", + "10.Helv", "9.WarpSans Bold"); + break; + case eSystemAttr_Font_MessageBox: + case eSystemAttr_Font_StatusBar: + case eSystemAttr_Font_Tooltips: + case eSystemAttr_Font_Widget: + FindSystemFont( aInfo->mFont, "WindowText", + "8.Helv", "9.Warpsans"); + break; + // don't want to be here + default: + NS_ASSERTION(0,"Bad eSystemAttr value"); + break; + } + + // Load colour if appropriate + if( sysclr != 0) + { + long lColor = WinQuerySysColor( HWND_DESKTOP, sysclr, 0); + + RGB2 *pRGB2 = (RGB2*) &lColor; + + *(aInfo->mColor) = NS_RGB( pRGB2->bRed, pRGB2->bGreen, pRGB2->bBlue); + } + else if( sysval != 0) + { + aInfo->mSize = WinQuerySysValue( HWND_DESKTOP, sysval); + } + + return NS_OK; +} + +// +// (XXX) the screen object thinks these are in pels, duh. +// +nsresult nsDeviceContextOS2::GetDeviceSurfaceDimensions( PRInt32 &aWidth, PRInt32 &aHeight) +{ + aWidth = NSToIntRound( mWidth * mDevUnitsToAppUnits); + aHeight = NSToIntRound( mHeight * mDevUnitsToAppUnits); + + return NS_OK; +} + +nsresult nsDeviceContextOS2::GetDepth( PRUint32& aDepth) +{ + aDepth = mDepth; + return NS_OK; +} + +// Yuck... +nsresult nsDeviceContextOS2::SupportsNativeWidgets( PRBool &aSupportsWidgets) +{ + aSupportsWidgets = (mDC == 0) ? PR_TRUE : PR_FALSE; + return NS_OK; +} + +nsresult nsDeviceContextOS2::GetCanonicalPixelScale( float &aScale) const +{ + aScale = mPixelScale; + return NS_OK; +} + +// Fonts --------------------------------------------------------------------- + +// Rather unfortunate place for this method... +nsresult nsDeviceContextOS2::CheckFontExistence( const nsString &aFontName) +{ + HPS hps = GetRepresentativePS(); + + char fontName[ FACESIZE]; + aFontName.ToCString( fontName, FACESIZE); + + long lWant = 0; + long lFonts = GpiQueryFonts( hps, QF_PUBLIC | QF_PRIVATE, + fontName, &lWant, 0, 0); + + ReleaseRepresentativePS( hps); + + return lFonts > 0 ? NS_OK : NS_ERROR_FAILURE; +} + +// Font setup - defaults aren't terribly helpful; this may be no better! +nsresult nsDeviceContextOS2::CreateFontAliasTable() +{ + nsresult result = NS_OK; + + if( !mFontAliasTable) + { + mFontAliasTable = new nsHashtable; + + AliasFont( "Times", "Tms Rmn", "Times New Roman", PR_FALSE); + AliasFont( "Times Roman", "Tms Rmn", "Times New Roman", PR_FALSE); + AliasFont( "Arial", "Helv", "Helvetica", PR_FALSE); + AliasFont( "Helvetica", "Helv", "Arial", PR_FALSE); + AliasFont( "Courier", "Courier New", "", PR_FALSE); // why does base force this alias? + AliasFont( "Courier New", "Courier", "", PR_FALSE); + AliasFont( "Sans", "Helv", "Arial", PR_FALSE); + // Is this right? + AliasFont( "Unicode", "Times New Roman MT 30", "", PR_FALSE); + } + return result; +} + +// Colourspaces and palettes ------------------------------------------------- + +// Override these so we can use palette manager +nsresult nsDeviceContextOS2::GetILColorSpace( IL_ColorSpace *&aColorSpace) +{ + if( !mColorSpace) + { + // !! Might want to do something funky for 4bpp displays + + // See if we're dealing with an 8-bit palette device + if( (8 == mDepth) && mPaletteInfo.isPaletteDevice) + { + IL_ColorMap *cMap = IL_NewCubeColorMap( 0, 0, COLOR_CUBE_SIZE); + if( !cMap) + return NS_ERROR_OUT_OF_MEMORY; + + // Create a pseudo color space + mColorSpace = IL_CreatePseudoColorSpace( cMap, 8, 8); + } + else + { + IL_RGBBits colorRGBBits; + + // Create a 24-bit color space + colorRGBBits.red_shift = 16; + colorRGBBits.red_bits = 8; + colorRGBBits.green_shift = 8; + colorRGBBits.green_bits = 8; + colorRGBBits.blue_shift = 0; + colorRGBBits.blue_bits = 8; + + mColorSpace = IL_CreateTrueColorSpace(&colorRGBBits, 24); + } + + if( !mColorSpace) + { + aColorSpace = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + } + + // Return the color space + aColorSpace = mColorSpace; + IL_AddRefToColorSpace( aColorSpace); + return NS_OK; +} + +nsresult nsDeviceContextOS2::GetPaletteInfo( nsPaletteInfo& aPaletteInfo) +{ + aPaletteInfo.isPaletteDevice = mPaletteInfo.isPaletteDevice; + aPaletteInfo.sizePalette = mPaletteInfo.sizePalette; + aPaletteInfo.numReserved = mPaletteInfo.numReserved; + + nsresult rc = NS_OK; + + SetupColorMaps(); + + aPaletteInfo.palette = mPaletteInfo.palette; + return rc; +} + +nsresult nsDeviceContextOS2::GetPalette( nsIPaletteOS2 *&aPalette) +{ + nsresult rc = SetupColorMaps(); + aPalette = mPalette; + NS_ADDREF( aPalette); + return rc; +} + +nsresult nsDeviceContextOS2::SetupColorMaps() +{ + nsresult rc = NS_OK; + if( !mPalette) + { + // Share a single palette between all screen instances; printers need + // a separate palette for compatability reasons. + if( mDC) rc = NS_CreatePalette( this, mPalette); + else mPalette = gModuleData.GetUIPalette( this); + + if( rc == NS_OK) + rc = mPalette->GetNSPalette( mPaletteInfo.palette); + } + return rc; +} + +NS_IMETHODIMP nsDeviceContextOS2::ConvertPixel(nscolor aColor, PRUint32 & aPixel) +{ + printf( "Alert: nsDeviceContext::ConvertPixel called\n"); + aPixel = aColor; + return NS_OK; +} + +// Printing ------------------------------------------------------------------ +nsresult nsDeviceContextOS2::BeginDocument() +{ + NS_ASSERTION(mDC, "BeginDocument for non-print DC"); + if( mPrintState == nsPrintState_ePreBeginDoc) + { + PrnStartJob( mDC, "Warpzilla NGLayout job"); + printf( "BeginDoc\n"); + mPrintState = nsPrintState_eBegunDoc; + } + return NS_OK; +} + +nsresult nsDeviceContextOS2::EndDocument() +{ + PrnEndJob( mDC); + mPrintState = nsPrintState_ePreBeginDoc; + printf("EndDoc\n"); + return NS_OK; +} + +nsresult nsDeviceContextOS2::BeginPage() +{ + if( mPrintState == nsPrintState_eBegunDoc) + mPrintState = nsPrintState_eBegunFirstPage; + else + { + PrnNewPage( mDC); + printf("NewPage"); + } + return NS_OK; +} + +nsresult nsDeviceContextOS2::EndPage() +{ + /* nop */ + return NS_OK; +} diff --git a/mozilla/gfx/src/os2/nsDeviceContextOS2.h b/mozilla/gfx/src/os2/nsDeviceContextOS2.h new file mode 100644 index 00000000000..d07d1839662 --- /dev/null +++ b/mozilla/gfx/src/os2/nsDeviceContextOS2.h @@ -0,0 +1,109 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsDeviceContextOS2_h +#define _nsDeviceContextOS2_h + +#include "nsDeviceContext.h" +#include "nsRenderingContextOS2.h" + +// Device contexts are either for windows or for printers. +// If the former, the DeviceContextImpl member mWidget is set. +// If the latter, the mDC member here is set. +// (yes, I know: eventually want to split these guys up) + +class nsIPaletteOS2; +class nsDrawingSurfaceOS2; + +class nsDeviceContextOS2 : public DeviceContextImpl +{ + public: + nsDeviceContextOS2(); + + NS_IMETHOD Init( nsNativeWidget aWidget); + + // what a bizarre method. These floats are app units. + NS_IMETHOD GetScrollBarDimensions( float &aWidth, float &aHeight) const; + + NS_IMETHOD GetSystemAttribute( nsSystemAttrID anID, SystemAttrStruct *aInfo) const; + + // get a low level drawing surface for rendering. the rendering context + // that is passed in is used to create the drawing surface if there isn't + // already one in the device context. the drawing surface is then cached + // in the device context for re-use. + NS_IMETHOD GetDrawingSurface( nsIRenderingContext &aContext, + nsDrawingSurface &aSurface); + NS_IMETHOD CheckFontExistence( const nsString &aFontName); + NS_IMETHOD GetDepth( PRUint32 &aDepth); + NS_IMETHOD GetILColorSpace( IL_ColorSpace*& aColorSpace); + NS_IMETHOD GetPaletteInfo( nsPaletteInfo &); + NS_IMETHOD ConvertPixel( nscolor aColor, PRUint32 & aPixel); + NS_IMETHOD GetDeviceSurfaceDimensions( PRInt32 &aWidth, PRInt32 &aHeight); + NS_IMETHOD SupportsNativeWidgets( PRBool &aSupportsWidgets); + NS_IMETHOD GetCanonicalPixelScale( float &aScale) const; + NS_IMETHOD GetDeviceContextFor( nsIDeviceContextSpec *aDevice, + nsIDeviceContext *&aContext); + NS_IMETHOD CreateRenderingContext( nsIRenderingContext *&aContext); + NS_IMETHOD BeginDocument(); + NS_IMETHOD EndDocument(); + NS_IMETHOD BeginPage(); + NS_IMETHOD EndPage(); + + // OS2 specific methods + public: + // Call to ensure colour table/palette is loaded and ready. + nsresult SetupColorMaps(); + // Get the palette object for the device, used to pick colours. + // Release when done. + nsresult GetPalette( nsIPaletteOS2 *&apalette); + // Init from a HDC for printing purposes + nsresult Init( nsNativeDeviceContext aContext, + nsIDeviceContext *aOrigContext); + void CommonInit( HDC aDC); + + // Needed by the fontmetrics - can't rely on having a widget. + HPS GetRepresentativePS() const; + void ReleaseRepresentativePS( HPS aPS); + + protected: + virtual ~nsDeviceContextOS2(); + + virtual nsresult CreateFontAliasTable(); + + nsDrawingSurfaceOS2 *mSurface; + PRUint32 mDepth; // bit depth of device + nsPaletteInfo mPaletteInfo; + nsIPaletteOS2 *mPalette; + float mPixelScale; + PRInt32 mWidth; + PRInt32 mHeight; + HDC mDC; // PrintDC. Owned by libprint. + HPS mPS; // PrintPS. + enum nsPrintState + { + nsPrintState_ePreBeginDoc, + nsPrintState_eBegunDoc, + nsPrintState_eBegunFirstPage, + nsPrintState_eEndedDoc + } mPrintState; +}; + +#endif diff --git a/mozilla/gfx/src/os2/nsDeviceContextSpecFactoryO.cpp b/mozilla/gfx/src/os2/nsDeviceContextSpecFactoryO.cpp new file mode 100644 index 00000000000..f97931efa2e --- /dev/null +++ b/mozilla/gfx/src/os2/nsDeviceContextSpecFactoryO.cpp @@ -0,0 +1,68 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// This class is part of the strange printing `architecture'. +// The `CreateDeviceContextSpec' method basically selects a print queue, +// known here as an `nsIDeviceContextSpec'. This is given to a method +// in nsIDeviceContext which creates a fresh device context for that +// printer. + +#include "nsGfxDefs.h" +#include "libprint.h" + +#include "nsDeviceContextSpecFactoryO.h" +#include "nsDeviceContextSpecOS2.h" +#include "nsRegionOS2.h" +#include "nsGfxCIID.h" + +nsDeviceContextSpecFactoryOS2::nsDeviceContextSpecFactoryOS2() +{ + NS_INIT_REFCNT(); +} + +NS_IMPL_ISUPPORTS(nsDeviceContextSpecFactoryOS2, nsIDeviceContextSpecFactory::GetIID()) + +NS_IMETHODIMP nsDeviceContextSpecFactoryOS2::Init() +{ + return NS_OK; +} + +NS_IMETHODIMP nsDeviceContextSpecFactoryOS2::CreateDeviceContextSpec( + nsIDeviceContextSpec *aOldSpec, + nsIDeviceContextSpec *&aNewSpec, + PRBool aQuiet) +{ + nsresult rc = NS_ERROR_FAILURE; + + // This currently ignores aOldSpec. This may be of no consequence... + PRTQUEUE *pq = PrnSelectPrinter( HWND_DESKTOP, aQuiet ? TRUE : FALSE); + + if( pq) + { + nsDeviceContextSpecOS2 *spec = new nsDeviceContextSpecOS2; + NS_ADDREF(spec); + spec->Init( pq); + aNewSpec = spec; + rc = NS_OK; + } + + return rc; +} diff --git a/mozilla/gfx/src/os2/nsDeviceContextSpecFactoryO.h b/mozilla/gfx/src/os2/nsDeviceContextSpecFactoryO.h new file mode 100644 index 00000000000..6648ca6d3f1 --- /dev/null +++ b/mozilla/gfx/src/os2/nsDeviceContextSpecFactoryO.h @@ -0,0 +1,49 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// This class is part of the strange printing `architecture'. +// The `CreateDeviceContextSpec' method basically selects a print queue, +// known here as an `nsIDeviceContextSpec'. This is given to a method +// in nsIDeviceContext which creates a fresh device context for that +// printer. + +#ifndef _nsDeviceContextSpecFactoryOS2_h +#define _nsDeviceContextSpecFactoryOS2_h + +#include "nsIDeviceContextSpecFactory.h" +#include "nsIDeviceContextSpec.h" + +class nsDeviceContextSpecFactoryOS2 : public nsIDeviceContextSpecFactory +{ + public: + nsDeviceContextSpecFactoryOS2(); + + NS_DECL_ISUPPORTS + + NS_IMETHOD Init(); + NS_IMETHOD CreateDeviceContextSpec( nsIDeviceContextSpec *aOldSpec, + nsIDeviceContextSpec *&aNewSpec, + PRBool aQuiet); + protected: + virtual ~nsDeviceContextSpecFactoryOS2() {} +}; + +#endif diff --git a/mozilla/gfx/src/os2/nsDeviceContextSpecOS2.cpp b/mozilla/gfx/src/os2/nsDeviceContextSpecOS2.cpp new file mode 100644 index 00000000000..7fdf0acb0f7 --- /dev/null +++ b/mozilla/gfx/src/os2/nsDeviceContextSpecOS2.cpp @@ -0,0 +1,51 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include "nsGfxDefs.h" +#include "libprint.h" + +#include "nsDeviceContextSpecOS2.h" + +nsDeviceContextSpecOS2::nsDeviceContextSpecOS2() +{ + NS_INIT_REFCNT(); + mQueue = nsnull; +} + +nsDeviceContextSpecOS2::~nsDeviceContextSpecOS2() +{ + if( mQueue) + PrnClosePrinter( mQueue); +} + +NS_IMPL_ISUPPORTS(nsDeviceContextSpecOS2, nsIDeviceContextSpec::GetIID()) + +nsresult nsDeviceContextSpecOS2::Init( PRTQUEUE *pq) +{ + mQueue = pq; + return NS_OK; +} + +nsresult nsDeviceContextSpecOS2::GetPRTQUEUE( PRTQUEUE *&p) +{ + p = mQueue; + return NS_OK; +} diff --git a/mozilla/gfx/src/os2/nsDeviceContextSpecOS2.h b/mozilla/gfx/src/os2/nsDeviceContextSpecOS2.h new file mode 100644 index 00000000000..1f3e4b92629 --- /dev/null +++ b/mozilla/gfx/src/os2/nsDeviceContextSpecOS2.h @@ -0,0 +1,43 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsDeviceContextSpecOS2_h +#define _nsDeviceContextSpecOS2_h + +#include "nsIDeviceContextSpec.h" + +class nsDeviceContextSpecOS2 : public nsIDeviceContextSpec +{ + public: + nsDeviceContextSpecOS2(); + + NS_DECL_ISUPPORTS + + NS_IMETHOD Init( PRTQUEUE *pq); + NS_IMETHOD GetPRTQUEUE( PRTQUEUE *&p); + + protected: + virtual ~nsDeviceContextSpecOS2(); + + PRTQUEUE *mQueue; +}; + +#endif diff --git a/mozilla/gfx/src/os2/nsDrawingSurfaceOS2.cpp b/mozilla/gfx/src/os2/nsDrawingSurfaceOS2.cpp new file mode 100644 index 00000000000..24d7874be61 --- /dev/null +++ b/mozilla/gfx/src/os2/nsDrawingSurfaceOS2.cpp @@ -0,0 +1,556 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include "nsGfxDefs.h" +#include "nsHashtable.h" +#include "nsIWidget.h" +#include "nsDrawingSurfaceOS2.h" +#include "nsFontMetricsOS2.h" +#include "nsPaletteOS2.h" + +// Base class -- fonts, palette and xpcom ----------------------------------- + +NS_IMPL_ISUPPORTS(nsDrawingSurfaceOS2,nsIDrawingSurface::GetIID()) + +// We start allocated lCIDs at 2. This leaves #1 for nsFontMetricsOS2 to +// do testing with, and 0 is, of course, LCID_DEFAULT. + +nsDrawingSurfaceOS2::nsDrawingSurfaceOS2() + : mNextID(2), mTopID(1), mPalette(0), mPS(0) +{ + NS_INIT_REFCNT(); + mHTFonts = new nsHashtable; +} + +nsDrawingSurfaceOS2::~nsDrawingSurfaceOS2() +{ + // release palette; no harm if it's already been done by a subclass + DeselectPalette(); + DisposeFonts(); +} + +void nsDrawingSurfaceOS2::DisposeFonts() +{ + if( mHTFonts) + { + // free font things + GpiSetCharSet( mPS, LCID_DEFAULT); + for( int i = 2; i <= mTopID; i++) + { + if( !GpiDeleteSetId( mPS, i)) + PMERROR( "GpiDeleteSetId"); + } + delete mHTFonts; + mHTFonts = 0; + } +} + +// Key for the hashtable +typedef nsVoidKey FontHandleKey; + +void nsDrawingSurfaceOS2::SelectFont( nsIFontMetrics *metrics) +{ + nsFontHandle fh = nsnull; + metrics->GetFontHandle( fh); + + nsFontHandleOS2 *pHandle = (nsFontHandleOS2 *) fh; + FontHandleKey key( pHandle); + + if( !mHTFonts->Get( &key)) + { + if( mNextID == 255) + // ids used up, need to empty table and start again. + FlushFontCache(); + + GpiCreateLogFont( mPS, 0, mNextID, &pHandle->fattrs); + mHTFonts->Put( &key, (void *) mNextID); + mNextID++; + if( mTopID < 254) + mTopID++; + } + + long lcid = (long) mHTFonts->Get( &key); + pHandle->SelectIntoPS( mPS, lcid); +} + +void nsDrawingSurfaceOS2::FlushFontCache() +{ + mHTFonts->Reset(); + mNextID = 2; + // leave mTopID where it is. +} + +// Palette +void nsDrawingSurfaceOS2::SetPalette( nsIPaletteOS2 *aPalette) +{ + NS_IF_RELEASE(mPalette); + mPalette = aPalette; + NS_ADDREF(mPalette); +} + +void nsDrawingSurfaceOS2::DeselectPalette() +{ + if( mPalette) + { + mPalette->Deselect( mPS); + NS_RELEASE(mPalette); // this nulls out mPalette + } +} + +// yuck. +nsresult nsDrawingSurfaceOS2::GetBitmap( HBITMAP &aBitmap) +{ + aBitmap = 0; + return NS_OK; +} + +nsresult nsDrawingSurfaceOS2::RequiresInvertedMask( PRBool *aBool) +{ + *aBool = (PRBool) (gModuleData.lDisplayDepth <= 8); + return NS_OK; +} + +// Offscreen surface -------------------------------------------------------- + +nsOffscreenSurface::nsOffscreenSurface() : mDC(0), mBitmap(0), + mHeight(0), mWidth(0), + mInfoHeader(0), mBits(0), + mYPels(0), mScans(0) +{} + +// Setup a new offscreen surface which is to be compatible with the +// passed-in presentation space. +nsresult nsOffscreenSurface::Init( HPS aCompatiblePS, + PRInt32 aWidth, PRInt32 aHeight) +{ + nsresult rc = NS_ERROR_FAILURE; + + // Find the compatible device context and create a memory one + HDC hdcCompat = GpiQueryDevice( aCompatiblePS); + DEVOPENSTRUC dop = { 0, 0, 0, 0, 0 }; + mDC = DevOpenDC( 0/*hab*/, OD_MEMORY, "*", 5, + (PDEVOPENDATA) &dop, hdcCompat); + + if( DEV_ERROR != mDC) + { + // create the PS + SIZEL sizel = { 0, 0 }; + mPS = GpiCreatePS( 0/*hab*/, mDC, &sizel, + PU_PELS | GPIT_MICRO | GPIA_ASSOC); + + if( GPI_ERROR != mPS) + { + // now create a bitmap of the right size + BITMAPINFOHEADER2 hdr = { 0 }; + + hdr.cbFix = sizeof( BITMAPINFOHEADER2); + hdr.cx = aWidth; + hdr.cy = aHeight; + hdr.cPlanes = 1; + + // find bitdepth + LONG lBitCount = 0; + DevQueryCaps( hdcCompat, CAPS_COLOR_BITCOUNT, 1, &lBitCount); + hdr.cBitCount = (USHORT) lBitCount; + + mBitmap = GpiCreateBitmap( mPS, &hdr, 0, 0, 0); + + if( GPI_ERROR != mBitmap) + { + // set final stats & select bitmap into ps + mHeight = aHeight; + mWidth = aWidth; + GpiSetBitmap( mPS, mBitmap); + rc = NS_OK; + } + else + PMERROR( "GpiCreateBitmap"); + } + else + PMERROR( "GpiCreatePS"); + } + else + PMERROR( "DevOpenDC"); + + return rc; +} + +nsOffscreenSurface::~nsOffscreenSurface() +{ + if( mPS) + { + DisposeFonts(); + if( HBM_ERROR == GpiSetBitmap( mPS, 0)) + PMERROR( "GpiSetBitmap"); + if( !GpiDeleteBitmap( mBitmap)) + PMERROR( "GpiDeleteBitmap"); + DeselectPalette(); +// +// Don't need to do this because the PS is a micro-one. +// +// if( !GpiAssociate( mPS, 0)) +// PMERROR( "GpiAssociate"); +// + if( !GpiDestroyPS( mPS)) + PMERROR( "GpiDestroyPS"); + if( DEV_ERROR == DevCloseDC( mDC)) + PMERROR( "DevCloseDC"); + mPS = 0; + } + if( mInfoHeader) + free( mInfoHeader); + delete [] mBits; +} + +nsresult nsOffscreenSurface::GetBitmap( HBITMAP &aBitmap) +{ + aBitmap = mBitmap; + return NS_OK; +} + +// Okay; plan here is to get the bits and hope that the fact that we're +// returning an upside-down rectangle doesn't matter. +// +// If it does, then the following needs to be done: +// +// * undefine the USD flag in libimg +// * alter the draw code in nsImageOS2 to draw right-way-up +// * fix the printing case (probably involving an ugly xform) +// +nsresult nsOffscreenSurface::Lock( PRInt32 aX, PRInt32 aY, + PRUint32 aWidth, PRUint32 aHeight, + void **aBits, PRInt32 *aStride, + PRInt32 *aWidthBytes, + PRUint32 aFlags) +{ + // Trust other platforms to ensure that we don't get nested! + PRInt32 lStride = 0; + ULONG rc = 0; + + // Allocate buffers first time we get called. + // + // Need to look at the way in which this functionality is exercised: + // may actually be more efficient to only grab the section of bitmap + // required on each call, and to free up memory afterwards. + // + // Currently: * allocate once enough space for the entire bitmap + // * only grab & set the required scanlines + // + if( !mBits) + { + BITMAPINFOHEADER bih = { sizeof( BITMAPINFOHEADER), 0, 0, 0, 0 }; + + rc = GpiQueryBitmapInfoHeader( mBitmap, (PBITMAPINFOHEADER2) &bih); + if( !rc) PMERROR( "GpiQueryInfoHeader"); + + // alloc space to query pel data into... + lStride = RASWIDTH( bih.cx, bih.cBitCount); + mBits = new PRUint8 [ lStride * bih.cy ]; + + // ..and colour table too + int cols = -1; + if( bih.cBitCount >= 24) cols = 0; + else cols = 1 << bih.cBitCount; + + int szStruct = sizeof( BITMAPINFOHEADER2) + cols * sizeof( RGB2); + + mInfoHeader = (PBITMAPINFOHEADER2) calloc( szStruct, 1); + mInfoHeader->cbFix = sizeof( BITMAPINFOHEADER2); + mInfoHeader->cx = bih.cx; + mInfoHeader->cy = bih.cy; + mInfoHeader->cPlanes = 1; + mInfoHeader->cBitCount = (USHORT) bih.cBitCount; + // GPI-Ref says these have to be set too... + mInfoHeader->ulCompression = BCA_UNCOMP; + mInfoHeader->usRecording = BRA_BOTTOMUP; + mInfoHeader->usRendering = BRH_NOTHALFTONED; // ...hmm... + mInfoHeader->ulColorEncoding = BCE_RGB; + } + else + lStride = RASWIDTH( mInfoHeader->cx, mInfoHeader->cBitCount); + + // record starting scanline (bottom is 0) + mYPels = mInfoHeader->cy - aY - aHeight; + mScans = aHeight; + + rc = GpiQueryBitmapBits( mPS, mYPels, mScans, (char*) mBits, + (PBITMAPINFO2) mInfoHeader); + if( rc != mInfoHeader->cy) PMERROR( "GpiQueryBitmapBits"); + +#ifdef DEBUG + printf( "Lock, requested %d x %d and got %d x %d\n", + aWidth, aHeight, (int) mInfoHeader->cx, aHeight); +#endif + + // Okay. Now have current state of bitmap in mBits. + *aStride = lStride; + *aBits = (void*) (mBits + (aX * (mInfoHeader->cBitCount >> 3))); + *aWidthBytes = aWidth * (mInfoHeader->cBitCount >> 3); + + return NS_OK; +} + +nsresult nsOffscreenSurface::Unlock() +{ + long rc = GpiSetBitmapBits( mPS, mYPels, mScans, (char*) mBits, + (PBITMAPINFO2) mInfoHeader); + if( rc == GPI_ALTERROR) PMERROR( "GpiSetBitmapBits"); + + return NS_OK; +} + +nsresult nsOffscreenSurface::GetDimensions( PRUint32 *aWidth, PRUint32 *aHeight) +{ + if( !aWidth || !aHeight) + return NS_ERROR_NULL_POINTER; + + *aWidth = mWidth; + *aHeight = mHeight; + + return NS_OK; +} + +nsresult nsOffscreenSurface::IsOffscreen( PRBool *aOffScreen) +{ + if( !aOffScreen) + return NS_ERROR_NULL_POINTER; + + *aOffScreen = PR_TRUE; + + return NS_OK; +} + +nsresult nsOffscreenSurface::IsPixelAddressable( PRBool *aAddressable) +{ + if( !aAddressable) + return NS_ERROR_NULL_POINTER; + + *aAddressable = PR_TRUE; + + return NS_OK; +} + +nsresult nsOffscreenSurface::GetPixelFormat( nsPixelFormat *aFormat) +{ + if( !aFormat) + return NS_ERROR_NULL_POINTER; + + // Okay. Who knows what's going on here - we (as wz) currently support + // only 8 and 24 bpp bitmaps; dunno what should be done for 32 bpp, + // even if os/2 supports them. + // + // (prob'ly need to get the FOURCC stuff into the act for 16bpp?) + // + BITMAPINFOHEADER bih = { sizeof( BITMAPINFOHEADER), 0, 0, 0, 0 }; + long rc = GpiQueryBitmapInfoHeader( mBitmap, (PBITMAPINFOHEADER2) &bih); + + switch( bih.cBitCount) + { + case 8: + memset( aFormat, 0, sizeof(nsPixelFormat)); + break; + + case 24: + aFormat->mRedZeroMask = 0xff; + aFormat->mGreenZeroMask = 0xff; + aFormat->mBlueZeroMask = 0xff; + aFormat->mAlphaZeroMask = 0; + aFormat->mRedMask = 0xff; + aFormat->mGreenMask = 0xff00; + aFormat->mBlueMask = 0xff0000; + aFormat->mAlphaMask = 0; + aFormat->mRedCount = 8; + aFormat->mGreenCount = 8; + aFormat->mBlueCount = 8; + aFormat->mAlphaCount = 0; + aFormat->mRedShift = 0; + aFormat->mGreenShift = 8; + aFormat->mBlueShift = 16; + aFormat->mAlphaShift = 0; + break; + + default: + printf( "Bad bit-depth for GetPixelFormat (%d)\n", bih.cBitCount); + break; + } + + return NS_OK; +} + +// Non-offscreen surfaces, base for window & print -------------------------- +nsOnscreenSurface::nsOnscreenSurface() : mProxySurface(nsnull) +{ +} + +nsOnscreenSurface::~nsOnscreenSurface() +{ + NS_IF_RELEASE(mProxySurface); +} + +void nsOnscreenSurface::EnsureProxy() +{ + if( !mProxySurface) + { + PRUint32 width, height; + GetDimensions( &width, &height); + + mProxySurface = new nsOffscreenSurface; + if( NS_SUCCEEDED(mProxySurface->Init( mPS, width, height))) + { + NS_ADDREF(mProxySurface); + } + else + { + delete mProxySurface; + mProxySurface = nsnull; + } + } +} + +nsresult nsOnscreenSurface::Lock( PRInt32 aX, PRInt32 aY, + PRUint32 aWidth, PRUint32 aHeight, + void **aBits, PRInt32 *aStride, + PRInt32 *aWidthBytes, + PRUint32 aFlags) +{ + EnsureProxy(); + + printf( "Locking through a proxy\n"); + + // blit our 'real' bitmap to the proxy surface + PRUint32 width, height; + GetDimensions( &width, &height); + POINTL pts[3] = { { 0, 0 }, { width, height }, { 0, 0 } }; + long lHits = GpiBitBlt( mProxySurface->mPS, mPS, 3, pts, + ROP_SRCCOPY, BBO_OR); + if( GPI_ERROR == lHits) PMERROR( "GpiBitBlt/DSL"); + + return mProxySurface->Lock( aX, aY, aWidth, aHeight, + aBits, aStride, aWidthBytes, aFlags); +} + +nsresult nsOnscreenSurface::Unlock() +{ + nsresult rc = mProxySurface->Unlock(); + + // blit proxy bitmap back to ours + PRUint32 width, height; + GetDimensions( &width, &height); + POINTL pts[3] = { { 0, 0 }, { width, height }, { 0, 0 } }; + long lHits = GpiBitBlt( mPS, mProxySurface->mPS, 3, pts, + ROP_SRCCOPY, BBO_OR); + if( GPI_ERROR == lHits) PMERROR( "GpiBitBlt/DSUL"); + + return rc; +} + +nsresult nsOnscreenSurface::GetPixelFormat( nsPixelFormat *aFormat) +{ + EnsureProxy(); + return mProxySurface->GetPixelFormat( aFormat); +} + +nsresult nsOnscreenSurface::IsOffscreen( PRBool *aOffScreen) +{ + if( !aOffScreen) + return NS_ERROR_NULL_POINTER; + + *aOffScreen = PR_FALSE; + + return NS_OK; +} + +nsresult nsOnscreenSurface::IsPixelAddressable( PRBool *aAddressable) +{ + if( !aAddressable) + return NS_ERROR_NULL_POINTER; + + *aAddressable = PR_FALSE; + + return NS_OK; +} + +// Surface for a PM window -------------------------------------------------- +nsWindowSurface::nsWindowSurface() : mWidget(nsnull) +{} + +nsWindowSurface::~nsWindowSurface() +{ + // palette will be deselected in superclass dtor + + // need to do this now because hps is invalid after subsequent free + DisposeFonts(); + // release hps + mWidget->FreeNativeData( (void*) mPS, NS_NATIVE_GRAPHIC); + mPS = 0; // just for safety +} + +nsresult nsWindowSurface::Init( nsIWidget *aOwner) +{ + mWidget = aOwner; + mPS = (HPS) mWidget->GetNativeData( NS_NATIVE_GRAPHIC); + return NS_OK; +} + +nsresult nsWindowSurface::GetDimensions( PRUint32 *aWidth, PRUint32 *aHeight) +{ + // I don't think we can be more efficient than this, except perhaps by + // doing some kind of `push' of height from the window to us. + nsRect rect; + mWidget->GetClientBounds( rect); + *aHeight = rect.height; + *aWidth = rect.width; + return NS_OK; +} + +// Printer surface. A few minor differences, like the page size is fixed --- +nsPrintSurface::nsPrintSurface() : mHeight(0), mWidth(0) +{} + +nsresult nsPrintSurface::Init( HPS aPS, PRInt32 aWidth, PRInt32 aHeight) +{ + mPS = aPS; + mHeight = aHeight; + mWidth = aWidth; + return NS_OK; +} + +nsPrintSurface::~nsPrintSurface() +{ + // PS is owned by the DC; superclass dtor will deselect palette. +} + +nsresult nsPrintSurface::GetDimensions( PRUint32 *aWidth, PRUint32 *aHeight) +{ + if( !aWidth || !aHeight) + return NS_ERROR_NULL_POINTER; + + *aWidth = mWidth; + *aHeight = mHeight; + + return NS_OK; +} + +nsresult nsPrintSurface::RequiresInvertedMask( PRBool *aBool) +{ + *aBool = PR_FALSE; + return NS_OK; +} diff --git a/mozilla/gfx/src/os2/nsDrawingSurfaceOS2.h b/mozilla/gfx/src/os2/nsDrawingSurfaceOS2.h new file mode 100644 index 00000000000..7941914dd3a --- /dev/null +++ b/mozilla/gfx/src/os2/nsDrawingSurfaceOS2.h @@ -0,0 +1,156 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsDrawingSurfaceOS2_h +#define _nsDrawingSurfaceOS2_h + +#include "nsIDrawingSurface.h" + +class nsHashtable; +class nsIWidget; +class nsIPaletteOS2; + +// These were called `drawables' in os2fe. +// +// Note that each surface has a ref to the palette of the device context +// from which it was spun off. This is because drawing surfaces have +// lifetimes which extend further than the rendering context which +// created them. The creating object must select the palette into the +// surface's presentation space; all the drawing surface does is deselect +// the palette when it's dying. +// +// This is rather unwieldy... +// +// Note: |nsDrawingSurface| == (void*)(nsDrawingSurfaceOS2*)surf + +class nsDrawingSurfaceOS2 : public nsIDrawingSurface +{ + nsHashtable *mHTFonts; // cache of fonthandle to lcid + long mNextID; // next lcid to allocate + long mTopID; // highest used lcid + nsIPaletteOS2 *mPalette; // palette + + protected: + void DeselectPalette(); + void DisposeFonts(); // MUST be called before disposing of PS + + public: + nsDrawingSurfaceOS2(); + virtual ~nsDrawingSurfaceOS2(); + + // nsISupports + NS_DECL_ISUPPORTS + + // nsIDrawingSurface actually implemented in subclasses + + HPS mPS; // presentation space for this surface + + void SelectFont( nsIFontMetrics *metrics); + void FlushFontCache(); + + void SetPalette( nsIPaletteOS2 *aPalette); + + NS_IMETHOD GetBitmap( HBITMAP &aBitmap); // yuck (for blender, may go) + NS_IMETHOD RequiresInvertedMask( PRBool *aBool); // double yuck (images) +}; + +// Offscreen surface. Others depend on this. +class nsOffscreenSurface : public nsDrawingSurfaceOS2 +{ + HDC mDC; + HBITMAP mBitmap; + PRInt32 mHeight; + PRInt32 mWidth; + + PBITMAPINFOHEADER2 mInfoHeader; + PRUint8 *mBits; + + PRInt32 mYPels; + PRUint32 mScans; + + public: + nsOffscreenSurface(); + virtual ~nsOffscreenSurface(); + + // os/2 methods + NS_IMETHOD Init( HPS aCompatiblePS, PRInt32 aWidth, PRInt32 aHeight); + NS_IMETHOD GetBitmap( HBITMAP &aBitmap); + + // nsIDrawingSurface methods + NS_IMETHOD Lock( PRInt32 aX, PRInt32 aY, PRUint32 aWidth, PRUint32 aHeight, + void **aBits, PRInt32 *aStride, PRInt32 *aWidthBytes, + PRUint32 aFlags); + NS_IMETHOD Unlock(); + NS_IMETHOD GetDimensions( PRUint32 *aWidth, PRUint32 *aHeight); + NS_IMETHOD IsOffscreen( PRBool *aOffScreen); + NS_IMETHOD IsPixelAddressable( PRBool *aAddressable); + NS_IMETHOD GetPixelFormat( nsPixelFormat *aFormat); +}; + +// Onscreen surface - uses an offscreen to implement bitlevel access +class nsOnscreenSurface : public nsDrawingSurfaceOS2 +{ + nsOffscreenSurface *mProxySurface; + void EnsureProxy(); + + public: + nsOnscreenSurface(); + virtual ~nsOnscreenSurface(); + + // nsIDrawingSurface methods + NS_IMETHOD Lock( PRInt32 aX, PRInt32 aY, PRUint32 aWidth, PRUint32 aHeight, + void **aBits, PRInt32 *aStride, PRInt32 *aWidthBytes, + PRUint32 aFlags); + NS_IMETHOD Unlock(); + NS_IMETHOD IsOffscreen( PRBool *aOffScreen); + NS_IMETHOD IsPixelAddressable( PRBool *aAddressable); + NS_IMETHOD GetPixelFormat( nsPixelFormat *aFormat); +}; + +// Surface for an onscreen window +class nsWindowSurface : public nsOnscreenSurface +{ + nsIWidget *mWidget; // window who owns the surface + + public: + nsWindowSurface(); + virtual ~nsWindowSurface(); + + NS_IMETHOD Init( nsIWidget *aOwner); + NS_IMETHOD GetDimensions( PRUint32 *aWidth, PRUint32 *aHeight); +}; + +// Surface for a printer-page +class nsPrintSurface : public nsOnscreenSurface +{ + PRInt32 mHeight; + PRInt32 mWidth; + + public: + nsPrintSurface(); + virtual ~nsPrintSurface(); + + NS_IMETHOD Init( HPS aPS, PRInt32 aWidth, PRInt32 aHeight); + NS_IMETHOD RequiresInvertedMask( PRBool *aNeedsIMask); + NS_IMETHOD GetDimensions( PRUint32 *aWidth, PRUint32 *aHeight); +}; + +#endif diff --git a/mozilla/gfx/src/os2/nsFontMetricsOS2.cpp b/mozilla/gfx/src/os2/nsFontMetricsOS2.cpp new file mode 100644 index 00000000000..22fb62a6c95 --- /dev/null +++ b/mozilla/gfx/src/os2/nsFontMetricsOS2.cpp @@ -0,0 +1,429 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// ToDo: Unicode, encoding. +// Revision by someone who *really* understands OS/2 fonts. + +#include "nsGfxDefs.h" +#include "nsDeviceContextOS2.h" +#include "nsFontMetricsOS2.h" +#include "nsString.h" +#include "nsFont.h" + +// font handle +nsFontHandleOS2::nsFontHandleOS2() +{ + memset( &fattrs, 0, sizeof fattrs); + fattrs.usRecordLength = sizeof fattrs; + charbox.cx = charbox.cy = 0; +} + +void nsFontHandleOS2::SelectIntoPS( HPS hps, long lcid) +{ + if( !GpiSetCharBox( hps, &charbox)) + PMERROR("GpiSetCharBox"); + if( !GpiSetCharSet( hps, lcid)) + PMERROR("GpiSetCharSet"); +} + +nsFontMetricsOS2::nsFontMetricsOS2() +{ + // members are zeroed by new operator (hmm) + NS_INIT_REFCNT(); +} + +nsFontMetricsOS2::~nsFontMetricsOS2() +{ + Destroy(); + + delete mFont; + delete mFontHandle; +} + +NS_IMPL_ISUPPORTS( nsFontMetricsOS2, nsIFontMetrics::GetIID()) + +nsresult nsFontMetricsOS2::Init( const nsFont &aFont, nsIDeviceContext *aContext) +{ + mFont = new nsFont( aFont); + mContext = (nsDeviceContextOS2 *) aContext; + RealizeFont(); + return NS_OK; +} + +nsresult nsFontMetricsOS2::Destroy() +{ + return NS_OK; +} + +// Map CSS font names to something we can understand locally. +// Some conversions are a bit dodgy (fantasy) but there's little option, I +// guess. +// Surely this should be in XP code somewhere? +static void MapGenericFamilyToFont( const nsString &aGenericFamily, + nsIDeviceContext *aDC, + nsString &aFontFace) +{ + // the CSS generic names (conversions from Nav for now) + // XXX this need to check availability with the dc + PRBool aliased; + if( aGenericFamily.EqualsIgnoreCase( "serif")) + aDC->GetLocalFontName( nsString( "Tms Rmn"), aFontFace, aliased); + else if( aGenericFamily.EqualsIgnoreCase( "sans-serif")) + aDC->GetLocalFontName( nsString( "Helv"), aFontFace, aliased); + else if( aGenericFamily.EqualsIgnoreCase( "Helv")) // !! + aDC->GetLocalFontName( nsString( "Script"), aFontFace, aliased); + else if( aGenericFamily.EqualsIgnoreCase( "fantasy")) // !! + aDC->GetLocalFontName(nsString( "Arial"), aFontFace, aliased); + else if( aGenericFamily.EqualsIgnoreCase( "monospace")) + aDC->GetLocalFontName( nsString( "Courier"), aFontFace, aliased); + else + aFontFace.Truncate(); +} + +struct FontEnumData +{ + FontEnumData( nsIDeviceContext* aContext, char* aFaceName) + : mContext( aContext), mFaceName( aFaceName) + {} + + nsIDeviceContext *mContext; + char *mFaceName; +}; + +// callback for each of the faces in the nsFont (use the first we can match) +static PRBool FontEnumCallback( const nsString& aFamily, PRBool aGeneric, void *aData) +{ + FontEnumData *data = (FontEnumData*)aData; + PRBool rc = PR_TRUE; + + if( aGeneric) + { + nsAutoString realFace; + MapGenericFamilyToFont( aFamily, data->mContext, realFace); + realFace.ToCString( data->mFaceName, FACESIZE); + rc = PR_FALSE; // stop + } + else + { + nsAutoString realFace; + PRBool aliased; + data->mContext->GetLocalFontName( aFamily, realFace, aliased); + if( aliased || (NS_OK == data->mContext->CheckFontExistence( realFace))) + { + realFace.ToCString(data->mFaceName, FACESIZE); + rc = PR_FALSE; // stop + } + } + + return PR_TRUE; +} + +// Current strategy wrt. image/outline fonts: +// If image face requested is available in the point size requested, +// use it. If not, use the corresponding outline font. The reason +// why we deal with this here instead of letting GpiCreateLogFont() do +// something sensible is because it doesn't do the right thing with +// bold/italic effects: if we ask for bold Tms Rmn in 35 pt, we don't +// get Times New Roman Bold in 35 pt, but Times New Roman 35pt with a +// fake bold effect courtesy of gpi, which looks ugly. +// +// Yes, it would be easier & quite plausable to ignore image fonts altogether +// and just use outlines, but I reckon image fonts look better at lower +// point sizes. +// +// Candidate for butchery! + +// Utility; delete [] when done. +static PFONTMETRICS getMetrics( long &lFonts, PCSZ facename, HPS hps) +{ + LONG lWant = 0; + lFonts = GpiQueryFonts( hps, QF_PUBLIC | QF_PRIVATE, + facename, &lWant, 0, 0); + PFONTMETRICS pMetrics = new FONTMETRICS [ lFonts]; + + GpiQueryFonts( hps, QF_PUBLIC | QF_PRIVATE, facename, &lFonts, + sizeof( FONTMETRICS), pMetrics); + + return pMetrics; +} + +void nsFontMetricsOS2::RealizeFont() +{ + nsFontHandleOS2 *fh = new nsFontHandleOS2; + + // 1) Find family name + char szFamily[ FACESIZE] = ""; + FontEnumData data( mContext, szFamily); + mFont->EnumerateFamilies( FontEnumCallback, &data); + + // sanity check - no way of telling whether we want a fixed or prop font.. + if( !szFamily[0]) + strcpy( szFamily, "System Proportional"); + + // 2) Get a representative PS for doing font queries into + HPS hps = mContext->GetRepresentativePS(); + + // 3) Work out what our options are wrt. image/outline, prefer image. + BOOL bOutline = FALSE, bImage = FALSE; + long lFonts = 0; int i; + PFONTMETRICS pMetrics = getMetrics( lFonts, szFamily, hps); + + for( i = 0; i < lFonts && !(bImage && bOutline); i++) + if( pMetrics[ i].fsDefn & FM_DEFN_OUTLINE) bOutline = TRUE; + else bImage = TRUE; + delete [] pMetrics; + + if( !bImage) fh->fattrs.fsFontUse = FATTR_FONTUSE_OUTLINE | + FATTR_FONTUSE_TRANSFORMABLE; + + // 4) Try to munge the face for italic & bold effects (could do better) + BOOL bBold = mFont->weight > NS_FONT_WEIGHT_NORMAL; + BOOL bItalic = !!(mFont->style & NS_FONT_STYLE_ITALIC); + FACENAMEDESC fnd = { sizeof( FACENAMEDESC), + bBold ? FWEIGHT_BOLD : FWEIGHT_DONT_CARE, + FWIDTH_DONT_CARE, + 0, + bItalic ? FTYPE_ITALIC : 0 }; + + ULONG rc = GpiQueryFaceString( hps, szFamily, &fnd, + FACESIZE, fh->fattrs.szFacename); + if( rc == GPI_ERROR) + { // no real font, fake it + strcpy( fh->fattrs.szFacename, szFamily); + if( bBold) fh->fattrs.fsSelection |= FATTR_SEL_BOLD; + if( bItalic) fh->fattrs.fsSelection |= FATTR_SEL_ITALIC; + } + + // 5) Add misc effects + if( mFont->decorations & NS_FONT_DECORATION_UNDERLINE) + fh->fattrs.fsSelection |= FATTR_SEL_UNDERSCORE; + if( mFont->decorations & NS_FONT_DECORATION_LINE_THROUGH) + fh->fattrs.fsSelection |= FATTR_SEL_STRIKEOUT; + + // 6) Encoding + // There doesn't seem to be any encoding stuff yet, so guess. + // (XXX unicode hack; use same codepage as converter!) + fh->fattrs.usCodePage = gModuleData.ulCodepage; + + // 7) Find the point size for the font, and set up the charbox too + float app2dev, app2twip, twip2dev; + mContext->GetAppUnitsToDevUnits( app2dev); + mContext->GetDevUnitsToTwips( app2twip); + mContext->GetTwipsToDevUnits( twip2dev); + + // !! Windows wants to mply up here. I don't think I do. If fonts + // !! ever begin to look `squished', try enabling the following code +#if 0 + float scale; + mContext->GetCanonicalPixelScale(scale); + app2twip *= app2dev * scale; +#else + app2twip *= app2dev; +#endif + + // Note: are you confused by the block above, and thinking that app2twip + // must be 1? Well, there's *no* guarantee that app units are + // twips, despite whatever nscoord.h says! + int points = NSTwipsToFloorIntPoints( nscoord( mFont->size * app2twip)); + fh->charbox.cx = MAKEFIXED( points * 20 * twip2dev, 0); + fh->charbox.cy = fh->charbox.cx; + + // 8) If we're using an image font, check it's available in the size + // required, substituting an outline if necessary. + if( bImage) + { + HDC hdc = GpiQueryDevice( hps); + long res[ 2]; + DevQueryCaps( hdc, CAPS_HORIZONTAL_FONT_RES, 2, res); + pMetrics = getMetrics( lFonts, szFamily, hps); + + for( i = 0; i < lFonts; i++) + if( !stricmp( szFamily, pMetrics[ i].szFamilyname) && + pMetrics[ i].sNominalPointSize / 10 == points && + pMetrics[ i].sXDeviceRes == res[0] && + pMetrics[ i].sYDeviceRes == res[1]) break; + + if( i == lFonts) + { + // Couldn't find an appropriate font, need to use an outline. + // If there was an outline originally, fine. If not... + if( !bOutline) + { + // Can't have the requested font in requested size; fake. + if( !stricmp( szFamily, "Helv")) + strcpy( szFamily, "Helvetica"); + else if( !stricmp( szFamily, "Courier")) + strcpy( szFamily, "Courier New"); + else + strcpy( szFamily, "Times New Roman"); // hmm + fh->fattrs.fsSelection &= ~(FATTR_SEL_BOLD | FATTR_SEL_ITALIC); + rc = GpiQueryFaceString( hps, szFamily, &fnd, + FACESIZE, fh->fattrs.szFacename); + if( rc == GPI_ERROR) + { + strcpy( fh->fattrs.szFacename, szFamily); + if( bBold) fh->fattrs.fsSelection |= FATTR_SEL_BOLD; + if( bItalic) fh->fattrs.fsSelection |= FATTR_SEL_ITALIC; + } + } + fh->fattrs.fsFontUse = FATTR_FONTUSE_OUTLINE | + FATTR_FONTUSE_TRANSFORMABLE; + } + else + { + // image face found fine, set required size in fattrs. + fh->fattrs.lMaxBaselineExt = pMetrics[ i].lMaxBaselineExt; + fh->fattrs.lAveCharWidth = pMetrics[ i].lAveCharWidth; + } + delete [] pMetrics; + } + + // 9) Record font handle & record various font metrics to cache + mFontHandle = fh; + if( GPI_ERROR == GpiCreateLogFont( hps, 0, 1, &fh->fattrs)) + PMERROR( "GpiCreateLogFont"); + fh->SelectIntoPS( hps, 1); + + FONTMETRICS fm; + GpiQueryFontMetrics( hps, sizeof fm, &fm); + + float dev2app; + mContext->GetDevUnitsToAppUnits( dev2app); + + // PM includes the internal leading in the max ascender. So the max + // ascender we tell raptor about should be lMaxAscent - lInternalLeading. + // + // This is probably all moot 'cos lInternalLeading is usually zero. + // More so 'cos layout doesn't look at the leading we give it. + // + // So let's leave it as zero to avoid confusion & change it if necessary. + + mHeight = NSToCoordRound( fm.lMaxBaselineExt * dev2app); + mMaxAscent = NSToCoordRound( fm.lMaxAscender * dev2app); + mMaxDescent = NSToCoordRound( fm.lMaxDescender * dev2app); + mMaxAdvance = NSToCoordRound( fm.lMaxCharInc * dev2app); + + mLeading = NSToCoordRound( fm.lInternalLeading * dev2app); + mXHeight = NSToCoordRound( fm.lXHeight * dev2app); + + mSuperscriptYOffset = NSToCoordRound( fm.lSuperscriptYOffset * dev2app); + mSubscriptYOffset = NSToCoordRound( fm.lSubscriptYOffset * dev2app); // !! check this + mStrikeoutPosition = NSToCoordRound( fm.lStrikeoutPosition * dev2app); + mStrikeoutSize = NSToCoordRound( fm.lStrikeoutSize * dev2app); + mUnderlinePosition = NSToCoordRound( -fm.lUnderscorePosition * dev2app); + mUnderlineSize = NSToCoordRound( fm.lUnderscoreSize * dev2app); + + // OS/2 field (needs to be kept in sync with mMaxAscent) + mDevMaxAscent = fm.lMaxAscender; + + // 10) Clean up + GpiSetCharSet( hps, LCID_DEFAULT); + if( !GpiDeleteSetId( hps, 1)) + PMERROR( "GpiDeleteSetID (FM)"); + mContext->ReleaseRepresentativePS( hps); +} + +nscoord nsFontMetricsOS2::GetSpaceWidth( nsIRenderingContext *aRContext) +{ + if( !mSpaceWidth) + { + char buf[1]; + buf[0] = ' '; + aRContext->GetWidth( buf, 1, mSpaceWidth); + } + + return mSpaceWidth; +} + +// Other metrics +NS_IMETHODIMP nsFontMetricsOS2::GetXHeight( nscoord &aResult) +{ + aResult = mXHeight; + return NS_OK; +} + +NS_IMETHODIMP nsFontMetricsOS2::GetSuperscriptOffset(nscoord& aResult) +{ + aResult = mSuperscriptYOffset; + return NS_OK; +} + +NS_IMETHODIMP nsFontMetricsOS2::GetSubscriptOffset(nscoord& aResult) +{ + aResult = mSubscriptYOffset; + return NS_OK; +} + +NS_IMETHODIMP nsFontMetricsOS2::GetStrikeout(nscoord& aOffset, nscoord& aSize) +{ + aOffset = mStrikeoutPosition; + aSize = mStrikeoutSize; + return NS_OK; +} + +NS_IMETHODIMP nsFontMetricsOS2::GetUnderline(nscoord& aOffset, nscoord& aSize) +{ + aOffset = mUnderlinePosition; + aSize = mUnderlineSize; + return NS_OK; +} + +NS_IMETHODIMP nsFontMetricsOS2::GetHeight( nscoord &aHeight) +{ + aHeight = mHeight; + return NS_OK; +} + +NS_IMETHODIMP nsFontMetricsOS2::GetLeading( nscoord &aLeading) +{ + aLeading = mLeading; + return NS_OK; +} + +NS_IMETHODIMP nsFontMetricsOS2::GetMaxAscent( nscoord &aAscent) +{ + aAscent = mMaxAscent; + return NS_OK; +} + +NS_IMETHODIMP nsFontMetricsOS2::GetMaxDescent( nscoord &aDescent) +{ + aDescent = mMaxDescent; + return NS_OK; +} + +NS_IMETHODIMP nsFontMetricsOS2::GetMaxAdvance( nscoord &aAdvance) +{ + aAdvance = mMaxAdvance; + return NS_OK; +} + +NS_IMETHODIMP nsFontMetricsOS2::GetFont( const nsFont *&aFont) +{ + aFont = mFont; + return NS_OK; +} + +NS_IMETHODIMP nsFontMetricsOS2::GetFontHandle( nsFontHandle &aHandle) +{ + aHandle = mFontHandle; + return NS_OK; +} diff --git a/mozilla/gfx/src/os2/nsFontMetricsOS2.h b/mozilla/gfx/src/os2/nsFontMetricsOS2.h new file mode 100644 index 00000000000..db403c6de80 --- /dev/null +++ b/mozilla/gfx/src/os2/nsFontMetricsOS2.h @@ -0,0 +1,101 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsFontMetricsOS2_h +#define _nsFontMetricsOS2_h + +#include "nsIFontMetrics.h" +#include "nsCRT.h" + +class nsIRenderingContext; +class nsDeviceContextOS2; +class nsString; +class nsFont; + +// An nsFontHandle is actually a pointer to one of these. +// It knows how to select itself into a ps. +struct nsFontHandleOS2 +{ + FATTRS fattrs; + SIZEF charbox; + + nsFontHandleOS2(); + void SelectIntoPS( HPS hps, long lcid); +}; + +class nsFontMetricsOS2 : public nsIFontMetrics +{ + public: + nsFontMetricsOS2(); + virtual ~nsFontMetricsOS2(); + + NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW + + NS_DECL_ISUPPORTS + + NS_IMETHOD Init( const nsFont& aFont, nsIDeviceContext *aContext); + NS_IMETHOD Destroy(); + + // Metrics + NS_IMETHOD GetXHeight( nscoord &aResult); + NS_IMETHOD GetSuperscriptOffset( nscoord &aResult); + NS_IMETHOD GetSubscriptOffset( nscoord &aResult); + NS_IMETHOD GetStrikeout( nscoord &aOffset, nscoord &aSize); + NS_IMETHOD GetUnderline( nscoord &aOffset, nscoord &aSize); + NS_IMETHOD GetHeight( nscoord &aHeight); + NS_IMETHOD GetLeading( nscoord &aLeading); + NS_IMETHOD GetMaxAscent( nscoord &aAscent); + NS_IMETHOD GetMaxDescent( nscoord &aDescent); + NS_IMETHOD GetMaxAdvance( nscoord &aAdvance); + + NS_IMETHOD GetFont( const nsFont *&aFont); + NS_IMETHOD GetFontHandle( nsFontHandle &aHandle); + + // for drawing text + PRUint32 GetDevMaxAscender() const { return mDevMaxAscent; } + nscoord GetSpaceWidth( nsIRenderingContext *aRContext); + + protected: + void RealizeFont(); + + nsFont *mFont; + + nscoord mXHeight; + nscoord mSuperscriptYOffset; + nscoord mSubscriptYOffset; + nscoord mStrikeoutPosition; + nscoord mStrikeoutSize; + nscoord mUnderlinePosition; + nscoord mUnderlineSize; + nscoord mHeight; + nscoord mLeading; + nscoord mMaxAscent; + nscoord mMaxDescent; + nscoord mMaxAdvance; + + PRUint32 mDevMaxAscent; + nscoord mSpaceWidth; + + nsFontHandleOS2 *mFontHandle; + nsDeviceContextOS2 *mContext; // sigh.. broken broken broken XP interfaces... +}; + +#endif diff --git a/mozilla/gfx/src/os2/nsGfxDefs.h b/mozilla/gfx/src/os2/nsGfxDefs.h new file mode 100644 index 00000000000..6c8e183b955 --- /dev/null +++ b/mozilla/gfx/src/os2/nsGfxDefs.h @@ -0,0 +1,86 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsgfxdefs_h +#define _nsgfxdefs_h + +// nsGfxDefs.h - common includes etc. for gfx library + +#include "nscore.h" + +#define INCL_PM +#define INCL_DOS +#include + +#include // XXX hack XXX + +#define COLOR_CUBE_SIZE 216 + +void PMERROR(const char *str); + +class nsString; +class nsIPaletteOS2; +class nsIDeviceContext; + +// Module data +struct nsGfxModuleData +{ + HMODULE hModResources; + HPS hpsScreen; + LONG lDisplayDepth; + + nsGfxModuleData(); + ~nsGfxModuleData(); + + // XXX XXX XXX this is a hack copied from the widget library (where it's + // not a hack but perfectly valid) until font-switching comes + // on-line. + // Unicode->local cp. conversions + char *ConvertFromUcs( const PRUnichar *pText, ULONG ulLength, char *szBuffer, ULONG ulSize); + char *ConvertFromUcs( const nsString &aStr, char *szBuffer, ULONG ulSize); + // these methods use a single static buffer + const char *ConvertFromUcs( const PRUnichar *pText, ULONG ulLength); + const char *ConvertFromUcs( const nsString &aStr); + + UconvObject converter; + BOOL supplantConverter; + PRUint32 renderingHints; + ULONG ulCodepage; + // XXX XXX XXX end hack + + void Init(); + + // This addref's + nsIPaletteOS2 *GetUIPalette( nsIDeviceContext *aContext); + + protected: + nsIPaletteOS2 *uiPalette; +}; + +extern nsGfxModuleData gModuleData; + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#define MK_RGB(r,g,b) ((r) * 65536) + ((g) * 256) + (b) + +#endif diff --git a/mozilla/gfx/src/os2/nsGfxFactoryOS2.cpp b/mozilla/gfx/src/os2/nsGfxFactoryOS2.cpp new file mode 100644 index 00000000000..b2e5be6ac47 --- /dev/null +++ b/mozilla/gfx/src/os2/nsGfxFactoryOS2.cpp @@ -0,0 +1,340 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// ToDo: nowt (except get rid of unicode hack) +#define INCL_DOS +#include "nsGfxDefs.h" +#include "libprint.h" +#include + +#include "nsISupports.h" +#include "nsIFactory.h" +#include "nsGfxCIID.h" +#include "nsFontMetricsOS2.h" +#include "nsRenderingContextOS2.h" +#include "nsImageOS2.h" +#include "nsDeviceContextOS2.h" +#include "nsRegionOS2.h" +#include "nsBlender.h" +#include "nsPaletteOS2.h" +#include "nsDeviceContextSpecOS2.h" +#include "nsDeviceContextSpecFactoryO.h" + +// nsGfxFactory.cpp - factory for creating os/2 graphics objects. + +static NS_DEFINE_IID(kCFontMetrics, NS_FONT_METRICS_CID); +static NS_DEFINE_IID(kCRenderingContext, NS_RENDERING_CONTEXT_CID); +static NS_DEFINE_IID(kCImage, NS_IMAGE_CID); +static NS_DEFINE_IID(kCDeviceContext, NS_DEVICE_CONTEXT_CID); +static NS_DEFINE_IID(kCRegion, NS_REGION_CID); +static NS_DEFINE_IID(kCBlender, NS_BLENDER_CID); +static NS_DEFINE_IID(kCDeviceContextSpec, NS_DEVICE_CONTEXT_SPEC_CID); +static NS_DEFINE_IID(kCDeviceContextSpecFactory, NS_DEVICE_CONTEXT_SPEC_FACTORY_CID); + +class nsGfxFactoryOS2 : public nsIFactory +{ + public: + + NS_DECL_ISUPPORTS + + // nsIFactory methods + NS_IMETHOD CreateInstance( nsISupports *aOuter, + const nsIID &aIID, + void **aResult); + + NS_IMETHOD LockFactory( PRBool aLock) { return NS_OK; } + + nsGfxFactoryOS2( const nsCID &aClass); + virtual ~nsGfxFactoryOS2(); + + private: + nsCID mClassID; +}; + +nsGfxFactoryOS2::nsGfxFactoryOS2( const nsCID &aClass) +{ + NS_INIT_REFCNT(); + mClassID = aClass; +} + +nsGfxFactoryOS2::~nsGfxFactoryOS2() +{ + NS_ASSERTION( mRefCnt == 0, "non-zero refcnt at destruction"); +} + +NS_IMPL_ISUPPORTS(nsGfxFactoryOS2,nsIFactory::GetIID()) + +nsresult nsGfxFactoryOS2::CreateInstance( nsISupports *aOuter, + const nsIID &aIID, + void **aResult) +{ + if( !aResult) + return NS_ERROR_NULL_POINTER; + + *aResult = 0; + + nsISupports *inst = nsnull; + + if( mClassID.Equals( kCFontMetrics)) { + inst = new nsFontMetricsOS2; + } + else if( mClassID.Equals( kCDeviceContext)) { + inst = new nsDeviceContextOS2; + } + else if( mClassID.Equals( kCRenderingContext)) { + inst = (nsISupports *)((nsIRenderingContext*)new nsRenderingContextOS2); + } + else if( mClassID.Equals( kCImage)) { + inst = new nsImageOS2; + } + else if( mClassID.Equals( kCRegion)) { + inst = new nsRegionOS2; + } + else if( mClassID.Equals( kCBlender)) { + inst = new nsBlender; + } + else if( mClassID.Equals( kCDeviceContextSpec)) { + inst = new nsDeviceContextSpecOS2; + } + else if( mClassID.Equals( kCDeviceContextSpecFactory)) { + inst = new nsDeviceContextSpecFactoryOS2; + } + + if( !inst) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult res = inst->QueryInterface(aIID, aResult); + + if( NS_FAILED(res)) + // We didn't get the right interface, so clean up + delete inst; + + return res; +} + +// This is a factory-factory: create a factory for the desired type. +extern "C" NS_GFXNONXP nsresult NSGetFactory(nsISupports* servMgr, + const nsCID &aClass, + const char *aClassName, + const char *aProgID, + nsIFactory **aFactory) +{ + if( !aFactory) + return NS_ERROR_NULL_POINTER; + + *aFactory = new nsGfxFactoryOS2( aClass); + + if( !*aFactory) + return NS_ERROR_OUT_OF_MEMORY; + + return (*aFactory)->QueryInterface( nsIFactory::GetIID(), (void**) aFactory); +} + +// Module-level data --------------------------------------------------------- +void PMERROR( const char *api) +{ + ERRORID eid = WinGetLastError(0); + USHORT usError = ERRORIDERROR(eid); + printf( "%s failed, error = 0x%X\n", api, usError); +} + +nsGfxModuleData::nsGfxModuleData() : hModResources(0), hpsScreen(0), + lDisplayDepth(0), uiPalette(0) +{} + +void nsGfxModuleData::Init() +{ + char buffer[CCHMAXPATH]; + APIRET rc; + + rc = DosLoadModule( buffer, CCHMAXPATH, "GFXOS2", &hModResources); + + if( rc) + { + printf( "Gfx failed to load self. rc = %d, cause = %s\n", (int)rc, buffer); + // rats. Can't load ourselves. Oh well. Try to be harmless... + hModResources = 0; + } + PrnInitialize( hModResources); + + // get screen bit-depth + hpsScreen = WinGetScreenPS( HWND_DESKTOP); + HDC hdc = GpiQueryDevice( hpsScreen); + DevQueryCaps( hdc, CAPS_COLOR_BITCOUNT, 1, &lDisplayDepth); + + // XXX XXX temp hack XXX XXX XXX + converter = 0; + supplantConverter = FALSE; + if( !getenv( "MOZ_DONT_DRAW_UNICODE")) + { + ULONG ulDummy = 0; + renderingHints = 0; + DosQueryCp( 4, &ulCodepage, &ulDummy); + } + else + { + renderingHints = NS_RENDERING_HINT_FAST_8BIT_TEXT; + ulCodepage = 1004; + } + // XXX XXX end temp hack XXX XXX XXX +} + +nsGfxModuleData::~nsGfxModuleData() +{ + // XXX XXX temp hack XXX XXX XXX + if( converter) + UniFreeUconvObject( converter); + // XXX XXX end temp hack XXX XXX XXX + + PrnTerminate(); + if( hModResources) + DosFreeModule( hModResources); + WinReleasePS( hpsScreen); + + NS_IF_RELEASE(uiPalette); +} + +nsIPaletteOS2 *nsGfxModuleData::GetUIPalette( nsIDeviceContext *aContext) +{ + if( !uiPalette) + NS_CreatePalette( aContext, uiPalette); + + NS_ADDREF(uiPalette); + + return uiPalette; +} + +nsGfxModuleData gModuleData; + +// XXX XXX XXX XXX Temp hack until font-switching comes on-line XXX XXX XXX XXX + +// Conversion from unicode to appropriate codepage +char *nsGfxModuleData::ConvertFromUcs( const PRUnichar *pText, ULONG ulLength, + char *szBuffer, ULONG ulSize) +{ + if( supplantConverter) + { + // We couldn't create a converter for some reason, so do this 'by hand'. + // Note this algorithm is fine for most of most western charsets, but + // fails dismally for various glyphs, baltic, points east... + ULONG ulCount = 0; + char *szSave = szBuffer; + while( *pText && ulCount < ulSize - 1) // (one for terminator) + { + *szBuffer = (char) *pText; + szBuffer++; + pText++; + ulCount++; + } + + // terminate string + *szBuffer = '\0'; + + return szSave; + } + + if( !converter) + { + // Create a converter from unicode to a codepage which PM can display. + UniChar codepage[20]; + int unirc = UniMapCpToUcsCp( 0, codepage, 20); + if( unirc == ULS_SUCCESS) + { + unirc = UniCreateUconvObject( codepage, &converter); + // XXX do we need to set substitution options here? + } + if( unirc != ULS_SUCCESS) + { + supplantConverter = TRUE; + renderingHints = NS_RENDERING_HINT_FAST_8BIT_TEXT; + ulCodepage = 1004; + printf( "Couldn't create gfx unicode converter.\n"); + return ConvertFromUcs( pText, szBuffer, ulSize); + } + } + + // Have converter, now get it to work... + + UniChar *ucsString = (UniChar*) pText; + size_t ucsLen = ulLength; + size_t cplen = ulSize; + size_t cSubs = 0; + + char *tmp = szBuffer; // function alters the out pointer + + int unirc = UniUconvFromUcs( converter, &ucsString, &ucsLen, + (void**) &tmp, &cplen, &cSubs); + + if( unirc == UCONV_E2BIG) // k3w1 + { + // terminate output string (truncating) + *(szBuffer + ulSize - 1) = '\0'; + } + else if( unirc != ULS_SUCCESS) + { + printf( "UniUconvFromUcs failed, rc %X\n", unirc); + supplantConverter = TRUE; + szBuffer = ConvertFromUcs( pText, szBuffer, ulSize); + supplantConverter = FALSE; + } + + return szBuffer; +} + +char *nsGfxModuleData::ConvertFromUcs( const nsString &aString, + char *szBuffer, ULONG ulSize) +{ + char *szRet = 0; + const PRUnichar *pUnicode = aString.GetUnicode(); + + if( pUnicode) + szRet = ConvertFromUcs( pUnicode, aString.Length() + 1, szBuffer, ulSize); + else + szRet = aString.ToCString( szBuffer, ulSize); + + return szRet; +} + +const char *nsGfxModuleData::ConvertFromUcs( const PRUnichar *pText, ULONG ulLength) +{ + // This is probably okay; longer strings will be truncated but istr there's + // a PM limit on things like windowtext + // (which these routines are usually used for) + + static char buffer[1024]; // XXX (multithread) + *buffer = '\0'; + return ConvertFromUcs( pText, ulLength, buffer, 1024); +} + +const char *nsGfxModuleData::ConvertFromUcs( const nsString &aString) +{ + const char *szRet = 0; + const PRUnichar *pUnicode = aString.GetUnicode(); + + if( pUnicode) + szRet = ConvertFromUcs( pUnicode, aString.Length() + 1); + else + szRet = aString.GetBuffer(); // hrm. + + return szRet; +} + +// XXX XXX XXX XXX End Temp hack until font-switching comes on-line XXX XXX XXX diff --git a/mozilla/gfx/src/os2/nsImageOS2.cpp b/mozilla/gfx/src/os2/nsImageOS2.cpp new file mode 100644 index 00000000000..92534f7e2ad --- /dev/null +++ b/mozilla/gfx/src/os2/nsImageOS2.cpp @@ -0,0 +1,356 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include "nsGfxDefs.h" +#include + +#include "nsImageOS2.h" +#include "nsIDeviceContext.h" +#include "nsRenderingContextOS2.h" + +NS_IMPL_ISUPPORTS(nsImageOS2,nsIImage::GetIID()); + +//------------------------------------------------------------ +nsImageOS2::nsImageOS2() +{ + NS_INIT_REFCNT(); + + mInfo = 0; + mStride = 0; + mImageBits = 0; + mBitmap = 0; + + mAStride = 0; + mAImageBits = 0; + mABitmap = 0; + mAlphaDepth = 0; + + mColorMap = 0; + + mOptimized = PR_FALSE; + + mDeviceDepth = 0; +} + +nsImageOS2::~nsImageOS2() +{ + Cleanup(); +} + +nsresult nsImageOS2::Init( PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth, + nsMaskRequirements aMaskRequirements) +{ + // Guard against memory leak in multiple init + Cleanup(); + + // (copying windows code - what about monochrome? Oh well.) + NS_ASSERTION( aDepth == 24 || aDepth == 8, "Bad image depth"); + + // Work out size of bitmap to allocate + mStride = RASWIDTH(aWidth,aDepth); + +// mStride = aWidth * aDepth; +// if( aDepth < 8) +// mStride += 7; +// mStride /= 8; +// +// // Make sure image width is 4byte aligned +// mStride = (mStride + 3) & ~0x3; + + mImageBits = new PRUint8 [ aHeight * mStride ]; + + // Set up bitmapinfo header + int cols = -1; + if( aDepth == 8) cols = COLOR_CUBE_SIZE; + else if( aDepth <= 32) cols = 0; + + int szStruct = sizeof( BITMAPINFOHEADER2) + cols * sizeof( RGB2); + + mInfo = (PBITMAPINFO2) calloc( szStruct, 1); + mInfo->cbFix = sizeof( BITMAPINFOHEADER2); + mInfo->cx = aWidth; + mInfo->cy = aHeight; + mInfo->cPlanes = 1; + mInfo->cBitCount = (USHORT) aDepth; + + // We can't set up the bitmap colour table yet. + + // init color map. + // XP will update the color map & then call ImageUpdated(), at which + // point we can change the color table in the bitmapinfo. + if( aDepth == 8) + { + mColorMap = new nsColorMap; + mColorMap->NumColors = COLOR_CUBE_SIZE; + mColorMap->Index = new PRUint8[3 * mColorMap->NumColors]; + } + + // Allocate stuff for mask bitmap + if( aMaskRequirements != nsMaskRequirements_kNoMask) + { + if( aMaskRequirements == nsMaskRequirements_kNeeds1Bit) + { + mAStride = (aWidth + 7) / 8; + mAlphaDepth = 1; + } + else + { + NS_ASSERTION( nsMaskRequirements_kNeeds8Bit == aMaskRequirements, + "unexpected mask depth"); + mAStride = aWidth; + mAlphaDepth = 8; + } + + // 32-bit align each row + mAStride = (mAStride + 3) & ~0x3; + + mAImageBits = new PRUint8 [ aHeight * mAStride]; + } + + return NS_OK; +} + +void nsImageOS2::Cleanup() +{ + if( mImageBits) { + delete [] mImageBits; mImageBits = 0; + } + if( mInfo) { + free( mInfo); mInfo = 0; + } + if( mColorMap) { + if( mColorMap->Index) + delete [] mColorMap->Index; + delete mColorMap; + mColorMap = 0; + } + if( mAImageBits) { + delete [] mAImageBits; mAImageBits = 0; + } + if( mBitmap) { + GpiDeleteBitmap( mBitmap); + mBitmap = 0; + } + if( mABitmap) { + GpiDeleteBitmap( mABitmap); + mABitmap = 0; + } +} + +void nsImageOS2::ImageUpdated( nsIDeviceContext *aContext, + PRUint8 aFlags, nsRect *aUpdateRect) +{ + // This is where we can set the bitmap colour table, as the XP code + // has filled in the colour map. It would be cute to be able to alias + // the bitmap colour table as the mColorMap->Index thing, but the formats + // are unfortunately different. Rats. + + if( aFlags & nsImageUpdateFlags_kColorMapChanged && mInfo->cBitCount == 8) + { + PRGB2 pBmpEntry = mInfo->argbColor; + PRUint8 *pMapByte = mColorMap->Index; + + for( PRInt32 i = 0; i < mColorMap->NumColors; i++, pBmpEntry++) + { + pBmpEntry->bRed = *pMapByte++; + pBmpEntry->bGreen = *pMapByte++; + pBmpEntry->bBlue = *pMapByte++; + } + + aContext->GetDepth( mDeviceDepth); + } + else if( aFlags & nsImageUpdateFlags_kBitsChanged) + { + // jolly good... + } +} + +nsresult nsImageOS2::Draw( nsIRenderingContext &aContext, + nsDrawingSurface aSurface, + PRInt32 aX, PRInt32 aY, + PRInt32 aWidth, PRInt32 aHeight) +{ + return Draw( aContext, aSurface, + 0, 0, mInfo->cx, mInfo->cy, + aX, aY, aWidth, aHeight); +} + +nsresult nsImageOS2::Draw( nsIRenderingContext &aContext, + nsDrawingSurface aSurface, + PRInt32 aSX, PRInt32 aSY, PRInt32 aSW, PRInt32 aSH, + PRInt32 aDX, PRInt32 aDY, PRInt32 aDW, PRInt32 aDH) +{ + // Find target rect in OS/2 coords. + nsRect trect( aDX, aDY, aDW, aDH); + RECTL rcl; + ((nsRenderingContextOS2 &)aContext).NS2PM_ININ( trect, rcl); // !! !! !! + + nsDrawingSurfaceOS2 *surf = (nsDrawingSurfaceOS2*) aSurface; + + // Set up blit coord array + POINTL aptl[ 4] = { { rcl.xLeft, rcl.yBottom }, + { rcl.xRight, rcl.yTop }, + { aSX, mInfo->cy - aSY - aSH}, + { aSX + aSW, mInfo->cy - aSY } }; + + // Don't bother creating HBITMAPs, just use the pel data to GpiDrawBits + // at all times. This (a) makes printing work 'cos bitmaps are + // device-independent. + // (b) is allegedly more efficient... + // +#if 0 + if( mBitmap == 0 && mOptimized) + { + // moz has asked us to optimize this image, but we haven't got + // round to actually doing it yet. So do it now. + CreateBitmaps( surf); + } +#endif + + if( mAlphaDepth == 0) + { + // no transparency, just blit it + DrawBitmap( surf->mPS, 4, aptl, ROP_SRCCOPY, PR_FALSE); + } + else + { + // from os2fe/cxdc1.cpp: + // > the transparent areas of the pixmap are coloured black. + // > Note this does *not* mean that all black pels are transparent! + // > + // > Thus all we need to do is AND the mask onto the target, taking + // > out pels that are not transparent, and then OR the image onto + // > the target. + // > + // > Note that GPI *ignores* the colour in monochrome bitmaps when + // > blitting, but uses the actual pel values (indices into cmap) + // > to do things with. For 8bpp palette surface, the XP mask is + // > backwards, so we need a custom ROP. + // > + // > There's probably a really good reason why ROP_SRCAND does the + // > right thing in true colour... + + #define ROP_NOTSRCAND 0x22 // NOT(SRC) AND DST + + PRBool aBool; + surf->RequiresInvertedMask( &aBool); + + long lRop = aBool ? ROP_NOTSRCAND : ROP_SRCAND; + + // Apply mask to target, clear pels we will fill in from the image + DrawBitmap( surf->mPS, 4, aptl, lRop, PR_TRUE); + // Now combine image with target + DrawBitmap( surf->mPS, 4, aptl, ROP_SRCPAINT, PR_FALSE); + } + + return NS_OK; +} + +nsresult nsImageOS2::Optimize( nsIDeviceContext* aContext) +{ + // Defer this until we have a PS... + mOptimized = PR_TRUE; + return NS_OK; +} + +// From os2fe/cxdc1.cpp + +static RGB2 rgb2White = { 0xff, 0xff, 0xff, 0 }; +static RGB2 rgb2Black = { 0, 0, 0, 0 }; + +struct MASKBMPINFO +{ + BITMAPINFOHEADER2 bmpInfo; + RGB2 rgbZero; + RGB2 rgbOne; + + operator PBITMAPINFO2 () { return (PBITMAPINFO2) &bmpInfo; } + operator PBITMAPINFOHEADER2 () { return &bmpInfo; } + + MASKBMPINFO( PBITMAPINFO2 pBI) + { + memcpy( &bmpInfo, pBI, sizeof( BITMAPINFOHEADER2)); + bmpInfo.cBitCount = 1; + rgbZero = rgb2Black; + rgbOne = rgb2White; + } +}; + +void nsImageOS2::CreateBitmaps( nsDrawingSurfaceOS2 *surf) +{ + mBitmap = GpiCreateBitmap( surf->mPS, + (PBITMAPINFOHEADER2) mInfo, + CBM_INIT, + (PBYTE) mImageBits, + mInfo); + if( mBitmap == GPI_ERROR) + PMERROR("GpiCreateBitmap"); + + if( mAImageBits) + { + if( mAlphaDepth == 1) + { + MASKBMPINFO maskInfo( mInfo); + mABitmap = GpiCreateBitmap( surf->mPS, + maskInfo, + CBM_INIT, + (PBYTE) mAImageBits, + maskInfo); + if( mABitmap == GPI_ERROR) + PMERROR( "GpiCreateBitmap (mask)"); + } + else + printf( "8 bit alpha mask, no chance...\n"); + } +} + +void nsImageOS2::DrawBitmap( HPS hps, LONG lCount, PPOINTL pPoints, + LONG lRop, PRBool bIsMask) +{ + HBITMAP hBmp = bIsMask ? mABitmap : mBitmap; + +#if 0 + if( hBmp) + { + if( GPI_ERROR == GpiWCBitBlt( hps, hBmp, lCount, pPoints, lRop, BBO_OR)) + PMERROR( "GpiWCBitBlt"); + } + else +#endif + { + MASKBMPINFO *pMaskInfo = 0; + PBITMAPINFO2 pBmp2 = mInfo; + + if( PR_TRUE == bIsMask) + { + pMaskInfo = new MASKBMPINFO( pBmp2); + pBmp2 = *pMaskInfo; + } + + void *pBits = bIsMask ? mAImageBits : mImageBits; + + if( GPI_ERROR == GpiDrawBits( hps, pBits, pBmp2, + lCount, pPoints, lRop, BBO_OR)) + PMERROR( "GpiDrawBits"); + + delete pMaskInfo; + } +} diff --git a/mozilla/gfx/src/os2/nsImageOS2.h b/mozilla/gfx/src/os2/nsImageOS2.h new file mode 100644 index 00000000000..8c66d968824 --- /dev/null +++ b/mozilla/gfx/src/os2/nsImageOS2.h @@ -0,0 +1,88 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsImageOS2_h_ +#define _nsImageOS2_h_ + +#include "nsIImage.h" + +struct nsDrawingSurfaceOS2; + +class nsImageOS2 : public nsIImage +{ + public: + nsImageOS2(); + virtual ~nsImageOS2(); + + NS_DECL_ISUPPORTS + + nsresult Init( PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth, + nsMaskRequirements aMaskRequirements); + PRInt32 GetWidth() { return mInfo ? mInfo->cx : 0; } + PRInt32 GetHeight() { return mInfo ? mInfo->cy : 0; } + PRInt32 GetLineStride() { return mStride; } + PRUint8 *GetBits() { return mImageBits; } + void *GetBitInfo() { return mInfo; } + nsColorMap *GetColorMap() { return mColorMap; } + PRInt32 GetBytesPix() { return mInfo ? mInfo->cBitCount : 0; } + + PRBool GetIsRowOrderTopToBottom() { return PR_FALSE; } + + // These may require more sensible returns... + PRInt32 GetAlphaWidth() { return mInfo ? mInfo->cx : 0; } + PRInt32 GetAlphaHeight() { return mInfo ? mInfo->cy : 0; } + PRInt32 GetAlphaLineStride() { return mAStride; } + PRUint8 *GetAlphaBits() { return mAImageBits; } + + void SetAlphaLevel(PRInt32 aAlphaLevel) {} + PRInt32 GetAlphaLevel() { return 0; } + + nsresult Optimize( nsIDeviceContext* aContext); + PRBool IsOptimized() { return mOptimized; } + + NS_IMETHOD Draw( nsIRenderingContext &aContext, nsDrawingSurface aSurface, + PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight); + NS_IMETHOD Draw( nsIRenderingContext &aContext, nsDrawingSurface aSurface, + PRInt32 aSX, PRInt32 aSY, PRInt32 aSWidth, PRInt32 aSHeight, + PRInt32 aDX, PRInt32 aDY, PRInt32 aDWidth, PRInt32 aDHeight); + + void ImageUpdated( nsIDeviceContext *aContext, + PRUint8 aFlags, nsRect *aUpdateRect); + + private: + BITMAPINFO2 *mInfo; + PRInt32 mStride; + PRInt32 mAStride; + PRUint8 *mImageBits; + PRUint8 *mAImageBits; + nsColorMap *mColorMap; + HBITMAP mBitmap; + HBITMAP mABitmap; + PRBool mOptimized; + PRInt32 mAlphaDepth; + PRUint32 mDeviceDepth; + + void Cleanup(); + void CreateBitmaps( nsDrawingSurfaceOS2 *surf); + void DrawBitmap( HPS hps, LONG cPts, PPOINTL pPts, LONG lRop, PRBool bMsk); +}; + +#endif diff --git a/mozilla/gfx/src/os2/nsPaletteOS2.cpp b/mozilla/gfx/src/os2/nsPaletteOS2.cpp new file mode 100644 index 00000000000..b92bcd02cc2 --- /dev/null +++ b/mozilla/gfx/src/os2/nsPaletteOS2.cpp @@ -0,0 +1,262 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// ToDo: nothing +#include "nsGfxDefs.h" +#include + +#include "nsDeviceContextOS2.h" // sigh... +#include "nsPaletteOS2.h" +#include "il_util.h" + +// os2fe/palette.cpp lives! Sort of. +// +// There's just the one palette, which is shared by all the windows, +// DC's and whatever that get created. +// +// This makes apprunner vaguely usable! +// +// Printing might need some work. + +// Common base +class nsPaletteOS2 : public nsIPaletteOS2 +{ + protected: + nsIDeviceContext *mContext; // don't hold a ref to avoid circularity + PRUint8 *mGammaTable; + + public: + virtual nsresult Init( nsIDeviceContext *aContext, + ULONG * = 0, ULONG = 0) + { + mContext = aContext; + mContext->GetGammaTable( mGammaTable); + return mContext == nsnull ? NS_ERROR_FAILURE : NS_OK; + } + + long GetGPIColor( HPS hps, nscolor rgb) + { + long gcolor = MK_RGB( mGammaTable[NS_GET_R(rgb)], + mGammaTable[NS_GET_G(rgb)], + mGammaTable[NS_GET_B(rgb)]); + return GpiQueryColorIndex( hps, 0, gcolor); + } + + virtual nsresult GetNSPalette( nsPalette &aPalette) const + { + aPalette = 0; + return NS_OK; + } + + NS_DECL_ISUPPORTS + + nsPaletteOS2() + { + NS_INIT_REFCNT(); + mContext = nsnull; + mGammaTable = 0; + } + + virtual ~nsPaletteOS2() + {} +}; + +// this isn't really an xpcom object, so don't allow anyone to get anything +nsresult nsPaletteOS2::QueryInterface( const nsIID&, void**) +{ + return NS_NOINTERFACE; +} + +NS_IMPL_ADDREF(nsPaletteOS2) +NS_IMPL_RELEASE(nsPaletteOS2) + +// Logical colour table, for 8bpp with no palette manager or explicit choice +class nsLCOLPaletteOS2 : public nsPaletteOS2 +{ + ULONG *mTable; + ULONG mSize; + + public: + nsresult Init( nsIDeviceContext *aContext, + ULONG *pEntries, ULONG cEntries) + { + mTable = pEntries; + mSize = cEntries; + return nsPaletteOS2::Init( aContext); + } + + nsresult Select( HPS hps, nsIDeviceContext *) + { + BOOL rc = GpiCreateLogColorTable( hps, LCOL_RESET | LCOL_PURECOLOR, + LCOLF_CONSECRGB, 0, + mSize, (PLONG) mTable); + if( !rc) + PMERROR( "GpiCreateLogColorTable"); + return rc ? NS_OK : NS_ERROR_FAILURE; + } + + nsresult Deselect( HPS hps) + { + BOOL rc = GpiCreateLogColorTable( hps, LCOL_RESET, 0, 0, 0, 0); + return rc ? NS_OK : NS_ERROR_FAILURE; + } + + nsLCOLPaletteOS2() + { + mTable = 0; + mSize = 0; + } + + ~nsLCOLPaletteOS2() + { + if( mTable) free( mTable); + } +}; + +// Palette manager palette, for 8bpp with palette manager +class nsHPALPaletteOS2 : public nsPaletteOS2 +{ + HPAL mHPal; + + public: + nsresult Init( nsIDeviceContext *aContext, + ULONG *pEntries, ULONG cEntries) + { + mHPal = GpiCreatePalette( 0/*hab*/, LCOL_PURECOLOR, LCOLF_CONSECRGB, + cEntries, pEntries); + free( pEntries); + + return nsPaletteOS2::Init( aContext); + } + + nsresult GetNSPalette( nsPalette &aPalette) const + { + aPalette = (nsPalette) mHPal; + return NS_OK; + } + + nsresult Select( HPS hps, nsIDeviceContext *aContext) + { + HPAL rc = GpiSelectPalette( hps, mHPal); + if( rc == (HPAL) PAL_ERROR) + { + PMERROR( "GpiSelectPalette"); + return NS_ERROR_FAILURE; + } + + // okay, we could do with a window here. Unfortunately there's + // no guarantee that this is going to return anything sensible. + nsNativeWidget wdg = ((nsDeviceContextOS2 *) aContext)->mWidget; + if( wdg) + { + ULONG ulDummy = 0; + WinRealizePalette( (HWND)wdg, hps, &ulDummy); + } + return NS_OK; + } + + nsresult Deselect( HPS hps) + { + HPAL rc = GpiSelectPalette( hps, 0); + return rc == ((HPAL)PAL_ERROR) ? NS_ERROR_FAILURE : NS_OK; + } + + nsHPALPaletteOS2() + { + mHPal = 0; + } + + ~nsHPALPaletteOS2() + { + if( mHPal) + GpiDeletePalette( mHPal); + } +}; + +// RGB colour table, for >8bpp +class nsRGBPaletteOS2 : public nsPaletteOS2 +{ + public: + nsresult Select( HPS hps, nsIDeviceContext *) + { + BOOL rc = GpiCreateLogColorTable( hps, LCOL_PURECOLOR, + LCOLF_RGB, 0, 0, 0); + if( !rc) + PMERROR( "GpiCreateLogColorTable #2"); + return rc ? NS_OK : NS_ERROR_FAILURE; + } + + nsresult Deselect( HPS hps) + { + BOOL rc = GpiCreateLogColorTable( hps, LCOL_RESET, 0, 0, 0, 0); + return rc ? NS_OK : NS_ERROR_FAILURE; + } + + nsRGBPaletteOS2() {} + ~nsRGBPaletteOS2() {} +}; + +nsresult NS_CreatePalette( nsIDeviceContext *aContext, nsIPaletteOS2 *&aPalette) +{ + nsresult rc = NS_OK; + IL_ColorSpace *colorSpace = 0; + + nsPaletteOS2 *newPalette = 0; + + rc = aContext->GetILColorSpace( colorSpace); + if( NS_SUCCEEDED(rc)) + { + if( NI_PseudoColor == colorSpace->type) + { + PULONG pPalette = (PULONG) calloc( COLOR_CUBE_SIZE, sizeof( ULONG)); + + // Now set the color cube entries. + for( PRInt32 i = 0; i < COLOR_CUBE_SIZE; i++) + { + IL_RGB *map = colorSpace->cmap.map + i; + pPalette[ i] = MK_RGB( map->red, map->green, map->blue); + } + + // this works, sorta. Should probably tell users, + // or activate via a pref, or something. + if( getenv( "MOZ_USE_LCOL")) + newPalette = new nsLCOLPaletteOS2; + else + newPalette = new nsHPALPaletteOS2; + rc = newPalette->Init( aContext, pPalette, COLOR_CUBE_SIZE); + } + else + { + newPalette = new nsRGBPaletteOS2; + rc = newPalette->Init( aContext); + } + + IL_ReleaseColorSpace( colorSpace); + } + + if( NS_SUCCEEDED(rc)) + { + NS_ADDREF(newPalette); + aPalette = newPalette; + } + + return rc; +} diff --git a/mozilla/gfx/src/os2/nsPaletteOS2.h b/mozilla/gfx/src/os2/nsPaletteOS2.h new file mode 100644 index 00000000000..f3c56339d96 --- /dev/null +++ b/mozilla/gfx/src/os2/nsPaletteOS2.h @@ -0,0 +1,53 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// Manage picking of colours via various GPI methods. +// Created & (hopefully) destroyed by nsDeviceContextOS2; each rendering +// context spun off from that dc holds a ref to it, and uses it to get things +// right. Gamma correction done here too using the dc's table, so don't +// go through gamma before GetGPIColor()'ing. +// +// !! What to do about A-channel ? + +#ifndef _nspaletteos2_h +#define _nspaletteos2_h + +#include "nsIDeviceContext.h" +#include "nscolor.h" + +class nsIDeviceContext; + +class nsIPaletteOS2 : public nsISupports +{ + public: + virtual long GetGPIColor( HPS hps, nscolor rgb) = 0; + virtual nsresult Select( HPS hps, nsIDeviceContext *aContext) = 0; + virtual nsresult Deselect( HPS hps) = 0; + virtual nsresult GetNSPalette( nsPalette &aPalette) const = 0; +}; + +// So yes, this could be an nsDeviceContextOS2 method, but this way is better +// for modularisation. Oh yes. +// Release when done. +nsresult NS_CreatePalette( nsIDeviceContext *aContext, + nsIPaletteOS2 *&aPalette); + +#endif diff --git a/mozilla/gfx/src/os2/nsRegionOS2.cpp b/mozilla/gfx/src/os2/nsRegionOS2.cpp new file mode 100644 index 00000000000..93ea9410854 --- /dev/null +++ b/mozilla/gfx/src/os2/nsRegionOS2.cpp @@ -0,0 +1,356 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// ToDo: nothing +#include "nsGfxDefs.h" +#include +#include + +#include "nsRegionOS2.h" + +// Crazy Region Space +// +// In OS/2, windows & presentation spaces have coord. systems with the +// origin in the bottom left & positive going up. +// +// The rest of mozilla assumes a coord. system with the origin in the +// top left & positive going down. +// +// Thus we have a host of methods to convert between the two when +// drawing into a window, and so on. +// +// Regions are different: when they're defined and operations done on +// them, there's no clue to the intended target. So we need another +// way of defining regions. Do this using something which is very close +// to XP space (actually much closer now we use nsRects instead of XP_Rects) +// which can be envisaged as a reflection in the (XP space) line y = 0 +// +// Hmm, perhaps it would cause less confusion not to mention this at all! + +#define nsRgnPS (gModuleData.hpsScreen) + +nsRegionOS2::nsRegionOS2() +{ + NS_INIT_REFCNT(); + + mRegion = 0; + mRegionType = RGN_NULL; +} + +nsRegionOS2::~nsRegionOS2() +{ + if( mRegion) + if( !GpiDestroyRegion( nsRgnPS, mRegion)) + PMERROR( "GpiDestroyRegion (nsR)"); +} + +NS_IMPL_ISUPPORTS(nsRegionOS2, nsIRegion::GetIID()) + +// Create empty region +nsresult nsRegionOS2::Init() +{ + mRegion = GpiCreateRegion( nsRgnPS, 0, 0); + if( mRegion == RGN_ERROR) + PMERROR("GpiCreateRegion"); + mRegionType = RGN_NULL; + return NS_OK; +} + +// assignment +void nsRegionOS2::SetTo( const nsIRegion &aRegion) +{ + nsRegionOS2 *pRegion = (nsRegionOS2 *) &aRegion; + + mRegionType = GpiCombineRegion( nsRgnPS, mRegion, pRegion->mRegion, + 0, CRGN_COPY); +} + +void nsRegionOS2::SetTo( PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight) +{ + if( 0 == mRegion) + Init(); + + RECTL rcl = { aX, aY, aX + aWidth, aY + aHeight }; // in-ex + + GpiSetRegion( nsRgnPS, mRegion, 1, &rcl); + + mRegionType = (aWidth && aHeight) ? RGN_RECT : RGN_NULL; +} + +// Combine region with something; generic helpers +void nsRegionOS2::combine( long lOp, PRInt32 aX, PRInt32 aY, PRInt32 aW, PRInt32 aH) +{ + RECTL rcl = { aX, aY, aX + aW, aY + aH }; // in-ex + HRGN rgn = GpiCreateRegion( nsRgnPS, 1, &rcl); + if( rgn == RGN_ERROR) + { + PMERROR( "GpiCreateRegion #2 "); + printf( "X Y W H is %d %d %d %d\n", aX, aY, aW, aH); + } + mRegionType = GpiCombineRegion( nsRgnPS, mRegion, mRegion, rgn, lOp); + if( mRegionType == RGN_ERROR) + PMERROR( "GpiCombineRegion #2 "); + if( !GpiDestroyRegion( nsRgnPS, rgn)) + PMERROR( "GpiDestroyRegion (nsR::c)"); +} + +void nsRegionOS2::combine( long lOp, const nsIRegion &aRegion) +{ + nsRegionOS2 *pRegion = (nsRegionOS2 *)&aRegion; + mRegionType = GpiCombineRegion( nsRgnPS, mRegion, mRegion, + pRegion->mRegion, lOp); + if( mRegionType == RGN_ERROR) + PMERROR( "GpiCombineRegion"); +} + +#define DECL_COMBINE(name,token) \ +void nsRegionOS2::name(const nsIRegion &aRegion) \ +{ combine( token, aRegion); } \ + \ +void nsRegionOS2::name( PRInt32 aX, PRInt32 aY, \ + PRInt32 aWidth, PRInt32 aHeight) \ +{ combine( token, aX, aY, aWidth, aHeight); } + +DECL_COMBINE(Intersect,CRGN_AND) +DECL_COMBINE(Union,CRGN_OR) +DECL_COMBINE(Subtract,CRGN_DIFF) + +// misc +PRBool nsRegionOS2::IsEmpty() +{ + return (mRegionType == RGN_NULL) ? PR_TRUE : PR_FALSE; +} + +PRBool nsRegionOS2::IsEqual( const nsIRegion &aRegion) +{ + nsRegionOS2 *pRegion = (nsRegionOS2 *)&aRegion; + + long lrc = GpiEqualRegion( nsRgnPS, mRegion, pRegion->mRegion); + + return lrc == EQRGN_EQUAL ? PR_TRUE : PR_FALSE; +} + +void nsRegionOS2::GetBoundingBox( PRInt32 *aX, PRInt32 *aY, PRInt32 *aWidth, PRInt32 *aHeight) +{ + if( mRegionType != RGN_NULL) + { + RECTL rcl; + if( RGN_ERROR == GpiQueryRegionBox( nsRgnPS, mRegion, &rcl)) + PMERROR( "GpiQueryRegionBox"); + + *aX = rcl.xLeft; + *aY = rcl.yBottom; + *aWidth = rcl.xRight - rcl.xLeft; // in-ex, okay. + *aHeight = rcl.yTop - rcl.yBottom; + } + else + *aX = *aY = *aWidth = *aHeight = 0; +} + +// translate +void nsRegionOS2::Offset( PRInt32 aXOffset, PRInt32 aYOffset) +{ + POINTL ptl = { aXOffset, aYOffset }; + GpiOffsetRegion( nsRgnPS, mRegion, &ptl); +} + +// hittest - precise spec, rect must be completely contained. +PRBool nsRegionOS2::ContainsRect( PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight) +{ + RECTL rcl = { aX, aY, aX + aWidth, aY + aHeight }; // in-ex + long lRC = GpiRectInRegion( nsRgnPS, mRegion, &rcl); + return lRC == RRGN_INSIDE ? PR_TRUE : PR_FALSE; +} + +// Accessor for the CRS region +nsresult nsRegionOS2::GetNativeRegion( void *&aRegion) const +{ + aRegion = (void*) mRegion; + return NS_OK; +} + +// Get the complexity of the region +nsresult nsRegionOS2::GetRegionComplexity( nsRegionComplexity &aComplexity) const +{ + NS_ASSERTION( mRegionType != RGN_ERROR, "Bad region complexity"); + + switch( mRegionType) + { + case RGN_NULL: aComplexity = eRegionComplexity_empty; break; + case RGN_RECT: aComplexity = eRegionComplexity_rect; break; + default: + case RGN_COMPLEX: aComplexity = eRegionComplexity_complex; break; + } + + return NS_OK; +} + +// Code recycled from os2fe/drawable.cpp (the good old days...) +// The beautiful thing about this is that it works both ways: os/2 +// space in, Crazy Region Space out, and vice-versa. +struct CGetRects +{ + PRECTL pRects; + ULONG ulUsed; + ULONG ulGot; + ULONG ulHeight; + + CGetRects( ULONG h) : ulUsed( 0), ulGot( 10), ulHeight( h) + { + pRects = (PRECTL) malloc( 10 * sizeof( RECTL)); + } + + ~CGetRects() { free( pRects); } + + inline void add( RECTL &rectl) // sneaky; might work... + { + if( ulUsed == ulGot) + { + ulGot += 10; + pRects = (PRECTL) realloc( pRects, ulGot * sizeof( RECTL)); + } + pRects[ ulUsed].xLeft = rectl.xLeft; + pRects[ ulUsed].yBottom = ulHeight - rectl.yTop; // This is right. + pRects[ ulUsed].xRight = rectl.xRight; // Trust me. + pRects[ ulUsed].yTop = ulHeight - rectl.yBottom; + ulUsed++; + } +}; + +// Big ugly function to accumulate lists of rectangles. +// All logic is in parameters (as opposed to making a callback per rect) for +// speed reasons (maybe spurious, but...) +static void RealQueryRects( HRGN hrgn, + HPS hps, + nsRegionRectSet **aRects, + CGetRects *aGetRects) +{ + BOOL isRECTL = aRects ? FALSE : TRUE; + + // right, this is far too complicated. What we want is a function to + // query how many rectangles we need before we start... + RECTL rects[ 10]; + RGNRECT rgnRect = { 1, 10, 0, RECTDIR_LFRT_TOPBOT }; + + for( ;;) + { + // get a batch of rectangles + GpiQueryRegionRects( hps, hrgn, 0, &rgnRect, rects); + // call them out + for( PRUint32 i = 0; i < rgnRect.crcReturned; i++) + { + if( isRECTL) + { + aGetRects->add( rects[i]); + } + else + { + // accumulate nsRects in the nsRegionRectSet structure + + // first check for space + if( (*aRects)->mNumRects == (*aRects)->mRectsLen) + { + *aRects = (nsRegionRectSet *) + realloc( *aRects, sizeof( nsRegionRectSet) + + ((*aRects)->mNumRects + 9) * sizeof(nsRegionRect)); + (*aRects)->mRectsLen += 10; +#ifdef DEBUG +// !! If this happens lots, bump up initial allocation + printf( "Allocating more regionrect space...\n"); +#endif + } + + nsRegionRect *theRect = (*aRects)->mRects + (*aRects)->mNumRects; + + theRect->x = rects[i].xLeft; + theRect->y = rects[i].yBottom; + theRect->width = rects[i].xRight - rects[i].xLeft; // in-ex + theRect->height = rects[i].yTop - rects[i].yBottom; + + (*aRects)->mNumRects++; + } + } + // are we done ? + if( rgnRect.crcReturned < rgnRect.crc) break; + + // set up for the next batch + rgnRect.ircStart += 10; + } +} + +#define GetRects_Native(r,p,a) RealQueryRects( r, p, nsnull, a) +#define GetRects_NS(r,p,a) RealQueryRects( r, p, a, nsnull) + +HRGN nsRegionOS2::GetHRGN( PRUint32 ulHeight, HPS hps) +{ + CGetRects getRects( ulHeight); + + GetRects_Native( mRegion, nsRgnPS, &getRects); + + return GpiCreateRegion( hps, getRects.ulUsed, getRects.pRects); +} + +// For copying from an existing region who has height & possibly diff. hdc +nsresult nsRegionOS2::Init( HRGN copy, PRUint32 ulHeight, HPS hps) +{ + CGetRects getRects( ulHeight); + + GetRects_Native( copy, hps, &getRects); + + Init(); + + mRegionType = GpiSetRegion( nsRgnPS, mRegion, + getRects.ulUsed, getRects.pRects); + return NS_OK; +} + +// Get the region as an array of rects for the new compositor +nsresult nsRegionOS2::GetRects( nsRegionRectSet **aRects) +{ + if( !aRects) + return NS_ERROR_NULL_POINTER; + + if( *aRects == nsnull) + { + *aRects = (nsRegionRectSet *) malloc( sizeof( nsRegionRectSet) + + 9 * sizeof( nsRegionRect)); + (*aRects)->mNumRects = 0; + (*aRects)->mRectsLen = 10; + } + else + { + // Can reuse the structures (says the header). + // That's quite sensible, actually. + (*aRects)->mNumRects = 0; + } + + GetRects_NS( mRegion, nsRgnPS, aRects); + + return NS_OK; +} + +nsresult nsRegionOS2::FreeRects( nsRegionRectSet *aRects) +{ + if( !aRects) + return NS_ERROR_NULL_POINTER; + free( aRects); + return NS_OK; +} diff --git a/mozilla/gfx/src/os2/nsRegionOS2.h b/mozilla/gfx/src/os2/nsRegionOS2.h new file mode 100644 index 00000000000..8351a832b20 --- /dev/null +++ b/mozilla/gfx/src/os2/nsRegionOS2.h @@ -0,0 +1,78 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// Region object. From os2fe\regions.cpp. +// Regions are defined in Crazy Region Space - see nsRegionOS2.cpp. + +#ifndef _nsRegionOS2_h +#define _nsRegionOS2_h + +#include "nsIRegion.h" + +typedef void (*nsRECTLInRegionFunc)(void *closure, RECTL &rectl); + +class nsRegionOS2 : public nsIRegion +{ + public: + nsRegionOS2(); + virtual ~nsRegionOS2(); + + NS_DECL_ISUPPORTS + + NS_IMETHOD Init(); + + virtual void SetTo( const nsIRegion &aRegion); + virtual void SetTo( PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight); + virtual void Intersect( const nsIRegion &aRegion); + virtual void Intersect( PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight); + virtual void Union( const nsIRegion &aRegion); + virtual void Union( PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight); + virtual void Subtract( const nsIRegion &aRegion); + virtual void Subtract( PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight); + virtual PRBool IsEmpty(); + virtual PRBool IsEqual( const nsIRegion &aRegion); + virtual void GetBoundingBox( PRInt32 *aX, PRInt32 *aY, PRInt32 *aWidth, PRInt32 *aHeight); + virtual void Offset( PRInt32 aXOffset, PRInt32 aYOffset); + virtual PRBool ContainsRect( PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight); + + NS_IMETHOD GetRects( nsRegionRectSet **aRects); + NS_IMETHOD FreeRects( nsRegionRectSet *aRects); + + // Don't use this -- it returns a region defined in CRS. + NS_IMETHOD GetNativeRegion( void *&aRegion) const; + NS_IMETHOD GetRegionComplexity( nsRegionComplexity &aComplexity) const; + + // OS/2 specific + // get region in widget's coord space for given device + HRGN GetHRGN( PRUint32 ulHeight, HPS hps); + + // copy from another region defined in aWidget's space for a given device + nsresult Init( HRGN copy, PRUint32 ulHeight, HPS hps); + + private: + void combine( long lOp, PRInt32 aX, PRInt32 aY, PRInt32 aW, PRInt32 aH); + void combine( long lOp, const nsIRegion &aRegion); + + HRGN mRegion; + long mRegionType; +}; + +#endif diff --git a/mozilla/gfx/src/os2/nsRenderingContextOS2.cpp b/mozilla/gfx/src/os2/nsRenderingContextOS2.cpp new file mode 100644 index 00000000000..d34bce6fddf --- /dev/null +++ b/mozilla/gfx/src/os2/nsRenderingContextOS2.cpp @@ -0,0 +1,1460 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +//#define PROFILE_GSTATE // be noisy about graphicsstate-usage +#define GSTATE_CACHESIZE 50 + +// ToDo: Unicode text draw-er +#include "nsGfxDefs.h" + +#include "nsRenderingContextOS2.h" +#include "nsIComponentManager.h" +#include "nsDeviceContextOS2.h" +#include "nsFontMetricsOS2.h" +#include "nsIFontMetrics.h" +#include "nsTransform2D.h" +#include "nsPaletteOS2.h" +#include "nsRegionOS2.h" +#include "nsGfxCIID.h" +#include "nsString.h" +#include "nsFont.h" +#include "libimg.h" +#include "prprf.h" + +#include "nsIScriptGlobalObject.h" + +// helper clip region functions - defined at the bottom of this file. +LONG GpiCombineClipRegion( HPS hps, HRGN hrgnCombine, LONG lOp); +HRGN GpiCopyClipRegion( HPS hps); +#define GpiDestroyClipRegion(hps) GpiCombineClipRegion(hps, 0, CRGN_COPY) +#define GpiSetClipRegion2(hps,hrgn) GpiCombineClipRegion(hps, hrgn, CRGN_COPY) + +// Use these instead of native GpiSave/RestorePS because: need to store ---- +// more information, and need to be able to push from onscreen & pop onto +// offscreen. Potentially. +struct GraphicsState +{ + GraphicsState() { Construct(); } + ~GraphicsState() { Destruct(); } + + void Construct(); + void Destruct(); + + nsTransform2D mMatrix; + HRGN mClipRegion; + nscolor mColor; + nsIFontMetrics *mFontMetrics; + nsLineStyle mLineStyle; + + GraphicsState *mNext; +}; + +void GraphicsState::Construct() +{ + mClipRegion = 0; + mColor = NS_RGB( 0, 0, 0); + mFontMetrics = nsnull; + mLineStyle = nsLineStyle_kSolid; + mNext = nsnull; +} + +void GraphicsState::Destruct() +{ + if( mClipRegion) + { + printf( "oops, leaked a region from rc-gs\n"); + mClipRegion = 0; + } + NS_IF_RELEASE( mFontMetrics); +} + +class GraphicsStateCache +{ + GraphicsState *mFirst; + UINT mSize; +#ifdef PROFILE_GSTATE + UINT mDeleted; + UINT mCount; + UINT mPeak; +#endif + + public: + GraphicsStateCache() : mFirst(nsnull), mSize(0) +#ifdef PROFILE_GSTATE + , mDeleted(0), mCount(0), mPeak(0) +#endif + {} + + ~GraphicsStateCache() + { +#ifdef PROFILE_GSTATE + printf( "---- Graphics-State Stats -----\n"); + printf( " GStates requested: %d\n", mCount); + printf( " Actual GStates created: %d\n", mPeak); + double d = mCount ? (double)(mCount - mPeak) / (double)mCount : 0; + printf( " Gstates recycled: %d (%d%%)\n", mCount - mPeak, (int)(d*100.0)); + UINT i = mSize+mDeleted; + printf( " Cached+Deleted: %d\n", i); + if( i != mPeak) + printf( " WARNING: GStates leaked: %d\n", mPeak - i); + printf( "------------------------------\n\n"); +#endif + + // Clear up the cache + GraphicsState *pTemp, *pNext = mFirst; + while( pNext) + { + pTemp = pNext->mNext; + delete pNext; + pNext = pTemp; + } + } + + GraphicsState *NewState() + { + GraphicsState *state = nsnull; + if( mFirst) + { + state = mFirst; + mFirst = mFirst->mNext; + state->Construct(); + mSize--; + } + else + { + state = new GraphicsState; +#ifdef PROFILE_GSTATE + mPeak++; +#endif + } +#ifdef PROFILE_GSTATE + mCount++; +#endif + return state; + } + + void DisposeState( GraphicsState *aState) + { + if( GSTATE_CACHESIZE == mSize) + { + delete aState; +#ifdef PROFILE_GSTATE + mDeleted++; +#endif + } + else + { + aState->Destruct(); + aState->mNext = mFirst; + mFirst = aState; + mSize++; + } + } + +} GStateCache; // XXX make this less static, I suppose + +// Rendering context ------------------------------------------------------- +static NS_DEFINE_IID(kIDOMRenderingContextIID, NS_IDOMRENDERINGCONTEXT_IID); + +NS_IMPL_ADDREF(nsRenderingContextOS2) +NS_IMPL_RELEASE(nsRenderingContextOS2) + +nsresult +nsRenderingContextOS2::QueryInterface( REFNSIID aIID, void **aInstancePtr) +{ + if( !aInstancePtr) + return NS_ERROR_NULL_POINTER; + + if( aIID.Equals( nsIRenderingContext::GetIID())) + *aInstancePtr = (void *) (nsIRenderingContext*) this; + else if( aIID.Equals( nsIScriptObjectOwner::GetIID())) + *aInstancePtr = (void *) (nsIScriptObjectOwner*) this; + else if( aIID.Equals( kIDOMRenderingContextIID)) + *aInstancePtr = (void *) (nsIDOMRenderingContext*) this; + else if( aIID.Equals( ((nsISupports*)(nsIRenderingContext*)this)->GetIID())) + *aInstancePtr = (void *) (nsISupports*)(nsIRenderingContext*)this; + + if( !*aInstancePtr) + return NS_NOINTERFACE; + + NS_ADDREF_THIS(); + + return NS_OK; +} + +// Init-term stuff --------------------------------------------------------- + +nsRenderingContextOS2::nsRenderingContextOS2() +{ + NS_INIT_REFCNT(); + + mContext = nsnull; + mPalette = nsnull; + mSurface = nsnull; + mFrontSurface = nsnull; + mScriptObject = nsnull; + mColor = NS_RGB( 0, 0, 0); + mP2T = 1.0f; + mStateStack = nsnull; + mFontMetrics = nsnull; + mCurrFontMetrics = nsnull; + mCurrDrawingColor = NS_RGB( 0, 0, 0); + mCurrTextColor = NS_RGB( 0, 0, 0); + mLineStyle = nsLineStyle_kSolid; + mCurrLineStyle = nsLineStyle_kSolid; + + // Other impls want to do a PushState() here. I can't see why... + // PushState(); +} + +nsRenderingContextOS2::~nsRenderingContextOS2() +{ + NS_IF_RELEASE(mContext); + + // clear state stack + GraphicsState *pTemp, *pNext = mStateStack; + while( pNext) + { + if( pNext->mClipRegion) + { + if( !GpiDestroyRegion( mSurface->mPS, pNext->mClipRegion)) + PMERROR( "GpiDestroyRegion (~RC)"); + pNext->mClipRegion = 0; + } + pTemp = pNext->mNext; + GStateCache.DisposeState( pNext); + pNext = pTemp; + } + + // Release surfaces and the palette + NS_IF_RELEASE(mFrontSurface); + NS_IF_RELEASE(mSurface); + NS_IF_RELEASE(mPalette); + NS_IF_RELEASE(mFontMetrics); +} + +// I've NS_ADDREF'd as opposed to NS_IF_ADDREF'd 'cos if certain things +// are null, then we want to know about it straight away. +// References rule, sigh. +nsresult nsRenderingContextOS2::Init( nsIDeviceContext *aContext, + nsIWidget *aWindow) +{ + mContext = aContext; + NS_ADDREF(mContext); + + // Create & remember an on-screen surface + nsWindowSurface *surf = new nsWindowSurface; + surf->Init(aWindow); + + mSurface = surf; + NS_ADDREF(mSurface); + + // Grab another reference to the onscreen for later uniformity + mFrontSurface = mSurface; + NS_ADDREF(mFrontSurface); + + return CommonInit(); +} + +nsresult nsRenderingContextOS2::Init( nsIDeviceContext *aContext, + nsDrawingSurface aSurface) +{ + mContext = aContext; + NS_IF_ADDREF(mContext); + + // Add a couple of references to the onscreen (or print, more likely) + mSurface = (nsDrawingSurfaceOS2 *) aSurface; + NS_ADDREF(mSurface); + mFrontSurface = mSurface; + NS_ADDREF(mFrontSurface); + + return CommonInit(); +} + +// Presentation space page units (& so world coords) are PU_PELS. +// We have a matrix, mTMatrix, which converts from the passed in app units +// to pels. Note there is *no* guarantee that app units == twips. +nsresult nsRenderingContextOS2::CommonInit() +{ + float app2dev = 0; + mContext->GetAppUnitsToDevUnits( app2dev); + mTMatrix.AddScale( app2dev, app2dev); + mContext->GetDevUnitsToAppUnits( mP2T); + + ((nsDeviceContextOS2 *) mContext)->GetPalette( mPalette); + + mPalette->Select( mSurface->mPS, mContext); + mSurface->SetPalette( mPalette); + return NS_OK; +} + +// PS & drawing surface management ----------------------------------------- + +nsresult nsRenderingContextOS2::SelectOffScreenDrawingSurface( nsDrawingSurface aSurface) +{ + nsresult rc = NS_ERROR_FAILURE; + + if( aSurface) + { + NS_IF_RELEASE(mSurface); + mSurface = (nsDrawingSurfaceOS2 *) aSurface; + mPalette->Select( mSurface->mPS, mContext); + mSurface->SetPalette( mPalette); + } + else // deselect current offscreen... + { + NS_IF_RELEASE(mSurface); + mSurface = mFrontSurface; + rc = NS_OK; + } + + // need to force a state refresh because the offscreen is something of + // an unknown quantity. + SetupDrawingColor( TRUE); + SetupFontAndColor( TRUE); + + // Flush the offscreen's font cache because it's being associated with + // a new onscreen. +// +// Actually I don't think this is necessary. +// +// mSurface->FlushFontCache(); +// + + NS_ADDREF(mSurface); + + return rc; +} + +// !! This is a bit dodgy; nsDrawingSurface *really* needs to be XP-comified +// !! properly... +nsresult nsRenderingContextOS2::GetDrawingSurface( nsDrawingSurface *aSurface) +{ + if( !aSurface) + return NS_ERROR_NULL_POINTER; + +#if 0 + NS_IF_RELEASE( *aSurface); +#endif + + *aSurface = (void*)((nsDrawingSurfaceOS2 *) mSurface); + // !! probably don't want to addref this 'cos client can't release it... + + return NS_OK; +} + +// The idea here is to create an offscreen surface for blitting with. +// I can't find any way for people to resize the bitmap created here, +// so I guess this gets called quite often. +// +// I'm reliably told that 'aBounds' is in device units, and that the +// position oughtn't to be ignored, but for all intents & purposes can be. +// +nsresult nsRenderingContextOS2::CreateDrawingSurface( nsRect *aBounds, + PRUint32 aSurfFlags, nsDrawingSurface &aSurface) +{ + // We're gonna ignore this `aSurfFlags' due to not understanding it... + + nsresult rc = NS_ERROR_FAILURE; + + nsOffscreenSurface *surf = new nsOffscreenSurface; + + rc = surf->Init( mFrontSurface->mPS, aBounds->width, aBounds->height); + + if(NS_SUCCEEDED(rc)) + { + NS_ADDREF(surf); + aSurface = (void*)((nsDrawingSurfaceOS2 *) surf); + } + else + delete surf; + + return rc; +} + +nsresult nsRenderingContextOS2::DestroyDrawingSurface( nsDrawingSurface aDS) +{ + nsDrawingSurfaceOS2 *surf = (nsDrawingSurfaceOS2 *) aDS; + nsresult rc = NS_ERROR_NULL_POINTER; + + // If the surface being destroyed is the one we're currently using for + // offscreen, then lose our reference to it & hook back to the onscreen. + if( surf && surf == mSurface) + { + NS_RELEASE(mSurface); // ref. from SelectOffscreen + mSurface = mFrontSurface; + NS_ADDREF(mSurface); + } + + if( surf) + { + NS_RELEASE(surf); // ref. from CreateSurface + rc = NS_OK; + } + + return rc; +} + +#if 0 // now inlined in the header +void nsRenderingContextOS2::GetTargetHeight( PRUint32 &ht) +{ + PRUint32 on, dummy, off; + mSurface->GetDimensions( &dummy, &on); + if( mSurface != mFrontSurface) + { + mFrontSurface->GetDimensions( &dummy, &off); + if( off < on) on = off; + } + ht = on; +} +#endif + +nsresult nsRenderingContextOS2::LockDrawingSurface( PRInt32 aX, PRInt32 aY, + PRUint32 aWidth, PRUint32 aHeight, + void **aBits, + PRInt32 *aStride, PRInt32 *aWidthBytes, + PRUint32 aFlags) +{ + return mSurface->Lock( aX, aY, aWidth, aHeight, aBits, + aStride, aWidthBytes, aFlags); +} + +nsresult nsRenderingContextOS2::UnlockDrawingSurface() +{ + return mSurface->Unlock(); +} + +// State stack ------------------------------------------------------------- +nsresult nsRenderingContextOS2::PushState() +{ + GraphicsState *state = GStateCache.NewState(); + + // copy matrix into state + state->mMatrix.SetMatrix( &mTMatrix); + // copy color & font + state->mColor = mColor; + state->mFontMetrics = mFontMetrics; + state->mLineStyle = mLineStyle; + + // add a new ref to the fontmetrics + NS_IF_ADDREF( mFontMetrics); + + // clip region: get current & copy it. + state->mClipRegion = GpiCopyClipRegion( mSurface->mPS); + + // push state onto stack + state->mNext = mStateStack; + mStateStack = state; + return NS_OK; +} + +// RC here is true if clip region is now empty. +nsresult nsRenderingContextOS2::PopState( PRBool &aClipEmpty) +{ + PRBool rc = PR_TRUE; + + NS_ASSERTION( mStateStack, "state underflow"); + if( !mStateStack) return NS_ERROR_FAILURE; + + GraphicsState *state = mStateStack; + mStateStack = state->mNext; + + // update xform matrix + mTMatrix.SetMatrix( &state->mMatrix); + + // color & font + SetColor( state->mColor); + SetLineStyle( state->mLineStyle); + NS_IF_RELEASE(mFontMetrics); + mFontMetrics = state->mFontMetrics; + state->mFontMetrics = nsnull; + + // Clip region + GpiSetClipRegion2( mSurface->mPS, state->mClipRegion); + if( state->mClipRegion != 0) + { + state->mClipRegion = 0; + rc = PR_FALSE; + } + + GStateCache.DisposeState( state); + + aClipEmpty = rc; + + return NS_OK; +} + +nsresult nsRenderingContextOS2::Reset() +{ + // okay, what's this supposed to do? Empty the state stack? + printf( "nsRenderingContext::Reset() -- hmm\n"); + return NS_OK; +} + +// OS/2 - XP coord conversion ---------------------------------------------- + +// get inclusive-inclusive rect +void nsRenderingContextOS2::NS2PM_ININ( const nsRect &in, RECTL &rcl) +{ + PRUint32 ulHeight; + GetTargetHeight( ulHeight); + + rcl.xLeft = in.x; + rcl.xRight = in.x + in.width - 1; + rcl.yTop = ulHeight - in.y - 1; + rcl.yBottom = rcl.yTop - in.height + 1; +} + +void nsRenderingContextOS2::PM2NS_ININ( const RECTL &in, nsRect &out) +{ + PRUint32 ulHeight; + GetTargetHeight( ulHeight); + + out.x = in.xLeft; + out.width = in.xRight - in.xLeft + 1; + out.y = ulHeight - in.yTop - 1; + out.height = in.yTop - in.yBottom + 1; +} + +// get in-ex rect +void nsRenderingContextOS2::NS2PM_INEX( const nsRect &in, RECTL &rcl) +{ + NS2PM_ININ( in, rcl); + rcl.xRight++; + rcl.yTop++; +} + +void nsRenderingContextOS2::NS2PM( PPOINTL aPointl, ULONG cPointls) +{ + PRUint32 ulHeight; + GetTargetHeight( ulHeight); + + for( ULONG i = 0; i < cPointls; i++) + aPointl[ i].y = ulHeight - aPointl[ i].y - 1; +} + +// Clip region management -------------------------------------------------- + +nsresult nsRenderingContextOS2::IsVisibleRect( const nsRect &aRect, + PRBool &aIsVisible) +{ + nsRect trect( aRect); + mTMatrix.TransformCoord( &trect.x, &trect.y, + &trect.width, &trect.height); + RECTL rcl; + NS2PM_ININ( trect, rcl); + + long rc = GpiRectVisible( mSurface->mPS, &rcl); + + aIsVisible = (rc == RVIS_PARTIAL || rc == RVIS_VISIBLE) ? PR_TRUE : PR_FALSE; + + + return NS_OK; +} + +// Return PR_TRUE if clip region is now empty +nsresult nsRenderingContextOS2::SetClipRect( const nsRect& aRect, nsClipCombine aCombine, PRBool &aClipEmpty) +{ + nsRect trect = aRect; + mTMatrix.TransformCoord( &trect.x, &trect.y, + &trect.width, &trect.height); + RECTL rcl; + long lrc = RGN_ERROR; + + switch( aCombine) + { + case nsClipCombine_kIntersect: + case nsClipCombine_kSubtract: + NS2PM_ININ( trect, rcl); + if( aCombine == nsClipCombine_kIntersect) + lrc = GpiIntersectClipRectangle( mSurface->mPS, &rcl); + else + lrc = GpiExcludeClipRectangle( mSurface->mPS, &rcl); + break; + + case nsClipCombine_kUnion: + case nsClipCombine_kReplace: + { + // need to create a new region & fiddle with it + NS2PM_INEX( trect, rcl); + HRGN hrgn = GpiCreateRegion( mSurface->mPS, 1, &rcl); + if( hrgn && aCombine == nsClipCombine_kReplace) + lrc = GpiSetClipRegion2( mSurface->mPS, hrgn); + else if( hrgn) + lrc = GpiCombineClipRegion( mSurface->mPS, hrgn, CRGN_OR); + break; + } + default: + // compiler informational... + NS_ASSERTION( 0, "illegal clip combination"); + break; + } + + aClipEmpty = (lrc == RGN_NULL) ? PR_TRUE : PR_FALSE; + + return NS_OK; +} + +// rc is whether there is a cliprect to return +// !! Potential problems here: I think we ought to return the rect +// !! transformed by the inverse of our xformation matrix. Which, +// !! frankly, I can't be bothered to write the code for - it ought +// !! to be a method in nsTransform2D. +nsresult nsRenderingContextOS2::GetClipRect( nsRect &aRect, PRBool &aHasLocalClip) +{ + RECTL rcl; + long rc = GpiQueryClipBox( mSurface->mPS, &rcl); + PRBool brc = PR_FALSE; + + if( rc != RGN_NULL && rc != RGN_ERROR) + { + PM2NS_ININ( rcl, aRect); + brc = PR_TRUE; + } + + aHasLocalClip = brc; + + return NS_OK; +} + +// Return PR_TRUE if clip region is now empty +nsresult nsRenderingContextOS2::SetClipRegion( const nsIRegion &aRegion, nsClipCombine aCombine, PRBool &aClipEmpty) +{ + nsRegionOS2 *pRegion = (nsRegionOS2 *) &aRegion; + PRUint32 ulHeight; + + GetTargetHeight( ulHeight); + + HRGN hrgn = pRegion->GetHRGN( ulHeight, mSurface->mPS); + long cmode = 0; + + switch( aCombine) + { + case nsClipCombine_kIntersect: + cmode = CRGN_AND; + break; + case nsClipCombine_kUnion: + cmode = CRGN_OR; + break; + case nsClipCombine_kSubtract: + cmode = CRGN_DIFF; + break; + case nsClipCombine_kReplace: + cmode = CRGN_COPY; + break; + default: + // Compiler informational... + NS_ASSERTION( 0, "illegal clip combination"); + break; + } + + long lrc = GpiCombineClipRegion( mSurface->mPS, hrgn, cmode); + + aClipEmpty = (lrc == RGN_NULL) ? PR_TRUE : PR_FALSE; + + return NS_OK; +} + +// Somewhat dubious & rather expensive +nsresult nsRenderingContextOS2::GetClipRegion( nsIRegion **aRegion) +{ + if( !aRegion) + return NS_ERROR_NULL_POINTER; + + *aRegion = 0; + + nsRegionOS2 *pRegion = new nsRegionOS2; + NS_ADDREF(pRegion); + + // Get current clip region + HRGN hrgnClip = 0; + + GpiSetClipRegion( mSurface->mPS, 0, &hrgnClip); + if( hrgnClip && hrgnClip != HRGN_ERROR) + { + // There was a clip region, so get it & init. + HRGN hrgnDummy = 0; + PRUint32 ulHeight; + GetTargetHeight( ulHeight); + pRegion->Init( hrgnClip, ulHeight, mSurface->mPS); + GpiSetClipRegion( mSurface->mPS, hrgnClip, &hrgnDummy); + } + else + pRegion->Init(); + + *aRegion = pRegion; + + return NS_OK; +} + +// Setters & getters ------------------------------------------------------- + +nsresult nsRenderingContextOS2::GetDeviceContext( nsIDeviceContext *&aDeviceContext) +{ +// NS_IF_RELEASE(aDeviceContext); + aDeviceContext = mContext; + NS_IF_ADDREF( mContext); + return NS_OK; +} + +nsresult nsRenderingContextOS2::SetColor( nscolor aColor) +{ + mColor = aColor; + return NS_OK; +} + +nsresult nsRenderingContextOS2::GetColor( nscolor &aColor) const +{ + aColor = mColor; + return NS_OK; +} + +nsresult nsRenderingContextOS2::SetLineStyle( nsLineStyle aLineStyle) +{ + mLineStyle = aLineStyle; + return NS_OK; +} + +nsresult nsRenderingContextOS2::GetLineStyle( nsLineStyle &aLineStyle) +{ + aLineStyle = mLineStyle; + return NS_OK; +} + +nsresult nsRenderingContextOS2::SetFont( const nsFont &aFont) +{ + NS_IF_RELEASE( mFontMetrics); + mContext->GetMetricsFor( aFont, mFontMetrics); + return NS_OK; +} + +nsresult nsRenderingContextOS2::SetFont( nsIFontMetrics *aFontMetrics) +{ + NS_IF_RELEASE( mFontMetrics); + mFontMetrics = aFontMetrics; + NS_IF_ADDREF( mFontMetrics); + return NS_OK; +} + +nsresult nsRenderingContextOS2::GetFontMetrics( nsIFontMetrics*& aFontMetrics) +{ +// Commented out because clients misuse the interface. +// +// NS_IF_RELEASE(aFontMetrics); + aFontMetrics = mFontMetrics; + NS_IF_ADDREF( mFontMetrics); + return NS_OK; +} + +// add the passed in translation to the current translation +nsresult nsRenderingContextOS2::Translate( nscoord aX, nscoord aY) +{ + mTMatrix.AddTranslation( (float) aX, (float) aY); + return NS_OK; +} + +// add the passed in scale to the current scale +nsresult nsRenderingContextOS2::Scale( float aSx, float aSy) +{ + mTMatrix.AddScale(aSx, aSy); + return NS_OK; +} + +nsresult nsRenderingContextOS2::GetCurrentTransform( nsTransform2D *&aTransform) +{ + NS_PRECONDITION(aTransform,"Null transform ptr"); + if( !aTransform) + return NS_ERROR_NULL_POINTER; + aTransform->SetMatrix( &mTMatrix); + return NS_OK; +} + +// this is voodoo... +NS_IMETHODIMP +nsRenderingContextOS2::GetScriptObject( nsIScriptContext* aContext, + void** aScriptObject) +{ + nsresult res = NS_OK; + nsIScriptGlobalObject *global = aContext->GetGlobalObject(); + + if( !mScriptObject) + { + res = NS_NewScriptRenderingContext( aContext, + (nsISupports *)(nsIRenderingContext*)this, + global, (void**)&mScriptObject); + } + *aScriptObject = mScriptObject; + NS_RELEASE(global); + return res; +} + +NS_IMETHODIMP +nsRenderingContextOS2::SetScriptObject(void* aScriptObject) +{ + mScriptObject = aScriptObject; + return NS_OK; +} + +// More daft nsIDOMRenderingContext methods +NS_IMETHODIMP nsRenderingContextOS2::GetColor( nsString &aColor) +{ + char cbuf[40]; + PR_snprintf( cbuf, sizeof(cbuf), "#%02x%02x%02x", + NS_GET_R(mColor), + NS_GET_G(mColor), + NS_GET_B(mColor)); + aColor = cbuf; + return NS_OK; +} + +NS_IMETHODIMP nsRenderingContextOS2::SetColor(const nsString& aColor) +{ + nscolor rgb; + char cbuf[40]; + + aColor.ToCString( cbuf, sizeof(cbuf)); + if( NS_ColorNameToRGB( cbuf, &rgb)) + SetColor(rgb); + else if( NS_HexToRGB( cbuf, &rgb)) + SetColor(rgb); + + return NS_OK; +} + +// Drawing methods --------------------------------------------------------- + +// !! this method could do with a rename... +void nsRenderingContextOS2::SetupDrawingColor( BOOL bForce) +{ + if( bForce || mColor != mCurrDrawingColor) + { + long lColor = mPalette->GetGPIColor( mSurface->mPS, mColor); + GpiSetAttrs( mSurface->mPS, PRIM_LINE, LBB_COLOR, 0, &lColor); + GpiSetAttrs( mSurface->mPS, PRIM_AREA, ABB_COLOR, 0, &lColor); + mCurrDrawingColor = mColor; + } + + if( bForce || mLineStyle != mCurrLineStyle) + { + long ltype = 0; + switch( mLineStyle) + { + case nsLineStyle_kNone: ltype = LINETYPE_INVISIBLE; break; + case nsLineStyle_kSolid: ltype = LINETYPE_SOLID; break; + case nsLineStyle_kDashed: ltype = LINETYPE_SHORTDASH; break; + case nsLineStyle_kDotted: ltype = LINETYPE_DOT; break; + default: + NS_ASSERTION(0, "Unexpected line style"); + break; + } + GpiSetLineType( mSurface->mPS, ltype); + mCurrLineStyle = mLineStyle; + } +} + +void nsRenderingContextOS2::SetupFontAndColor( BOOL bForce) +{ + if( bForce || mFontMetrics != mCurrFontMetrics) + { + // select font + mCurrFontMetrics = mFontMetrics; + if( mCurrFontMetrics) + mSurface->SelectFont( mCurrFontMetrics); + } + + if( bForce || mColor != mCurrTextColor) + { + long lColor = mPalette->GetGPIColor( mSurface->mPS, mColor); + GpiSetAttrs( mSurface->mPS, PRIM_CHAR, CBB_COLOR, 0, &lColor); + mCurrTextColor = mColor; + } +} + +nsresult nsRenderingContextOS2::DrawLine( nscoord aX0, nscoord aY0, nscoord aX1, nscoord aY1) +{ + mTMatrix.TransformCoord( &aX0, &aY0); + mTMatrix.TransformCoord( &aX1, &aY1); + + POINTL ptls[] = { { (long) aX0, (long) aY0 }, + { (long) aX1, (long) aY1 } }; + NS2PM( ptls, 2); + + SetupDrawingColor(); + + GpiMove( mSurface->mPS, ptls); + GpiLine( mSurface->mPS, ptls + 1); + return NS_OK; +} + +// Stupid DOM method +nsresult nsRenderingContextOS2::DrawLine2( PRInt32 aX0, PRInt32 aY0, + PRInt32 aX1, PRInt32 aY1) +{ + DrawLine(aX0, aY0, aX1, aY1); + return NS_OK; +} + +nsresult nsRenderingContextOS2::DrawPolyline(const nsPoint aPoints[], PRInt32 aNumPoints) +{ + PMDrawPoly( aPoints, aNumPoints, PR_FALSE); + return NS_OK; +} + +nsresult nsRenderingContextOS2::DrawPolygon( const nsPoint aPoints[], PRInt32 aNumPoints) +{ + PMDrawPoly( aPoints, aNumPoints, PR_FALSE); + return NS_OK; +} + +nsresult nsRenderingContextOS2::FillPolygon( const nsPoint aPoints[], PRInt32 aNumPoints) +{ + PMDrawPoly( aPoints, aNumPoints, PR_TRUE); + return NS_OK; +} + +void nsRenderingContextOS2::PMDrawPoly( const nsPoint aPoints[], PRInt32 aNumPoints, PRBool bFilled) +{ + if( aNumPoints > 1) + { + // Xform coords + POINTL aptls[ 20]; + PPOINTL pts = aptls; + + if( aNumPoints > 20) + pts = new POINTL [ aNumPoints]; + + PPOINTL pp = pts; + const nsPoint *np = &aPoints[0]; + + for( PRInt32 i = 0; i < aNumPoints; i++, pp++, np++) + { + pp->x = np->x; + pp->y = np->y; + mTMatrix.TransformCoord( (int*)&pp->x, (int*)&pp->y); + } + + // go to os2 + NS2PM( pts, aNumPoints); + + SetupDrawingColor(); + + // We draw closed pgons using polyline to avoid filling it. This works + // because the API to this class specifies that the last point must + // be the same as the first one... + + GpiMove( mSurface->mPS, pts); + + if( bFilled == PR_TRUE) + { + POLYGON pgon = { aNumPoints - 1, pts + 1 }; + GpiPolygons( mSurface->mPS, 1, &pgon, + POLYGON_BOUNDARY, POLYGON_INCL); + } + else + { + GpiPolyLine( mSurface->mPS, aNumPoints - 1, pts + 1); + } + + if( aNumPoints > 20) + delete [] pts; + } +} + +nsresult nsRenderingContextOS2::DrawRect( const nsRect& aRect) +{ + nsRect tr = aRect; + PMDrawRect( tr, FALSE); + return NS_OK; +} + +nsresult nsRenderingContextOS2::DrawRect( nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) +{ + nsRect tr( aX, aY, aWidth, aHeight); + PMDrawRect( tr, FALSE); + return NS_OK; +} + +nsresult nsRenderingContextOS2::FillRect( const nsRect& aRect) +{ + nsRect tr = aRect; + PMDrawRect( tr, TRUE); + return NS_OK; +} + +nsresult nsRenderingContextOS2::FillRect( nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) +{ + nsRect tr( aX, aY, aWidth, aHeight); + PMDrawRect( tr, TRUE); + return NS_OK; +} + +void nsRenderingContextOS2::PMDrawRect( nsRect &rect, BOOL fill) +{ + mTMatrix.TransformCoord( &rect.x, &rect.y, &rect.width, &rect.height); + + RECTL rcl; + NS2PM_ININ( rect, rcl); + + SetupDrawingColor(); + + long lOps = DRO_OUTLINE; + if( fill) + lOps |= DRO_FILL; + + GpiMove( mSurface->mPS, (PPOINTL) &rcl); + GpiBox( mSurface->mPS, lOps, ((PPOINTL)&rcl) + 1, 0, 0); +} + +// Arc-drawing methods, all proxy on to PMDrawArc +nsresult nsRenderingContextOS2::DrawEllipse( const nsRect& aRect) +{ + nsRect tRect( aRect); + PMDrawArc( tRect, PR_FALSE, PR_TRUE); + return NS_OK; +} + +nsresult nsRenderingContextOS2::DrawEllipse( nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) +{ + nsRect tRect( aX, aY, aWidth, aHeight); + PMDrawArc( tRect, PR_FALSE, PR_TRUE); + return NS_OK; +} + +nsresult nsRenderingContextOS2::FillEllipse( const nsRect& aRect) +{ + nsRect tRect( aRect); + PMDrawArc( tRect, PR_TRUE, PR_TRUE); + return NS_OK; +} + +nsresult nsRenderingContextOS2::FillEllipse( nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) +{ + nsRect tRect( aX, aY, aWidth, aHeight); + PMDrawArc( tRect, PR_TRUE, PR_TRUE); + return NS_OK; +} + +nsresult nsRenderingContextOS2::DrawArc( const nsRect& aRect, + float aStartAngle, float aEndAngle) +{ + nsRect tRect( aRect); + PMDrawArc( tRect, PR_FALSE, PR_FALSE, + (PRInt32)aStartAngle, (PRInt32)aEndAngle); + return NS_OK; +} + +nsresult nsRenderingContextOS2::DrawArc( nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, + float aStartAngle, float aEndAngle) +{ + nsRect tRect( aX, aY, aWidth, aHeight); + PMDrawArc( tRect, PR_FALSE, PR_FALSE, + (PRInt32)aStartAngle, (PRInt32)aEndAngle); + return NS_OK; +} + +nsresult nsRenderingContextOS2::FillArc( const nsRect& aRect, + float aStartAngle, float aEndAngle) +{ + nsRect tRect( aRect); + PMDrawArc( tRect, PR_TRUE, PR_FALSE, + (PRInt32)aStartAngle, (PRInt32)aEndAngle); + return NS_OK; +} + +nsresult nsRenderingContextOS2::FillArc( nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, + float aStartAngle, float aEndAngle) +{ + nsRect tRect( aX, aY, aWidth, aHeight); + PMDrawArc( tRect, PR_TRUE, PR_FALSE, + (PRInt32)aStartAngle, (PRInt32)aEndAngle); + return NS_OK; +} + +void nsRenderingContextOS2::PMDrawArc( nsRect &rect, PRBool bFilled, + PRBool bFull, + PRInt32 start, PRInt32 end) +{ + // convert coords + mTMatrix.TransformCoord( &rect.x, &rect.y, &rect.width, &rect.height); + + RECTL rcl; + NS2PM_ININ( rect, rcl); + + SetupDrawingColor(); + + long lOps = DRO_OUTLINE; + if( bFilled) + lOps |= DRO_FILL; + + // set arc params. + long lWidth = rect.width / 2; + long lHeight = rect.height / 2; + ARCPARAMS arcparams = { lWidth, lHeight, 0, 0 }; + GpiSetArcParams( mSurface->mPS, &arcparams); + + // move to center + rcl.xLeft += lWidth; + rcl.yBottom += lHeight; + GpiMove( mSurface->mPS, (PPOINTL)&rcl); + + if( bFull) + { + // draw ellipse + GpiFullArc( mSurface->mPS, lOps, MAKEFIXED(1,0)); + } + else + { + // draw an arc or a pie + if( bFilled) + { + GpiBeginArea( mSurface->mPS, BA_BOUNDARY); + GpiPartialArc( mSurface->mPS, (PPOINTL)&rcl, MAKEFIXED(1,0), + MAKEFIXED(start,0), MAKEFIXED(end-start,0)); + GpiEndArea( mSurface->mPS); + } + else + { + // draw an invisible partialarc to get to the start of the arc. + long lLineType = GpiQueryLineType( mSurface->mPS); + GpiSetLineType( mSurface->mPS, LINETYPE_INVISIBLE); + GpiPartialArc( mSurface->mPS, (PPOINTL)&rcl, MAKEFIXED(1,0), + MAKEFIXED(0,0), MAKEFIXED(start,0)); + // now draw a real arc + GpiSetLineType( mSurface->mPS, lLineType); + GpiPartialArc( mSurface->mPS, (PPOINTL)&rcl, MAKEFIXED(1,0), + MAKEFIXED(start,0), MAKEFIXED(end-start,0)); + } + } +} + +NS_IMETHODIMP nsRenderingContextOS2::GetHints(PRUint32& aResult) +{ + aResult = gModuleData.renderingHints; + return NS_OK; +} + +nsresult nsRenderingContextOS2::DrawString( const char *aString, + PRUint32 aLength, + nscoord aX, nscoord aY, + const nscoord* aSpacing) +{ + mTMatrix.TransformCoord( &aX, &aY); + POINTL ptl = { aX, aY }; + NS2PM( &ptl, 1); + + SetupFontAndColor(); + + // the pointl we are at is the top of the charbox. We need to find the + // baseline for output, so dec by the lMaxAscender. + ptl.y -= ((nsFontMetricsOS2*)mFontMetrics)->GetDevMaxAscender(); + + // there's clearly a conspiracy to make this method as slow as is + // humanly possible... + int dxMem[200]; + int *dx0 = 0; + if( aSpacing) + { + dx0 = dxMem; + if( aLength > 500) + dx0 = new int[ aLength]; + mTMatrix.ScaleXCoords( aSpacing, aLength, dx0); + } + + GpiMove( mSurface->mPS, &ptl); + + // GpiCharString has a max length of 512 chars at a time... + while( aLength) + { + ULONG thislen = min( aLength, 512); + GpiCharStringPos( mSurface->mPS, nsnull, + aSpacing == nsnull ? 0 : CHS_VECTOR, + thislen, (PCH)aString, + aSpacing == nsnull ? nsnull : (const long int *) dx0); + aLength -= thislen; + aString += thislen; + dx0 += thislen; + } + + return NS_OK; +} + +nsresult nsRenderingContextOS2::DrawString( const PRUnichar *aString, PRUint32 aLength, + nscoord aX, nscoord aY, + PRInt32 aFontID, + const nscoord* aSpacing) +{ + // XXX unicode hack XXX + return DrawString( gModuleData.ConvertFromUcs( aString, aLength), + aLength, aX, aY, aSpacing); +} + +nsresult nsRenderingContextOS2::DrawString( const nsString& aString, + nscoord aX, nscoord aY, + PRInt32 aFontID, + const nscoord* aSpacing) +{ + return DrawString( aString.GetUnicode(), aString.Length(), + aX, aY, aFontID, aSpacing); +} + +// Width-getting methods for string-drawing. Finally in a sensible place! +NS_IMETHODIMP nsRenderingContextOS2::GetWidth( char ch, nscoord &aWidth) +{ + // Optimize spaces; happens *very* often! + if( ch == ' ' && mFontMetrics) + { + aWidth = ((nsFontMetricsOS2*)mFontMetrics)->GetSpaceWidth(this); + return NS_OK; + } + + char buf[1]; + buf[0] = ch; + return GetWidth( buf, 1, aWidth); +} + +NS_IMETHODIMP nsRenderingContextOS2::GetWidth( PRUnichar ch, nscoord &aWidth, + PRInt32 */*aFontID*/) +{ + if( ch == 32 && mFontMetrics) + { + aWidth = ((nsFontMetricsOS2*)mFontMetrics)->GetSpaceWidth(this); + return NS_OK; + } + + PRUnichar buf[1]; + buf[0] = ch; + return GetWidth( buf, 1, aWidth); +} + +NS_IMETHODIMP nsRenderingContextOS2::GetWidth( const char *aString, + nscoord &aWidth) +{ + return GetWidth( aString, strlen(aString), aWidth); +} + +NS_IMETHODIMP nsRenderingContextOS2::GetWidth( const nsString &aString, + nscoord &aWidth, + PRInt32 */*aFontID*/) +{ + return GetWidth( aString.GetUnicode(), aString.Length(), aWidth); +} + +NS_IMETHODIMP nsRenderingContextOS2::GetWidth( const char* aString, + PRUint32 aLength, + nscoord &aWidth) +{ + PRUint32 sum = 0; + + SetupFontAndColor(); // select font + + POINTL ptls[ 4]; + + while( aLength) // max data to gpi function is 512 chars. + { + ULONG thislen = min( aLength, 512); + GpiQueryTextBox( mSurface->mPS, thislen, (PCH) aString, 4, ptls); + sum += ptls[ TXTBOX_TOPRIGHT].x; + aLength -= thislen; + aString += thislen; + } + + aWidth = NSToCoordRound(float(sum) * mP2T); + + return NS_OK; +} + +NS_IMETHODIMP nsRenderingContextOS2::GetWidth( const PRUnichar *aString, + PRUint32 aLength, + nscoord &aWidth, + PRInt32 *aFontID) +{ + // XXX unicode hack XXX + return GetWidth( gModuleData.ConvertFromUcs( aString, aLength), + aLength, aWidth); +} + +// Image drawing: just proxy on to the image object, so no worries yet. +nsresult nsRenderingContextOS2::DrawImage( nsIImage *aImage, nscoord aX, nscoord aY) +{ + nscoord width, height; + + width = NSToCoordRound( mP2T * aImage->GetWidth()); + height = NSToCoordRound( mP2T * aImage->GetHeight()); + + return this->DrawImage( aImage, aX, aY, width, height); +} + +nsresult nsRenderingContextOS2::DrawImage( nsIImage *aImage, nscoord aX, nscoord aY, + nscoord aWidth, nscoord aHeight) +{ + nsRect tr; + + tr.x = aX; + tr.y = aY; + tr.width = aWidth; + tr.height = aHeight; + + return this->DrawImage( aImage, tr); +} + +nsresult nsRenderingContextOS2::DrawImage( nsIImage *aImage, const nsRect& aSRect, const nsRect& aDRect) +{ + nsRect sr,dr; + + sr = aSRect; + mTMatrix.TransformCoord( &sr.x, &sr.y, &sr.width, &sr.height); + + dr = aDRect; + mTMatrix.TransformCoord( &dr.x, &dr.y, &dr.width, &dr.height); + + return aImage->Draw( *this, mSurface, sr.x, sr.y, sr.width, sr.height, dr.x, dr.y, dr.width, dr.height); +} + +nsresult nsRenderingContextOS2::DrawImage( nsIImage *aImage, const nsRect& aRect) +{ + nsRect tr( aRect); + mTMatrix.TransformCoord( &tr.x, &tr.y, &tr.width, &tr.height); + + return aImage->Draw( *this, mSurface, tr.x, tr.y, tr.width, tr.height); +} + +nsresult nsRenderingContextOS2::CopyOffScreenBits( + nsDrawingSurface aSrcSurf, PRInt32 aSrcX, PRInt32 aSrcY, + const nsRect &aDestBounds, PRUint32 aCopyFlags) +{ + NS_ASSERTION( aSrcSurf && mSurface && mFrontSurface, "bad surfaces"); + + nsDrawingSurfaceOS2 *theSurf = (nsDrawingSurfaceOS2 *) aSrcSurf; + + nsRect drect( aDestBounds); + HPS hpsTarget = mFrontSurface->mPS; + + if( aCopyFlags & NS_COPYBITS_TO_BACK_BUFFER) + hpsTarget = mSurface->mPS; + +// When the bitmap-tiling code calls us, we must respect the SOURCE_CLIP_REGION +// flag (ie. not do it). But we must put it on for the compositor. +// +// Finding out *why* this is so is a definite task. +// +#if 0 + // this is what we ought to do! + if( aCopyFlags & NS_COPYBITS_USE_SOURCE_CLIP_REGION) +#else + // compositor doesn't use this flag +// if( !(aCopyFlags & NS_COPYBITS_TO_BACK_BUFFER)) +#endif + { + // Set clip region on dest surface to be that from the hps + // in the passed-in drawing surface. + GpiSetClipRegion2( hpsTarget, GpiCopyClipRegion( theSurf->mPS)); + } + + // Windows wants to select palettes here. I don't think I do. + + if( aCopyFlags & NS_COPYBITS_XFORM_SOURCE_VALUES) + mTMatrix.TransformCoord( &aSrcX, &aSrcY); + + if( aCopyFlags & NS_COPYBITS_XFORM_DEST_VALUES) + mTMatrix.TransformCoord( &drect.x, &drect.y, + &drect.width, &drect.height); + + // Note rects for GpiBitBlt are in-ex. + // Doing coord-conversion by hand to avoid calling GetClientBounds() twice. + RECTL rcls[ 2]; + PRUint32 ulHeight, ulDummy; + + GetTargetHeight( ulHeight); + + rcls[0].xLeft = drect.x; + rcls[0].xRight = drect.x + drect.width; + rcls[0].yTop = ulHeight - drect.y; + rcls[0].yBottom = rcls[0].yTop - drect.height; + + if( aCopyFlags & NS_COPYBITS_TO_BACK_BUFFER) + theSurf->GetDimensions( &ulDummy, &ulHeight); + + rcls[1].xLeft = aSrcX; + rcls[1].yBottom = ulHeight - aSrcY - drect.height; + + long lRC = GpiBitBlt( hpsTarget, theSurf->mPS, + 3, (PPOINTL) rcls, ROP_SRCCOPY, BBO_OR); + if( lRC == GPI_ERROR) + PMERROR("GpiBitBlt"); + + return NS_OK; +} + +// Clip region helper functions -------------------------------------------- + +/* hrgnCombine becomes the clip region. Any current clip region is */ +/* dealt with. hrgnCombine may be NULLHANDLE. */ +/* Return value is lComplexity. */ +/* lOp should be CRGN_* */ +LONG GpiCombineClipRegion( HPS hps, HRGN hrgnCombine, LONG lOp) +{ + if( !hps) return RGN_ERROR; + + /* Get current hps clip region */ + HRGN hrgnClip = 0; + if( GpiQueryClipRegion( hps)) + { + GpiSetClipRegion( hps, 0, &hrgnClip); + + if( hrgnClip && hrgnClip != HRGN_ERROR) + { + /* There is a clip region; combine it with new one if necessary */ + if( lOp != CRGN_COPY) + GpiCombineRegion( hps, hrgnCombine, hrgnClip, hrgnCombine, lOp); + if( !GpiDestroyRegion( hps, hrgnClip)) + PMERROR( "GpiDestroyRegion"); + } + } + + /* hrgnCombine is the correct clip region, & hrgnClip is invalid */ + hrgnClip = 0; + return GpiSetClipRegion( hps, hrgnCombine, &hrgnClip); +} + +/* Return value is HRGN_ */ +HRGN GpiCopyClipRegion( HPS hps) +{ + if( !hps) return HRGN_ERROR; + + HRGN hrgn = 0; + if( GpiQueryClipRegion( hps)) + { + HRGN hrgnClip = 0; + GpiSetClipRegion( hps, 0, &hrgnClip); + if( hrgnClip != HRGN_ERROR) + { + hrgn = GpiCreateRegion( hps, 0, 0); + GpiCombineRegion( hps, hrgn, hrgnClip, 0, CRGN_COPY); + /* put the current clip back */ + HRGN hrgnDummy = 0; + GpiSetClipRegion( hps, hrgnClip, &hrgnDummy); + } + else + hrgn = HRGN_ERROR; + } + + return hrgn; +} diff --git a/mozilla/gfx/src/os2/nsRenderingContextOS2.h b/mozilla/gfx/src/os2/nsRenderingContextOS2.h new file mode 100644 index 00000000000..1cc8a961f84 --- /dev/null +++ b/mozilla/gfx/src/os2/nsRenderingContextOS2.h @@ -0,0 +1,232 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsRenderingContextOS2_h +#define _nsRenderingContextOS2_h + +#include "nsIRenderingContext.h" +#include "nsIScriptObjectOwner.h" +#include "nsIDOMRenderingContext.h" +#include "nsTransform2D.h" +#include "nscoord.h" +#include "nscolor.h" +#include "nsCRT.h" + +class nsIDeviceContext; +class nsIFontMetrics; +class nsIPaletteOS2; +class nsString; +class nsIWidget; +class nsPoint; +class nsFont; +class nsRect; + +struct GraphicsState; + +#include "nsDrawingSurfaceOS2.h" + +class nsRenderingContextOS2 : public nsIRenderingContext, + public nsIDOMRenderingContext, + public nsIScriptObjectOwner +{ + public: + nsRenderingContextOS2(); + virtual ~nsRenderingContextOS2(); + + void *operator new( size_t sz) { + void *rv = new char[ sz]; + nsCRT::zero( rv, sz); + return rv; + } + + NS_DECL_ISUPPORTS + + NS_IMETHOD Init( nsIDeviceContext* aContext, nsIWidget *aWindow); + NS_IMETHOD Init( nsIDeviceContext* aContext, nsDrawingSurface aSurface); + + NS_IMETHOD Reset(); + + NS_IMETHOD GetDeviceContext( nsIDeviceContext *&aDeviceContext); + + NS_IMETHOD LockDrawingSurface( PRInt32 aX, PRInt32 aY, + PRUint32 aWidth, PRUint32 aHeight, + void **aBits, + PRInt32 *aStride, PRInt32 *aWidthBytes, + PRUint32 aFlags); + NS_IMETHOD UnlockDrawingSurface(); + + NS_IMETHOD SelectOffScreenDrawingSurface( nsDrawingSurface aSurface); + NS_IMETHOD GetDrawingSurface( nsDrawingSurface *aSurface); + + NS_IMETHOD PushState(); + NS_IMETHOD PopState( PRBool &aClipEmpty); + + NS_IMETHOD IsVisibleRect( const nsRect& aRect, PRBool &aIsVisible); + + NS_IMETHOD SetClipRect( const nsRect& aRect, nsClipCombine aCombine, PRBool &aClipEmpty); + NS_IMETHOD GetClipRect( nsRect &aRect, PRBool &aHasLocalClip); + NS_IMETHOD SetClipRegion( const nsIRegion& aRegion, nsClipCombine aCombine, PRBool &aClipEmpty); + NS_IMETHOD GetClipRegion( nsIRegion **aRegion); + + NS_IMETHOD SetColor( nscolor aColor); + NS_IMETHOD GetColor( nscolor &aColor) const; + + NS_IMETHOD SetFont( const nsFont& aFont); + NS_IMETHOD SetFont( nsIFontMetrics *aFontMetrics); + + NS_IMETHOD GetFontMetrics( nsIFontMetrics*& aFontMetrics); + + NS_IMETHOD Translate( nscoord aX, nscoord aY); + NS_IMETHOD Scale( float aSx, float aSy); + NS_IMETHOD GetCurrentTransform( nsTransform2D *&aTransform); + + NS_IMETHOD SetLineStyle( nsLineStyle aLineStyle); + NS_IMETHOD GetLineStyle( nsLineStyle &aLineStyle); + + NS_IMETHOD CreateDrawingSurface( nsRect *aBounds, PRUint32 aSurfFlags, nsDrawingSurface &aSurface); + NS_IMETHOD DestroyDrawingSurface( nsDrawingSurface aDS); + + NS_IMETHOD DrawLine( nscoord aX0, nscoord aY0, nscoord aX1, nscoord aY1); + NS_IMETHOD DrawPolyline( const nsPoint aPoints[], PRInt32 aNumPoints); + + NS_IMETHOD DrawRect( const nsRect& aRect); + NS_IMETHOD DrawRect( nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight); + NS_IMETHOD FillRect( const nsRect& aRect); + NS_IMETHOD FillRect( nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight); + + NS_IMETHOD DrawPolygon( const nsPoint aPoints[], PRInt32 aNumPoints); + NS_IMETHOD FillPolygon( const nsPoint aPoints[], PRInt32 aNumPoints); + + NS_IMETHOD DrawEllipse( const nsRect& aRect); + NS_IMETHOD DrawEllipse( nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight); + NS_IMETHOD FillEllipse( const nsRect& aRect); + NS_IMETHOD FillEllipse( nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight); + + NS_IMETHOD DrawArc( const nsRect& aRect, + float aStartAngle, float aEndAngle); + NS_IMETHOD DrawArc( nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, + float aStartAngle, float aEndAngle); + NS_IMETHOD FillArc( const nsRect& aRect, + float aStartAngle, float aEndAngle); + NS_IMETHOD FillArc( nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, + float aStartAngle, float aEndAngle); + // String widths + NS_IMETHOD GetWidth( char aC, nscoord &aWidth); + NS_IMETHOD GetWidth( PRUnichar aC, nscoord &aWidth, + PRInt32 *aFontID = nsnull); + NS_IMETHOD GetWidth( const nsString &aString, nscoord &aWidth, + PRInt32 *aFontID = nsnull); + NS_IMETHOD GetWidth( const char* aString, nscoord &aWidth); + NS_IMETHOD GetWidth( const char* aString, PRUint32 aLength, + nscoord &aWidth); + NS_IMETHOD GetWidth( const PRUnichar *aString, PRUint32 aLength, + nscoord &aWidth, PRInt32 *aFontID = nsnull); + + NS_IMETHOD DrawString( const char *aString, PRUint32 aLength, + nscoord aX, nscoord aY, + const nscoord* aSpacing = nsnull); + NS_IMETHOD DrawString( const PRUnichar *aString, PRUint32 aLength, + nscoord aX, nscoord aY, + PRInt32 aFontID = -1, + const nscoord* aSpacing = nsnull); + NS_IMETHOD DrawString( const nsString& aString, + nscoord aX, nscoord aY, + PRInt32 aFontID = -1, + const nscoord* aSpacing = nsnull); + + NS_IMETHOD DrawImage( nsIImage *aImage, nscoord aX, nscoord aY); + NS_IMETHOD DrawImage( nsIImage *aImage, nscoord aX, nscoord aY, + nscoord aWidth, nscoord aHeight); + NS_IMETHOD DrawImage( nsIImage *aImage, const nsRect& aRect); + NS_IMETHOD DrawImage( nsIImage *aImage, const nsRect& aSRect, const nsRect& aDRect); + + NS_IMETHOD CopyOffScreenBits( nsDrawingSurface aSrcSurf, + PRInt32 aSrcX, PRInt32 aSrcY, + const nsRect &aDestBounds, + PRUint32 aCopyFlags); + + NS_IMETHOD GetHints( PRUint32 &aResult); + + // nsIScriptObjectOwner + NS_IMETHOD GetScriptObject( nsIScriptContext *aContext, void** aScriptObject); + NS_IMETHOD SetScriptObject( void* aScriptObject); + + // nsIDOMRenderingContext + NS_DECL_IDOMRENDERINGCONTEXT + + // Convert XP-rects to OS/2 space. + // World coordinates given & required, double inclusive rcl wanted. + void NS2PM_ININ( const nsRect &in, RECTL &rcl); + // World coordinates given & required, inclusive-exclusive rcl wanted. + void NS2PM_INEX( const nsRect &in, RECTL &rcl); + + // Convert OS/2 rects to XP space. + // World coords given & required, double-inclusive rcl wanted + void PM2NS_ININ( const RECTL &in, nsRect &out); + + // Convert XP points to OS/2 space. + void NS2PM( PPOINTL aPointl, ULONG cPointls); + + private: + nsresult CommonInit(); + nsresult SetupPS( HPS oldPS, HPS newPS); + void GetTargetHeight( PRUint32 &ht); + + // Colour/font setting; call before drawing things. + void SetupDrawingColor( BOOL bForce = FALSE); + void SetupFontAndColor( BOOL bForce = FALSE); + + // Primitive draw-ers + void PMDrawRect( nsRect &rect, BOOL fill); + void PMDrawPoly( const nsPoint aPoints[], PRInt32 aNumPoints, PRBool bFilled); + void PMDrawArc( nsRect &rect, PRBool bFilled, PRBool bFull, PRInt32 start=0, PRInt32 end=0); + + protected: + nsIDeviceContext *mContext; // device context + nsIPaletteOS2 *mPalette; // palette from the dc + nsDrawingSurfaceOS2 *mSurface; // draw things here + nsDrawingSurfaceOS2 *mFrontSurface; // if offscreen, this is onscreen + nscolor mColor; // current colour + nsLineStyle mLineStyle; // current line style + nsTransform2D mTMatrix; // current xform matrix + float mP2T; // cache pix-2-app factor from DC + GraphicsState *mStateStack; // stack of graphics states + nsIFontMetrics *mFontMetrics; // current font + nsIFontMetrics *mCurrFontMetrics; // currently selected font + nscolor mCurrDrawingColor;// currently selected drawing color + nscolor mCurrTextColor; // currently selected text color + nsLineStyle mCurrLineStyle; // currently selected line style + void *mScriptObject; // crazy script object thing. +}; + +inline void nsRenderingContextOS2::GetTargetHeight( PRUint32 &ht) +{ + PRUint32 on, dummy, off; + mSurface->GetDimensions( &dummy, &on); + if( mSurface != mFrontSurface) + { + mFrontSurface->GetDimensions( &dummy, &off); + if( off < on) on = off; + } + ht = on; +} + +#endif diff --git a/mozilla/gfx/src/os2/nsTimerOS2.cpp b/mozilla/gfx/src/os2/nsTimerOS2.cpp new file mode 100644 index 00000000000..b2140aa290a --- /dev/null +++ b/mozilla/gfx/src/os2/nsTimerOS2.cpp @@ -0,0 +1,601 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#define INCL_DOS +#define INCL_WIN +#include + +#include // UINT_MAX (don't ask...) +#include + +#include "nsHashtable.h" + +//#define PROFILE_TIMERS // print stats on timer usage +//#define VERIFY_THREADS // check timers are being used thread-correctly + +#include "nsTimerOS2.h" + +// Implementation of timers lifted from os2fe timer.cpp. +// Which was itself lifted pretty much from the winfe. +// +// mjf 28-9-98 +// +// Rewrite 16-3-1999 to work correctly in a multithreaded world: +// Now, each thread has an nsTimerManager. +// This has a Timer window owned by the thread, and +// a queue (linked list) of timer objects. +// There is a static hashtable of these TimerManager +// object, keyed by TID. Thus things work. Ahem. +// +// Problem: nsTimerManagers are not cleaned up until +// module unload time. +// +// Update 16-4-1999 to recycle timers and collect statistics on how effective +// this is. + +// Declarations, prototypes of useful functions +MRESULT EXPENTRY fnwpTimer( HWND h, ULONG msg, MPARAM mp1, MPARAM mp2); +#define NSTIMER_TIMER (TID_USERMAX - 2) +#define TIMEOUT_NEVER ((ULONG)-1) +#define TIMERCLASS ("WarpzillaTimerClass") +#define TIMER_CACHESIZE 20 + +static TID QueryCurrentTID(); + +// Timer object (funky 'release' method for recycler) +NS_IMPL_ADDREF(nsTimer) +NS_IMPL_QUERY_INTERFACE(nsTimer, nsITimer::GetIID()) + +nsrefcnt nsTimer::Release() +{ + if( --mRefCnt == 0) + mManager->DisposeTimer( this); + + return mRefCnt; +} + +nsTimer::nsTimer( nsTimerManager *aManager) +{ + Construct(); + mManager = aManager; +} + +void nsTimer::Construct() +{ + NS_INIT_REFCNT(); + mDelay = 0; + mFunc = nsnull; + mClosure = nsnull; + mCallback = nsnull; + mFireTime = 0; + mNext = nsnull; +} + +void nsTimer::Destruct() +{ + Cancel(); +} + +nsTimer::~nsTimer() +{ + Destruct(); +} + +nsresult nsTimer::Init( nsTimerCallbackFunc aFunc, + void *aClosure, PRUint32 aDelay) +{ + mFunc = aFunc; + mClosure = aClosure; + + return mManager->InitTimer( this, aDelay); +} + +nsresult nsTimer::Init( nsITimerCallback *aCallback, PRUint32 aDelay) +{ + mCallback = aCallback; + NS_ADDREF(mCallback); // this is daft, but test14 traps without it + + return mManager->InitTimer( this, aDelay); +} + +void nsTimer::Cancel() +{ + if( mCallback || mFunc) // guard against double-cancel + { + mManager->CancelTimer( this); + NS_IF_RELEASE(mCallback); + mFunc = nsnull; + } +} + +void nsTimer::Fire( ULONG aNow) +{ + if( mFunc) + (*mFunc)( this, mClosure); + else if( mCallback) + mCallback->Notify( this); +} + +// Timer manager + +// First, GUI stuff. + +nsTimerManager::nsTimerManager() : mTimerList(nsnull), mTimerSet(FALSE), + mNextFire(TIMEOUT_NEVER), mHWNDTimer(0), + mBusy(FALSE), mBase(nsnull), mSize(0) +#ifdef PROFILE_TIMERS + ,mDeleted(0),mActive(0),mCount(0),mPeak(0) +#endif +{ + // As a part of the PM setup protocol (see somewhere under + // http://www.mozilla.org/ports/os2/code_docs/), create a HMQ if + // appropriate. + if( FALSE == WinQueryQueueInfo( HMQ_CURRENT, 0, 0)) + { + HAB hab = WinInitialize( 0); + WinCreateMsgQueue( hab, 0); + } + // Register timer window class if we haven't done that yet. + EnsureWndClass(); + + // Create timer window + mHWNDTimer = WinCreateWindow( HWND_DESKTOP, TIMERCLASS, 0, 0, 0, 0, 0, + 0, HWND_DESKTOP, HWND_TOP, 0, 0, 0); + NS_ASSERTION(mHWNDTimer, "Couldn't create Timer window"); + + // stick pointer to us in the window word + WinSetWindowPtr( mHWNDTimer, QWL_USER, this); + +#ifdef PROFILE_TIMERS + mTID = QueryCurrentTID(); +#endif +} + +nsTimerManager::~nsTimerManager() +{ + // I reckon PM has already gone down by this point. + // There might be an API to do this (register listener for app shutdown) + // at some point, or maybe when we get into the widget DLL. + if( mHWNDTimer) + WinDestroyWindow( mHWNDTimer); + +#ifdef PROFILE_TIMERS + printf( "\n----- Timer Statistics %d -----\n", (int)mTID); + printf( " Calls to NS_NewTimer: %d\n", mCount); + printf( " Actual timers created: %d\n", mPeak); + double d = mCount ? (double)(mCount - mPeak) / (double)mCount : 0; + printf( " Timers recycled: %d (%d%%)\n", mCount - mPeak, (int)(d*100.0)); + UINT i = mSize+mActive+mDeleted; + printf( " Cache+Active+Deleted: %d\n", i); + if( i != mPeak) + printf( " WARNING: Timers leaked: %d\n", mPeak - i); + printf( "------------------------------\n\n"); +#endif + + // delete timers in the 'cache' list + nsTimer *pTemp, *pNext = mBase; + while( 0 != pNext) + { + pTemp = pNext->mNext; + delete pNext; + pNext = pTemp; + // and then the 'active' list... + if( 0 == pNext) { pNext = mTimerList; mTimerList = 0; } + } +} + +void nsTimerManager::EnsureWndClass() +{ + static BOOL bRegistered = FALSE; + + if( !bRegistered) + { + BOOL rc = WinRegisterClass( 0, TIMERCLASS, fnwpTimer, 0, 4); + NS_ASSERTION(rc,"Can't register class"); + bRegistered = TRUE; + } +} + +MRESULT nsTimerManager::HandleMsg( ULONG msg, MPARAM mp1, MPARAM mp2) +{ + MRESULT mRC = 0; + + if( msg == WM_TIMER && SHORT1FROMMP(mp1) == NSTIMER_TIMER) + { + // Block only one entry into this function, or else. + // (windows does this; don't completely understand or belive + // it's necessary -- maybe if nested eventloops happen). + if( !mBusy) + { + mBusy = TRUE; + // see if we need to fork off any timeout functions + if( mTimerList) + ProcessTimeouts( 0); + mBusy = FALSE; + } + else + printf( "mBusy == TRUE but want to fire Timer!\n"); + } + else + mRC = WinDefWindowProc( mHWNDTimer, msg, mp1, mp2); + + return mRC; +} + +void nsTimerManager::StopTimer() +{ + WinStopTimer( 0/*hab*/, mHWNDTimer, NSTIMER_TIMER); +} + +void nsTimerManager::StartTimer( UINT aDelay) +{ + WinStartTimer( 0/*hab*/, mHWNDTimer, NSTIMER_TIMER, aDelay); +} + +MRESULT EXPENTRY fnwpTimer( HWND h, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + nsTimerManager *pMgr = (nsTimerManager*) WinQueryWindowPtr( h, QWL_USER); + MRESULT mRet = 0; + if( pMgr) + mRet = pMgr->HandleMsg( msg, mp1, mp2); + else + mRet = WinDefWindowProc( h, msg, mp1, mp2); + return mRet; +} + +// Recycling management +nsTimer *nsTimerManager::CreateTimer() +{ + nsTimer *rc; + if( !mBase) + { + rc = new nsTimer( this); +#ifdef PROFILE_TIMERS + mPeak++; +#endif + } + else + { + rc = mBase; + mBase = rc->mNext; + rc->Construct(); + mSize--; + } +#ifdef PROFILE_TIMERS + mCount++; +#endif + return rc; +} + +void nsTimerManager::DisposeTimer( nsTimer *aTimer) +{ + if( TIMER_CACHESIZE == mSize) + { + delete aTimer; +#ifdef PROFILE_TIMERS + mDeleted++; +#endif + } + else + { + aTimer->Destruct(); + aTimer->mNext = mBase; + mBase = aTimer; + mSize++; + } +} + +// Complicated functions to maintain the list of timers. +// This code has something of a pedigree -- I worked it through once, +// ages ago, for os2fe, and convinced myself it was correct. + +// Adjust the period of the window timer according to the contents of +// the timer list, and record the absolute time that the next firing +// will occur. May well stop the window timer entirely. +void nsTimerManager::SyncTimeoutPeriod( ULONG aTickCount) +{ + // May want us to set tick count ourselves. + if( 0 == aTickCount) + aTickCount = WinGetCurrentTime( 0/*hab*/); + + // If there's no list, we should clear the timer. + if( !mTimerList) + { + if( mTimerSet) + { + StopTimer(); + mNextFire = TIMEOUT_NEVER; + mTimerSet = FALSE; + } + } + else + { + // See if we need to clear the current timer. + // Circumstances are that if the timer will not + // fire on time for the next timeout. + BOOL bSetTimer = FALSE; + nsTimer *pTimeout = mTimerList; + if( mTimerSet) + { + if( pTimeout->mFireTime != mNextFire) + { + StopTimer(); + mNextFire = TIMEOUT_NEVER; + mTimerSet = FALSE; + + // Set the timer. + bSetTimer = TRUE; + } + } + else + { + // No timer set, attempt. + bSetTimer = TRUE; + } + + if( bSetTimer) + { + ULONG ulFireWhen = pTimeout->mFireTime > aTickCount ? + pTimeout->mFireTime - aTickCount : 0; + if( ulFireWhen > UINT_MAX) + ulFireWhen = UINT_MAX; + + NS_ASSERTION(mTimerSet == FALSE,"logic error in timer sync magic"); + StartTimer( ulFireWhen); + + // Set the fire time. + mNextFire = pTimeout->mFireTime; + } + } +} + +// Walk down the timeout list and fire those which are due. +void nsTimerManager::ProcessTimeouts( ULONG aNow) +{ + nsTimer *p = mTimerList; + + if( 0 == aNow) + aNow = WinGetCurrentTime( 0/*hab*/); + + BOOL bCalledSync = FALSE; + + // loop over all entries + while( p) + { + // send it + if( p->mFireTime < aNow) + { + // Fire it, making sure the timer doesn't die. + NS_ADDREF(p); + p->Fire( aNow); + + // Clear the timer. + // Period synced. + p->Cancel(); + bCalledSync = TRUE; + NS_RELEASE(p); + + // Reset the loop (can't look at p->pNext now, and called + // code may have added/cleared timers). + // (could do this by going recursive and returning). + p = mTimerList; + } + else + { + // Make sure we fire a timer. + // Also, we need to check to see if things are backing up (they + // may be asking to be fired long before we ever get to them, + // and we don't want to pass in negative values to the real + // timer code, or it takes days to fire.... + if( FALSE == bCalledSync) + { + SyncTimeoutPeriod( aNow); + bCalledSync = TRUE; + } + // Get next timer. + p = p->mNext; + } + } +} + +// Init a timer - insert it into the list, adjust the window timer to be +// running fast enough to make sure it fires when it should. +nsresult nsTimerManager::InitTimer( nsTimer *aTimer, PRUint32 aDelay) +{ +#ifdef VERIFY_THREADS + if( aTimer->mTID != QueryCurrentTID()) + printf( "*** Thread assumption violated in base/src/os2/nsTimerOS2.cpp\n"); +#endif + + ULONG ulNow = WinGetCurrentTime( 0/*hab*/); + + aTimer->mDelay = aDelay; + aTimer->mFireTime = (ULONG) aDelay + ulNow; + aTimer->mNext = nsnull; + + // add it to the list + if( !mTimerList) + mTimerList = aTimer; + else + { + // is it before everything else on the list? + if( aTimer->mFireTime < mTimerList->mFireTime) + { + aTimer->mNext = mTimerList; + mTimerList = aTimer; + } + else + { + nsTimer *pPrev = mTimerList; + nsTimer *pCurrent = mTimerList; + + while( pCurrent && + (pCurrent->mFireTime <= aTimer->mFireTime)) + { + pPrev = pCurrent; + pCurrent = pCurrent->mNext; + } + + NS_ASSERTION(pPrev,"logic error in InitTimer"); + + // insert it after pPrev (this could be at the end of the list) + aTimer->mNext = pPrev->mNext; + pPrev->mNext = aTimer; + } + } + +#ifdef PROFILE_TIMERS + mActive++; +#endif + + // Sync the timer fire period. + SyncTimeoutPeriod( ulNow); + + return NS_OK; +} + +// Cancel a timer - remove it from the list, adjust the window timer as +// appropriate. +void nsTimerManager::CancelTimer( nsTimer *aTimer) +{ + if( mTimerList == aTimer) + { + // first element in the list lossage + mTimerList = aTimer->mNext; + } + else + { + // walk until no next pointer + nsTimer *p = mTimerList; + while( p && p->mNext && (p->mNext != aTimer)) + p = p->mNext; + + // if we found something valid pull it out of the list + if( p && p->mNext && p->mNext == aTimer) + { + p->mNext = aTimer->mNext; + } + else + { + // we come here at app-shutdown/crash when timers which are still in the + // active-timer list are deleted. + return; + } + } + +#ifdef PROFILE_TIMERS + mActive--; +#endif + + // Adjust window timer + SyncTimeoutPeriod( 0); +} + +// Data structure to hold and create nsTimerManagers. +// This is (meant to be) thread-safe. +class nsTimerManagers +{ + nsHashtable mTable; + HMTX mMutex; + + struct TIDKey : public nsVoidKey + { + TIDKey() : nsVoidKey((void*)QueryCurrentTID()) + {} + }; + + struct Lock + { + HMTX mHmtx; + Lock( HMTX hmtx) : mHmtx(hmtx) + { + DosRequestMutexSem( mHmtx, SEM_INDEFINITE_WAIT); + } + ~Lock() + { + DosReleaseMutexSem( mHmtx); + } + }; + + public: + nsTimerManagers() : mMutex(0) + { + DosCreateMutexSem( 0, &mMutex, 0, 0 /*unowned*/); + } + + static PRBool mgr_dtor( nsHashKey *aKey, void *aData, void */*aClosure*/) + { + nsTimerManager *pManager = (nsTimerManager*) aData; + delete pManager; + return PR_TRUE; + } + + ~nsTimerManagers() + { + mTable.Enumerate( &mgr_dtor); + if( mMutex) + DosCloseMutexSem( mMutex); + } + + nsTimerManager *Get() + { + Lock lock(mMutex); + TIDKey key; + + nsTimerManager *aMgr = (nsTimerManager*) mTable.Get( &key); + + if( !aMgr) + { + aMgr = new nsTimerManager; + mTable.Put( &key, aMgr); + } + + return aMgr; + } + +} TimerManagers; + +// Entry into the DLL. No, I dunno why there's not a normal factory +// for this either. Ease of use? + +NS_BASE nsresult NS_NewTimer( nsITimer **aInstance) +{ + if( !aInstance) + return NS_ERROR_NULL_POINTER; + + // Assumption: timers are created in the same thread they are to be + // used in. This seems likely, but we shall see. + // If things seem screwy, set the VERIFY_THREADS flag on this file. + + nsTimer *timer = TimerManagers.Get()->CreateTimer(); + if( !timer) + return NS_ERROR_OUT_OF_MEMORY; + + return timer->QueryInterface( nsITimer::GetIID(), (void **) aInstance); +} + +TID QueryCurrentTID() +{ + PTIB pTib = 0; + PPIB pPib = 0; + DosGetInfoBlocks( &pTib, &pPib); + return pTib->tib_ptib2->tib2_ultid; +} diff --git a/mozilla/gfx/src/os2/nsTimerOS2.h b/mozilla/gfx/src/os2/nsTimerOS2.h new file mode 100644 index 00000000000..cba33e2c6f7 --- /dev/null +++ b/mozilla/gfx/src/os2/nsTimerOS2.h @@ -0,0 +1,116 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nstimeros2_h +#define _nstimeros2_h + +// Class definitions for the timers. +// +// These timer classes are reentrant, thread-correct and supports recycling of +// timer objects on a per-thread basis. + +#include "nsITimer.h" +#include "nsITimerCallback.h" + +// Implementation of the timer interface. + +class nsTimerManager; + +class nsTimer : public nsITimer +{ + public: + nsTimer( nsTimerManager *aManager); + virtual ~nsTimer(); + + // nsISupports + NS_DECL_ISUPPORTS + + // Explicit init-term for recycler + void Construct(); + void Destruct(); + + nsresult Init( nsTimerCallbackFunc aFunc, void *aClosure, PRUint32 aDelay); + nsresult Init( nsITimerCallback *aCallback, PRUint32 aDelay); + void Cancel(); + PRUint32 GetDelay() { return mDelay; } + void SetDelay( PRUint32 aDelay) {}; // XXX Windows does this too... + void *GetClosure() { return mClosure; } + + // Implementation + void Fire( ULONG aNow); + + private: + PRUint32 mDelay; + nsTimerCallbackFunc mFunc; + void *mClosure; + nsITimerCallback *mCallback; + ULONG mFireTime; + nsTimer *mNext; + + friend class nsTimerManager; + + nsTimerManager *mManager; +}; + + +// Timer manager class, one of these per-thread + +class nsTimerManager +{ + public: + nsTimerManager(); + ~nsTimerManager(); + + nsresult InitTimer( nsTimer *aTimer, PRUint32 aDelay); + void CancelTimer( nsTimer *aTimer); + + MRESULT HandleMsg( ULONG msg, MPARAM mp1, MPARAM mp2); + + nsTimer *CreateTimer(); + void DisposeTimer( nsTimer *aTimer); + + private: + nsTimer *mTimerList; // linked list of active timers, sorted in priority order + BOOL mTimerSet; // timer running? + ULONG mNextFire; // absolute time of next fire + HWND mHWNDTimer; // window for timer messages + BOOL mBusy; // dubious lock thingy + + void StartTimer( UINT delay); + void StopTimer(); + void EnsureWndClass(); + + void ProcessTimeouts( ULONG aNow); + void SyncTimeoutPeriod( ULONG aTickCount); + + // timer-cache + nsTimer *mBase; + UINT mSize; +#ifdef PROFILE_TIMERS + UINT mDeleted; + UINT mActive; + UINT mCount; + UINT mPeak; + TID mTID; +#endif +}; + +#endif diff --git a/mozilla/widget/src/os2/nsAppShell.cpp b/mozilla/widget/src/os2/nsAppShell.cpp new file mode 100644 index 00000000000..f571926c7a0 --- /dev/null +++ b/mozilla/widget/src/os2/nsAppShell.cpp @@ -0,0 +1,315 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include "nsAppShell.h" +#include "nsHashtable.h" + +// Appshell manager. Same threads must get the same appshell object, +// or else the message queue will be taken over by the second (nested) +// appshell and subsequently killed when it does. This is bad because +// the main (first) appshell should still be running. + +TID QueryCurrentTID(); + +class nsAppshellManager +{ + HMTX mLock; + nsHashtable *mTable; + + struct ThreadKey : public nsVoidKey + { + ThreadKey() : nsVoidKey( (void*) QueryCurrentTID()) {} + }; + + public: + nsAppshellManager() + { + mTable = new nsHashtable; + DosCreateMutexSem( 0, &mLock, 0, FALSE /*unowned*/); + } + + ~nsAppshellManager() + { + DosCloseMutexSem( mLock); + delete mTable; + } + + nsIAppShell *GetAppshell() + { + ThreadKey key; + + DosRequestMutexSem( mLock, SEM_INDEFINITE_WAIT); + + nsIAppShell *pShell = (nsIAppShell*) mTable->Get( &key); + + if( nsnull == pShell) + { + pShell = new nsAppShell; + mTable->Put( &key, (void*) pShell); + } + + DosReleaseMutexSem( mLock); + + return pShell; + } + + void RemoveAppshell( nsIAppShell *aShell) + { + ThreadKey key; + + DosRequestMutexSem( mLock, SEM_INDEFINITE_WAIT); + + nsIAppShell *pShell = (nsIAppShell*) mTable->Get( &key); + + if( pShell != aShell) + printf( "Appshell object dying in a foreign thread\n"); + else + mTable->Remove( &key); + + DosReleaseMutexSem( mLock); + } +}; + +static nsAppshellManager *pManager = nsnull; + +NS_IMPL_ISUPPORTS(nsAppShell, nsIAppShell::GetIID()) + +// nsAppShell constructor +nsAppShell::nsAppShell() +{ + NS_INIT_REFCNT(); + mDispatchListener = 0; + mHab = 0; mHmq = 0; + mQuitNow = FALSE; + memset( &mQmsg, 0, sizeof mQmsg); +} + +nsresult nsAppShell::SetDispatchListener( nsDispatchListener *aDispatchListener) +{ + mDispatchListener = aDispatchListener; + return NS_OK; +} + +// Create the application shell +nsresult nsAppShell::Create( int */*argc*/, char **/*argv*/) +{ + // It is possible that there already is a HAB/HMQ for this thread. + // This condition arises when an event queue (underlying, PLEvent) is + // created before the appshell. + // When this happens, we must take over ownership of these existing + // objects (and so destroy them when we go, too). + + if( FALSE == WinQueryQueueInfo( HMQ_CURRENT, 0, 0)) + { + mHab = WinInitialize( 0); + mHmq = WinCreateMsgQueue( mHab, 0); + } + else + { + mHab = 0; // HABs don't actually seem to be checked, ever. + // But 0 == (current pid,current tid) + mHmq = HMQ_CURRENT; + } + + return NS_OK; +} + +// Enter a message handler loop +nsresult nsAppShell::Run() +{ + if( !mHmq) return NS_ERROR_FAILURE; // (mHab = 0 is okay) + + // Add a reference to deal with async. shutdown + NS_ADDREF_THIS(); + + // XXX if we're HMQ_CURRENT, peek the first message & get the right one ? + + // Process messages + for( ;;) + { + if( TRUE == WinGetMsg( mHab, &mQmsg, 0, 0, 0)) + { + WinDispatchMsg( mHab, &mQmsg); + } + else + { // WM_QUIT + if( mQmsg.hwnd) + // send WM_SYSCOMMAND, SC_CLOSE to window (tasklist close) + WinSendMsg( mQmsg.hwnd, WM_SYSCOMMAND, MPFROMSHORT(SC_CLOSE), 0); + else + { + if( mQuitNow) // Don't want to close the app when a window is + break; // closed, just when our `Exit' is called. + } + } + + if( mDispatchListener) + mDispatchListener->AfterDispatch(); + } + + // reset mQuitNow flag for re-entrant appshells + mQuitNow = FALSE; + + // Release the reference we added earlier + Release(); + + return NS_OK; +} + +// GetNativeData - return the HMQ for NS_NATIVE_SHELL +void *nsAppShell::GetNativeData( PRUint32 aDataType) +{ + void *rc = 0; + + switch( aDataType) + { + case NS_NATIVE_SHELL: rc = (void*) mHmq; break; + } + + return rc; +} + +// Exit a message handler loop +nsresult nsAppShell::Exit() +{ + NS_ASSERTION( mQuitNow == FALSE, "Double AppShell::Exit"); + mQuitNow = TRUE; + WinPostQueueMsg( mHmq, WM_QUIT, 0, 0); + return NS_OK; +} + +// nsAppShell destructor +nsAppShell::~nsAppShell() +{ + WinDestroyMsgQueue( mHmq); + WinTerminate( mHab); +} + +// These are for modal dialogs and also tres weird. +// +// XXX must handle WM_QUIT sensibly (close window) +// -- dependency on xptoolkit dialogs being close by other means. +// +nsresult nsAppShell::GetNativeEvent( PRBool &aRealEvent, void *&aEvent) +{ + BOOL isNotQuit = WinGetMsg( mHab, &mQmsg, 0, 0, 0); + nsresult rc = NS_ERROR_FAILURE; + + if( isNotQuit) + { + aRealEvent = PR_TRUE; + rc = NS_OK; + aEvent = &mQmsg; + } + else + aRealEvent = PR_FALSE; + + return rc; +} + +nsresult nsAppShell::DispatchNativeEvent( PRBool /*aRealEvent*/, void */*aEvent*/) +{ + WinDispatchMsg( mHab, &mQmsg); + return NS_OK; +} + +nsresult nsAppShell::EventIsForModalWindow( PRBool aRealEvent, + void */*aEvent*/, + nsIWidget *aWidget, + PRBool *aForWindow) +{ + nsresult rc = NS_ERROR_FAILURE; + + if( PR_FALSE == aRealEvent) + { + *aForWindow = PR_FALSE; + rc = NS_OK; + } + else if( nsnull != aWidget) + { + // Set aForWindow if either: + // * the message is for a descendent of the given window + // * the message is for another window, but is a message which + // should be allowed for a disabled window. + + PRBool isMouseEvent = PR_FALSE; + PRBool isInWindow = PR_FALSE; + + // Examine the target window & find the frame + // XXX should GetNativeData() use GetMainWindow() ? + HWND hwnd = (HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW); + hwnd = WinQueryWindow(hwnd, QW_PARENT); + + if( hwnd == mQmsg.hwnd || WinIsChild( mQmsg.hwnd, hwnd)) + isInWindow = PR_TRUE; + + // XXX really ought to do something about focus here + + if( !isInWindow) + { + // Block mouse messages for non-modal windows + if( mQmsg.msg >= WM_MOUSEFIRST && mQmsg.msg <= WM_MOUSELAST) + isMouseEvent = PR_TRUE; + else if( mQmsg.msg >= WM_MOUSETRANSLATEFIRST && + mQmsg.msg <= WM_MOUSETRANSLATELAST) + isMouseEvent = PR_TRUE; + else if( mQmsg.msg == WMU_MOUSEENTER || mQmsg.msg == WMU_MOUSELEAVE) + isMouseEvent = PR_TRUE; + } + + // set dispatch indicator + *aForWindow = isInWindow || !isMouseEvent; + + rc = NS_OK; + } + + return rc; +} + +extern "C" nsresult NS_CreateAppshell( nsIAppShell **aAppShell) +{ + if( !aAppShell) + return NS_ERROR_NULL_POINTER; + + BOOL bFirstTime = FALSE; + + if( !pManager) + { + bFirstTime = TRUE; + pManager = new nsAppshellManager; + } + + *aAppShell = pManager->GetAppshell(); + + if( bFirstTime) + gModuleData.Init( *aAppShell); + + return NS_OK; +} + +// Get the current TID [vacpp doesn't have gettid()] +TID QueryCurrentTID() +{ + PTIB pTib = 0; + PPIB pPib = 0; + DosGetInfoBlocks( &pTib, &pPib); + return pTib->tib_ptib2->tib2_ultid; +} diff --git a/mozilla/widget/src/os2/nsAppShell.h b/mozilla/widget/src/os2/nsAppShell.h new file mode 100644 index 00000000000..7ab61de0c92 --- /dev/null +++ b/mozilla/widget/src/os2/nsAppShell.h @@ -0,0 +1,65 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsAppShell_h +#define _nsAppShell_h + +#include "nsWidgetDefs.h" +#include "nsIAppShell.h" + +// Native PM Application shell wrapper. +class nsAppShell : public nsIAppShell +{ + public: + nsAppShell(); + virtual ~nsAppShell(); + + // nsISupports + NS_DECL_ISUPPORTS + + // nsIAppShell + NS_IMETHOD Create( int *argc, char **argv); + NS_IMETHOD SetDispatchListener( nsDispatchListener *aDispatchListener); + NS_IMETHOD Spinup() { return NS_OK; } + NS_IMETHOD Run(); + NS_IMETHOD Spindown() { return NS_OK; } + NS_IMETHOD Exit(); + + NS_IMETHOD GetNativeEvent( PRBool &aRealEvent, void *&aEvent); + NS_IMETHOD EventIsForModalWindow( PRBool aRealEvent, void *aEvent, + nsIWidget *aWidget, PRBool *aForWindow); + NS_IMETHOD DispatchNativeEvent( PRBool aRealEvent, void *aEvent); + + // return the HMQ for NS_NATIVE_SHELL, fwiw + virtual void *GetNativeData( PRUint32 aDataType); + + private: + nsDispatchListener *mDispatchListener; + HAB mHab; + HMQ mHmq; + BOOL mQuitNow; + QMSG mQmsg; +}; + +// obtain an appropriate appshell object +extern "C" nsresult NS_CreateAppshell( nsIAppShell **aAppShell); + +#endif diff --git a/mozilla/widget/src/os2/nsBaseList.cpp b/mozilla/widget/src/os2/nsBaseList.cpp new file mode 100644 index 00000000000..0955ae7ecb6 --- /dev/null +++ b/mozilla/widget/src/os2/nsBaseList.cpp @@ -0,0 +1,148 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include "nsWidgetDefs.h" +#include "nsBaseList.h" +#include "nsStringUtil.h" + +// Basic things for talking to listboxen. +// Code shared by listbox & combobox controls. +// +// Very straight-forward; potential DBCS/Unicode problems as ever. + +// return false if index is silly +PRBool nsBaseList::CheckIndex( PRInt32 &index) +{ + short sItems = GetItemCount(); + if( index == -1) + index = sItems - 1; + + return index >= sItems ? PR_FALSE : PR_TRUE; +} + +nsresult nsBaseList::AddItemAt( nsString &aItem, PRInt32 aPosition) +{ + NS_ALLOC_STR_BUF(buf, aItem, 256); + + short iPos = aPosition; + if( iPos == -1) + iPos = LIT_END; + + SendMsg( LM_INSERTITEM, MPFROMSHORT(iPos), MPFROMP(buf)); + + NS_FREE_STR_BUF(buf); + + return NS_OK; +} + +// Despite what the comment says, return the found index. +PRInt32 nsBaseList::FindItem( nsString &aItem, PRInt32 aStartPos) +{ + PRInt32 ret = -1; + + if( PR_TRUE == CheckIndex( aStartPos)) + { + NS_ALLOC_STR_BUF(buf, aItem, 256); + + short sStart = aStartPos; + if( sStart == 0) + sStart = LIT_FIRST; + + MRESULT rc = SendMsg( LM_SEARCHSTRING, + MPFROM2SHORT(LSS_CASESENSITIVE,sStart), + MPFROMP(buf)); + ret = SHORT1FROMMR(rc); + + if( ret == LIT_NONE) + ret = -1; + + NS_FREE_STR_BUF(buf); + } + return ret; +} + +PRInt32 nsBaseList::GetItemCount() +{ + return SHORT1FROMMR( SendMsg( LM_QUERYITEMCOUNT)); +} + +PRBool nsBaseList::RemoveItemAt( PRInt32 aPosition) +{ + PRBool rc = CheckIndex( aPosition); + + if( rc == PR_TRUE) + SendMsg( LM_DELETEITEM, MPFROMSHORT(aPosition)); + + return rc; +} + +PRBool nsBaseList::GetItemAt( nsString& anItem, PRInt32 aPosition) +{ + PRBool rc = CheckIndex( aPosition); + + if( rc == PR_TRUE) + { + // first get text length + short len = SHORT1FROMMR( SendMsg( LM_QUERYITEMTEXTLENGTH, + MPFROMSHORT(aPosition))); + + NS_ALLOC_CHAR_BUF(buf,256,len+1); + + // now get text & fill in string + SendMsg( LM_QUERYITEMTEXT, MPFROM2SHORT(aPosition,len+1), MPFROMP(buf)); + anItem.SetString(buf); + + NS_FREE_CHAR_BUF(buf); + } + + return rc; +} + +nsresult nsBaseList::GetSelectedItem( nsString &aItem) +{ + PRInt32 sel = GetSelectedIndex(); + if( sel != -1) + GetItemAt( aItem, sel); + return NS_OK; +} + +PRInt32 nsBaseList::GetSelectedIndex() +{ + short sel = SHORT1FROMMR( SendMsg( LM_QUERYSELECTION, + MPFROMSHORT(LIT_FIRST))); + if( sel == LIT_NONE) + sel = -1; + + return sel; +} + +nsresult nsBaseList::SelectItem( PRInt32 aPosition) +{ + if( PR_TRUE == CheckIndex( aPosition)) + SendMsg( LM_SELECTITEM, MPFROMSHORT(aPosition), MPFROMLONG(TRUE)); + return NS_OK; +} + +nsresult nsBaseList::Deselect() +{ + SendMsg( LM_SELECTITEM, MPFROMSHORT(LIT_NONE)); + return NS_OK; +} diff --git a/mozilla/widget/src/os2/nsBaseList.h b/mozilla/widget/src/os2/nsBaseList.h new file mode 100644 index 00000000000..b5ca157b45d --- /dev/null +++ b/mozilla/widget/src/os2/nsBaseList.h @@ -0,0 +1,73 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsbaselist_h +#define _nsbaselist_h + +// Share code between listbox & combobox controls. +// Avoid inheriting one from the other. + +#include "nsstring.h" +#include "nsISupports.h" + +class nsBaseList +{ + public: + // nsIListWidget implementation + NS_IMETHOD AddItemAt( nsString &aItem, PRInt32 aPosition); + virtual PRInt32 FindItem( nsString &aItem, PRInt32 aStartPos); + virtual PRInt32 GetItemCount(); + virtual PRBool RemoveItemAt( PRInt32 aPosition); + virtual PRBool GetItemAt( nsString& anItem, PRInt32 aPosition); + NS_IMETHOD GetSelectedItem( nsString &aItem); + virtual PRInt32 GetSelectedIndex(); + NS_IMETHOD SelectItem( PRInt32 aPosition); + NS_IMETHOD Deselect(); + + // helper + virtual MRESULT SendMsg( ULONG msg, MPARAM mp1=0, MPARAM mp2=0) = 0; + + protected: + PRBool CheckIndex( PRInt32 &index); +}; + +#define DECL_BASE_LIST_METHODS virtual nsresult AddItemAt( nsString &aItem, PRInt32 aPosition) \ + { return nsBaseList::AddItemAt( aItem,aPosition); } \ + virtual PRInt32 FindItem( nsString &aItem, PRInt32 aStartPos) \ + { return nsBaseList::FindItem( aItem, aStartPos); } \ + virtual PRInt32 GetItemCount() \ + { return nsBaseList::GetItemCount(); } \ + virtual PRBool RemoveItemAt( PRInt32 aPosition) \ + { return nsBaseList::RemoveItemAt( aPosition); } \ + virtual PRBool GetItemAt( nsString& anItem, PRInt32 aPosition) \ + { return nsBaseList::GetItemAt( anItem, aPosition); } \ + NS_IMETHOD GetSelectedItem( nsString &aItem) \ + { return nsBaseList::GetSelectedItem( aItem); } \ + virtual PRInt32 GetSelectedIndex() \ + { return nsBaseList::GetSelectedIndex(); } \ + NS_IMETHOD SelectItem( PRInt32 aPosition) \ + { return nsBaseList::SelectItem( aPosition); } \ + NS_IMETHOD Deselect() \ + { return nsBaseList::Deselect(); } \ + virtual MRESULT SendMsg( ULONG msg, MPARAM mp1=0, MPARAM mp2=0) \ + { return mOS2Toolkit->SendMsg( mWnd, msg, mp1, mp2); } + +#endif diff --git a/mozilla/widget/src/os2/nsCanvas.cpp b/mozilla/widget/src/os2/nsCanvas.cpp new file mode 100644 index 00000000000..55bf8ecd42d --- /dev/null +++ b/mozilla/widget/src/os2/nsCanvas.cpp @@ -0,0 +1,256 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// nscanvas - basic window class that dispatches paint events. + +#include "nscanvas.h" +#include "nsIDeviceContext.h" +#include + +nsCanvas::nsCanvas() : mIsTLB(FALSE) +{} + + +// Called in the PM thread. +void nsCanvas::RealDoCreate( HWND hwndP, nsWindow *aParent, const nsRect &aRect, + EVENT_CALLBACK aHandleEventFunction, + nsIDeviceContext *aContext, nsIAppShell *aAppShell, + nsWidgetInitData *aInitData, HWND hwndO) +{ + if( aInitData && aInitData->mBorderStyle == eBorderStyle_BorderlessTopLevel) + { + // Untested hackery for (eg.) drop-downs on gfx-drawn comboboxes + // + // * Examine the window-type field in any init data. + // * If this is set to 'borderless top-level' then + // * Parent window to desktop + // * Owner window to the frame of the xptoolkit parent + // * Record xptoolkit parent because coordinates are relative to it. + // * Pray that gecko will close the popup before trying to scroll content! + + mIsTLB = TRUE; + + // Find the frame. + HWND hwndFrame = hwndP; + while( !(FI_FRAME & (ULONG)WinSendMsg( hwndFrame, WM_QUERYFRAMEINFO, 0, 0))) + hwndFrame = WinQueryWindow( hwndFrame, QW_PARENT); + + // Create the window. Parent to desktop, owner to the frame (moving works), + // maintain the xptoolkit parent, which handles coordinate resolution. + nsWindow::RealDoCreate( HWND_DESKTOP, aParent, aRect, + aHandleEventFunction, aContext, + aAppShell, aInitData, hwndFrame); + } + else + { + // just pass thru' + nsWindow::RealDoCreate( hwndP, aParent, aRect, aHandleEventFunction, + aContext, aAppShell, aInitData, hwndO); + } +} + +// Need to override this because the coords passed in are in OS/2 space but +// relative to the xptoolkit parent. + +BOOL nsCanvas::SetWindowPos( HWND ib, long x, long y, + long cx, long cy, ULONG flags) +{ + POINTL ptl = { x, y }; + if( mIsTLB) + WinMapWindowPoints( (HWND) mParent->GetNativeData(NS_NATIVE_WIDGET), + HWND_DESKTOP, &ptl, 1); + return nsWindow::SetWindowPos( ib, ptl.x, ptl.y, cx, cy, flags); +} + +PRBool nsCanvas::OnReposition( PSWP pSwp) +{ + PRBool rc = PR_FALSE; + + if( mIsTLB) + { + if( pSwp->fl & SWP_MOVE && !(pSwp->fl & SWP_MINIMIZE)) + rc = OnMove( pSwp->x, gModuleData.szScreen.cy - pSwp->y - pSwp->cy); + if( pSwp->fl & SWP_SIZE && !(pSwp->fl & SWP_MINIMIZE)) + rc = OnResize( pSwp->cx, pSwp->cy); + } + else + rc = nsWindow::OnReposition( pSwp); + + return rc; +} + +PRBool nsCanvas::OnPaint() +{ + PRBool rc = PR_FALSE; + + if( mContext && (mEventCallback || mEventListener)) + { + // Get rect to redraw and validate window +#if 0 + RECTL rcl; + WinQueryUpdateRect( mWnd, &rcl); + WinValidateRect( mWnd, &rcl, TRUE); + + if( rcl.xLeft || rcl.xRight || rcl.yBottom || rcl.yTop) + { + // build XP rect from in-ex window rect + nsRect rect; + rect.x = rcl.xLeft; + rect.y = GetClientHeight() - rcl.yTop; + rect.width = rcl.xRight - rcl.xLeft; + rect.height = rcl.yTop - rcl.yBottom; + + // build & dispatch paint event + nsPaintEvent event; + InitEvent( event, NS_PAINT); + event.rect = ▭ + event.eventStructType = NS_PAINT_EVENT; + event.renderingContext = GetRenderingContext(); + rc = DispatchEventInternal( &event); + + NS_RELEASE( event.renderingContext); + } +#else + RECTL rcl = { 0 }; + HPS thePS = (HPS) GetNativeData( NS_NATIVE_GRAPHIC); + thePS = WinBeginPaint( mWnd, thePS, &rcl); + + if( rcl.xLeft || rcl.xRight || rcl.yBottom || rcl.yTop) + { + // build XP rect from in-ex window rect + nsRect rect; + rect.x = rcl.xLeft; + rect.y = GetClientHeight() - rcl.yTop; + rect.width = rcl.xRight - rcl.xLeft; + rect.height = rcl.yTop - rcl.yBottom; + + // build & dispatch paint event + nsPaintEvent event; + InitEvent( event, NS_PAINT); + event.rect = ▭ + event.eventStructType = NS_PAINT_EVENT; + event.renderingContext = GetRenderingContext(); + rc = DispatchEventInternal( &event); + + NS_RELEASE( event.renderingContext); + } + + WinEndPaint( thePS); + FreeNativeData( (void*)thePS, NS_NATIVE_GRAPHIC); +#endif + } + + return rc; +} + +// Realize-palette. I reckon only top-level windows get the message, so +// there's code in frame to broadcast it to children. +PRBool nsCanvas::OnRealizePalette() +{ + PRBool rc = PR_FALSE; + + // Get palette info from device + nsPaletteInfo palInfo; + mContext->GetPaletteInfo( palInfo); + + if( mPS && palInfo.isPaletteDevice && palInfo.palette) + { + // An onscreen nsDrawingSurface has been created for the window, + // and we have a palette. So realize it. + ULONG cclr; + long palrc = WinRealizePalette( mWnd, mPS, &cclr); + if( palrc && palrc != PAL_ERROR) + // Colours have changed, redraw. + WinInvalidateRect( mWnd, 0, FALSE); + + rc = PR_TRUE; + } + + return rc; +} + +PRBool nsCanvas::OnKey( MPARAM mp1, MPARAM mp2) +{ + nsWindow::OnKey( mp1, mp2); + return PR_TRUE; // Gecko doesn't expect unhandled events to propagate +} + +extern BOOL g_bHandlingMouseClick; + +PRBool nsCanvas::DispatchMouseEvent( PRUint32 msg, int clickcount, + MPARAM mp1, MPARAM mp2) +{ + PRBool rc = PR_FALSE; + + // Stop multiple messages for the same PM action + if( g_bHandlingMouseClick) + return rc; + + // Don't capture mb2 so that drag'n'drop works. + + if( mEventCallback || mMouseListener) + { + switch( msg) + { + case NS_MOUSE_LEFT_BUTTON_DOWN: + case NS_MOUSE_MIDDLE_BUTTON_DOWN: + WinSetCapture( HWND_DESKTOP, mWnd); + break; + + case NS_MOUSE_LEFT_BUTTON_UP: + case NS_MOUSE_MIDDLE_BUTTON_UP: + WinSetCapture( HWND_DESKTOP, 0); // release + break; + + default: + break; + } + rc = nsWindow::DispatchMouseEvent( msg, clickcount, mp1, mp2); + } + +// Mousemove messages mustn't propagate to get cursors working. Try commenting +// this block out & then move the mouse over a link. + + if( msg == NS_MOUSE_MOVE) + rc = PR_TRUE; + + return rc; +} + +// Creation hooks +static BOOL bRegistered; +PCSZ nsCanvas::WindowClass() +{ + if( !bRegistered) + { + BOOL rc = WinRegisterClass( 0 /*hab*/, NSCANVASCLASS, + WinDefWindowProc, 0, 4); + NS_ASSERTION(rc, "Couldn't register canvas class"); + bRegistered = TRUE; + } + + return (PCSZ) NSCANVASCLASS; +} + +ULONG nsCanvas::WindowStyle() +{ + return BASE_CONTROL_STYLE | WS_CLIPCHILDREN; +} diff --git a/mozilla/widget/src/os2/nsCanvas.h b/mozilla/widget/src/os2/nsCanvas.h new file mode 100644 index 00000000000..e1461f763aa --- /dev/null +++ b/mozilla/widget/src/os2/nsCanvas.h @@ -0,0 +1,60 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nscanvas_h +#define _nscanvas_h + +// nscanvas - this is the NS_CHILD_CID class which contains content. +// The main code added in here is to do painting. + +#include "nswindow.h" + +class nsCanvas : public nsWindow +{ + public: + nsCanvas(); + + protected: + // So we can do the right thing for 'top-level borderless' widgets (popups) + virtual void RealDoCreate( HWND hwndP, nsWindow *aParent, + const nsRect &aRect, + EVENT_CALLBACK aHandleEventFunction, + nsIDeviceContext *aContext, + nsIAppShell *aAppShell, + nsWidgetInitData *aInitData, + HWND hwndOwner); + + virtual BOOL SetWindowPos( HWND hwndInsertBehind, long x, long y, + long cx, long cy, unsigned long flags); + + virtual PRBool OnReposition( PSWP pSwp); + virtual PRBool OnPaint(); + virtual PRBool OnKey( MPARAM mp1, MPARAM mp2); + virtual PRBool OnRealizePalette(); + virtual PRBool DispatchMouseEvent( PRUint32 msg, int clickcount, + MPARAM mp1, MPARAM mp2); + virtual PCSZ WindowClass(); + virtual ULONG WindowStyle(); + + BOOL mIsTLB; +}; + +#endif diff --git a/mozilla/widget/src/os2/nsCheckButton.cpp b/mozilla/widget/src/os2/nsCheckButton.cpp new file mode 100644 index 00000000000..f2b0370fc29 --- /dev/null +++ b/mozilla/widget/src/os2/nsCheckButton.cpp @@ -0,0 +1,69 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// Check button control + +#include "nsCheckButton.h" + +// XP-com +NS_IMPL_ADDREF(nsCheckButton) +NS_IMPL_RELEASE(nsCheckButton) + +nsresult nsCheckButton::QueryInterface( const nsIID &aIID, void **aInstancePtr) +{ + nsresult result = nsWindow::QueryInterface( aIID, aInstancePtr); + + if( result == NS_NOINTERFACE && aIID.Equals( nsICheckButton::GetIID())) + { + *aInstancePtr = (void*) ((nsICheckButton*)this); + NS_ADDREF_THIS(); + result = NS_OK; + } + + return result; +} + +NS_IMPL_LABEL(nsCheckButton) + +// checked-ness +nsresult nsCheckButton::GetState( PRBool &aState) +{ + MRESULT rc = mOS2Toolkit->SendMsg( mWnd, BM_QUERYCHECK); + aState = SHORT1FROMMR(rc); + return NS_OK; +} + +nsresult nsCheckButton::SetState( const PRBool aState) +{ + mOS2Toolkit->SendMsg( mWnd, BM_SETCHECK, MPFROMLONG(aState)); + return NS_OK; +} + +// Creation hooks +PCSZ nsCheckButton::WindowClass() +{ + return WC_BUTTON; +} + +ULONG nsCheckButton::WindowStyle() +{ + return BASE_CONTROL_STYLE | BS_CHECKBOX; +} diff --git a/mozilla/widget/src/os2/nsCheckButton.h b/mozilla/widget/src/os2/nsCheckButton.h new file mode 100644 index 00000000000..ea979c7ac9d --- /dev/null +++ b/mozilla/widget/src/os2/nsCheckButton.h @@ -0,0 +1,59 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsCheckButton_h +#define _nsCheckButton_h + +#include "nsWindow.h" +#include "nsICheckButton.h" + +// WC_BUTTON, BS_CHECKBUTTON wrapper for NS_CHECKBUTTON_CID +// +// !! Really want to share code with (at least) nsRadioButton, but there's +// !! so little of it a `nsBaseSelectionButton' seems like overkill. +// !! Maybe if this 'GetPreferredSize' thing get's going it would be better. + +class nsCheckButton : public nsWindow, public nsICheckButton +{ + public: + nsCheckButton() {} + + // nsISupports + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(void); + NS_IMETHOD_(nsrefcnt) Release(void); + + // nsICheckButton + NS_DECL_LABEL + NS_IMETHOD GetState( PRBool &aState); + NS_IMETHOD SetState( const PRBool aState); + + protected: + // message stopping + virtual PRBool OnMove( PRInt32 aX, PRInt32 aY) { return PR_FALSE; } + virtual PRBool OnResize( PRInt32 aX, PRInt32 aY) { return PR_FALSE; } + + // Creation hooks + virtual PCSZ WindowClass(); + virtual ULONG WindowStyle(); +}; + +#endif diff --git a/mozilla/widget/src/os2/nsClipboard.cpp b/mozilla/widget/src/os2/nsClipboard.cpp new file mode 100644 index 00000000000..24efa99e5de --- /dev/null +++ b/mozilla/widget/src/os2/nsClipboard.cpp @@ -0,0 +1,255 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include "nsClipboard.h" +#include "nsVoidArray.h" + +#include // for UniStrlen + +// The relation between mozilla's mime formats and those understood by the +// clipboard is a little hazy, mostly in the areas of images. +// +// Could be a lot cleverer & use delayed rendering or something to provide +// a consumer with text when what we've got is unicode, or whatever. + +// Okay, I'm not entirely sure why I did this in this way; it just sortof grew +// like this... + +typedef PRUint32 (*ImportDataFn)( void *pData, void **pDataOut); +typedef PRUint32 (*ExportDataFn)( void *pDataIn, PRUint32 cData, void *pBuffer); + +struct FormatRecord +{ + const char *szMimeType; + ULONG ulClipboardFmt; + const char *szFmtName; + ImportDataFn pfnImport; + ExportDataFn pfnExport; +}; + +// scaffolding +nsClipboard::nsClipboard() +{} + +nsClipboard::~nsClipboard() +{} + +nsresult nsClipboard::SetNativeClipboardData() +{ + return DoClipboardAction( nsClipboard::Write); +} + +nsresult nsClipboard::GetNativeClipboardData( nsITransferable *aTransferable) +{ + nsITransferable *tmp = mTransferable; + mTransferable = aTransferable; + nsresult rc = DoClipboardAction( nsClipboard::Read); + mTransferable = tmp; + return rc; +} + +// Native clipboard. +// +// We do slightly odd things in order to store the length of the data +// in the object: for non textual data, the first 4 bytes is an ULONG +// containing the length of the REST of the data. May change this. +// + + +// Get some data from the clipboard +void nsClipboard::GetClipboardData( nsString *aFlavour) +{ + FormatRecord *pRecord; + ULONG ulFmt = GetFormatID( aFlavour, &pRecord); + PULONG pData = (PULONG) WinQueryClipbrdData( 0/*hab*/, ulFmt); + + if( pData) + { + PRUint32 cbData = pRecord->pfnImport( pData, (void**) &pData); + + // XXX any guesses how we could decode a HBITMAP into gif/png/jpeg data?? + // + // We have libpng ready to use, which is well documented & configurable. + // It should be easy to write a routine to convert a bitmap directly to + // an in-memory buffer as required here. + // + // http://www.physik.fu-berlin.de/edv_docu/documentation/libpng/libpng.txt + + // unfortunately we need to copy the data because the transferable + // needs to be able to delete [] it. + PRUint8 *pMozData = new PRUint8 [ cbData ]; + memcpy( pMozData, pData, cbData); + mTransferable->SetTransferData( aFlavour, pMozData, cbData); + } +} + +// Set some data onto the clipboard +void nsClipboard::SetClipboardData( nsString *aFlavour) +{ + void *pMozData = nsnull, *pData = nsnull; + PRUint32 cbMozData = 0, cbData = 0; + + // Get the data from the transferable + mTransferable->GetTransferData( aFlavour, &pMozData, &cbMozData); + + // Figure out how much memory we need to store the native version + FormatRecord *pRecord; + GetFormatID( aFlavour, &pRecord); + cbData = pRecord->pfnExport( pMozData, cbMozData, 0); + + // allocatate some memory to put the data in + APIRET rc = DosAllocSharedMem( &pData, nsnull, cbData, + PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE); + if( !rc) + { + // copy across & pin up. + pRecord->pfnExport( pMozData, cbMozData, pData); + WinSetClipbrdData( 0/*hab*/, (ULONG) pData, + pRecord->ulClipboardFmt, CFI_POINTER); + } +#ifdef DEBUG + else + printf( "DosAllocSharedMem failed, rc %d\n", (int)rc); +#endif +} + +// Go through the flavors in the transferable and either get or set them +nsresult nsClipboard::DoClipboardAction( nsClipboard::ClipboardAction aAction) +{ + nsresult rc = NS_ERROR_FAILURE; + + if( WinOpenClipbrd( 0/*hab*/)) + { + if( aAction == nsClipboard::Write) + WinEmptyClipbrd( 0/*hab*/); + + // Get the list of formats the transferable can handle + nsVoidArray *pFormats = nsnull; + if( aAction == nsClipboard::Read) + mTransferable->FlavorsTransferableCanImport( &pFormats); + else + mTransferable->FlavorsTransferableCanExport( &pFormats); + + PRUint32 cFormats = pFormats->Count(); + + for( PRUint32 i = 0; i < cFormats; i++) + { + nsString *pFlavour = (nsString*) pFormats->ElementAt( i); + if( pFlavour) // just in case + { + if( aAction == nsClipboard::Read) GetClipboardData( pFlavour); + else SetClipboardData( pFlavour); + } + } + + WinCloseClipbrd( 0/*hab*/); + rc = NS_OK; + delete pFormats; + } + + return rc; +} + +// Converters for various types of data + +static PRUint32 Import8Bit( void *pString, void **pOut) +{ + *pOut = pString; + return strlen( (char*) pString); +} + +static PRUint32 Export8Bit( void *pDataIn, PRUint32 cData, void *pBuffer) +{ + if( pBuffer) + { + memcpy( pBuffer, pDataIn, cData); + *(((char*)pBuffer) + cData) = '\0'; + } + return cData + 1; +} + +static PRUint32 Import16Bit( void *pString, void **pOut) +{ + *pOut = pString; + return UniStrlen( (UniChar*) pString) * 2; +} + +static PRUint32 Export16Bit( void *pDataIn, PRUint32 cData, void *pBuffer) +{ + if( pBuffer) + { + memcpy( pBuffer, pDataIn, cData); + *((UniChar*)pBuffer + (cData>>1)) = 0; + } + return cData + sizeof(UniChar); +} + +static PRUint32 ImportBin( void *pData, void **pOut) +{ + *pOut = ((PRUint32*)pData) + 1; + return *(PRUint32*)pData; +} + +static PRUint32 ExportBin( void *pDataIn, PRUint32 cData, void *pBuffer) +{ + if( pBuffer) + { + *((PRUint32*)pBuffer) = cData; + memcpy( (PRUint32*)pBuffer + 1, pDataIn, cData); + } + return cData + sizeof(PRUint32); +} + +static FormatRecord records[] = +{ + { kTextMime, CF_TEXT, 0, Import8Bit, Export8Bit }, + { kUnicodeMime, 0, "CF_UNICODE", Import16Bit, Export16Bit }, + { kHTMLMime, 0, "CF_HTML", Import8Bit, Export8Bit }, + { kXIFMime, 0, "CF_XIF", Import8Bit, Export8Bit }, + { kPNGImageMime, 0, "CF_PNG", ImportBin, ExportBin }, + { kGIFImageMime, 0, "CF_GIF", ImportBin, ExportBin }, + { kJPEGImageMime, 0, "CF_JPEG", ImportBin, ExportBin }, + { kAOLMailMime, 0, "CF_AOLMAIL", Import8Bit, Export8Bit }, + { 0, 0, 0, 0, 0 } +}; + +// get the format ID for a given mimetype +ULONG nsClipboard::GetFormatID( nsString *aMimeStr, FormatRecord **pFmtRec) +{ + ULONG ulFormat = 0; + + const char *pszFmt = gModuleData.ConvertFromUcs( *aMimeStr); + + for( FormatRecord *pRecord = records; pRecord->szMimeType; pRecord++) + if( !strcmp( pRecord->szMimeType, pszFmt)) + { + if( !pRecord->ulClipboardFmt) + // create an atom for the format + pRecord->ulClipboardFmt = gModuleData.GetAtom( pRecord->szFmtName); + ulFormat = pRecord->ulClipboardFmt; + *pFmtRec = pRecord; + break; + } + + NS_ASSERTION(ulFormat, "Clipboard beseiged by unknown mimetype"); + + return ulFormat; +} diff --git a/mozilla/widget/src/os2/nsClipboard.h b/mozilla/widget/src/os2/nsClipboard.h new file mode 100644 index 00000000000..d014d76bde8 --- /dev/null +++ b/mozilla/widget/src/os2/nsClipboard.h @@ -0,0 +1,55 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsClipboard_h +#define _nsClipboard_h + +#include "nsWidgetDefs.h" +#include "nsBaseClipboard.h" + +// Clipboard service. + +struct FormatRecord; + +class nsClipboard : public nsBaseClipboard +{ + public: + nsClipboard(); + virtual ~nsClipboard(); + + protected: + // nsBaseClipboard + NS_IMETHOD SetNativeClipboardData(); + NS_IMETHOD GetNativeClipboardData( nsITransferable *aTransferable); + + enum ClipboardAction + { + Read, + Write + }; + + ULONG GetFormatID( nsString *aMimeStr, FormatRecord **ppRecord); + void GetClipboardData( nsString *aFlavour); + void SetClipboardData( nsString *aFlavour); + nsresult DoClipboardAction( ClipboardAction aAction); +}; + +#endif diff --git a/mozilla/widget/src/os2/nsComboBox.cpp b/mozilla/widget/src/os2/nsComboBox.cpp new file mode 100644 index 00000000000..e50d4e4d888 --- /dev/null +++ b/mozilla/widget/src/os2/nsComboBox.cpp @@ -0,0 +1,111 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include "nscombobox.h" + +// WC_COMBOBOX wrapper. Hackery present in nsWindow to enable user to just +// talk about the height of the entryfield portion. This may well not work +// because the combobox will size it on its own. Oh well, can be worked on. + +NS_IMPL_ADDREF(nsComboBox) +NS_IMPL_RELEASE(nsComboBox) + +nsresult nsComboBox::QueryInterface( const nsIID &aIID, void **aInstancePtr) +{ + if( aIID.Equals( nsIComboBox::GetIID())) + { + *aInstancePtr = (void*) ((nsIComboBox*)this); + NS_ADDREF_THIS(); + return NS_OK; + } + else if( aIID.Equals( nsIListWidget::GetIID())) + { + *aInstancePtr = (void*) ((nsIListWidget*)this); + NS_ADDREF_THIS(); + return NS_OK; + } + + return nsWindow::QueryInterface( aIID,aInstancePtr); +} + +nsComboBox::nsComboBox() : mDropdown(60), mEntry(gModuleData.lHtEntryfield) +{} + +nsresult nsComboBox::PreCreateWidget( nsWidgetInitData *aInitData) +{ + if( aInitData != nsnull) + { + // remember the dropdown height + nsComboBoxInitData *comboData = (nsComboBoxInitData*) aInitData; + mDropdown = comboData->mDropDownHeight; + } + return NS_OK; +} + +PRBool nsComboBox::OnPresParamChanged( MPARAM mp1, MPARAM mp2) +{ + if( LONGFROMMP(mp1) == PP_FONTNAMESIZE) + { + // reget height of entryfield + SWP swp; + WinQueryWindowPos( WinWindowFromID( mWnd, CBID_EDIT), &swp); + mEntry = swp.cy + 6; // another magic number... + } + + return PR_FALSE; +} + +PRInt32 nsComboBox::GetHeight( PRInt32 aProposedHeight) +{ +// See layout/html/forms/src/nsSelectControlFrame.cpp +// return aProposedHeight + mDropdown; + return mDropdown + mEntry; +} + +nsresult nsComboBox::GetBounds( nsRect &aRect) +{ + aRect.x = mBounds.x; + aRect.y = mBounds.y; + aRect.width = mBounds.width; + aRect.height = mEntry; + + return NS_OK; +} + +nsresult nsComboBox::GetClientBounds( nsRect &aRect) +{ + aRect.x = 0; + aRect.y = 0; + aRect.width = mBounds.width; + aRect.height = mEntry; + + return NS_OK; +} + +PCSZ nsComboBox::WindowClass() +{ + return WC_COMBOBOX; +} + +ULONG nsComboBox::WindowStyle() +{ + return CBS_DROPDOWNLIST | BASE_CONTROL_STYLE; +} diff --git a/mozilla/widget/src/os2/nsComboBox.h b/mozilla/widget/src/os2/nsComboBox.h new file mode 100644 index 00000000000..2184e3d5a12 --- /dev/null +++ b/mozilla/widget/src/os2/nsComboBox.h @@ -0,0 +1,65 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nscombobox_h +#define _nscombobox_h + +#include "nsWindow.h" +#include "nsBaseList.h" +#include "nsIComboBox.h" + +// WC_COMBOBOX wrapper for NS_COMBOBOX_CID + +class nsComboBox : public nsWindow, public nsIComboBox, + public nsBaseList, public nsIListWidget +{ + public: + nsComboBox(); + + // nsISupports + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(void); + NS_IMETHOD_(nsrefcnt) Release(void); + + // baselist + DECL_BASE_LIST_METHODS + + // platform hooks + virtual PCSZ WindowClass(); + virtual ULONG WindowStyle(); + virtual PRInt32 GetHeight( PRInt32 aHeight); + NS_IMETHOD PreCreateWidget( nsWidgetInitData *aInitData); + + // Message stopping + virtual PRBool OnMove( PRInt32 aX, PRInt32 aY) { return PR_FALSE; } + virtual PRBool OnResize( PRInt32 aX, PRInt32 aY) { return PR_FALSE; } + + // Hacks to pretend we're the size of our entryfield part + NS_IMETHOD GetBounds( nsRect &aRect); + NS_IMETHOD GetClientBounds( nsRect &aRect); + virtual PRBool OnPresParamChanged( MPARAM mp1, MPARAM mp2); + + protected: + PRInt32 mDropdown; + PRInt32 mEntry; +}; + +#endif diff --git a/mozilla/widget/src/os2/nsContextMenu.cpp b/mozilla/widget/src/os2/nsContextMenu.cpp new file mode 100644 index 00000000000..955d747a243 --- /dev/null +++ b/mozilla/widget/src/os2/nsContextMenu.cpp @@ -0,0 +1,224 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// popup context menu + +#include "nsContextMenu.h" +#include "nsWindow.h" +#include "nsCOMPtr.h" + +// Can't WinQueryWindowRect() on menu before popping up... +static void CalcMenuSize( HWND hwnd, PSIZEL szl); + +NS_IMPL_ADDREF(nsContextMenu) +NS_IMPL_RELEASE(nsContextMenu) + +nsresult nsContextMenu::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if( !aInstancePtr) + return NS_ERROR_NULL_POINTER; + + *aInstancePtr = 0; + + if( aIID.Equals(nsIContextMenu::GetIID())) + { + *aInstancePtr = (void*) ((nsIContextMenu*) this); + NS_ADDREF_THIS(); + return NS_OK; + } + if( aIID.Equals(nsIMenuListener::GetIID())) + { + *aInstancePtr = (void*) ((nsIMenuListener*)this); + NS_ADDREF_THIS(); + return NS_OK; + } + if( aIID.Equals(((nsISupports*)(nsIContextMenu*)this)->GetIID())) + { + *aInstancePtr = (void*) ((nsISupports*) ((nsIContextMenu*)this)); + NS_ADDREF_THIS(); + return NS_OK; + } + + return NS_NOINTERFACE; +} + +nsContextMenu::nsContextMenu() : mOwner(nsnull), mX(0), mY(0), mShowing(PR_FALSE) +{ + NS_INIT_REFCNT(); +} + +nsContextMenu::~nsContextMenu() +{ +} + +// Well, not real sure what kind of window we've got here. +nsresult nsContextMenu::Create( nsISupports *aParent, + const nsString &str1, const nsString &str2) +{ + nsresult rc = NS_ERROR_FAILURE; + nsCOMPtr pWidget = do_QueryInterface(aParent); + + if( pWidget) + { + HWND wnd = (HWND) pWidget->GetNativeData( NS_NATIVE_WIDGET); + mOwner = NS_HWNDToWindow(wnd); + + if( !mOwner) + rc = NS_ERROR_NULL_POINTER; + else + { + nsToolkit *pToolkit = (nsToolkit*) pWidget->GetToolkit(); + + nsMenuBase::Create( wnd, pToolkit); + NS_RELEASE(pToolkit); + + rc = NS_OK; + } + } + + mAlignment = str1; + mAnchor = str2; + + return rc; +} + +nsresult nsContextMenu::GetParent( nsISupports *&aParent) +{ + NS_IF_RELEASE(aParent); + aParent = mOwner; + NS_IF_ADDREF(mOwner); + return NS_OK; +} + +nsresult nsContextMenu::SetLocation( PRInt32 aX, PRInt32 aY) +{ + mX = aX; + mY = aY; + return NS_OK; +} + +// nsIMenuListener specialization for + +// Called to display the menu: update the DOM tree & then pop up the menu +nsEventStatus nsContextMenu::MenuSelected( const nsMenuEvent &aMenuEvent) +{ + // Bail if we're already up. This happens for complicated reasons. + if( mShowing) return nsEventStatus_eIgnore; + + // Call superclass method to build the menu + nsDynamicMenu::MenuSelected( aMenuEvent); + + // The coords we have are relative to the desktop. Convert to PM. + POINTL ptl = { mX, mY }; + ptl.y = gModuleData.szScreen.cy - ptl.y - 1; + + // Now look at the "popupalign" attribute to see what corner of the popup + // should go at this location. + // (see http://www.mozilla.org/xpfe/xptoolkit/popups.html) + SIZEL szMenu; + CalcMenuSize( mWnd, &szMenu); + + if( mAlignment == "topleft") // most common case + ptl.y -= szMenu.cy; + else if( mAlignment == "bottomright") + ptl.x -= szMenu.cx; + else if( mAlignment == "topright") + { + ptl.x -= szMenu.cx; + ptl.y -= szMenu.cy; + } + + mShowing = TRUE; + + // Tell owner we're up so it can dispatch our commands. + mOwner->SetContextMenu( this); + + WinPopupMenu( HWND_DESKTOP, + (HWND) mOwner->GetNativeData( NS_NATIVE_WIDGET), + mWnd, + ptl.x, ptl.y, + 0, + PU_HCONSTRAIN | PU_VCONSTRAIN | PU_NONE | + PU_KEYBOARD | PU_MOUSEBUTTON1 | PU_MOUSEBUTTON2); + + // Because XPFE is Really Great, this is meant to be synchronous. Oh yes. + // + // XXX this loop is WRONG if there is a ``modal dialog'' showing. + +#if 0 + nsIAppShell *pAppShell; + NS_CreateAppShell( &pAppShell); +#endif + + // Guess we ought to get appshell in on the act -- we can get + // the current appshell using NS_GetAppShell() or something, and it + // knows if there's a modal loop 'cos it's smart :-). + // Add a method to the appshell to 'process contextmenu' or something. + // + QMSG qmsg; + BOOL rc; + + while( mShowing) + { + rc = WinGetMsg( 0, &qmsg, 0, 0, 0); + if( qmsg.msg == WM_USER) break; // menu is done, leave loop. + WinDispatchMsg( 0, &qmsg); + } + + mOwner->SetContextMenu(0); + + mShowing = PR_FALSE; + + return nsEventStatus_eIgnore; +} + +nsEventStatus nsContextMenu::MenuDeselected( const nsMenuEvent &aMenuEvent) +{ + // terminate modal loop from popup method + if( mShowing) + { + WinPostQueueMsg( HMQ_CURRENT, WM_USER, 0, 0); + } + return nsEventStatus_eIgnore; +} + +// Can't WinQueryWindowRect() on menu before popping up... +void CalcMenuSize( HWND hwnd, PSIZEL szl) +{ + SHORT sItems = (SHORT) WinSendMsg( hwnd, MM_QUERYITEMCOUNT, 0, 0); + + memset( szl, 0, sizeof(SIZEL)); + + for( SHORT i = 0; i < sItems; i++) + { + SHORT sID = (SHORT) WinSendMsg( hwnd, MM_ITEMIDFROMPOSITION, + MPFROMSHORT(i), 0); + RECTL rclItem; + + WinSendMsg( hwnd, MM_QUERYITEMRECT, MPFROM2SHORT(sID,0), MPFROMP(&rclItem)); + LONG lWidth = rclItem.xRight - rclItem.xLeft; + if( lWidth > szl->cx) szl->cx = lWidth; + szl->cy += (rclItem.yTop - rclItem.yBottom); + } + + // Fudge-factor + szl->cy += WinQuerySysValue( HWND_DESKTOP, SV_CYSIZEBORDER); +} diff --git a/mozilla/widget/src/os2/nsContextMenu.h b/mozilla/widget/src/os2/nsContextMenu.h new file mode 100644 index 00000000000..67bafe0cc31 --- /dev/null +++ b/mozilla/widget/src/os2/nsContextMenu.h @@ -0,0 +1,62 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nscontextmenu_h +#define _nscontextmenu_h + +#include "nsIContextMenu.h" +#include "nsMenuBase.h" + +class nsWindow; + +// Pop-up menu + +class nsContextMenu : public nsIContextMenu, public nsDynamicMenu +{ + public: + nsContextMenu(); + virtual ~nsContextMenu(); + + // nsISupports + NS_DECL_ISUPPORTS + + // nsIContextMenu extras + NS_IMETHOD Create( nsISupports *aParent, + const nsString &str1, const nsString &str2); + NS_IMETHOD GetParent( nsISupports *&aParent); + NS_IMETHOD SetLocation( PRInt32 aX, PRInt32 aY); + + // nsIMenuListener overrides + nsEventStatus MenuSelected( const nsMenuEvent &aMenuEvent); + nsEventStatus MenuDeselected( const nsMenuEvent &aMenuEvent); + + // Common methods + DECL_DYNAMIC_MENU_METHODS + + protected: + nsWindow *mOwner; + PRInt32 mX, mY; + PRBool mShowing; + nsString mAnchor; + nsString mAlignment; +}; + +#endif diff --git a/mozilla/widget/src/os2/nsDeviceContextSpecFactoryO.cpp b/mozilla/widget/src/os2/nsDeviceContextSpecFactoryO.cpp new file mode 100644 index 00000000000..f97931efa2e --- /dev/null +++ b/mozilla/widget/src/os2/nsDeviceContextSpecFactoryO.cpp @@ -0,0 +1,68 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// This class is part of the strange printing `architecture'. +// The `CreateDeviceContextSpec' method basically selects a print queue, +// known here as an `nsIDeviceContextSpec'. This is given to a method +// in nsIDeviceContext which creates a fresh device context for that +// printer. + +#include "nsGfxDefs.h" +#include "libprint.h" + +#include "nsDeviceContextSpecFactoryO.h" +#include "nsDeviceContextSpecOS2.h" +#include "nsRegionOS2.h" +#include "nsGfxCIID.h" + +nsDeviceContextSpecFactoryOS2::nsDeviceContextSpecFactoryOS2() +{ + NS_INIT_REFCNT(); +} + +NS_IMPL_ISUPPORTS(nsDeviceContextSpecFactoryOS2, nsIDeviceContextSpecFactory::GetIID()) + +NS_IMETHODIMP nsDeviceContextSpecFactoryOS2::Init() +{ + return NS_OK; +} + +NS_IMETHODIMP nsDeviceContextSpecFactoryOS2::CreateDeviceContextSpec( + nsIDeviceContextSpec *aOldSpec, + nsIDeviceContextSpec *&aNewSpec, + PRBool aQuiet) +{ + nsresult rc = NS_ERROR_FAILURE; + + // This currently ignores aOldSpec. This may be of no consequence... + PRTQUEUE *pq = PrnSelectPrinter( HWND_DESKTOP, aQuiet ? TRUE : FALSE); + + if( pq) + { + nsDeviceContextSpecOS2 *spec = new nsDeviceContextSpecOS2; + NS_ADDREF(spec); + spec->Init( pq); + aNewSpec = spec; + rc = NS_OK; + } + + return rc; +} diff --git a/mozilla/widget/src/os2/nsDeviceContextSpecFactoryO.h b/mozilla/widget/src/os2/nsDeviceContextSpecFactoryO.h new file mode 100644 index 00000000000..6648ca6d3f1 --- /dev/null +++ b/mozilla/widget/src/os2/nsDeviceContextSpecFactoryO.h @@ -0,0 +1,49 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// This class is part of the strange printing `architecture'. +// The `CreateDeviceContextSpec' method basically selects a print queue, +// known here as an `nsIDeviceContextSpec'. This is given to a method +// in nsIDeviceContext which creates a fresh device context for that +// printer. + +#ifndef _nsDeviceContextSpecFactoryOS2_h +#define _nsDeviceContextSpecFactoryOS2_h + +#include "nsIDeviceContextSpecFactory.h" +#include "nsIDeviceContextSpec.h" + +class nsDeviceContextSpecFactoryOS2 : public nsIDeviceContextSpecFactory +{ + public: + nsDeviceContextSpecFactoryOS2(); + + NS_DECL_ISUPPORTS + + NS_IMETHOD Init(); + NS_IMETHOD CreateDeviceContextSpec( nsIDeviceContextSpec *aOldSpec, + nsIDeviceContextSpec *&aNewSpec, + PRBool aQuiet); + protected: + virtual ~nsDeviceContextSpecFactoryOS2() {} +}; + +#endif diff --git a/mozilla/widget/src/os2/nsDeviceContextSpecOS2.cpp b/mozilla/widget/src/os2/nsDeviceContextSpecOS2.cpp new file mode 100644 index 00000000000..7fdf0acb0f7 --- /dev/null +++ b/mozilla/widget/src/os2/nsDeviceContextSpecOS2.cpp @@ -0,0 +1,51 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include "nsGfxDefs.h" +#include "libprint.h" + +#include "nsDeviceContextSpecOS2.h" + +nsDeviceContextSpecOS2::nsDeviceContextSpecOS2() +{ + NS_INIT_REFCNT(); + mQueue = nsnull; +} + +nsDeviceContextSpecOS2::~nsDeviceContextSpecOS2() +{ + if( mQueue) + PrnClosePrinter( mQueue); +} + +NS_IMPL_ISUPPORTS(nsDeviceContextSpecOS2, nsIDeviceContextSpec::GetIID()) + +nsresult nsDeviceContextSpecOS2::Init( PRTQUEUE *pq) +{ + mQueue = pq; + return NS_OK; +} + +nsresult nsDeviceContextSpecOS2::GetPRTQUEUE( PRTQUEUE *&p) +{ + p = mQueue; + return NS_OK; +} diff --git a/mozilla/widget/src/os2/nsDeviceContextSpecOS2.h b/mozilla/widget/src/os2/nsDeviceContextSpecOS2.h new file mode 100644 index 00000000000..1f3e4b92629 --- /dev/null +++ b/mozilla/widget/src/os2/nsDeviceContextSpecOS2.h @@ -0,0 +1,43 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsDeviceContextSpecOS2_h +#define _nsDeviceContextSpecOS2_h + +#include "nsIDeviceContextSpec.h" + +class nsDeviceContextSpecOS2 : public nsIDeviceContextSpec +{ + public: + nsDeviceContextSpecOS2(); + + NS_DECL_ISUPPORTS + + NS_IMETHOD Init( PRTQUEUE *pq); + NS_IMETHOD GetPRTQUEUE( PRTQUEUE *&p); + + protected: + virtual ~nsDeviceContextSpecOS2(); + + PRTQUEUE *mQueue; +}; + +#endif diff --git a/mozilla/widget/src/os2/nsDirPicker.cpp b/mozilla/widget/src/os2/nsDirPicker.cpp new file mode 100644 index 00000000000..75ba0b3016d --- /dev/null +++ b/mozilla/widget/src/os2/nsDirPicker.cpp @@ -0,0 +1,540 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// To do +// * Use the correct icons on drives +// This requires beefing up DosIsRemovable() from FSTree.cpp to a +// general 'DosQueryDriveType', and providing a handy array of icons +// in the resource module, OR doing something funky with the WPS. +// +// * Helptext +// +// (dialog is usable at this point; those below are just for bonus points) +// +// * Make dialog resizable +// Just requires coding. +// +// * Add a 1-pixel bevel-in border around the container +// +// * When user supplies a pathname in their DIRPICKER, hilight it in +// the tree. This is a bit hard 'cos of asynchronous FSTree. Maybe +// should fix that to allow "synchronous calls", so Expand() and Trash() +// would have completed by the time they return (easy). +// +// * Save preferences (cnr colour, dialog position & size) somewhere +// +// * Directory history (replace typein at bottom with an entryfield) +// +// * More options? Subclassing? + +#define INCL_WIN +#define INCL_DOS +#define INCL_DOSERRORS +#include +#include +#include +#include +#include "nsFSTree.h" +#include "resid.h" +#include "nsDirPicker.h" + +// XXX kludges +static HMODULE res_handle; + +// Container records + +struct TREENODE +{ + MINIRECORDCORE m; + FS::IDir *pDir; +}; + +typedef TREENODE *PTREENODE; + +#define DIR2REC(dir) ((PTREENODE)dir->GetFileInfo()->GetUserData()) + +static void insertTree( HWND hwndCnr, PTREENODE pParent, PTREENODE pRecord, + PRECORDINSERT pRI); + +APIRET DosReallyCreateDir( PSZ dirpath); + +void CenterWindow( HWND hwnd, HWND hwndOver); + +// Window-word data for the dialog; implement fs callbacks to dynamically +// build the tree (and stuff) + +struct DirPicker : public FS::ICallbacks +{ + HWND hwndDlg; + HWND hwndCnr; + HWND hwndCBox; + HWND hwndEf; + FS::ITreeBuilder *fsTree; + FS::IDir *pMetaNode; + BOOL initted; + PTREENODE pCurrRoot; + PDIRPICKER pDirPicker; + HPOINTER icoFolder; + + DirPicker( HWND dlg, PDIRPICKER aPicker) : hwndDlg(dlg), pMetaNode(0), + initted(FALSE), pCurrRoot(0), + pDirPicker(aPicker) + { + hwndCnr = WinWindowFromID( hwndDlg, IDD_TREECNR); + hwndCBox = WinWindowFromID( hwndDlg, IDD_CBDRIVES); + hwndEf = WinWindowFromID( hwndDlg, IDD_EFPATH); + fsTree = FS::CreateTreeBuilder(); + fsTree->Init( this); + fsTree->RequiresPM( TRUE); + icoFolder = WinLoadPointer( HWND_DESKTOP, res_handle, ID_ICO_FOLDER); + } + + virtual ~DirPicker() + { + WinDestroyPointer( icoFolder); + } + + void CreateRoot( FS::IDir *aRootNode) + { + pMetaNode = aRootNode; + } + + void CreateDir( FS::IDir *aNewNode) + { + // Create a new node + PTREENODE pRec = (PTREENODE) WinSendMsg( hwndCnr, CM_ALLOCRECORD, + MPFROMLONG(4), MPFROMLONG(1)); + // find some strings; note that fstree owns them + pRec->m.pszIcon = (char*) aNewNode->GetFileInfo()->GetLeafName(); + if( aNewNode->AsDrive()) + { + // Now add the drive to the combobox + char listitem[40]; + strcpy( listitem, pRec->m.pszIcon); + PCSZ vollbl = aNewNode->AsDrive()->GetVolumeLabel(); + if( vollbl && *vollbl) + { + strcat( listitem, " ["); + strcat( listitem, vollbl); + strcat( listitem, "]"); + } + MRESULT index = WinSendMsg( hwndCBox, LM_INSERTITEM, + MPFROMSHORT(LIT_END), MPFROMP(listitem)); + WinSendMsg( hwndCBox, LM_SETITEMHANDLE, index, MPFROMP(pRec)); + + // display the current drive first; if the user gave us a seed, we'll + // do that in InitialScanComplete(). + ULONG ulDriveNum, ulDriveMap; + DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap); + char buffer[] = "A:"; + buffer[0] += ulDriveNum - 1; + + // Filter out all but the root of this drive + if( stricmp( pRec->m.pszIcon, buffer)) + pRec->m.flRecordAttr = CRA_FILTERED; + else + { + pCurrRoot = pRec; + WinSendMsg( hwndCBox, LM_SELECTITEM, index, MPFROMSHORT(TRUE)); + } + + // XXX use the right icon + pRec->m.hptrIcon = icoFolder; + } + else + { + PCSZ pcszPathname = aNewNode->GetFileInfo()->GetPathName(); + // don't need to doserror protect this call 'cos we'll only get + // callbacks if the directory has been seen. + pRec->m.hptrIcon = WinLoadFileIcon( pcszPathname, FALSE); + + // once we start getting straight directories, toplevel is done + if( !initted) + { + initted = TRUE; + WinPostMsg( hwndCnr, CM_EXPANDTREE, MPFROMP(pCurrRoot), 0); + } + } + + // Tie up both ways + pRec->pDir = aNewNode; + aNewNode->GetFileInfo()->SetUserData( pRec); + + // Now insert the record into the container + RECORDINSERT rI = { sizeof(RECORDINSERT), (PRECORDCORE) CMA_END, 0, + TRUE, CMA_TOP, 1 }; + // Set parent if appropriate + if( aNewNode->GetParent()->GetParent()) + { + rI.pRecordParent = (PRECORDCORE) DIR2REC(aNewNode->GetParent()); + } + + WinSendMsg( hwndCnr, CM_INSERTRECORD, MPFROMP(pRec), MPFROMP(&rI)); + } + + void DestroyDir( FS::IDir *aNode) + { + if( aNode != pMetaNode) + { + PTREENODE pNode = DIR2REC(aNode); + if( pNode == pCurrRoot) + WinSendMsg( hwndCnr, CM_REMOVERECORD, + MPFROMP(&pNode), MPFROM2SHORT(1, 0)); + WinSendMsg( hwndCnr, CM_FREERECORD, MPFROMP(&pNode), MPFROMSHORT(1)); + } + } + + void InitialScanComplete() + { + // Mismatch between our gui requirements and the way that FSTree provides + // us with data. Really ought to alter FSTree to build drives selectively; + // this would be done + // + // Anyhow, now we know that the initial scan has completed, we can take + // out of the container those drives which have been filtered away. + // They needed to be in the container in order to build the tree. + + FS::IDir *pNode = pMetaNode->GetFirstChild(); + while( pNode) + { + if( pNode != pCurrRoot->pDir) + { + PTREENODE pRecord = DIR2REC(pNode); + WinSendMsg( hwndCnr, CM_REMOVERECORD, + MPFROMP(&pRecord), MPFROM2SHORT(1, 0)); + pRecord->m.flRecordAttr &= ~CRA_FILTERED; + } + + pNode = pNode->GetNextSibling(); + } + + // Now we know where we are. + // If the user has given a seed directory, try & find it (!) + if( pDirPicker->szFullFile[0]) + { + // XXX write me + } + } + + void CreateFile( FS::IFile *aNewLeaf) {} + void DestroyFile( FS::IFile *aLeaf) {} +}; + +MRESULT EXPENTRY fndpDirPicker( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + DirPicker *pData = (DirPicker *) WinQueryWindowPtr( hwnd, QWL_USER); + + switch( msg) + { + case WM_INITDLG: + { + PDIRPICKER pPicker = (PDIRPICKER) mp2; + // create data area & save it away + pData = new DirPicker( hwnd, pPicker); + WinSetWindowPtr( hwnd, QWL_USER, pData); + + // prep window + CenterWindow( hwnd, WinQueryWindow( hwnd, QW_OWNER)); + + // XXX make dynamic, save fontnamesize + WinSetPresParam( hwnd, PP_FONTNAMESIZE, 11, "9.WarpSans"); + // XXX colour for container bg? + // XXX Do help later + WinEnableControl( hwnd, IDD_HELPBUTTON, FALSE); + + // sort out container + CNRINFO cnrInfo = { sizeof(CNRINFO), 0 }; + cnrInfo.flWindowAttr = CV_TREE | CV_ICON | CV_MINI | CA_TREELINE; + WinSendMsg( pData->hwndCnr, CM_SETCNRINFO, + MPFROMP( &cnrInfo), MPFROMLONG( CMA_FLWINDOWATTR)); + WinSetWindowBits( pData->hwndCnr, QWL_STYLE, 0, WS_CLIPSIBLINGS); + + // allow entryfield to be long enough to display a full pathname + WinSendMsg( pData->hwndEf, EM_SETTEXTLIMIT, MPFROMSHORT(CCHMAXPATH), 0); + if( *pPicker->szFullFile) + WinSetWindowText( pData->hwndEf, pPicker->szFullFile); + + if( pPicker->pszTitle) + WinSetWindowText( hwnd, pPicker->pszTitle); + WinShowWindow( hwnd, TRUE); + + // begin scan (returns immediately) + pData->fsTree->Build( FS::Lazy); + + break; + } + + case WM_CONTROL: + switch( SHORT1FROMMP(mp1)) + { + case IDD_TREECNR: + switch( SHORT2FROMMP(mp1)) + { + case CN_EXPANDTREE: + { + PTREENODE pNode = (PTREENODE) mp2; + pNode->pDir->Expand(); + return 0; + } + case CN_ENTER: + { + // Trigger an expand + PNOTIFYRECORDENTER pThing = (PNOTIFYRECORDENTER) mp2; + if( pThing->pRecord) // trap double-click on background + WinPostMsg( pData->hwndCnr, CM_EXPANDTREE, + MPFROMP(pThing->pRecord), 0); + return 0; + } + case CN_EMPHASIS: + { + PNOTIFYRECORDEMPHASIS pThing = (PNOTIFYRECORDEMPHASIS) mp2; + if( pThing->fEmphasisMask & CRA_SELECTED) + { + PTREENODE pNode = (PTREENODE) pThing->pRecord; + // check this node has GAINED not LOST selection + if( pNode->m.flRecordAttr & CRA_SELECTED) + { + // set path into entryfield, specialcase root dirs + // to get the backslash + char buffer[4] = "A:\\"; + char *pname = + (char*) pNode->pDir->GetFileInfo()->GetPathName(); + if( pNode->pDir->AsDrive()) + { + buffer[0] = pname[0]; + pname = buffer; + } + WinSetWindowText( pData->hwndEf, pname); + } + } + return 0; + } + } + break; + + case IDD_CBDRIVES: + switch( SHORT2FROMMP(mp1)) + { + case CBN_EFCHANGE: + { + // change drives (potentially) + MRESULT index; + index = WinSendMsg( pData->hwndCBox, LM_QUERYSELECTION, + MPFROMSHORT(LIT_FIRST),0); + PTREENODE pNode = (PTREENODE) + WinSendMsg( pData->hwndCBox, LM_QUERYITEMHANDLE, index, 0); + + // actually a change? + if( pNode != pData->pCurrRoot) + { + // remove old drive tree + WinSendMsg( pData->hwndCnr, CM_REMOVERECORD, + MPFROMP(&pData->pCurrRoot), MPFROM2SHORT(1,0)); + + // insert new one + // + // I could have *sworn* that you could insert an entire + // tree just by inserting the root. Unfortunately this + // isn't so :-( + + // Single RI on the stack + RECORDINSERT rI = { sizeof(RECORDINSERT), + (PRECORDCORE) CMA_END, + 0, TRUE, CMA_TOP, 1 }; + + // if the new drive is removable, generate a fresh tree + FS::IDrive *pDrive = pNode->pDir->AsDrive(); + if( pDrive->IsRemovable()) + { + WinSendMsg( pData->hwndCnr, CM_INSERTRECORD, + MPFROMP(pNode), MPFROMP(&rI)); + pNode->pDir->Trash(); + } + else + insertTree( pData->hwndCnr, 0, pNode, &rI); + + pData->pCurrRoot = pNode; + WinPostMsg( pData->hwndCnr, CM_EXPANDTREE, + MPFROMP(pData->pCurrRoot), 0); + } + + return 0; + } + } + break; + } + break; + + case WM_DESTROY: + { + pData->fsTree->DeleteInstance(); + delete pData; + break; + } + + case WM_COMMAND: + switch( SHORT1FROMMP(mp1)) + { + case DID_CANCEL: + case DID_OK: + { + WinQueryWindowText( pData->hwndEf, CCHMAXPATH, + pData->pDirPicker->szFullFile); + pData->pDirPicker->lReturn = SHORT1FROMMP(mp1); + + if( SHORT1FROMMP(mp1) == DID_OK) + { + // Check if directory exists etc. + FILESTATUS3 fs3; + APIRET rc = DosQueryPathInfo( pData->pDirPicker->szFullFile, + FIL_STANDARD, &fs3, sizeof fs3); + if( rc) + { + char msg1[256], buffer[500]; + WinLoadString( 0, res_handle, ID_STR_HMMDIR, 256, msg1); + sprintf( buffer, msg1, pData->pDirPicker->szFullFile); + ULONG ret = WinMessageBox( HWND_DESKTOP, hwnd, buffer, + 0, 0, MB_YESNO | MB_QUERY | + MB_APPLMODAL); + if( ret != MBID_YES) return 0; + else + { + rc = DosReallyCreateDir( pData->pDirPicker->szFullFile); + if( rc) + { + WinLoadString( 0, res_handle, ID_STR_NOCDIR, 256, msg1); + WinMessageBox( HWND_DESKTOP, hwnd, msg1, 0, 0, + MB_OK | MB_ERROR | MB_APPLMODAL); + return 0; + } + } + } + } + + // break out, defdlgproc will close the window. + break; + } + } + break; + + case WM_CLOSE: + WinPostMsg( hwnd, WM_COMMAND, MPFROM2SHORT(DID_CANCEL,0), 0); + return 0; + } + + return WinDefDlgProc( hwnd, msg, mp1, mp2); +} + +// Insert an FSTree tree (DFS, recursive; ought to do iterative magic, or +// at least optimize the 'insert children' case to insert them all at once) +static void insertTree( HWND hwndCnr, PTREENODE pParent, PTREENODE pRecord, + PRECORDINSERT pRI) +{ + // insert this node + pRI->pRecordParent = (PRECORDCORE) pParent; + WinSendMsg( hwndCnr, CM_INSERTRECORD, MPFROMP(pRecord), MPFROMP(pRI)); + + // do each child + FS::IDir *pDir = pRecord->pDir->GetFirstChild(); + while( pDir) + { + insertTree( hwndCnr, pRecord, DIR2REC(pDir), pRI); + pDir = pDir->GetNextSibling(); + } +} + +// Entrypoint +HWND APIENTRY FS_PickDirectory( HWND hwndParent, + HWND hwndOwner, + HMODULE hModResources, + PDIRPICKER pDirPicker) +{ + HWND hwndRet = 0; + + if( pDirPicker) + { + // XXX fix this somehow; FS_SetResourceHandle(), or move whole lot + // XXX into a dll (not for mozilla, tho') + res_handle = hModResources; + + if( pDirPicker->bModal) + { + ULONG rc = WinDlgBox( hwndParent, hwndOwner, + fndpDirPicker, hModResources, + DID_DIRPICKER, pDirPicker); + hwndRet = (rc == DID_ERROR); + } + else + { + hwndRet = WinLoadDlg( hwndParent, hwndOwner, + fndpDirPicker, hModResources, + DID_DIRPICKER, pDirPicker); + } + } + + return hwndRet; +} + +// create all segments in the path +APIRET DosReallyCreateDir( PSZ dirpath) +{ + APIRET rc = 0; + int depth = 0; + char *c; + char buff[CCHMAXPATH]; + + strcpy( buff, dirpath); + + for(;;) + { + rc = DosCreateDir( dirpath, 0); + if( (rc == NO_ERROR && depth == 0) || + (rc && rc != ERROR_PATH_NOT_FOUND)) break; + // if rc = 0 go down a level, else go up a level + if( rc == ERROR_PATH_NOT_FOUND) + { + c = strrchr( buff, '\\'); + if( !c) break; + depth++; + *c = '\0'; + } + else + { + depth--; + buff[ strlen( buff)] = '\\'; + } + } + + return rc; +} + +// Center hwnd over hwndOver +void CenterWindow( HWND hwnd, HWND hwndOver) +{ + SWP swp1, swp2; + if( !hwndOver) hwndOver = HWND_DESKTOP; + + WinQueryWindowPos( hwnd, &swp1); + WinQueryWindowPos( hwndOver, &swp2); + swp1.x = (swp2.cx - swp1.cx) / 2; + swp1.y = (swp2.cy - swp1.cy) / 2; + WinSetWindowPos( hwnd, 0, swp1.x, swp1.y, 0, 0, SWP_MOVE); +} diff --git a/mozilla/widget/src/os2/nsDirPicker.h b/mozilla/widget/src/os2/nsDirPicker.h new file mode 100644 index 00000000000..dee27cd0c65 --- /dev/null +++ b/mozilla/widget/src/os2/nsDirPicker.h @@ -0,0 +1,57 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _dirpicker_h +#define _dirpicker_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* This is an interface to a 'choose directory' dialog which uses the FSTree */ +/* code as a back-end. */ +/* */ +/* It could be expanded to give a 'choose file' dialog along the same lines as */ +/* the one from win32 very easily -- add another container for files, a */ +/* vertical (draggable) split bar to separate the two, add something for file */ +/* types, a little WPS integration and there you go. */ + +typedef struct _DIRPICKER +{ + CHAR szFullFile[CCHMAXPATH]; /* directory picked; may be set on init */ + LONG lReturn; /* button pressed, DID_CANCEL or DID_OK */ + BOOL bModal; /* should the dialog be shown modally */ + PSZ pszTitle; /* title for the dialog */ +} DIRPICKER, *PDIRPICKER; + +/* return: if bModal then return hwnd of dialog or 0 on error */ +/* else TRUE if successful, FALSE on error. */ + +HWND APIENTRY FS_PickDirectory( HWND hwndParent, /* parent for dialog */ + HWND hwndOwner, /* owner for dialog */ + HMODULE hModResources, /* resource module */ + PDIRPICKER pDirPicker); /* running data */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mozilla/widget/src/os2/nsDragService.cpp b/mozilla/widget/src/os2/nsDragService.cpp new file mode 100644 index 00000000000..72fc4b3b5d7 --- /dev/null +++ b/mozilla/widget/src/os2/nsDragService.cpp @@ -0,0 +1,997 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// Drag'n'drop manager + +#include "nsWidgetDefs.h" +#include "nsDragService.h" +#include "nsITransferable.h" +#include "nsIFileListTransferable.h" +#include "nsVoidArray.h" + +#include "nsFileSpec.h" +#include "nsFileStream.h" +#include "nsSpecialSystemDirectory.h" + +#include "resid.h" + +#include // for sscanf +#include // realloc/free + +// +// There are three major cases to consider: +// +// 1. Drag from xptoolkit to non-xptoolkit +// +// Use DRM_OS2FILE. Source render to get right rf used. +// +// 2. Drag from xptoolkit to xptoolkit +// +// Use a custom shared-memory RM; special-case same process +// +// 3. Drag from non-xptoolkit to xptoolkit +// +// Use DRM_OS2FILE and create nsFileListTransferable's +// Problem: we need to copy the file because we have no way of knowing +// when client has done with it & we can DM_ENDCONVERSATION +// +// Plus: xptoolkit will eventually acquire text/URL (or text/URI or something) +// which we can handle. +// +// Apart from this, the major thing not implemented is the initiation of +// post-drop conversations for DRM_OS2FILE. This is because of various reasons, +// see comment in nsDragService::DoPushedOS2FILE() below. +// + +// Quick utility class to clean up files we create at some later point... +class nsGCFileSpec : public nsFileSpec +{ + public: + nsGCFileSpec(nsFileSpec &fs) : nsFileSpec(fs) {} + ~nsGCFileSpec() + { + Delete( FALSE); + } +}; + +static char *DecodeStrHandle( HSTR hstr); +static const char *MimeTypeToRF( const char *pcsz); +static const char *RFToMimeType( const char *pcsz); +static BOOL FindFile( PDRAGITEM pItem, nsFileSpec &aFileSpec); +static void GetTempFile( nsFileSpec &tempfile); + +// convert between pm & xptoolkit drag operation types +#define DragOperation(at) \ + (at == nsIDragService::DRAGDROP_ACTION_NONE ? DO_DEFAULT : \ + (at == nsIDragService::DRAGDROP_ACTION_COPY ? DO_COPY : \ + (at == nsIDragService::DRAGDROP_ACTION_MOVE ? DO_MOVE : DO_LINK))) + +#define DragDropAction(do) \ + (do == DO_LINK ? nsIDragService::DRAGDROP_ACTION_LINK : \ + (do == DO_COPY ? nsIDragService::DRAGDROP_ACTION_COPY : \ + nsIDragService::DRAGDROP_ACTION_MOVE)) + +nsDragService::nsDragService() : mDragInfo(0), mDragItems(0) +{ + // XXX temporary icon until xptoolkit realises it needs to give us one + mIcon = WinLoadPointer( HWND_DESKTOP, gModuleData.hModResources, + ID_ICO_DRAGITEM); + + // Window for doing things + mDragWnd = WinCreateWindow( HWND_DESKTOP, WC_STATIC, 0, 0, 0, 0, 0, 0, + HWND_DESKTOP, HWND_BOTTOM, 0, 0, 0); + mWndProc = WinSubclassWindow( mDragWnd, fnwpDragSource); +} + +nsDragService::~nsDragService() +{ + WinDestroyPointer( mIcon); + WinDestroyWindow( mDragWnd); +} + +nsresult nsDragService::InvokeDragSession( nsISupportsArray *aTransArray, + nsIRegion *aRegion, + PRUint32 aActionType) +{ + // This is horribly multidimensional -- we have an array of dragitems, fine. + // But -- each dragitem may be a file list, which itself is several dragitems. + PDRAGITEM pDragItems = 0; + ULONG cDragItems = 0; + + PRUint32 cItems; + aTransArray->Count( &cItems); + for( PRUint32 i = 0; i < cItems; i++) + { + nsCOMPtr pThing; + pThing = dont_AddRef( aTransArray->ElementAt(i)); // XXX check this doesn't leak + if( pThing) + { + // Get dragitems for this array element + nsCOMPtr pXfer = do_QueryInterface(pThing); + PDRAGITEM pDItems = 0; + ULONG cDItems = 0; + + CreateDragItems( &cDItems, &pDItems, pXfer); + + // Now extend & copy up into the local array + pDragItems = (PDRAGITEM) + realloc( pDragItems, cDragItems + cDItems * sizeof(DRAGITEM)); + memcpy( pDragItems + cDragItems, pDItems, cDItems * sizeof(DRAGITEM)); + cDragItems += cDItems; + + // free local data + delete [] pDItems; + } + } + + nsresult rc = NS_ERROR_FAILURE; + + if( cDragItems) + { + rc = InvokeDrag( pDragItems, cDragItems, aActionType); + free( pDragItems); + } + + return rc; +} + +// Even though it says single, it may well be multiple 'cos of the files thing. +nsresult nsDragService::InvokeDragSessionSingle( nsITransferable *aTransferable, + nsIRegion *aRegion, + PRUint32 aActionType) +{ + PDRAGITEM pDragItems = 0; + ULONG cDragItems = 0; + + CreateDragItems( &cDragItems, &pDragItems, aTransferable); + + nsresult rc = NS_ERROR_FAILURE; + + if( cDragItems) + { + rc = InvokeDrag( pDragItems, cDragItems, aActionType); + delete [] pDragItems; + } + + return rc; +} + +nsresult nsDragService::GetData( nsITransferable *aTransferable, + PRUint32 aItemIndex) +{ + // Fill the transferable with data from the given dragitem. + if( !aTransferable || aItemIndex >= mDragInfo->cditem) + return NS_ERROR_FAILURE; + + PDRAGITEM pItem = DrgQueryDragitemPtr( mDragInfo, aItemIndex); + + // Problem here. Unless we're xptoolkit<->xptoolkit we can only + // get data in *one* flavour. + // + // Oh well; do our best. + + nsVoidArray *pFormats = nsnull; + aTransferable->FlavorsTransferableCanImport( &pFormats); + PRUint32 cFormats = pFormats->Count(); + + for( PRUint32 i = 0; i < cFormats; i++) + { + nsString *pFlavour = (nsString*) pFormats->ElementAt( i); + char buff[40]; + gModuleData.ConvertFromUcs( *pFlavour, buff, 40); + const char *rf = MimeTypeToRF( buff); + if( rf && DrgVerifyRMF( pItem, 0, rf)) + { + // Okay, have something to do. Now pick a rendering mechanism: + void *pData = 0; + PRUint32 cData = 0; + + BOOL source_dry_p = FALSE; // can only get single flavour + + // 1. Some xptoolkit - use DRM_MOZILLA + if( DrgVerifyRMF( pItem, "DRM_MOZILLA", 0)) + { + DoMozillaXfer( pItem, buff, &pData, &cData); + } + // 2. Some random process - use DRM_OS2FILE + else if( DrgVerifyRMF( pItem, "DRM_OS2FILE", 0)) + { + // 2a. `normal' rendering - load it, break out + if( pItem->hstrSourceName && pItem->hstrContainerName) + { + nsFileSpec file; + + if( !FindFile( pItem, file)) + printf( "Can't find dropped file\n"); + else + { + cData = file.GetFileSize(); + pData = new char [ cData ]; + nsInputFileStream istream( file); + istream.read( pData, (PRInt32) cData); + istream.close(); + + source_dry_p = TRUE; + } + } + // 2b. DRM_OS2FILE push - faff around endlessly, break out + // This is a bit tricky 'cos this method needs to be synchronous. + else + { + DoPushedOS2FILE( pItem, rf, &pData, &cData); + source_dry_p = TRUE; + } + } + else + { + const char *rmf = DecodeStrHandle( pItem->hstrRMF); + printf( "Incomprehensible DRM (%s)\n", rmf); + } + + if( pData && cData) + aTransferable->SetTransferData( pFlavour, pData, cData); + + if( source_dry_p) + break; + } + else if( pFlavour->Equals( kDropFilesMime)) + { + // Moan if this isn't a filelisttransferable. + nsCOMPtr pFileList = do_QueryInterface(aTransferable); + + if( !pFileList) + printf( "kDropFilesMime requested but no filelisttransferable!\n"); + else + { + // Need a file. + nsFileSpec *pFileSpec = 0; + + if( DrgVerifyRMF( pItem, "DRM_MOZILLA", 0)) + { + void *pData = 0; + PRUint32 cData; + DoMozillaXfer( pItem, buff, &pData, &cData); + + if( pData) + { + nsFileSpec tempfile; + GetTempFile( tempfile); + + nsOutputFileStream stream(tempfile); + stream.write( pData, (PRInt32)cData); + stream.close(); + + // Make sure this temp file is erased eventually. + pFileSpec = new nsGCFileSpec( tempfile); + } + } + // 2. Some random process - use DRM_OS2FILE + else if( DrgVerifyRMF( pItem, "DRM_OS2FILE", 0)) + { + if( pItem->hstrSourceName && pItem->hstrContainerName) + { + nsFileSpec file; + + if( !FindFile( pItem, file)) + printf( "Can't find dropped file\n"); + else + pFileSpec = new nsFileSpec(file); + } + else + { + // (can't actually do source rendering yet) + DoPushedOS2FILE(0,0,0,0); + } + } + else + { + const char *rmf = DecodeStrHandle( pItem->hstrRMF); + printf( "Incomprehensible DRM -> file (%s)\n", rmf); + } + + // Did we get one? + if( pFileSpec) + { + nsVoidArray array; + array.AppendElement(pFileSpec); + pFileList->SetFileList(&array); + } + } + } + } + + return NS_OK; +} + +nsresult nsDragService::GetNumDropItems( PRUint32 *aNumItems) +{ + if( !aNumItems) + return NS_ERROR_NULL_POINTER; + + *aNumItems = mDragInfo->cditem; + + return NS_OK; +} + +nsresult nsDragService::IsDataFlavorSupported( nsString *aDataFlavour) +{ + // The idea here is to return NS_OK if any of the dragitems supports + // this flavour (yeah, hmm...) + // + // Maybe we should change it so they all have to be (which is what CUA + // says we should do...) + + nsresult rc = NS_ERROR_FAILURE; + + char buff[40]; + gModuleData.ConvertFromUcs( *aDataFlavour, buff, 40); + + const char *rf = MimeTypeToRF( buff); + +#ifdef DEBUG + printf( "IsDataFlavorSupported %s\n", buff); + printf( "RF for that is %s\n", rf); +#endif + + if( rf) + { + for( PRUint32 i = 0; i < mDragInfo->cditem; i++) + { + PDRAGITEM pItem = DrgQueryDragitemPtr( mDragInfo, i); + // this checks for ANY rm, which is a bit dubious. + if( DrgVerifyRMF( pItem, 0, rf)) + { + rc = NS_OK; + break; + } + } + } + +#ifdef DEBUG + printf( "Flavor is %ssupported.\n", rc == NS_OK ? "" : "not "); +#endif + + return rc; +} + +// Starting drag-over event block. +void nsDragService::InitDragOver( PDRAGINFO aDragInfo) +{ + // If the drag's from another process, grab it + if( !mDragInfo) + { + DrgAccessDraginfo( aDragInfo); + mDragInfo = aDragInfo; + } + + // Set xp flags + SetCanDrop( PR_FALSE); + SetDragAction( DragDropAction(mDragInfo->usOperation)); + StartDragSession(); +} + +// end of drag-over event block; get xp settings & convert. +MRESULT nsDragService::TermDragOver() +{ + MRESULT rc; + PRBool bCanDrop; + PRUint32 action; + + EndDragSession(); + GetCanDrop( &bCanDrop); + GetDragAction( &action); + + rc = MPFROM2SHORT( bCanDrop ? DOR_DROP : DOR_NODROP, DragOperation(action)); + + // ...factor code... + TermDragExit(); + + return rc; +} + +void nsDragService::InitDragExit( PDRAGINFO aDragInfo) +{ + // Nothing else to do + InitDragOver( aDragInfo); +} + +void nsDragService::TermDragExit() +{ + // release draginfo if appropriate. Note we use the slightly icky way + // of looking at the value of mDragItems to see if we started the drag. + if( !mDragItems) + { + DrgFreeDraginfo( mDragInfo); + mDragInfo = 0; + } +} + +void nsDragService::InitDrop( PDRAGINFO aDragInfo) +{ + // again, doesn't look like there's anything else to do + InitDragOver( aDragInfo); +} + +void nsDragService::TermDrop() +{ + // do an end-conversation for each dragitem. + // Any actual rendering is done in response to the GetData method above. + for( PRUint32 i = 0; i < mDragInfo->cditem; i++) + { + PDRAGITEM pItem = DrgQueryDragitemPtr( mDragInfo, i); + DrgSendTransferMsg( pItem->hwndItem, + DM_ENDCONVERSATION, + MPFROMLONG(pItem->ulItemID), + MPFROMSHORT(DMFL_TARGETSUCCESSFUL)); // I suppose + } + + TermDragExit(); +} + +// access the singleton +nsresult NS_GetDragService( nsISupports **aDragService) +{ + if( !aDragService) + return NS_ERROR_NULL_POINTER; + + *aDragService = (nsIDragService*)gModuleData.dragService; + NS_ADDREF(*aDragService); + + return NS_OK; +} + +// Examine a transferable and allocate & fill in appropriate DRAGITEMs +void nsDragService::CreateDragItems( PULONG pCount, PDRAGITEM *ppItems, + nsITransferable *aTransferable) +{ + nsCOMPtr pFileList = do_QueryInterface(aTransferable); + + if( pFileList) + { + nsVoidArray aFiles; + pFileList->GetFileList( &aFiles); + *pCount = aFiles.Count(); + if( *pCount) + { + // Create a dragitem for each filespec + *ppItems = new DRAGITEM [*pCount]; + for( PRUint32 i = 0; i < *pCount; i++) + { + nsFileSpec *pFile = (nsFileSpec*) aFiles.ElementAt(i); + FillDragItem( *ppItems + i, pFile); + } + } + } + else + { + *ppItems = new DRAGITEM [1]; // alloc w' new [] for uniform deletion + *pCount = 1; + FillDragItem( *ppItems, aTransferable); + } +} + +void nsDragService::FillDragItem( PDRAGITEM aItem, nsFileSpec *aFilespec) +{ + // We don't have to source-render these, 'cos they're unique files which + // already exist (we hope). + // + // On the down side, I have to trust nsFileSpec... + // + + aItem->hwndItem = mDragWnd; // just for completeness + aItem->ulItemID = 0; + aItem->hstrType = DrgAddStrHandle( DRT_UNKNOWN); + // XXX print & discard to come ? Maybe not, actually. + aItem->hstrRMF = DrgAddStrHandle( ""); + + // (this is a really messy, unwieldy api) + nsFileSpec parentDir; + aFilespec->GetParent( parentDir); + aItem->hstrContainerName = DrgAddStrHandle( nsNSPRPath(parentDir)); + char *pszLeaf = aFilespec->GetLeafName(); + aItem->hstrSourceName = DrgAddStrHandle( pszLeaf); + aItem->hstrTargetName = DrgAddStrHandle( pszLeaf); + nsCRT::free( pszLeaf); + + aItem->cxOffset = aItem->cyOffset = 0; + aItem->fsControl = 0; + aItem->fsSupportedOps = DO_COPYABLE | DO_MOVEABLE | DO_LINKABLE; +} + +// Transferables passed in here are guaranteed not to be nsIFileListTransferables +// +void nsDragService::FillDragItem( PDRAGITEM aItem, nsITransferable *aTransferable) +{ + aItem->hwndItem = mDragWnd; + + // ref the transferable to write out the data when we know which is needed + aItem->ulItemID = (ULONG) aTransferable; + NS_ADDREF(aTransferable); + + // Now go through transferable building things + nsVoidArray *pFormats = nsnull; + aTransferable->FlavorsTransferableCanExport( &pFormats); + + // XXX DRM_DISCARD and DRM_PRINTFILE to come when xptoolkit decides how + // (whether...) to handle them + + char rmf[200] = "(DRM_OS2FILE,DRM_MOZILLA) X (DRF_UNKNOWN"; + char buff[40]; + + PRUint32 cFormats = pFormats->Count(); + + for( PRUint32 i = 0; i < cFormats; i++) + { + nsString *pFlavour = (nsString*) pFormats->ElementAt( i); + gModuleData.ConvertFromUcs( *pFlavour, buff, 40); + const char *rf = MimeTypeToRF( buff); + if( rf) + { + strcat( rmf, ","); + strcat( rmf, rf); + } +#if 0 + else if( pFlavour->Equals( kURLMime)) + { + // Abort any processing already done; the idea here is to provide + // the URL format so the WPS can do the Right Thing; we also need to + // provide some kind of text format for insertion into a program. + aItem->hstrType = DrgAddStrHandle( DRT_URL","DRT_TEXT); + aItem->hstrRMF = DrgAddStrHandle( ","); + aItem->hstrContainerName = 0; + aItem->hstrSourceName = DrgAddStrHandle( full url ); + aItem->hstrTargetName = DrgAddStrHandle( title for object ); + aItem->cxOffset = aItem->cyOffset = 0; + aItem->fsControl = 0; + aItem->fsSupportedOps = DO_COPYABLE | DO_MOVEABLE | DO_LINKABLE; + + return; + } +#endif + // Not sure what to do about 'Type'. Setting everything is wrong, + // but picking an arbitary one is also bad. + // + // So leave it as unknown for now. + } + + delete pFormats; + + strcat( rmf, ")"); + + aItem->hstrType = DrgAddStrHandle( DRT_UNKNOWN); + aItem->hstrRMF = DrgAddStrHandle( rmf); + + // For source-rendering, don't supply `source name' + nsSpecialSystemDirectory tmpDir(nsSpecialSystemDirectory::OS_TemporaryDirectory); + aItem->hstrContainerName = DrgAddStrHandle( nsNSPRPath(tmpDir)); + aItem->hstrSourceName = 0; + aItem->hstrTargetName = DrgAddStrHandle( "ATempFile"); + aItem->cxOffset = aItem->cyOffset = 0; // DrgDrag() sets these + aItem->fsControl = 0; + aItem->fsSupportedOps = DO_COPYABLE | DO_MOVEABLE | DO_LINKABLE; +} + + +// Actually do the drag +nsresult nsDragService::InvokeDrag( PDRAGITEM aItems, ULONG aCItems, + PRUint32 aActionType) +{ + // keep track of allocated draginfos + NS_ASSERTION(!mDragInfo,"Drag info leaked"); + + nsresult rc = NS_ERROR_FAILURE; + PDRAGINFO pDragInfo = DrgAllocDraginfo( aCItems); + + if( pDragInfo) + { + pDragInfo->usOperation = DragOperation(aActionType); + pDragInfo->hwndSource = mDragWnd; + for( PRUint32 i = 0; i < aCItems; i++) + DrgSetDragitem( pDragInfo, aItems + i, sizeof(DRAGITEM), i); + + // XXX Need to make a dragimage from somewhere. There ought to be an + // nsIImage passed in here, but let's just make something up for now. + // + // XXX also need to handle the multiple-dragitem case correctly + // + DRAGIMAGE dimage = { sizeof(DRAGIMAGE), 0, mIcon, + { 0, 0 }, DRG_ICON, 0, 0 }; + + // Set draginfo pointer for reentrancy + mDragInfo = pDragInfo; + mDragItems = aCItems; + + HWND hwndDest = DrgDrag( mDragWnd, pDragInfo, &dimage, 1, VK_ENDDRAG, +#ifdef DEBUG + (void*) 0x80000000L // makes IPMD happier +#else + 0 +#endif + ); + rc = NS_OK; // hwndDest == 0 may be error or just cancelled; shrug. + + if( !hwndDest) + { + // Clean up everything here; no async. case to consider. + DrgDeleteDraginfoStrHandles( pDragInfo); + DrgFreeDraginfo( pDragInfo); + mDragInfo = 0; + mDragItems = 0; + } + + // We don't DrgFreeDragInfo() here if there is a transfer of some sort; + // instead this is done when we get the appropriate DM_ENDCONVERSATION. + } + + return rc; +} + +// Window-proc. for the drag-source window +MRESULT EXPENTRY fnwpDragSource( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + MRESULT mr; + + if( gModuleData.dragService) + mr = gModuleData.dragService->HandleMessage( msg, mp1, mp2); + else + mr = WinDefWindowProc( hwnd, msg, mp1, mp2); + + return mr; +} + +MRESULT nsDragService::HandleMessage( ULONG msg, MPARAM mp1, MPARAM mp2) +{ + switch(msg) + { + case DM_RENDER: + { + NS_ASSERTION(mDragItems && mDragInfo, "Spurious DM_RENDER"); + + // The target wants us to put some data somewhere. + PDRAGTRANSFER pXFer = (PDRAGTRANSFER) mp1; + BOOL rc = FALSE; + + // This is vitally important, apparently. + pXFer->pditem->hstrSourceName = DrgAddStrHandle( "Dummy.fil"); + + if( !pXFer->pditem->ulItemID) + { + // the target (silly boy) has asked us to source-render something + // it's completely capable of rendering all by itself. + pXFer->fsReply = DMFL_NATIVERENDER; + DrgFreeDragtransfer( pXFer); + } + else + { + // Need to actually return from this call before we can render the + // thing... + WinPostMsg( mDragWnd, WM_USER, mp1, mp2); + rc = TRUE; + } + + return MRFROMLONG(rc); + } + + // + // Very possibly this should be in a fresh thread. + // + // This rather large block is the source-side of the source-render + // protocol; the target picks which format (from those provided by + // the transferable) it would like & where we should put it. + // + case WM_USER: + { + // Posted to ourselves in order to carry out a target's desired + // rendering. + PDRAGTRANSFER pXFer = (PDRAGTRANSFER) mp1; + nsITransferable *pTrans = (nsITransferable*) pXFer->pditem->ulItemID; + USHORT usFlags = DMFL_RENDERFAIL; + + NS_ASSERTION(pTrans, "No transferable to source-render"); + +#ifdef DEBUG + char *target = DecodeStrHandle( pXFer->hstrRenderToName); + printf( "Source-rendering to %s\n", target); + nsFileSpec dest( target); +#else + nsFileSpec dest( DecodeStrHandle( pXFer->hstrRenderToName)); +#endif + // Now, the fun bit is working out what format to use. + char *rmf = DecodeStrHandle( pXFer->hstrSelectedRMF); + char rm[50], rf[50]; + int tokens = sscanf( rmf, "<%s,%s>", rm, rf); + + NS_ASSERTION(tokens == 2, "Couldn't parse hstrSelectedRMF"); +#ifdef DEBUG + printf( "%d - %s %s\n", tokens, rm, rf); +#endif + if( !strcmp( rm, "DRM_OS2FILE")) + { + // Go through the transferable's flavours looking for one which + // matches the requested rf. + nsVoidArray *pFormats = nsnull; + char buff[40]; + pTrans->FlavorsTransferableCanExport( &pFormats); + PRUint32 cFormats = pFormats->Count(), i; + + for( i = 0; i < cFormats; i++) + { + nsString *pFlavour = (nsString*) pFormats->ElementAt( i); + gModuleData.ConvertFromUcs( *pFlavour, buff, 40); + const char *this_rf = MimeTypeToRF( buff); + if( this_rf && !strcmp( this_rf, rf)) + { + // Found it! + void *pData; + PRUint32 cData; + pTrans->GetTransferData( pFlavour, &pData, &cData); + + // (uh-oh) + nsOutputFileStream stream(dest); + stream.write( pData, (PRInt32)cData); + stream.close(); + usFlags = DMFL_RENDEROK; + break; + } + } + + delete pFormats; + if( i == cFormats) +#ifdef DEBUG + printf( "Target asked for format %s which we can't do.\n", rf); +#endif + } + else + { + printf( "Unexpected rendering mechanism\n"); + } + + // Tell the target we're done. + DrgPostTransferMsg( pXFer->hwndClient, + DM_RENDERCOMPLETE, + pXFer, + usFlags, + 0, + TRUE); + + DrgFreeDragtransfer( pXFer); + + // Note that the transferable we have here will be release'd in + // the DM_ENDCONVERSATION for the dragitem in question. + + return 0; + } + + // DRM_MOZILLA messages; see nsWidgetDefs.h for details + case WMU_GETFLAVOURLEN: + case WMU_GETFLAVOURDATA: + { + char buffer[40] = ""; + PRUint32 cData = 0; + void *pData; + + nsITransferable *pTrans = (nsITransferable*) mp1; + + if( pTrans) + { + PWZDROPXFER pXFer = (PWZDROPXFER) mp2; + ATOM atom; + + if( msg == WMU_GETFLAVOURLEN) atom = LONGFROMMP(mp2); + else atom = pXFer->hAtomFlavour; + + WinQueryAtomName( WinQuerySystemAtomTable(), atom, buffer, 40); + nsAutoString str(buffer); + if( NS_SUCCEEDED(pTrans->GetTransferData( &str, &pData, &cData))) + { + if( msg == WMU_GETFLAVOURDATA) + { + memcpy( &pXFer->data[0], pData, cData); + DosFreeMem( pXFer); + return MPFROMLONG(TRUE); + } + } + } + + return MRFROMLONG(cData); + } + + case DM_ENDCONVERSATION: + { + NS_ASSERTION(mDragItems && mDragInfo, "Unexpected DM_ENDCONVERSATION"); + + // If it was necessary (for source-rendering), we kept a reference + // to the transferable in the dragitem. Now it's safe to release. + nsITransferable *pTransferable = (nsITransferable*) mp1; + NS_IF_RELEASE(pTransferable); + + mDragItems--; + if( mDragItems == 0) + { + // the last of the dragitems has been ack'ed, so free the draginfo + DrgFreeDraginfo( mDragInfo); + mDragInfo = 0; + } +#ifdef DEBUG + printf( "DM_ENDCONVERSATION, mDragItems = %d\n", (int)mDragItems); +#endif + return 0; + } + } + + return (*mWndProc)( mDragWnd, msg, mp1, mp2); +} + +// Various forms of source-rendering, DRM_MOZILLA and "pushed-file" ------------- +// +// Custom shared-memory rendering mechanism +// +// Probably ought to just get creative with DRAGTRANSFER as is, but that (a) +// confuses the DRM_OS2FILE source-rendering & (b) imposes unhelpful constraints + +void nsDragService::DoMozillaXfer( PDRAGITEM pItem, char *szFlavour, + void **ppData, PRUint32 *cData) +{ + // First check if this is an intra-process transfer! + if( mDragItems) + { + // Yes. + nsITransferable *pSource = (nsITransferable*) pItem->ulItemID; + if( !pSource) + printf( "intra-process xfer fails due to null ulItemID\n"); + else + { + nsAutoString flavour(szFlavour); + if( NS_SUCCEEDED(pSource->GetTransferData( &flavour, ppData, cData))) + { + // need to make a copy... + char *tmp = new char [ *cData ]; + memcpy( tmp, *ppData, *cData); + *ppData = tmp; + } + } + return; + } + + HATOMTBL hAtomTbl = WinQuerySystemAtomTable(); + ATOM hAtom = WinAddAtom( hAtomTbl, szFlavour); + + ULONG ulLen = (ULONG) WinSendMsg( pItem->hwndItem, WMU_GETFLAVOURLEN, + MPFROMLONG(pItem->ulItemID), + MPFROMLONG(hAtom)); + if( ulLen) + { + void *shmem = 0; + if( !DosAllocSharedMem( &shmem, 0, ulLen + sizeof(ATOM), + PAG_COMMIT | OBJ_GIVEABLE | PAG_WRITE)) + { + // Find the tid of the source so we can give it the memory + PID pid; + TID tid; + WinQueryWindowProcess( pItem->hwndItem, &pid, &tid); + DosGiveSharedMem( shmem, pid, PAG_WRITE); + + PWZDROPXFER pWzData = (PWZDROPXFER) shmem; + pWzData->hAtomFlavour = hAtom; + + BOOL ok = (BOOL) WinSendMsg( pItem->hwndItem, WMU_GETFLAVOURDATA, + MPFROMLONG(pItem->ulItemID), + MPFROMP(pWzData)); + if( ok) + { + // now allocate (too many copies I know, but transferable has + // restrictions...) + char *buf = new char [ ulLen ]; + memcpy( buf, &pWzData->data[0], ulLen); + *cData = ulLen; + *ppData = buf; + } + + // free shared memory + DosFreeMem( shmem); + } + } + + WinDeleteAtom( hAtomTbl, hAtom); +} + +void nsDragService::DoPushedOS2FILE( PDRAGITEM pItem, const char *szRf, + void **pData, PRUint32 *cData) +{ + // Unfortunately there's no way we can do this: we must return from DM_DROP + // before having a "post-drop conversation" involving DM_RENDER. + // + // BUT we need to fill the transferable NOW, before we return from DM_DROP + // so that gecko (or whoever's underneath us). + // + // So we're stuck until there's some asynch. way of proceeding. + // + // But it's not all bad: not many people use source rendering; mozilla + // does, but we can use DRM_MOZILLA to do that. + + printf( "\n\nSorry, source-rendering of DRM_OS2FILE not working.\n"); + printf( "(see mozilla/widget/src/os2/nsDragService::DoPushedOS2FILE)\n\n"); +} + +// Quick utility functions ------------------------------------------------------ + +static char *DecodeStrHandle( HSTR hstr) +{ + static char buf[CCHMAXPATH]; + DrgQueryStrName( hstr, CCHMAXPATH, buf); + return buf; +} + +// Table to map mozilla "mimetypes" to PM "rendering formats" +// Could optimize I guess, but not really important. + +static const char *gFormatMap[][2] = +{ + { "DRF_TEXT", kTextMime }, + { "DRF_UNICODE", kUnicodeMime }, + { "DRF_HTML", kHTMLMime }, + { "DRF_XIF", kXIFMime }, + { "DRF_PNG", kPNGImageMime }, + { "DRF_GIF", kGIFImageMime }, + { "DRF_JPEG", kJPEGImageMime }, + { "DRF_AOLMAIL", kAOLMailMime }, + { 0, 0 } +}; + +static const char *MimeTypeToRF( const char *pcsz) +{ + int i = 0; + while( gFormatMap[i][0]) + if( !strcmp( pcsz, gFormatMap[i][1])) break; + return gFormatMap[i][0]; +} + +static const char *RFToMimeType( const char *pcsz) +{ + int i = 0; + while( gFormatMap[i][0]) + if( !strcmp( pcsz, gFormatMap[i][0])) break; + return gFormatMap[i][1]; +} + +static BOOL FindFile( PDRAGITEM pItem, nsFileSpec &aFileSpec) +{ + const char *str = DecodeStrHandle( pItem->hstrContainerName); +#ifdef DEBUG + printf( "Getting drag data from `%s'", str); +#endif + aFileSpec = str; + str = DecodeStrHandle( pItem->hstrSourceName); +#ifdef DEBUG + printf( "`%s'\n", str); +#endif + aFileSpec += str; + + return aFileSpec.Exists(); +} + +static void GetTempFile( nsFileSpec &tempfile) +{ + nsSpecialSystemDirectory tmpDir(nsSpecialSystemDirectory::OS_TemporaryDirectory); + tmpDir += "tmpfile"; + tmpDir.MakeUnique(); + tempfile = tmpDir; +} diff --git a/mozilla/widget/src/os2/nsDragService.h b/mozilla/widget/src/os2/nsDragService.h new file mode 100644 index 00000000000..0e1fb68bd53 --- /dev/null +++ b/mozilla/widget/src/os2/nsDragService.h @@ -0,0 +1,91 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsdragservice_h +#define _nsdragservice_h + +// Drag service. Manages drag & drop events, converts between OS/2 and +// mozilla-style databuffers. +// +// This exists as a singleton in the nsModule; it's created at creation of the +// primaeval appshell and destroyed at DLL unload-time. +// + +#include "nsBaseDragService.h" + +class nsFileSpec; + +// This implements nsIDragSession and nsIDragService. + +class nsDragService : public nsBaseDragService +{ + public: + nsDragService(); + virtual ~nsDragService(); + + // nsIDragService + NS_IMETHOD InvokeDragSession( nsISupportsArray *anArrayTransferables, + nsIRegion *aRegion, PRUint32 aActionType); + NS_IMETHOD InvokeDragSessionSingle( nsITransferable *aTransferable, + nsIRegion *aRegion, PRUint32 aActionType); + + // nsIDragSession + NS_IMETHOD GetData( nsITransferable *aTransferable, PRUint32 aItemIndex); + NS_IMETHOD GetNumDropItems( PRUint32 *aNumItems); + NS_IMETHOD IsDataFlavorSupported( nsString *aDataFlavour); + + // platform methods, called from nsWindow + void InitDragOver( PDRAGINFO aDragInfo); + MRESULT TermDragOver(); + + void InitDragExit( PDRAGINFO aDragInfo); + void TermDragExit(); + + void InitDrop( PDRAGINFO aDragInfo); + void TermDrop(); + + protected: + // Natives + void CreateDragItems( PULONG pCount, PDRAGITEM *ppItems, + nsITransferable *aTransferable); + void FillDragItem( PDRAGITEM aItem, nsITransferable *aTransferable); + void FillDragItem( PDRAGITEM aItem, nsFileSpec *aFilespec); + nsresult InvokeDrag( PDRAGITEM aItems, ULONG aCItems, PRUint32 aActionType); + MRESULT HandleMessage( ULONG msg, MPARAM mp1, MPARAM mp2); + void DoPushedOS2FILE( PDRAGITEM pItem, const char *szRf, + void **pData, PRUint32 *cData); + void DoMozillaXfer( PDRAGITEM pItem, char *szFlavour, + void **ppData, PRUint32 *cData); + + HWND mDragWnd; + HPOINTER mIcon; + + // State; allocated draginfo & outstanding items + PDRAGINFO mDragInfo; + PFNWP mWndProc; + ULONG mDragItems; + + friend MRESULT EXPENTRY fnwpDragSource(HWND,ULONG,MPARAM,MPARAM); +}; + +nsresult NS_GetDragService( nsISupports **aDragService); + +#endif diff --git a/mozilla/widget/src/os2/nsEntryField.cpp b/mozilla/widget/src/os2/nsEntryField.cpp new file mode 100644 index 00000000000..d9c2734a336 --- /dev/null +++ b/mozilla/widget/src/os2/nsEntryField.cpp @@ -0,0 +1,202 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include "nsEntryField.h" + +NS_IMPL_ADDREF(nsEntryField) +NS_IMPL_RELEASE(nsEntryField) + +nsresult nsEntryField::QueryInterface( const nsIID &aIID, void **aInstancePtr) +{ + nsresult result = nsWindow::QueryInterface( aIID, aInstancePtr); + + if( result == NS_NOINTERFACE && aIID.Equals( nsITextWidget::GetIID())) + { + *aInstancePtr = (void*) ((nsITextWidget*)this); + NS_ADDREF_THIS(); + result = NS_OK; + } + + return result; +} + +// Textfield messages; all very straight-forward to translate into PM. + +nsresult nsEntryField::GetText( nsString &aTextBuffer, PRUint32 aBufferSize, PRUint32 &size) +{ + nsWindow::GetWindowText( aTextBuffer, &size); + return NS_OK; +} + +nsresult nsEntryField::SetText( const nsString &aText, PRUint32 &len) +{ + SetTitle( aText); + mText = aText; + len = aText.Length(); + return NS_OK; +} + +nsresult nsEntryField::InsertText( const nsString &aText, PRUint32 aStartPos, + PRUint32 aEndPos, PRUint32 &rc) +{ + PRUint32 dummy; + nsString currentText; + GetText( currentText, 256, dummy); + nsString newText( aText); + currentText.Insert( newText, aStartPos, aText.Length()); + SetText( currentText, dummy); + rc = aText.Length(); + return NS_OK; +} + +nsresult nsEntryField::RemoveText() +{ + PRUint32 dummy; + SetText( nsString(), dummy); + return NS_OK; +} + +nsresult nsEntryField::SetPassword( PRBool aIsPassword) +{ + if( mWnd) + { + if( aIsPassword) + AddToStyle( ES_UNREADABLE); + else + RemoveFromStyle( ES_UNREADABLE); + } + else + { + if( aIsPassword) + mStyle |= ES_UNREADABLE; + else + mStyle &= ~ES_UNREADABLE; + } + return NS_OK; +} + +nsresult nsEntryField::SetMaxTextLength( PRUint32 aChars) +{ + short sLength = aChars ? (short) aChars : 500; // !! hmm + mOS2Toolkit->SendMsg( mWnd, EM_SETTEXTLIMIT, MPFROMSHORT(sLength)); + return NS_OK; +} + +nsresult nsEntryField::SetReadOnly( PRBool aReadOnlyFlag, PRBool &old) +{ + BOOL bOldState; + + if( mWnd) + { + bOldState = (BOOL) mOS2Toolkit->SendMsg( mWnd, EM_QUERYREADONLY); + mOS2Toolkit->SendMsg( mWnd, EM_SETREADONLY, MPFROMLONG(aReadOnlyFlag)); + } + else + { + bOldState = mStyle & ES_READONLY; + if( aReadOnlyFlag) + mStyle |= ES_READONLY; + else + mStyle &= ~ES_READONLY; + } + + old = bOldState ? PR_TRUE : PR_FALSE; + return NS_OK; +} + +nsresult nsEntryField::SelectAll() +{ + SetSelection( 0, 32000); + return NS_OK; +} + +// Maybe off-by-one errors here, test & see +nsresult nsEntryField::SetSelection( PRUint32 aStartSel, PRUint32 aEndSel) +{ + mOS2Toolkit->SendMsg( mWnd, EM_SETSEL, + MPFROM2SHORT( (short)aStartSel, (short)aEndSel)); + return NS_OK; +} + +nsresult nsEntryField::GetSelection( PRUint32 *aStartSel, PRUint32 *aEndSel) +{ + MRESULT rc = mOS2Toolkit->SendMsg( mWnd, EM_QUERYSEL); + if( aStartSel) + *aStartSel = SHORT1FROMMR( rc); + if( aEndSel) + *aEndSel = SHORT2FROMMR( rc); + return NS_OK; +} + +nsresult nsEntryField::SetCaretPosition( PRUint32 aPosition) +{ + SetSelection( aPosition, aPosition); + return NS_OK; +} + +// We're in a bit of trouble here 'cos we can't find out where the cursor +// is if there's a selection. Oh well, do what windows does... +nsresult nsEntryField::GetCaretPosition( PRUint32 &rc) +{ + PRUint32 selStart, selEnd; + GetSelection( &selStart, &selEnd); + if( selStart == selEnd) + rc = selStart; + else + rc = (PRUint32) -1; + + return NS_OK; +} + +// platform hooks +PCSZ nsEntryField::WindowClass() +{ + return WC_ENTRYFIELD; +} + +ULONG nsEntryField::WindowStyle() +{ + return mStyle | ES_MARGIN | ES_LEFT | ES_AUTOSCROLL | BASE_CONTROL_STYLE; +} + +nsresult nsEntryField::PreCreateWidget( nsWidgetInitData *aInitData) +{ + if( nsnull != aInitData) + { + nsTextWidgetInitData *data = (nsTextWidgetInitData *) aInitData; + if( data->mIsPassword) + mStyle |= ES_UNREADABLE; + if( data->mIsReadOnly) + mStyle |= ES_READONLY; + } + return NS_OK; +} + +ULONG nsEntryField::GetSWPFlags( ULONG flags) +{ + // add SWP_NOADJUST to stop ever-increasing entryfields + return flags | SWP_NOADJUST; +} + +void nsEntryField::PostCreateWidget() +{ + SetMaxTextLength( 0); +} diff --git a/mozilla/widget/src/os2/nsEntryField.h b/mozilla/widget/src/os2/nsEntryField.h new file mode 100644 index 00000000000..a2721884317 --- /dev/null +++ b/mozilla/widget/src/os2/nsEntryField.h @@ -0,0 +1,66 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nstextwidget_h +#define _nstextwidget_h + +#include "nswindow.h" +#include "nsITextWidget.h" + +// WC_ENTRYFIELD wrapper, for NS_TEXTFIELD_CID + +class nsEntryField : public nsWindow, public nsITextWidget +{ + public: + nsEntryField() : nsWindow(), mStyle( 0) {} + + // nsISupports + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(void); + NS_IMETHOD_(nsrefcnt) Release(void); + + // nsITextWidget + NS_IMETHOD GetText( nsString &aTextBuffer, PRUint32 aBufferSize, PRUint32 &); + NS_IMETHOD SetText( const nsString &aText, PRUint32 &); + NS_IMETHOD InsertText( const nsString &aText, PRUint32 aStartPos, PRUint32 aEndPos, PRUint32 &); + NS_IMETHOD RemoveText(); + NS_IMETHOD SetPassword( PRBool aIsPassword); + NS_IMETHOD SetMaxTextLength( PRUint32 aChars); + NS_IMETHOD SetReadOnly( PRBool aReadOnlyFlag, PRBool &); + NS_IMETHOD SelectAll(); + NS_IMETHOD SetSelection( PRUint32 aStartSel, PRUint32 aEndSel); + NS_IMETHOD GetSelection( PRUint32 *aStartSel, PRUint32 *aEndSel); + NS_IMETHOD SetCaretPosition( PRUint32 aPosition); + NS_IMETHOD GetCaretPosition( PRUint32 &pos); + + // platform hooks + virtual PCSZ WindowClass(); + virtual ULONG WindowStyle(); + NS_IMETHOD PreCreateWidget( nsWidgetInitData *aInitData); + virtual ULONG GetSWPFlags( ULONG flags); + virtual void PostCreateWidget(); + + protected: + ULONG mStyle; + nsString mText; +}; + +#endif diff --git a/mozilla/widget/src/os2/nsFSTree.cpp b/mozilla/widget/src/os2/nsFSTree.cpp new file mode 100644 index 00000000000..cbd441ae968 --- /dev/null +++ b/mozilla/widget/src/os2/nsFSTree.cpp @@ -0,0 +1,921 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// +// FSTree.cpp - asynchronous directory scanner +// +// mjf Sunday 06 June 1999 +// +// TODO +// * (maybe) Abstract away filing system from scanner ('datasource' idea) +// +// * Break out Dos* functions to some central useful place +// +// * Add more fine-grained synchronous-ness (see DirPicker.cpp) +// + +#define INCL_DOS +#define INCL_DOSERRORS +#define INCL_DOSDEVIOCTL +#define INCL_WIN +#include +#include +#include +#include +// disable asserts +#define NDEBUG +#include +#include "nsFSTree.h" + +#ifdef DEBUG +# define TRACE(x) printf x +#else +# define TRACE(x) +#endif + +// helper Dos* style functions +APIRET DosQueryNumDrives( PULONG cDrives); +APIRET DosIsDriveRemovable( USHORT drive, PBOOL rem); +APIRET DosIsDriveAvailable( USHORT dirve, PBOOL yesno); + +// Simple pipe-based queue class, templated to make some attempt at type-safety +template +class Queue +{ + HFILE mRead; + HFILE mWrite; + + public: + Queue() : mRead(0), mWrite(0) {} + ~Queue() { Close(); } + + void Create() + { + DosCreatePipe( &mRead, &mWrite, 1024); + } + + APIRET Write( T *aThing) + { + ULONG ulActual = 0; + APIRET rc = DosWrite( mWrite, aThing, sizeof(T), &ulActual); + assert( rc || ulActual == sizeof(T)); + return rc; + } + + APIRET Read( T *aThing) + { + ULONG ulActual = 0; + APIRET rc = DosRead( mRead, aThing, sizeof(T), &ulActual); + assert( rc || ulActual == sizeof(T)); + return rc; + } + + void Close() + { + DosClose( mRead); + DosClose( mWrite); + } +}; + +class fsFile; +class fsDir; + +// messages sent from client to scanning thread +struct RQPacket +{ + enum Cmd + { + Expand, + Trash, + Foliate, + Defoliate + }; + + Cmd mCmd; + fsDir *mDir; + + RQPacket( fsDir *aDir, RQPacket::Cmd aCmd) : mCmd(aCmd), mDir(aDir) {} + RQPacket() {} +}; + +// messages sent from scanner to callback thread +struct CBPacket +{ + enum Cmd + { + CreateRoot, + CreateNode, + DestroyNode, + CreateLeaf, + DestroyLeaf, + ScanComplete + }; + + Cmd mCmd; + union + { + fsDir *mDir; + fsFile *mFile; + } mData; + + CBPacket( fsDir *aDir, CBPacket::Cmd aCmd) : mCmd(aCmd) + { mData.mDir = aDir; } + CBPacket( fsFile *aFile, CBPacket::Cmd aCmd) : mCmd(aCmd) + { mData.mFile = aFile; } + CBPacket() : mCmd(CBPacket::ScanComplete) + {} +}; + +// fsTree, implementation of main treebuilder class +class fsTree : public FS::ITreeBuilder +{ + FS::ICallbacks *mCallbacks; + FS::BuildMode mBuildMode; + Queue mRQQueue; + Queue mCBQueue; + fsDir *mRoot; + HEV mHEV; + BOOL mDestructing; + HMTX mMutex; + BOOL mNeedsPM; + + void SendMsg( fsDir *aDir, RQPacket::Cmd aCmd); + void SendMsg( fsDir *aDir, CBPacket::Cmd aCmd); + void SendMsg( fsFile *aFile, CBPacket::Cmd aCmd); + void SendCompleteMsg(); + void Scan(); + void Notify(); + void CreateRootNode(); + void CreateDrives(); + void ScanForChildren( fsDir *aDir); + void DestroyNode( fsDir *aDir); + void Defoliate( fsDir *aDir); + void Foliate( fsDir *aDir); + + friend void _Optlink scannerThread( void *arg) + { ((fsTree*)arg)->Scan(); } + + friend void _Optlink notifyThread( void *arg) + { ((fsTree*)arg)->Notify(); } + + public: + fsTree() : mCallbacks(0), mRoot(0), mDestructing(0), mMutex(0), mNeedsPM(0) {} + virtual ~fsTree(); + + // ITreeBuilder + BOOL Init( FS::ICallbacks *aCallbacks); + BOOL RequiresPM( BOOL bSet) { mNeedsPM = bSet; return TRUE; } + BOOL Build( FS::BuildMode aBuildMode); + BOOL Lock(); + BOOL Unlock(); + BOOL DeleteInstance(); + + // Called by fsDirs in response to user requests + void ExpandNode( fsDir *aDir) + { SendMsg( aDir, RQPacket::Expand); } + void TrashNode( fsDir *aDir) + { SendMsg( aDir, RQPacket::Trash); } + void FoliateNode( fsDir *aDir) + { SendMsg( aDir, RQPacket::Foliate); } + void DefoliateNode( fsDir *aDir) + { SendMsg( aDir, RQPacket::Defoliate); } +}; + + +// Base fs entity class +class fsBase : public FS::IFileInfo +{ + void *mUserData; + FILEFINDBUF3 mFindBuf; + PSZ mPathname; + + protected: + FS::IDir *mParent; + + public: + fsBase( FILEFINDBUF3 *aBuf, FS::IDir *aParent) : mUserData(0), mPathname(0), + mParent(aParent) + { + assert(aBuf); + memcpy( &mFindBuf, aBuf, sizeof mFindBuf); + } + + virtual ~fsBase() + { + delete [] mPathname; + } + + PCSZ GetLeafName() { return mFindBuf.achName; } + ULONG GetAttributes() { return mFindBuf.attrFile; } + ULONG GetSize() { return mFindBuf.cbFile; } + FDATE GetCreationDate() { return mFindBuf.fdateCreation; } + FTIME GetCreationTime() { return mFindBuf.ftimeCreation; } + FDATE GetLastAccessDate() { return mFindBuf.fdateLastAccess; } + FTIME GetLastAccessTime() { return mFindBuf.ftimeLastAccess; } + FDATE GetLastWriteDate() { return mFindBuf.fdateLastWrite; } + FTIME GetLastWriteTime() { return mFindBuf.ftimeLastWrite; } + void *GetUserData() { return mUserData; } + void SetUserData( void *aData) { mUserData = aData; } + + PCSZ GetPathName() + { + if( !mPathname && mParent) + { + mPathname = new char [ CCHMAXPATH ]; + PCSZ pszParentPath = mParent->GetFileInfo()->GetPathName(); + if( pszParentPath) + { + strcpy( mPathname, pszParentPath); + strcat( mPathname, "\\"); + } + else + *mPathname = 0; + strcat( mPathname, GetLeafName()); + } + return mPathname; + } +}; + +// Files +class fsFile : public FS::IFile, public fsBase +{ + fsFile *mNext; + + public: + fsFile( FILEFINDBUF3 *aBuf, FS::IDir *aParent) : fsBase(aBuf, aParent), + mNext(0) + {} + + virtual ~fsFile() + {} + + fsFile *GetNext() { return mNext; } + FS::IDir *GetParent() { return mParent; } // XXX move into fsBase? + FS::IFileInfo *GetFileInfo() { return this; } + + void SetNext( fsFile *aNext) { mNext = aNext; } +}; + +// Directories +class fsDir : public FS::IDir, public fsBase +{ + fsFile *mFiles; + fsDir *mChild; + fsDir *mSibling; + fsTree *mTree; + + #define FSDIR_FOLIATED 1 + #define FSDIR_EXPANDED 2 + + ULONG mFlags; + + public: + fsDir( fsTree *aTree, FILEFINDBUF3 *aBuf, FS::IDir *aParent) + : fsBase(aBuf, aParent), + mFiles(0), mChild(0), mSibling(0), mTree(aTree), mFlags(0) + {} + + virtual ~fsDir() + {} + + FS::IDir *GetParent() { return mParent; } // XXX move into fsBase? + fsDir *GetFirstChild() { return mChild; } + fsDir *GetNextSibling() { return mSibling; } + void Expand(); + void Trash(); + + fsFile *GetFirstLeaf() { return mFiles; } + void Foliate( BOOL aForce); + + fsBase *GetFileInfo() { return this; } + + void SetFiles( fsFile *aFile) { mFiles = aFile; } + void SetChild( fsDir *aDir) { mChild = aDir; } + void SetSibling( fsDir *aDir) { mSibling = aDir; } + + virtual FS::IDrive *AsDrive() { return 0; } +}; + +void fsDir::Expand() +{ + if( !(mFlags & FSDIR_EXPANDED)) + { + mTree->ExpandNode( this); + mFlags |= FSDIR_EXPANDED; + } +} + +void fsDir::Trash() +{ + if( mFlags & FSDIR_FOLIATED) + mTree->DefoliateNode( this); + mTree->TrashNode( this); + mFlags = 0; +} + +void fsDir::Foliate( BOOL aForce) +{ + if( !(mFlags & FSDIR_FOLIATED) || aForce) + { + if( aForce) + mTree->DefoliateNode( this); + mTree->FoliateNode( this); + mFlags |= FSDIR_FOLIATED; + } +} + +// Drives +class fsDrive : public FS::IDrive, public fsDir +{ + BOOL mIsRemovable; + FSINFO mFSInfo; + + public: + fsDrive( fsTree *aTree, FILEFINDBUF3 *aBuf, FS::IDir *aParent) + : fsDir( aTree, aBuf, aParent), + mIsRemovable((BOOL)-1) + {} + + virtual ~fsDrive() + {} + + BOOL IsRemovable() + { + if( mIsRemovable == (BOOL)-1) + DosIsDriveRemovable( *GetLeafName() - 'A', &mIsRemovable); + return mIsRemovable; + } + + PCSZ GetVolumeLabel() + { + PCSZ pcszLabel = 0; + USHORT usDrive = *GetLeafName() - 'A'; + BOOL bAvail = FALSE; + + // bit of a race here, but it's not critical. + + DosIsDriveAvailable( usDrive, &bAvail); + + if( bAvail) + { + APIRET rc = DosQueryFSInfo( usDrive + 1, FSIL_VOLSER, + &mFSInfo, sizeof mFSInfo); + + if( !rc) pcszLabel = mFSInfo.vol.szVolLabel; + } + return pcszLabel; + } + + fsDrive *AsDrive() { return this; } +}; + +// fsTree ----------------------------------------------------------------------- + +BOOL fsTree::DeleteInstance() +{ + delete this; + return TRUE; +} + +fsTree::~fsTree() +{ + // Execute synchronously to prevent leaky pain + mDestructing = TRUE; + if( mRoot) + DestroyNode( mRoot); + + mRQQueue.Close(); + mCBQueue.Close(); + + if( mHEV) + DosCloseEventSem( mHEV); + + if( mMutex) + DosCloseMutexSem( mMutex); +} + + +BOOL fsTree::Init( FS::ICallbacks *aCallbacks) +{ + assert(!mCallbacks); // double-init is bad + + mCallbacks = aCallbacks; + + DosCreateMutexSem( 0, &mMutex, 0, 0); + DosCreateEventSem( 0, &mHEV, 0, 0); + + return TRUE; +} + +BOOL fsTree::Build( FS::BuildMode aBuildMode) +{ + assert( mCallbacks); // must have callbacks + assert( !mRoot); // can't call twice + + BOOL rc = FALSE; + if( mCallbacks && !mRoot) + { + mBuildMode = aBuildMode; + + mRQQueue.Create(); + + _beginthread( scannerThread, 0, 32768, this); + + if( mBuildMode == FS::Synchronous) + DosWaitEventSem( mHEV, SEM_INDEFINITE_WAIT); + + rc = TRUE; + } + + return rc; +} + +BOOL fsTree::Lock() +{ + DosRequestMutexSem( mMutex, SEM_INDEFINITE_WAIT); + return TRUE; +} + +BOOL fsTree::Unlock() +{ + DosReleaseMutexSem( mMutex); + return TRUE; +} + +void fsTree::SendMsg( fsDir *aDir, RQPacket::Cmd aCmd) +{ + RQPacket packet( aDir, aCmd); + APIRET rc = mRQQueue.Write( &packet); + + if( rc) + TRACE(( "ERROR: fsTree::SendMsg (RQ) rc = %d\n", (int)rc)); +} + +void fsTree::SendMsg( fsDir *aDir, CBPacket::Cmd aCmd) +{ + CBPacket packet( aDir, aCmd); + APIRET rc = mCBQueue.Write( &packet); + + if( rc) + TRACE(( "ERROR: fsTree::SendMsg (CB 1) rc = %d\n", (int)rc)); +} + +void fsTree::SendMsg( fsFile *aFile, CBPacket::Cmd aCmd) +{ + CBPacket packet( aFile, aCmd); + APIRET rc = mCBQueue.Write( &packet); + + if( rc) + TRACE(( "ERROR: fsTree::SendMsg (CB 2) rc = %d\n", (int)rc)); +} + +void fsTree::SendCompleteMsg() +{ + CBPacket packet; + APIRET rc = mCBQueue.Write( &packet); + + if( rc) + TRACE(( "ERROR: fsTree::SendMsg (CB 3) rc = %d\n", (int)rc)); +} + +// Scanner thread --------------------------------------------------------------- +void fsTree::Scan() +{ + // Set up the notify thread + mCBQueue.Create(); + _beginthread( notifyThread, 0, 32768, this); + + // Do root node + CreateRootNode(); + + // Do drives -- root dir for each drive + // This will do *everything* if we're not in Lazy mode. + CreateDrives(); + + // Signal that we've done the initial scan. + // This lets the user thread go if we're synchronous. + SendCompleteMsg(); + + // Process commands + for(;;) + { + RQPacket pkt; + APIRET rc = mRQQueue.Read( &pkt); + if( rc) + { + TRACE(( "scanThread got rc %d, quitting\n", (int)rc)); + break; + } + + switch( pkt.mCmd) + { + case RQPacket::Expand: + { + // scan on each child of pkt.mDir + fsDir *pDir = pkt.mDir->GetFirstChild(); + while( pDir) + { + ScanForChildren( pDir); + pDir = pDir->GetNextSibling(); + } + break; + } + + case RQPacket::Trash: + { + // Refresh a node - destroy tree below & rescan at top level. + fsDir *pDir = pkt.mDir->GetFirstChild(); + pkt.mDir->SetChild(0); + while( pDir) + { + fsDir *pTemp = pDir->GetNextSibling(); + Lock(); + DestroyNode( pDir); // pDir no longer valid + Unlock(); + pDir = pTemp; + } + ScanForChildren( pkt.mDir); + break; + } + + case RQPacket::Foliate: + // scan for files in pkt.mDir + Foliate( pkt.mDir); + break; + + case RQPacket::Defoliate: + // remove all leaves from pkt.mDir + Defoliate( pkt.mDir); + break; + } + } +} + +void fsTree::CreateRootNode() +{ + FILEFINDBUF3 buf = { 0 }; + strcpy( buf.achName, "$ROOT"); + buf.cchName = 5; + mRoot = new fsDir( this, &buf, 0); + SendMsg( mRoot, CBPacket::CreateRoot); +} + +void fsTree::CreateDrives() +{ + ULONG ulDrives = 0; + DosQueryNumDrives( &ulDrives); + + fsDrive *pPrev = 0; + + // go through the drives one by one + for( UINT i = 0; i < ulDrives; i++) + { + APIRET rc; + FILESTATUS3 fs3 = { { 0, 0, 0 } }; + FILEFINDBUF3 ffb3 = { 0 }; + + strcpy( ffb3.achName, "A:\\"); + ffb3.achName[0] += i; + + // create drive node from disk data + DosError(0); + rc = DosQueryPathInfo( ffb3.achName, FIL_STANDARD, &fs3, sizeof fs3); + DosError(1); + + ffb3.achName[2] = 0; + memcpy( &ffb3.fdateCreation, &fs3, sizeof fs3); + + // Insert drive node into tree + fsDrive *pDrive = new fsDrive( this, &ffb3, mRoot); + Lock(); + if( !pPrev) mRoot->SetChild( pDrive); + else pPrev->SetSibling( pDrive); + pPrev = pDrive; + Unlock(); + + SendMsg( pDrive, CBPacket::CreateNode); + } + + // now scan for children. Splitting the task up this way makes UIs more + // responsive, as they can wap up the roots first before going digging. + fsDir *pDir = mRoot->GetFirstChild(); + while( pDir) + { + ScanForChildren( pDir); + pDir = pDir->GetNextSibling(); + } +} + +void fsTree::ScanForChildren( fsDir *aParent) +{ + // Look through the directory indicated for child directories and + // insert them into the tree. + char buffer[CCHMAXPATH] = ""; + APIRET rc; + HDIR hDir = HDIR_CREATE; + ULONG ulCount = 1; + FILEFINDBUF3 fb; + + fsDir *pPrev = 0; + + strcpy( buffer, aParent->GetPathName()); + strcat( buffer, "\\*"); + + // Scan for directories & build node-list + + DosError(0); + rc = DosFindFirst( buffer, &hDir, + MUST_HAVE_DIRECTORY | FILE_ARCHIVED | FILE_SYSTEM | + FILE_HIDDEN | FILE_READONLY | FILE_DIRECTORY, + &fb, sizeof fb, + &ulCount, FIL_STANDARD); + DosError(1); + + while( !rc) + { + if( strcmp( fb.achName, ".") && strcmp( fb.achName, "..")) + { + Lock(); + fsDir *pDir = new fsDir( this, &fb, aParent); + if( !pPrev) aParent->SetChild( pDir); + else pPrev->SetSibling( pDir); + pPrev = pDir; + Unlock(); + + SendMsg( pDir, CBPacket::CreateNode); + + // If we're not in lazy mode, recurse (ahem!) + if( mBuildMode != FS::Lazy) + ScanForChildren( pDir); + + } + rc = DosFindNext( hDir, &fb, sizeof fb, &ulCount); + } + + DosFindClose( hDir); +} + +// Destroy a node (recursively) +void fsTree::DestroyNode( fsDir *aDir) +{ + fsDir *aNotherDir = aDir->GetNextSibling(); + if( aNotherDir) + { + DestroyNode( aNotherDir); + aDir->SetSibling( 0); + } + + aNotherDir = aDir->GetFirstChild(); + if( aNotherDir) + { + DestroyNode( aNotherDir); + aDir->SetChild( 0); + } + + if( mDestructing) + { + Defoliate( aDir); + mCallbacks->DestroyDir( aDir); + delete aDir; + } + else + SendMsg( aDir, CBPacket::DestroyNode); +} + +// Destroy a node's leaves +void fsTree::Defoliate( fsDir *aDir) +{ + Lock(); + + fsFile *pFile = aDir->GetFirstLeaf(); + + while( pFile) + { + fsFile *pTemp = pFile->GetNext(); + pFile->SetNext(0); + + if( mDestructing) + { + mCallbacks->DestroyFile( pFile); + delete pFile; + } + else + SendMsg( pFile, CBPacket::DestroyLeaf); + + pFile = pTemp; + } + + aDir->SetFiles( 0); + + Unlock(); +} + +// Examine directory and add files to tree +void fsTree::Foliate( fsDir *aDir) +{ + FILEFINDBUF3 fb = { 0 }; + APIRET rc = 0; + ULONG ulCount = 1; + HDIR hDir = HDIR_CREATE; + char path[ CCHMAXPATH]; + + strcpy( path, aDir->GetPathName()); + strcat( path, "\\*"); + + // Scan for files + + DosError(0); + rc = DosFindFirst( path, &hDir, + FILE_ARCHIVED | FILE_SYSTEM | + FILE_HIDDEN | FILE_READONLY, + &fb, sizeof fb, + &ulCount, + FIL_STANDARD); + DosError(1); + fsFile *pLast = 0; + + while( !rc) + { + Lock(); + fsFile *pFile = new fsFile( &fb, aDir); + if( !pLast) aDir->SetFiles( pFile); + else pLast->SetNext( pFile); + pLast = pFile; + Unlock(); + + SendMsg( pFile, CBPacket::CreateLeaf); + + rc = DosFindNext( hDir, &fb, sizeof fb, &ulCount); + } + + DosFindClose( hDir); +} + +// Notify thread ---------------------------------------------------------------- +void fsTree::Notify() +{ + // Create PM if necessary (hackish, sorry) + HAB hab; + HMQ hmq; + + if( mNeedsPM) + { + hab = WinInitialize( 0); + hmq = WinCreateMsgQueue( hab, 0); + } + + for(;;) + { + CBPacket pkt; + APIRET rc = mCBQueue.Read( &pkt); + if( rc) + { + TRACE(( "notifyThread got rc %d, quitting\n", (int)rc)); + break; + } + + switch( pkt.mCmd) + { + case CBPacket::CreateRoot: + mCallbacks->CreateRoot( pkt.mData.mDir); + break; + + case CBPacket::CreateNode: + mCallbacks->CreateDir( pkt.mData.mDir); + break; + + case CBPacket::DestroyNode: + mCallbacks->DestroyDir( pkt.mData.mDir); + delete pkt.mData.mDir; + break; + + case CBPacket::CreateLeaf: + mCallbacks->CreateFile( pkt.mData.mFile); + break; + + case CBPacket::DestroyLeaf: + mCallbacks->DestroyFile( pkt.mData.mFile); + delete pkt.mData.mFile; + break; + + case CBPacket::ScanComplete: + mCallbacks->InitialScanComplete(); + if( mBuildMode == FS::Synchronous) + DosPostEventSem( mHEV); + break; + + default: + assert(0); + break; + } + } + + if( mNeedsPM) + { + WinDestroyMsgQueue( hmq); + WinTerminate( hab); + } +} + +// Bootstrap -------------------------------------------------------------------- +FS::ITreeBuilder *FS::CreateTreeBuilder() +{ + return new fsTree; +} + +// Dos-functions ---------------------------------------------------------------- +APIRET DosQueryNumDrives( PULONG cDrives) +{ + int i; + BOOL dummy; + for( i = 0; i < 26; i++) + if( DosIsDriveRemovable( i, &dummy)) break; + *cDrives = i; + return NO_ERROR; +} + +APIRET DosIsDriveRemovable( USHORT drive, PBOOL rem) +{ + struct { + BYTE commandInformation; + BYTE driveUnit; + } driveRequest; + ULONG parmSize; + BIOSPARAMETERBLOCK driveInfo; + ULONG dataSize; + APIRET rc; + + driveRequest.commandInformation = 0; + driveRequest.driveUnit = drive; + parmSize = sizeof driveRequest; + dataSize = sizeof driveInfo; + memset( &driveInfo, 0, dataSize); + DosError(0); + rc = DosDevIOCtl( (HFILE)-1, IOCTL_DISK, DSK_GETDEVICEPARAMS, + &driveRequest, parmSize, &parmSize, + &driveInfo, dataSize, &dataSize); + DosError(1); + + if( !rc && !driveInfo.bDeviceType) rc = ERROR_INVALID_DRIVE; + else *rem = !(driveInfo.fsDeviceAttr & 1); + + return rc; +} + +APIRET DosIsDriveAvailable( USHORT drive, PBOOL yesno) +{ + APIRET rc = 1;//DosIsDriveRemovable( drive, yesno); + + if( !rc && !*yesno) + { + *yesno = TRUE; // bad assumption ? + } + else + { + #pragma pack(1) + + struct { + UCHAR commandInformation; + USHORT driveunit; + } paramPacket; + + #pragma pack() + + ULONG paramSize; + USHORT dataPacket; + ULONG dataSize; + + paramPacket.commandInformation = 0; + paramPacket.driveunit = drive; + paramSize = sizeof paramPacket; + dataPacket = 0; + dataSize = sizeof dataPacket; + + rc = DosDevIOCtl( (HFILE)-1, IOCTL_DISK, DSK_GETLOCKSTATUS, + ¶mPacket, paramSize, ¶mSize, + &dataPacket, dataSize, &dataSize); + + /* drive is available if (a) there is media (b) drive not locked */ + *yesno = !rc && (dataPacket & 0x4) && ((dataPacket & 3) != 1); + } + + return rc; +} diff --git a/mozilla/widget/src/os2/nsFSTree.h b/mozilla/widget/src/os2/nsFSTree.h new file mode 100644 index 00000000000..053cdd08a4f --- /dev/null +++ b/mozilla/widget/src/os2/nsFSTree.h @@ -0,0 +1,142 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// +// FSTree -- filing-system-tree-builder +// +// This is in mozilla to provide an adaquate 'choose directory' dialog. +// It could be used to provide a nice 'choose file' dialog as well. +// +// * Lazy or eager +// * Synchronous or asynchronous +// * UI-free +// +// mjf Sunday 06 June 1999, rehashing various versions of this code written for +// various purposes written over the past few years into one beauteous whole. +// +// The interface scheme is something of an experiment. +// + +#ifndef _fstree_h +#define _fstree_h + +// Name-space for interfaces +struct FS +{ + // Base class for filing-system entities + class IFileInfo + { + public: + virtual PCSZ GetLeafName() = 0; + virtual PCSZ GetPathName() = 0; + virtual ULONG GetAttributes() = 0; + virtual ULONG GetSize() = 0; + virtual FDATE GetCreationDate() = 0; + virtual FTIME GetCreationTime() = 0; + virtual FDATE GetLastAccessDate() = 0; + virtual FTIME GetLastAccessTime() = 0; + virtual FDATE GetLastWriteDate() = 0; + virtual FTIME GetLastWriteTime() = 0; + + virtual void *GetUserData() = 0; + virtual void SetUserData( void *aUserData) = 0; + }; + + class IDir; + + // Files + class IFile + { + public: + virtual IFile *GetNext() = 0; + virtual IDir *GetParent() = 0; + virtual IFileInfo *GetFileInfo() = 0; + }; + + class IDrive; + + // Directories + class IDir + { + public: + virtual IDir *GetParent() = 0; + virtual IDir *GetFirstChild() = 0; + virtual IDir *GetNextSibling() = 0; + virtual void Expand() = 0; + virtual void Trash() = 0; + + virtual IFile *GetFirstLeaf() = 0; + virtual void Foliate( BOOL bForceRefresh) = 0; + + virtual IFileInfo *GetFileInfo() = 0; + + virtual IDrive *AsDrive() = 0; + }; + + // Drives + class IDrive + { + public: + virtual BOOL IsRemovable() = 0; + virtual PCSZ GetVolumeLabel() = 0; + }; + + // Callbacks (clients implement this interface) + class ICallbacks + { + public: + // The meta node, parent of all drives + virtual void CreateRoot( IDir *aRootNode) = 0; + // Callback to notify completion of initial scan + virtual void InitialScanComplete() = 0; + // All directories named here have parents + virtual void CreateDir( IDir *aNewNode) = 0; + // Clean up user data if necessary + virtual void DestroyDir( IDir *aNode) = 0; + virtual void CreateFile( IFile *aNewLeaf) = 0; + // Clean up user data if necessary + virtual void DestroyFile( IFile *aLeaf) = 0; + }; + + enum BuildMode // ways in which tree can be built + { + Lazy, // keep 1 level ahead of expand requests + Eager, // expand until there's nothing left to do + Synchronous // do everything (as for Eager) before Build() returns + }; + + // Tree builder + class ITreeBuilder + { + public: + virtual BOOL Init( ICallbacks *aCallbacks) = 0; + virtual BOOL RequiresPM( BOOL bSet) = 0; + virtual BOOL Build( BuildMode aBuildMode) = 0; + virtual BOOL Lock() = 0; + virtual BOOL Unlock() = 0; + virtual BOOL DeleteInstance() = 0; + }; + + // Bootstrap (use DeleteInstance() to destroy) + static ITreeBuilder *CreateTreeBuilder(); +}; + +#endif diff --git a/mozilla/widget/src/os2/nsFileDialog.cpp b/mozilla/widget/src/os2/nsFileDialog.cpp new file mode 100644 index 00000000000..b11c1161573 --- /dev/null +++ b/mozilla/widget/src/os2/nsFileDialog.cpp @@ -0,0 +1,229 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include "nsWidgetDefs.h" +#include "nsIToolkit.h" +#include "nsFileDialog.h" +#include "nsDirPicker.h" + +#include + +// File dialog. +// +// ToDo: types array + +nsFileDialog::nsFileDialog() : mWndOwner( 0), mCFilters(0) +{ + NS_INIT_REFCNT(); + memset( &mFileDlg, 0, sizeof mFileDlg); + mFileDlg.cbSize = sizeof mFileDlg; + mFileDlg.fl = FDS_CENTER | FDS_ENABLEFILELB; + strcpy( mFileDlg.szFullFile, "*.*"); +} + +nsFileDialog::~nsFileDialog() +{ + if( mFileDlg.pszTitle) + free( mFileDlg.pszTitle); +} + +NS_IMPL_ISUPPORTS(nsFileDialog,nsIFileWidget::GetIID()) + +nsresult nsFileDialog::Create( nsIWidget *aParent, + const nsString &aTitle, + nsFileDlgMode aMode, + nsIDeviceContext *aContext, + nsIAppShell *aAppShell, + nsIToolkit *aToolkit, + void *aInitData) +{ + // set owner + if( aParent) + mWndOwner = (HWND) aParent->GetNativeData( NS_NATIVE_WIDGET); + else + mWndOwner = HWND_DESKTOP; + + if( mFileDlg.pszTitle) + { + free( mFileDlg.pszTitle); + mFileDlg.pszTitle = 0; + } + if( aTitle.Length() > 0) + mFileDlg.pszTitle = strdup( gModuleData.ConvertFromUcs( aTitle)); + + if( aMode == eMode_load) + mFileDlg.fl |= FDS_OPEN_DIALOG; + else if( aMode == eMode_save) + mFileDlg.fl |= FDS_SAVEAS_DIALOG; + else + NS_ASSERTION(0, "Dodgy file dialog type"); + + return NS_OK; +} + +// FQ Filename (I suspect this method will vanish) +nsresult nsFileDialog::SetDefaultString( const nsString &aString) +{ + gModuleData.ConvertFromUcs( aString, mFileDlg.szFullFile, CCHMAXPATH); + return NS_OK; +} + +nsresult nsFileDialog::SetDisplayDirectory( const nsFileSpec &aDirectory) +{ + // first copy the file part of whatever we have into 'buff' + char buff[CCHMAXPATH] = ""; + char *lastslash = strrchr( mFileDlg.szFullFile, '\\'); + + strcpy( buff, lastslash ? lastslash + 1 : mFileDlg.szFullFile); + + // Now copy directory from filespec into filedlg + strcpy( mFileDlg.szFullFile, nsNSPRPath(aDirectory)); + + // Ensure there's a trailing backslash... + if( '\\' != lastchar( mFileDlg.szFullFile)) + strcat( mFileDlg.szFullFile, "\\"); + + // ...and stick the file back on. + strcat( mFileDlg.szFullFile, buff); + +#ifdef DEBUG + printf( "SetDisplayDir, szFullFile = %s\n", mFileDlg.szFullFile); +#endif + + return NS_OK; +} + +nsresult nsFileDialog::GetDisplayDirectory( nsFileSpec &aDirectory) +{ + char buff[CCHMAXPATH] = ""; + strcpy( buff, mFileDlg.szFullFile); + printf( "mFileDlg.szFullFile = %s\n", buff); + char *lastslash = strrchr( buff, '\\'); + + if( lastslash && '\0' != *lastslash) + *lastslash = '\0'; + else + // no directory set + *buff = '\0'; + + aDirectory = (const char*) buff; + + return NS_OK; +} + +nsresult nsFileDialog::SetFilterList( PRUint32 aNumberOfFilters, + const nsString aTitles[], + const nsString aFilters[]) +{ + // + // XXX really need a subclassed file dialog for this. + // Just using the papszITypeList doesn't work because that's meant to + // be .TYPE eas. + // + + return NS_OK; +} + +nsresult nsFileDialog::GetSelectedType( PRInt16 &theType) +{ + theType = 0; + return NS_OK; +} + +// return false if cancel happens. +PRBool nsFileDialog::Show() +{ + PRBool rc = PR_TRUE; + + WinFileDlg( HWND_DESKTOP, mWndOwner, &mFileDlg); + if( mFileDlg.lReturn == DID_CANCEL) + rc = PR_FALSE; + + return rc; +} + +nsresult nsFileDialog::GetFile( nsFileSpec &aSpec) +{ + aSpec = mFileDlg.szFullFile; + return NS_OK; +} + +// Methods for folks who can't be bothered to call Create() & Show() +nsFileDlgResults nsFileDialog::GetFile( nsIWidget *aParent, + const nsString &promptString, + nsFileSpec &theFileSpec) +{ + nsFileDlgResults rc = nsFileDlgResults_Cancel; + + Create( aParent, promptString, eMode_load); + + if( Show()) + { + rc = nsFileDlgResults_OK; + GetFile( theFileSpec); + } + + return rc; +} + +nsFileDlgResults nsFileDialog::PutFile( nsIWidget *aParent, + const nsString &promptString, + nsFileSpec &theFileSpec) +{ + nsFileDlgResults rc = nsFileDlgResults_Cancel; + + Create( aParent, promptString, eMode_save); + + if( Show()) + { + rc = nsFileDlgResults_OK; + GetFile( theFileSpec); + } + + return rc; +} + +nsFileDlgResults nsFileDialog::GetFolder( nsIWidget *aParent, + const nsString &promptString, + nsFileSpec &theFileSpec) +{ + nsFileDlgResults rc = nsFileDlgResults_Cancel; + + HWND hwndOwner = HWND_DESKTOP; + if( aParent) + hwndOwner = (HWND) aParent->GetNativeData( NS_NATIVE_WIDGET); + + DIRPICKER dp = { { 0 }, 0, TRUE, 0 }; // modal dialog + + gModuleData.ConvertFromUcs( promptString, dp.szFullFile, CCHMAXPATH); + + HWND ret = FS_PickDirectory( HWND_DESKTOP, hwndOwner, + gModuleData.hModResources, &dp); + + if( ret && dp.lReturn == DID_OK) + { + theFileSpec = dp.szFullFile; + strcpy( mFileDlg.szFullFile, dp.szFullFile); // just in case... + rc = nsFileDlgResults_OK; + } + + return rc; +} diff --git a/mozilla/widget/src/os2/nsFileDialog.h b/mozilla/widget/src/os2/nsFileDialog.h new file mode 100644 index 00000000000..0cd103f190a --- /dev/null +++ b/mozilla/widget/src/os2/nsFileDialog.h @@ -0,0 +1,77 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsfilewidget_h +#define _nsfilewidget_h + +// File dialog wrapper. +// +// This is really a temporary thing - eventually want to replace with +// some better things, especially if 'select directory' appears. +// +// Want to do some kind of mode filtering - like EAs are meant to work, +// but better. + +class nsIWidget; +class nsIAppShell; +class nsIDeviceContext; + +#include "nsIFileWidget.h" + +class nsFileDialog : public nsIFileWidget +{ + public: + nsFileDialog(); + virtual ~nsFileDialog(); + + NS_DECL_ISUPPORTS + + // nsIFileWidget + NS_IMETHOD Create( nsIWidget *aParent, const nsString &aTitle, + nsFileDlgMode aMode, nsIDeviceContext *aContext = nsnull, + nsIAppShell *aAppShell = nsnull, + nsIToolkit *aToolkit = nsnull, void *aInitData = 0); + NS_IMETHOD SetFilterList( PRUint32 aNumberOfFilters, + const nsString aTitles[], + const nsString aFilters[]); + NS_IMETHOD GetSelectedType( PRInt16 &theType); + virtual PRBool Show(); + NS_IMETHOD GetFile( nsFileSpec &aFile); + NS_IMETHOD SetDefaultString( const nsString &aFilename); + NS_IMETHOD SetDisplayDirectory( const nsFileSpec &aDirectory); + NS_IMETHOD GetDisplayDirectory( nsFileSpec &aDirectory); + + nsFileDlgResults GetFile( nsIWidget *aParent, const nsString &promptString, + nsFileSpec &theFileSpec); + + nsFileDlgResults GetFolder( nsIWidget *aParent, const nsString &promptString, + nsFileSpec &theFileSpec); + + nsFileDlgResults PutFile( nsIWidget *aParent, const nsString &promptString, + nsFileSpec &theFileSpec); + + protected: + HWND mWndOwner; + FILEDLG mFileDlg; + PRUint32 mCFilters; +}; + +#endif diff --git a/mozilla/widget/src/os2/nsFontServices.cpp b/mozilla/widget/src/os2/nsFontServices.cpp new file mode 100644 index 00000000000..d9419874865 --- /dev/null +++ b/mozilla/widget/src/os2/nsFontServices.cpp @@ -0,0 +1,353 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include "nsWidgetDefs.h" +#include "nsFontServices.h" +#include "nsIFontNameIterator.h" +#include "nsIFontSizeIterator.h" +#include "nsString.h" + +#include + +// FONTMETRICS are obtained and stored in a datastructure which is optimized +// towards the enumeration-style purpose for which they are required in this +// toolkit (primarily to populate combobox widgets, I guess) + +class FaceInstance +{ + PFONTMETRICS mFontMetrics; + FaceInstance *mNext; + + public: + FaceInstance( PFONTMETRICS aMetrics) : mFontMetrics(aMetrics), mNext(0) + {} + + ~FaceInstance() + { + delete mNext; + } + + PRBool IsScalable() + { + return mFontMetrics->fsDefn & FM_DEFN_OUTLINE; + } + + double GetPointSize() + { + return ((double)mFontMetrics->sNominalPointSize) / 10.0; + } + + void Append( FaceInstance *aInstance) + { + if( IsScalable() || GetPointSize() == aInstance->GetPointSize()) + delete aInstance; + else + { + if( !mNext) mNext = aInstance; + else mNext->Append( aInstance); + } + } + + FaceInstance *GetNext() { return mNext; } +}; + + +class FontFamily +{ + char *mFamName; + FaceInstance *mInstances; + FontFamily *mNext; + + public: + FontFamily( PFONTMETRICS aMetrics) : mFamName(0), mInstances(0), mNext(0) + { + mFamName = strdup( aMetrics->szFamilyname); + mInstances = new FaceInstance( aMetrics); + } + + ~FontFamily() + { + if( mFamName) free( mFamName); + delete mInstances; + delete mNext; + } + + void Append( FontFamily *aFamily) + { + if( !mNext) mNext = aFamily; + else mNext->Append( aFamily); + } + + FontFamily *GetNext() { return mNext; } + + FaceInstance *GetInstances() { return mInstances; } + const char *GetName() const { return mFamName; } + // XXX maybe have a method here to do the system atom-table thing + // ("good grief", I know...) +}; + +class FontLister +{ + FontFamily *mFamilies; + FontFamily *mCache; + PFONTMETRICS mMetrics; + + public: + // XXX ought to take a DC or PS or something... + FontLister() : mFamilies(0), mCache(0), mMetrics(0) + { + HPS hps = WinGetScreenPS( HWND_DESKTOP); + + // Get fontmetrics for the display + LONG lWant = 0, lFonts; + lFonts = GpiQueryFonts( hps, QF_PUBLIC | QF_PRIVATE, + 0, &lWant, 0, 0); + mMetrics = new FONTMETRICS [ lFonts ]; + + GpiQueryFonts( hps, QF_PUBLIC | QF_PRIVATE, 0, &lFonts, + sizeof( FONTMETRICS), mMetrics); + + // now stick 'em in our datastructures + for( LONG l = 0; l < lFonts; l++) + { + FontFamily *pFamily = FindFamily( mMetrics[l].szFamilyname); + if( pFamily) + { + FaceInstance *pInstance = new FaceInstance( mMetrics + l); + pFamily->GetInstances()->Append( pInstance); + } + else + { + pFamily = new FontFamily( mMetrics + l); + if( !mFamilies) mFamilies = pFamily; + else mFamilies->Append( pFamily); + } + } + + WinReleasePS( hps); + } + + ~FontLister() + { + delete mFamilies; + delete [] mMetrics; + } + + FontFamily *FindFamily( const char *aName) + { + if( !mCache || stricmp( mCache->GetName(), aName)) + { + FontFamily *pFamily = mFamilies; + while( pFamily) + { + if( !stricmp( pFamily->GetName(), aName)) + break; + pFamily = pFamily->GetNext(); + } + mCache = pFamily; + } + return mCache; + } + + FontFamily *GetFamilies() { return mFamilies; } +}; + +// Now declare a couple of iterators for font size and name. +// Could maybe share code somehow (base template class?) + +// Font-size iterator (xpcom) +class nsFontSizeIterator : public nsIFontSizeIterator +{ + FaceInstance *mFirst; + FaceInstance *mCurrent; + + public: + nsFontSizeIterator( FaceInstance *aFace) + : mFirst(aFace), mCurrent(aFace) + { + NS_INIT_REFCNT(); + } + + virtual ~nsFontSizeIterator() {} + + // nsISupports + NS_DECL_ISUPPORTS + + // nsIFontSizeIterator + NS_IMETHOD Reset() + { + mCurrent = mFirst; + return NS_OK; + } + + NS_IMETHOD Get( double *aFontSize) + { + nsresult rc = NS_ERROR_FAILURE; + if( mCurrent) + { + *aFontSize = mCurrent->GetPointSize(); + rc = NS_OK; + } + return rc; + } + + NS_IMETHOD Advance() + { + nsresult rc = NS_ERROR_FAILURE; + if( mCurrent) + { + mCurrent = mCurrent->GetNext(); + if( mCurrent) rc = NS_OK; + } + return rc; + } +}; + +NS_IMPL_ISUPPORTS(nsFontSizeIterator, nsIFontSizeIterator::GetIID()) + +// Font-name iterator (xpcom) +class nsFontNameIterator : public nsIFontNameIterator +{ + FontFamily *mFirst; + FontFamily *mCurrent; + + public: + nsFontNameIterator( FontFamily *aFamily) + : mFirst(aFamily), mCurrent(aFamily) + { + NS_INIT_REFCNT(); + } + + // nsISupports + NS_DECL_ISUPPORTS + + // nsIFontNameIterator + NS_IMETHOD Reset() + { + mCurrent = mFirst; + return NS_OK; + } + + NS_IMETHOD Get( nsString *aString) + { + nsresult rc = NS_ERROR_FAILURE; + if( mCurrent) + { + aString->SetString( mCurrent->GetName()); + rc = NS_OK; + } + return rc; + } + + NS_IMETHOD Advance() + { + nsresult rc = NS_ERROR_FAILURE; + if( mCurrent) + { + mCurrent = mCurrent->GetNext(); + if( mCurrent) rc = NS_OK; + } + return rc; + } +}; + +NS_IMPL_ISUPPORTS(nsFontNameIterator, nsIFontNameIterator::GetIID()) + +// font retriever service +NS_IMPL_ISUPPORTS(nsFontRetrieverService, nsIFontRetrieverService::GetIID()) + +nsFontRetrieverService::nsFontRetrieverService() +{ + NS_INIT_REFCNT(); + mFontLister = new FontLister; +} + +nsFontRetrieverService::~nsFontRetrieverService() +{ + delete mFontLister; +} + +nsresult +nsFontRetrieverService::CreateFontNameIterator( nsIFontNameIterator **aIterator) +{ + if( !aIterator) + return NS_ERROR_NULL_POINTER; + + *aIterator = new nsFontNameIterator( mFontLister->GetFamilies()); + NS_ADDREF(*aIterator); + + return NS_OK; +} + +nsresult +nsFontRetrieverService::CreateFontSizeIterator( const nsString &aFontName, + nsIFontSizeIterator **aIterator) +{ + if( !aIterator) + return NS_ERROR_NULL_POINTER; + + char buffer[100]; + gModuleData.ConvertFromUcs( aFontName, buffer, 100); + + FontFamily *pFamily = mFontLister->FindFamily( buffer); + if( !pFamily) + return NS_ERROR_FAILURE; + + *aIterator = new nsFontSizeIterator( pFamily->GetInstances()); + NS_ADDREF(*aIterator); + + return NS_OK; +} + +nsresult +nsFontRetrieverService::IsFontScalable( const nsString &aFontName, + PRBool *aResult) +{ + if( !aResult) + return NS_ERROR_NULL_POINTER; + + char buffer[100]; + gModuleData.ConvertFromUcs( aFontName, buffer, 100); + + FontFamily *pFamily = mFontLister->FindFamily( buffer); + if( !pFamily) + return NS_ERROR_FAILURE; + + *aResult = pFamily->GetInstances()->IsScalable(); + + return NS_OK; +} + +// singleton behaviour -- don't trust xpcom so do it ourselves +nsresult NS_GetFontService( nsISupports **aResult) +{ + if( !aResult) + return NS_ERROR_NULL_POINTER; + + if( !gModuleData.fontService) + { + gModuleData.fontService = new nsFontRetrieverService; + NS_ADDREF(gModuleData.fontService); + } + + *aResult = gModuleData.fontService; + return NS_OK; +} diff --git a/mozilla/widget/src/os2/nsFontServices.h b/mozilla/widget/src/os2/nsFontServices.h new file mode 100644 index 00000000000..e40abcaf0fd --- /dev/null +++ b/mozilla/widget/src/os2/nsFontServices.h @@ -0,0 +1,49 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsfontservices_h +#define _nsfontservices_h + +#include "nsIFontRetrieverService.h" + +class FontLister; + +class nsFontRetrieverService : public nsIFontRetrieverService +{ + FontLister *mFontLister; + + public: + nsFontRetrieverService(); + virtual ~nsFontRetrieverService(); + + // nsISupports + NS_DECL_ISUPPORTS + + // nsIFontRetrieverService + NS_IMETHOD CreateFontNameIterator( nsIFontNameIterator **aIterator); + NS_IMETHOD CreateFontSizeIterator( const nsString &aFontName, + nsIFontSizeIterator **aIterator); + NS_IMETHOD IsFontScalable( const nsString &aFontName, PRBool *aResult); +}; + +nsresult NS_GetFontService( nsISupports **aResult); + +#endif diff --git a/mozilla/widget/src/os2/nsFrameWindow.cpp b/mozilla/widget/src/os2/nsFrameWindow.cpp new file mode 100644 index 00000000000..18601f56317 --- /dev/null +++ b/mozilla/widget/src/os2/nsFrameWindow.cpp @@ -0,0 +1,202 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// Frame window - produced when NS_WINDOW_CID is required. + +#include "nsFrameWindow.h" + +nsFrameWindow::nsFrameWindow() : nsCanvas() +{ + hwndFrame = 0; + fnwpDefFrame = 0; +} + +nsFrameWindow::~nsFrameWindow() +{ +} + +// Called in the PM thread. +void nsFrameWindow::RealDoCreate( HWND hwndP, nsWindow *aParent, + const nsRect &aRect, + EVENT_CALLBACK aHandleEventFunction, + nsIDeviceContext *aContext, + nsIAppShell *aAppShell, + nsWidgetInitData *aInitData, HWND hwndO) +{ + NS_ASSERTION( hwndP == HWND_DESKTOP && aParent == nsnull, + "Attempt to create non-top-level frame"); + + // Create the frame window. + FRAMECDATA fcd = { sizeof( FRAMECDATA), 0, 0, 0 }; + fcd.flCreateFlags = GetFCFlags(); + + // Assume frames are toplevel. Breaks if anyone tries to do MDI, which + // is an extra bonus feature :-) + hwndFrame = WinCreateWindow( HWND_DESKTOP, + WC_FRAME, + 0, 0, // text, style + 0, 0, 0, 0, // position + HWND_DESKTOP, + HWND_TOP, + 0, // ID + &fcd, 0); + + // This is a bit weird; without an icon, we get WM_PAINT messages + // when minimized. They don't stop, giving maxed cpu. Go figure. + + NS_ASSERTION( hwndFrame, "Couldn't create frame"); + + // Now create the client as a child of us, triggers resize and sets + // up the client size (with any luck...) + nsCanvas::RealDoCreate( hwndFrame, nsnull, aRect, aHandleEventFunction, + aContext, aAppShell, aInitData, hwndO); + + // Subclass frame + fnwpDefFrame = WinSubclassWindow( hwndFrame, fnwpFrame); + WinSetWindowPtr( hwndFrame, QWL_USER, this); + BOOL brc = (BOOL) WinSendMsg( hwndFrame, WM_SETICON, + MPFROMLONG( gModuleData.GetFrameIcon()), 0); + + // make the client the client. + WinSetWindowUShort( mWnd, QWS_ID, FID_CLIENT); + WinSendMsg( hwndFrame, WM_UPDATEFRAME, 0, 0); // possibly superfluous + + // Set up initial client size + UpdateClientSize(); + + // Record frame hwnd somewhere that the window object can see during dtor + mHackDestroyWnd = hwndFrame; +} + +ULONG nsFrameWindow::GetFCFlags() +{ + return FCF_TITLEBAR | FCF_SYSMENU | FCF_SIZEBORDER | + FCF_MINMAX | FCF_TASKLIST | FCF_NOBYTEALIGN | + (gModuleData.bIsDBCS ? FCF_DBE_APPSTAT : 0); +} + +void nsFrameWindow::UpdateClientSize() +{ + RECTL rcl = { 0, 0, mBounds.width, mBounds.height }; + WinCalcFrameRect( hwndFrame, &rcl, TRUE); // provided == frame rect + mSizeClient.width = rcl.xRight - rcl.xLeft; + mSizeClient.height = rcl.yTop - rcl.yBottom; + mSizeBorder.width = (mBounds.width - mSizeClient.width) / 2; + mSizeBorder.height = (mBounds.height - mSizeClient.height) / 2; +} + +nsresult nsFrameWindow::GetClientBounds( nsRect &aRect) +{ + aRect.x = 0; + aRect.y = 0; + aRect.width = mSizeClient.width; + aRect.height = mSizeClient.height; + return NS_OK; +} + +nsresult nsFrameWindow::GetBorderSize( PRInt32 &aWidth, PRInt32 &aHeight) +{ + aWidth = mSizeBorder.width; + aHeight = mSizeBorder.height; + return NS_OK; +} + +// Just ignore this callback; the correct stuff is done in the frame wp. +PRBool nsFrameWindow::OnReposition( PSWP pSwp) +{ + return PR_TRUE; +} + +// For frame windows, 'Show' is equivalent to 'Show & Activate' +nsresult nsFrameWindow::Show( PRBool bState) +{ + if( mWnd) + { + nsWindow::Show( bState); + if( bState) + WinSetWindowPos( GetMainWindow(), 0, 0, 0, 0, 0, SWP_ACTIVATE); + } + + return NS_OK; +} + +// Subclass for frame window +MRESULT EXPENTRY fnwpFrame( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + nsFrameWindow *pFrame = (nsFrameWindow*) WinQueryWindowPtr( hwnd, QWL_USER); + return pFrame->FrameMessage( msg, mp1, mp2); +} + +// Process messages from the frame +MRESULT nsFrameWindow::FrameMessage( ULONG msg, MPARAM mp1, MPARAM mp2) +{ + MRESULT mRC = 0; + BOOL bDone = FALSE; + + switch( msg) + { + case WM_WINDOWPOSCHANGED: + { + PSWP pSwp = (PSWP) mp1; + + // Note that client windows never get 'move' messages (well, they won't here anyway) + if( pSwp->fl & SWP_MOVE && !(pSwp->fl & SWP_MINIMIZE)) + { + // These commented-out `-1's cancel each other out. + POINTL ptl = { pSwp->x, pSwp->y + pSwp->cy /* - 1 */ }; + ptl.y = gModuleData.szScreen.cy - ptl.y /* - 1*/ ; + mBounds.x = ptl.x; + mBounds.y = ptl.y; + OnMove( ptl.x, ptl.y); + } + + // When the frame is sized, do stuff to recalculate client size. + if( pSwp->fl & SWP_SIZE && !(pSwp->fl & SWP_MINIMIZE)) + { + mRC = (*fnwpDefFrame)( hwndFrame, msg, mp1, mp2); + bDone = TRUE; + + mBounds.width = pSwp->cx; + mBounds.height = pSwp->cy; + + UpdateClientSize(); + DispatchResizeEvent( mSizeClient.width, mSizeClient.height); + } + break; + } + + case WM_DESTROY: + WinSubclassWindow( hwndFrame, fnwpDefFrame); + WinSetWindowPtr( hwndFrame, QWL_USER, 0); + break; + + // adjust client size when menu appears or disappears. + case WM_UPDATEFRAME: + if( LONGFROMMP(mp1) & FCF_MENU) + UpdateClientSize(); + break; + } + + if( !bDone) + mRC = (*fnwpDefFrame)( hwndFrame, msg, mp1, mp2); + + return mRC; +} diff --git a/mozilla/widget/src/os2/nsFrameWindow.h b/mozilla/widget/src/os2/nsFrameWindow.h new file mode 100644 index 00000000000..87f0988bb72 --- /dev/null +++ b/mozilla/widget/src/os2/nsFrameWindow.h @@ -0,0 +1,81 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsframewindow_h +#define _nsframewindow_h + +// Widget needs to treat the frame/client as one window - it's only really +// interested in the client. +// +// mWnd is the client window; mBounds holds the frame rectangle relative to +// the desktop. +// +// The frame itself is subclassed so OnMove events for the client happen. + +#include "nscanvas.h" +#include "nssize.h" + +class nsFrameWindow : public nsCanvas +{ + public: + nsFrameWindow(); + virtual ~nsFrameWindow(); + + protected: + HWND hwndFrame; + PFNWP fnwpDefFrame; + nsSize mSizeClient; + nsSize mSizeBorder; + + // So we can create the frame, parent the client & position it right + virtual void RealDoCreate( HWND hwndP, nsWindow *aParent, + const nsRect &aRect, + EVENT_CALLBACK aHandleEventFunction, + nsIDeviceContext *aContext, + nsIAppShell *aAppShell, + nsWidgetInitData *aInitData, HWND hwndO); + + // hook so dialog can be created looking like a dialog + virtual ULONG GetFCFlags(); + + // So Destroy, Show, SetWindowPos, SetTitle, etc. work + HWND GetMainWindow() const { return hwndFrame; } + + // So correct sizing behaviour happens + PRBool OnReposition( PSWP pSwp); + + // Set up client sizes from frame dimensions + void UpdateClientSize(); + PRInt32 GetClientHeight() { return mSizeClient.height; } + + // So we can catch move messages + MRESULT FrameMessage( ULONG msg, MPARAM mp1, MPARAM mp2); + + NS_IMETHOD Show( PRBool bState); + + // We have client + NS_IMETHOD GetBorderSize( PRInt32 &aWidth, PRInt32 &aHeight); + NS_IMETHOD GetClientBounds( nsRect &aRect); + + friend MRESULT EXPENTRY fnwpFrame( HWND, ULONG, MPARAM, MPARAM); +}; + +#endif diff --git a/mozilla/widget/src/os2/nsLabel.cpp b/mozilla/widget/src/os2/nsLabel.cpp new file mode 100644 index 00000000000..6f8ae55e5ae --- /dev/null +++ b/mozilla/widget/src/os2/nsLabel.cpp @@ -0,0 +1,99 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include "nsLabel.h" + +// XP-com +NS_IMPL_ADDREF(nsLabel) +NS_IMPL_RELEASE(nsLabel) + +nsresult nsLabel::QueryInterface( const nsIID &aIID, void **aInstancePtr) +{ + nsresult result = nsWindow::QueryInterface( aIID, aInstancePtr); + + if( result == NS_NOINTERFACE && aIID.Equals( nsILabel::GetIID())) + { + *aInstancePtr = (void*) ((nsILabel*)this); + NS_ADDREF_THIS(); + result = NS_OK; + } + + return result; +} + +// nsLabel constructor +nsLabel::nsLabel() +{ + mAlignment = eAlign_Left; +} + +// Creation hook to create with correct aligment +nsresult nsLabel::PreCreateWidget( nsWidgetInitData *aInitData) +{ + if( nsnull != aInitData) + { + nsLabelInitData* data = (nsLabelInitData *) aInitData; + mAlignment = data->mAlignment; + } + return NS_OK; +} + +ULONG nsLabel::GetPMStyle( nsLabelAlignment aAlignment) +{ + ULONG rc = 0; + + switch( aAlignment) + { + case eAlign_Right : rc = DT_RIGHT; break; + case eAlign_Left : rc = DT_LEFT; break; + case eAlign_Center: rc = DT_CENTER; break; + } + + return rc; +} + +// Label style +nsresult nsLabel::SetAlignment( nsLabelAlignment aAlignment) +{ + if( mWnd && aAlignment != mAlignment) + { + // already created a PM window; remove current aligment & add new + RemoveFromStyle( GetPMStyle( mAlignment)); + AddToStyle( GetPMStyle( aAlignment)); + } + + mAlignment = aAlignment; + return NS_OK; +} + +// Label text +NS_IMPL_LABEL(nsLabel) + +// Creation hooks +PCSZ nsLabel::WindowClass() +{ + return WC_STATIC; +} + +ULONG nsLabel::WindowStyle() +{ + return BASE_CONTROL_STYLE | SS_TEXT | GetPMStyle( mAlignment); +} diff --git a/mozilla/widget/src/os2/nsLabel.h b/mozilla/widget/src/os2/nsLabel.h new file mode 100644 index 00000000000..120b348f84d --- /dev/null +++ b/mozilla/widget/src/os2/nsLabel.h @@ -0,0 +1,61 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsLabel_h +#define _nsLabel_h + +#include "nsWindow.h" +#include "nsILabel.h" + +// WC_STATIC, SS_TEXT wrapper for NS_LABEL_CID + +class nsLabel : public nsWindow, public nsILabel +{ + public: + nsLabel(); + + // nsISupports + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(void); + NS_IMETHOD_(nsrefcnt) Release(void); + + // nsILabel part + NS_DECL_LABEL + NS_IMETHOD SetAlignment( nsLabelAlignment aAlignment); + + // message stopping + virtual PRBool OnMove( PRInt32 aX, PRInt32 aY) { return PR_FALSE; } + virtual PRBool OnResize( PRInt32 aX, PRInt32 aY) { return PR_FALSE; } + + // platform hooks + NS_IMETHOD PreCreateWidget( nsWidgetInitData *aInitData); + + protected: + nsLabelAlignment mAlignment; + + // utility to get the pm style bit from the alignment enumeration value + ULONG GetPMStyle( nsLabelAlignment aAlignment); + + virtual PCSZ WindowClass(); + virtual ULONG WindowStyle(); +}; + +#endif diff --git a/mozilla/widget/src/os2/nsListBox.cpp b/mozilla/widget/src/os2/nsListBox.cpp new file mode 100644 index 00000000000..75412376697 --- /dev/null +++ b/mozilla/widget/src/os2/nsListBox.cpp @@ -0,0 +1,136 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include "nsListBox.h" + +// listbox; need more code here to allow multiple selections. + +NS_IMPL_ADDREF(nsListBox) +NS_IMPL_RELEASE(nsListBox) + +nsresult nsListBox::QueryInterface( const nsIID &aIID, void **aInstancePtr) +{ + nsresult result = nsWindow::QueryInterface( aIID, aInstancePtr); + + if( result == NS_NOINTERFACE) + { + if( aIID.Equals( nsIListBox::GetIID())) + { + *aInstancePtr = (void*) ((nsIListBox*)this); + NS_ADDREF_THIS(); + result = NS_OK; + } + else if( aIID.Equals( nsIListWidget::GetIID())) + { + *aInstancePtr = (void*) ((nsIListWidget*)this); + NS_ADDREF_THIS(); + result = NS_OK; + } + } + + return result; +} + +#define LS_U_MULTISEL (LS_MULTIPLESEL | LS_EXTENDEDSEL) + +nsresult nsListBox::SetMultipleSelection( PRBool aMultipleSelections) +{ + if( mWnd) + { + if( aMultipleSelections) + AddToStyle( LS_U_MULTISEL); + else + RemoveFromStyle( LS_U_MULTISEL); + } + else + { + if( aMultipleSelections) + mStyle |= LS_U_MULTISEL; + else + mStyle &= ~LS_U_MULTISEL; + } + return NS_OK; +} + +// Helper +PRInt32 nsListBox::GetSelections( PRInt32 *aIndices, PRInt32 aSize) +{ + PRInt32 cItems = 0; + short sItemStart = LIT_FIRST; + + for(;;) + { + sItemStart = SHORT1FROMMR( SendMsg( LM_QUERYSELECTION, + MPFROMSHORT(sItemStart))); + if( sItemStart == LIT_NONE) + break; + + if( aIndices && cItems < aSize) + aIndices[cItems] = sItemStart; + cItems++; + } + + return cItems; +} + +PRInt32 nsListBox::GetSelectedCount() +{ + return GetSelections( 0, 0); +} + +nsresult nsListBox::GetSelectedIndices( PRInt32 aIndices[], PRInt32 aSize) +{ + GetSelections( aIndices, aSize); + return NS_OK; +} + +nsresult nsListBox::SetSelectedIndices( PRInt32 aIndices[], PRInt32 aSize) +{ + // clear selection + Deselect(); + + for( int i = 0; i < aSize; i++) + SendMsg( LM_SELECTITEM, MPFROMSHORT( aIndices[i]), MPFROMLONG( TRUE)); + + return NS_OK; +} + +// Platform hooks +nsresult nsListBox::PreCreateWidget( nsWidgetInitData *aInitData) +{ + if( nsnull != aInitData) + { + nsListBoxInitData *data = (nsListBoxInitData *) aInitData; + if( data->mMultiSelect) + mStyle |= LS_U_MULTISEL; + } + return NS_OK; +} + +PCSZ nsListBox::WindowClass() +{ + return WC_LISTBOX; +} + +ULONG nsListBox::WindowStyle() +{ + return mStyle | LS_NOADJUSTPOS | BASE_CONTROL_STYLE; +} diff --git a/mozilla/widget/src/os2/nsListBox.h b/mozilla/widget/src/os2/nsListBox.h new file mode 100644 index 00000000000..461f4681e8a --- /dev/null +++ b/mozilla/widget/src/os2/nsListBox.h @@ -0,0 +1,65 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nslistbox_h +#define _nslistbox_h + +#include "nsWindow.h" +#include "nsBaseList.h" +#include "nsIListBox.h" + +// WC_LISTBOX wrapper for NS_LISTBOX_CID + +class nsListBox : public nsWindow, public nsIListBox, + public nsBaseList, public nsIListWidget +{ + public: + nsListBox() : mStyle(0) {} + + // nsISupports + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(void); + NS_IMETHOD_(nsrefcnt) Release(void); + + // baselist + DECL_BASE_LIST_METHODS + + // nsIListbox + NS_IMETHOD SetMultipleSelection( PRBool aMultipleSelections); + virtual PRInt32 GetSelectedCount(); + NS_IMETHOD GetSelectedIndices( PRInt32 aIndices[], PRInt32 aSize); + NS_IMETHOD SetSelectedIndices( PRInt32 aIndices[], PRInt32 aSize); + + // platform hooks + virtual PCSZ WindowClass(); + virtual ULONG WindowStyle(); + NS_IMETHOD PreCreateWidget( nsWidgetInitData *aInitData); + + // Message stopping + virtual PRBool OnMove( PRInt32 aX, PRInt32 aY) { return PR_FALSE; } + virtual PRBool OnResize( PRInt32 aX, PRInt32 aY) { return PR_FALSE; } + + protected: + PRInt32 GetSelections( PRInt32 *aIndices, PRInt32 aSize); + ULONG mStyle; +}; + +#endif diff --git a/mozilla/widget/src/os2/nsLookAndFeel.cpp b/mozilla/widget/src/os2/nsLookAndFeel.cpp new file mode 100644 index 00000000000..11b0e54d574 --- /dev/null +++ b/mozilla/widget/src/os2/nsLookAndFeel.cpp @@ -0,0 +1,177 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include "nsLookAndFeel.h" +#include "nsColor.h" +#include "nsWidgetDefs.h" + +#include + +// XPCom scaffolding +NS_IMPL_ISUPPORTS(nsLookAndFeel, nsILookAndFeel::GetIID()) + +nsLookAndFeel::nsLookAndFeel() +{ + NS_INIT_REFCNT(); +} + +// Colours +NS_IMETHODIMP nsLookAndFeel::GetColor(const nsColorID aID, nscolor &aColor) +{ + int idx = 0; + switch (aID) + { + case eColor_WindowBackground: idx = SYSCLR_BACKGROUND; break; + case eColor_WindowForeground: idx = SYSCLR_WINDOWTEXT; break; + case eColor_WidgetBackground: idx = SYSCLR_BUTTONMIDDLE; break; + case eColor_WidgetForeground: idx = SYSCLR_WINDOWTEXT; break; + case eColor_WidgetSelectBackground: idx = SYSCLR_HILITEBACKGROUND; break; + case eColor_WidgetSelectForeground: idx = SYSCLR_HILITEFOREGROUND; break; + case eColor_Widget3DHighlight: idx = SYSCLR_BUTTONLIGHT; break; + case eColor_Widget3DShadow: idx = SYSCLR_BUTTONDARK; break; + case eColor_TextBackground: idx = SYSCLR_ENTRYFIELD; break; + case eColor_TextForeground: idx = SYSCLR_WINDOWTEXT; break; + case eColor_TextSelectBackground: idx = SYSCLR_HILITEBACKGROUND; break; + case eColor_TextSelectForeground: idx = SYSCLR_HILITEFOREGROUND; break; + + default: + NS_ASSERTION(0, "Bad system colour"); + break; + } + + long lColor = WinQuerySysColor( HWND_DESKTOP, idx, 0); + + RGB2 *pRGB2 = (RGB2*) &lColor; + + aColor = NS_RGB( pRGB2->bRed, pRGB2->bGreen, pRGB2->bBlue); + + return NS_OK; +} + +// metrics +NS_IMETHODIMP nsLookAndFeel::GetMetric(const nsMetricID aID, PRInt32 & aMetric) +{ + long svalue = 0; + aMetric = 0; + + switch( aID) + { + case eMetric_WindowTitleHeight: svalue = SV_CYTITLEBAR; break; + case eMetric_WindowBorderWidth: svalue = SV_CXSIZEBORDER; break; + case eMetric_WindowBorderHeight: svalue = SV_CYSIZEBORDER; break; + case eMetric_Widget3DBorder: svalue = SV_CXBORDER; break; + case eMetric_TextFieldHeight: aMetric = gModuleData.lHtEntryfield; break; + + // + // These are copied from the Win32 version; changes welcome + // + case eMetric_TextVerticalInsidePadding: + aMetric = 0; + break; + case eMetric_TextShouldUseVerticalInsidePadding: + aMetric = 0; + break; + case eMetric_TextHorizontalInsideMinimumPadding: + aMetric = 3; + break; + case eMetric_TextShouldUseHorizontalInsideMinimumPadding: + aMetric = 1; + break; + + case eMetric_ButtonHorizontalInsidePaddingNavQuirks: + aMetric = 10; + break; + case eMetric_ButtonHorizontalInsidePaddingOffsetNavQuirks: + aMetric = 8; + break; + + case eMetric_CheckboxSize: + aMetric = 12; + break; + case eMetric_RadioboxSize: + aMetric = 12; + break; + + case eMetric_ListHorizontalInsideMinimumPadding: + aMetric = 3; + break; + case eMetric_ListShouldUseHorizontalInsideMinimumPadding: + aMetric = 0; + break; + case eMetric_ListVerticalInsidePadding: + aMetric = 0; + break; + case eMetric_ListShouldUseVerticalInsidePadding: + aMetric = 0; + break; + + default: + NS_ASSERTION( 0, "Bad metric"); + break; + } + + if( svalue != 0) + aMetric = WinQuerySysValue( HWND_DESKTOP, svalue); + + return NS_OK; +} + +// +// These are copied from the Win32 version; changes welcome +// +// float metrics +NS_IMETHODIMP nsLookAndFeel::GetMetric( const nsMetricFloatID aID, + float &aMetric) +{ + nsresult res = NS_OK; + switch( aID) + { + case eMetricFloat_TextFieldVerticalInsidePadding: + aMetric = 0.25f; + break; + case eMetricFloat_TextFieldHorizontalInsidePadding: + aMetric = 0.95f; + break; + case eMetricFloat_TextAreaVerticalInsidePadding: + aMetric = 0.40f; + break; + case eMetricFloat_TextAreaHorizontalInsidePadding: + aMetric = 0.40f; + break; + case eMetricFloat_ListVerticalInsidePadding: + aMetric = 0.10f; + break; + case eMetricFloat_ListHorizontalInsidePadding: + aMetric = 0.40f; + break; + case eMetricFloat_ButtonVerticalInsidePadding: + aMetric = 0.25f; + break; + case eMetricFloat_ButtonHorizontalInsidePadding: + aMetric = 0.25f; + break; + default: + aMetric = -1.0; + res = NS_ERROR_FAILURE; + break; + } + return res; +} diff --git a/mozilla/widget/src/os2/nsLookAndFeel.h b/mozilla/widget/src/os2/nsLookAndFeel.h new file mode 100644 index 00000000000..6db69a66761 --- /dev/null +++ b/mozilla/widget/src/os2/nsLookAndFeel.h @@ -0,0 +1,39 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsLookAndFeel_h +#define _nsLookAndFeel_h + +#include "nsILookAndFeel.h" + +class nsLookAndFeel: public nsILookAndFeel +{ + public: + nsLookAndFeel(); + + NS_DECL_ISUPPORTS + + NS_IMETHOD GetColor( const nsColorID aID, nscolor &aColor); + NS_IMETHOD GetMetric( const nsMetricID aID, PRInt32 &aMetric); + NS_IMETHOD GetMetric( const nsMetricFloatID aID, float &aMetric); +}; + +#endif diff --git a/mozilla/widget/src/os2/nsMenu.cpp b/mozilla/widget/src/os2/nsMenu.cpp new file mode 100644 index 00000000000..277bc3717fb --- /dev/null +++ b/mozilla/widget/src/os2/nsMenu.cpp @@ -0,0 +1,141 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// normal menu + +#include "nsMenu.h" +#include "nsIMenuBar.h" +#include "nsMenuItem.h" +#include "nsIContextMenu.h" + +#include "nsIWebShell.h" +#include "nsIDOMNode.h" +#include "nsIDOMElement.h" + +#include "nsCOMPtr.h" + +NS_IMPL_ADDREF(nsMenu) +NS_IMPL_RELEASE(nsMenu) + +nsresult nsMenu::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if( !aInstancePtr) + return NS_ERROR_NULL_POINTER; + + *aInstancePtr = 0; + + if( aIID.Equals(nsIMenu::GetIID())) + { + *aInstancePtr = (void*) ((nsIMenu*) this); + NS_ADDREF_THIS(); + return NS_OK; + } + if( aIID.Equals(nsIMenuListener::GetIID())) + { + *aInstancePtr = (void*) ((nsIMenuListener*)this); + NS_ADDREF_THIS(); + return NS_OK; + } + if( aIID.Equals(((nsISupports*)(nsIMenu*)this)->GetIID())) + { + *aInstancePtr = (void*) ((nsISupports*) ((nsIMenu*)this)); + NS_ADDREF_THIS(); + return NS_OK; + } + + return NS_NOINTERFACE; +} + +nsMenu::nsMenu() : mParent(nsnull) +{ + NS_INIT_REFCNT(); +} + +nsMenu::~nsMenu() +{ +} + +nsresult nsMenu::Create( nsISupports *aThing, const nsString &aLabel) +{ + if( !aThing) + return NS_ERROR_NULL_POINTER; + + void *pvHwnd = 0; + nsIMenu *aMenu = nsnull; + nsIContextMenu *aPopup = nsnull; + nsIMenuBar *aBar = nsnull; + + if( NS_SUCCEEDED( aThing->QueryInterface( nsIMenuBar::GetIID(), + (void**) &aBar))) + { + aBar->GetNativeData( pvHwnd); + NS_RELEASE(aBar); + } + else if( NS_SUCCEEDED( aThing->QueryInterface( nsIMenu::GetIID(), + (void**) &aMenu))) + { + aMenu->GetNativeData( &pvHwnd); + NS_RELEASE(aMenu); + } + else if( NS_SUCCEEDED( aThing->QueryInterface( nsIContextMenu::GetIID(), + (void**) &aPopup))) + { + aPopup->GetNativeData( &pvHwnd); + NS_RELEASE(aPopup); + } + + // This is a bit dubious, as there's no guarantee that this menu + // is being created in the same thread as the parent was. But this + // is probably moot... + + nsMenuBase *pPBase = (nsMenuBase*) WinQueryWindowPtr( (HWND) pvHwnd, QWL_USER); + + nsMenuBase::Create( HWND_DESKTOP, pPBase->GetTK()); + + // Connect up to parent menu component + WinSetOwner( mWnd, (HWND) pvHwnd); + mParent = aThing; + + // record text + mLabel = aLabel; + + return NS_OK; +} + +nsresult nsMenu::GetParent( nsISupports * &aParent) +{ + NS_IF_RELEASE(aParent); + aParent = mParent; + NS_IF_ADDREF(aParent); + return NS_OK; +} + +nsresult nsMenu::GetLabel( nsString &aText) +{ + aText = mLabel; + return NS_OK; +} + +nsresult nsMenu::SetLabel( const nsString &aText) +{ + mLabel = aText; + return NS_OK; +} diff --git a/mozilla/widget/src/os2/nsMenu.h b/mozilla/widget/src/os2/nsMenu.h new file mode 100644 index 00000000000..ef3ad943448 --- /dev/null +++ b/mozilla/widget/src/os2/nsMenu.h @@ -0,0 +1,53 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsMenu_h +#define _nsMenu_h + +// A submenu which reflects a DOM content model + +#include "nsIMenu.h" +#include "nsMenuBase.h" + +class nsMenu : public nsIMenu, public nsDynamicMenu +{ + public: + nsMenu(); + ~nsMenu(); + + // nsISupports + NS_DECL_ISUPPORTS + + // nsIMenu extras + NS_IMETHOD Create( nsISupports *aParent, const nsString &aLabel); + NS_IMETHOD GetParent( nsISupports *&aParent); + NS_IMETHOD GetLabel( nsString &aText); + NS_IMETHOD SetLabel( const nsString &aText); + + // Common methods + DECL_DYNAMIC_MENU_METHODS + + protected: + nsString mLabel; + nsISupports *mParent; +}; + +#endif diff --git a/mozilla/widget/src/os2/nsMenuBar.cpp b/mozilla/widget/src/os2/nsMenuBar.cpp new file mode 100644 index 00000000000..c11f3c28d06 --- /dev/null +++ b/mozilla/widget/src/os2/nsMenuBar.cpp @@ -0,0 +1,240 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// menu bar + +#include "nsWindow.h" +#include "nsMenuBar.h" +#include "nsMenu.h" + +#include "nsIWebShell.h" +#include "nsIDOMNode.h" +#include "nsIDOMElement.h" + +// XPCom +NS_IMPL_ADDREF(nsMenuBar) +NS_IMPL_RELEASE(nsMenuBar) + +nsresult nsMenuBar::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if( !aInstancePtr) + return NS_ERROR_NULL_POINTER; + + *aInstancePtr = 0; + + if( aIID.Equals(nsIMenuBar::GetIID())) + { + *aInstancePtr = (void*) ((nsIMenuBar*) this); + NS_ADDREF_THIS(); + return NS_OK; + } + if( aIID.Equals(nsIMenuListener::GetIID())) + { + *aInstancePtr = (void*) ((nsIMenuListener*)this); + NS_ADDREF_THIS(); + return NS_OK; + } + if( aIID.Equals(((nsISupports*)(nsIMenuBar*)this)->GetIID())) + { + *aInstancePtr = (void*) ((nsISupports*)((nsIMenuBar*)this)); + NS_ADDREF_THIS(); + return NS_OK; + } + + return NS_NOINTERFACE; +} + +nsMenuBar::nsMenuBar() : mWndFrame(nsnull), mParent(nsnull) +{ + NS_INIT_REFCNT(); +} + +nsMenuBar::~nsMenuBar() +{ +} + +// Creation +nsresult nsMenuBar::Create( nsIWidget *aParent) +{ + NS_ASSERTION(aParent,"Menu must have a parent"); + + nsToolkit *aToolkit = (nsToolkit*) aParent->GetToolkit(); + + mWndFrame = (HWND) aParent->GetNativeData( NS_NATIVE_WINDOW); + // + // Who knows what kind of window the client's given to us here. + // Search up the window hierarchy until we find a frame. + // + while( !((ULONG)aToolkit->SendMsg( mWndFrame, WM_QUERYFRAMEINFO) & FI_FRAME)) + mWndFrame = WinQueryWindow( mWndFrame, QW_PARENT); + + nsMenuBase::Create( mWndFrame, aToolkit); + NS_RELEASE(aToolkit); // add-ref'd by above call + + // must have id FID_MENU + WinSetWindowUShort( mWnd, QWS_ID, FID_MENU); + // tell the frame about us + UpdateFrame(); + + // remember parent + mParent = aParent; + + return NS_OK; +} + +ULONG nsMenuBar::WindowStyle() +{ + return MS_ACTIONBAR; +} + +nsresult nsMenuBar::GetParent( nsIWidget *&aParent) +{ + NS_IF_RELEASE(aParent); + aParent = mParent; + NS_ADDREF(aParent); + return NS_OK; +} + +nsresult nsMenuBar::SetParent( nsIWidget *aParent) +{ + // XXX oh dear. I don't really want to implement this. + // I guess we could work out what new frame window this + // is & then reparent ourselves, but ewwww. + printf( "nsMenuBar::SetParent() - tell someone\n"); + + return NS_OK; +} + +void nsMenuBar::UpdateFrame() +{ + if( mToolkit) + mToolkit->SendMsg( mWndFrame, WM_UPDATEFRAME, MPFROMLONG(FCF_MENU)); +} + +// Need to override these so we can tell the frame about the new entries +nsresult nsMenuBar::AddMenu( nsIMenu *aMenu) +{ + nsresult rc = nsMenuBase::InsertItemAt( aMenu); + UpdateFrame(); + return rc; +} + +nsresult nsMenuBar::InsertMenuAt( const PRUint32 aCount, nsIMenu *&aMenu) +{ + nsresult rc = nsMenuBase::InsertItemAt( aMenu, aCount); + UpdateFrame(); + return rc; +} + +nsresult nsMenuBar::RemoveMenu( const PRUint32 aCount) +{ + nsresult rc = nsMenuBase::RemoveItemAt( aCount); + UpdateFrame(); + return rc; +} + +nsresult nsMenuBar::RemoveAll() +{ + nsresult rc = nsMenuBase::RemoveAll(); + UpdateFrame(); + return rc; +} + +// accessor +nsresult nsMenuBar::GetMenuAt( const PRUint32 aCount, nsIMenu *&aMenu) +{ + nsresult rc = NS_ERROR_FAILURE; + + NS_IF_RELEASE(aMenu); + + if( VerifyIndex( aCount)) + { + MENUITEM mI; + nsMenuBase::GetItemAt( aCount, &mI); + + nsISupports *aThing = (nsISupports*) mI.hItem; + rc = aThing->QueryInterface( nsIMenu::GetIID(), (void**) &aMenu); + } + + return rc; +} + +// hmm +nsresult nsMenuBar::Paint() +{ + UpdateFrame(); + mParent->Invalidate( PR_TRUE); + return NS_OK; +} + +// nsIMenuListener interface - used to update menu dynamically and build it +// from a dom content model + +// nsWebShellWindow currently fakes a call into here to kick us off +nsEventStatus nsMenuBar::MenuConstruct( const nsMenuEvent &aMenuEvent, + nsIWidget *aParentWindow, + void *aMenubarNode, + void *aWebShell) +{ + nsIWebShell *pWebShell = (nsIWebShell*) aWebShell; + nsIDOMNode *pMenubarNode = (nsIDOMNode*) aMenubarNode; + + // Create the menubar, register for notifications with the window + Create( aParentWindow); + aParentWindow->AddMenuListener( this); + aParentWindow->SetMenuBar( this); + + // Now iterate through the DOM children creating submenus. + nsCOMPtr pMenuNode; + pMenubarNode->GetFirstChild( getter_AddRefs(pMenuNode)); + while( pMenuNode) + { + nsCOMPtr pMenuElement( do_QueryInterface(pMenuNode)); + if( pMenuElement) + { + nsString nodeType, menuName; + pMenuElement->GetNodeName( nodeType); + if( nodeType.Equals( "menu")) + { + // new submenu + pMenuElement->GetAttribute( nsAutoString( "name"), menuName); + nsIMenu *pMenu = new nsMenu; + NS_ADDREF(pMenu); + pMenu->Create( (nsIMenuBar*)this, menuName); + pMenu->SetDOMNode( pMenuNode); + pMenu->SetDOMElement( pMenuElement); + pMenu->SetWebShell( pWebShell); + + // insert into menubar; nsMenuBase takes ownership + AddMenu( pMenu); + NS_RELEASE(pMenu); + } + } + nsCOMPtr pOldNode( pMenuNode); + pOldNode->GetNextSibling( getter_AddRefs(pMenuNode)); + } + + // Hackish -- nsWebShellWindow doesn't cut its ref, so leave the frame + // window with ownership. + Release(); // can't call NS_RELEASE 'cos |this| is not an lvalue... + + return nsEventStatus_eIgnore; +} diff --git a/mozilla/widget/src/os2/nsMenuBar.h b/mozilla/widget/src/os2/nsMenuBar.h new file mode 100644 index 00000000000..7d139e25294 --- /dev/null +++ b/mozilla/widget/src/os2/nsMenuBar.h @@ -0,0 +1,70 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsMenubar_h +#define _nsMenubar_h + +// menubar; WC_MENU with MS_ACTIONBAR + +#include "nsMenuBase.h" +#include "nsIMenuBar.h" + +class nsMenuBar : public nsIMenuBar, public nsMenuBase +{ + public: + nsMenuBar(); + ~nsMenuBar(); + + // nsISupports + NS_DECL_ISUPPORTS + + // nsIMenuBar + NS_IMETHOD Create( nsIWidget *aParent); + NS_IMETHOD GetParent( nsIWidget *&aParent); + NS_IMETHOD SetParent( nsIWidget *aParent); + NS_IMETHOD AddMenu( nsIMenu *aMenu); + NS_IMETHOD InsertMenuAt( const PRUint32 aCount, nsIMenu *&aMenu); + NS_IMETHOD GetMenuCount( PRUint32 &aCount) + { return nsMenuBase::GetItemCount( aCount); } + NS_IMETHOD GetMenuAt( const PRUint32 aCount, nsIMenu *&aMenu); + NS_IMETHOD RemoveMenu( const PRUint32 aCount); + NS_IMETHOD RemoveAll(); + NS_IMETHOD GetNativeData( void *&aData) + { return nsMenuBase::GetNativeData( &aData); } + NS_IMETHOD Paint(); + + // strange mac method + NS_IMETHOD SetNativeData( void *aData) { return NS_OK; } + + // nsIMenuListener interface + nsEventStatus MenuConstruct( const nsMenuEvent &aMenuEvent, + nsIWidget *aParentWindow, + void *menubarNode, + void *aWebShell); + protected: + ULONG WindowStyle(); + void UpdateFrame(); + + HWND mWndFrame; // hang on to the frame hwnd so we can update it + nsIWidget *mParent; // nsIWidget for the frame/client window +}; + +#endif diff --git a/mozilla/widget/src/os2/nsMenuBase.cpp b/mozilla/widget/src/os2/nsMenuBase.cpp new file mode 100644 index 00000000000..8d0fc2c4b03 --- /dev/null +++ b/mozilla/widget/src/os2/nsMenuBase.cpp @@ -0,0 +1,430 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include "nsMenuBase.h" +#include "nsMenuItem.h" +#include "nsMenu.h" +#include "nsToolkit.h" +#include "nsISupportsArray.h" + +#include "nsCOMPtr.h" +#include "nsIDOMNode.h" +#include "nsIDOMElement.h" + +// Common code used by menu classes + +nsMenuBase::nsMenuBase() : mToolkit(0), mWnd(0), mElements(nsnull) +{} + +void nsMenuBase::Create( HWND hwndParent, nsToolkit *aToolkit) +{ + NS_ASSERTION( aToolkit, "Missing toolkit in menucreation"); + + mToolkit = aToolkit; + NS_ADDREF(mToolkit); + + // thread-switch if necessary + if( !mToolkit->IsPMThread()) + { + NS_NOTYETIMPLEMENTED( "Threaded menus"); + } + else + { + mWnd = WinCreateWindow( hwndParent, + WC_MENU, + 0, // text + WindowStyle(), + 0, 0, 0, 0, // pos/size + hwndParent, // owner + HWND_TOP, + 0, // window ID + 0, 0); // ctldata, presparams + NS_ASSERTION( mWnd, "No menu window"); + + // store nsMenuBase * in QWL_USER + WinSetWindowPtr( mWnd, QWL_USER, this); + + // nice font (hmm) + WinSetPresParam( mWnd, PP_FONTNAMESIZE, + strlen( gModuleData.pszFontNameSize) + 1, + gModuleData.pszFontNameSize); + + NS_NewISupportsArray( &mElements); + } +} + +ULONG nsMenuBase::WindowStyle() +{ + return 0; +} + +void nsMenuBase::Destroy() +{ + if( mToolkit) + if( !mToolkit->IsPMThread()) + { + NS_NOTYETIMPLEMENTED( "Threaded menus"); + } + else + { + // XXX Not sure about this -- need to think more. + // Shouldn't it be dealt with by the normal parent-death process? + WinDestroyWindow( mWnd); + mWnd = 0; + } +} + +// dumb helper +MRESULT nsMenuBase::SendMsg( ULONG m, MPARAM mp1, MPARAM mp2) +{ + MRESULT mrc = 0; + if( mToolkit) + mrc = mToolkit->SendMsg( mWnd, m, mp1, mp2); + return mrc; +} + +nsMenuBase::~nsMenuBase() +{ + if( mWnd) Destroy(); + NS_IF_RELEASE(mToolkit); + NS_IF_RELEASE(mElements); +} + +nsresult nsMenuBase::GetItemCount( PRUint32 &aCount) +{ + MRESULT rc = SendMsg( MM_QUERYITEMCOUNT); + aCount = SHORT1FROMMP( rc); + return NS_OK; +} + +nsresult nsMenuBase::GetNativeData( void **aNative) +{ + *aNative = (void*) mWnd; + return NS_OK; +} + +// New all-singing, all-dancing insert routine. +// +// The 'aThing' may be an nsIMenu or an nsIMenuItem, joy. +// If it is null, then we're talking about a separator, though this ought +// not to be used. +nsresult nsMenuBase::InsertItemAt( nsISupports *aThing, PRUint32 aPos) +{ + nsIMenu *pMenu = nsnull; + nsIMenuItem *pItem = nsnull; + MENUITEM mI = { aPos, 0, 0, 0, 0, (ULONG) aThing }; + char *pStr = nsnull; + + // XXX needs to use unicode converter to get right text + // This is very much an issue now that menus are constructed + // from XUL and so can have an arbitrary encoding. + // + // Whether PM will know what to do with non-western characters + // is another issue! Probably okay if it's in the process' + // codepage (font set via presparams, which take that cp) + + // set up menitem depending on what we have... + if( nsnull == aThing) + { + mI.afStyle |= MIS_SEPARATOR; + } + else if( NS_SUCCEEDED( aThing->QueryInterface( nsIMenu::GetIID(), + (void**) &pMenu))) + { + void *hwnd = nsnull; + + nsString aString; + pMenu->GetLabel( aString); + pStr = gModuleData.ConvertFromUcs( aString); + + mI.afStyle |= MIS_SUBMENU | MIS_TEXT; + + pMenu->GetNativeData( &hwnd); + mI.hwndSubMenu = (HWND) hwnd; + + NS_RELEASE(pMenu); + } + else if( NS_SUCCEEDED( aThing->QueryInterface( nsIMenuItem::GetIID(), + (void**) &pItem))) + { + nsMenuItem *pPMItem = (nsMenuItem*) pItem; // XXX + nsString aString; + PRBool bIsSep = PR_FALSE; + + mI.id = pPMItem->GetPMID(); + + pPMItem->IsSeparator( bIsSep); + if( bIsSep) + { + mI.afStyle |= MIS_SEPARATOR; + } + else + { + mI.afStyle |= MIS_TEXT; + pPMItem->GetLabel( aString); + pStr = gModuleData.ConvertFromUcs( aString); + } + NS_RELEASE(pItem); + } + else + { +#ifdef DEBUG + printf( "Erk, strange menu thing being added\n"); +#endif + return NS_ERROR_FAILURE; + } + + // add menu item to gui + SendMsg( MM_INSERTITEM, MPFROMP(&mI), MPFROMP(pStr)); + // ..and take ownership of it (separators don't have it) + if( aThing) + mElements->InsertElementAt( aThing, 0); + + return NS_OK; +} + +// Pull items off of a menu +nsresult nsMenuBase::GetItemID( USHORT usID, PMENUITEM pItem) +{ + SendMsg( MM_QUERYITEM, MPFROM2SHORT(usID, FALSE), MPFROMP(pItem)); + return NS_OK; +} + +nsresult nsMenuBase::GetItemAt( const PRUint32 &pos, PMENUITEM pItem) +{ + nsresult rc = NS_ERROR_ILLEGAL_VALUE; + + if( VerifyIndex( pos)) + { + // find the ID + MRESULT mrc = SendMsg( MM_ITEMIDFROMPOSITION, MPFROMLONG(pos)); + rc = GetItemID( SHORT1FROMMR(mrc), pItem); + rc = NS_OK; + } + return rc; +} + +nsresult nsMenuBase::GetItemAt( const PRUint32 &aPos, nsISupports *&aThing) +{ + MENUITEM mI = { 0 }; + nsresult rc = GetItemAt( aPos, &mI); + + if( NS_SUCCEEDED(rc)) + { + NS_IF_RELEASE(aThing); // XP-COM correct, but probably bad, sigh. + + // This is either an nsIMenu or an nsIMenuItem + aThing = (nsISupports*) mI.hItem; + NS_ADDREF(aThing); + } + + return rc; +} + +// Update an item (grey, tick) +nsresult nsMenuBase::UpdateItem( PMENUITEM aItem) +{ + SendMsg( MM_SETITEM, 0, MPFROMP(aItem)); + return NS_OK; +} + +nsresult nsMenuBase::RemoveItemAt( const PRUint32 index) +{ + MENUITEM mI = { 0 }; + nsresult rc = GetItemAt( index, &mI); + + if( NS_SUCCEEDED(rc)) + { + // remove item from gui + SendMsg( MM_REMOVEITEM, MPFROM2SHORT( mI.id, FALSE)); + + // remove item from our list if we have it (& hence delete the window) + nsISupports *pThing = (nsISupports*) mI.hItem; + PRInt32 lIndex = 0; + if( pThing && NS_SUCCEEDED( mElements->GetIndexOf( pThing, &lIndex))) + rc = mElements->DeleteElementAt( lIndex); + } + + return rc; +} + +nsresult nsMenuBase::RemoveAll() +{ + PRUint32 count; + GetItemCount( count); + + for( PRUint32 i = 0; i < count; i++) + RemoveItemAt( 0); + + return NS_OK; +} + +BOOL nsMenuBase::VerifyIndex( PRUint32 index) +{ + PRUint32 count; + GetItemCount( count); + return index == NS_MIT_END || index < count; +} + +// Dummy nsIMenuListener implementation + +nsEventStatus nsMenuBase::MenuItemSelected( const nsMenuEvent &aMenuEvent) +{ + return nsEventStatus_eIgnore; +} + +nsEventStatus nsMenuBase::MenuSelected(const nsMenuEvent & aMenuEvent) +{ + return nsEventStatus_eIgnore; +} + +nsEventStatus nsMenuBase::MenuDeselected(const nsMenuEvent & aMenuEvent) +{ + return nsEventStatus_eIgnore; +} + +nsEventStatus nsMenuBase::MenuDestruct( const nsMenuEvent &aMenuEvent) +{ + return nsEventStatus_eIgnore; +} + +nsEventStatus nsMenuBase::MenuConstruct( const nsMenuEvent &aMenuEvent, + nsIWidget *aParentWindow, + void *menubarNode, + void *aWebShell) +{ + return nsEventStatus_eIgnore; +} + +// nsDynamicMenu, common base class for context & 'normal' menus +// +nsDynamicMenu::nsDynamicMenu() : mListener(0), mWebShell(0), + mDOMNode(0), mDOMElement(0) +{} + +nsDynamicMenu::~nsDynamicMenu() +{ + NS_IF_RELEASE(mListener); +} + +nsresult nsDynamicMenu::AddMenuListener( nsIMenuListener *aMenuListener) +{ + if( !aMenuListener) + return NS_ERROR_NULL_POINTER; + + NS_IF_RELEASE(mListener); + mListener = aMenuListener; + NS_ADDREF(mListener); + + return NS_OK; +} + +nsresult nsDynamicMenu::RemoveMenuListener( nsIMenuListener *aMenuListener) +{ + if( aMenuListener == mListener) + NS_IF_RELEASE(mListener); + return NS_OK; +} + +nsresult nsDynamicMenu::SetDOMNode( nsIDOMNode *aMenuNode) +{ + mDOMNode = aMenuNode; + return NS_OK; +} + +nsresult nsDynamicMenu::SetDOMElement( nsIDOMElement *aMenuElement) +{ + mDOMElement = aMenuElement; + return NS_OK; +} + +nsresult nsDynamicMenu::SetWebShell( nsIWebShell *aWebShell) +{ + mWebShell = aWebShell; + return NS_OK; +} + +// build the menu from the DOM content model. +// +// Note that the tear-down from the previous display is done in the init for +// the next menu so that the MENUITEMs are valid for WM_COMMAND dispatching +// +nsEventStatus nsDynamicMenu::MenuSelected( const nsMenuEvent &aMenuEvent) +{ + RemoveAll(); + + // Go through children of menu node and populate menu + nsCOMPtr pItemNode; + mDOMNode->GetFirstChild( getter_AddRefs(pItemNode)); + + while( pItemNode) + { + nsCOMPtr pItemElement( do_QueryInterface(pItemNode)); + if( pItemElement) + { + nsString nodeType; + pItemElement->GetNodeName( nodeType); + if( nodeType.Equals( "menuitem")) + { + // find attributes of menu item & create gui peer + nsString itemName; + nsIMenuItem *pItem = new nsMenuItem; + NS_ADDREF(pItem); + pItemElement->GetAttribute( nsAutoString("name"), itemName); + pItem->Create( (nsIMenu*)this, itemName, PR_FALSE); + InsertItemAt( pItem); + + nsString itemCmd, disabled, checked; + pItemElement->GetAttribute( nsAutoString("onclick"), itemCmd); + pItemElement->GetAttribute( nsAutoString("disabled"), disabled); + pItemElement->GetAttribute( nsAutoString("checked"), checked); + pItem->SetCommand( itemCmd); + pItem->SetWebShell( mWebShell); + pItem->SetDOMElement( pItemElement); + pItem->SetEnabled( !disabled.Equals( nsAutoString("true"))); + pItem->SetChecked( checked.Equals( nsAutoString("true"))); + NS_RELEASE(pItem); // ownership of the item has passed to nsMenuBase + } + else if( nodeType.Equals( "separator")) + InsertItemAt( 0); + else if( nodeType.Equals( "menu")) + { + // new submenu + nsString menuName; + nsIMenu *pMenu = new nsMenu; + NS_ADDREF(pMenu); + pItemElement->GetAttribute( nsAutoString("name"), menuName); + pMenu->Create( (nsIMenu*)this, menuName); + pMenu->SetDOMNode( pItemNode); + pMenu->SetDOMElement( pItemElement); + pMenu->SetWebShell( mWebShell); + + // insert into menubar + InsertItemAt( pMenu); + NS_RELEASE(pMenu); // owned in nsMenuBase + } + } + nsCOMPtr pOldNode( pItemNode); + pOldNode->GetNextSibling( getter_AddRefs(pItemNode)); + } + + return nsEventStatus_eIgnore; +} diff --git a/mozilla/widget/src/os2/nsMenuBase.h b/mozilla/widget/src/os2/nsMenuBase.h new file mode 100644 index 00000000000..3ddc5653f61 --- /dev/null +++ b/mozilla/widget/src/os2/nsMenuBase.h @@ -0,0 +1,141 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsmenubase_h +#define _nsmenubase_h + +#include "nsWidgetDefs.h" +#include "nsIMenuListener.h" + +class nsString; +class nsIWebShell; +class nsIDOMElement; +class nsIDOMNode; +class nsISupportsArray; + +// Base class for the various menu widgets to share code. + +class nsToolkit; + +class nsMenuBase : public nsIMenuListener +{ + public: + nsMenuBase(); + virtual ~nsMenuBase(); + + // common menu methods + NS_IMETHOD GetItemCount( PRUint32 &aCount); + NS_IMETHOD InsertItemAt( nsISupports *aThing, PRUint32 aPos = NS_MIT_END); + NS_IMETHOD GetItemID( USHORT usID, PMENUITEM pItem); + NS_IMETHOD GetItemAt( const PRUint32 &pos, PMENUITEM pItem); + NS_IMETHOD GetItemAt( const PRUint32 &pos, nsISupports *&aThing); + NS_IMETHOD UpdateItem( PMENUITEM pItem); + NS_IMETHOD RemoveItemAt( const PRUint32 index); + NS_IMETHOD RemoveAll(); + NS_IMETHOD GetNativeData( void **aNative); + + // dummy nsIMenuListener implementation + virtual nsEventStatus MenuSelected( const nsMenuEvent &aMenuEvent); + virtual nsEventStatus MenuItemSelected( const nsMenuEvent &aMenuEvent); + virtual nsEventStatus MenuDeselected( const nsMenuEvent &aMenuEvent); + virtual nsEventStatus MenuConstruct( const nsMenuEvent &aMenuEvent, + nsIWidget *aParentWindow, + void *menubarNode, + void *aWebShell); + virtual nsEventStatus MenuDestruct( const nsMenuEvent &aMenuEvent); + + // helpers + MRESULT SendMsg( ULONG m, MPARAM mp1=0, MPARAM mp2=0); + nsToolkit *GetTK() { return mToolkit; } + + protected: + virtual BOOL VerifyIndex( PRUint32 index); + + void Create( HWND hwndParent, nsToolkit *aToolkit); + void Destroy(); + + // Subclasses should supply extra style bits here if required. + virtual ULONG WindowStyle(); + + nsToolkit *mToolkit; + HWND mWnd; + nsISupportsArray *mElements; // we now own the menu elements +}; + +#define DECL_MENU_BASE_METHODS \ + NS_IMETHOD AddItem( nsISupports *aThing) \ + { return nsMenuBase::InsertItemAt( aThing); } \ + NS_IMETHOD AddSeparator() \ + { return nsMenuBase::InsertItemAt( nsnull); } \ + NS_IMETHOD GetItemCount( PRUint32 &aCount) \ + { return nsMenuBase::GetItemCount( aCount); } \ + NS_IMETHOD GetItemAt( const PRUint32 aCount, nsISupports *&aThing) \ + { return nsMenuBase::GetItemAt( aCount, aThing); } \ + NS_IMETHOD InsertItemAt( const PRUint32 aCount, nsISupports *aThing) \ + { return nsMenuBase::InsertItemAt( aThing, aCount); } \ + NS_IMETHOD InsertSeparator( const PRUint32 aCount) \ + { return nsMenuBase::InsertItemAt( nsnull, aCount); } \ + NS_IMETHOD RemoveItem( const PRUint32 aCount) \ + { return nsMenuBase::RemoveItemAt( aCount); } \ + NS_IMETHOD RemoveAll() \ + { return nsMenuBase::RemoveAll(); } \ + NS_IMETHOD GetNativeData( void **aNative) \ + { return nsMenuBase::GetNativeData( aNative); } + +// Base class for nsMenu & nsContextMenu, menus whose contents are build afresh +// from the DOM content model on each activation. +class nsDynamicMenu : public nsMenuBase +{ + public: + nsDynamicMenu(); + virtual ~nsDynamicMenu(); + + // Common methods + NS_IMETHOD AddMenuListener( nsIMenuListener *aMenuListener); + NS_IMETHOD RemoveMenuListener( nsIMenuListener *aMenuListener); + NS_IMETHOD SetDOMNode( nsIDOMNode *aMenuNode); + NS_IMETHOD SetDOMElement( nsIDOMElement *aMenuElement); + NS_IMETHOD SetWebShell( nsIWebShell *aWebShell); + + // nsIMenuListener override to build/tear down the menu + virtual nsEventStatus MenuSelected( const nsMenuEvent &aMenuEvent); + + protected: + nsIMenuListener *mListener; + nsIWebShell *mWebShell; + nsIDOMNode *mDOMNode; + nsIDOMElement *mDOMElement; +}; + +#define DECL_DYNAMIC_MENU_METHODS \ + DECL_MENU_BASE_METHODS \ + NS_IMETHOD AddMenuListener( nsIMenuListener *aMenuListener) \ + { return nsDynamicMenu::AddMenuListener( aMenuListener); } \ + NS_IMETHOD RemoveMenuListener( nsIMenuListener *aMenuListener) \ + { return nsDynamicMenu::RemoveMenuListener( aMenuListener); } \ + NS_IMETHOD SetDOMNode( nsIDOMNode *aMenuNode) \ + { return nsDynamicMenu::SetDOMNode( aMenuNode); } \ + NS_IMETHOD SetDOMElement( nsIDOMElement *aMenuElement) \ + { return nsDynamicMenu::SetDOMElement( aMenuElement); } \ + NS_IMETHOD SetWebShell( nsIWebShell *aWebShell) \ + { return nsDynamicMenu::SetWebShell( aWebShell); } + +#endif diff --git a/mozilla/widget/src/os2/nsMenuItem.cpp b/mozilla/widget/src/os2/nsMenuItem.cpp new file mode 100644 index 00000000000..aca317de69d --- /dev/null +++ b/mozilla/widget/src/os2/nsMenuItem.cpp @@ -0,0 +1,387 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// menu item + +#include "nsWidgetDefs.h" +#include "nsMenuItem.h" +#include "nsMenuBase.h" +#include "nsIMenu.h" +#include "nsIContextMenu.h" +#include "nsIMenuBar.h" +#include "nsWindow.h" + +#include "nsIDocumentViewer.h" +#include "nsIContent.h" +#include "nsIPresContext.h" +#include "nsIWebShell.h" +#include "nsIDOMElement.h" + +// XP-Com +NS_IMPL_ADDREF(nsMenuItem) +NS_IMPL_RELEASE(nsMenuItem) + +nsresult nsMenuItem::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if( nsnull == aInstancePtr) + return NS_ERROR_NULL_POINTER; + + *aInstancePtr = nsnull; + + if( aIID.Equals(nsIMenuItem::GetIID())) + { + *aInstancePtr = (void*) ((nsIMenuItem*) this); + NS_ADDREF_THIS(); + return NS_OK; + } + if( aIID.Equals(nsIMenuListener::GetIID())) + { + *aInstancePtr = (void*) ((nsIMenuListener*)this); + NS_ADDREF_THIS(); + return NS_OK; + } + if( aIID.Equals(((nsISupports*)(nsIMenuItem*)this)->GetIID())) + { + *aInstancePtr = (void*) ((nsISupports*)((nsIMenuItem*)this)); + NS_ADDREF_THIS(); + return NS_OK; + } + + return NS_NOINTERFACE; +} + +// Constructor +nsMenuItem::nsMenuItem() : mMenuBase(nsnull), mIsSeparator(PR_FALSE), + mTarget(nsnull), mPMID(0), mMenuListener(nsnull), + mDOMElement(nsnull), mWebShell(nsnull) +{ + NS_INIT_REFCNT(); +} + +nsMenuItem::~nsMenuItem() +{ + NS_IF_RELEASE(mMenuListener); +} + +// Helper function to find the widget at the root of the menu tree. +// +// This may have to traverse an arbitrary number of cascaded menus. + +static nsIWidget *FindWidget( nsISupports *aParent) +{ + nsIWidget *widget = nsnull; + nsIMenu *menu = nsnull; + nsIMenuBar *menuBar = nsnull; + nsIContextMenu *popup = nsnull; + nsISupports *parent = aParent; + + // Bump the ref count on the parent, since it gets released unconditionally.. + NS_ADDREF(parent); + for( ;;) + { + if( NS_OK == parent->QueryInterface( nsIMenu::GetIID(), (void**) &menu)) + { + NS_RELEASE(parent); + if( NS_OK != menu->GetParent(parent)) + { + NS_RELEASE(menu); + return nsnull; + } + NS_RELEASE(menu); + } + else if( NS_OK == parent->QueryInterface( nsIContextMenu::GetIID(), + (void**) &popup)) + { + nsISupports *pThing = 0; + if( NS_OK != popup->GetParent( pThing)) + { + widget = nsnull; + } + pThing->QueryInterface( nsIWidget::GetIID(), (void**) &widget); + NS_RELEASE(parent); + NS_RELEASE(popup); + return widget; + } + else if( NS_OK == parent->QueryInterface( nsIMenuBar::GetIID(), + (void**) &menuBar)) + { + if( NS_OK != menuBar->GetParent(widget)) + { + widget = nsnull; + } + NS_RELEASE(parent); + NS_RELEASE(menuBar); + return widget; + } + else + { + NS_RELEASE(parent); + return nsnull; + } + } + return nsnull; +} + +nsresult nsMenuItem::Create( nsISupports *aParent, const nsString &aLabel, + PRBool aIsSeparator) +{ + nsIContextMenu *pPopup = nsnull; + nsIMenu *pMenu = nsnull; + + void *pvWnd = 0; + + if( NS_SUCCEEDED( aParent->QueryInterface( nsIMenu::GetIID(), + (void**) &pMenu))) + { + pMenu->GetNativeData( &pvWnd); + NS_RELEASE(pMenu); + } + else if( NS_SUCCEEDED( aParent->QueryInterface( nsIContextMenu::GetIID(), + (void**) &pPopup))) + { + pPopup->GetNativeData( &pvWnd); + NS_RELEASE(pPopup); + } + + mMenuBase = (nsMenuBase*) WinQueryWindowPtr( (HWND) pvWnd, QWL_USER); + mLabel = aLabel; + + mTarget = FindWidget( aParent); + NS_ASSERTION(mTarget,"Can't find window to target menuitem to"); + if( mTarget) + { + mIsSeparator = aIsSeparator; + + HWND hwnd = (HWND) mTarget->GetNativeData( NS_NATIVE_WINDOW); + nsWindow *wnd = NS_HWNDToWindow( hwnd); // doesn't addref + mPMID = wnd->GetNextCmdID(); + mTarget->Release(); // don't want to hold a ref to the window + } + + return NS_OK; +} + +nsresult nsMenuItem::GetLabel( nsString &aText) +{ + aText = mLabel; + return NS_OK; +} + +nsresult nsMenuItem::SetLabel( nsString &aText) +{ + mLabel = aText; + return NS_OK; +} + +// menuitem style +nsresult nsMenuItem::SetEnabled( PRBool aIsEnabled) +{ + MENUITEM mI; + mMenuBase->GetItemID( mPMID, &mI); + if( PR_TRUE == aIsEnabled) + mI.afAttribute &= ~MIA_DISABLED; + else + mI.afAttribute |= MIA_DISABLED; + mMenuBase->UpdateItem( &mI); + return NS_OK; +} + +nsresult nsMenuItem::GetEnabled( PRBool *aIsEnabled) +{ + if( nsnull == aIsEnabled) + return NS_ERROR_NULL_POINTER; + + MENUITEM mI; + mMenuBase->GetItemID( mPMID, &mI); + + *aIsEnabled = ((mI.afAttribute & MIA_DISABLED) ? PR_FALSE : PR_TRUE); + return NS_OK; +} + +nsresult nsMenuItem::SetChecked( PRBool aIsChecked) +{ + MENUITEM mI; + mMenuBase->GetItemID( mPMID, &mI); + if( PR_TRUE == aIsChecked) + mI.afAttribute |= MIA_CHECKED; + else + mI.afAttribute &= ~MIA_CHECKED; + mMenuBase->UpdateItem( &mI); + return NS_OK; +} + +nsresult nsMenuItem::GetChecked( PRBool *aIsChecked) +{ + if( nsnull == aIsChecked) + return NS_ERROR_NULL_POINTER; + + MENUITEM mI; + mMenuBase->GetItemID( mPMID, &mI); + + *aIsChecked = ((mI.afAttribute & MIA_CHECKED) ? PR_TRUE : PR_FALSE); + return NS_OK; +} + +nsresult nsMenuItem::GetCommand( PRUint32 &aCommand) +{ + return NS_ERROR_FAILURE; +} + +nsresult nsMenuItem::GetTarget( nsIWidget *&aTarget) +{ + NS_IF_RELEASE(aTarget); + aTarget = mTarget; + NS_IF_ADDREF(aTarget); + return NS_OK; +} + +nsresult nsMenuItem::GetNativeData( void *&aData) +{ + return mMenuBase->GetNativeData( &aData); +} + +NS_METHOD nsMenuItem::AddMenuListener( nsIMenuListener *aMenuListener) +{ + NS_IF_RELEASE(mMenuListener); + mMenuListener = aMenuListener; + NS_ADDREF(mMenuListener); + return NS_OK; +} + +NS_METHOD nsMenuItem::RemoveMenuListener( nsIMenuListener *aMenuListener) +{ + if( mMenuListener == aMenuListener) + NS_IF_RELEASE(mMenuListener); + return NS_OK; +} + +nsresult nsMenuItem::IsSeparator( PRBool &aIsSep) +{ + aIsSep = mIsSeparator; + return NS_OK; +} + +nsresult nsMenuItem::SetCommand( const nsString &aStrCmd) +{ + mCmdString = aStrCmd; + return NS_OK; +} + +nsresult nsMenuItem::DoCommand() +{ + // code copied from windows + nsresult rv = NS_ERROR_FAILURE; + + nsCOMPtr contentViewerContainer; + contentViewerContainer = do_QueryInterface(mWebShell); + if (!contentViewerContainer) { + NS_ERROR("Webshell doesn't support the content viewer container interface"); + return rv; + } + + nsCOMPtr contentViewer; + if (NS_FAILED(rv = contentViewerContainer->GetContentViewer(getter_AddRefs(contentViewer)))) { + NS_ERROR("Unable to retrieve content viewer."); + return rv; + } + + nsCOMPtr docViewer; + docViewer = do_QueryInterface(contentViewer); + if (!docViewer) { + NS_ERROR("Document viewer interface not supported by the content viewer."); + return rv; + } + + nsCOMPtr presContext; + if (NS_FAILED(rv = docViewer->GetPresContext(*getter_AddRefs(presContext)))) { + NS_ERROR("Unable to retrieve the doc viewer's presentation context."); + return rv; + } + + nsEventStatus status = nsEventStatus_eIgnore; + nsMouseEvent event; + event.eventStructType = NS_MOUSE_EVENT; + event.message = NS_MOUSE_LEFT_CLICK; + + nsCOMPtr contentNode; + contentNode = do_QueryInterface(mDOMElement); + if (!contentNode) { + NS_ERROR("DOM Node doesn't support the nsIContent interface required to handle DOM events."); + return rv; + } + + rv = contentNode->HandleDOMEvent(*presContext, &event, nsnull, NS_EVENT_FLAG_INIT, status); + + return rv; +} + +nsresult nsMenuItem::SetDOMElement( nsIDOMElement *aDOMElement) +{ + mDOMElement = aDOMElement; + return NS_OK; +} + +nsresult nsMenuItem::GetDOMElement( nsIDOMElement **aDOMElement) +{ + if( !aDOMElement) + return NS_ERROR_NULL_POINTER; + + NS_IF_RELEASE(*aDOMElement); + *aDOMElement = mDOMElement; + NS_IF_ADDREF(mDOMElement); + return NS_OK; +} + +nsresult nsMenuItem::SetWebShell( nsIWebShell *aWebShell) +{ + mWebShell = aWebShell; + return NS_OK; +} + +// nsIMenuListener interface +nsEventStatus nsMenuItem::MenuItemSelected( const nsMenuEvent &aMenuEvent) +{ + DoCommand(); + return nsEventStatus_eIgnore; +} + +nsEventStatus nsMenuItem::MenuConstruct( const nsMenuEvent &aMenuEvent, + nsIWidget *aParentWindow, + void *menubarNode, + void *aWebShell) +{ + return nsEventStatus_eIgnore; +} + +nsEventStatus nsMenuItem::MenuSelected( const nsMenuEvent &aMenuEvent) +{ + return nsEventStatus_eIgnore; +} + +nsEventStatus nsMenuItem::MenuDeselected(const nsMenuEvent & aMenuEvent) +{ + return nsEventStatus_eIgnore; +} + +nsEventStatus nsMenuItem::MenuDestruct( const nsMenuEvent &aMenuEvent) +{ + return nsEventStatus_eIgnore; +} diff --git a/mozilla/widget/src/os2/nsMenuItem.h b/mozilla/widget/src/os2/nsMenuItem.h new file mode 100644 index 00000000000..3f33b63cda3 --- /dev/null +++ b/mozilla/widget/src/os2/nsMenuItem.h @@ -0,0 +1,92 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// nsMenuItem - interface to things which live in menus. +// +// This is rather complicated, not least because it contains about 2 1/2 +// versions of the API rolled up into 1. + +#ifndef _nsmenuitem_h +#define _nsmenuitem_h + +#include "nsString.h" +#include "nsIMenuItem.h" +#include "nsIMenuListener.h" + +class nsMenuBase; +class nsIDOMElement; +class nsIWebShell; + +class nsMenuItem : public nsIMenuItem, public nsIMenuListener +{ + public: + nsMenuItem(); + virtual ~nsMenuItem(); + + // nsISupports + NS_DECL_ISUPPORTS + + // nsIMenuItem + NS_IMETHOD Create( nsISupports *aParent, const nsString &aLabel, PRBool isSep); + NS_IMETHOD GetLabel( nsString &aText); + NS_IMETHOD SetLabel( nsString &aText); + NS_IMETHOD SetEnabled( PRBool aIsEnabled); + NS_IMETHOD GetEnabled( PRBool *aIsEnabled); + NS_IMETHOD SetChecked( PRBool aIsEnabled); + NS_IMETHOD GetChecked( PRBool *aIsEnabled); + NS_IMETHOD GetCommand( PRUint32 &aCommand); + NS_IMETHOD GetTarget( nsIWidget *&aTarget); + NS_IMETHOD GetNativeData( void *&aData); + NS_IMETHOD AddMenuListener( nsIMenuListener *aMenuListener); + NS_IMETHOD RemoveMenuListener( nsIMenuListener *aMenuListener); + NS_IMETHOD IsSeparator( PRBool &aIsSep); + NS_IMETHOD SetCommand( const nsString &aStrCmd); + NS_IMETHOD DoCommand(); + NS_IMETHOD SetDOMElement( nsIDOMElement *aDOMElement); + NS_IMETHOD GetDOMElement( nsIDOMElement **aDOMElement); + NS_IMETHOD SetWebShell( nsIWebShell *aWebShell); + + // nsIMenuListener interface + nsEventStatus MenuSelected( const nsMenuEvent &aMenuEvent); + nsEventStatus MenuItemSelected( const nsMenuEvent &aMenuEvent); + nsEventStatus MenuDeselected( const nsMenuEvent &aMenuEvent); + nsEventStatus MenuConstruct( const nsMenuEvent &aMenuEvent, + nsIWidget *aParentWindow, + void *menubarNode, + void *aWebShell); + nsEventStatus MenuDestruct( const nsMenuEvent &aMenuEvent); + + // nsMenuItem + USHORT GetPMID() { return mPMID; } + + protected: + nsMenuBase *mMenuBase; // Menu we are attached to + nsString mLabel; + PRBool mIsSeparator; + nsIWidget *mTarget; // window we dispatch to + USHORT mPMID; // PM command ID + nsIMenuListener *mMenuListener; + nsString mCmdString; // JS command + nsIDOMElement *mDOMElement; // dom element for item + nsIWebShell *mWebShell; +}; + +#endif diff --git a/mozilla/widget/src/os2/nsModule.cpp b/mozilla/widget/src/os2/nsModule.cpp new file mode 100644 index 00000000000..964b710d2d2 --- /dev/null +++ b/mozilla/widget/src/os2/nsModule.cpp @@ -0,0 +1,416 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#define INCL_DOSDEVIOCTL // for keyboard layout + +#include "nsWidgetDefs.h" +#include "nsHashtable.h" +#include "resid.h" +#include +#include + +// Module-level data & utility functions: +// * unicode keycode & string conversion +// * atom management +// * printing bits & pieces (though not really any more) + +#include "nsIFontRetrieverService.h" +#include "nsDragService.h" +#include "nsAppShell.h" + +#include + +#define WARPZILLA_PRESPARAM "PP_WARPZILLA" + +static void GetKeyboardName( char *buff); + +nsWidgetModuleData::nsWidgetModuleData() +{} + +// This is called when the first appshell is created. +void nsWidgetModuleData::Init( nsIAppShell *aPrimaevalAppShell) +{ + if( 0 != hModResources) return; + + char buffer[CCHMAXPATH]; + APIRET rc; + + rc = DosLoadModule( buffer, CCHMAXPATH, "WDGTRES", &hModResources); + + if( rc) + { + printf( "Widget failed to load resource DLL. rc = %d, cause = %s\n", + (int)rc, buffer); + hModResources = 0; + } + + szScreen.cx = WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN); + szScreen.cy = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN); + + bMouseSwitched = WinQuerySysValue( HWND_DESKTOP, SV_SWAPBUTTON); + + // Magic number -- height of normal text fields in pixels. + // Both combobox and (atm) nsBrowserWindow depend on this. + lHtEntryfield = 26; + + rc = WinLoadString( 0/*hab*/, hModResources, ID_STR_FONT, 256, buffer); + if( !rc) strcpy( buffer, "8.Helv"); + pszFontNameSize = strdup( buffer); + + hptrSelect = hptrFrameIcon = 0; + + // Work out if the system is DBCS + COUNTRYCODE cc = { 0 }; + DosQueryDBCSEnv( CCHMAXPATH, &cc, buffer); + bIsDBCS = buffer[0] || buffer[1]; + + ppMozilla = GetAtom( WARPZILLA_PRESPARAM); + + fontService = nsnull; + + dragService = new nsDragService; + NS_ADDREF(dragService); + + // keep a ref beyond the client app so we shut ourselves down properly. + appshell = aPrimaevalAppShell; + NS_ADDREF(appshell); + + converter = 0; + supplantConverter = FALSE; + + // create unicode keyboard object + char kbdname[8]; + UniChar unikbdname[8]; + GetKeyboardName( kbdname); + for( int i = 0; i < 8; i++) + unikbdname[i] = kbdname[i]; + + if( UniCreateKeyboard( &hKeyboard, unikbdname, 0) != ULS_SUCCESS) + hKeyboard = 0; +#ifdef DEBUG + else + printf( "Widget library loaded keyboard table for %s\n", kbdname); +#endif + +#if 0 + mWindows = nsnull; +#endif +} + +nsWidgetModuleData::~nsWidgetModuleData() +{ + if( hKeyboard) + UniDestroyKeyboard( hKeyboard); + + if( converter) + UniFreeUconvObject( converter); + + NS_IF_RELEASE(dragService); + + NS_IF_RELEASE(fontService); + + PRInt32 cAtoms = atoms.Count(); + HATOMTBL systbl = WinQuerySystemAtomTable(); + for( PRInt32 i = 0; i < cAtoms; i++) + WinDeleteAtom( systbl, (ATOM) atoms.ElementAt(i)); + + if( hptrSelect) + WinDestroyPointer( hptrSelect); + if( hptrFrameIcon) + WinDestroyPointer( hptrFrameIcon); + if( hModResources) + DosFreeModule( hModResources); + free( pszFontNameSize); +#if 0 + delete mWindows; +#endif + + // finally shut down the appshell. No more PM. + // (hope that gfxos2 has gone first!) + NS_IF_RELEASE(appshell); +} + +HPOINTER nsWidgetModuleData::GetPointer( nsCursor aCursor) +{ + if( aCursor != eCursor_hyperlink) + printf( "\n*** Need to implement cursor type %d (see widget/os2/nsModule.cpp)\n\n", (int) aCursor); + + // Use an array and indices here when we have all the pointers in place. + if( !hptrSelect) + hptrSelect = WinLoadPointer( HWND_DESKTOP, + hModResources, ID_PTR_SELECTURL); + return hptrSelect; +} + +HPOINTER nsWidgetModuleData::GetFrameIcon() +{ + if( !hptrFrameIcon) + hptrFrameIcon = WinLoadPointer( HWND_DESKTOP, + hModResources, ID_ICO_FRAME); + return hptrFrameIcon; +} + +// Conversion from unicode to appropriate codepage +char *nsWidgetModuleData::ConvertFromUcs( const PRUnichar *pText, + char *szBuffer, ULONG ulSize) +{ + if( supplantConverter) + { + // We couldn't create a converter for some reason, so do this 'by hand'. + // Note this algorithm is fine for most of most western charsets, but + // fails dismally for various glyphs, baltic, points east... + ULONG ulCount = 0; + char *szSave = szBuffer; + while( *pText && ulCount < ulSize - 1) // (one for terminator) + { + *szBuffer = (char) *pText; + szBuffer++; + pText++; + ulCount++; + } + + // terminate string + *szBuffer = '\0'; + + return szSave; + } + + if( !converter) + { + // Create a converter from unicode to a codepage which PM can display. + UniChar codepage[20]; + int unirc = UniMapCpToUcsCp( 0, codepage, 20); + if( unirc == ULS_SUCCESS) + { + unirc = UniCreateUconvObject( codepage, &converter); + // XXX do we need to set substitution options here? +#ifdef DEBUG + if( unirc == ULS_SUCCESS) + { + printf( "Widget library created unicode converter for cp %s\n", + ConvertFromUcs( (PRUnichar *) codepage)); + } +#endif + } + if( unirc != ULS_SUCCESS) + { + supplantConverter = TRUE; + printf( "Couldn't create widget unicode converter.\n"); + return ConvertFromUcs( pText, szBuffer, ulSize); + } + } + + // Have converter, now get it to work... + + UniChar *ucsString = (UniChar*) pText; + size_t ucsLen = UniStrlen( ucsString) + 1; + size_t cplen = ulSize; + size_t cSubs = 0; + + char *tmp = szBuffer; // function alters the out pointer + + int unirc = UniUconvFromUcs( converter, &ucsString, &ucsLen, + (void**) &tmp, &cplen, &cSubs); + + if( unirc == UCONV_E2BIG) // k3w1 + { + // terminate output string (truncating) + *(szBuffer + ulSize - 1) = '\0'; + } + else if( unirc != ULS_SUCCESS) + { + printf( "UniUconvFromUcs failed, rc %X\n", unirc); + supplantConverter = TRUE; + szBuffer = ConvertFromUcs( pText, szBuffer, ulSize); + supplantConverter = FALSE; + } + + return szBuffer; +} + +char *nsWidgetModuleData::ConvertFromUcs( const nsString &aString, + char *szBuffer, ULONG ulSize) +{ + char *szRet = 0; + const PRUnichar *pUnicode = aString.GetUnicode(); + + if( pUnicode) + szRet = ConvertFromUcs( pUnicode, szBuffer, ulSize); + else + szRet = aString.ToCString( szBuffer, ulSize); + + return szRet; +} + +const char *nsWidgetModuleData::ConvertFromUcs( const PRUnichar *pText) +{ + // This is probably okay; longer strings will be truncated but istr there's + // a PM limit on things like windowtext + // (which these routines are usually used for) + + static char buffer[1024]; // XXX (multithread) + *buffer = '\0'; + return ConvertFromUcs( pText, buffer, 1024); +} + +const char *nsWidgetModuleData::ConvertFromUcs( const nsString &aString) +{ + const char *szRet = 0; + const PRUnichar *pUnicode = aString.GetUnicode(); + + if( pUnicode) + szRet = ConvertFromUcs( pUnicode); + else + szRet = aString.GetBuffer(); // hrm. + + return szRet; +} + +// Wrapper around UniTranslateKey to deal with shift-state etc. +int nsWidgetModuleData::TranslateKey( VSCAN scan, UniChar *pChar, VDKEY *vdkey) +{ + int unirc = 1; + + // bail if we've not got a keyboard + if( !hKeyboard) return unirc; + + // XXX Right, this seems madly wrong, but I'm not sure what else to do. + // We need to work out the 'effective shift state' before calling + // UniTranslateKey(). This is derived from the state of the keyboard + // and the current scancode. Unfortunately, the only way I can find + // the current state of the various keys is by doing this on each + // keypress! + // + // XXX Anything else to test? Layers? Or are they just deadkey applications? + // Are deadkeys meant to go in here? + + ULONG sstate = 0; + + if( WinIsKeyDown(VK_SHIFT)) sstate |= KBD_SHIFT; + if( WinIsKeyDown(VK_CTRL)) sstate |= KBD_CTRL; +// if( WinIsKeyDown(VK_ALT)) sstate |= KBD_ALT; +// if( WinIsKeyDown(VK_ALTGRAF)) sstate |= KBD_ALTGR; + + #define TOGGLED(vk) (WinGetKeyState(HWND_DESKTOP,vk) & 1) + + if( TOGGLED(VK_CAPSLOCK)) sstate |= KBD_CAPSLOCK; + if( TOGGLED(VK_NUMLOCK)) sstate |= KBD_NUMLOCK; + if( TOGGLED(VK_SCRLLOCK)) sstate |= KBD_SCROLLLOCK; + + USHIFTSTATE uss = { sstate, 0, 0 }; + + unirc = UniUpdateShiftState( hKeyboard, &uss, scan, 0); + if( unirc == ULS_SUCCESS) + { + BYTE bBiosScancode; + unirc = UniTranslateKey( hKeyboard, + uss.Effective, + scan, + pChar, + vdkey, + &bBiosScancode); + } + + return unirc; +} + +static void GetKeyboardName( char *buff) +{ + HFILE hKeyboard = 0; + ULONG ulAction; + + strcpy( buff, "UK"); + + if( !DosOpen( "KBD$", &hKeyboard, &ulAction, 0, FILE_NORMAL, FILE_OPEN, + OPEN_ACCESS_READONLY | OPEN_SHARE_DENYWRITE, NULL)) + { + ULONG ulDataLen; +#pragma pack(2) + struct { USHORT usLength; USHORT usCp; CHAR ach[8];} kcp; +#pragma pack() + + kcp.usLength = ulDataLen = sizeof kcp; + + if( !DosDevIOCtl( hKeyboard, IOCTL_KEYBOARD, KBD_QUERYKBDCODEPAGESUPPORT, + 0, 0, 0, + &kcp, ulDataLen, &ulDataLen)) + strcpy( buff, kcp.ach); + + DosClose( hKeyboard); + } +} + +ATOM nsWidgetModuleData::GetAtom( const char *atomname) +{ + ATOM atom = WinAddAtom( WinQuerySystemAtomTable(), atomname); + atoms.AppendElement( (void*) atom); + return atom; +} + +ATOM nsWidgetModuleData::GetAtom( const nsString &atomname) +{ + return GetAtom( ConvertFromUcs( atomname)); +} + +// Printing stuff -- need to be able to generate a window of a given +// flavour and then do stuff to it in nsWindow::Paint() + +#if 0 + +class nsWndClassKey : public nsHashKey +{ + PCSZ pszClassname; + +public: + nsWndClassKey( PCSZ pszName) : pszClassname( pszName) + {} + PRUint32 HashValue() const + { return (PRUint32) pszClassname; } + PRBool Equals( const nsHashKey *aKey) const + { return HashValue() == aKey->HashValue(); } + nsHashKey *Clone() const + { return new nsWndClassKey( pszClassname); } +}; + + +// Get a window to render its state +HWND nsWidgetModuleData::GetWindowForPrinting( PCSZ pszClass, ULONG ulStyle) +{ + if( mWindows == nsnull) + mWindows = new nsHashtable; + + nsWndClassKey aKey( pszClass); + + if( mWindows->Get( &aKey) == nsnull) + { + HWND hwnd = WinCreateWindow( HWND_DESKTOP, pszClass, "", ulStyle, + 0, -4096, 0, 0, HWND_DESKTOP, + HWND_TOP, 0, 0, 0); + NS_ASSERTION( hwnd, "WinCreateWindow for printing failed"); + mWindows->Put( &aKey, (void*) hwnd); + } + + return (HWND) mWindows->Get( &aKey); +} + +#endif + +nsWidgetModuleData gModuleData; diff --git a/mozilla/widget/src/os2/nsPopupMenu.cpp b/mozilla/widget/src/os2/nsPopupMenu.cpp new file mode 100644 index 00000000000..b988fc5bf7b --- /dev/null +++ b/mozilla/widget/src/os2/nsPopupMenu.cpp @@ -0,0 +1,107 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// popup menu + +#include "nsPopupMenu.h" +#include "nsWindow.h" + +// XPCom +NS_IMPL_ADDREF(nsPopupMenu) +NS_IMPL_RELEASE(nsPopupMenu) + +nsresult nsPopupMenu::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if( !aInstancePtr) + return NS_ERROR_NULL_POINTER; + + *aInstancePtr = 0; + + if( aIID.Equals(nsIPopupMenu::GetIID())) + { + *aInstancePtr = (void*) ((nsIPopUpMenu*) this); + NS_ADDREF_THIS(); + return NS_OK; + } + if( aIID.Equals(((nsISupports*)(nsIPopUpMenu*)this)->GetIID())) + { + *aInstancePtr = (void*) ((nsISupports*)this); + NS_ADDREF_THIS(); + return NS_OK; + } + + return NS_NOINTERFACE; +} + + +nsPopupMenu::nsPopupMenu() : mParent(0), nsMenuBase() +{ + NS_INIT_REFCNT(); +} + +nsPopupMenu::~nsPopupMenu() +{ + NS_IF_RELEASE(mParent); +} + +// Creation: parent to the desktop, owner to the `parent' +nsresult nsPopupMenu::Create( nsIWidget *aParent) +{ + // find the owner hwnd & nsWindow (for the toolkit) + HWND hwndOwner = (HWND) aParent->GetNativeData( NS_NATIVE_WINDOW); + mParent = NS_HWNDToWindow( hwndOwner); + NS_ADDREF(mParent); + + nsIToolkit *aToolkit = mParent->GetToolkit(); + + nsMenuBase::Create( HWND_DESKTOP, (nsToolkit*) aToolkit); + NS_RELEASE(aToolkit); + + WinSetOwner( mWnd, hwndOwner); + + return NS_OK; +} + +nsresult nsPopupMenu::GetParent( nsIWidget *&aParent) +{ + NS_IF_RELEASE(aParent); + aParent = mParent; + NS_IF_ADDREF(aParent); + return NS_OK; +} + +ULONG nsPopupMenu::WindowStyle() +{ + return 0; +} + +nsresult nsPopupMenu::ShowMenu( PRInt32 aX, PRInt32 aY) +{ + POINTL pos = { aX, aY }; + mParent->NS2PM(pos); + + WinPopupMenu( HWND_DESKTOP, + (HWND) mParent->GetNativeData( NS_NATIVE_WIDGET), + mWnd, pos.x, pos.y, 0, + PU_HCONSTRAIN | PU_VCONSTRAIN | PU_NONE | + PU_KEYBOARD | PU_MOUSEBUTTON1 | PU_MOUSEBUTTON2); + return NS_OK; +} diff --git a/mozilla/widget/src/os2/nsPopupMenu.h b/mozilla/widget/src/os2/nsPopupMenu.h new file mode 100644 index 00000000000..f7a665f36f5 --- /dev/null +++ b/mozilla/widget/src/os2/nsPopupMenu.h @@ -0,0 +1,71 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsPopupMenu_h +#define _nsPopupMenu_h + +// A menu for popping up. + +#include "nsIPopupMenu.h" +#include "nsMenuBase.h" + +class nsWindow; +class nsIMenuItem; + +class nsPopupMenu : public nsIPopUpMenu, public nsMenuBase +{ + public: + nsPopupMenu(); + ~nsPopupMenu(); + + // nsISupports + NS_DECL_ISUPPORTS + + // nsIPopupMenu + NS_IMETHOD Create( nsIWidget *aParent); + NS_IMETHOD GetParent( nsIWidget *&aParent); + NS_IMETHOD ShowMenu( PRInt32 aX, PRInt32 aY); + + // Common methods with nsMenu + DECL_MENU_BASE_METHODS + + // nsIPopUpMenu hasn't been revamped along with the other menu classes + // in the `dynamic menu' effort, so don't try too hard getting these + // old-style methods implemented -- it'll change soon. (ask saari if + // concerned). + NS_IMETHOD AddItem( nsIMenuItem *aMenuItem) + { return nsMenuBase::InsertItemAt( aMenuItem); } + NS_IMETHOD GetItemAt( const PRUint32 aCount, nsIMenuItem *&aThing) + { return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD InsertItemAt( const PRUint32 aCount, nsIMenuItem *&aMenuItem) + { return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD InsertItemAt( const PRUint32 aCount, const nsString &aMenuItemName) + { return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD GetNativeData( void *&aData) + { return nsMenuBase::GetNativeData( &aData); } + + protected: + ULONG WindowStyle(); + + nsWindow *mParent; +}; + +#endif diff --git a/mozilla/widget/src/os2/nsPushButton.cpp b/mozilla/widget/src/os2/nsPushButton.cpp new file mode 100644 index 00000000000..93f134b3a88 --- /dev/null +++ b/mozilla/widget/src/os2/nsPushButton.cpp @@ -0,0 +1,56 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// Push button control; don't really come any simpler than this... + +#include "nsPushButton.h" + +// XP-com +NS_IMPL_ADDREF(nsPushButton) +NS_IMPL_RELEASE(nsPushButton) + +nsresult nsPushButton::QueryInterface( const nsIID &aIID, void **aInstancePtr) +{ + nsresult result = nsWindow::QueryInterface( aIID, aInstancePtr); + + if( result == NS_NOINTERFACE && aIID.Equals( nsIButton::GetIID())) + { + *aInstancePtr = (void*) ((nsIButton*)this); + NS_ADDREF_THIS(); + result = NS_OK; + } + + return result; +} + +// Text +NS_IMPL_LABEL(nsPushButton) + +// Creation hooks +PCSZ nsPushButton::WindowClass() +{ + return WC_BUTTON; +} + +ULONG nsPushButton::WindowStyle() +{ + return BASE_CONTROL_STYLE | BS_PUSHBUTTON; +} diff --git a/mozilla/widget/src/os2/nsPushButton.h b/mozilla/widget/src/os2/nsPushButton.h new file mode 100644 index 00000000000..3c60a45aa0a --- /dev/null +++ b/mozilla/widget/src/os2/nsPushButton.h @@ -0,0 +1,53 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsPushButton_h +#define _nsPushButton_h + +#include "nsWindow.h" +#include "nsIButton.h" + +// WC_BUTTON, BS_PUSHBUTTON wrapper for NS_BUTTON_CID + +class nsPushButton : public nsWindow, public nsIButton +{ + public: + nsPushButton() {} + + // nsISupports + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(void); + NS_IMETHOD_(nsrefcnt) Release(void); + + // nsIButton + NS_DECL_LABEL + + protected: + // message stopping + virtual PRBool OnMove( PRInt32 aX, PRInt32 aY) { return PR_FALSE; } + virtual PRBool OnResize( PRInt32 aX, PRInt32 aY) { return PR_FALSE; } + + // Creation hooks + virtual PCSZ WindowClass(); + virtual ULONG WindowStyle(); +}; + +#endif diff --git a/mozilla/widget/src/os2/nsRadioButton.cpp b/mozilla/widget/src/os2/nsRadioButton.cpp new file mode 100644 index 00000000000..19c819dc788 --- /dev/null +++ b/mozilla/widget/src/os2/nsRadioButton.cpp @@ -0,0 +1,70 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// Radio button control + +#include "nsRadioButton.h" + +// XP-com +NS_IMPL_ADDREF(nsRadioButton) +NS_IMPL_RELEASE(nsRadioButton) + +nsresult nsRadioButton::QueryInterface( const nsIID &aIID, void **aInstancePtr) +{ + nsresult result = nsWindow::QueryInterface( aIID, aInstancePtr); + + if( result == NS_NOINTERFACE && aIID.Equals( nsIRadioButton::GetIID())) + { + *aInstancePtr = (void*) ((nsIRadioButton*)this); + NS_ADDREF_THIS(); + result = NS_OK; + } + + return result; +} + +// Text +NS_IMPL_LABEL(nsRadioButton) + +// checked-ness +nsresult nsRadioButton::GetState( PRBool &aState) +{ + MRESULT rc = mOS2Toolkit->SendMsg( mWnd, BM_QUERYCHECK); + aState = SHORT1FROMMR(rc); + return NS_OK; +} + +nsresult nsRadioButton::SetState( const PRBool aState) +{ + mOS2Toolkit->SendMsg( mWnd, BM_SETCHECK, MPFROMLONG(aState)); + return NS_OK; +} + +// Creation hooks +PCSZ nsRadioButton::WindowClass() +{ + return WC_BUTTON; +} + +ULONG nsRadioButton::WindowStyle() +{ + return BASE_CONTROL_STYLE | BS_RADIOBUTTON; +} diff --git a/mozilla/widget/src/os2/nsRadioButton.h b/mozilla/widget/src/os2/nsRadioButton.h new file mode 100644 index 00000000000..96c2c0f3b97 --- /dev/null +++ b/mozilla/widget/src/os2/nsRadioButton.h @@ -0,0 +1,59 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsRadioButton_h +#define _nsRadioButton_h + +#include "nsWindow.h" +#include "nsIRadioButton.h" + +// WC_BUTTON, BS_RADIOBUTTON wrapper for NS_RADIOBUTTON_CID +// +// !! Really want to share code with (at least) nsCheckButton, but there's +// !! so little of it a `nsBaseSelectionButton' seems like overkill. +// !! Maybe if this 'GetPreferredSize' thing get's going it would be better. + +class nsRadioButton : public nsWindow, public nsIRadioButton +{ + public: + nsRadioButton() {} + + // nsISupports + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(void); + NS_IMETHOD_(nsrefcnt) Release(void); + + // nsIRadioButton + NS_DECL_LABEL + NS_IMETHOD GetState( PRBool &aState); + NS_IMETHOD SetState( const PRBool aState); + + protected: + // message stopping + virtual PRBool OnMove( PRInt32 aX, PRInt32 aY) { return PR_FALSE; } + virtual PRBool OnResize( PRInt32 aX, PRInt32 aY) { return PR_FALSE; } + + // Creation hooks + virtual PCSZ WindowClass(); + virtual ULONG WindowStyle(); +}; + +#endif diff --git a/mozilla/widget/src/os2/nsScrollbar.cpp b/mozilla/widget/src/os2/nsScrollbar.cpp new file mode 100644 index 00000000000..392b7896b80 --- /dev/null +++ b/mozilla/widget/src/os2/nsScrollbar.cpp @@ -0,0 +1,225 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include "nsScrollbar.h" +#include "nsGUIEvent.h" +#include "nsUnitConversion.h" + +NS_IMPL_ADDREF(nsScrollbar) +NS_IMPL_RELEASE(nsScrollbar) + +nsresult nsScrollbar::QueryInterface( const nsIID &aIID, void **aInstancePtr) +{ + nsresult result = nsWindow::QueryInterface( aIID, aInstancePtr); + + if( result == NS_NOINTERFACE && aIID.Equals( nsIScrollbar::GetIID())) + { + *aInstancePtr = (void*) ((nsIScrollbar*)this); + NS_ADDREF_THIS(); + result = NS_OK; + } + + return result; +} + +// Init; window creation +nsScrollbar::nsScrollbar( PRBool aIsVertical) : nsWindow() +{ + mOrientation = aIsVertical ? SBS_VERT : SBS_HORZ; + mScaleFactor = 1.0f; + mLineIncrement = 0; + mThumbSize = 0; + mMaxRange = 0; +} + +// nsWindow overrides to create the right kind of window +PCSZ nsScrollbar::WindowClass() +{ + return WC_SCROLLBAR; +} + +ULONG nsScrollbar::WindowStyle() +{ + return mOrientation | SBS_THUMBSIZE | SBS_AUTOTRACK | BASE_CONTROL_STYLE; +} + +//--------------------------------------------------------------------------- +// Metrics set/get ---------------------------------------------------------- + +// Note carefully that the widget concepts of "thumb size" & "range" are not +// the same as the corresponding PM ones; they're much more like (?identical) +// Java's. Basically the thumb size is not just cosmetic. +// +// This means that changing the thumb size or the max range means the other +// must be changed too. This code may need some work. + +#define ROUND_D(u) NSToIntRound( (u) / mScaleFactor) +#define ROUND_U(u) (PRUint32) NSToIntRound( (u) * mScaleFactor) + +void nsScrollbar::SetThumbRange( PRUint32 aEndRange, PRUint32 aSize) +{ + // get current position + + PRUint32 pos; + GetPosition( pos); + + // set scale factor dependent on max range + if( aEndRange > 32000) + mScaleFactor = aEndRange / 32000.0f; + + // set new sizes + mMaxRange = aEndRange; + mThumbSize = aSize; + + // set range & pos + mOS2Toolkit->SendMsg( mWnd, SBM_SETSCROLLBAR, + MPFROMSHORT( ROUND_D(pos)), + MPFROM2SHORT( 0, ROUND_D(mMaxRange-mThumbSize))); + + // set thumb + mOS2Toolkit->SendMsg( mWnd, SBM_SETTHUMBSIZE, + MPFROM2SHORT( ROUND_D(mThumbSize), + ROUND_D(mMaxRange))); +} + +// Range - 0 to max range +nsresult nsScrollbar::SetMaxRange( PRUint32 aEndRange) +{ + SetThumbRange( aEndRange, mThumbSize); + return NS_OK; +} + +// Thumb size +nsresult nsScrollbar::SetThumbSize( PRUint32 aSize) +{ + SetThumbRange( mMaxRange, aSize); + return NS_OK; +} + +// Thumb position +nsresult nsScrollbar::SetPosition( PRUint32 aPos) +{ + mOS2Toolkit->SendMsg( mWnd, SBM_SETPOS, MPFROMSHORT(ROUND_D( aPos))); + return NS_OK; +} + +NS_IMETHODIMP nsScrollbar::GetPosition( PRUint32 &pos) +{ + MRESULT rc = mOS2Toolkit->SendMsg( mWnd, SBM_QUERYPOS); + pos = ROUND_U( SHORT1FROMMR(rc)); + return NS_OK; +} + +// All the above +nsresult nsScrollbar::SetParameters( PRUint32 aMaxRange, PRUint32 aThumbSize, + PRUint32 aPosition, PRUint32 aLineIncrement) +{ + SetThumbRange( aMaxRange, aThumbSize); + SetPosition( aPosition); + SetLineIncrement( aLineIncrement); + return NS_OK; +} + +//------------------------------------------------------------------------- +// Deal with scrollbar messages ------------------------------------------- + +PRBool nsScrollbar::OnScroll( MPARAM mp1, MPARAM mp2) +{ + PRBool rc = PR_TRUE; + + USHORT usCmd = SHORT2FROMMP(mp2); + int msg = 0; + + BOOL hasEvent = mEventListener != nsnull || mEventCallback != nsnull; + + PRUint32 newpos, li, ts; + + GetPosition( newpos); + GetLineIncrement( li); + GetThumbSize( ts); + + switch( usCmd) + { + case SB_LINERIGHT: // == SB_LINEDOWN + { + newpos += li; + msg = NS_SCROLLBAR_LINE_NEXT; + break; + } + + case SB_LINELEFT: // == SB_LINEUP + { + if( newpos > li) newpos -= li; + else newpos = 0; + msg = NS_SCROLLBAR_LINE_PREV; + break; + } + + case SB_PAGERIGHT: // == SB_PAGEDOWN + { + newpos += (ts - li); + msg = NS_SCROLLBAR_PAGE_NEXT; + break; + } + + case SB_PAGELEFT: // == SB_PAGEUP + { + PRUint32 delta; + delta = ts - li; + if( newpos > delta) newpos -= delta; + else newpos = 0; + msg = NS_SCROLLBAR_PAGE_PREV; + break; + } + + case SB_SLIDERTRACK: + newpos = ROUND_U( SHORT1FROMMP(mp2)); + msg = NS_SCROLLBAR_POS; + break; + } + + if( msg != 0) + { + // Ensure newpos is sensible + if( newpos > (mMaxRange - mThumbSize)) + newpos = mMaxRange - mThumbSize; + + // if there are listeners, give them a chance to alter newpos + if( mEventListener != nsnull || mEventCallback != nsnull) + { + nsScrollbarEvent event; + InitEvent( event, msg); + event.eventStructType = NS_SCROLLBAR_EVENT; + event.position = newpos; + DispatchEventInternal( &event); + + // Ensure position is still sensible + newpos = event.position; + if( newpos > (mMaxRange - mThumbSize)) + newpos = mMaxRange - mThumbSize; + } + + // Now move the scrollbar + SetPosition( newpos); + } + + return rc; +} diff --git a/mozilla/widget/src/os2/nsScrollbar.h b/mozilla/widget/src/os2/nsScrollbar.h new file mode 100644 index 00000000000..bc95e0142f6 --- /dev/null +++ b/mozilla/widget/src/os2/nsScrollbar.h @@ -0,0 +1,70 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsscrollbar_h +#define _nsscrollbar_h + +#include "nsWindow.h" + +#include "nsIScrollbar.h" + +// WC_SCROLLBAR wrapper, for NS_HORZSCROLLBAR_CID & NS_VERTSCROLLBAR_CID + +class nsScrollbar : public nsWindow, public nsIScrollbar +{ + public: + nsScrollbar( PRBool aIsVertical); + + // nsISupports + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(void); + NS_IMETHOD_(nsrefcnt) Release(void); + + // nsIScrollbar part + NS_IMETHOD SetMaxRange( PRUint32 aEndRange); + NS_IMETHOD GetMaxRange( PRUint32 &mr) { mr = mMaxRange; return NS_OK; } + NS_IMETHOD SetPosition( PRUint32 aPos); + NS_IMETHOD GetPosition( PRUint32 &pos); + NS_IMETHOD SetThumbSize( PRUint32 aSize); + NS_IMETHOD GetThumbSize( PRUint32 &ts) { ts = mThumbSize; return NS_OK; } + NS_IMETHOD SetLineIncrement( PRUint32 aSize) { mLineIncrement = aSize; return NS_OK; } + NS_IMETHOD GetLineIncrement( PRUint32 &li) { li = mLineIncrement; return NS_OK; } + NS_IMETHOD SetParameters( PRUint32 aMaxRange, PRUint32 aThumbSize, + PRUint32 aPosition, PRUint32 aLineInc); + + // Manage scroll events we generate + virtual PRBool OnScroll( MPARAM mp1, MPARAM mp2); + + protected: + // Creation hooks + virtual PCSZ WindowClass(); + virtual ULONG WindowStyle(); + + private: + void SetThumbRange( PRUint32 aEndRange, PRUint32 aSize); + ULONG mOrientation; // horz/vert + int mLineIncrement; // inc. for line-scrolls + float mScaleFactor; // to allow for >32k sizes + PRUint32 mThumbSize; // cache XP thumbsize + PRUint32 mMaxRange; // cache XP maxrange +}; + +#endif diff --git a/mozilla/widget/src/os2/nsSound.cpp b/mozilla/widget/src/os2/nsSound.cpp new file mode 100644 index 00000000000..81b763278b1 --- /dev/null +++ b/mozilla/widget/src/os2/nsSound.cpp @@ -0,0 +1,51 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include "nsWidgetDefs.h" +#include "nsSound.h" + +NS_IMPL_ISUPPORTS(nsSound,nsISound::GetIID()) + +nsSound::nsSound() +{} + +nsSound::~nsSound() +{} + +nsresult nsSound::Beep() +{ + WinAlarm( HWND_DESKTOP, WA_WARNING); + return NS_OK; +} + +// This function should NOT exist -- how do people expect to componentize +// widget & gfx if they keep introducing static functions. + +#if 0 +nsresult NS_NewSound( nsISound** aSound) +{ + if( !aSound) + return NS_ERROR_NULL_POINTER; + + nsSound *pSound = new nsSound; + return pSound->QueryInterface( nsISound::GetIID(), (void**) aSound); +} +#endif diff --git a/mozilla/widget/src/os2/nsSound.h b/mozilla/widget/src/os2/nsSound.h new file mode 100644 index 00000000000..f9cdda294e5 --- /dev/null +++ b/mozilla/widget/src/os2/nsSound.h @@ -0,0 +1,40 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nssound_h +#define _nssound_h + +#include "nsISound.h" + +// This is rather lame! + +class nsSound : public nsISound +{ + public: + nsSound(); + virtual ~nsSound(); + + NS_DECL_ISUPPORTS + + NS_IMETHOD Beep(); +}; + +#endif diff --git a/mozilla/widget/src/os2/nsTabWidget.cpp b/mozilla/widget/src/os2/nsTabWidget.cpp new file mode 100644 index 00000000000..62e465413d0 --- /dev/null +++ b/mozilla/widget/src/os2/nsTabWidget.cpp @@ -0,0 +1,118 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +// C++ interface +#include "nsTabWidget.h" + +// C interface +#include "tabapi.h" // !! TAB-FIX + +#include + +// XP-com +NS_IMPL_ADDREF(nsTabWidget) +NS_IMPL_RELEASE(nsTabWidget) + +nsresult nsTabWidget::QueryInterface( const nsIID &aIID, void **aInstancePtr) +{ + nsresult result = nsWindow::QueryInterface( aIID, aInstancePtr); + + if( result == NS_NOINTERFACE && aIID.Equals( nsITabWidget::GetIID())) + { + *aInstancePtr = (void*) ((nsITabWidget*)this); + NS_ADDREF_THIS(); + result = NS_OK; + } + + return result; +} + +// tab methods +nsresult nsTabWidget::SetTabs( PRUint32 aNumberOfTabs, + const nsString aTabLabels[]) +{ + nsresult rc = NS_ERROR_FAILURE; + + if( mToolkit && mWnd) + { + // first remove current tabs... + // !! oops, can't do this yet :-) // !! TAB-FIX + // mOS2Toolkit->SendMsg( mWnd, TABM_REMOVEALLTABS); + + PRUint32 i; + char **strings = new char * [aNumberOfTabs]; + + for( i = 0; i < aNumberOfTabs; i++) + strings[i] = strdup( gModuleData.ConvertFromUcs( aTabLabels[i])); + + BOOL bOk = (BOOL) mOS2Toolkit->SendMsg( mWnd, TABM_INSERTMULTTABS, + MPFROMSHORT(aNumberOfTabs), + MPFROMP(strings)); + for( i = 0; i < aNumberOfTabs; i++) + free( strings[i]); + delete [] strings; + + if( bOk) + rc = NS_OK; + } + + return rc; +} + +nsresult nsTabWidget::GetSelectedTab( PRUint32 &aTab) +{ + nsresult rc = NS_ERROR_FAILURE; + + if( mWnd && mToolkit) + { + MRESULT mrc = mOS2Toolkit->SendMsg( mWnd, TABM_QUERYHILITTAB); + aTab = SHORT1FROMMR( mrc); + if( aTab != TABC_FAILURE) + rc = NS_OK; + aTab--; // !! TAB-INDEX + } + + return rc; +} + +// Generate mozilla events when appropriate... +PRBool nsTabWidget::OnControl( MPARAM mp1, MPARAM mp2) +{ + switch( SHORT2FROMMP(mp1)) + { + case TTN_TABCHANGE: + DispatchStandardEvent( NS_TABCHANGE); + break; + } + + return PR_TRUE; +} + +// Creation hooks... +PCSZ nsTabWidget::WindowClass() +{ + return (PCSZ) TabGetTabControlName(); +} + +ULONG nsTabWidget::WindowStyle() +{ + return BASE_CONTROL_STYLE; +} diff --git a/mozilla/widget/src/os2/nsTabWidget.h b/mozilla/widget/src/os2/nsTabWidget.h new file mode 100644 index 00000000000..84fdba9b0a8 --- /dev/null +++ b/mozilla/widget/src/os2/nsTabWidget.h @@ -0,0 +1,56 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nsTabWidget_h +#define _nsTabWidget_h + +#include "nsWindow.h" +#include "nsITabWidget.h" + +// C++ wrapper for tab control + +class nsTabWidget : public nsWindow, public nsITabWidget +{ + public: + nsTabWidget() {} + + // nsISupports + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(void); + NS_IMETHOD_(nsrefcnt) Release(void); + + // nsITabWidget + NS_IMETHOD SetTabs( PRUint32 aNumberOfTabs, + const nsString aTabLabels[]); + NS_IMETHOD GetSelectedTab( PRUint32 &aTab); + + // message stopping.. + virtual PRBool OnMove( PRInt32 aX, PRInt32 aY) { return PR_FALSE; } + // ..and starting + virtual PRBool OnControl( MPARAM mp1, MPARAM mp2); + + protected: + // creation hooks + virtual PCSZ WindowClass(); + virtual ULONG WindowStyle(); +}; + +#endif diff --git a/mozilla/widget/src/os2/nsTextArea.cpp b/mozilla/widget/src/os2/nsTextArea.cpp new file mode 100644 index 00000000000..d5c0d98e1a5 --- /dev/null +++ b/mozilla/widget/src/os2/nsTextArea.cpp @@ -0,0 +1,241 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include "nsTextArea.h" + +NS_IMPL_ADDREF(nsTextArea) +NS_IMPL_RELEASE(nsTextArea) +nsresult nsTextArea::QueryInterface( const nsIID &aIID, void **aInstancePtr) +{ + nsresult result = nsWindow::QueryInterface( aIID, aInstancePtr); + + if( result == NS_NOINTERFACE && aIID.Equals( nsITextAreaWidget::GetIID())) + { + *aInstancePtr = (void*) ((nsITextAreaWidget*)this); + NS_ADDREF_THIS(); + result = NS_OK; + } + + return result; +} + +// MLE notes: in Warp 4 (and I guess Warp3 fp 28-ish) MLE's *do* respond +// correctly to colour-changes via presparams. +// +// Should really add code to deal with text lengths > 64k. +// +// No DBCS support. +// +// Format is currently left as MLFIE_CFTEXT; need to wait & see what it +// should be. MLFIE_WINFMT could well be the right thing to do; set this +// using the PostCreateWidget() hook. +// +// May also need strategic MLM_DISABLEREFRESH + +nsresult nsTextArea::GetText( nsString &aTextBuffer, PRUint32 aBufferSize, PRUint32 &len) +{ + if( mToolkit != nsnull) + { + IPT clength = (IPT) mOS2Toolkit->SendMsg( mWnd, MLM_QUERYTEXTLENGTH); + // now get bytes + long length = (long) mOS2Toolkit->SendMsg( mWnd, MLM_QUERYFORMATTEXTLENGTH, + 0, MPFROMLONG(length)); + // ..buffer.. + NS_ALLOC_CHAR_BUF(buf,256,length+1) + + mOS2Toolkit->SendMsg( mWnd, MLM_SETIMPORTEXPORT, + MPFROMP(buf), MPFROMLONG(length+1)); + IPT start = 0; + mOS2Toolkit->SendMsg( mWnd, MLM_EXPORT, MPFROMP(&start), MPFROMP(&length)); + + aTextBuffer.SetLength(0); + aTextBuffer.Append(buf); + + NS_FREE_CHAR_BUF(buf) + + len = clength; + } + else + { + aTextBuffer = mText; + len = aTextBuffer.Length(); + } + + return NS_OK; +} + +nsresult nsTextArea::SetText( const nsString &aText, PRUint32 &len) +{ + if( mOS2Toolkit != nsnull) + { + RemoveText(); + + NS_ALLOC_STR_BUF(buf,aText,512) + + mOS2Toolkit->SendMsg( mWnd, MLM_SETIMPORTEXPORT, + MPFROMP(buf), MPFROMLONG(aText.Length() + 1)); + IPT ipt = 0; + mOS2Toolkit->SendMsg( mWnd, MLM_IMPORT, + MPFROMP(&ipt), MPFROMLONG(aText.Length())); + + NS_FREE_STR_BUF(buf) + } + + len = aText.Length(); + mText = aText; + + return NS_OK; +} + +nsresult nsTextArea::InsertText( const nsString &aText, PRUint32 aStartPos, PRUint32 aEndPos, PRUint32 &len) +{ + PRUint32 dummy; + nsString currentText; + GetText( currentText, 256, dummy); + nsString newText( aText); + currentText.Insert( newText, aStartPos, aText.Length()); + SetText( currentText, dummy); + len = aText.Length(); + return NS_OK; +} + +nsresult nsTextArea::RemoveText() +{ + if( mOS2Toolkit != nsnull) + { + IPT length = (IPT) mOS2Toolkit->SendMsg( mWnd, MLM_QUERYTEXTLENGTH); + mOS2Toolkit->SendMsg( mWnd, MLM_DELETE, MPFROMLONG(0), MPFROMLONG(length)); + } + return NS_OK; +} + +nsresult nsTextArea::SetPassword( PRBool aIsPassword) +{ + // no... + return NS_OK; +} + +nsresult nsTextArea::SetMaxTextLength( PRUint32 aChars) +{ + if( mToolkit != nsnull) + { + long lSize = aChars ? (long)aChars : -1; + mOS2Toolkit->SendMsg( mWnd, MLM_SETTEXTLIMIT, MPFROMLONG(lSize)); + } + + return NS_OK; +} + +nsresult nsTextArea::SetReadOnly( PRBool aReadOnlyFlag, PRBool &bOld) +{ + BOOL bOldState; + if( mWnd) + { + bOldState = (BOOL) mOS2Toolkit->SendMsg( mWnd, MLM_QUERYREADONLY); + mOS2Toolkit->SendMsg( mWnd, MLM_SETREADONLY, MPFROMSHORT(aReadOnlyFlag)); + } + else + { + bOldState = mStyle & MLS_READONLY; + if( aReadOnlyFlag) + mStyle |= MLS_READONLY; + else + mStyle &= ~MLS_READONLY; + } + bOld = bOldState ? PR_TRUE : PR_FALSE; + return NS_OK; +} + +nsresult nsTextArea::SelectAll() +{ + if( mToolkit != nsnull) + { + IPT length = (IPT) mOS2Toolkit->SendMsg( mWnd, MLM_QUERYTEXTLENGTH); + SetSelection( 0, length); + } + + return NS_OK; +} + +nsresult nsTextArea::SetSelection( PRUint32 aStartSel, PRUint32 aEndSel) +{ + if( mToolkit != nsnull) + mOS2Toolkit->SendMsg( mWnd, MLM_SETSEL, + MPFROMLONG(aStartSel), MPFROMLONG(aEndSel)); + return NS_OK; +} + +nsresult nsTextArea::GetSelection( PRUint32 *aStartSel, PRUint32 *aEndSel) +{ + if( mToolkit != nsnull) + { + MRESULT rc = mOS2Toolkit->SendMsg( mWnd, MLM_QUERYSEL, + MPFROMLONG(MLFQS_MINMAXSEL)); + if( aStartSel) + *aStartSel = SHORT1FROMMR(rc); + if( aEndSel) + *aEndSel = SHORT2FROMMR(rc); + } + + return NS_OK; +} + +nsresult nsTextArea::SetCaretPosition( PRUint32 aPosition) +{ + if( mToolkit != nsnull) + mOS2Toolkit->SendMsg( mWnd, MLM_SETSEL, + MPFROMLONG(aPosition), MPFROMLONG(aPosition)); + return NS_OK; +} + +nsresult nsTextArea::GetCaretPosition( PRUint32 &ret) +{ + if( mToolkit != nsnull) + { + MRESULT rc = mOS2Toolkit->SendMsg( mWnd, MLM_QUERYSEL, + MPFROMLONG(MLFQS_CURSORSEL)); + ret = (PRUint32) rc; + } + + return NS_OK; +} + +// platform hooks +PCSZ nsTextArea::WindowClass() +{ + return WC_MLE; +} + +ULONG nsTextArea::WindowStyle() +{ // no wordwrap, intentional; should be in interface... + return mStyle | MLS_BORDER | MLS_HSCROLL | MLS_VSCROLL | BASE_CONTROL_STYLE; +} + +nsresult nsTextArea::PreCreateWidget( nsWidgetInitData *aInitData) +{ + if( nsnull != aInitData) + { + nsTextWidgetInitData *data = (nsTextWidgetInitData *) aInitData; + if( data->mIsReadOnly) + mStyle |= MLS_READONLY; + } + return NS_OK; +} diff --git a/mozilla/widget/src/os2/nsTextArea.h b/mozilla/widget/src/os2/nsTextArea.h new file mode 100644 index 00000000000..b9dc0e5b2b5 --- /dev/null +++ b/mozilla/widget/src/os2/nsTextArea.h @@ -0,0 +1,68 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nstextarea_h +#define _nstextarea_h + +#include "nswindow.h" +#include "nsITextAreaWidget.h" + +// WC_MLE wrapper, for NS_TEXTAREAWIDGET_CID +class nsTextArea : public nsWindow, public nsITextAreaWidget +{ + public: + // scaffolding + nsTextArea() : nsWindow(), mStyle( 0) {} + + // nsISupports + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(void); + NS_IMETHOD_(nsrefcnt) Release(void); + + // nsITextAreaWidget + NS_IMETHOD GetText( nsString &aTextBuffer, PRUint32 aBufferSize, PRUint32 &); + NS_IMETHOD SetText( const nsString &aText, PRUint32 &); + NS_IMETHOD InsertText( const nsString &aText, PRUint32 aStartPos, PRUint32 aEndPos, PRUint32 &); + NS_IMETHOD RemoveText(); + NS_IMETHOD SetPassword( PRBool aIsPassword); + NS_IMETHOD SetMaxTextLength( PRUint32 aChars); + NS_IMETHOD SetReadOnly( PRBool aReadOnlyFlag, PRBool &old); + NS_IMETHOD SelectAll(); + NS_IMETHOD SetSelection( PRUint32 aStartSel, PRUint32 aEndSel); + NS_IMETHOD GetSelection( PRUint32 *aStartSel, PRUint32 *aEndSel); + NS_IMETHOD SetCaretPosition( PRUint32 aPosition); + NS_IMETHOD GetCaretPosition( PRUint32 &); + + // platform hooks + virtual PCSZ WindowClass(); + virtual ULONG WindowStyle(); + NS_IMETHOD PreCreateWidget( nsWidgetInitData *aInitData); + + // Message stopping + virtual PRBool OnMove( PRInt32 aX, PRInt32 aY) { return PR_FALSE; } + virtual PRBool OnResize( PRInt32 aX, PRInt32 aY) { return PR_FALSE; } + + protected: + ULONG mStyle; + nsString mText; +}; + +#endif diff --git a/mozilla/widget/src/os2/nsToolkit.cpp b/mozilla/widget/src/os2/nsToolkit.cpp new file mode 100644 index 00000000000..70c5ccd397a --- /dev/null +++ b/mozilla/widget/src/os2/nsToolkit.cpp @@ -0,0 +1,247 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include "nsToolkit.h" + +#include "nsIAppShell.h" +#include "nsGUIEvent.h" +#include "nsWidgetsCID.h" +#include "nsIComponentManager.h" + +// Bits to deal with the case where a new toolkit is initted with a null ---- +// thread. In this case it has to create a new thread to be the PM thread. +// Hopefully this will never happen! + +// struct passed to new thread +struct ThreadInitInfo +{ + PRMonitor *pMonitor; + nsToolkit *toolkit; + + ThreadInitInfo( nsToolkit *tk, PRMonitor *pMon) + : pMonitor( pMon), toolkit( tk) + {} +}; + +// main for the message pump thread +extern "C" void RunPump( void *arg) +{ + ThreadInitInfo *info = (ThreadInitInfo *) arg; + nsIAppShell *pShell = nsnull; + nsresult res; + + static NS_DEFINE_IID(kAppShellCID, NS_APPSHELL_CID); + + res = nsComponentManager::CreateInstance( kAppShellCID, nsnull, + nsIAppShell::GetIID(), + (void **) &pShell); + NS_ASSERTION( res == NS_OK, "Couldn't create new shell"); + + pShell->Create( 0, 0); + + // do registration and creation in this thread + info->toolkit->CreateInternalWindow( PR_GetCurrentThread()); + + // let the main thread continue + PR_EnterMonitor( info->pMonitor); + PR_Notify( info->pMonitor); + PR_ExitMonitor( info->pMonitor); + + pShell->Run(); + NS_RELEASE( pShell); +} + +// toolkit method to create a new thread and process the msgq there +void nsToolkit::CreatePMThread() +{ + PR_EnterMonitor( mMonitor); + + ThreadInitInfo ti( this, mMonitor); + + // create a pm thread + mPMThread = ::PR_CreateThread( PR_SYSTEM_THREAD, + RunPump, + &ti, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + // wait for it to start + PR_Wait( mMonitor, PR_INTERVAL_NO_TIMEOUT); + PR_ExitMonitor( mMonitor); +} + +// 'Normal use' toolkit methods --------------------------------------------- +nsToolkit::nsToolkit() : mDispatchWnd( 0), mPMThread( 0) +{ + NS_INIT_REFCNT(); + mMonitor = PR_NewMonitor(); +} + +nsToolkit::~nsToolkit() +{ + // Destroy the Dispatch Window + WinDestroyWindow( mDispatchWnd); + + // Destroy monitor + PR_DestroyMonitor( mMonitor); +} + +// nsISupports implementation macro +NS_IMPL_ISUPPORTS(nsToolkit, nsIToolkit::GetIID()) + +static MRESULT EXPENTRY fnwpDispatch( HWND, ULONG, MPARAM, MPARAM); +#define UWC_DISPATCH "DispatchWndClass" + +// Create the internal window - also sets the pm thread 'formally' +void nsToolkit::CreateInternalWindow( PRThread *aThread) +{ + NS_PRECONDITION(aThread, "null thread"); + mPMThread = aThread; + + BOOL rc = WinRegisterClass( 0/*hab*/, UWC_DISPATCH, fnwpDispatch, 0, 0); + NS_ASSERTION( rc, "Couldn't register class"); + + // create the internal window - just use a static + mDispatchWnd = WinCreateWindow( HWND_DESKTOP, + UWC_DISPATCH, + 0, 0, + 0, 0, 0, 0, + HWND_DESKTOP, + HWND_BOTTOM, + 0, 0, 0); + + NS_ASSERTION( mDispatchWnd, "Couldn't create toolkit internal window"); +} + +// Set up the toolkit - create window, check for thread. +nsresult nsToolkit::Init( PRThread *aThread) +{ + // Store the thread ID of the thread with the message queue. + // If no thread is provided create one (!!) + if( aThread) + CreateInternalWindow( aThread); + else + // create a thread where the message pump will run + CreatePMThread(); + return NS_OK; +} + +// Bits to reflect events into the pm thread -------------------------------- + +// additional structure to provide synchronization & returncode +// Unlike Windows, we cannot use WinSendMsg() +struct RealMethodInfo +{ + MethodInfo *pInfo; + PRMonitor *pMonitor; + nsresult rc; + + RealMethodInfo( MethodInfo *info, PRMonitor *pMon) + : pInfo( info), pMonitor( pMon), rc( NS_ERROR_FAILURE) + {} +}; + +nsresult nsToolkit::CallMethod( MethodInfo *pInfo) +{ + PR_EnterMonitor( mMonitor); + + RealMethodInfo rminfo( pInfo, mMonitor); + + // post the message to the window + WinPostMsg( mDispatchWnd, WMU_CALLMETHOD, MPFROMP(&rminfo), 0); + + // wait for it to complete... + PR_Wait( mMonitor, PR_INTERVAL_NO_TIMEOUT); + PR_ExitMonitor( mMonitor); + + // cleanup & return + return rminfo.rc; +} + +struct SendMsgStruct +{ + HWND hwnd; + ULONG msg; + MPARAM mp1, mp2; + MRESULT rc; + + PRMonitor *pMonitor; + + SendMsgStruct( HWND h, ULONG m, MPARAM p1, MPARAM p2, PRMonitor *pMon) + : hwnd( h), msg( m), mp1( p1), mp2( p2), rc( 0), pMonitor( pMon) + {} +}; + +MRESULT nsToolkit::SendMsg( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + MRESULT rc = 0; + + if( hwnd && IsPMThread()) + rc = WinSendMsg( hwnd, msg, mp1, mp2); + else if( hwnd) + { + PR_EnterMonitor( mMonitor); + + SendMsgStruct data( hwnd, msg, mp1, mp2, mMonitor); + + // post a message to the window + WinPostMsg( mDispatchWnd, WMU_SENDMSG, MPFROMP(&data), 0); + + // wait for it to complete... + PR_Wait( mMonitor, PR_INTERVAL_NO_TIMEOUT); + PR_ExitMonitor( mMonitor); + + rc = data.rc; + } + + return rc; +} + +MRESULT EXPENTRY fnwpDispatch( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + MRESULT mRC = 0; + + if( msg == WMU_CALLMETHOD) + { + RealMethodInfo *pInfo = (RealMethodInfo*) mp1; + // call the method (indirection-fest :-) + pInfo->rc = pInfo->pInfo->target->CallMethod( pInfo->pInfo); + // signal the monitor to let the caller continue + PR_EnterMonitor( pInfo->pMonitor); + PR_Notify( pInfo->pMonitor); + PR_ExitMonitor( pInfo->pMonitor); + } + else if( msg == WMU_SENDMSG) + { + SendMsgStruct *pData = (SendMsgStruct*) mp1; + // send the message + pData->rc = WinSendMsg( pData->hwnd, pData->msg, pData->mp1, pData->mp2); + // signal the monitor to let the caller continue + PR_EnterMonitor( pData->pMonitor); + PR_Notify( pData->pMonitor); + PR_ExitMonitor( pData->pMonitor); + } + else + mRC = WinDefWindowProc( hwnd, msg, mp1, mp2); + + return mRC; +} diff --git a/mozilla/widget/src/os2/nsToolkit.h b/mozilla/widget/src/os2/nsToolkit.h new file mode 100644 index 00000000000..193b1fef0cd --- /dev/null +++ b/mozilla/widget/src/os2/nsToolkit.h @@ -0,0 +1,117 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _toolkit_h +#define _toolkit_h + +#include "nsIToolkit.h" +#include "nsWidgetDefs.h" +#include "prmon.h" + +// This is a wrapper around the 'pm thread' which runs the message queue. +// Need to do this to 1) ensure windows are always created/destroyed etc. +// in the same thread, 2) because there's no guarantee that a calling +// thread will have a message queue. +// +// In normal operation, a top level window will be created with a null +// toolkit. This creates a new toolkit & init's with the current thread. +// There is an assumption that there is an nsAppShell for that thread, +// which becomes the 'PM thread'. A null thread can be passed in, in +// which case a new thread is created & set to be the PM thread - this +// shouldn't really happen because there's no condition for thread#1 to +// exit! +// +// To allow non-pm threads to call pm functions, a slightly contorted +// mechanism is used. +// +// The object which wishes to do tasks in the pm thread (eg. nsWindow) must +// derive from the nsSwitchToPMThread class. +// At task-time, create an instance of MethodInfo and call the 'CallMethod' +// method in the widget's toolkit. This will call back into the object's +// 'CallMethod' in the pm thread, and not return until it does. +// +// The good news is that you probably don't need to worry about this! +// +// What you may need to 'worry about' is the 'SendMsg' method. When you +// want to call WinSendMsg & you're not certain you're in the PM thread, +// use this one, and the right thing will happen. + +struct MethodInfo; + +class nsToolkit : public nsIToolkit +{ + public: + nsToolkit(); + virtual ~nsToolkit(); + + NS_DECL_ISUPPORTS + + NS_IMETHOD Init( PRThread *aThread); + + nsresult CallMethod( MethodInfo *info); + MRESULT SendMsg( HWND hwnd, ULONG msg, MPARAM mp1 = 0, MPARAM mp2 = 0); + + // Return whether the current thread is the application's PM thread. + PRBool IsPMThread() { return (PRBool)(mPMThread == PR_GetCurrentThread());} + PRThread *GetPMThread() { return mPMThread; } + HWND GetDispatchWindow() { return mDispatchWnd; } + + void CreateInternalWindow( PRThread *aThread); + + private: + void CreatePMThread(); + + protected: + // Handle of the window used to receive dispatch messages. + HWND mDispatchWnd; + // Thread Id of the PM thread. + PRThread *mPMThread; + // Monitor used to coordinate dispatch + PRMonitor *mMonitor; +}; + +// Interface to derive things from +class nsSwitchToPMThread +{ + public: + // No return code: if this is a problem then + virtual nsresult CallMethod( MethodInfo *info) = 0; +}; + +// Structure used for passing the information +struct MethodInfo +{ + nsSwitchToPMThread *target; + UINT methodId; + int nArgs; + ULONG *args; + + MethodInfo( nsSwitchToPMThread *obj, UINT id, + int numArgs = 0, ULONG *arguments = 0) + { + target = obj; + methodId = id; + nArgs = numArgs; + args = arguments; + } +}; + +#endif diff --git a/mozilla/widget/src/os2/nsTooltipManager.cpp b/mozilla/widget/src/os2/nsTooltipManager.cpp new file mode 100644 index 00000000000..00426ae57d7 --- /dev/null +++ b/mozilla/widget/src/os2/nsTooltipManager.cpp @@ -0,0 +1,364 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include "nsTooltipManager.h" +#include "nswindow.h" + +// Created 25-9-98 mjf, improvising furiously... + +// --> Bank on TTData->cRcls being smallish. +// +// This is probably a bad bet, seeing as the main use will be on a child +// window rendering content with many separate areas of interest (eg. 1 +// per image with alt text). +// +// So it may turn out to be a good idea to make this data structure more +// sophisticated -- hash on the coordinates. + +// Hashtable defs; key is HWND, element is TTData* +class HWNDHashKey : public nsHashKey +{ + HWND hwnd; + + public: + HWNDHashKey( HWND h) : hwnd(h) {} + + virtual PRUint32 HashValue() const { return hwnd; } + virtual PRBool Equals( const nsHashKey *aKey) const + { return (((HWNDHashKey*)aKey)->hwnd == hwnd) ? PR_TRUE : PR_FALSE; } + virtual nsHashKey *Clone() const + { return new HWNDHashKey( hwnd); } +}; + +#define ID_TT_TIMER (TID_USERMAX-1) + +struct TTData +{ + HWND hwnd; + RECTL *aRcls; // could use a region to hold rects, but need to know + ULONG cRcls; // index of rectangle for notifications. + // [see large comment above] + + + LONG lIndex; // Index of last rectangle hit. -1 is none. + LONG lIndexShowing; + PFNWP oldFnWp; + BOOL bTimerSet; + POINTL ptStart; + + TTData( HWND h) : hwnd(h), aRcls(0), cRcls(0), lIndex(-1), + lIndexShowing(-1), oldFnWp(0), bTimerSet(0) + { ptStart.x = 0; ptStart.y = 0; } + + ~TTData() + { delete [] aRcls; } + + // if cRects is 0, same number as we already have. + void UpdateTooltips( nsWindow *w, nsRect *rects[], PRUint32 cRects = 0) + { + if( cRects > 0) + { + delete [] aRcls; + aRcls = new RECTL [cRects]; + cRcls = cRects; + } + + // Get bounds once.. + nsRect bounds; + w->GetBounds( bounds); + + for( ULONG i = 0; i < cRects; i++) + { + // convert the ith nsrect to the ith in-ex rectl + aRcls[i].yTop = bounds.height - rects[i]->y; + aRcls[i].xLeft = rects[i]->x; + aRcls[i].xRight = aRcls[i].xLeft + rects[i]->width; + aRcls[i].yBottom = aRcls[i].yTop - rects[i]->height; + } + } + + void StopTimer() + { + if( bTimerSet) + { + WinStopTimer( 0/*hab*/, hwnd, ID_TT_TIMER); + bTimerSet = FALSE; + } + } + + void StartTimer() + { + if( !bTimerSet) + { + WinStartTimer( 0/*hab*/, hwnd, ID_TT_TIMER, 1000); // 1 second? + bTimerSet = TRUE; + } + } + + long Test( PPOINTL pt) + { + lIndex = -1; + for( ULONG i = 0; lIndex == -1 && i < cRcls; i++) + if( WinPtInRect( 0/*hab*/, aRcls + i, pt)) + lIndex = i; + return lIndex; + } + + void ShowTooltip() + { + NS_ASSERTION( lIndex >= 0, "Invalid tt index"); + if( lIndex != lIndexShowing) + { + WinSendMsg( hwnd, WMU_SHOW_TOOLTIP, MPFROMLONG(lIndex), 0); + lIndexShowing = lIndex; + } + } + + void HideTooltip() + { + if( lIndexShowing != -1) + { + WinSendMsg( hwnd, WMU_HIDE_TOOLTIP, 0, 0); + lIndexShowing = -1; + } + } +}; + +// subclass to watch for mouse messages +MRESULT EXPENTRY HandleMsg( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + return nsTooltipManager::GetManager()->HandleMsg( hwnd, msg, mp1, mp2); +} + +#define HOVER_DIST_SQR 100 + +// Message handler --------------------------------------------------------- +MRESULT nsTooltipManager::HandleMsg( HWND hwnd, ULONG msg, + MPARAM mp1, MPARAM mp2) +{ + MRESULT mRC = 0; + + // find data area + TTData *pData = GetEntry( hwnd); + + if( pData) + { + BOOL bSet = FALSE; + + switch( msg) + { + case WMU_MOUSEENTER: + case WM_MOUSEMOVE: + { + // Is point in rectl list? + // Yes: Is tooltip mode on? + // Yes: Show tooltip + // No: Is timer set? + // Yes: Is point < HOVER_DIST from startpoint ? + // Yes: run away + // No: Stop timer + // No: nop + // Record startpoint + // Start timer + // No: No tooltip here: Stop timer, run away + pData->StopTimer(); + POINTL pt = { SHORT1FROMMP(mp1), SHORT2FROMMP(mp1) }; + if( pData->Test( &pt) >= 0) + { + if( mTTMode == PR_TRUE) + { + pData->ShowTooltip(); + } + else + { + if( pData->bTimerSet) + { + // ..approx.. + long lX = pt.x - pData->ptStart.x; + long lY = pt.y - pData->ptStart.y; + + if( lX * lX + lY * lY < HOVER_DIST_SQR) + { + break; + } + else + { + pData->StopTimer(); + } + } + memcpy( &pData->ptStart, &pt, sizeof pt); + pData->StartTimer(); + } + } + else + { + pData->StopTimer(); + } + break; + } + + case WM_TIMER: + // Is it our timer? + // Yes: Set tooltip mode; cancel timer; show tooltip + // No: Run away + if( SHORT1FROMMP( mp1) == ID_TT_TIMER) + { + mTTMode = PR_TRUE; + pData->StopTimer(); + pData->ShowTooltip(); + bSet = TRUE; + } + break; + + case WMU_MOUSELEAVE: + // Is tooltip mode on? + // Yes: hide tooltip; Is next window one of ours? + // Yes: do nothing + // No: unset tooltip mode + // No: stop timer + if( mTTMode) + { + pData->HideTooltip(); + if( 0 == GetEntry( HWNDFROMMP(mp2))) + { + mTTMode = PR_FALSE; + } + } + else + { + pData->StopTimer(); + } + break; + + case WM_BUTTON1DOWN: + case WM_BUTTON2DOWN: + case WM_BUTTON3DOWN: + // Is tooltip mode on? + // Yes: hide tooltip; unset tooltip mode + // No: Stop timer + if( mTTMode) + { + pData->HideTooltip(); + mTTMode = PR_FALSE; + } + else + { + pData->StopTimer(); + } + break; + } + + if( !bSet && pData->oldFnWp) + mRC = (*pData->oldFnWp)( hwnd, msg, mp1, mp2); + } + else // ..oops.. + mRC = WinDefWindowProc( hwnd, msg, mp1, mp2); + return mRC; +} + +// Manager methods --------------------------------------------------------- +TTData *nsTooltipManager::GetEntry( nsWindow *w) +{ + HWND hwnd = (HWND) w->GetNativeData( NS_NATIVE_WINDOW); + return GetEntry( hwnd); +} + +TTData *nsTooltipManager::GetEntry( HWND hwnd) +{ + HWNDHashKey key( hwnd); + return (TTData*) mManaged.Get( &key); +} + +void nsTooltipManager::SetTooltips( nsWindow *window, + PRUint32 cTips, nsRect *rects[]) +{ + TTData *pData = GetEntry( window); + + if( !pData) + { + HWND hwnd = (HWND) window->GetNativeData( NS_NATIVE_WINDOW); + pData = new TTData( hwnd); + pData->oldFnWp = WinSubclassWindow( hwnd, ::HandleMsg); + HWNDHashKey key(hwnd); + mManaged.Put( &key, pData); + mElements++; + } + pData->UpdateTooltips( window, rects, cTips); +} + +void nsTooltipManager::UpdateTooltips( nsWindow *window, nsRect *rects[]) +{ + TTData *pData = GetEntry( window); + + NS_ASSERTION( pData, "Update tt for bad window"); + + pData->UpdateTooltips( window, rects); +} + +void nsTooltipManager::RemoveTooltips( nsWindow *window) +{ + HWND hwnd = (HWND) window->GetNativeData( NS_NATIVE_WINDOW); + + HWNDHashKey key( hwnd); + TTData *pData = (TTData*) mManaged.Remove( &key); + + if( pData) + { + pData->StopTimer(); // just for safety + WinSubclassWindow( hwnd, pData->oldFnWp); + + delete pData; + mElements--; + } + + if( 0 == mElements) // no clients, go away + { + delete this; + nsTooltipManager::sMgr = 0; + } +} + +// Ctor/dtor stuff --------------------------------------------------------- +nsTooltipManager::nsTooltipManager() : mElements(0), mTTMode( PR_FALSE) +{} + +PRBool emptyHashtableFunc( nsHashKey *aKey, void *aData, void *pClosure) +{ + delete (TTData*) aData; + return PR_TRUE; // keep going +} + +nsTooltipManager::~nsTooltipManager() +{ + // shouldn't be any elements... + // NS_ASSERTION( mElements == 0, "Non-deregistered tts"); + mManaged.Enumerate( emptyHashtableFunc); +} + +nsTooltipManager *nsTooltipManager::GetManager() +{ + if( !sMgr) + sMgr = new nsTooltipManager; + + return sMgr; +} + +nsTooltipManager *nsTooltipManager::sMgr; diff --git a/mozilla/widget/src/os2/nsTooltipManager.h b/mozilla/widget/src/os2/nsTooltipManager.h new file mode 100644 index 00000000000..660518cdcee --- /dev/null +++ b/mozilla/widget/src/os2/nsTooltipManager.h @@ -0,0 +1,64 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nstooltipmgr_h +#define _nstooltipmgr_h + +// Tooltip manager: code to watch windows & send tooltip events. +// +// Created 25-9-98; interface determined by nsWindow requirements. + +#include "nscore.h" +#include "nsrect.h" +#include "nsWidgetDefs.h" +#include "nshashtable.h" + +class nsWindow; +class TTData; + +class nsTooltipManager +{ + protected: + static nsTooltipManager *sMgr; + + nsHashtable mManaged; + PRInt32 mElements; + PRBool mTTMode; + + MRESULT HandleMsg( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2); + + TTData *GetEntry( nsWindow *); + TTData *GetEntry( HWND); + + nsTooltipManager(); + ~nsTooltipManager(); + + friend MRESULT EXPENTRY HandleMsg( HWND hwnd, ULONG msg, MPARAM, MPARAM); + + public: + static nsTooltipManager *GetManager(); + + void SetTooltips( nsWindow *window, PRUint32 cTips, nsRect *rects[]); + void UpdateTooltips( nsWindow *window, nsRect *rects[]); + void RemoveTooltips( nsWindow *window); +}; + +#endif diff --git a/mozilla/widget/src/os2/nsTooltipWidget.cpp b/mozilla/widget/src/os2/nsTooltipWidget.cpp new file mode 100644 index 00000000000..f9e2b95ed5f --- /dev/null +++ b/mozilla/widget/src/os2/nsTooltipWidget.cpp @@ -0,0 +1,86 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include "nsTooltipWidget.h" + +// Tooltip class; just a custom canvas-like class to put things on. + +NS_IMPL_ADDREF(nsTooltipWidget) +NS_IMPL_RELEASE(nsTooltipWidget) + +nsresult nsTooltipWidget::QueryInterface( const nsIID &aIID, void **aInstancePtr) +{ + nsresult result = nsWindow::QueryInterface(aIID, aInstancePtr); + + if( result == NS_NOINTERFACE && aIID.Equals( nsITooltipWidget::GetIID())) + { + *aInstancePtr = (void*) ((nsITooltipWidget*)this); + NS_ADDREF_THIS(); + result = NS_OK; + } + + return result; +} + +static BOOL bRegistered; +#define NSTOOLTIPCLASS (PCSZ)"WarpzillaTooltip" + +PCSZ nsTooltipWidget::WindowClass() +{ + if( !bRegistered) + { + BOOL rc = WinRegisterClass( 0 /*hab*/, NSTOOLTIPCLASS, + WinDefWindowProc, 0, 4); + NS_ASSERTION( rc, "Couldn't register tooltip class"); + bRegistered = TRUE; + } + + return NSTOOLTIPCLASS; +} + +ULONG nsTooltipWidget::WindowStyle() +{ + return 0; +} + +// background for tooltips +#define MK_RGB(r,g,b) ((r) * 65536) + ((g) * 256) + (b) + + +PRBool nsTooltipWidget::OnPaint() +{ + // Draw tooltip - black border, off-white interior + RECTL rcl; + HPS hps = WinBeginPaint( mWnd, 0, &rcl); + WinQueryWindowRect( mWnd, &rcl); + GpiCreateLogColorTable( hps, LCOL_PURECOLOR, LCOLF_RGB, 0, 0, 0); + long lColor = 0; // black + GpiSetAttrs( hps, PRIM_LINE, LBB_COLOR, 0, &lColor); + lColor = MK_RGB(255,255,185); // off-white + GpiSetAttrs( hps, PRIM_AREA, ABB_COLOR, 0, &lColor); + rcl.yTop--; + rcl.xRight--; + PPOINTL pts = (PPOINTL) &rcl; + GpiMove( hps, pts); + GpiBox( hps, DRO_OUTLINEFILL, pts + 1, 0, 0); + WinEndPaint( hps); + return PR_TRUE; +} diff --git a/mozilla/widget/src/os2/nsTooltipWidget.h b/mozilla/widget/src/os2/nsTooltipWidget.h new file mode 100644 index 00000000000..4d887234226 --- /dev/null +++ b/mozilla/widget/src/os2/nsTooltipWidget.h @@ -0,0 +1,51 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nstooltipwidget_h +#define _nstooltipwidget_h + +#include "nsWindow.h" +#include "nsITooltipWidget.h" + +// Tooltip window. + +class nsTooltipWidget : public nsWindow, public nsITooltipWidget +{ + public: + nsTooltipWidget() : nsWindow() {} + + // nsISupports + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(void); + NS_IMETHOD_(nsrefcnt) Release(void); + + // platform hooks + virtual PCSZ WindowClass(); + virtual ULONG WindowStyle(); + + // Message stopping + virtual PRBool OnResize( PRInt32 aX, PRInt32 aY) { return PR_FALSE; } + + // Look like a tooltip + virtual PRBool OnPaint(); +}; + +#endif diff --git a/mozilla/widget/src/os2/nsWidgetDefs.h b/mozilla/widget/src/os2/nsWidgetDefs.h new file mode 100644 index 00000000000..52d77745bdf --- /dev/null +++ b/mozilla/widget/src/os2/nsWidgetDefs.h @@ -0,0 +1,190 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nswidgetdefs_h +#define _nswidgetdefs_h + +// OS/2 defines; for user messages & warp4 stuff, plus module-global data + +#include "nsIWidget.h" +#include "nsVoidArray.h" + +#define INCL_PM +#define INCL_NLS +#define INCL_DOS +#include +#include // Rather not have to include these two, but need types... +#include // + +#define SUPPORT_NON_XPFE /* support for viewer.exe */ + +class nsIFontRetrieverService; +class nsDragService; +class nsIAppShell; + +// Module data -- anything that would be static, should be module-visible, +// or any magic constants. +class nsWidgetModuleData +{ + public: + HMODULE hModResources; // resource module + SIZEL szScreen; // size of screen in pixels + BOOL bMouseSwitched; // true if MB1 is the RH mouse button + LONG lHtEntryfield; // ideal height of an entryfield + char *pszFontNameSize; // fns for default widget font + BOOL bIsDBCS; // true if system is dbcs + ULONG ppMozilla; // pres-param for hwnd <-> nsWindow* + + // xptoolkit services we look after, & the primaeval appshell too. + nsIFontRetrieverService *fontService; + nsDragService *dragService; + nsIAppShell *appshell; + + // We're caching resource-loaded things here too. This may be + // better-suited elsewhere, but there shouldn't be very many of them. + HPOINTER GetPointer( nsCursor aCursor); + HPOINTER GetFrameIcon(); + + // Unicode->local cp. conversions + char *ConvertFromUcs( const PRUnichar *pText, char *szBuffer, ULONG ulSize); + char *ConvertFromUcs( const nsString &aStr, char *szBuffer, ULONG ulSize); + // these methods use a single static buffer + const char *ConvertFromUcs( const PRUnichar *pText); + const char *ConvertFromUcs( const nsString &aStr); + + // Unicode keyboard utility stuff + KHAND hKeyboard; + int TranslateKey( VSCAN scan, UniChar *aChar, VDKEY *vdkey); + + // Atom service; clients don't need to bother about freeing them. + ATOM GetAtom( const char *atomname); + ATOM GetAtom( const nsString &atomname); + +#if 0 + HWND GetWindowForPrinting( PCSZ pszClass, ULONG ulStyle); +#endif + + nsWidgetModuleData(); + ~nsWidgetModuleData(); + + void Init( nsIAppShell *aPrimaevalAppShell); + + private: + HPOINTER hptrSelect; // !! be more sensible about this... + HPOINTER hptrFrameIcon; +#if 0 + nsHashtable *mWindows; +#endif + + UconvObject converter; + BOOL supplantConverter; + + nsVoidArray atoms; +}; + +extern nsWidgetModuleData gModuleData; + +// messages - here to avoid duplication +#define WMU_CALLMETHOD (WM_USER + 1) +#define WMU_SENDMSG (WM_USER + 2) + +// MP1 is "LONG lIndex", MP2 is reserved +#define WMU_SHOW_TOOLTIP (WM_USER + 3) + +// MP1 & MP2 both reserved +#define WMU_HIDE_TOOLTIP (WM_USER + 4) + +// DRM_MOZILLA messages + +// WMU_GETFLAVOURLEN +// +// mp1 - ULONG ulItemID Item ID from DRAGITEM +// mp2 - HATOM hAtomFlavour Atom in the system table for the data flavour +// +// returns - ULONG ulSize Size in bytes of transfer data, 0 for error +// +#define WMU_GETFLAVOURLEN (WM_USER + 5) + +typedef struct _WZDROPXFER +{ + ATOM hAtomFlavour; + CHAR data[1]; +} WZDROPXFER, *PWZDROPXFER; + +// WMU_GETFLAVOURDATA +// +// mp1 - ULONG ulItemID Item ID from DRAGITEM +// mp2 - PWZDROPXFER pvData Pointer to buffer to put data. +// Must DosFreeMem(). +// +// returns - BOOL bSuccess TRUE ok, FALSE error occurred. + +#define WMU_GETFLAVOURDATA (WM_USER + 6) + +#define WinIsKeyDown(vk) ((WinGetKeyState(HWND_DESKTOP,vk) & 0x8000) ? PR_TRUE : PR_FALSE) + +// Tab control uses messages from TABM_BASE, which is currently (WM_USER+50). +// See tabapi.h for details. + +// WMU'd to avoid potential clash with offical names. +// MP2 is the other window. +#define WMU_MOUSEENTER 0x041e +#define WMU_MOUSELEAVE 0x041f + +#ifndef FCF_CLOSEBUTTON // defined in the Merlin toolkit +#define FCF_CLOSEBUTTON 0x04000000L +#endif + +#ifndef DRT_URL +#define DRT_URL "UniformResourceLocator" +#endif + +#define BASE_CONTROL_STYLE WS_TABSTOP + +#define NS_MIT_END ((const PRUint32) MIT_END) + +// A common pattern in widget is the 'Get/SetLabel' methods. These macros +// can be used to fill in implementations who derive from nsWindow and just +// want to call WinSet/QueryWindowText. + +#define NS_DECL_LABEL \ + NS_IMETHOD SetLabel( const nsString &aText); \ + NS_IMETHOD GetLabel( nsString &aBuffer); + +#define NS_IMPL_LABEL(_clsname) \ + nsresult _clsname::SetLabel( const nsString &aText) \ + { \ + SetTitle( aText); \ + return NS_OK; \ + } \ + \ + nsresult _clsname::GetLabel( nsString &aBuffer) \ + { \ + PRUint32 dummy; \ + GetWindowText( aBuffer, &dummy); \ + return NS_OK; \ + } + +// can be used as an lvalue too. +#define lastchar(s) *((s) + strlen((s)) - 1) + + +#endif diff --git a/mozilla/widget/src/os2/nsWindow.cpp b/mozilla/widget/src/os2/nsWindow.cpp new file mode 100644 index 00000000000..eab28686b16 --- /dev/null +++ b/mozilla/widget/src/os2/nsWindow.cpp @@ -0,0 +1,2019 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include "nsWindow.h" +#include "nsIAppShell.h" +#include "nsIFontMetrics.h" +#include "nsGUIEvent.h" +#include "nsIRenderingContext.h" +#include "nsIDeviceContext.h" +#include "nsTransform2D.h" +#include "nsGfxCIID.h" +#include "prtime.h" +#include "nsFont.h" +#include "nsTooltipManager.h" +#include "nsISupportsArray.h" +#include "nsITimer.h" +#include "nsIMenuBar.h" +#include "nsIMenuItem.h" +#include "nsHashtable.h" +#include "nsMenu.h" +#include "nsDragService.h" +#include "nsContextMenu.h" + +#include "tabapi.h" // !! TAB-FIX + +#include +#include + +// HWNDs are mapped to nsWindow objects using a custom presentation parameter, +// which is registered in nsModule -- thanks to Cindy Ross for explaining how +// to do this. +// +// The subclass proc (fnwpNSWindow) calls ProcessMessage() in the object. +// Decisions are taken here about what to do - the purpose of the OnFoo() +// methods is to generate an NS event to the various people who are +// listening, or not. +// +// OS/2 things: remember supplied coords are in the XP space. There are +// NS2PM methods for conversion of points & rectangles; position is a bit +// different in that it's the *parent* window whose height must be used. +// +// Deferred window positioning is emulated using WinSetMultWindowPos in +// the hopes that there was a good reason for adding it to nsIWidget. +// +// SetColorSpace() is not implemented on purpose. So there. +// +// John Fairhurst 17-09-98 first version +// Revised 01-12-98 to inherit from nsBaseWidget. +// Revised 24-01-99 to use hashtable +// Revised 15-03-99 for new menu classes +// Revised 05-06-99 to use pres-params +// Revised 19-06-99 drag'n'drop, etc. + +// XXX don't deliver click-events to obscured parents +BOOL g_bHandlingMouseClick = FALSE; + +// -------------------------------------------------------------------------- +// HWND -> (nsWindow *) conversion ------------------------------------------ + +nsWindow *NS_HWNDToWindow( HWND hwnd) +{ + nsWindow *pWnd = nsnull; + + WinQueryPresParam( hwnd, gModuleData.ppMozilla, 0, NULL, + sizeof pWnd, &pWnd, QPF_NOINHERIT); + return pWnd; +} + +// -------------------------------------------------------------------------- +// NSWindow create / destroy ------------------------------------------------ + +nsWindow::nsWindow() : nsBaseWidget() +{ + NS_INIT_REFCNT(); + + mWnd = 0; + mFnWP = 0; + mParent = 0; + mNextID = 1; + mNextCmdID = 1; + mSWPs = 0; + mlHave = 0; + mlUsed = 0; + mPointer = 0; + mPS = 0; + mPSRefs = 0; + mDragInside = FALSE; + mDeadKey = 0; + mHaveDeadKey = FALSE; + // This is so that frame windows can be destroyed from their destructors. + mHackDestroyWnd = 0; + + mPreferredWidth = 0; + mPreferredHeight = 0; + mWindowState = nsWindowState_ePrecreate; + mFont = nsnull; + mOS2Toolkit = nsnull; + mMenuBar = nsnull; + mActiveMenu = nsnull; +} + +// Do a little work in both create methods & call on to a common DoCreate() +nsresult nsWindow::Create( nsIWidget *aParent, const nsRect &aRect, + EVENT_CALLBACK aHandleEventFunction, + nsIDeviceContext *aContext, nsIAppShell *aAppShell, + nsIToolkit *aToolkit, nsWidgetInitData *aInitData) +{ + HWND hwndP = aParent ? (HWND)aParent->GetNativeData( NS_NATIVE_WINDOW) + : HWND_DESKTOP; + DoCreate( hwndP, (nsWindow*) aParent, aRect, aHandleEventFunction, + aContext, aAppShell, aToolkit, aInitData); + + return NS_OK; +} + +nsresult nsWindow::Create( nsNativeWidget aParent, const nsRect &aRect, + EVENT_CALLBACK aHandleEventFunction, + nsIDeviceContext *aContext, nsIAppShell *aAppShell, + nsIToolkit *aToolkit, nsWidgetInitData *aInitData) +{ + // We need to find the nsWindow that goes with the native window, or controls + // all get the ID of 0, and a zillion toolkits get created. + // + nsWindow *pParent = nsnull; + HWND hwndP = (HWND) aParent; + + if( hwndP && hwndP != HWND_DESKTOP) + pParent = NS_HWNDToWindow( hwndP); + + // XXX WC_MOZILLA will probably need a change here + // + if( !hwndP) + hwndP = HWND_DESKTOP; + + DoCreate( hwndP, pParent, aRect, aHandleEventFunction, aContext, + aAppShell, aToolkit, aInitData); + + return NS_OK; +} + +void nsWindow::DoCreate( HWND hwndP, nsWindow *aParent, const nsRect &aRect, + EVENT_CALLBACK aHandleEventFunction, + nsIDeviceContext *aContext, + nsIAppShell *aAppShell, nsIToolkit *aToolkit, + nsWidgetInitData *aInitData) +{ + mWindowState = nsWindowState_eInCreate; + + // Must ensure toolkit before attempting to thread-switch! + if( !mToolkit) + { + if( aToolkit) + { + mToolkit = aToolkit; + NS_ADDREF(mToolkit); + } + else if( aParent) + mToolkit = aParent->GetToolkit(); + else + { + // it's some top level window with no toolkit passed in. + // Create a default toolkit with the current thread + mToolkit = new nsToolkit; + NS_ADDREF(mToolkit); + mToolkit->Init( PR_GetCurrentThread()); + } + mOS2Toolkit = (nsToolkit*) mToolkit; + } + + // Switch to the PM thread if necessary... + if( !mOS2Toolkit->IsPMThread()) + { + ULONG args[7] = { hwndP, (ULONG) aParent, (ULONG) &aRect, + (ULONG) aHandleEventFunction, + (ULONG) aContext, (ULONG) aAppShell, + (ULONG) aInitData }; + MethodInfo info( this, nsWindow::W_CREATE, 7, args); + mOS2Toolkit->CallMethod( &info); + } + else + // This is potentially virtual; overridden in nsFrameWindow + RealDoCreate( hwndP, aParent, aRect, aHandleEventFunction, + aContext, aAppShell, aInitData); + + mWindowState = nsWindowState_eLive; +} + +void nsWindow::RealDoCreate( HWND hwndP, + nsWindow *aParent, + const nsRect &aRect, + EVENT_CALLBACK aHandleEventFunction, + nsIDeviceContext *aContext, + nsIAppShell *aAppShell, + nsWidgetInitData *aInitData, + HWND hwndOwner) +{ + // Set up parent data - don't addref to avoid circularity + mParent = aParent; + + // Set up window style: first give subclass a chance to prepare + if( aInitData) + PreCreateWidget( aInitData); + + ULONG style = WindowStyle(); + if( aInitData) + { + if( aInitData->clipChildren) + style |= WS_CLIPCHILDREN; +#if 0 + // + // Windows has a slightly different idea of what the implications are + // of a window having or not having the CLIPSIBLINGS style. + // All 'canvas' components we create must have clipsiblings, or + // strange things happen & performance actually degrades. + // + else + style &= ~WS_CLIPCHILDREN; +#endif + + if( aInitData->clipSiblings) + style |= WS_CLIPSIBLINGS; + else + style &= ~WS_CLIPSIBLINGS; + } + + // Create a window: create hidden & then size to avoid swp_noadjust problems + // owner == parent except for 'borderless top-level' -- see nsCanvas.cpp + mWnd = WinCreateWindow( hwndP, + WindowClass(), + 0, // text + style, + 0, 0, 0, 0, // pos/size + hwndOwner ? hwndOwner : hwndP, + HWND_TOP, + mParent ? mParent->GetNextID() : 0, + 0, 0); // ctldata, presparams + + NS_ASSERTION( mWnd, "Couldn't create window"); + + // Make sure we have a device context from somewhere + if( aContext) + { + mContext = aContext; + NS_ADDREF(mContext); + } + else + { + nsresult rc = NS_OK; + static NS_DEFINE_IID(kDeviceContextCID, NS_DEVICE_CONTEXT_CID); + + rc = nsComponentManager::CreateInstance( kDeviceContextCID, nsnull, + nsIDeviceContext::GetIID(), + (void **)&mContext); + if( NS_SUCCEEDED(rc)) + mContext->Init( (nsNativeWidget) mWnd); +#ifdef DEBUG + else + printf( "Couldn't find DC instance for nsWindow\n"); +#endif + } + + WinSetPresParam( mWnd, PP_FONTNAMESIZE, + strlen( gModuleData.pszFontNameSize) + 1, + gModuleData.pszFontNameSize); + + Resize( aRect.x, aRect.y, aRect.width, aRect.height, PR_FALSE); + + // Record bounds. This is XP, the rect of the entire main window in + // parent space. Returned by GetBounds(). + // NB: We haven't subclassed yet, so callbacks to change mBounds won't + // have happened! + mBounds = aRect; + mBounds.height = GetHeight( aRect.height); + + // Record passed in things + mAppShell = aAppShell; + NS_IF_ADDREF( mAppShell); + mEventCallback = aHandleEventFunction; + + if( mParent) + mParent->AddChild( this); + + // call the event callback to notify about creation + DispatchStandardEvent( NS_CREATE); + SubclassWindow( PR_TRUE); + PostCreateWidget(); +} + +// How destruction works: A call of Destroy() destroys the PM window. This +// triggers an OnDestroy(), which frees resources. If not Destroy'd at +// delete time, Destroy() gets called anyway. + +// NOTE: Calling virtual functions from destructors is bad; they always bind +// in the current object (ie. as if they weren't virtual). It may even +// be illegal to call them from here. +// +nsWindow::~nsWindow() +{ + // If the widget was released without calling Destroy() then the native + // window still exists, and we need to destroy it. + if( mWindowState != nsWindowState_eDead) + { + mWindowState = nsWindowState_eDoingDelete; + if( mWnd); + Destroy(); + } +} + +// Close this nsWindow +nsresult nsWindow::Destroy() +{ + // Switch to the PM thread if necessary... + if( mToolkit && !mOS2Toolkit->IsPMThread()) + { + MethodInfo info( this, nsWindow::W_DESTROY); + mOS2Toolkit->CallMethod( &info); + } + else + { + // avoid calling into other objects if we're being deleted, 'cos + // they must have no references to us. + if( mWindowState == nsWindowState_eLive && mParent) + nsBaseWidget::Destroy(); + + if( mWnd) + WinDestroyWindow( mHackDestroyWnd ? mHackDestroyWnd : mWnd); + } + return NS_OK; +} + +// WM_DESTROY has been received +void nsWindow::OnDestroy() +{ + SubclassWindow( PR_FALSE); + mWnd = 0; + + // if we were in the middle of deferred window positioning then free up + if( mSWPs) free( mSWPs); + mSWPs = 0; + mlHave = mlUsed = 0; + + // release any ps (erm, probably an error if this is necessary) + if( mPS) + WinReleasePS( mPS); + mPS = 0; + + // release references to context, toolkit, appshell, children + nsBaseWidget::OnDestroy(); + + // kill font + delete mFont; + + // release menubar + NS_IF_RELEASE(mMenuBar); + + // dispatching of the event may cause the reference count to drop to 0 + // and result in this object being deleted. To avoid that, add a + // reference and then release it after dispatching the event. + // + // It's important *not* to do this if we're being called from the + // destructor -- this would result in our destructor being called *again* + // from the Release() below. This is very bad... + if( nsWindowState_eDoingDelete != mWindowState) + { + AddRef(); + DispatchStandardEvent( NS_DESTROY); + Release(); + } + + // dead widget + mWindowState = nsWindowState_eDead; +} + +// -------------------------------------------------------------------------- +// PM messaging layer - wndproc, subclasser, default handler ---------------- + +// the nsWindow procedure for all nsWindows in this toolkit +MRESULT EXPENTRY fnwpNSWindow( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + // Get the nsWindow for this hwnd + nsWindow *wnd = NS_HWNDToWindow( hwnd); + + // Messages which get re-routed if their source was an nsWindow + // (it's very bad to reroute messages whose source isn't an nsWindow, + // listboxes with scrollbars for example would break) + switch( msg) + { + case WM_CONTROL: + case WM_HSCROLL: + case WM_VSCROLL: // !! potential problems here if canvas children + { + // assume parent == owner, true for our creations + HWND hwndChild = WinWindowFromID( hwnd, SHORT1FROMMP( mp1)); + if( hwndChild) + { + nsWindow *w = NS_HWNDToWindow( hwndChild); + if( w) + wnd = w; + } + break; + } + } + + MRESULT mRC = 0; + + if( wnd) + { + BOOL bPreHandling = g_bHandlingMouseClick; + if( PR_FALSE == wnd->ProcessMessage( msg, mp1, mp2, mRC) && + wnd->GetPrevWP()) + { + mRC = (wnd->GetPrevWP())( hwnd, msg, mp1, mp2); + + } + if( !bPreHandling) + g_bHandlingMouseClick = FALSE; + } + else + /* erm */ mRC = WinDefWindowProc( hwnd, msg, mp1, mp2); + + return mRC; +} + +// Subclass (or remove the subclass) +void nsWindow::SubclassWindow( PRBool bState) +{ + NS_PRECONDITION(WinIsWindow( 0/*hab*/, mWnd), "Invalid window handle"); + + if( PR_TRUE == bState) + { + mFnWP = WinSubclassWindow( mWnd, fnwpNSWindow); + // connect the this pointer to the window handle + nsWindow *pWin = this; // learn something new about C++ every day... + WinSetPresParam( mWnd, gModuleData.ppMozilla, sizeof pWin, &pWin); + } + else + { + WinSubclassWindow( mWnd, mFnWP); + WinRemovePresParam( mWnd, gModuleData.ppMozilla); + mFnWP = nsnull; + } +} + +// 'Window procedure' +PRBool nsWindow::ProcessMessage( ULONG msg, MPARAM mp1, MPARAM mp2, MRESULT &rc) +{ + PRBool result = PR_FALSE; // call the default window procedure + + switch( msg) + { + case WM_COMMAND: // fire off menu selections + { + USHORT usSrc = SHORT1FROMMP( mp2); + if( usSrc == CMDSRC_MENU || usSrc == CMDSRC_ACCELERATOR) + result = OnMenuClick( SHORT1FROMMP(mp1)); + break; + } + + case WM_INITMENU: + result = OnActivateMenu( HWNDFROMMP(mp2), TRUE); + break; + + case WM_MENUEND: + result = OnActivateMenu( HWNDFROMMP(mp2), FALSE); + break; + + case WMU_SHOW_TOOLTIP: + { + nsTooltipEvent event; + InitEvent( event, NS_SHOW_TOOLTIP); + event.tipIndex = LONGFROMMP(mp1); + event.eventStructType = NS_TOOLTIP_EVENT; + result = DispatchEventInternal(&event); + break; + } + + case WMU_HIDE_TOOLTIP: + result = DispatchStandardEvent( NS_HIDE_TOOLTIP); + break; + + case WM_CONTROL: // remember this is resent to the orginator... + result = OnControl( mp1, mp2); + break; + + case WM_HSCROLL: + case WM_VSCROLL: + result = OnScroll( mp1, mp2); + break; + + case WM_DESTROY: // clean up object + OnDestroy(); + break; + + case WM_CLOSE: + { + // for now... eventually there'll be an nsIFrameWindow which will + // generate 'close' events which will be veto-able. Hopefully. + // (that'll be `re-write the hierarchy' time for us...) + Destroy(); + result = PR_TRUE; + break; + } + + case WM_PAINT: + result = OnPaint(); + break; + + case WM_CHAR: + result = OnKey( mp1, mp2); + break; + + // Mouseclicks: we don't dispatch CLICK events because they just cause + // trouble: gecko seems to expect EITHER buttondown/up OR click events + // and so that's what we give it. + // + // Plus we make WM_CHORD do a button3down in order to get warp-4 paste + // behaviour (see nsEditorEventListeners.cpp) + + case WM_BUTTON1DOWN: + result = DispatchMouseEvent( NS_MOUSE_LEFT_BUTTON_DOWN, 1, mp1, mp2); + break; + case WM_BUTTON1UP: + result = DispatchMouseEvent( NS_MOUSE_LEFT_BUTTON_UP, 1, mp1, mp2); + break; + case WM_BUTTON1DBLCLK: + result = DispatchMouseEvent( NS_MOUSE_LEFT_DOUBLECLICK, 2, mp1, mp2); + break; + + case WM_BUTTON2DOWN: + result = DispatchMouseEvent( NS_MOUSE_RIGHT_BUTTON_DOWN, 1, mp1, mp2); + break; + case WM_BUTTON2UP: + result = DispatchMouseEvent( NS_MOUSE_RIGHT_BUTTON_UP, 1, mp1, mp2); + break; + case WM_BUTTON2DBLCLK: + result = DispatchMouseEvent( NS_MOUSE_RIGHT_DOUBLECLICK, 2, mp1, mp2); + break; + + case WM_CHORD: + result = DispatchMouseEvent( 0, 1, mp1, mp2); + break; + case WM_BUTTON3DOWN: + result = DispatchMouseEvent( NS_MOUSE_MIDDLE_BUTTON_DOWN, 1, mp1, mp2); + break; + case WM_BUTTON3UP: + result = DispatchMouseEvent( NS_MOUSE_MIDDLE_BUTTON_UP, 1, mp1, mp2); + break; + case WM_BUTTON3DBLCLK: + result = DispatchMouseEvent( NS_MOUSE_MIDDLE_DOUBLECLICK, 2, mp1, mp2); + break; + + case WM_MOUSEMOVE: + result = DispatchMouseEvent( NS_MOUSE_MOVE, 0, mp1, mp2); + break; + case WMU_MOUSEENTER: + result = DispatchMouseEvent( NS_MOUSE_ENTER, 0, mp1, mp2); + break; + case WMU_MOUSELEAVE: + result = DispatchMouseEvent( NS_MOUSE_EXIT, 0, mp1, mp2); + break; + + case WM_SETFOCUS: + result = DispatchStandardEvent( SHORT1FROMMP( mp2) ? NS_GOTFOCUS + : NS_LOSTFOCUS); + break; + + case WM_WINDOWPOSCHANGED: + result = OnReposition( (PSWP) mp1); + break; + + + case WM_REALIZEPALETTE: // hopefully only nsCanvas & nsFrame + result = OnRealizePalette(); // will need this + break; + + case WM_PRESPARAMCHANGED: + // This is really for font-change notifies. Do that first. + rc = GetPrevWP()( mWnd, msg, mp1, mp2); + OnPresParamChanged( mp1, mp2); + result = PR_TRUE; + break; + + case DM_DRAGOVER: + result = OnDragOver( mp1, mp2, rc); + break; + + case DM_DRAGLEAVE: + result = OnDragLeave( mp1, mp2); + break; + + case DM_DROP: + result = OnDrop( mp1, mp2); + break; + + // Need to handle this method in order to keep track of whether there + // is a drag inside the window; we need to do *this* so that we can + // generate DRAGENTER messages [which os/2 doesn't provide]. + case DM_DROPHELP: + mDragInside = FALSE; + break; + } + + return result; +} + +// -------------------------------------------------------------------------- +// Local methods to dispatch NS events -------------------------------------- + +// Convert nsEventStatus value to a ProcessEvents() return code +PRBool nsWindow::ConvertStatus( nsEventStatus aStatus) +{ + PRBool rc = PR_FALSE; + + switch( aStatus) + { + case nsEventStatus_eIgnore: + case nsEventStatus_eConsumeDoDefault: + break; + case nsEventStatus_eConsumeNoDefault: + rc = PR_TRUE; + break; + default: + NS_ASSERTION(0, "Illegal nsEventStatus enumeration value"); + break; + } + + return rc; +} + +// Initialize an event pre-dispatch +void nsWindow::InitEvent( nsGUIEvent &event, PRUint32 aEventType, nsPoint *pt) +{ + event.widget = this; + event.nativeMsg = nsnull; + + if( !pt) + { + // get the message position in client coordinates + POINTL ptl; + WinQueryMsgPos( 0/*hab*/, &ptl); + WinMapWindowPoints( HWND_DESKTOP, mWnd, &ptl, 1); + PM2NS( ptl); + + event.point.x = ptl.x; + event.point.y = ptl.y; + } + else + { + event.point.x = pt->x; + event.point.y = pt->y; + } + + event.time = WinQueryMsgTime( 0/*hab*/); + event.message = aEventType; +} + +// Invokes callback and ProcessEvent method on Event Listener object +PRBool nsWindow::DispatchEventInternal( nsGUIEvent *event) +{ + PRBool result = PR_FALSE; + + nsEventStatus status; + DispatchEvent( event, status); + result = ConvertStatus( status); + + return result; +} + +// NOTE that this is now part of the nsIWidget interface... +NS_IMETHODIMP nsWindow::DispatchEvent( nsGUIEvent *event, + nsEventStatus &aStatus) +{ + aStatus = nsEventStatus_eIgnore; + + // Filters: if state is eInCreate, only send out NS_CREATE + // if state is eDoingDelete, don't send out anything because, + // well, the object's being deleted... + if( (mWindowState == nsWindowState_eInCreate && event->message == NS_CREATE) + || (mWindowState == nsWindowState_eLive)) + { + if( mEventCallback) + aStatus = (*mEventCallback)( event); + + // Dispatch to event listener if event was not consumed + if( (aStatus != nsEventStatus_eIgnore) && mEventListener) + aStatus = mEventListener->ProcessEvent(*event); + } + + return NS_OK; +} + + +// Dispatch a standard event +PRBool nsWindow::DispatchStandardEvent( PRUint32 aMsg, PRUint8 aEST) +{ + nsGUIEvent event; + event.eventStructType = aEST; + InitEvent( event, aMsg); + return DispatchEventInternal( &event); +} + +// Deal with all sort of mouse event +PRBool nsWindow::DispatchMouseEvent( PRUint32 msg, int clickcount, + MPARAM mp1, MPARAM mp2) +{ + PRBool result = PR_FALSE; + + if( !mEventCallback && !mMouseListener) + return result; + + // Stop multiple messages for the same PM action + if( g_bHandlingMouseClick) + return result; + + nsMouseEvent event; + event.eventStructType = NS_MOUSE_EVENT; + event.clickCount = clickcount; + + // Mouse leave & enter messages don't seem to have position built in. + if( msg && msg != NS_MOUSE_ENTER && msg != NS_MOUSE_EXIT) + { + POINTL ptl = { SHORT1FROMMP( mp1), SHORT2FROMMP( mp1) }; + PM2NS( ptl); + nsPoint pt( ptl.x, ptl.y); + InitEvent( event, msg, &pt); + + USHORT usFlags = SHORT2FROMMP( mp2); + event.isShift = (usFlags & KC_SHIFT) ? PR_TRUE : PR_FALSE; + event.isControl = (usFlags & KC_CTRL) ? PR_TRUE : PR_FALSE; + event.isAlt = (usFlags & KC_ALT) ? PR_TRUE : PR_FALSE; + } + else + { + if( !msg) msg = NS_MOUSE_MIDDLE_BUTTON_DOWN; // WM_CHORD hack + + InitEvent( event, msg, nsnull); + event.isShift = WinIsKeyDown( VK_SHIFT); + event.isControl = WinIsKeyDown( VK_CTRL); + event.isAlt = WinIsKeyDown( VK_ALT) || WinIsKeyDown( VK_ALTGRAF); + } + + // call the listeners + if( mMouseListener) + switch( msg) + { + case NS_MOUSE_MOVE: + result = ConvertStatus( mMouseListener->MouseMoved( event)); + break; + + case NS_MOUSE_LEFT_BUTTON_DOWN: + case NS_MOUSE_MIDDLE_BUTTON_DOWN: + case NS_MOUSE_RIGHT_BUTTON_DOWN: + result = ConvertStatus( mMouseListener->MousePressed( event)); + break; + + case NS_MOUSE_LEFT_BUTTON_UP: + case NS_MOUSE_MIDDLE_BUTTON_UP: + case NS_MOUSE_RIGHT_BUTTON_UP: + result = ConvertStatus( mMouseListener->MouseReleased( event)); + break; + + case NS_MOUSE_LEFT_CLICK: + case NS_MOUSE_MIDDLE_CLICK: + case NS_MOUSE_RIGHT_CLICK: + result = ConvertStatus( mMouseListener->MouseClicked( event)); + break; + } + else + result = DispatchEventInternal( &event); + + + g_bHandlingMouseClick = TRUE; + + return result; +} + +// -------------------------------------------------------------------------- +// Overridable OnMessage() methods ------------------------------------------ + +// Key handler. Specs for the various text messages are really confused; +// see other platforms for best results of how things are supposed to work. +// +// Perhaps more importantly, the main man listening to these events (besides +// random bits of javascript) is ender -- see +// mozilla/editor/base/nsEditorEventListeners.cpp. +// +PRBool nsWindow::OnKey( MPARAM mp1, MPARAM mp2) +{ + nsKeyEvent event; + USHORT fsFlags = SHORT1FROMMP(mp1); + USHORT usVKey = SHORT2FROMMP(mp2); + UCHAR uchScan = CHAR4FROMMP(mp1); + int unirc = ULS_SUCCESS; + + // It appears we're not supposed to transmit shift, control & alt events + // to gecko. Shrug. + // + // XXX this may be wrong, but is what gtk is doing... + if( fsFlags & KC_VIRTUALKEY && + (usVKey == VK_SHIFT || usVKey == VK_CTRL || + usVKey == VK_ALT || usVKey == VK_ALTGRAF)) return PR_FALSE; + + // Now check if it's a dead-key + if( fsFlags & KC_DEADKEY) + { + UniChar tmp; + unirc = gModuleData.TranslateKey( uchScan, &tmp, &mDeadKey); + if( unirc == ULS_SUCCESS) + mHaveDeadKey = TRUE; + else + printf( "Couldn't translate dead key\n"); + + // XXX CUA says we're supposed to give some kind of feedback `display the + // dead key glyph'. I'm not sure if we can use the COMPOSE messages + // to do this -- it should really be done by someone who can test it + // & has some idea what `ought' to happen... + + return PR_TRUE; + } + + // Now dispatch a keyup/keydown event. This one is *not* meant to + // have the unicode charcode in. + + InitEvent( event, (fsFlags & KC_KEYUP) ? NS_KEY_UP : NS_KEY_DOWN); + event.keyCode = WMChar2KeyCode( mp1, mp2); + event.isShift = (fsFlags & KC_SHIFT) ? PR_TRUE : PR_FALSE; + event.isControl = (fsFlags & KC_CTRL) ? PR_TRUE : PR_FALSE; + event.isAlt = (fsFlags & KC_ALT) ? PR_TRUE : PR_FALSE; + event.eventStructType = NS_KEY_EVENT; + event.charCode = 0; + + PRBool rc = DispatchEventInternal( &event); + + // Break off now if this was a key-up. + if( fsFlags & KC_KEYUP) return rc; + + // Break off if we've got an "invalid composition" -- that is, the user + // typed a deadkey last time, but has now typed something that doesn't + // make sense in that context. + if( fsFlags & KC_INVALIDCOMP) + { + mHaveDeadKey = FALSE; + // XXX actually, not sure whether we're supposed to abort the keypress + // or process it as though the dead key has been pressed. + return rc; + } + + // Now we need to dispatch a keypress event which has the unicode char. + // + // Only send keypress events for characters which create textual input. + // + if( !(fsFlags & (KC_CHAR | KC_COMPOSITE))) + return rc; + + event.message = NS_KEY_PRESS; + + VDKEY vdkeyTmp; + unirc = gModuleData.TranslateKey( uchScan, (UniChar*) &event.charCode, + &vdkeyTmp); + + if( mHaveDeadKey && (fsFlags & KC_COMPOSITE) && unirc == ULS_SUCCESS) + { + unirc = UniTranslateDeadkey( gModuleData.hKeyboard, + &mDeadKey, + (UniChar) event.charCode, + (UniChar*) &event.charCode, + &mDeadKey); + mHaveDeadKey = FALSE; + } + + if( unirc != ULS_SUCCESS) + { + printf( "UniTranslate[Dead]Key returned %d\n", unirc); + event.charCode = CHAR2FROMMP(mp2); + } + + return DispatchEventInternal( &event); +} + +PRBool nsWindow::OnReposition( PSWP pSwp) +{ + PRBool result = PR_FALSE; + + if( pSwp->fl & SWP_MOVE && !(pSwp->fl & SWP_MINIMIZE)) + { + // need screen coords. + POINTL ptl = { pSwp->x, pSwp->y + pSwp->cy - 1 }; + PM2NS_PARENT( ptl); + mBounds.x = ptl.x; + mBounds.y = ptl.y; + + WinMapWindowPoints( GetParentHWND(), HWND_DESKTOP, &ptl, 1); + result = OnMove( ptl.x, ptl.y); + } + if( pSwp->fl & SWP_SIZE && !(pSwp->fl & SWP_MINIMIZE)) + result = OnResize( pSwp->cx, pSwp->cy); + + return result; +} + +// Params here are in XP-space for the desktop +PRBool nsWindow::OnMove( PRInt32 aX, PRInt32 aY) +{ + nsGUIEvent event; + InitEvent( event, NS_MOVE); + event.point.x = aX; + event.point.y = aY; + event.eventStructType = NS_GUI_EVENT; + return DispatchEventInternal( &event); +} + +PRBool nsWindow::OnPaint() +{ + return PR_FALSE; +} + +PRBool nsWindow::OnResize( PRInt32 aX, PRInt32 aY) +{ + mBounds.width = aX; + mBounds.height = aY; + return DispatchResizeEvent( aX, aY); +} + +PRBool nsWindow::DispatchResizeEvent( PRInt32 aX, PRInt32 aY) +{ + // call the event callback + nsSizeEvent event; + nsRect rect( 0, 0, aX, aY); + + InitEvent( event, NS_SIZE); + event.eventStructType = NS_SIZE_EVENT; + event.windowSize = ▭ // this is the *client* rectangle + event.mWinWidth = mBounds.width; + event.mWinHeight = mBounds.height; + + return DispatchEventInternal( &event); +} + +PRBool nsWindow::OnScroll( MPARAM mp1, MPARAM mp2) +{ + return PR_FALSE; +} + +PRBool nsWindow::OnRealizePalette() +{ + return PR_FALSE; +} + +PRBool nsWindow::OnPresParamChanged( MPARAM mp1, MPARAM mp2) +{ + return PR_FALSE; +} + +// This is necessary because notification codes are defined from 1 for each +// control: thus we cannot tell the difference between an EN_SELECT and +// a TABN_SELECT, etc. +// So delegate to those classes who actually want to handle the thing. +PRBool nsWindow::OnControl( MPARAM mp1, MPARAM mp2) +{ + return PR_TRUE; // default to speed things up a bit... +} + +// -------------------------------------------------------------------------- +// Menus -------------------------------------------------------------------- + +// wm_commands generated from menus +// XXX should this only be in nsFrameWindow? +// Probably worth trying for abstraction reasons. +// +PRBool nsWindow::OnMenuClick( USHORT aCmd) +{ + PRBool result = PR_TRUE; + + // find if this is a menuitem being clicked or a submenu + // (actually I don't think submenu items generate wm_commands...) + MENUITEM mI = { 0 }; + +#ifdef SUPPORT_NON_XPFE + if( mMenuBar || mActiveMenu) +#endif + { + void *hwndMenu = 0; + // context menu takes precedence over menubar + if( mActiveMenu) + { + mActiveMenu->GetNativeData( &hwndMenu); + mActiveMenu = 0; // now forget it + } + else + mMenuBar->GetNativeData( hwndMenu); + + mOS2Toolkit->SendMsg( (HWND) hwndMenu, MM_QUERYITEM, + MPFROM2SHORT(aCmd,TRUE), MPFROMP(&mI)); + } + + if( !(mI.afStyle & MIS_SUBMENU)) + { + // Find the nsIMenuItem for this selection + nsISupports *aThing = (nsISupports*) mI.hItem; + nsIMenuItem *aItem = nsnull; + nsIMenuListener *aListener = nsnull; + +#ifndef SUPPORT_NON_XPFE + NS_ASSERTION( aThing, "Disconnected menuitem"); +#else + // viewer.exe uses pure native menus, and so aThing will be null there. + if( aThing) +#endif + { + aThing->QueryInterface( nsIMenuItem::GetIID(), + (void**) &aItem); + } + + // Fill out a menu event + nsMenuEvent event; + event.eventStructType = NS_MENU_EVENT; + InitEvent(event, NS_MENU_SELECTED); + event.mMenuItem = aItem; + +#ifdef SUPPORT_NON_XPFE + if( !aItem) + event.mCommand = aCmd; + else +#endif + aItem->GetCommand( event.mCommand); + +#ifdef SUPPORT_NON_XPFE + // Notify those interested + result = DispatchEventInternal( &event); // XXX just for viewer.exe + + if( aThing) +#endif + { + aThing->QueryInterface( nsIMenuListener::GetIID(), + (void**) &aListener); + result = ConvertStatus( aListener->MenuItemSelected( event)); + } + + // Clean up + NS_IF_RELEASE(aItem); + NS_IF_RELEASE(aListener); + } + + return result; +} + +PRBool nsWindow::OnActivateMenu( HWND hwndMenu, BOOL aActivate) +{ + nsMenuBase *pBase = (nsMenuBase*) WinQueryWindowPtr( hwndMenu, QWL_USER); + PRBool result = PR_FALSE; + + if( nsnull != pBase) + { + nsMenu *aMenu = (nsMenu*) pBase; // XXX yeargh + + // Fill out a menu event + nsMenuEvent event; + event.eventStructType = NS_MENU_EVENT; + // even if this is a deselect, same event type. + InitEvent( event, NS_MENU_SELECTED); + event.mMenuItem = nsnull; // XXX I guess + event.mCommand = 0; // XXX I guess + +#ifdef SUPPORT_NON_XPFE + // not sure if this is necessary, but can't do any harm. + DispatchEventInternal( &event); +#endif + + // dispatch to listener + nsEventStatus es; + if( aActivate) + es = aMenu->MenuSelected( event); + else + es = aMenu->MenuDeselected( event); + + result = ConvertStatus( es); + } + + return result; +} + +// (there needs to be a distinct nsTopLevelWindow class) +nsresult nsWindow::SetMenuBar( nsIMenuBar *aMenuBar) +{ + NS_IF_RELEASE(mMenuBar); + mMenuBar = aMenuBar; + NS_ADDREF(mMenuBar); + + return NS_OK; +} + +nsresult nsWindow::ShowMenuBar( PRBool bShow) +{ + if( mMenuBar) + { + HWND hwndMenu = 0; + mMenuBar->GetNativeData( (void*&)hwndMenu); + if( WinIsWindowVisible(hwndMenu) != (BOOL)bShow) + { + WinSetWindowUShort( mWnd, QWS_ID, bShow ? FID_MENU : 0); + mOS2Toolkit->SendMsg( GetMainWindow(), WM_UPDATEFRAME, + MPFROMLONG(FCF_MENU)); + } + } + + return NS_OK; +} + +nsresult nsWindow::IsMenuBarVisible( PRBool *aVisible) +{ + if( !aVisible) + return NS_ERROR_NULL_POINTER; + + *aVisible = PR_FALSE; + + if( mMenuBar) + { + void *hwndMenu = 0; + mMenuBar->GetNativeData( hwndMenu); + *aVisible = WinIsWindowVisible( (HWND)hwndMenu); + } + + return NS_OK; +} + +void nsWindow::SetContextMenu( nsContextMenu *aMenu) +{ + mActiveMenu = aMenu; +} + +// -------------------------------------------------------------------------- +// Hierarchy - children & parent -------------------------------------------- + +// We keep a pointer to our parent because we need parent a lot for doing +// positioning things. We don't hold a reference to it, though. This should +// be okay 'cos there's no scope for reparenting in this library and we +// can't live longer than it. + +// First, nsIWidget methods +nsIWidget* nsWindow::GetParent() +{ + nsWindow *widget = nsnull; + if( nsnull != mParent) + { + NS_ADDREF(mParent); + widget = mParent; + } + + return widget; +} + +// Now, OS/2 methods +HWND nsWindow::GetParentHWND() const +{ + HWND hwnd = 0; + if( nsnull != mParent) + hwnd = mParent->mWnd; + else + hwnd = WinQueryWindow( GetMainWindow(), QW_PARENT); + return hwnd; +} + +// ptl is in parent's space +void nsWindow::NS2PM_PARENT( POINTL &ptl) +{ + if( mParent) + mParent->NS2PM( ptl); + else + { + HWND hwndp = WinQueryWindow( GetMainWindow(), QW_PARENT); + SWP swp = { 0 }; + WinQueryWindowPos( hwndp, &swp); + ptl.y = swp.cy - ptl.y - 1; + } +} + +// ptl is in this window's space +void nsWindow::NS2PM( POINTL &ptl) +{ + ptl.y = GetClientHeight() - ptl.y - 1; +} + +// -------------------------------------------------------------------------- +// Physical properties - size, position, visibility + +// Hide or show this window +nsresult nsWindow::Show( PRBool bState) +{ + // doesn't seem to require a message queue. + if( mWnd) + WinShowWindow( GetMainWindow(), !!bState); + + return NS_OK; +} + +// Move this component (WinSetWindowPos() appears not to require a msgq) +nsresult nsWindow::Move( PRUint32 aX, PRUint32 aY) +{ + Resize( aX, aY, mBounds.width, mBounds.height, PR_FALSE); + return NS_OK; +} + +// Resize this component: need to keep top-left corner in the same place +nsresult nsWindow::Resize( PRUint32 aWidth, PRUint32 aHeight, PRBool aRepaint) +{ + Resize( mBounds.x, mBounds.y, aWidth, aHeight, aRepaint); + return NS_OK; +} + +// Resize this component +nsresult nsWindow::Resize( PRUint32 aX, PRUint32 aY, PRUint32 w, PRUint32 h, + PRBool aRepaint) +{ + if( mWnd) + { + // work out real coords of top left + POINTL ptl= { aX, aY }; + NS2PM_PARENT( ptl); + // work out real coords of bottom left + ptl.y -= GetHeight( h) - 1; + + if( !SetWindowPos( 0, ptl.x, ptl.y, w, GetHeight(h), SWP_MOVE | SWP_SIZE)) + if( aRepaint) + Update(); + } + else + { + mBounds.x = aX; + mBounds.y = aY; + mBounds.width = w; + mBounds.height = h; + } + + return NS_OK; +} + +BOOL nsWindow::SetWindowPos( HWND ib, long x, long y, long cx, long cy, ULONG flags) +{ + BOOL bDeferred = FALSE; + + if( mParent && mParent->mSWPs) // XXX bit implicit... + { + mParent->DeferPosition( GetMainWindow(), ib, x, y, cx, cy, flags); + bDeferred = TRUE; + } + else // WinSetWindowPos appears not to need msgq (hmm) + WinSetWindowPos( GetMainWindow(), ib, x, y, cx, cy, GetSWPFlags(flags)); + + // When the window is actually sized, mBounds will be updated in the fnwp. + + return bDeferred; +} + +// Enable/disable this window +nsresult nsWindow::Enable( PRBool bState) +{ + if( mWnd) + WinEnableWindow( GetMainWindow(), !!bState); + return NS_OK; +} + +// Give the focus to this component +nsresult nsWindow::SetFocus() +{ + // Switch to the PM thread if necessary... + if( !mOS2Toolkit->IsPMThread()) + { + MethodInfo info(this, nsWindow::W_SET_FOCUS); + mOS2Toolkit->CallMethod(&info); + } + else if( mWnd) + WinSetFocus( HWND_DESKTOP, mWnd); + return NS_OK; +} + +nsresult nsWindow::IsVisible( PRBool &aState) +{ + // I guess this means visible & not showing... + BOOL b = WinIsWindowVisible( mWnd); + aState = b ? PR_TRUE : PR_FALSE; + return NS_OK; +} + +// nsFrameWindow overrides this... +nsresult nsWindow::GetClientBounds( nsRect &aRect) +{ + aRect.x = 0; + aRect.y = 0; + aRect.width = mBounds.width; + aRect.height = mBounds.height; + return NS_OK; +} + +// We don' wan' no steekin' borda! +nsresult nsWindow::GetBorderSize( PRInt32 &aWidth, PRInt32 &aHeight) +{ + aWidth = 0; + aHeight = 0; + return NS_OK; +} + +// Preferred size; default here. +nsresult nsWindow::GetPreferredSize( PRInt32 &aWidth, PRInt32 &aHeight) +{ + aWidth = mPreferredWidth; + aHeight = mPreferredHeight; + return NS_OK; +} + +nsresult nsWindow::SetPreferredSize( PRInt32 aWidth, PRInt32 aHeight) +{ + mPreferredWidth = aWidth; + mPreferredHeight = aHeight; + return NS_OK; +} + +// Deferred window positioning +nsresult nsWindow::BeginResizingChildren() +{ + if( !mSWPs) + { + mlHave = 10; + mlUsed = 0; + mSWPs = (PSWP) malloc( 10 * sizeof( SWP)); + } + return NS_OK; +} + +void nsWindow::DeferPosition( HWND hwnd, HWND hwndInsertBehind, + long x, long y, long cx, long cy, ULONG flags) +{ + if( mSWPs) + { + if( mlHave == mlUsed) // need more swps + { + mlHave += 10; + mSWPs = (PSWP) realloc( mSWPs, mlHave * sizeof( SWP)); + } + mSWPs[ mlUsed].hwnd = hwnd; + mSWPs[ mlUsed].hwndInsertBehind = hwndInsertBehind; + mSWPs[ mlUsed].x = x; + mSWPs[ mlUsed].y = y; + mSWPs[ mlUsed].cx = cx; + mSWPs[ mlUsed].cy = cy; + mSWPs[ mlUsed].fl = flags; + mSWPs[ mlUsed].ulReserved1 = 0; + mSWPs[ mlUsed].ulReserved2 = 0; + mlUsed++; + } +} + +nsresult nsWindow::EndResizingChildren() +{ + if( nsnull != mSWPs) + { + WinSetMultWindowPos( 0/*hab*/, mSWPs, mlUsed); + free( mSWPs); + mSWPs = nsnull; + mlUsed = mlHave = 0; + } + return NS_OK; +} + +// Screen <--> window coordinate conversion +nsresult nsWindow::WidgetToScreen( const nsRect &aOldRect, nsRect &aNewRect) +{ + POINTL pt = { aOldRect.x, aOldRect.y }; + NS2PM( pt); + + WinMapWindowPoints( mWnd, HWND_DESKTOP, &pt, 1); + + aNewRect.x = pt.x; + aNewRect.y = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN) - pt.y - 1; + aNewRect.width = aOldRect.width; + aNewRect.height = aOldRect.height; + return NS_OK; +} + +nsresult nsWindow::ScreenToWidget( const nsRect &aOldRect, nsRect &aNewRect) +{ + POINTL pt = { aOldRect.x, + WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN) - aOldRect.y - 1 }; + WinMapWindowPoints( HWND_DESKTOP, mWnd, &pt, 1); + + PM2NS( pt); + + aNewRect.x = pt.x; + aNewRect.y = pt.y; + aNewRect.width = aOldRect.width; + aNewRect.height = aOldRect.height; + return NS_OK; +} + +// -------------------------------------------------------------------------- +// Colours, fonts, painting ------------------------------------------------- + +nsresult nsWindow::Paint( nsIRenderingContext &aRenderingContext, + const nsRect &aDirtyRect) +{ + printf( "Yikes - nsWindow::Paint called. Run for the hills...\n"); +#if 0 // XXX This is thankfully done in XP-land now. + // Get a proxy window + HWND hwndProxy = gModuleData.GetWindowForPrinting( WindowClass(), + WindowStyle()); + + // Size it correctly + WinSetWindowPos( hwndProxy, HWND_TOP, 0, 0, mBounds.width, mBounds.height, + SWP_SIZE | SWP_ZORDER); + + // Set pres-params: colors.. + + // ..and font + + // Subclass specific bits + SetupForPrint( hwndProxy); + + // now get a HPS from the rc & do the WM_DRAW thing + // (via drawingsurface, QI/cast) +#endif + + return NS_OK; +} + +nscolor nsWindow::QueryPresParam( ULONG ppID) +{ + nscolor col = 0; + RGB2 rgb; + ULONG found = 0; + + WinQueryPresParam( mWnd, ppID, 0, &found, + sizeof( RGB2), &rgb, QPF_PURERGBCOLOR); + + if( found == ppID) + col = NS_RGB( rgb.bRed, rgb.bGreen, rgb.bBlue); + return col; +} + +void nsWindow::SetPresParam( ULONG ppID, const nscolor &c) +{ + RGB2 rgb = { NS_GET_B( c), NS_GET_G( c), NS_GET_R( c), 0 }; + WinSetPresParam( mWnd, ppID, sizeof( RGB2), &rgb); +} + +nscolor nsWindow::GetForegroundColor() +{ + return (mWnd ? QueryPresParam( PP_FOREGROUNDCOLOR) : mForeground); +} + +nsresult nsWindow::SetForegroundColor( const nscolor &aColor) +{ + if( mWnd) + SetPresParam( PP_FOREGROUNDCOLOR, aColor); + mForeground = aColor; + + return NS_OK; +} + +nscolor nsWindow::GetBackgroundColor() +{ + return (mWnd ? QueryPresParam( PP_BACKGROUNDCOLOR) : mBackground); +} + +nsresult nsWindow::SetBackgroundColor(const nscolor &aColor) +{ + if( mWnd) + SetPresParam( PP_BACKGROUNDCOLOR, aColor); + mBackground = aColor; + return NS_OK; +} + +// Well this should be interesting... +nsIFontMetrics *nsWindow::GetFont() +{ + nsIFontMetrics *metrics = nsnull; + + if( mToolkit) + { + char buf[2][128]; + int ptSize; + + WinQueryPresParam( mWnd, PP_FONTNAMESIZE, 0, 0, 128, buf[0], 0); + + if( 2 == sscanf( buf[0], "%d.%s", &ptSize, buf[1])) // mmm, scanf()... + { + float twip2dev, twip2app; + mContext->GetTwipsToDevUnits( twip2dev); + mContext->GetDevUnitsToAppUnits( twip2app); + twip2app *= twip2dev; + + nscoord appSize = (nscoord) (twip2app * ptSize * 20); + + nsFont font( buf[1], NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL, + NS_FONT_WEIGHT_NORMAL, 0 /*decoration*/, appSize); + + mContext->GetMetricsFor( font, metrics); + } + } + + return metrics; +} + +nsresult nsWindow::SetFont( const nsFont &aFont) +{ + if( mToolkit) // called from print-routine (XXX check) + { + const char *fontname = gModuleData.ConvertFromUcs( aFont.name); + + // jump through hoops to convert the size in the font (in app units) + // into points. + float dev2twip, app2twip; + mContext->GetDevUnitsToTwips( dev2twip); + mContext->GetAppUnitsToDevUnits( app2twip); + app2twip *= dev2twip; + + int points = NSTwipsToFloorIntPoints( nscoord( aFont.size * app2twip)); + + char *buffer = new char [ strlen( fontname) + 6]; + sprintf( buffer, "%d.%s", points, fontname); + + BOOL rc = WinSetPresParam( mWnd, PP_FONTNAMESIZE, + strlen( buffer) + 1, buffer); + if( !rc) + printf( "WinSetPresParam PP_FONTNAMESIZE %s failed\n", buffer); + + delete [] buffer; + } + + if( !mFont) + mFont = new nsFont( aFont); + else + *mFont = aFont; + + return NS_OK; +} + +// SetColorMap - not implemented. +// Any palette lives in the device context & should be altered there. +// And shouldn't be altered at all, once libimg has decided what should +// be in it. So my opinion is this method shouldn't be called. +nsresult nsWindow::SetColorMap( nsColorMap *aColorMap) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +// Cursor - more bizarre types not implemented yet + +nsresult nsWindow::SetCursor( nsCursor aCursor) +{ + ULONG sptr = 0; + switch( aCursor) + { + // builtins + case eCursor_select: sptr = SPTR_TEXT; break; + case eCursor_wait: sptr = SPTR_WAIT; break; + case eCursor_sizeWE: sptr = SPTR_SIZEWE; break; + case eCursor_sizeNS: sptr = SPTR_SIZENS; break; + case eCursor_standard: sptr = SPTR_ARROW; break; + // custom + case eCursor_hyperlink: + case eCursor_arrow_west_plus: + case eCursor_arrow_west: + case eCursor_arrow_east_plus: + case eCursor_arrow_east: + case eCursor_arrow_south_plus: + case eCursor_arrow_south: + case eCursor_arrow_north: + case eCursor_arrow_north_plus: + break; + + default: + NS_ASSERTION( 0, "Unknown cursor type"); + break; + } + + if( sptr) + mPointer = WinQuerySysPointer( HWND_DESKTOP, sptr, FALSE); + else + mPointer = gModuleData.GetPointer( aCursor); + + WinSetPointer( HWND_DESKTOP, mPointer); + mCursor = aCursor; + + return NS_OK; +} + +// Invalidate and force a redraw +nsresult nsWindow::Invalidate( PRBool aIsSynchronous) +{ + if( mWnd) + { + WinInvalidateRect( mWnd, 0, FALSE); +#if 0 + if( PR_TRUE == aIsSynchronous) + Update(); +#endif + } + return NS_OK; +} + +nsresult nsWindow::Invalidate( const nsRect &aRect, PRBool aIsSynchronous) +{ + if( mWnd) + { + // XXX could do with NS2PM for rectangles here... + RECTL rcl; + rcl.xLeft = aRect.x; + rcl.xRight = aRect.x + aRect.width; + rcl.yTop = GetClientHeight() - aRect.y; + rcl.yBottom = rcl.yTop - aRect.height + 1; + + WinInvalidateRect( mWnd, &rcl, FALSE); +#if 0 + if( PR_TRUE == aIsSynchronous) + Update(); +#endif + } + return NS_OK; +} + +// force invalid areas to be updated +nsresult nsWindow::Update() +{ + // Switch to the PM thread if necessary... + if( !mOS2Toolkit->IsPMThread()) + { + MethodInfo info(this, nsWindow::W_UPDATE_WINDOW); + mOS2Toolkit->CallMethod(&info); + } + else if( mWnd) + WinUpdateWindow( mWnd); + return NS_OK; +} + +nsresult nsWindow::SetTitle( const nsString &aTitle) +{ + // Switch to the PM thread if necessary... + if( mOS2Toolkit && !mOS2Toolkit->IsPMThread()) + { + ULONG ulong = (ULONG) &aTitle; + MethodInfo info( this, nsWindow::W_SET_TITLE, 1, &ulong); + mOS2Toolkit->CallMethod( &info); + } + else if( mWnd) + { + WinSetWindowText( GetMainWindow(), + gModuleData.ConvertFromUcs( aTitle)); + } + return NS_OK; +} + +nsresult nsWindow::GetWindowText( nsString &aStr, PRUint32 *rc) +{ + // Switch to the PM thread if necessary... + if( !mOS2Toolkit->IsPMThread()) + { + ULONG args[] = { (ULONG) &aStr, (ULONG) rc }; + MethodInfo info( this, nsWindow::W_GET_TITLE, 2, args); + mOS2Toolkit->CallMethod( &info); + } + else if( mWnd) + { + // XXX there must be some way to query the text straight into the string! + int length = WinQueryWindowTextLength( mWnd); + char *tmp = new char [ length + 1 ]; + WinQueryWindowText( mWnd, length + 1, tmp); + aStr = tmp; + delete [] tmp; + } + return NS_OK; +} + +// Scroll the bits of a window - this may need to bye thread-switched +nsresult nsWindow::Scroll( PRInt32 aDx, PRInt32 aDy, nsRect *aClipRect) +{ + RECTL rcl; + + if( aClipRect) + { + rcl.xLeft = aClipRect->x; + rcl.yBottom = aClipRect->y + aClipRect->height - 1; + NS2PM( (POINTL&) rcl); // hmm + rcl.xRight = rcl.xLeft + aClipRect->width; + rcl.yTop = rcl.yBottom + aClipRect->height; + // this rect is inex + } + + WinScrollWindow( mWnd, aDx, -aDy, aClipRect ? &rcl : 0, 0, 0, + 0, SW_SCROLLCHILDREN | SW_INVALIDATERGN); + Update(); + return NS_OK; +} + +// -------------------------------------------------------------------------- +// Misc helpers ------------------------------------------------------------- + +// May need to thread-switch these... +void nsWindow::AddToStyle( ULONG style) +{ + if( mWnd) + WinSetWindowBits( mWnd, QWL_STYLE, style, style); +} + +void nsWindow::RemoveFromStyle( ULONG style) +{ + if( mWnd) + { + ULONG oldStyle = WinQueryWindowULong( mWnd, QWL_STYLE); + oldStyle &= ~style; + WinSetWindowULong( mWnd, QWL_STYLE, oldStyle); + } +} + +void nsWindow::GetStyle( ULONG &out) +{ + if( mWnd) + out = WinQueryWindowULong( mWnd, QWL_STYLE); +} + +// -------------------------------------------------------------------------- +// Tooltips ----------------------------------------------------------------- + +nsresult nsWindow::SetTooltips( PRUint32 cTips, nsRect *areas[]) +{ + nsTooltipManager::GetManager()->SetTooltips( this, cTips, areas); + return NS_OK; +} + +nsresult nsWindow::UpdateTooltips( nsRect *aNewTips[]) +{ + nsTooltipManager::GetManager()->UpdateTooltips( this, aNewTips); + return NS_OK; +} + +nsresult nsWindow::RemoveTooltips() +{ + nsTooltipManager::GetManager()->RemoveTooltips( this); + return NS_OK; +} + +// -------------------------------------------------------------------------- +// Drag'n'drop -------------------------------------------------------------- + +#define DispatchDragDropEvent(msg) DispatchStandardEvent(msg,NS_DRAGDROP_EVENT) + +PRBool nsWindow::OnDragOver( MPARAM mp1, MPARAM mp2, MRESULT &mr) +{ + // Drawing drop feedback should be fun, have to get DrgGetPS() involved + // somehow. + + // Tell drag service about the drag + gModuleData.dragService->InitDragOver( (PDRAGINFO) mp1); + + // Invoke gecko for enter if appropriate + if( !mDragInside) + { + DispatchDragDropEvent( NS_DRAGDROP_ENTER); + mDragInside = TRUE; + } + + // Invoke for 'over' to set candrop flag + DispatchDragDropEvent( NS_DRAGDROP_OVER); + + // Get action back from drag service + mr = gModuleData.dragService->TermDragOver(); + + return PR_TRUE; +} + +PRBool nsWindow::OnDragLeave( MPARAM mp1, MPARAM mp2) +{ + gModuleData.dragService->InitDragExit( (PDRAGINFO) mp1); + DispatchDragDropEvent( NS_DRAGDROP_EXIT); + gModuleData.dragService->TermDragExit(); + + mDragInside = FALSE; + + return PR_TRUE; +} + +PRBool nsWindow::OnDrop( MPARAM mp1, MPARAM mp2) +{ + gModuleData.dragService->InitDrop( (PDRAGINFO) mp1); + DispatchDragDropEvent( NS_DRAGDROP_DROP); + gModuleData.dragService->TermDrop(); + + mDragInside = FALSE; + + return PR_TRUE; +} + +// -------------------------------------------------------------------------- +// Raptor object access + +// 'Native data' +void *nsWindow::GetNativeData( PRUint32 aDataType) +{ + void *rc = 0; + + switch( aDataType) + { + case NS_NATIVE_WIDGET: + case NS_NATIVE_WINDOW: + case NS_NATIVE_PLUGIN_PORT: + rc = (void*) mWnd; + break; + + case NS_NATIVE_GRAPHIC: + if( !mPS) + { + if( mDragInside) mPS = DrgGetPS( mWnd); + else mPS = WinGetPS( mWnd); + } + mPSRefs++; + rc = (void*) mPS; + break; + + case NS_NATIVE_COLORMAP: + case NS_NATIVE_DISPLAY: + case NS_NATIVE_REGION: + case NS_NATIVE_OFFSETX: + case NS_NATIVE_OFFSETY: // could do this, I suppose; but why? + // OTOH, this might make plugins work! + break; + + default: +#ifdef DEBUG + printf( "*** Someone's added a new NS_NATIVE value...\n"); +#endif + break; + } + + return rc; +} + +void nsWindow::FreeNativeData( void *aDatum, PRUint32 aDataType) +{ + switch( aDataType) + { + case NS_NATIVE_GRAPHIC: + mPSRefs--; + if( !mPSRefs) + { + BOOL rc; + if( mDragInside) rc = DrgReleasePS( mPS); + else rc = WinReleasePS( mPS); + if( !rc) + printf( "Error from {Win/Drg}ReleasePS()\n"); + mPS = 0; + } + break; + + case NS_NATIVE_COLORMAP: + case NS_NATIVE_DISPLAY: + case NS_NATIVE_REGION: + case NS_NATIVE_OFFSETX: + case NS_NATIVE_OFFSETY: + case NS_NATIVE_WIDGET: + case NS_NATIVE_WINDOW: + case NS_NATIVE_PLUGIN_PORT: + break; + + default: +#ifdef DEBUG + printf( "*** Someone's added a new NS_NATIVE value...\n"); +#endif + break; + } +} + +// Thread switch callback +nsresult nsWindow::CallMethod(MethodInfo *info) +{ + nsresult rc = NS_ERROR_FAILURE; + + switch( info->methodId) + { + case nsWindow::W_CREATE: + NS_ASSERTION(info->nArgs == 7, "Bad args to Create"); + DoCreate( (HWND) info->args[0], + (nsWindow*) info->args[1], + (const nsRect&)*(nsRect*) (info->args[2]), + (EVENT_CALLBACK) (info->args[3]), + (nsIDeviceContext*) (info->args[4]), + (nsIAppShell*) (info->args[5]), + nsnull, /* toolkit */ + (nsWidgetInitData*) (info->args[6])); + rc = NS_OK; + break; + + case nsWindow::W_DESTROY: + NS_ASSERTION(info->nArgs == 0, "Bad args to Destroy"); + Destroy(); + rc = NS_OK; + break; + + case nsWindow::W_SET_FOCUS: + NS_ASSERTION(info->nArgs == 0, "Bad args to SetFocus"); + SetFocus(); + rc = NS_OK; + break; + + case nsWindow::W_UPDATE_WINDOW: + NS_ASSERTION(info->nArgs == 0, "Bad args to UpdateWindow"); + Update(); + rc = NS_OK; + break; + + case nsWindow::W_SET_TITLE: + NS_ASSERTION(info->nArgs == 1, "Bad args to SetTitle"); + SetTitle( (const nsString &) info->args[0]); + rc = NS_OK; + break; + + case nsWindow::W_GET_TITLE: + NS_ASSERTION(info->nArgs == 2, "Bad args to GetTitle"); + rc = GetWindowText( *((nsString*) info->args[0]), + (PRUint32*)info->args[1]); + break; + + default: + break; + } + + return rc; +} + +// function to translate from a WM_CHAR to an NS VK_ constant --------------- +PRUint32 WMChar2KeyCode( MPARAM mp1, MPARAM mp2) +{ + PRUint32 rc = 0; + USHORT flags = SHORT1FROMMP( mp1); + + // First check for characters. + // This is complicated by keystrokes such as Ctrl+K not having the KC_CHAR + // bit set, but thankfully they do have the character actually there. + // + // So go on the assumption that `if not vkey or deadkey then char' + // + if( !(flags & (KC_VIRTUALKEY | KC_DEADKEY))) + { + rc = SHORT1FROMMP(mp2); + // Need nls-correct way of doing this... + if( isalnum( rc)) + rc = toupper( rc); // no lower case + else switch( rc) + { + case ';': rc = NS_VK_SEMICOLON; break; + case '=': rc = NS_VK_EQUALS; break; + case '*': rc = NS_VK_MULTIPLY; break; + case '+': rc = NS_VK_ADD; break; + case '-': rc = NS_VK_SUBTRACT; break; + case '.': rc = NS_VK_PERIOD; break; // NS_VK_DECIMAL ? + case '|': rc = NS_VK_SEPARATOR; break; + case ',': rc = NS_VK_COMMA; break; + case '/': rc = NS_VK_SLASH; break; // NS_VK_DIVIDE ? + case '`': rc = NS_VK_BACK_QUOTE; break; + case '(': rc = NS_VK_OPEN_BRACKET; break; + case '\\': rc = NS_VK_BACK_SLASH; break; + case ')': rc = NS_VK_CLOSE_BRACKET; break; + case '\'': rc = NS_VK_QUOTE; break; + } + } + else if( flags & KC_VIRTUALKEY) + { + USHORT vk = SHORT2FROMMP( mp2); + + if( vk >= VK_F1 && vk <= VK_F24) + rc = NS_VK_F1 + (vk - VK_F1); + else switch( vk) + { + case VK_NUMLOCK: rc = NS_VK_NUM_LOCK; break; + case VK_SCRLLOCK: rc = NS_VK_SCROLL_LOCK; break; + case VK_ESC: rc = NS_VK_ESCAPE; break; // NS_VK_CANCEL + case VK_BACKSPACE: rc = NS_VK_BACK; break; + case VK_TAB: rc = NS_VK_TAB; break; + case VK_BACKTAB: rc = NS_VK_TAB; break; // layout tests for isShift + case VK_CLEAR: rc = NS_VK_CLEAR; break; + case VK_NEWLINE: rc = NS_VK_RETURN; break; + case VK_ENTER: rc = NS_VK_ENTER; break; + case VK_SHIFT: rc = NS_VK_SHIFT; break; + case VK_CTRL: rc = NS_VK_CONTROL; break; + case VK_ALT: rc = NS_VK_ALT; break; + case VK_PAUSE: rc = NS_VK_PAUSE; break; + case VK_CAPSLOCK: rc = NS_VK_CAPS_LOCK; break; + case VK_SPACE: rc = NS_VK_SPACE; break; + case VK_PAGEUP: rc = NS_VK_PAGE_UP; break; + case VK_PAGEDOWN: rc = NS_VK_PAGE_DOWN; break; + case VK_END: rc = NS_VK_END; break; + case VK_HOME: rc = NS_VK_HOME; break; + case VK_LEFT: rc = NS_VK_LEFT; break; + case VK_UP: rc = NS_VK_UP; break; + case VK_RIGHT: rc = NS_VK_RIGHT; break; + case VK_DOWN: rc = NS_VK_DOWN; break; + case VK_PRINTSCRN: rc = NS_VK_PRINTSCREEN; break; + case VK_INSERT: rc = NS_VK_INSERT; break; + case VK_DELETE: rc = NS_VK_DELETE; break; + } + } + + return rc; +} diff --git a/mozilla/widget/src/os2/nsWindow.h b/mozilla/widget/src/os2/nsWindow.h new file mode 100644 index 00000000000..702461923aa --- /dev/null +++ b/mozilla/widget/src/os2/nsWindow.h @@ -0,0 +1,292 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _nswindow_h +#define _nswindow_h + +#include "nsWidgetDefs.h" +#include "nsBaseWidget.h" +#include "nsToolkit.h" + +class nsIMenuBar; +class nsContextMenu; + +// Base widget class. +// This is abstract. Controls (labels, radio buttons, listboxen) derive +// from here. A thing called a child window derives from here, and the +// frame window class derives from the child. The content-displaying +// classes are off on their own branch to avoid creating a palette for +// every window we create. This may turn out to be what's required, in +// which case the paint & palette code from nsChildWindow needs to be +// munged in here. nsFrameWindow is separate because work needs to be done +// there to decide whether methods apply to frame or client. + +class nsWindow : public nsBaseWidget, + public nsSwitchToPMThread +{ + public: + // Scaffolding + nsWindow(); + virtual ~nsWindow(); + + // nsIWidget + + // Creation from native (eh?) or widget parent, destroy + NS_IMETHOD Create( nsIWidget *aParent, + const nsRect &aRect, + EVENT_CALLBACK aHandleEventFunction, + nsIDeviceContext *aContext, + nsIAppShell *aAppShell = nsnull, + nsIToolkit *aToolkit = nsnull, + nsWidgetInitData *aInitData = nsnull); + NS_IMETHOD Create( nsNativeWidget aParent, + const nsRect &aRect, + EVENT_CALLBACK aHandleEventFunction, + nsIDeviceContext *aContext, + nsIAppShell *aAppShell = nsnull, + nsIToolkit *aToolkit = nsnull, + nsWidgetInitData *aInitData = nsnull); + NS_IMETHOD Destroy(); // call before releasing + + // Hierarchy: only interested in widget children (it seems) + virtual nsIWidget *GetParent(); + + // Strangely misplaced menubar methods + NS_IMETHOD SetMenuBar( nsIMenuBar *aMenuBar); + NS_IMETHOD ShowMenuBar( PRBool bShow); + NS_IMETHOD IsMenuBarVisible( PRBool *aVisible); + + // Physical properties + NS_IMETHOD Show( PRBool bState); + NS_IMETHOD Move( PRUint32 aX, PRUint32 aY); + NS_IMETHOD Resize( PRUint32 aWidth, + PRUint32 aHeight, + PRBool aRepaint); + NS_IMETHOD Resize( PRUint32 aX, + PRUint32 aY, + PRUint32 aWidth, + PRUint32 aHeight, + PRBool aRepaint); + NS_IMETHOD GetClientBounds( nsRect &aRect); + NS_IMETHOD GetBorderSize( PRInt32 &aWidth, PRInt32 &aHeight); + NS_IMETHOD Enable( PRBool bState); + NS_IMETHOD SetFocus(); + NS_IMETHOD IsVisible( PRBool &aState); + + NS_IMETHOD GetPreferredSize( PRInt32 &aWidth, PRInt32 &aHeight); + NS_IMETHOD SetPreferredSize( PRInt32 aWidth, PRInt32 aHeight); + + NS_IMETHOD BeginResizingChildren(); + NS_IMETHOD EndResizingChildren(); + NS_IMETHOD WidgetToScreen( const nsRect &aOldRect, nsRect &aNewRect); + NS_IMETHOD ScreenToWidget( const nsRect &aOldRect, nsRect &aNewRect); + NS_IMETHOD DispatchEvent( struct nsGUIEvent *event, nsEventStatus &aStatus); + + // Widget appearance + virtual nscolor GetForegroundColor(); + NS_IMETHOD SetForegroundColor( const nscolor &aColor); + virtual nscolor GetBackgroundColor(); + NS_IMETHOD SetBackgroundColor( const nscolor &aColor); + virtual nsIFontMetrics *GetFont(); + NS_IMETHOD SetFont( const nsFont &aFont); + NS_IMETHOD SetColorMap( nsColorMap *aColorMap); + NS_IMETHOD SetCursor( nsCursor aCursor); + NS_IMETHOD SetTitle( const nsString& aTitle); + NS_IMETHOD Invalidate( PRBool aIsSynchronous); + NS_IMETHOD Invalidate( const nsRect & aRect, PRBool aIsSynchronous); + NS_IMETHOD Update(); + NS_IMETHOD Scroll( PRInt32 aDx, PRInt32 aDy, nsRect *aClipRect); + NS_IMETHOD Paint( nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + // Tooltips + NS_IMETHOD SetTooltips( PRUint32 aNumberOfTips, nsRect *aTooltipAreas[]); + NS_IMETHOD RemoveTooltips(); + NS_IMETHOD UpdateTooltips( nsRect* aNewTips[]); + + // Get a HWND or a HPS. + virtual void *GetNativeData( PRUint32 aDataType); + virtual void FreeNativeData( void *aDatum, PRUint32 aDataType); + + // nsSwitchToPMThread interface + NS_IMETHOD CallMethod( MethodInfo *info); + + // PM methods which need to be public (menus, etc) + ULONG GetNextID() { return mNextID++; } + USHORT GetNextCmdID() { return mNextCmdID++; } + void NS2PM_PARENT( POINTL &ptl); + void NS2PM( POINTL &ptl); + void SetContextMenu( nsContextMenu *aMenu); + + protected: + // nsWindow methods subclasses must provide for creation to work + virtual PCSZ WindowClass() = 0; + virtual ULONG WindowStyle() = 0; + + // hooks subclasses may wish to override! + virtual void PostCreateWidget() {} + virtual PRInt32 GetHeight( PRInt32 aHeight) { return aHeight; } + virtual PRInt32 GetClientHeight() { return mBounds.height; } + virtual ULONG GetSWPFlags( ULONG flags) { return flags; } + virtual HWND GetMainWindow() const { return mWnd; } + virtual void SetupForPrint( HWND /*hwnd*/) {} + + // Useful functions for subclasses to use, threaded as necessary. + virtual nsresult GetWindowText( nsString &str, PRUint32 *rc); + virtual void AddToStyle( ULONG style); + virtual void RemoveFromStyle( ULONG style); + virtual void GetStyle( ULONG &out); + virtual nscolor QueryPresParam( ULONG ppID); + virtual void SetPresParam( ULONG ppID, const nscolor &c); + // return true if deferred + virtual BOOL SetWindowPos( HWND hwndInsertBehind, long x, long y, + long cx, long cy, unsigned long flags); + + // Message handlers - may wish to override. Default implementation for + // palette, control, paint & scroll is to do nothing. + + // Return whether message has been processed. + virtual PRBool ProcessMessage( ULONG m, MPARAM p1, MPARAM p2, MRESULT &r); + virtual PRBool OnPaint(); + virtual void OnDestroy(); + virtual PRBool OnReposition( PSWP pNewSwp); + virtual PRBool OnResize( PRInt32 aX, PRInt32 aY); + virtual PRBool OnMove( PRInt32 aX, PRInt32 aY); + virtual PRBool OnKey( MPARAM mp1, MPARAM mp2); + virtual PRBool OnRealizePalette(); + virtual PRBool OnScroll( MPARAM mp1, MPARAM mp2); + virtual PRBool OnControl( MPARAM mp1, MPARAM mp2); + virtual PRBool OnMenuClick( USHORT aCmd); + virtual PRBool OnActivateMenu( HWND aMenu, BOOL aActivate); + // called after param has been set... + virtual PRBool OnPresParamChanged( MPARAM mp1, MPARAM mp2); + virtual PRBool OnDragOver( MPARAM mp1, MPARAM mp2, MRESULT &mr); + virtual PRBool OnDragLeave( MPARAM mp1, MPARAM mp2); + virtual PRBool OnDrop( MPARAM mp1, MPARAM mp2); + + // PM data members + HWND mWnd; // window handle + PFNWP mFnWP; // previous window procedure + nsWindow *mParent; // parent widget + ULONG mNextID; // next child window id + USHORT mNextCmdID; // next WM_COMMAND id for menus + PSWP mSWPs; // SWPs for deferred window positioning + ULONG mlHave, mlUsed; // description of mSWPs array + HPOINTER mPointer; // current PM pointer + HPS mPS; // cache PS for window + ULONG mPSRefs; // number of refs to cache ps + BOOL mDragInside; // track draginside state + VDKEY mDeadKey; // dead key from previous keyevent + BOOL mHaveDeadKey; // is mDeadKey valid [0 may be a valid dead key, for all I know] + HWND mHackDestroyWnd; // access GetMainWindow() window from destructor + + HWND GetParentHWND() const; + HWND GetHWND() const { return mWnd; } + PFNWP GetPrevWP() const { return mFnWP; } + + // nglayout data members + PRInt32 mPreferredHeight; + PRInt32 mPreferredWidth; + nsToolkit *mOS2Toolkit; + nsFont *mFont; + nsIMenuBar *mMenuBar; + nsContextMenu *mActiveMenu; // record this so we can send it events + + // State of the window, used to emulate windows better... + enum nsWindowState + { + nsWindowState_ePrecreate, // default state; Create() not called + nsWindowState_eInCreate, // processing Create() method + nsWindowState_eLive, // active, existing window + nsWindowState_eDoingDelete, // object destructor running + nsWindowState_eDead // window destroyed + } mWindowState; + + // Implementation ------------------------------ + void DoCreate( HWND hwndP, nsWindow *wndP, const nsRect &rect, + EVENT_CALLBACK aHandleEventFunction, + nsIDeviceContext *aContext, nsIAppShell *aAppShell, + nsIToolkit *aToolkit, nsWidgetInitData *aInitData); + + virtual void RealDoCreate( HWND hwndP, nsWindow *aParent, + const nsRect &aRect, + EVENT_CALLBACK aHandleEventFunction, + nsIDeviceContext *aContext, + nsIAppShell *aAppShell, + nsWidgetInitData *aInitData, + HWND hwndOwner = 0); + + virtual void SubclassWindow( PRBool bState); + + PRBool ConvertStatus( nsEventStatus aStatus); + void InitEvent( nsGUIEvent &event, PRUint32 aEventType, nsPoint *pt = 0); + PRBool DispatchEventInternal( struct nsGUIEvent *event); + PRBool DispatchStandardEvent( PRUint32 aMsg, PRUint8 aStructType = NS_GUI_EVENT); + virtual PRBool DispatchMouseEvent( PRUint32 msg, int clickcount, + MPARAM mp1, MPARAM mp2); + virtual PRBool DispatchResizeEvent( PRInt32 aClientX, PRInt32 aClientY); + void DeferPosition( HWND, HWND, long, long, long, long, ULONG); + + // Enumeration of the methods which are accessable on the PM thread + enum { + W_CREATE, + W_DESTROY, + W_SET_FOCUS, + W_UPDATE_WINDOW, + W_SET_TITLE, + W_GET_TITLE + }; + friend MRESULT EXPENTRY fnwpNSWindow( HWND, ULONG, MPARAM, MPARAM); + friend MRESULT EXPENTRY fnwpFrame( HWND, ULONG, MPARAM, MPARAM); +}; + +#define PM2NS_PARENT NS2PM_PARENT +#define PM2NS NS2PM + +extern PRUint32 WMChar2KeyCode( MPARAM mp1, MPARAM mp2); + +extern nsWindow *NS_HWNDToWindow( HWND hwnd); + +#define NSCANVASCLASS "WarpzillaCanvas" + +#if 0 + +// Need to do this because the cross-platform widgets (toolbars) assume +// that the name of the NS_CHILD_CID is ChildWindow and that it gets +// defined in "nsWindow.h". +// +// However, if we've included this header *from nsCanvas.h*, then we +// get a lovely circular dependency, and so special-case this. +// +// Yes, I suppose I'm just being perverse by having three separate classes +// here, but I just baulk at naming a class 'ChildWindow'. +// +// (and don't tell me there's a JLib class called JMother. Believe me, +// I know, and I regret it at least twice a week...) +// +#ifndef _nscanvas_h +#include "nsCanvas.h" +typedef nsCanvas ChildWindow; +#endif + +#endif + +#endif diff --git a/mozilla/widget/src/os2/res/Makefile.in b/mozilla/widget/src/os2/res/Makefile.in new file mode 100644 index 00000000000..531f5791677 --- /dev/null +++ b/mozilla/widget/src/os2/res/Makefile.in @@ -0,0 +1,59 @@ +# The contents of this file are subject to the Mozilla Public License +# Version 1.1 (the "License"); you may not use this file except in +# compliance with the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +# License for the specific language governing rights and limitations +# under the License. +# +# The Original Code is the Mozilla OS/2 libraries. +# +# The Initial Developer of the Original Code is John Fairhurst, +# . Portions created by John Fairhurst are +# Copyright (C) 1999 John Fairhurst. All Rights Reserved. +# +# Makefile for widget\src\os2\res + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +DLL = wdgtres.dll +OS2_LIBRARYNAME = wdgtres +export: + +libs: $(DLL) + +install: + $(INSTALL) -m 444 $(DLL) $(DIST)/bin + +RCOPTS = -n -x2 -i . $(RCDEFS) + +# XXX Have to copy files because rc and link386 are too stupid for a mirror tree build + +$(DLL): wdgtres.obj wdgtres.rc + cp $(topsrcdir)/widget/src/os2/resID.h ./resID.h + cp $(srcdir)/frame.ico ./frame.ico + cp $(srcdir)/folder.ico ./folder.ico + cp $(srcdir)/dragitem.ico ./dragitem.ico + cp $(srcdir)/select.ptr ./select.ptr + cp $(srcdir)/wdgtres.def ./wdgtres.def + link386 /nol wdgtres,$@,nul,,wdgtres.def + rc $(RCOPTS) $(srcdir)/wdgtres.rc $@ + +ifneq ($(MOZ_OS2_TOOLS),VACPP) +OMF_FLAG = -Zomf +endif + +wdgtres.obj: wdgtres.C + $(CC) -o $@ -s -c $(CFLAGS) $(OMF_FLAG) $< + +realclean clean: + rm -rf $(DLL) *.res *.obj diff --git a/mozilla/widget/src/os2/res/dragitem.ico b/mozilla/widget/src/os2/res/dragitem.ico new file mode 100644 index 00000000000..cfb293f6941 Binary files /dev/null and b/mozilla/widget/src/os2/res/dragitem.ico differ diff --git a/mozilla/widget/src/os2/res/folder.ico b/mozilla/widget/src/os2/res/folder.ico new file mode 100644 index 00000000000..73af5631457 Binary files /dev/null and b/mozilla/widget/src/os2/res/folder.ico differ diff --git a/mozilla/widget/src/os2/res/frame.ico b/mozilla/widget/src/os2/res/frame.ico new file mode 100644 index 00000000000..d6e358ac3c9 Binary files /dev/null and b/mozilla/widget/src/os2/res/frame.ico differ diff --git a/mozilla/widget/src/os2/res/select.ptr b/mozilla/widget/src/os2/res/select.ptr new file mode 100644 index 00000000000..fbc0faa2611 Binary files /dev/null and b/mozilla/widget/src/os2/res/select.ptr differ diff --git a/mozilla/widget/src/os2/res/wdgtres.c b/mozilla/widget/src/os2/res/wdgtres.c new file mode 100644 index 00000000000..d2a9cd8684d --- /dev/null +++ b/mozilla/widget/src/os2/res/wdgtres.c @@ -0,0 +1,22 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +static const char *id = "Warpzilla Resource DLL"; diff --git a/mozilla/widget/src/os2/res/wdgtres.def b/mozilla/widget/src/os2/res/wdgtres.def new file mode 100644 index 00000000000..579e518671a --- /dev/null +++ b/mozilla/widget/src/os2/res/wdgtres.def @@ -0,0 +1,17 @@ +; The contents of this file are subject to the Mozilla Public License +; Version 1.1 (the "License"); you may not use this file except in +; compliance with the License. You may obtain a copy of the License at +; http://www.mozilla.org/MPL/ +; +; Software distributed under the License is distributed on an "AS IS" +; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +; License for the specific language governing rights and limitations +; under the License. +; +; The Original Code is the Mozilla OS/2 libraries. +; +; The Initial Developer of the Original Code is John Fairhurst, +; . Portions created by John Fairhurst are +; Copyright (C) 1999 John Fairhurst. All Rights Reserved. + +LIBRARY WDGTRES diff --git a/mozilla/widget/src/os2/res/wdgtres.dlg b/mozilla/widget/src/os2/res/wdgtres.dlg new file mode 100644 index 00000000000..6c1c1bf2f04 --- /dev/null +++ b/mozilla/widget/src/os2/res/wdgtres.dlg @@ -0,0 +1,42 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef OS2_INCLUDED + #include +#endif + +DLGTEMPLATE DID_DIRPICKER LOADONCALL MOVEABLE DISCARDABLE +BEGIN + DIALOG "Choose directory", DID_DIRPICKER, 0, 0, 190, 143, NOT WS_VISIBLE, + FCF_SYSMENU | FCF_TITLEBAR | FCF_CLOSEBUTTON + BEGIN + LTEXT "Choose drive:", 0, 3, 132, 60, 8 + CONTROL "", IDD_CBDRIVES, 63, 96, 124, 45, WC_COMBOBOX, + CBS_DROPDOWNLIST | WS_GROUP | WS_TABSTOP | + WS_VISIBLE + CONTAINER IDD_TREECNR, 3, 29, 184, 100, WS_TABSTOP | CCS_SINGLESEL | + CCS_READONLY | CCS_MINIRECORDCORE | CCS_MINIICONS + ENTRYFIELD "", IDD_EFPATH, 4, 18, 182, 7, ES_MARGIN | WS_TABSTOP + PUSHBUTTON "~OK", DID_OK, 2, 2, 36, 12, WS_GROUP | WS_TABSTOP + PUSHBUTTON "~Cancel", DID_CANCEL, 42, 2, 36, 12 + PUSHBUTTON "~Help", IDD_HELPBUTTON, 82, 2, 36, 12 + END +END diff --git a/mozilla/widget/src/os2/res/wdgtres.rc b/mozilla/widget/src/os2/res/wdgtres.rc new file mode 100644 index 00000000000..982d762773c --- /dev/null +++ b/mozilla/widget/src/os2/res/wdgtres.rc @@ -0,0 +1,57 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#include +#include "resid.h" + +DLGTEMPLATE DID_DIRPICKER LOADONCALL MOVEABLE DISCARDABLE +BEGIN + DIALOG "Choose directory", DID_DIRPICKER, 0, 0, 190, 143, NOT WS_VISIBLE, + FCF_SYSMENU | FCF_TITLEBAR | FCF_CLOSEBUTTON + BEGIN + LTEXT "Choose drive:", 0, 3, 132, 60, 8 + CONTROL "", IDD_CBDRIVES, 63, 96, 124, 45, WC_COMBOBOX, + CBS_DROPDOWNLIST | WS_GROUP | WS_TABSTOP | + WS_VISIBLE + CONTAINER IDD_TREECNR, 3, 29, 184, 100, WS_TABSTOP | CCS_SINGLESEL | + CCS_READONLY | CCS_MINIRECORDCORE | CCS_MINIICONS + ENTRYFIELD "", IDD_EFPATH, 4, 18, 182, 7, ES_MARGIN | WS_TABSTOP + PUSHBUTTON "~OK", DID_OK, 2, 2, 36, 12, WS_GROUP | WS_TABSTOP + PUSHBUTTON "~Cancel", DID_CANCEL, 42, 2, 36, 12 + PUSHBUTTON "~Help", IDD_HELPBUTTON, 82, 2, 36, 12 + END +END + +/* icons */ +ICON ID_ICO_FRAME frame.ico +ICON ID_ICO_FOLDER folder.ico +ICON ID_ICO_DRAGITEM dragitem.ico + +/* pointers */ +POINTER ID_PTR_SELECTURL select.ptr + +/* stringtable */ +STRINGTABLE +BEGIN + ID_STR_FONT "8.Helv" + ID_STR_HMMDIR "Cannot locate directory %s. Would you like it to be created?" + ID_STR_NOCDIR "Could not create directory." +END diff --git a/mozilla/widget/src/os2/resID.h b/mozilla/widget/src/os2/resID.h new file mode 100644 index 00000000000..c55f130bd4f --- /dev/null +++ b/mozilla/widget/src/os2/resID.h @@ -0,0 +1,46 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _resid_h +#define _resid_h + +// Resource IDs for the widget DLL. + +// Directory-picker dialog +#define DID_DIRPICKER 100 + +#define IDD_TREECNR 101 +#define IDD_CBDRIVES 102 +#define IDD_EFPATH 103 +#define IDD_HELPBUTTON 104 + +// Icons +#define ID_ICO_FRAME 500 +#define ID_ICO_FOLDER 501 +#define ID_ICO_DRAGITEM 502 + +#define ID_PTR_SELECTURL 2000 + +#define ID_STR_FONT 10000 +#define ID_STR_HMMDIR 10001 +#define ID_STR_NOCDIR 10002 + +#endif diff --git a/mozilla/widget/src/os2/tabapi.h b/mozilla/widget/src/os2/tabapi.h new file mode 100644 index 00000000000..6ea09af9e36 --- /dev/null +++ b/mozilla/widget/src/os2/tabapi.h @@ -0,0 +1,121 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +#ifndef _tabapi_h +#define _tabapi_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* Call to get the class name; will register the class on first call */ +PSZ TabGetTabControlName(void); + +/* messages that can be sent to the tab control */ +#define TABM_BASE (WM_USER + 50) + +#define TABC_END ((USHORT)-1) +#define TABC_FAILURE ((USHORT)-1) + +/* TABM_INSERTMULTTABS - append several tabs to the control */ +/* */ +/* param1 USHORT usTabs, number of tabs to insert. */ +/* param2 PSZ *apszLabels, array of tab labels */ +/* */ +/* returns BOOL bSuccess */ +#define TABM_INSERTMULTTABS (TABM_BASE + 0) + +/* TABM_INSERTTAB - add a new tab to the control. If this is the first */ +/* tab in the control, it will be the hilighted tab. */ +/* */ +/* param1 USHORT usIndex, index to insert. May be TABC_END. */ +/* param2 PSZ pszStr, label for new tab */ +/* */ +/* returns USHORT usIndex, index of new tab or TABC_FAILURE */ +#define TABM_INSERTTAB (TABM_BASE + 1) + +/* TABM_QUERYHILITTAB - get the index of the hilighted tab */ +/* */ +/* param1 ULONG ulReserved, reserved */ +/* param2 ULONG ulReserved, reserved */ +/* */ +/* returns USHORT usIndex, index of active tab or TABC_FAILURE */ +#define TABM_QUERYHILITTAB (TABM_BASE + 2) + +/* TABM_QUERYTABCOUNT - how many tabs are there? */ +/* */ +/* param1 ULONG ulReserved, reserved */ +/* param2 ULONG ulReserved, reserved */ +/* */ +/* returns USHORT usTabs, number of tabs */ +#define TABM_QUERYTABCOUNT (TABM_BASE + 3) + +/* TABM_QUERYTABTEXT - get a tab's label */ +/* */ +/* param1 USHORT usIndex, index of tab to query text for */ +/* USHORT usLength, length of buffer */ +/* param2 PSZ pszBuffer, buffer to get text into */ +/* */ +/* returns USHORT usChars, chars not copied or TABC_FAILURE */ +#define TABM_QUERYTABTEXT (TABM_BASE + 4) + +/* TABM_QUERYTABTEXTLENGTH - get the length of a tab's label */ +/* */ +/* param1 USHORT usIndex, index of tab to query text length for */ +/* param2 ULONG ulReserved, reserved */ +/* */ +/* returns ULONG ulLength, length of text not including null terminator */ +#define TABM_QUERYTABTEXTLENGTH (TABM_BASE + 5) + +/* TABM_REMOVETAB - remove a tab from the control */ +/* */ +/* param1 USHORT usIndex, index of tab to remove */ +/* param2 ULONG ulReserved, reserved */ +/* */ +/* returns BOOL bSuccess */ +#define TABM_REMOVETAB (TABM_BASE + 6) + +/* TABM_SETHILITTAB - set the index of the hilighted tab */ +/* */ +/* param1 USHORT usIndex, index of requested tab */ +/* param2 ULONG ulReserved, reserved */ +/* */ +/* returns BOOL bSuccess */ +#define TABM_SETHILITTAB (TABM_BASE + 7) + +/* TABM_SETCAPTION - Change the caption of an existing tab */ +/* */ +/* param1 USHORT usIndex, index to change. */ +/* param2 PSZ pszStr, label for new tab */ +/* */ +/* returns TRUE or TABC_FAILURE */ +#define TABM_SETCAPTION (TABM_BASE + 8) + +#define TABM_LASTPUBLIC TABM_SETCAPTION + +/* WM_CONTROL id sent to owner; mp2 is the index of the newly selected tab */ +#define TTN_TABCHANGE 1 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mozilla/widget/src/os2/tabctrl.c b/mozilla/widget/src/os2/tabctrl.c new file mode 100644 index 00000000000..6b6cbed8b82 --- /dev/null +++ b/mozilla/widget/src/os2/tabctrl.c @@ -0,0 +1,412 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): Dan Holmes + * + * + * TabCtrl.c - Warpzilla tab control + * + */ + +#define INCL_WIN +#define INCL_GPI +#include +#include +#include + +#include "tabapi.h" + +/* prototype of window procedure */ +MRESULT EXPENTRY fnwpTabCtrl( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2); +void DrawLine (HPS hps, int x1,int x2, int y1, int y2); + +/* Convenience method to get classname & register class */ +static BOOL bRegistered; + +#define UWC_TABCONTROL "WarpzillaTabControl" + +PSZ TabGetTabControlName(void) +{ + static PSZ pszClassname; + + if(!pszClassname) + { + BOOL rc = WinRegisterClass( 0, /* don't actually need a hab */ + UWC_TABCONTROL, + fnwpTabCtrl, + 0, /* maybe want CS_SIZEREDRAW here? */ + 8); /* 4 bytes spare for user, 4 for us */ + if(rc) + pszClassname = UWC_TABCONTROL; + } + + return pszClassname; +} + +/***************************************************************************/ +/* */ +/* TABDATA */ +/* */ +/***************************************************************************/ +typedef struct _PERTABDATA +{ + ULONG ulLength; + PSZ pszTabCaption; + struct _PERTABDATA *nextPerTabdata; +} PERTABDATA,*PPERTABDATA; + +typedef struct _TABDATA +{ + RECTL rclTabctl; + USHORT usTabCount; + USHORT usCurrentTab; + USHORT usMouseX; + USHORT usMouseY; + PPERTABDATA perTabData; +} TABDATA, *PTABDATA; + +/***************************************************************************/ +/* */ +/* Window procedure - add whatever messages you need */ +/* */ +/* When you want to define new messages to send to yourself, start at */ +/* TABM_LASTPUBLIC + 1 */ +/* */ +/***************************************************************************/ +MRESULT EXPENTRY fnwpTabCtrl( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + PTABDATA pData = (PTABDATA) WinQueryWindowPtr( hwnd, 4); + switch( msg) + { + case WM_CREATE: + /* allocate and set up default TABDATA structure */ + pData = (PTABDATA) calloc( sizeof(TABDATA), 1); + pData->usTabCount=0; + pData->usCurrentTab=0; + pData->usMouseX=0; + pData->usMouseY=0; + pData->rclTabctl.yTop=0; + pData->rclTabctl.yBottom=0; + pData->rclTabctl.xLeft=0; + pData->rclTabctl.xRight=0; + WinSetWindowPtr( hwnd, 4, pData); + break; + + case WM_DESTROY: + { + /* free up contents of TABDATA structure */ + /* then free the structure itself */ + PPERTABDATA pPTD, pPTD1; + pPTD=pData->perTabData; + while (pPTD) { + if (pPTD->pszTabCaption) + free(pPTD->pszTabCaption); + pPTD1=pPTD->nextPerTabdata; + free(pPTD); + pPTD=pPTD1; + } /* endwhile */ + free( pData); + break; + } + case WM_PAINT: + { + PPERTABDATA pPTD, pPTD1; + int x1,i,j,k,numChars; + POINTL ptl; + RECTL rcl,rcl1; + HPS hps = WinBeginPaint( hwnd, NULLHANDLE, &rcl); + WinQueryWindowRect(hwnd,&rcl); + pData->rclTabctl=rcl; + WinFillRect( hps, &rcl, CLR_PALEGRAY); + WinDrawBorder(hps,&rcl,1,1,0L,0L,DB_AREAATTRS); + GpiSetColor (hps,CLR_BLACK); + if (pData->usTabCount>0) { + if (pData->usCurrentTab==0) + pData->usCurrentTab=1; + if (pData->usCurrentTab>0) { + x1=(rcl.xRight-rcl.xLeft) / pData->usTabCount; + rcl1.xLeft=rcl.xLeft+(x1*(pData->usCurrentTab-1)); + rcl1.xRight=rcl1.xLeft+x1; + rcl1.yTop=rcl.yTop; + rcl1.yBottom=rcl.yBottom; +// WinFillRect( hps, &rcl1, CLR_DARKGRAY); + } /* endif */ + j=(rcl.xRight-rcl.xLeft) / pData->usTabCount; + i=k=0; + /* draw left white line */ + if (pData->usCurrentTab==1) { + GpiSetColor (hps,CLR_DARKGRAY); + } else { + GpiSetColor (hps,CLR_WHITE); + } /* endif */ + DrawLine(hps,i+1,i+1,rcl.yBottom+1,rcl.yTop-2); + DrawLine(hps,i+2,i+2,rcl.yBottom+1,rcl.yTop-2); + /* draw top white line */ + DrawLine(hps,i+1,rcl.xRight-2,rcl.yTop-2,rcl.yTop-2); + DrawLine(hps,i+1,rcl.xRight-2,rcl.yTop-3,rcl.yTop-3); + GpiSetColor (hps,CLR_BLACK); + /* draw left dark gray line */ + if (pData->usCurrentTab!=1) { + GpiSetColor (hps,CLR_DARKGRAY); + } else { + GpiSetColor (hps,CLR_WHITE); + } /* endif */ + DrawLine(hps,rcl1.xRight-2,rcl1.xRight-2,rcl1.yBottom+1,rcl1.yTop-2); + DrawLine(hps,rcl1.xRight-3,rcl1.xRight-3,rcl1.yBottom+1,rcl1.yTop-2); + /* draw bottom dark gray line */ + DrawLine(hps,rcl1.xLeft+1,rcl1.xRight-2,rcl1.yBottom+1,rcl1.yBottom+1); + DrawLine(hps,rcl1.xLeft+1,rcl1.xRight-2,rcl1.yBottom+2,rcl1.yBottom+2); + GpiSetColor (hps,CLR_BLACK); + rcl1.xLeft=rcl.xLeft+i; + rcl1.xRight=rcl1.xLeft+j-2; + rcl1.yTop=rcl.yTop-3; + rcl1.yBottom=rcl.yBottom; + pPTD=pData->perTabData; + numChars=WinDrawText(hps,(LONG)strlen(pPTD->pszTabCaption),pPTD->pszTabCaption,&rcl1,0,0,DT_CENTER|DT_TEXTATTRS|DT_WORDBREAK|DT_VCENTER); + for (i=j;iusTabCount) { + GpiSetColor (hps,CLR_BLACK); + k++; + rcl1.xLeft=rcl.xLeft+i; + rcl1.xRight=rcl1.xLeft+j-2; + rcl1.yTop=rcl.yTop-3; + rcl1.yBottom=rcl.yBottom; + if (!pPTD->nextPerTabdata) break; + pPTD=pPTD->nextPerTabdata; + numChars=WinDrawText(hps,(LONG)strlen(pPTD->pszTabCaption),pPTD->pszTabCaption,&rcl1,0,0,DT_CENTER|DT_TEXTATTRS|DT_WORDBREAK|DT_VCENTER); + DrawLine(hps,i,i,rcl.yBottom,rcl.yTop); + /* draw highlites */ + if (pData->usCurrentTab==(k+1)) { + GpiSetColor (hps,CLR_DARKGRAY); + } else { + GpiSetColor (hps,CLR_WHITE); + } /* endif */ + /* draw left white line */ + DrawLine(hps,i+1,i+1,rcl.yBottom+1,rcl.yTop-2); + DrawLine(hps,i+2,i+2,rcl.yBottom+1,rcl.yTop-2); + /* draw top white line */ + DrawLine(hps,i+1,rcl.xRight-2,rcl.yTop-2,rcl.yTop-2); + DrawLine(hps,i+1,rcl.xRight-2,rcl.yTop-3,rcl.yTop-3); + if (pData->usCurrentTab!=(k+1)) { + GpiSetColor (hps,CLR_DARKGRAY); + } else { + GpiSetColor (hps,CLR_WHITE); + } /* endif */ + /* draw right dark gray line */ + DrawLine(hps,rcl1.xRight,rcl1.xRight,rcl1.yBottom+1,rcl1.yTop-2); + DrawLine(hps,rcl1.xRight-1,rcl1.xRight-1,rcl1.yBottom+1,rcl1.yTop-2); + /* draw bottom dark gray line */ + DrawLine(hps,rcl1.xLeft+1,rcl1.xRight-2,rcl1.yBottom+1,rcl1.yBottom+1); + DrawLine(hps,rcl1.xLeft+1,rcl1.xRight-2,rcl1.yBottom+2,rcl1.yBottom+2); + GpiSetColor (hps,CLR_BLACK); + } /* endfor */ + } /* endif */ + WinEndPaint( hps); + return 0; + } + case WM_BUTTON1DOWN: + { + int x1; + RECTL rcl; + if (pData->usTabCount>0) { + WinQueryWindowRect(hwnd,&rcl); + pData->usMouseX=SHORT1FROMMP(mp1); + pData->usMouseY=SHORT2FROMMP(mp1); + x1=pData->usMouseX / (rcl.xRight / pData->usTabCount)+1; + if (x1!=pData->usCurrentTab) { + pData->usCurrentTab=x1; + WinSendMsg(WinQueryWindow(hwnd,QW_OWNER), + WM_CONTROL, + MPFROM2SHORT(WinQueryWindowUShort(hwnd,QWS_ID),TTN_TABCHANGE), + MPFROMSHORT(x1)); + WinInvalidateRect( hwnd, 0, TRUE); + } /* endif */ + } /* endif */ + break; + } + case TABM_INSERTMULTTABS: + { + PPERTABDATA pFirstTabData=0, pPrevious=0; + int k; + /* create new tabs */ + for (k=1;k<=SHORT1FROMMP(mp1);k++) { + PPERTABDATA pTabData = calloc( sizeof(PERTABDATA), 1); + if( pPrevious != 0) + { + pPrevious->nextPerTabdata = pTabData; + pPrevious = pTabData; + } + if( pFirstTabData == 0) + { + pFirstTabData = pTabData; + pPrevious = pTabData; + } + pTabData->pszTabCaption=strdup(((char **)mp2)[k-1]); + pTabData->ulLength=strlen(pTabData->pszTabCaption); + pData->usTabCount++; + } /* end for */ + if (pData->usTabCount==SHORT1FROMMP(mp1)) + pData->perTabData=pFirstTabData; + else + { + PPERTABDATA pPTD=0; + pPTD=pData->perTabData; + while (pPTD->nextPerTabdata) + pPTD=pPTD->nextPerTabdata; + pPTD->nextPerTabdata=pFirstTabData; + } + WinInvalidateRect( hwnd, 0, TRUE); + return (MRESULT)TRUE; + } + case TABM_INSERTTAB: + { + int i,j; + PPERTABDATA pTempTabData, pTabData = calloc(sizeof(PERTABDATA),1); + pTabData->ulLength=strlen((char *)mp2); + pTabData->pszTabCaption=calloc(pTabData->ulLength+1,1); + strcpy(pTabData->pszTabCaption,(char *)mp2); + if (SHORT1FROMMP(mp1)==1) { + pData->perTabData=pTabData; + pData->usTabCount=1; + WinInvalidateRect( hwnd, 0, TRUE); + return (MRESULT)1; + } else { + j=SHORT1FROMMP(mp1); + if (j<=pData->usTabCount+1) { + pTempTabData=pData->perTabData; + for (i=2;inextPerTabdata; + pTempTabData->nextPerTabdata=pTabData; + if (pData->usTabCountusTabCount++; + } /* endif */ + WinInvalidateRect( hwnd, 0, TRUE); + return mp1; + } else { + free(pTabData); + return (MRESULT)TABC_FAILURE; + } /* endif */ + } /* endif */ + } /* end case */ + case TABM_QUERYHILITTAB: + return MRFROMSHORT((pData->usTabCount?pData->usCurrentTab:TABC_FAILURE)); + + case TABM_QUERYTABCOUNT: + return MRFROMSHORT(pData->usTabCount); + + case TABM_QUERYTABTEXT: + { + int i; + PPERTABDATA pTabData=pData->perTabData; + if (pData->usTabCount>0) { + for (i=1;inextPerTabdata; + } /* endfor */ + strncpy((char *)mp2,pTabData->pszTabCaption,SHORT1FROMMP(mp2)); + return MRFROMSHORT(((SHORT2FROMMP(mp1)pszTabCaption))?strlen(pTabData->pszTabCaption)-SHORT2FROMMP(mp1):0)); + } else { + return MRFROMSHORT(TABC_FAILURE); + } /* endif */ + } + case TABM_QUERYTABTEXTLENGTH: + { + int i; + PPERTABDATA pTabData=pData->perTabData; + if (pData->usTabCount>0) { + for (i=1;inextPerTabdata; + } /* endfor */ + return (MRESULT)(strlen(pTabData->pszTabCaption)); + } else { + return (MRESULT)TABC_FAILURE; + } /* endif */ + } + case TABM_REMOVETAB: + { + int i; + PPERTABDATA pPTD, pPTD1; + if (SHORT1FROMMP(mp1)>pData->usTabCount) + return (MRESULT)TABC_FAILURE; + if (SHORT1FROMMP(mp1)==1) { + pPTD=pData->perTabData->nextPerTabdata; + free(pData->perTabData->pszTabCaption); + free(pData->perTabData); + pData->perTabData=pPTD; + } else if (SHORT1FROMMP(mp1)==pData->usTabCount) { + pPTD=pData->perTabData; + for (i=1;inextPerTabdata; + free(pPTD->nextPerTabdata->pszTabCaption); + free(pPTD->nextPerTabdata); + pPTD->nextPerTabdata='\0'; + if (SHORT1FROMMP(mp1)==pData->usCurrentTab) + pData->usCurrentTab--; + } else { + pPTD=pData->perTabData; /* first tab */ + for (i=1;inextPerTabdata; /* at end of loop tab before the one to delete */ + pPTD1=pPTD->nextPerTabdata; /* the tab to remove */ + if (pPTD1->pszTabCaption) + free(pPTD1->pszTabCaption); + pPTD->nextPerTabdata=pPTD1->nextPerTabdata; + free(pPTD1); + } + pData->usTabCount--; + WinSendMsg(WinQueryWindow(hwnd,QW_OWNER), + WM_CONTROL, + MPFROM2SHORT(WinQueryWindowUShort(hwnd,QWS_ID),TTN_TABCHANGE), + MPFROMSHORT(pData->usCurrentTab)); + WinInvalidateRect( hwnd, 0, TRUE); + return (MRESULT) TABC_END; + } + case TABM_SETHILITTAB: + { + if (pData->usCurrentTab!=SHORT1FROMMP(mp1)) { + pData->usCurrentTab=SHORT1FROMMP(mp1); + WinInvalidateRect( hwnd, 0, TRUE); + } + return (MRESULT) TABC_END; + } + case TABM_SETCAPTION: + { + int i; + PPERTABDATA pTabData=pData->perTabData; + if (LONGFROMMP(mp1)<=pData->usTabCount) { + for (i=1;inextPerTabdata; + free(pTabData->pszTabCaption); + pTabData->pszTabCaption=calloc(LONGFROMMP(mp1),1); + strcpy(pTabData->pszTabCaption,(char *)mp2); + WinInvalidateRect( hwnd, 0, TRUE); + return (MRESULT)1; + } else { + return (MRESULT)TABC_FAILURE; + } /* endif */ + } + } + /* call the default window procedure so normal things still work */ + return WinDefWindowProc( hwnd, msg, mp1, mp2); +} +void DrawLine (HPS hps, int x1,int x2, int y1, int y2) +{ + POINTL ptl; + ptl.x=x1; + ptl.y=y1; + GpiMove(hps,&ptl); + ptl.x=x2; + ptl.y=y2; + GpiLine(hps,&ptl); +} diff --git a/mozilla/widget/src/os2/tests/Makefile.in b/mozilla/widget/src/os2/tests/Makefile.in new file mode 100644 index 00000000000..eee9d6e9208 --- /dev/null +++ b/mozilla/widget/src/os2/tests/Makefile.in @@ -0,0 +1,34 @@ +# The contents of this file are subject to the Mozilla Public License +# Version 1.1 (the "License"); you may not use this file except in +# compliance with the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +# License for the specific language governing rights and limitations +# under the License. +# +# The Original Code is the Mozilla OS/2 libraries. +# +# The Initial Developer of the Original Code is John Fairhurst, +# . Portions created by John Fairhurst are +# Copyright (C) 1999 John Fairhurst. All Rights Reserved. + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = raptor + +SIMPLE_PROGRAMS = dirpicker$(BIN_SUFFIX) + +CPPSRCS = dirpicker.cpp + +LIBS = $(DIST)/lib/libraptorwidget_s.lib + +include $(topsrcdir)/config/rules.mk + +INCLUDES += -I$(srcdir)/.. diff --git a/mozilla/widget/src/os2/tests/dirpicker.cpp b/mozilla/widget/src/os2/tests/dirpicker.cpp new file mode 100644 index 00000000000..05bc5ec57a3 --- /dev/null +++ b/mozilla/widget/src/os2/tests/dirpicker.cpp @@ -0,0 +1,68 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is the Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is John Fairhurst, + * . Portions created by John Fairhurst are + * Copyright (C) 1999 John Fairhurst. All Rights Reserved. + * + * Contributor(s): + * + */ + +/* Quick test program to develop/demonstrate the directory picker */ + +#define INCL_DOS +#define INCL_WIN +#include +#include + +#include "nsDirPicker.h" + +int main() +{ + HAB hab; + HMQ hmq; + DIRPICKER dirpicker = { "", 0, TRUE, 0 }; + HMODULE hModRes; + APIRET rc; + PTIB ptib; + PPIB ppib; + + /* need to do this 'cos we don't link against NSPR */ + DosGetInfoBlocks( &ptib, &ppib); + ppib->pib_ultype = 3; + + hab = WinInitialize(0); + hmq = WinCreateMsgQueue( hab, 0); + + rc = DosLoadModule( 0, 0, "WDGTRES", &hModRes); + + if( !rc) + { + + FS_PickDirectory( HWND_DESKTOP, HWND_DESKTOP, hModRes, &dirpicker); + + printf( "%s\n", dirpicker.szFullFile); + + DosFreeModule( hModRes); + } + else + { + printf( "Unable to load WDGTRES dll -- check running from $(DIST)/bin\n"); + } + + WinDestroyMsgQueue( hmq); + WinTerminate( hab); + + return 0; +}