From 2646f485163f410baaad5bcf49028c604a352d19 Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Sat, 20 Mar 2004 07:43:01 +0000 Subject: [PATCH] split classic and carbon git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@26277 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- src/mac/classic/Info.plist.in | 36 + src/mac/classic/accel.cpp | 108 ++ src/mac/classic/aga.cpp | 2 + src/mac/classic/app.cpp | 2439 +++++++++++++++++++++++++++++++++ src/mac/classic/apprsrc.h | 6 + src/mac/classic/apprsrc.r | 32 + src/mac/classic/bitmap.cpp | 1436 +++++++++++++++++++ src/mac/classic/bmpbuttn.cpp | 113 ++ src/mac/classic/brush.cpp | 229 ++++ src/mac/classic/button.cpp | 132 ++ src/mac/classic/carbrsrc.r | 7 + src/mac/classic/checkbox.cpp | 179 +++ src/mac/classic/checklst.cpp | 453 ++++++ src/mac/classic/choice.cpp | 300 ++++ src/mac/classic/clipbrd.cpp | 406 ++++++ src/mac/classic/colordlg.cpp | 70 + src/mac/classic/colour.cpp | 116 ++ src/mac/classic/combobox.cpp | 540 ++++++++ src/mac/classic/control.cpp | 814 +++++++++++ src/mac/classic/corersrc.r | 159 +++ src/mac/classic/cursor.cpp | 505 +++++++ src/mac/classic/data.cpp | 25 + src/mac/classic/dataobj.cpp | 308 +++++ src/mac/classic/dc.cpp | 2297 +++++++++++++++++++++++++++++++ src/mac/classic/dcclient.cpp | 175 +++ src/mac/classic/dcmemory.cpp | 100 ++ src/mac/classic/dcprint.cpp | 416 ++++++ src/mac/classic/dcscreen.cpp | 63 + src/mac/classic/dialog.cpp | 268 ++++ src/mac/classic/dirdlg.cpp | 146 ++ src/mac/classic/dirmac.cpp | 322 +++++ src/mac/classic/display.cpp | 446 ++++++ src/mac/classic/dnd.cpp | 607 ++++++++ src/mac/classic/filedlg.cpp | 647 +++++++++ src/mac/classic/font.cpp | 446 ++++++ src/mac/classic/fontdlg.cpp | 54 + src/mac/classic/fontenum.cpp | 173 +++ src/mac/classic/fontutil.cpp | 117 ++ src/mac/classic/frame.cpp | 338 +++++ src/mac/classic/gauge.cpp | 95 ++ src/mac/classic/gdiobj.cpp | 22 + src/mac/classic/glcanvas.cpp | 385 ++++++ src/mac/classic/gsocket.c | 1653 ++++++++++++++++++++++ src/mac/classic/gsockosx.c | 181 +++ src/mac/classic/gsockosx.cpp | 181 +++ src/mac/classic/helpxxxx.cpp | 84 ++ src/mac/classic/hid.cpp | 417 ++++++ src/mac/classic/icon.cpp | 132 ++ src/mac/classic/joystick.cpp | 286 ++++ src/mac/classic/listbox.cpp | 1023 ++++++++++++++ src/mac/classic/macnotfy.cpp | 162 +++ src/mac/classic/main.cpp | 12 + src/mac/classic/mdi.cpp | 395 ++++++ src/mac/classic/menu.cpp | 881 ++++++++++++ src/mac/classic/menuitem.cpp | 283 ++++ src/mac/classic/metafile.cpp | 219 +++ src/mac/classic/mimetmac.cpp | 228 +++ src/mac/classic/minifram.cpp | 22 + src/mac/classic/msgdlg.cpp | 262 ++++ src/mac/classic/notebmac.cpp | 729 ++++++++++ src/mac/classic/palette.cpp | 118 ++ src/mac/classic/pen.cpp | 186 +++ src/mac/classic/pnghand.cpp | 904 ++++++++++++ src/mac/classic/printdlg.cpp | 124 ++ src/mac/classic/printmac.cpp | 781 +++++++++++ src/mac/classic/radiobox.cpp | 580 ++++++++ src/mac/classic/radiobut.cpp | 150 ++ src/mac/classic/region.cpp | 437 ++++++ src/mac/classic/renderer.cpp | 283 ++++ src/mac/classic/scrolbar.cpp | 184 +++ src/mac/classic/settings.cpp | 279 ++++ src/mac/classic/slider.cpp | 433 ++++++ src/mac/classic/sound.cpp | 243 ++++ src/mac/classic/spinbutt.cpp | 182 +++ src/mac/classic/spinctrl.cpp | 333 +++++ src/mac/classic/statbmp.cpp | 86 ++ src/mac/classic/statbox.cpp | 56 + src/mac/classic/statbrma.cpp | 155 +++ src/mac/classic/statline.cpp | 61 + src/mac/classic/statlmac.cpp | 67 + src/mac/classic/stattext.cpp | 262 ++++ src/mac/classic/tabctrl.cpp | 206 +++ src/mac/classic/textctrl.cpp | 1810 ++++++++++++++++++++++++ src/mac/classic/tglbtn.cpp | 127 ++ src/mac/classic/thread.cpp | 921 +++++++++++++ src/mac/classic/timer.cpp | 143 ++ src/mac/classic/toolbar.cpp | 620 +++++++++ src/mac/classic/tooltip.cpp | 408 ++++++ src/mac/classic/toplevel.cpp | 1463 ++++++++++++++++++++ src/mac/classic/treectrl.cpp | 419 ++++++ src/mac/classic/uma.cpp | 815 +++++++++++ src/mac/classic/utils.cpp | 1395 +++++++++++++++++++ src/mac/classic/utilsexc.cpp | 223 +++ src/mac/classic/window.cpp | 2096 ++++++++++++++++++++++++++++ src/mac/classic/wxmac.icns | Bin 0 -> 36901 bytes 95 files changed, 39232 insertions(+) create mode 100644 src/mac/classic/Info.plist.in create mode 100644 src/mac/classic/accel.cpp create mode 100644 src/mac/classic/aga.cpp create mode 100644 src/mac/classic/app.cpp create mode 100644 src/mac/classic/apprsrc.h create mode 100644 src/mac/classic/apprsrc.r create mode 100644 src/mac/classic/bitmap.cpp create mode 100644 src/mac/classic/bmpbuttn.cpp create mode 100644 src/mac/classic/brush.cpp create mode 100644 src/mac/classic/button.cpp create mode 100644 src/mac/classic/carbrsrc.r create mode 100644 src/mac/classic/checkbox.cpp create mode 100644 src/mac/classic/checklst.cpp create mode 100644 src/mac/classic/choice.cpp create mode 100644 src/mac/classic/clipbrd.cpp create mode 100644 src/mac/classic/colordlg.cpp create mode 100644 src/mac/classic/colour.cpp create mode 100644 src/mac/classic/combobox.cpp create mode 100644 src/mac/classic/control.cpp create mode 100644 src/mac/classic/corersrc.r create mode 100644 src/mac/classic/cursor.cpp create mode 100644 src/mac/classic/data.cpp create mode 100644 src/mac/classic/dataobj.cpp create mode 100644 src/mac/classic/dc.cpp create mode 100644 src/mac/classic/dcclient.cpp create mode 100644 src/mac/classic/dcmemory.cpp create mode 100644 src/mac/classic/dcprint.cpp create mode 100644 src/mac/classic/dcscreen.cpp create mode 100644 src/mac/classic/dialog.cpp create mode 100644 src/mac/classic/dirdlg.cpp create mode 100644 src/mac/classic/dirmac.cpp create mode 100644 src/mac/classic/display.cpp create mode 100644 src/mac/classic/dnd.cpp create mode 100644 src/mac/classic/filedlg.cpp create mode 100644 src/mac/classic/font.cpp create mode 100644 src/mac/classic/fontdlg.cpp create mode 100644 src/mac/classic/fontenum.cpp create mode 100644 src/mac/classic/fontutil.cpp create mode 100644 src/mac/classic/frame.cpp create mode 100644 src/mac/classic/gauge.cpp create mode 100644 src/mac/classic/gdiobj.cpp create mode 100644 src/mac/classic/glcanvas.cpp create mode 100644 src/mac/classic/gsocket.c create mode 100644 src/mac/classic/gsockosx.c create mode 100644 src/mac/classic/gsockosx.cpp create mode 100644 src/mac/classic/helpxxxx.cpp create mode 100644 src/mac/classic/hid.cpp create mode 100644 src/mac/classic/icon.cpp create mode 100644 src/mac/classic/joystick.cpp create mode 100644 src/mac/classic/listbox.cpp create mode 100644 src/mac/classic/macnotfy.cpp create mode 100644 src/mac/classic/main.cpp create mode 100644 src/mac/classic/mdi.cpp create mode 100644 src/mac/classic/menu.cpp create mode 100644 src/mac/classic/menuitem.cpp create mode 100644 src/mac/classic/metafile.cpp create mode 100644 src/mac/classic/mimetmac.cpp create mode 100644 src/mac/classic/minifram.cpp create mode 100644 src/mac/classic/msgdlg.cpp create mode 100644 src/mac/classic/notebmac.cpp create mode 100644 src/mac/classic/palette.cpp create mode 100644 src/mac/classic/pen.cpp create mode 100644 src/mac/classic/pnghand.cpp create mode 100644 src/mac/classic/printdlg.cpp create mode 100644 src/mac/classic/printmac.cpp create mode 100644 src/mac/classic/radiobox.cpp create mode 100644 src/mac/classic/radiobut.cpp create mode 100644 src/mac/classic/region.cpp create mode 100644 src/mac/classic/renderer.cpp create mode 100644 src/mac/classic/scrolbar.cpp create mode 100644 src/mac/classic/settings.cpp create mode 100644 src/mac/classic/slider.cpp create mode 100644 src/mac/classic/sound.cpp create mode 100644 src/mac/classic/spinbutt.cpp create mode 100644 src/mac/classic/spinctrl.cpp create mode 100644 src/mac/classic/statbmp.cpp create mode 100644 src/mac/classic/statbox.cpp create mode 100644 src/mac/classic/statbrma.cpp create mode 100644 src/mac/classic/statline.cpp create mode 100644 src/mac/classic/statlmac.cpp create mode 100644 src/mac/classic/stattext.cpp create mode 100644 src/mac/classic/tabctrl.cpp create mode 100644 src/mac/classic/textctrl.cpp create mode 100644 src/mac/classic/tglbtn.cpp create mode 100644 src/mac/classic/thread.cpp create mode 100644 src/mac/classic/timer.cpp create mode 100644 src/mac/classic/toolbar.cpp create mode 100644 src/mac/classic/tooltip.cpp create mode 100644 src/mac/classic/toplevel.cpp create mode 100644 src/mac/classic/treectrl.cpp create mode 100644 src/mac/classic/uma.cpp create mode 100644 src/mac/classic/utils.cpp create mode 100644 src/mac/classic/utilsexc.cpp create mode 100644 src/mac/classic/window.cpp create mode 100644 src/mac/classic/wxmac.icns diff --git a/src/mac/classic/Info.plist.in b/src/mac/classic/Info.plist.in new file mode 100644 index 0000000000..2be3d33364 --- /dev/null +++ b/src/mac/classic/Info.plist.in @@ -0,0 +1,36 @@ + + + + + CFBundleInfoDictionaryVersion + 6.0 + CFBundleIdentifier + org.wxwindows.IDENTIFIER + CFBundleDevelopmentRegion + English + CFBundleExecutable + EXECUTABLE + CFBundleIconFile + wxmac.icns + CFBundleName + EXECUTABLE + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + VERSION + CFBundleShortVersionString + VERSION + CFBundleGetInfoString + EXECUTABLE version VERSION, (c) 2002 wxWindows + CFBundleLongVersionString + VERSION, (c) 2002 wxWindows + NSHumanReadableCopyright + Copyright 2002 wxWindows + LSRequiresCarbon + + CSResourcesFileMapped + + + diff --git a/src/mac/classic/accel.cpp b/src/mac/classic/accel.cpp new file mode 100644 index 0000000000..14aa88e53a --- /dev/null +++ b/src/mac/classic/accel.cpp @@ -0,0 +1,108 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: accel.cpp +// Purpose: wxAcceleratorTable +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "accel.h" +#endif + +#include "wx/setup.h" +#include "wx/accel.h" +#include "wx/string.h" + +#if !USE_SHARED_LIBRARIES +IMPLEMENT_DYNAMIC_CLASS(wxAcceleratorTable, wxObject) +#endif + +// ---------------------------------------------------------------------------- +// wxAccelList: a list of wxAcceleratorEntries +// ---------------------------------------------------------------------------- + +WX_DECLARE_LIST(wxAcceleratorEntry, wxAccelList); +#include "wx/listimpl.cpp" +WX_DEFINE_LIST(wxAccelList); + +// ---------------------------------------------------------------------------- +// wxAccelRefData: the data used by wxAcceleratorTable +// ---------------------------------------------------------------------------- + +class WXDLLEXPORT wxAcceleratorRefData: public wxObjectRefData +{ + friend class WXDLLEXPORT wxAcceleratorTable; +public: + wxAcceleratorRefData(); + ~wxAcceleratorRefData(); + + wxAccelList m_accels; +}; + +#define M_ACCELDATA ((wxAcceleratorRefData *)m_refData) + +wxAcceleratorRefData::wxAcceleratorRefData() + : m_accels() +{ +} + +wxAcceleratorRefData::~wxAcceleratorRefData() +{ + m_accels.DeleteContents( TRUE ); +} + +wxAcceleratorTable::wxAcceleratorTable() +{ + m_refData = NULL; +} + +wxAcceleratorTable::~wxAcceleratorTable() +{ +} + +// Create from an array +wxAcceleratorTable::wxAcceleratorTable(int n, const wxAcceleratorEntry entries[]) +{ + m_refData = new wxAcceleratorRefData; + + for (int i = 0; i < n; i++) + { + int flag = entries[i].GetFlags(); + int keycode = entries[i].GetKeyCode(); + int command = entries[i].GetCommand(); + if ((keycode >= (int)'a') && (keycode <= (int)'z')) keycode = (int)toupper( (char)keycode ); + M_ACCELDATA->m_accels.Append( new wxAcceleratorEntry( flag, keycode, command ) ); + } +} + +bool wxAcceleratorTable::Ok() const +{ + return (m_refData != NULL); +} + +int wxAcceleratorTable::GetCommand( wxKeyEvent &event ) +{ + if (!Ok()) return -1; + + wxAccelList::Node *node = M_ACCELDATA->m_accels.GetFirst(); + while (node) + { + wxAcceleratorEntry *entry = (wxAcceleratorEntry*)node->GetData(); + if ((event.m_keyCode == entry->GetKeyCode()) && + (((entry->GetFlags() & wxACCEL_CTRL) == 0) || event.ControlDown()) && + (((entry->GetFlags() & wxACCEL_SHIFT) == 0) || event.ShiftDown()) && + (((entry->GetFlags() & wxACCEL_ALT) == 0) || event.AltDown() || event.MetaDown())) + { + return entry->GetCommand(); + } + node = node->GetNext(); + } + + return -1; +} + + diff --git a/src/mac/classic/aga.cpp b/src/mac/classic/aga.cpp new file mode 100644 index 0000000000..543fc10137 --- /dev/null +++ b/src/mac/classic/aga.cpp @@ -0,0 +1,2 @@ +// NOT NEEDED ANYMORE + diff --git a/src/mac/classic/app.cpp b/src/mac/classic/app.cpp new file mode 100644 index 0000000000..613c323b92 --- /dev/null +++ b/src/mac/classic/app.cpp @@ -0,0 +1,2439 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: app.cpp +// Purpose: wxApp +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "app.h" +#endif + +#include "wx/defs.h" + +#include "wx/window.h" +#include "wx/frame.h" +#include "wx/button.h" +#include "wx/app.h" +#include "wx/utils.h" +#include "wx/gdicmn.h" +#include "wx/pen.h" +#include "wx/brush.h" +#include "wx/cursor.h" +#include "wx/intl.h" +#include "wx/icon.h" +#include "wx/palette.h" +#include "wx/dc.h" +#include "wx/dialog.h" +#include "wx/msgdlg.h" +#include "wx/log.h" +#include "wx/module.h" +#include "wx/memory.h" +#include "wx/tooltip.h" +#include "wx/textctrl.h" +#include "wx/menu.h" +#include "wx/docview.h" +#include "wx/filename.h" + +#include + +// mac + +#ifndef __DARWIN__ + #if __option(profile) + #include + #endif +#endif + +#include "apprsrc.h" + +#include "wx/mac/uma.h" +#include "wx/mac/macnotfy.h" + +#ifdef __DARWIN__ +# include +# if defined(WXMAKINGDLL_CORE) +# include +# endif +#else +# include +# include +# include +# include +# include +#endif + +extern wxList wxPendingDelete; +extern wxList *wxWinMacWindowList; +extern wxList *wxWinMacControlList; +#if wxUSE_THREADS +extern size_t g_numberOfThreads; +#endif // wxUSE_THREADS + +// statics for implementation + +static bool s_inYield = FALSE; + +#if TARGET_CARBON +static bool s_inReceiveEvent = FALSE ; +static EventTime sleepTime = kEventDurationNoWait ; +#else +static long sleepTime = 0 ; +#endif + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler) +BEGIN_EVENT_TABLE(wxApp, wxEvtHandler) + EVT_IDLE(wxApp::OnIdle) + EVT_END_SESSION(wxApp::OnEndSession) + EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession) +END_EVENT_TABLE() +#endif + + +const short kMacMinHeap = (29 * 1024) ; +// platform specific static variables + +const short kwxMacMenuBarResource = 1 ; +const short kwxMacAppleMenuId = 1 ; + +WXHRGN wxApp::s_macCursorRgn = NULL; +wxWindow* wxApp::s_captureWindow = NULL ; +int wxApp::s_lastMouseDown = 0 ; +long wxApp::sm_lastMessageTime = 0; +long wxApp::s_lastModifiers = 0 ; + + +bool wxApp::s_macSupportPCMenuShortcuts = true ; +long wxApp::s_macAboutMenuItemId = wxID_ABOUT ; +long wxApp::s_macPreferencesMenuItemId = wxID_PREFERENCES ; +long wxApp::s_macExitMenuItemId = wxID_EXIT ; +wxString wxApp::s_macHelpMenuTitleName = wxT("&Help") ; + +// Normally we're not a plugin +bool wxApp::sm_isEmbedded = false; +//---------------------------------------------------------------------- +// Core Apple Event Support +//---------------------------------------------------------------------- + +pascal OSErr AEHandleODoc( const AppleEvent *event , AppleEvent *reply , long refcon ) ; +pascal OSErr AEHandleOApp( const AppleEvent *event , AppleEvent *reply , long refcon ) ; +pascal OSErr AEHandlePDoc( const AppleEvent *event , AppleEvent *reply , long refcon ) ; +pascal OSErr AEHandleQuit( const AppleEvent *event , AppleEvent *reply , long refcon ) ; +pascal OSErr AEHandleRApp( const AppleEvent *event , AppleEvent *reply , long refcon ) ; + +pascal OSErr AEHandleODoc( const AppleEvent *event , AppleEvent *reply , long WXUNUSED(refcon) ) +{ + return wxTheApp->MacHandleAEODoc( (AppleEvent*) event , reply) ; +} + +pascal OSErr AEHandleOApp( const AppleEvent *event , AppleEvent *reply , long WXUNUSED(refcon) ) +{ + return wxTheApp->MacHandleAEOApp( (AppleEvent*) event , reply ) ; +} + +pascal OSErr AEHandlePDoc( const AppleEvent *event , AppleEvent *reply , long WXUNUSED(refcon) ) +{ + return wxTheApp->MacHandleAEPDoc( (AppleEvent*) event , reply ) ; +} + +pascal OSErr AEHandleQuit( const AppleEvent *event , AppleEvent *reply , long WXUNUSED(refcon) ) +{ + return wxTheApp->MacHandleAEQuit( (AppleEvent*) event , reply) ; +} + +pascal OSErr AEHandleRApp( const AppleEvent *event , AppleEvent *reply , long WXUNUSED(refcon) ) +{ + return wxTheApp->MacHandleAERApp( (AppleEvent*) event , reply) ; +} + +// AEODoc Calls MacOpenFile on each of the files passed + +short wxApp::MacHandleAEODoc(const WXEVENTREF event, WXEVENTREF WXUNUSED(reply)) +{ + AEDescList docList; + AEKeyword keywd; + DescType returnedType; + Size actualSize; + long itemsInList; + FSSpec theSpec; + OSErr err; + short i; + err = AEGetParamDesc((AppleEvent *)event, keyDirectObject, typeAEList,&docList); + if (err != noErr) + return err; + + err = AECountItems(&docList, &itemsInList); + if (err != noErr) + return err; + + ProcessSerialNumber PSN ; + PSN.highLongOfPSN = 0 ; + PSN.lowLongOfPSN = kCurrentProcess ; + SetFrontProcess( &PSN ) ; + + for (i = 1; i <= itemsInList; i++) { + AEGetNthPtr(&docList, i, typeFSS, &keywd, &returnedType, + (Ptr) & theSpec, sizeof(theSpec), &actualSize); + wxString fName = wxMacFSSpec2MacFilename(&theSpec); + MacOpenFile(fName); + } + return noErr; +} + +// AEPDoc Calls MacPrintFile on each of the files passed + +short wxApp::MacHandleAEPDoc(const WXEVENTREF event , WXEVENTREF WXUNUSED(reply)) +{ + AEDescList docList; + AEKeyword keywd; + DescType returnedType; + Size actualSize; + long itemsInList; + FSSpec theSpec; + OSErr err; + short i; + err = AEGetParamDesc((AppleEvent *)event, keyDirectObject, typeAEList,&docList); + if (err != noErr) + return err; + + err = AECountItems(&docList, &itemsInList); + if (err != noErr) + return err; + + ProcessSerialNumber PSN ; + PSN.highLongOfPSN = 0 ; + PSN.lowLongOfPSN = kCurrentProcess ; + SetFrontProcess( &PSN ) ; + + for (i = 1; i <= itemsInList; i++) { + AEGetNthPtr(&docList, i, typeFSS, &keywd, &returnedType, + (Ptr) & theSpec, sizeof(theSpec), &actualSize); + wxString fName = wxMacFSSpec2MacFilename(&theSpec); + MacPrintFile(fName); + } + return noErr; +} + +// AEOApp calls MacNewFile + +short wxApp::MacHandleAEOApp(const WXEVENTREF WXUNUSED(event) , WXEVENTREF WXUNUSED(reply)) +{ + MacNewFile() ; + return noErr ; +} + +// AEQuit attempts to quit the application + +short wxApp::MacHandleAEQuit(const WXEVENTREF WXUNUSED(event) , WXEVENTREF WXUNUSED(reply)) +{ + wxWindow* win = GetTopWindow() ; + if ( win ) + { + wxCommandEvent exitEvent(wxEVT_COMMAND_MENU_SELECTED, s_macExitMenuItemId); + if (!win->ProcessEvent(exitEvent)) + win->Close(TRUE ) ; + } + else + { + ExitMainLoop() ; + } + return noErr ; +} + +// AEROApp calls MacReopenApp + +short wxApp::MacHandleAERApp(const WXEVENTREF WXUNUSED(event) , WXEVENTREF WXUNUSED(reply)) +{ + MacReopenApp() ; + return noErr ; +} + + +//---------------------------------------------------------------------- +// Support Routines linking the Mac...File Calls to the Document Manager +//---------------------------------------------------------------------- + +void wxApp::MacOpenFile(const wxString & fileName ) +{ + wxDocManager* dm = wxDocManager::GetDocumentManager() ; + if ( dm ) + dm->CreateDocument(fileName , wxDOC_SILENT ) ; +} + +void wxApp::MacPrintFile(const wxString & fileName ) +{ + wxDocManager* dm = wxDocManager::GetDocumentManager() ; + if ( dm ) + { + wxDocument *doc = dm->CreateDocument(fileName , wxDOC_SILENT ) ; + if ( doc ) + { + wxView* view = doc->GetFirstView() ; + if( view ) + { + wxPrintout *printout = view->OnCreatePrintout(); + if (printout) + { + wxPrinter printer; + printer.Print(view->GetFrame(), printout, TRUE); + delete printout; + } + } + if (doc->Close()) + { + doc->DeleteAllViews(); + dm->RemoveDocument(doc) ; + } + } + } +} + +void wxApp::MacNewFile() +{ +} + +void wxApp::MacReopenApp() +{ + // eventually check for open docs, if none, call MacNewFile +} + +//---------------------------------------------------------------------- +// Carbon Event Handler +//---------------------------------------------------------------------- + +#if TARGET_CARBON + + static const EventTypeSpec eventList[] = + { + { kEventClassCommand, kEventProcessCommand } , + { kEventClassCommand, kEventCommandUpdateStatus } , + + { kEventClassMenu, kEventMenuOpening }, + { kEventClassMenu, kEventMenuClosed }, + { kEventClassMenu, kEventMenuTargetItem }, + + { kEventClassApplication , kEventAppActivated } , + { kEventClassApplication , kEventAppDeactivated } , + // handling the quit event is not recommended by apple + // rather using the quit apple event - which we do + + { kEventClassAppleEvent , kEventAppleEvent } , + + { kEventClassMouse , kEventMouseDown } , + { kEventClassMouse , kEventMouseMoved } , + { kEventClassMouse , kEventMouseUp } , + { kEventClassMouse , kEventMouseDragged } , + { 'WXMC' , 'WXMC' } + } ; + +static pascal OSStatus +MenuEventHandler( EventHandlerCallRef handler , EventRef event , void *data ) +{ + wxMenuBar* mbar = wxMenuBar::MacGetInstalledMenuBar(); + + if ( mbar ) + { + wxFrame* win = mbar->GetFrame(); + if ( win ) + { + + // VZ: we could find the menu from its handle here by examining all + // the menus in the menu bar recursively but knowing that neither + // wxMSW nor wxGTK do it why bother... + #if 0 + MenuRef menuRef; + + GetEventParameter(event, + kEventParamDirectObject, + typeMenuRef, NULL, + sizeof(menuRef), NULL, + &menuRef); + #endif // 0 + + wxEventType type=0; + MenuCommand cmd=0; + switch (GetEventKind(event)) + { + case kEventMenuOpening: + type = wxEVT_MENU_OPEN; + break; + case kEventMenuClosed: + type = wxEVT_MENU_CLOSE; + break; + case kEventMenuTargetItem: + type = wxEVT_MENU_HIGHLIGHT; + GetEventParameter(event, kEventParamMenuCommand, + typeMenuCommand, NULL, + sizeof(cmd), NULL, &cmd); + if (cmd == 0) return eventNotHandledErr; + break; + default: + wxFAIL_MSG(wxT("Unexpected menu event kind")); + break; + } + + wxMenuEvent wxevent(type, cmd); + wxevent.SetEventObject(win); + + (void)win->GetEventHandler()->ProcessEvent(wxevent); + } + } + + return eventNotHandledErr; +} + +// due to the rather low-level event API of wxWindows, we cannot use RunApplicationEventLoop +// but have to use ReceiveNextEvent dealing with events manually, therefore we also have +// deal with clicks in the menu bar explicitely + +pascal OSStatus wxMacWindowEventHandler( EventHandlerCallRef handler , EventRef event , void *data ) ; + +static pascal OSStatus MouseEventHandler( EventHandlerCallRef handler , EventRef event , void *data ) +{ + OSStatus result = eventNotHandledErr ; + + Point point ; + UInt32 modifiers = 0; + EventMouseButton button = 0 ; + UInt32 click = 0 ; + + GetEventParameter( event, kEventParamMouseLocation, typeQDPoint, NULL, + sizeof( Point ), NULL, &point ); + GetEventParameter( event, kEventParamKeyModifiers, typeUInt32, NULL, + sizeof( UInt32 ), NULL, &modifiers ); + GetEventParameter( event, kEventParamMouseButton, typeMouseButton, NULL, + sizeof( EventMouseButton ), NULL, &button ); + GetEventParameter( event, kEventParamClickCount, typeUInt32, NULL, + sizeof( UInt32 ), NULL, &click ); + + if ( button == 0 || GetEventKind( event ) == kEventMouseUp ) + modifiers += btnState ; + + + switch( GetEventKind(event) ) + { + case kEventMouseDown : + { + WindowRef window ; + + short windowPart = ::FindWindow(point, &window); + + if ( windowPart == inMenuBar ) + { + MenuSelect( point ) ; + result = noErr ; + } + } + break ; + case kEventMouseDragged : + case kEventMouseUp : + { + if ( wxTheApp->s_captureWindow ) + wxMacWindowEventHandler( handler , event , (void*) wxTheApp->s_captureWindow->MacGetTopLevelWindow() ) ; + } + break ; + case kEventMouseMoved : + { + wxTheApp->MacHandleMouseMovedEvent( point.h , point.v , modifiers , EventTimeToTicks( GetEventTime( event ) ) ) ; + result = noErr ; + break ; + } + break ; + } + + return result ; +} + +static pascal OSStatus CommandEventHandler( EventHandlerCallRef handler , EventRef event , void *data ) +{ + OSStatus result = eventNotHandledErr ; + + HICommand command ; + + GetEventParameter( event, kEventParamDirectObject, typeHICommand, NULL, + sizeof( HICommand ), NULL, &command ); + + MenuCommand id = command.commandID ; + if ( id == kHICommandPreferences ) + id = wxApp::s_macPreferencesMenuItemId ; + + wxMenuBar* mbar = wxMenuBar::MacGetInstalledMenuBar() ; + wxMenu* menu = NULL ; + wxMenuItem* item = NULL ; + + if ( mbar ) + { + item = mbar->FindItem( id , &menu ) ; + // it is not 100 % sure that an menu of id 0 is really ours, safety check + if ( id == 0 && menu != NULL && menu->GetHMenu() != command.menu.menuRef ) + { + item = NULL ; + menu = NULL ; + } + } + + if ( item == NULL || menu == NULL || mbar == NULL ) + return result ; + + switch( GetEventKind( event ) ) + { + case kEventProcessCommand : + { + if (item->IsCheckable()) + { + item->Check( !item->IsChecked() ) ; + } + + menu->SendEvent( id , item->IsCheckable() ? item->IsChecked() : -1 ) ; + result = noErr ; + } + break ; + case kEventCommandUpdateStatus: + // eventually trigger an updateui round + result = noErr ; + break ; + default : + break ; + } + + return result ; +} + +static pascal OSStatus ApplicationEventHandler( EventHandlerCallRef handler , EventRef event , void *data ) +{ + OSStatus result = eventNotHandledErr ; + switch ( GetEventKind( event ) ) + { + case kEventAppActivated : + { + if ( wxTheApp ) + wxTheApp->MacResume( true ) ; + result = noErr ; + } + break ; + case kEventAppDeactivated : + { + if ( wxTheApp ) + wxTheApp->MacSuspend( true ) ; + result = noErr ; + } + break ; + default : + break ; + } + return result ; +} + +pascal OSStatus wxAppEventHandler( EventHandlerCallRef handler , EventRef event , void *data ) +{ + OSStatus result = eventNotHandledErr ; + switch( GetEventClass( event ) ) + { + case kEventClassCommand : + result = CommandEventHandler( handler , event , data ) ; + break ; + case kEventClassApplication : + result = ApplicationEventHandler( handler , event , data ) ; + break ; + case kEventClassMenu : + result = MenuEventHandler( handler , event , data ) ; + break ; + case kEventClassMouse : + result = MouseEventHandler( handler , event , data ) ; + break ; + case kEventClassAppleEvent : + { + EventRecord rec ; + wxMacConvertEventToRecord( event , &rec ) ; + result = AEProcessAppleEvent( &rec ) ; + } + break ; + default : + break ; + } + + return result ; +} + +DEFINE_ONE_SHOT_HANDLER_GETTER( wxAppEventHandler ) + +#endif + +#if defined(WXMAKINGDLL_CORE) && !defined(__DARWIN__) +// we know it's there ;-) +WXIMPORT char std::__throws_bad_alloc ; +#endif + +bool wxApp::Initialize(int& argc, wxChar **argv) +{ + int error = 0 ; + + // Mac-specific + + UMAInitToolbox( 4, sm_isEmbedded ) ; + SetEventMask( everyEvent ) ; + UMAShowWatchCursor() ; + +#if defined(WXMAKINGDLL_CORE) && defined(__DARWIN__) + // open shared library resources from here since we don't have + // __wxinitialize in Mach-O shared libraries + wxStAppResource::OpenSharedLibraryResource(NULL); +#endif + +#ifndef __DARWIN__ + // test the minimal configuration necessary + +# if !TARGET_CARBON + long theSystem ; + long theMachine; + + if (Gestalt(gestaltMachineType, &theMachine) != noErr) + { + error = kMacSTRWrongMachine; + } + else if (theMachine < gestaltMacPlus) + { + error = kMacSTRWrongMachine; + } + else if (Gestalt(gestaltSystemVersion, &theSystem) != noErr ) + { + error = kMacSTROldSystem ; + } + else if ( theSystem < 0x0860 ) + { + error = kMacSTROldSystem ; + } + else if ((long)GetApplLimit() - (long)ApplicationZone() < kMacMinHeap) + { + error = kMacSTRSmallSize; + } +# endif + /* + else + { + if ( !UMAHasAppearance() ) + { + error = kMacSTRNoPre8Yet ; + } + } + */ +#endif + + // if we encountered any problems so far, give the error code and exit immediately + + if ( error ) + { + wxStAppResource resload ; + short itemHit; + Str255 message; + + GetIndString(message, 128, error); + UMAShowArrowCursor() ; + ParamText("\pFatal Error", message, (ConstStr255Param)"\p", (ConstStr255Param)"\p"); + itemHit = Alert(128, nil); + return FALSE ; + } + +#ifndef __DARWIN__ +# if __option(profile) + ProfilerInit( collectDetailed, bestTimeBase , 40000 , 50 ) ; +# endif +#endif + +#ifndef __DARWIN__ + // now avoid exceptions thrown for new (bad_alloc) + // FIXME CS for some changes outside wxMac does not compile anymore +#if 0 + std::__throws_bad_alloc = 0 ; +#endif + +#endif + + s_macCursorRgn = ::NewRgn() ; + + // Mac OS X passes a process serial number command line argument when + // the application is launched from the Finder. This argument must be + // removed from the command line arguments before being handled by the + // application (otherwise applications would need to handle it) + if ( argc > 1 ) + { + static const wxChar *ARG_PSN = _T("-psn_"); + if ( wxStrncmp(argv[1], ARG_PSN, wxStrlen(ARG_PSN)) == 0 ) + { + // remove this argument + --argc; + memmove(argv + 1, argv + 2, argc * sizeof(char *)); + } + } + + if ( !wxAppBase::Initialize(argc, argv) ) + return false; + +#if wxUSE_INTL + wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding()); +#endif + + + wxWinMacWindowList = new wxList(wxKEY_INTEGER); + wxWinMacControlList = new wxList(wxKEY_INTEGER); + + wxMacCreateNotifierTable() ; + + UMAShowArrowCursor() ; + + return true; +} + +bool wxApp::OnInitGui() +{ + if( !wxAppBase::OnInitGui() ) + return false ; + +#if TARGET_CARBON + InstallStandardEventHandler( GetApplicationEventTarget() ) ; + + if (!sm_isEmbedded) + { + InstallApplicationEventHandler( + GetwxAppEventHandlerUPP(), + GetEventTypeCount(eventList), eventList, wxTheApp, (EventHandlerRef *)&(wxTheApp->m_macEventHandler)); + } +#endif + + if (!sm_isEmbedded) + { +#if defined(UNIVERSAL_INTERFACES_VERSION) && (UNIVERSAL_INTERFACES_VERSION >= 0x0340) + AEInstallEventHandler( kCoreEventClass , kAEOpenDocuments , + NewAEEventHandlerUPP(AEHandleODoc) , + 0 , FALSE ) ; + AEInstallEventHandler( kCoreEventClass , kAEOpenApplication , + NewAEEventHandlerUPP(AEHandleOApp) , + 0 , FALSE ) ; + AEInstallEventHandler( kCoreEventClass , kAEPrintDocuments , + NewAEEventHandlerUPP(AEHandlePDoc) , + 0 , FALSE ) ; + AEInstallEventHandler( kCoreEventClass , kAEReopenApplication , + NewAEEventHandlerUPP(AEHandleRApp) , + 0 , FALSE ) ; + AEInstallEventHandler( kCoreEventClass , kAEQuitApplication , + NewAEEventHandlerUPP(AEHandleQuit) , + 0 , FALSE ) ; +#else + AEInstallEventHandler( kCoreEventClass , kAEOpenDocuments , + NewAEEventHandlerProc(AEHandleODoc) , + 0 , FALSE ) ; + AEInstallEventHandler( kCoreEventClass , kAEOpenApplication , + NewAEEventHandlerProc(AEHandleOApp) , + 0 , FALSE ) ; + AEInstallEventHandler( kCoreEventClass , kAEPrintDocuments , + NewAEEventHandlerProc(AEHandlePDoc) , + 0 , FALSE ) ; + AEInstallEventHandler( kCoreEventClass , kAEReopenApplication , + NewAEEventHandlerProc(AEHandleRApp) , + 0 , FALSE ) ; + AEInstallEventHandler( kCoreEventClass , kAEQuitApplication , + NewAEEventHandlerProc(AEHandleQuit) , + 0 , FALSE ) ; +#endif + } + + return TRUE ; +} + +void wxApp::CleanUp() +{ + wxToolTip::RemoveToolTips() ; + + // One last chance for pending objects to be cleaned up + wxTheApp->DeletePendingObjects(); + + wxMacDestroyNotifierTable() ; + + delete wxWinMacWindowList ; + wxWinMacWindowList = NULL; + + delete wxWinMacControlList ; + wxWinMacControlList = NULL; + +#ifndef __DARWIN__ +# if __option(profile) + ProfilerDump( (StringPtr)"\papp.prof" ) ; + ProfilerTerm() ; +# endif +#endif + +#if defined(WXMAKINGDLL_CORE) && defined(__DARWIN__) + // close shared library resources from here since we don't have + // __wxterminate in Mach-O shared libraries + wxStAppResource::CloseSharedLibraryResource(); +#endif + + UMACleanupToolbox() ; + if (s_macCursorRgn) { + ::DisposeRgn((RgnHandle)s_macCursorRgn); + } + + #if 0 + TerminateAE() ; + #endif + + wxAppBase::CleanUp(); +} + +//---------------------------------------------------------------------- +// misc initialization stuff +//---------------------------------------------------------------------- + +// extern variable for shared library resource id +// need to be able to find it with NSLookupAndBindSymbol +short gSharedLibraryResource = kResFileNotOpened ; + +#if defined(WXMAKINGDLL_CORE) && defined(__DARWIN__) +CFBundleRef gSharedLibraryBundle = NULL; +#endif /* WXMAKINGDLL_CORE && __DARWIN__ */ + +wxStAppResource::wxStAppResource() +{ + m_currentRefNum = CurResFile() ; + if ( gSharedLibraryResource != kResFileNotOpened ) + { + UseResFile( gSharedLibraryResource ) ; + } +} + +wxStAppResource::~wxStAppResource() +{ + if ( m_currentRefNum != kResFileNotOpened ) + { + UseResFile( m_currentRefNum ) ; + } +} + +void wxStAppResource::OpenSharedLibraryResource(const void *initBlock) +{ + gSharedLibraryResource = kResFileNotOpened; + +#ifdef WXMAKINGDLL_CORE + if ( initBlock != NULL ) { + const CFragInitBlock *theInitBlock = (const CFragInitBlock *)initBlock; + FSSpec *fileSpec = NULL; + + if (theInitBlock->fragLocator.where == kDataForkCFragLocator) { + fileSpec = theInitBlock->fragLocator.u.onDisk.fileSpec; + } + else if (theInitBlock->fragLocator.where == kResourceCFragLocator) { + fileSpec = theInitBlock->fragLocator.u.inSegs.fileSpec; + } + + if (fileSpec != NULL) { + gSharedLibraryResource = FSpOpenResFile(fileSpec, fsRdPerm); + } + } + else { +#ifdef __DARWIN__ + // Open the shared library resource file if it is not yet open + NSSymbol theSymbol; + NSModule theModule; + const char *theLibPath; + + gSharedLibraryBundle = CFBundleGetBundleWithIdentifier(CFSTR("com.wxwindows.wxWindows")); + if (gSharedLibraryBundle != NULL) { + // wxWindows has been bundled into a framework + // load the framework resources + + gSharedLibraryResource = CFBundleOpenBundleResourceMap(gSharedLibraryBundle); + } + else { + // wxWindows is a simple dynamic shared library + // load the resources from the data fork of a separate resource file + wxString theResPath; + wxString theName; + FSRef theResRef; + OSErr theErr = noErr; + + // get the library path + theSymbol = NSLookupAndBindSymbol("_gSharedLibraryResource"); + theModule = NSModuleForSymbol(theSymbol); + theLibPath = NSLibraryNameForModule(theModule); + + // if we call wxLogDebug from here then, as wxTheApp hasn't been + // created yet when we're called from wxApp::Initialize(), wxLog + // is going to create a default stderr-based log target instead of + // the expected normal GUI one -- don't do it, if we really want + // to see this message just use fprintf() here +#if 0 + wxLogDebug( wxT("wxMac library installation name is '%s'"), + theLibPath ); +#endif + + // allocate copy to replace .dylib.* extension with .rsrc + if (theLibPath != NULL) { +#if wxUSE_UNICODE + theResPath = wxString(theLibPath, wxConvLocal); +#else + theResPath = wxString(theLibPath); +#endif + // replace '_core' with '' in case of multi-lib build + theResPath.Replace(wxT("_core"), wxEmptyString); + // replace ".dylib" shared library extension with ".rsrc" + theResPath.Replace(wxT(".dylib"), wxT(".rsrc")); + // Find the begining of the filename + theName = theResPath.AfterLast('/'); + +#if 0 + wxLogDebug( wxT("wxMac resources file name is '%s'"), + theResPath.mb_str() ); +#endif + + theErr = FSPathMakeRef((UInt8 *) theResPath.mb_str(), &theResRef, false); + if (theErr != noErr) { + // try in current directory (using name only) + theErr = FSPathMakeRef((UInt8 *) theName.mb_str(), &theResRef, false); + } + + // open the resource file + if (theErr == noErr) { + theErr = FSOpenResourceFile( &theResRef, 0, NULL, fsRdPerm, + &gSharedLibraryResource); + } + if (theErr != noErr) { +#ifdef __WXDEBUG__ + wxLogDebug( wxT("unable to open wxMac resource file '%s'\n"), + theResPath.mb_str() ); +#endif // __WXDEBUG__ + } + + } + } +#endif /* __DARWIN__ */ + } +#endif /* WXMAKINGDLL_CORE */ +} + +void wxStAppResource::CloseSharedLibraryResource() +{ +#ifdef WXMAKINGDLL_CORE + // Close the shared library resource file + if (gSharedLibraryResource != kResFileNotOpened) { +#ifdef __DARWIN__ + if (gSharedLibraryBundle != NULL) { + CFBundleCloseBundleResourceMap(gSharedLibraryBundle, + gSharedLibraryResource); + gSharedLibraryBundle = NULL; + } + else +#endif /* __DARWIN__ */ + { + CloseResFile(gSharedLibraryResource); + } + gSharedLibraryResource = kResFileNotOpened; + } +#endif /* WXMAKINGDLL_CORE */ +} + +#if defined(WXMAKINGDLL_CORE) && !defined(__DARWIN__) + +// for shared libraries we have to manually get the correct resource +// ref num upon initializing and releasing when terminating, therefore +// the __wxinitialize and __wxterminate must be used + +extern "C" { + void __sinit(void); /* (generated by linker) */ + pascal OSErr __initialize(const CFragInitBlock *theInitBlock); + pascal void __terminate(void); +} + +pascal OSErr __wxinitialize(const CFragInitBlock *theInitBlock) +{ + wxStAppResource::OpenSharedLibraryResource( theInitBlock ) ; + return __initialize( theInitBlock ) ; +} + +pascal void __wxterminate(void) +{ + wxStAppResource::CloseSharedLibraryResource() ; + __terminate() ; +} + +#endif /* WXMAKINGDLL_CORE && !__DARWIN__ */ + +#if TARGET_CARBON + +bool wxMacConvertEventToRecord( EventRef event , EventRecord *rec) +{ + bool converted = ConvertEventRefToEventRecord( event,rec) ; + OSStatus err = noErr ; + if ( !converted ) + { + switch( GetEventClass( event ) ) + { + case kEventClassKeyboard : + { + converted = true ; + switch( GetEventKind(event) ) + { + case kEventRawKeyDown : + rec->what = keyDown ; + break ; + case kEventRawKeyRepeat : + rec->what = autoKey ; + break ; + case kEventRawKeyUp : + rec->what = keyUp ; + break ; + case kEventRawKeyModifiersChanged : + rec->what = nullEvent ; + break ; + default : + converted = false ; + break ; + } + if ( converted ) + { + UInt32 keyCode ; + unsigned char charCode ; + UInt32 modifiers ; + GetMouse( &rec->where) ; + + err = GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, 4, NULL, &modifiers); + err = GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, 4, NULL, &keyCode); + err = GetEventParameter(event, kEventParamKeyMacCharCodes, typeChar, NULL, 1, NULL, &charCode); + rec->modifiers = modifiers ; + rec->message = (keyCode << 8 ) + charCode ; + } + } + break ; + case kEventClassTextInput : + { + switch( GetEventKind( event ) ) + { + case kEventTextInputUnicodeForKeyEvent : + { + EventRef rawEvent ; + err = GetEventParameter( event , kEventParamTextInputSendKeyboardEvent ,typeEventRef,NULL,sizeof(rawEvent),NULL,&rawEvent ) ; + converted = true ; + { + UInt32 keyCode ; + unsigned char charCode ; + UInt32 modifiers ; + GetMouse( &rec->where) ; + rec->what = keyDown ; + err = GetEventParameter(rawEvent, kEventParamKeyModifiers, typeUInt32, NULL, 4, NULL, &modifiers); + err = GetEventParameter(rawEvent, kEventParamKeyCode, typeUInt32, NULL, 4, NULL, &keyCode); + err = GetEventParameter(rawEvent, kEventParamKeyMacCharCodes, typeChar, NULL, 1, NULL, &charCode); + rec->modifiers = modifiers ; + rec->message = (keyCode << 8 ) + charCode ; + } + } + break ; + default : + break ; + } + } + break ; + } + } + + return converted ; +} + +/* +pascal OSStatus wxMacApplicationEventHandler( EventHandlerCallRef handler , EventRef event , void *data ) +{ + OSStatus result = eventNotHandledErr ; + + EventRecord rec ; + switch ( GetEventClass( event ) ) + { + case kEventClassKeyboard : + if ( wxMacConvertEventToRecord( event , &rec ) ) + { + wxTheApp->MacHandleModifierEvents( &rec ) ; + wxTheApp->MacHandleOneEvent( &rec ) ; + result = noErr ; + } + break ; + case kEventClassTextInput : + if ( wxMacConvertEventToRecord( event , &rec ) ) + { + wxTheApp->MacHandleModifierEvents( &rec ) ; + wxTheApp->MacHandleOneEvent( &rec ) ; + result = noErr ; + } + break ; + default : + break ; + } + return result ; +} +*/ +#endif + +wxApp::wxApp() +{ + m_printMode = wxPRINT_WINDOWS; + m_auto3D = TRUE; + + m_macCurrentEvent = NULL ; +#if TARGET_CARBON + m_macCurrentEventHandlerCallRef = NULL ; +#endif +} + +int wxApp::MainLoop() +{ + m_keepGoing = TRUE; + + while (m_keepGoing) + { + MacDoOneEvent() ; + } + + return 0; +} + +void wxApp::ExitMainLoop() +{ + m_keepGoing = FALSE; +} + +// Is a message/event pending? +bool wxApp::Pending() +{ +#if TARGET_CARBON + // without the receive event (with pull param = false ) nothing is ever reported + EventRef theEvent; + ReceiveNextEvent (0, NULL, kEventDurationNoWait, false, &theEvent); + return GetNumEventsInQueue( GetMainEventQueue() ) > 0 ; +#else + EventRecord event ; + + return EventAvail( everyEvent , &event ) ; +#endif +} + +// Dispatch a message. +bool wxApp::Dispatch() +{ + MacDoOneEvent() ; + + return true; +} + +void wxApp::OnIdle(wxIdleEvent& event) +{ + wxAppBase::OnIdle(event); + + // If they are pending events, we must process them: pending events are + // either events to the threads other than main or events posted with + // wxPostEvent() functions + wxMacProcessNotifierAndPendingEvents(); + + if(!wxMenuBar::MacGetInstalledMenuBar() && wxMenuBar::MacGetCommonMenuBar()) + wxMenuBar::MacGetCommonMenuBar()->MacInstallMenuBar(); +} + +void wxApp::WakeUpIdle() +{ + wxMacWakeUp() ; +} + +void wxApp::Exit() +{ + wxApp::CleanUp(); + ::ExitToShell() ; +} + +void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event)) +{ + if (GetTopWindow()) + GetTopWindow()->Close(TRUE); +} + +// Default behaviour: close the application with prompts. The +// user can veto the close, and therefore the end session. +void wxApp::OnQueryEndSession(wxCloseEvent& event) +{ + if (GetTopWindow()) + { + if (!GetTopWindow()->Close(!event.CanVeto())) + event.Veto(TRUE); + } +} + +extern "C" void wxCYield() ; +void wxCYield() +{ + wxYield() ; +} + +// Yield to other processes + +bool wxApp::Yield(bool onlyIfNeeded) +{ + if (s_inYield) + { + if ( !onlyIfNeeded ) + { + wxFAIL_MSG( wxT("wxYield called recursively" ) ); + } + + return FALSE; + } + + s_inYield = TRUE; + +#if wxUSE_THREADS + YieldToAnyThread() ; +#endif + // by definition yield should handle all non-processed events +#if TARGET_CARBON + EventRef theEvent; + + OSStatus status = noErr ; + do + { + s_inReceiveEvent = true ; + status = ReceiveNextEvent(0, NULL,kEventDurationNoWait,true,&theEvent) ; + s_inReceiveEvent = false ; + + if ( status == eventLoopTimedOutErr ) + { + // make sure next time the event loop will trigger idle events + sleepTime = kEventDurationNoWait ; + } + else if ( status == eventLoopQuitErr ) + { + // according to QA1061 this may also occur when a WakeUp Process + // is executed + } + else + { + MacHandleOneEvent( theEvent ) ; + ReleaseEvent(theEvent); + } + } while( status == noErr ) ; +#else + EventRecord event ; + + // having a larger value here leads to large performance slowdowns + // so we cannot give background apps more processor time here + // we do so however having a large sleep value in the main event loop + sleepTime = 0 ; + + while ( !IsExiting() && WaitNextEvent(everyEvent, &event,sleepTime, (RgnHandle) wxApp::s_macCursorRgn)) + { + MacHandleModifierEvents( &event ) ; + MacHandleOneEvent( &event ); + if ( event.what != kHighLevelEvent ) + SetRectRgn( (RgnHandle) wxApp::s_macCursorRgn , event.where.h , event.where.v , event.where.h + 1 , event.where.v + 1 ) ; + } + MacHandleModifierEvents( &event ) ; +#endif + + wxMacProcessNotifierAndPendingEvents() ; + s_inYield = FALSE; + + return TRUE; +} + +// platform specifics + +void wxApp::MacSuspend( bool convertClipboard ) +{ +#if !TARGET_CARBON + // we have to deactive the top level windows manually + + wxWindowListNode* node = wxTopLevelWindows.GetFirst(); + while (node) + { + wxTopLevelWindow* win = (wxTopLevelWindow*) node->Data(); +#if TARGET_CARBON +#if 0 // having problems right now with that + if (!win->HasFlag(wxSTAY_ON_TOP)) +#endif +#endif + win->MacActivate( ((EventRecord*) MacGetCurrentEvent())->when , false ) ; + + node = node->GetNext(); + } + + ::HideFloatingWindows() ; +#endif + s_lastMouseDown = 0 ; + + if( convertClipboard ) + { + MacConvertPrivateToPublicScrap() ; + } +} + +extern wxList wxModalDialogs; + +void wxApp::MacResume( bool convertClipboard ) +{ + s_lastMouseDown = 0 ; + if( convertClipboard ) + { + MacConvertPublicToPrivateScrap() ; + } + +#if !TARGET_CARBON + ::ShowFloatingWindows() ; + // raise modal dialogs in case a non modal window was selected to activate the app + + wxNode* node = wxModalDialogs.GetFirst(); + while (node) + { + wxDialog* dialog = (wxDialog *) node->GetData(); + dialog->Raise(); + + node = node->GetNext(); + } +#endif +} + +void wxApp::MacConvertPrivateToPublicScrap() +{ +} + +void wxApp::MacConvertPublicToPrivateScrap() +{ +} + +void wxApp::MacDoOneEvent() +{ +#if TARGET_CARBON + EventRef theEvent; + + s_inReceiveEvent = true ; + OSStatus status = ReceiveNextEvent(0, NULL,sleepTime,true,&theEvent) ; + s_inReceiveEvent = false ; + if ( status == eventLoopTimedOutErr ) + { + if ( wxTheApp->ProcessIdle() ) + sleepTime = kEventDurationNoWait ; + else + { +#if wxUSE_THREADS + if (g_numberOfThreads) + { + sleepTime = kEventDurationNoWait; + } + else +#endif // wxUSE_THREADS + { + sleepTime = kEventDurationSecond; + } + } + } + else if ( status == eventLoopQuitErr ) + { + // according to QA1061 this may also occur when a WakeUp Process + // is executed + } + else + { + MacHandleOneEvent( theEvent ) ; + ReleaseEvent(theEvent); + sleepTime = kEventDurationNoWait ; + } +#else + EventRecord event ; + + EventMask eventMask = everyEvent ; + + if (WaitNextEvent(eventMask, &event, sleepTime, (RgnHandle) s_macCursorRgn)) + { + MacHandleModifierEvents( &event ) ; + MacHandleOneEvent( &event ); + } + else + { + MacHandleModifierEvents( &event ) ; + // idlers + WindowPtr window = ::FrontWindow() ; + if ( window ) + ::IdleControls( window ) ; + + if ( wxTheApp->ProcessIdle() ) + sleepTime = kEventDurationNoWait; + else + { +#if wxUSE_THREADS + if (g_numberOfThreads) + { + sleepTime = kEventDurationNoWait; + } + else +#endif // wxUSE_THREADS + { + sleepTime = kEventDurationSecond; + } + } + } + if ( event.what != kHighLevelEvent ) + SetRectRgn( (RgnHandle) s_macCursorRgn , event.where.h , event.where.v , event.where.h + 1 , event.where.v + 1 ) ; +#endif + // repeaters + + DeletePendingObjects() ; + wxMacProcessNotifierAndPendingEvents() ; +} + +/*virtual*/ void wxApp::MacHandleUnhandledEvent( WXEVENTREF evr ) +{ + // Override to process unhandled events as you please +} + +void wxApp::MacHandleOneEvent( WXEVENTREF evr ) +{ +#if TARGET_CARBON + EventTargetRef theTarget; + theTarget = GetEventDispatcherTarget(); + m_macCurrentEvent = evr ; + OSStatus status = SendEventToEventTarget ((EventRef) evr , theTarget); + if(status == eventNotHandledErr) + { + MacHandleUnhandledEvent(evr); + } +#else + EventRecord* ev = (EventRecord*) evr ; + m_macCurrentEvent = ev ; + + wxApp::sm_lastMessageTime = ev->when ; + + switch (ev->what) + { + case mouseDown: + MacHandleMouseDownEvent( ev ) ; + if ( ev->modifiers & controlKey ) + s_lastMouseDown = 2; + else + s_lastMouseDown = 1; + break; + case mouseUp: + if ( s_lastMouseDown == 2 ) + { + ev->modifiers |= controlKey ; + } + else + { + ev->modifiers &= ~controlKey ; + } + MacHandleMouseUpEvent( ev ) ; + s_lastMouseDown = 0; + break; + case activateEvt: + MacHandleActivateEvent( ev ) ; + break; + case updateEvt: + // In embedded mode we first let the UnhandledEvent function + // try to handle the update event. If we handle it ourselves + // first and then pass it on, the host's windows won't update. + MacHandleUnhandledEvent(ev); + MacHandleUpdateEvent( ev ) ; + break; + case keyDown: + case autoKey: + MacHandleKeyDownEvent( ev ) ; + break; + case keyUp: + MacHandleKeyUpEvent( ev ) ; + break; + case diskEvt: + MacHandleDiskEvent( ev ) ; + break; + case osEvt: + MacHandleOSEvent( ev ) ; + break; + case kHighLevelEvent: + MacHandleHighLevelEvent( ev ) ; + break; + default: + break; + } +#endif + wxMacProcessNotifierAndPendingEvents() ; +} + +#if !TARGET_CARBON +bool s_macIsInModalLoop = false ; + +void wxApp::MacHandleModifierEvents( WXEVENTREF evr ) +{ + EventRecord* ev = (EventRecord*) evr ; + if ( ev->modifiers != s_lastModifiers && wxWindow::FindFocus() != NULL ) + { + wxKeyEvent event(wxEVT_KEY_DOWN); + + event.m_shiftDown = ev->modifiers & shiftKey; + event.m_controlDown = ev->modifiers & controlKey; + event.m_altDown = ev->modifiers & optionKey; + event.m_metaDown = ev->modifiers & cmdKey; + + event.m_x = ev->where.h; + event.m_y = ev->where.v; + event.m_timeStamp = ev->when; + wxWindow* focus = wxWindow::FindFocus() ; + event.SetEventObject(focus); + + if ( (ev->modifiers ^ s_lastModifiers ) & controlKey ) + { + event.m_keyCode = WXK_CONTROL ; + event.SetEventType( ( ev->modifiers & controlKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ; + focus->GetEventHandler()->ProcessEvent( event ) ; + } + if ( (ev->modifiers ^ s_lastModifiers ) & shiftKey ) + { + event.m_keyCode = WXK_SHIFT ; + event.SetEventType( ( ev->modifiers & shiftKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ; + focus->GetEventHandler()->ProcessEvent( event ) ; + } + if ( (ev->modifiers ^ s_lastModifiers ) & optionKey ) + { + event.m_keyCode = WXK_ALT ; + event.SetEventType( ( ev->modifiers & optionKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ; + focus->GetEventHandler()->ProcessEvent( event ) ; + } + if ( ( ev->modifiers ^ s_lastModifiers ) & cmdKey ) + { + event.m_keyCode = WXK_COMMAND ; + event.SetEventType( ( ev->modifiers & cmdKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ; + focus->GetEventHandler()->ProcessEvent( event ) ; + } + s_lastModifiers = ev->modifiers ; + } +} + +void wxApp::MacHandleHighLevelEvent( WXEVENTREF evr ) +{ + // we must avoid reentrancy problems when processing high level events eg printing + bool former = s_inYield ; + s_inYield = TRUE ; + EventRecord* ev = (EventRecord*) evr ; + ::AEProcessAppleEvent( ev ) ; + s_inYield = former ; +} + +void wxApp::MacHandleMouseDownEvent( WXEVENTREF evr ) +{ + EventRecord* ev = (EventRecord*) evr ; + wxToolTip::RemoveToolTips() ; + + WindowRef window; + WindowRef frontWindow = ::FrontNonFloatingWindow() ; + WindowAttributes frontWindowAttributes = NULL ; + if ( frontWindow ) + ::GetWindowAttributes( frontWindow , &frontWindowAttributes ) ; + + short windowPart = ::FindWindow(ev->where, &window); + wxTopLevelWindowMac* win = wxFindWinFromMacWindow( window ) ; + if ( wxPendingDelete.Member(win) ) + return ; + + BitMap screenBits; + GetQDGlobalsScreenBits( &screenBits ); + + switch (windowPart) + { + case inMenuBar : + if ( s_macIsInModalLoop ) + { + SysBeep ( 30 ) ; + } + else + { + UInt32 menuresult = MenuSelect(ev->where) ; + MacHandleMenuSelect( HiWord( menuresult ) , LoWord( menuresult ) ); + s_lastMouseDown = 0; + } + break ; + case inSysWindow : + SystemClick( ev , window ) ; + s_lastMouseDown = 0; + break ; + case inDrag : + if ( window != frontWindow && s_macIsInModalLoop && !(ev->modifiers & cmdKey ) ) + { + SysBeep ( 30 ) ; + } + else + { + DragWindow(window, ev->where, &screenBits.bounds); + if (win) + { + GrafPtr port ; + GetPort( &port ) ; + Point pt = { 0, 0 } ; + SetPortWindowPort(window) ; + LocalToGlobal( &pt ) ; + SetPort( port ) ; + win->SetSize( pt.h , pt.v , -1 , + -1 , wxSIZE_USE_EXISTING); + } + s_lastMouseDown = 0; + } + break ; + case inGoAway: + if (TrackGoAway(window, ev->where)) + { + if ( win ) + win->Close() ; + } + s_lastMouseDown = 0; + break; + case inGrow: + { + Rect newContentRect ; + Rect constraintRect ; + constraintRect.top = win->GetMinHeight() ; + if ( constraintRect.top == -1 ) + constraintRect.top = 0 ; + constraintRect.left = win->GetMinWidth() ; + if ( constraintRect.left == -1 ) + constraintRect.left = 0 ; + constraintRect.right = win->GetMaxWidth() ; + if ( constraintRect.right == -1 ) + constraintRect.right = 32000 ; + constraintRect.bottom = win->GetMaxHeight() ; + if ( constraintRect.bottom == -1 ) + constraintRect.bottom = 32000 ; + + Boolean growResult = ResizeWindow( window , ev->where , + &constraintRect , &newContentRect ) ; + if ( growResult ) + { + win->SetSize( newContentRect.left , newContentRect.top , + newContentRect.right - newContentRect.left , + newContentRect.bottom - newContentRect.top, wxSIZE_USE_EXISTING); + } + s_lastMouseDown = 0; + } + break; + case inZoomIn: + case inZoomOut: + if (TrackBox(window, ev->where, windowPart)) + { + // TODO setup size event + ZoomWindow( window , windowPart , false ) ; + if (win) + { + Rect tempRect ; + GrafPtr port ; + GetPort( &port ) ; + Point pt = { 0, 0 } ; + SetPortWindowPort(window) ; + LocalToGlobal( &pt ) ; + SetPort( port ) ; + + GetWindowPortBounds(window, &tempRect ) ; + win->SetSize( pt.h , pt.v , tempRect.right-tempRect.left , + tempRect.bottom-tempRect.top, wxSIZE_USE_EXISTING); + } + } + s_lastMouseDown = 0; + break; + case inCollapseBox : + // TODO setup size event + s_lastMouseDown = 0; + break ; + + case inContent : + { + GrafPtr port ; + GetPort( &port ) ; + SetPortWindowPort(window) ; + SetPort( port ) ; + } + if ( window != frontWindow && wxTheApp->s_captureWindow == NULL ) + { + if ( s_macIsInModalLoop ) + { + SysBeep ( 30 ) ; + } + else if ( UMAIsWindowFloating( window ) ) + { + if ( win ) + win->MacMouseDown( ev , windowPart ) ; + } + else + { + // Activate window first + ::SelectWindow( window ) ; + + // Send event later + if ( win ) + win->MacMouseDown( ev , windowPart ) ; + } + } + else + { + if ( win ) + win->MacMouseDown( ev , windowPart ) ; + } + break ; + default: + break; + } +} + +void wxApp::MacHandleMouseUpEvent( WXEVENTREF evr ) +{ + EventRecord* ev = (EventRecord*) evr ; + WindowRef window; + + short windowPart = inNoWindow ; + if ( wxTheApp->s_captureWindow ) + { + window = (WindowRef) s_captureWindow->MacGetRootWindow() ; + windowPart = inContent ; + } + else + { + windowPart = ::FindWindow(ev->where, &window) ; + } + + switch (windowPart) + { + case inMenuBar : + break ; + case inSysWindow : + break ; + default: + { + wxTopLevelWindowMac* win = wxFindWinFromMacWindow( window ) ; + if ( win ) + win->MacMouseUp( ev , windowPart ) ; + } + break; + } +} + +#endif + +long wxMacTranslateKey(unsigned char key, unsigned char code) ; +long wxMacTranslateKey(unsigned char key, unsigned char code) +{ + long retval = key ; + switch (key) + { + case kHomeCharCode : + retval = WXK_HOME; + break; + case kEnterCharCode : + retval = WXK_RETURN; + break; + case kEndCharCode : + retval = WXK_END; + break; + case kHelpCharCode : + retval = WXK_HELP; + break; + case kBackspaceCharCode : + retval = WXK_BACK; + break; + case kTabCharCode : + retval = WXK_TAB; + break; + case kPageUpCharCode : + retval = WXK_PAGEUP; + break; + case kPageDownCharCode : + retval = WXK_PAGEDOWN; + break; + case kReturnCharCode : + retval = WXK_RETURN; + break; + case kFunctionKeyCharCode : + { + switch( code ) + { + case 0x7a : + retval = WXK_F1 ; + break; + case 0x78 : + retval = WXK_F2 ; + break; + case 0x63 : + retval = WXK_F3 ; + break; + case 0x76 : + retval = WXK_F4 ; + break; + case 0x60 : + retval = WXK_F5 ; + break; + case 0x61 : + retval = WXK_F6 ; + break; + case 0x62: + retval = WXK_F7 ; + break; + case 0x64 : + retval = WXK_F8 ; + break; + case 0x65 : + retval = WXK_F9 ; + break; + case 0x6D : + retval = WXK_F10 ; + break; + case 0x67 : + retval = WXK_F11 ; + break; + case 0x6F : + retval = WXK_F12 ; + break; + case 0x69 : + retval = WXK_F13 ; + break; + case 0x6B : + retval = WXK_F14 ; + break; + case 0x71 : + retval = WXK_F15 ; + break; + } + } + break ; + case kEscapeCharCode : + retval = WXK_ESCAPE ; + break ; + case kLeftArrowCharCode : + retval = WXK_LEFT ; + break ; + case kRightArrowCharCode : + retval = WXK_RIGHT ; + break ; + case kUpArrowCharCode : + retval = WXK_UP ; + break ; + case kDownArrowCharCode : + retval = WXK_DOWN ; + break ; + case kDeleteCharCode : + retval = WXK_DELETE ; + default: + break ; + } // end switch + + return retval; +} + +int wxKeyCodeToMacModifier(wxKeyCode key) +{ + switch (key) + { + case WXK_START: + case WXK_MENU: + return cmdKey; + + case WXK_SHIFT: + return shiftKey; + + case WXK_CAPITAL: + return alphaLock; + + case WXK_ALT: + return optionKey; + + case WXK_CONTROL: + return controlKey; + + default: + return 0; + } +} + +bool wxGetKeyState(wxKeyCode key) //virtual key code if < 10.2.x, else see below +{ +//#ifdef __DARWIN__ +// wxHIDKeyboard keyboard; +// return keyboard.IsActive(key); +//#else +// TODO: Have it use HID Manager on OSX... +//if OS X > 10.2 (i.e. 10.2.x) +//a known apple bug prevents the system from determining led +//states with GetKeys... can only determine caps lock led + return !!(GetCurrentKeyModifiers() & wxKeyCodeToMacModifier(key)); +//else +// KeyMapByteArray keymap; +// GetKeys((BigEndianLong*)keymap); +// return !!(BitTst(keymap, (sizeof(KeyMapByteArray)*8) - iKey)); +//#endif +} + +#if !TARGET_CARBON +void wxApp::MacHandleKeyDownEvent( WXEVENTREF evr ) +{ + EventRecord* ev = (EventRecord*) evr ; + wxToolTip::RemoveToolTips() ; + + UInt32 menuresult = UMAMenuEvent(ev) ; + if ( HiWord( menuresult ) ) + { + if ( !s_macIsInModalLoop ) + MacHandleMenuSelect( HiWord( menuresult ) , LoWord( menuresult ) ) ; + } + else + { + wxWindow* focus = wxWindow::FindFocus() ; + + if ( MacSendKeyDownEvent( focus , ev->message , ev->modifiers , ev->when , ev->where.h , ev->where.v ) == false ) + { +#if 0 + // we must handle control keys the other way round, otherwise text content is updated too late + // has not been handled -> perform default + wxControl* control = wxDynamicCast( focus , wxControl ) ; + if ( control && control->GetMacControl() != NULL ) + { + short keycode ; + short keychar ; + keychar = short(ev->message & charCodeMask); + keycode = short(ev->message & keyCodeMask) >> 8 ; + ::HandleControlKey( (ControlHandle) control->GetMacControl() , keycode , keychar , ev->modifiers ) ; + } +#endif + } + } +} + +void wxApp::MacHandleKeyUpEvent( WXEVENTREF evr ) +{ + EventRecord* ev = (EventRecord*) evr ; + wxToolTip::RemoveToolTips() ; + + UInt32 menuresult = UMAMenuEvent(ev) ; + if ( HiWord( menuresult ) ) + { + } + else + { + MacSendKeyUpEvent( wxWindow::FindFocus() , ev->message , ev->modifiers , ev->when , ev->where.h , ev->where.v ) ; + } +} + +#endif + +bool wxApp::MacSendKeyDownEvent( wxWindow* focus , long keymessage , long modifiers , long when , short wherex , short wherey ) +{ + if ( !focus ) + return false ; + + short keycode ; + short keychar ; + keychar = short(keymessage & charCodeMask); + keycode = short(keymessage & keyCodeMask) >> 8 ; + + if ( modifiers & ( controlKey|shiftKey|optionKey ) ) + { + // control interferes with some built-in keys like pgdown, return etc. therefore we remove the controlKey modifier + // and look at the character after + UInt32 state = 0; + UInt32 keyInfo = KeyTranslate((Ptr)GetScriptManagerVariable(smKCHRCache), ( modifiers & (~(controlKey|shiftKey|optionKey))) | keycode, &state); + keychar = short(keyInfo & charCodeMask); + keycode = short(keyInfo & keyCodeMask) >> 8 ; + } + long keyval = wxMacTranslateKey(keychar, keycode) ; + long realkeyval = keyval ; + if ( keyval == keychar ) + { + // we are not on a special character combo -> pass the real os event-value to EVT_CHAR, but not to EVT_KEY (make upper first) + realkeyval = short(keymessage & charCodeMask) ; + keyval = wxToupper( keyval ) ; + } + + wxKeyEvent event(wxEVT_KEY_DOWN); + bool handled = false ; + event.m_shiftDown = modifiers & shiftKey; + event.m_controlDown = modifiers & controlKey; + event.m_altDown = modifiers & optionKey; + event.m_metaDown = modifiers & cmdKey; + event.m_keyCode = keyval ; + + event.m_x = wherex; + event.m_y = wherey; + event.m_timeStamp = when; + event.SetEventObject(focus); + handled = focus->GetEventHandler()->ProcessEvent( event ) ; + if ( handled && event.GetSkipped() ) + handled = false ; + if ( !handled ) + { +#if wxUSE_ACCEL + if (!handled) + { + wxWindow *ancestor = focus; + while (ancestor) + { + int command = ancestor->GetAcceleratorTable()->GetCommand( event ); + if (command != -1) + { + wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command ); + handled = ancestor->GetEventHandler()->ProcessEvent( command_event ); + break; + } + if (ancestor->IsTopLevel()) + break; + ancestor = ancestor->GetParent(); + } + } +#endif // wxUSE_ACCEL + } + if (!handled) + { + event.Skip( FALSE ) ; + event.SetEventType( wxEVT_CHAR ) ; + // raw value again + event.m_keyCode = realkeyval ; + + handled = focus->GetEventHandler()->ProcessEvent( event ) ; + if ( handled && event.GetSkipped() ) + handled = false ; + } + if ( !handled && + (keyval == WXK_TAB) && +// CS: copied the change below from wxGTK +// VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may +// have this style, yet choose not to process this particular TAB in which +// case TAB must still work as a navigational character +#if 0 + (!focus->HasFlag(wxTE_PROCESS_TAB)) && +#endif + (focus->GetParent()) && + (focus->GetParent()->HasFlag( wxTAB_TRAVERSAL)) ) + { + wxNavigationKeyEvent new_event; + new_event.SetEventObject( focus ); + new_event.SetDirection( !event.ShiftDown() ); + /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */ + new_event.SetWindowChange( event.ControlDown() ); + new_event.SetCurrentFocus( focus ); + handled = focus->GetEventHandler()->ProcessEvent( new_event ); + if ( handled && new_event.GetSkipped() ) + handled = false ; + } + // backdoor handler for default return and command escape + if ( !handled && (!focus->IsKindOf(CLASSINFO(wxControl) ) || !focus->MacCanFocus() ) ) + { + // if window is not having a focus still testing for default enter or cancel + // TODO add the UMA version for ActiveNonFloatingWindow + wxWindow* focus = wxFindWinFromMacWindow( FrontWindow() ) ; + if ( focus ) + { + if ( keyval == WXK_RETURN ) + { + wxButton *def = wxDynamicCast(focus->GetDefaultItem(), + wxButton); + if ( def && def->IsEnabled() ) + { + wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() ); + event.SetEventObject(def); + def->Command(event); + return true ; + } + } + /* generate wxID_CANCEL if command-. or has been pressed (typically in dialogs) */ + else if (keyval == WXK_ESCAPE || (keyval == '.' && modifiers & cmdKey ) ) + { + wxCommandEvent new_event(wxEVT_COMMAND_BUTTON_CLICKED,wxID_CANCEL); + new_event.SetEventObject( focus ); + handled = focus->GetEventHandler()->ProcessEvent( new_event ); + } + } + } + return handled ; +} + +bool wxApp::MacSendKeyUpEvent( wxWindow* focus , long keymessage , long modifiers , long when , short wherex , short wherey ) +{ + if ( !focus ) + return false ; + + short keycode ; + short keychar ; + keychar = short(keymessage & charCodeMask); + keycode = short(keymessage & keyCodeMask) >> 8 ; + if ( modifiers & ( controlKey|shiftKey|optionKey ) ) + { + // control interferes with some built-in keys like pgdown, return etc. therefore we remove the controlKey modifier + // and look at the character after + UInt32 state = 0; + UInt32 keyInfo = KeyTranslate((Ptr)GetScriptManagerVariable(smKCHRCache), ( modifiers & (~(controlKey|shiftKey|optionKey))) | keycode, &state); + keychar = short(keyInfo & charCodeMask); + keycode = short(keyInfo & keyCodeMask) >> 8 ; + } + long keyval = wxMacTranslateKey(keychar, keycode) ; + + if ( keyval == keychar ) + { + keyval = wxToupper( keyval ) ; + } + bool handled = false ; + + wxKeyEvent event(wxEVT_KEY_UP); + event.m_shiftDown = modifiers & shiftKey; + event.m_controlDown = modifiers & controlKey; + event.m_altDown = modifiers & optionKey; + event.m_metaDown = modifiers & cmdKey; + event.m_keyCode = keyval ; + + event.m_x = wherex; + event.m_y = wherey; + event.m_timeStamp = when; + event.SetEventObject(focus); + handled = focus->GetEventHandler()->ProcessEvent( event ) ; + + return handled ; +} + +#if !TARGET_CARBON +void wxApp::MacHandleActivateEvent( WXEVENTREF evr ) +{ + EventRecord* ev = (EventRecord*) evr ; + WindowRef window = (WindowRef) ev->message ; + if ( window ) + { + bool activate = (ev->modifiers & activeFlag ) ; + WindowClass wclass ; + ::GetWindowClass ( window , &wclass ) ; + if ( wclass == kFloatingWindowClass ) + { + // if it is a floater we activate/deactivate the front non-floating window instead + window = ::FrontNonFloatingWindow() ; + } + wxTopLevelWindowMac* win = wxFindWinFromMacWindow( window ) ; + if ( win ) + win->MacActivate( ev->when , activate ) ; + } +} + +void wxApp::MacHandleUpdateEvent( WXEVENTREF evr ) +{ + EventRecord* ev = (EventRecord*) evr ; + WindowRef window = (WindowRef) ev->message ; + wxTopLevelWindowMac * win = wxFindWinFromMacWindow( window ) ; + if ( win ) + { + if ( !wxPendingDelete.Member(win) ) + win->MacUpdate( ev->when ) ; + } + else + { + // since there is no way of telling this foreign window to update itself + // we have to invalidate the update region otherwise we keep getting the same + // event over and over again + BeginUpdate( window ) ; + EndUpdate( window ) ; + } +} + +void wxApp::MacHandleDiskEvent( WXEVENTREF evr ) +{ + EventRecord* ev = (EventRecord*) evr ; + if ( HiWord( ev->message ) != noErr ) + { + OSErr err ; + Point point ; + SetPt( &point , 100 , 100 ) ; + + err = DIBadMount( point , ev->message ) ; + wxASSERT( err == noErr ) ; + } +} + +void wxApp::MacHandleOSEvent( WXEVENTREF evr ) +{ + EventRecord* ev = (EventRecord*) evr ; + switch( ( ev->message & osEvtMessageMask ) >> 24 ) + { + case suspendResumeMessage : + { + bool isResuming = ev->message & resumeFlag ; + bool convertClipboard = ev->message & convertClipboardFlag ; + + bool doesActivate = UMAGetProcessModeDoesActivateOnFGSwitch() ; + if ( isResuming ) + { + WindowRef oldFrontWindow = NULL ; + WindowRef newFrontWindow = NULL ; + + // in case we don't take care of activating ourselves, we have to synchronize + // our idea of the active window with the process manager's - which it already activated + + if ( !doesActivate ) + oldFrontWindow = ::FrontNonFloatingWindow() ; + + MacResume( convertClipboard ) ; + + newFrontWindow = ::FrontNonFloatingWindow() ; + + if ( oldFrontWindow ) + { + wxTopLevelWindowMac* win = wxFindWinFromMacWindow( oldFrontWindow ) ; + if ( win ) + win->MacActivate( ev->when , false ) ; + } + if ( newFrontWindow ) + { + wxTopLevelWindowMac* win = wxFindWinFromMacWindow( newFrontWindow ) ; + if ( win ) + win->MacActivate( ev->when , true ) ; + } + } + else + { + MacSuspend( convertClipboard ) ; + } + } + break ; + case mouseMovedMessage : + { + WindowRef window; + + wxWindow* currentMouseWindow = NULL ; + + if (s_captureWindow ) + { + currentMouseWindow = s_captureWindow ; + } + else + { + wxWindow::MacGetWindowFromPoint( wxPoint( ev->where.h , ev->where.v ) , + ¤tMouseWindow ) ; + } + + if ( currentMouseWindow != wxWindow::s_lastMouseWindow ) + { + wxMouseEvent event ; + + bool isDown = !(ev->modifiers & btnState) ; // 1 is for up + bool controlDown = ev->modifiers & controlKey ; // for simulating right mouse + + event.m_leftDown = isDown && !controlDown; + event.m_middleDown = FALSE; + event.m_rightDown = isDown && controlDown; + event.m_shiftDown = ev->modifiers & shiftKey; + event.m_controlDown = ev->modifiers & controlKey; + event.m_altDown = ev->modifiers & optionKey; + event.m_metaDown = ev->modifiers & cmdKey; + event.m_x = ev->where.h; + event.m_y = ev->where.v; + event.m_timeStamp = ev->when; + event.SetEventObject(this); + + if ( wxWindow::s_lastMouseWindow ) + { + wxMouseEvent eventleave(event); + eventleave.SetEventType( wxEVT_LEAVE_WINDOW ); + wxWindow::s_lastMouseWindow->ScreenToClient( &eventleave.m_x, &eventleave.m_y ); + eventleave.SetEventObject( wxWindow::s_lastMouseWindow ) ; + + wxWindow::s_lastMouseWindow->GetEventHandler()->ProcessEvent(eventleave); + } + if ( currentMouseWindow ) + { + wxMouseEvent evententer(event); + evententer.SetEventType( wxEVT_ENTER_WINDOW ); + currentMouseWindow->ScreenToClient( &evententer.m_x, &evententer.m_y ); + evententer.SetEventObject( currentMouseWindow ) ; + currentMouseWindow->GetEventHandler()->ProcessEvent(evententer); + } + wxWindow::s_lastMouseWindow = currentMouseWindow ; + } + + short windowPart = inNoWindow ; + + if ( s_captureWindow ) + { + window = (WindowRef) s_captureWindow->MacGetRootWindow() ; + windowPart = inContent ; + } + else + { + windowPart = ::FindWindow(ev->where, &window); + } + + switch (windowPart) + { + case inContent : + { + wxTopLevelWindowMac* win = wxFindWinFromMacWindow( window ) ; + if ( win ) + win->MacMouseMoved( ev , windowPart ) ; + else + { + if ( wxIsBusy() ) + { + } + else + UMAShowArrowCursor(); + } + } + break; + default : + { + if ( wxIsBusy() ) + { + } + else + UMAShowArrowCursor(); + } + break ; + } + } + break ; + + } +} +#else + +void wxApp::MacHandleMouseMovedEvent(wxInt32 x , wxInt32 y ,wxUint32 modifiers , long timestamp) +{ + WindowRef window; + + wxWindow* currentMouseWindow = NULL ; + + if (s_captureWindow ) + { + currentMouseWindow = s_captureWindow ; + } + else + { + wxWindow::MacGetWindowFromPoint( wxPoint( x, y ) , ¤tMouseWindow ) ; + } + + if ( currentMouseWindow != wxWindow::s_lastMouseWindow ) + { + wxMouseEvent event ; + + bool isDown = !(modifiers & btnState) ; // 1 is for up + bool controlDown = modifiers & controlKey ; // for simulating right mouse + + event.m_leftDown = isDown && !controlDown; + + event.m_middleDown = FALSE; + event.m_rightDown = isDown && controlDown; + + event.m_shiftDown = modifiers & shiftKey; + event.m_controlDown = modifiers & controlKey; + event.m_altDown = modifiers & optionKey; + event.m_metaDown = modifiers & cmdKey; + + event.m_x = x; + event.m_y = y; + event.m_timeStamp = timestamp; + + if ( wxWindow::s_lastMouseWindow ) + { + wxMouseEvent eventleave(event); + eventleave.SetEventType( wxEVT_LEAVE_WINDOW ); + wxWindow::s_lastMouseWindow->ScreenToClient( &eventleave.m_x, &eventleave.m_y ); + eventleave.SetEventObject( wxWindow::s_lastMouseWindow ) ; + +#if wxUSE_TOOLTIPS + wxToolTip::RelayEvent( wxWindow::s_lastMouseWindow , eventleave); +#endif // wxUSE_TOOLTIPS + wxWindow::s_lastMouseWindow->GetEventHandler()->ProcessEvent(eventleave); + } + if ( currentMouseWindow ) + { + wxMouseEvent evententer(event); + evententer.SetEventType( wxEVT_ENTER_WINDOW ); + currentMouseWindow->ScreenToClient( &evententer.m_x, &evententer.m_y ); + evententer.SetEventObject( currentMouseWindow ) ; +#if wxUSE_TOOLTIPS + wxToolTip::RelayEvent( currentMouseWindow , evententer); +#endif // wxUSE_TOOLTIPS + currentMouseWindow->GetEventHandler()->ProcessEvent(evententer); + } + wxWindow::s_lastMouseWindow = currentMouseWindow ; + } + + short windowPart = inNoWindow ; + + if ( s_captureWindow ) + { + window = (WindowRef) s_captureWindow->MacGetRootWindow() ; + windowPart = inContent ; + } + else + { + Point pt= { y , x } ; + windowPart = ::FindWindow(pt , &window); + } + + switch (windowPart) + { + case inContent : + { + wxTopLevelWindowMac* win = wxFindWinFromMacWindow( window ) ; + if ( win ) + win->MacFireMouseEvent( nullEvent , x , y , modifiers , timestamp ) ; + else + { + if ( wxIsBusy() ) + { + } + else + UMAShowArrowCursor(); + } + } + break; + default : + { + if ( wxIsBusy() ) + { + } + else + UMAShowArrowCursor(); + } + break ; + } +} +#endif + +void wxApp::MacHandleMenuCommand( wxUint32 id ) +{ + wxMenuBar* mbar = wxMenuBar::MacGetInstalledMenuBar() ; + wxFrame* frame = mbar->GetFrame(); + wxCHECK_RET( mbar != NULL && frame != NULL, wxT("error in menu item callback") ); + if ( frame ) + { + frame->ProcessCommand(id); + } +} + +#if !TARGET_CARBON +void wxApp::MacHandleMenuSelect( int macMenuId , int macMenuItemNum ) +{ + if (macMenuId == 0) + return; // no menu item selected + + if (macMenuId == kwxMacAppleMenuId && macMenuItemNum > 1) + { + #if ! TARGET_CARBON + Str255 deskAccessoryName ; + GrafPtr savedPort ; + + GetMenuItemText(GetMenuHandle(kwxMacAppleMenuId), macMenuItemNum, deskAccessoryName); + GetPort(&savedPort); + OpenDeskAcc(deskAccessoryName); + SetPort(savedPort); + #endif + } + else + { + MenuCommand id ; + GetMenuItemCommandID( GetMenuHandle(macMenuId) , macMenuItemNum , &id ) ; + MacHandleMenuCommand( id ) ; + } + HiliteMenu(0); +} +#endif diff --git a/src/mac/classic/apprsrc.h b/src/mac/classic/apprsrc.h new file mode 100644 index 0000000000..c887ac2d5b --- /dev/null +++ b/src/mac/classic/apprsrc.h @@ -0,0 +1,6 @@ +#define kMacSTRWrongMachine 1 +#define kMacSTRSmallSize 2 +#define kMacSTRNoMemory 3 +#define kMacSTROldSystem 4 +#define kMacSTRGenericAbout 5 +#define kMacSTRNoPre8Yet 6 diff --git a/src/mac/classic/apprsrc.r b/src/mac/classic/apprsrc.r new file mode 100644 index 0000000000..020b34f73a --- /dev/null +++ b/src/mac/classic/apprsrc.r @@ -0,0 +1,32 @@ +#ifdef __UNIX__ +# include +#else +# include +#endif +#include "apprsrc.h" + +resource 'STR#' ( 128 , "Simple Alert Messages" ) +{ + { + "This application needs at least a MacPlus" , + "This application needs more memory" , + "This application is out of memory" , + "This application needs at least System 8.6" , + "About this wxWindows Application" , + "This application needs Appearance extension (built in with System 8) - this restriction will be relieved in the final release" + } +} ; + +resource 'MENU' (1, preload) +{ + 1, textMenuProc, 0b11111111111111111111111111111110 , enabled, apple , + { + "AboutÉ" , noicon, nokey,nomark,plain , + "-" , noicon, nokey,nomark,plain + } +} ; + +resource 'MBAR' (1,preload) +{ + { 1 } ; +} ; diff --git a/src/mac/classic/bitmap.cpp b/src/mac/classic/bitmap.cpp new file mode 100644 index 0000000000..6cbaa9d9b7 --- /dev/null +++ b/src/mac/classic/bitmap.cpp @@ -0,0 +1,1436 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: bitmap.cpp +// Purpose: wxBitmap +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "bitmap.h" +#endif + +#include "wx/defs.h" + +#include "wx/bitmap.h" +#include "wx/icon.h" +#include "wx/log.h" +#include "wx/image.h" +#include "wx/xpmdecod.h" + +#include "wx/rawbmp.h" + +IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject) +IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject ) + +#ifdef __DARWIN__ + #include +#else + #include +#endif + +#include "wx/mac/uma.h" + +CTabHandle wxMacCreateColorTable( int numColors ) +{ + CTabHandle newColors; /* Handle to the new color table */ + + /* Allocate memory for the color table */ + newColors = (CTabHandle)NewHandleClear( sizeof (ColorTable) + + sizeof (ColorSpec) * (numColors - 1) ); + if (newColors != nil) + { + /* Initialize the fields */ + (**newColors).ctSeed = GetCTSeed(); + (**newColors).ctFlags = 0; + (**newColors).ctSize = numColors - 1; + /* Initialize the table of colors */ + } + return newColors ; +} + +void wxMacDestroyColorTable( CTabHandle colors ) +{ + DisposeHandle( (Handle) colors ) ; +} + +void wxMacSetColorTableEntry( CTabHandle newColors , int index , int red , int green , int blue ) +{ + (**newColors).ctTable[index].value = index; + (**newColors).ctTable[index].rgb.red = red ; // someRedValue; + (**newColors).ctTable[index].rgb.green = green ; // someGreenValue; + (**newColors).ctTable[index].rgb.blue = blue ; // someBlueValue; +} + +GWorldPtr wxMacCreateGWorld( int width , int height , int depth ) +{ + OSErr err = noErr ; + GWorldPtr port ; + Rect rect = { 0 , 0 , height , width } ; + + if ( depth < 0 ) + { + depth = wxDisplayDepth() ; + } + + err = NewGWorld( &port , depth , &rect , NULL , NULL , 0 ) ; + if ( err == noErr ) + { + return port ; + } + return NULL ; +} + +void wxMacDestroyGWorld( GWorldPtr gw ) +{ + if ( gw ) + DisposeGWorld( gw ) ; +} + +#define kDefaultRes 0x00480000 /* Default resolution is 72 DPI; Fixed type */ + +OSErr SetupCIconHandlePixMap( CIconHandle icon , short depth , Rect *bounds , CTabHandle colors ) +{ + CTabHandle newColors; /* Color table used for the off-screen PixMap */ + Ptr offBaseAddr; /* Pointer to the off-screen pixel image */ + OSErr error; /* Returns error code */ + short bytesPerRow; /* Number of bytes per row in the PixMap */ + + + error = noErr; + newColors = nil; + offBaseAddr = nil; + + bytesPerRow = ((depth * (bounds->right - bounds->left) + 31) / 32) * 4; + + /* Clone the clut if indexed color; allocate a dummy clut if direct color*/ + if (depth <= 8) + { + newColors = colors; + error = HandToHand((Handle *) &newColors); + } + else + { + newColors = (CTabHandle) NewHandle(sizeof(ColorTable) - + sizeof(CSpecArray)); + error = MemError(); + } + if (error == noErr) + { + /* Allocate pixel image; long integer multiplication avoids overflow */ + (**icon).iconData = NewHandle((unsigned long) bytesPerRow * (bounds->bottom - + bounds->top)); + if ((**icon).iconData != nil) + { + /* Initialize fields common to indexed and direct PixMaps */ + (**icon).iconPMap.baseAddr = 0; /* Point to image */ + (**icon).iconPMap.rowBytes = bytesPerRow | /* MSB set for PixMap */ + 0x8000; + (**icon).iconPMap.bounds = *bounds; /* Use given bounds */ + (**icon).iconPMap.pmVersion = 0; /* No special stuff */ + (**icon).iconPMap.packType = 0; /* Default PICT pack */ + (**icon).iconPMap.packSize = 0; /* Always zero in mem */ + (**icon).iconPMap.hRes = kDefaultRes; /* 72 DPI default res */ + (**icon).iconPMap.vRes = kDefaultRes; /* 72 DPI default res */ + (**icon).iconPMap.pixelSize = depth; /* Set # bits/pixel */ + + /* Initialize fields specific to indexed and direct PixMaps */ + if (depth <= 8) + { + /* PixMap is indexed */ + (**icon).iconPMap.pixelType = 0; /* Indicates indexed */ + (**icon).iconPMap.cmpCount = 1; /* Have 1 component */ + (**icon).iconPMap.cmpSize = depth; /* Component size=depth */ + (**icon).iconPMap.pmTable = newColors; /* Handle to CLUT */ + } + else + { + /* PixMap is direct */ + (**icon).iconPMap.pixelType = RGBDirect; /* Indicates direct */ + (**icon).iconPMap.cmpCount = 3; /* Have 3 components */ + if (depth == 16) + (**icon).iconPMap.cmpSize = 5; /* 5 bits/component */ + else + (**icon).iconPMap.cmpSize = 8; /* 8 bits/component */ + (**newColors).ctSeed = 3 * (**icon).iconPMap.cmpSize; + (**newColors).ctFlags = 0; + (**newColors).ctSize = 0; + (**icon).iconPMap.pmTable = newColors; + } + } + else + error = MemError(); + } + else + newColors = nil; + + /* If no errors occured, return a handle to the new off-screen PixMap */ + if (error != noErr) + { + if (newColors != nil) + DisposeCTable(newColors); + } + + /* Return the error code */ + return error; +} + +CIconHandle wxMacCreateCIcon(GWorldPtr image , GWorldPtr mask , short dstDepth , short iconSize ) +{ + GWorldPtr saveWorld; + GDHandle saveHandle; + + GetGWorld(&saveWorld,&saveHandle); // save Graphics env state + SetGWorld(image,nil); + + Rect frame = { 0 , 0 , iconSize , iconSize } ; + Rect imageBounds = frame ; + GetPortBounds( image , &imageBounds ) ; + + int bwSize = iconSize / 8 * iconSize ; + CIconHandle icon = (CIconHandle) NewHandleClear( sizeof ( CIcon ) + 2 * bwSize) ; + HLock((Handle)icon) ; + SetupCIconHandlePixMap( icon , dstDepth , &frame,GetCTable(dstDepth)) ; + HLock( (**icon).iconData ) ; + (**icon).iconPMap.baseAddr = *(**icon).iconData ; + + LockPixels(GetGWorldPixMap(image)); + + CopyBits(GetPortBitMapForCopyBits(image), + (BitMapPtr)&((**icon).iconPMap), + &imageBounds, + &imageBounds, + srcCopy | ditherCopy, nil); + + + UnlockPixels(GetGWorldPixMap(image)); + HUnlock( (**icon).iconData ) ; + + (**icon).iconMask.rowBytes = iconSize / 8 ; + (**icon).iconMask.bounds = frame ; + + (**icon).iconBMap.rowBytes = iconSize / 8 ; + (**icon).iconBMap.bounds = frame ; + (**icon).iconMask.baseAddr = (char*) &(**icon).iconMaskData ; + (**icon).iconBMap.baseAddr = (char*) &(**icon).iconMaskData + bwSize ; + + if ( mask ) + { + Rect r ; + GetPortBounds( image , &r ) ; + LockPixels(GetGWorldPixMap(mask) ) ; + CopyBits(GetPortBitMapForCopyBits(mask) , + &(**icon).iconBMap , &r , &r, srcCopy , nil ) ; + CopyBits(GetPortBitMapForCopyBits(mask) , + &(**icon).iconMask , &r , &r, srcCopy , nil ) ; + UnlockPixels(GetGWorldPixMap( mask ) ) ; + } + else + { + Rect r ; + GetPortBounds( image , &r ) ; + LockPixels(GetGWorldPixMap(image)); + CopyBits(GetPortBitMapForCopyBits(image) , + &(**icon).iconBMap , &r , &r, srcCopy , nil ) ; + CopyBits(GetPortBitMapForCopyBits(image) , + &(**icon).iconMask , &r , &r, srcCopy , nil ) ; + UnlockPixels(GetGWorldPixMap(image)); + } + + (**icon).iconMask.baseAddr = NULL ; + (**icon).iconBMap.baseAddr = NULL ; + (**icon).iconPMap.baseAddr = NULL ; + HUnlock((Handle)icon) ; + SetGWorld(saveWorld,saveHandle); + + return icon; +} + +PicHandle wxMacCreatePict(GWorldPtr wp, GWorldPtr mask) +{ + CGrafPtr origPort ; + GDHandle origDev ; + + PicHandle pict; + + RGBColor white = { 0xffff ,0xffff , 0xffff } ; + RGBColor black = { 0x0000 ,0x0000 , 0x0000 } ; + + GetGWorld( &origPort , &origDev ) ; + + RgnHandle clipRgn = NULL ; + + if ( mask ) + { + clipRgn = NewRgn() ; + LockPixels( GetGWorldPixMap( mask ) ) ; + BitMapToRegion( clipRgn , (BitMap*) *GetGWorldPixMap( mask ) ) ; + UnlockPixels( GetGWorldPixMap( mask ) ) ; + } + + SetGWorld( wp , NULL ) ; + Rect portRect ; + if ( clipRgn ) + GetRegionBounds( clipRgn , &portRect ) ; + else + GetPortBounds( wp , &portRect ) ; + pict = OpenPicture(&portRect); + if(pict) + { + RGBForeColor( &black ) ; + RGBBackColor( &white ) ; + + if ( clipRgn ) + SetClip( clipRgn ) ; + + LockPixels( GetGWorldPixMap( wp ) ) ; + CopyBits(GetPortBitMapForCopyBits(wp), + GetPortBitMapForCopyBits(wp), + &portRect, + &portRect, + srcCopy,clipRgn); + UnlockPixels( GetGWorldPixMap( wp ) ) ; + ClosePicture(); + } + SetGWorld( origPort , origDev ) ; + if ( clipRgn ) + DisposeRgn( clipRgn ) ; + return pict; +} + +void wxMacCreateBitmapButton( ControlButtonContentInfo*info , const wxBitmap& bitmap , int forceType ) +{ + memset( info , 0 , sizeof(ControlButtonContentInfo) ) ; + if ( bitmap.Ok() ) + { + wxBitmapRefData * bmap = (wxBitmapRefData*) ( bitmap.GetRefData()) ; + if ( bmap == NULL ) + return ; + + if ( bmap->m_bitmapType == kMacBitmapTypePict ) + { + info->contentType = kControlContentPictHandle ; + info->u.picture = MAC_WXHMETAFILE(bmap->m_hPict) ; + } + else if ( bmap->m_bitmapType == kMacBitmapTypeGrafWorld ) + { + if ( (forceType == kControlContentCIconHandle || ( bmap->m_width == bmap->m_height && forceType != kControlContentPictHandle ) ) && ((bmap->m_width & 0x3) == 0) ) + { + info->contentType = kControlContentCIconHandle ; + if ( bitmap.GetMask() ) + { + info->u.cIconHandle = wxMacCreateCIcon( MAC_WXHBITMAP(bmap->m_hBitmap) , MAC_WXHBITMAP(bitmap.GetMask()->GetMaskBitmap()) , + 8 , bmap->m_width ) ; + } + else + { + info->u.cIconHandle = wxMacCreateCIcon( MAC_WXHBITMAP(bmap->m_hBitmap) , NULL , + 8 , bmap->m_width ) ; + } + } + else + { + info->contentType = kControlContentPictHandle ; + if ( bitmap.GetMask() ) + { + info->u.picture = wxMacCreatePict( MAC_WXHBITMAP(bmap->m_hBitmap) , MAC_WXHBITMAP(bitmap.GetMask()->GetMaskBitmap() ) ) ; + } + else + { + info->u.picture = wxMacCreatePict( MAC_WXHBITMAP(bmap->m_hBitmap) , NULL ) ; + } + } + } + else if ( bmap->m_bitmapType == kMacBitmapTypeIcon ) + { + info->contentType = kControlContentCIconHandle ; + info->u.cIconHandle = MAC_WXHICON(bmap->m_hIcon) ; + } + } +} + +wxBitmapRefData::wxBitmapRefData() + : m_width(0) + , m_height(0) + , m_depth(0) + , m_ok(FALSE) + , m_numColors(0) + , m_quality(0) +{ + m_bitmapMask = NULL; + m_hBitmap = NULL ; + m_hPict = NULL ; + m_hIcon = NULL ; + m_bitmapType = kMacBitmapTypeUnknownType ; + m_hasAlpha = false; +} + +// TODO move this to a public function of Bitmap Ref +static void DisposeBitmapRefData(wxBitmapRefData *data) +{ + if ( !data ) + return ; + + switch (data->m_bitmapType) + { + case kMacBitmapTypePict : + { + if ( data->m_hPict ) + { + KillPicture( MAC_WXHMETAFILE( data->m_hPict ) ) ; + data->m_hPict = NULL ; + } + } + break ; + case kMacBitmapTypeGrafWorld : + { + if ( data->m_hBitmap ) + { + wxMacDestroyGWorld( MAC_WXHBITMAP(data->m_hBitmap) ) ; + data->m_hBitmap = NULL ; + } + } + break ; + case kMacBitmapTypeIcon : + if ( data->m_hIcon ) + { + DisposeCIcon( MAC_WXHICON(data->m_hIcon) ) ; + data->m_hIcon = NULL ; + } + + default : + // unkown type ? + break ; + } + + if (data->m_bitmapMask) + { + delete data->m_bitmapMask; + data->m_bitmapMask = NULL; + } +} + +wxBitmapRefData::~wxBitmapRefData() +{ + DisposeBitmapRefData( this ) ; +} + +bool wxBitmap::CopyFromIcon(const wxIcon& icon) +{ + Ref(icon) ; + return true; +} + +wxBitmap::wxBitmap() +{ + m_refData = NULL; +} + +wxBitmap::~wxBitmap() +{ +} + +wxBitmap::wxBitmap(const char bits[], int the_width, int the_height, int no_bits) +{ + m_refData = new wxBitmapRefData; + + M_BITMAPDATA->m_width = the_width ; + M_BITMAPDATA->m_height = the_height ; + M_BITMAPDATA->m_depth = no_bits ; + M_BITMAPDATA->m_numColors = 0; + if ( no_bits == 1 ) + { + M_BITMAPDATA->m_bitmapType = kMacBitmapTypeGrafWorld ; + M_BITMAPDATA->m_hBitmap = wxMacCreateGWorld( the_width , the_height , no_bits ) ; + M_BITMAPDATA->m_ok = (MAC_WXHBITMAP(M_BITMAPDATA->m_hBitmap) != NULL ) ; + + CGrafPtr origPort ; + GDHandle origDevice ; + + GetGWorld( &origPort , &origDevice ) ; + SetGWorld( MAC_WXHBITMAP(M_BITMAPDATA->m_hBitmap) , NULL ) ; + LockPixels( GetGWorldPixMap( MAC_WXHBITMAP(M_BITMAPDATA->m_hBitmap) ) ) ; + + // bits is a char array + + unsigned char* linestart = (unsigned char*) bits ; + int linesize = ( the_width / (sizeof(unsigned char) * 8)) ; + if ( the_width % (sizeof(unsigned char) * 8) ) { + linesize += sizeof(unsigned char); + } + + RGBColor colors[2] = { + { 0xFFFF , 0xFFFF , 0xFFFF } , + { 0, 0 , 0 } + } ; + + for ( int y = 0 ; y < the_height ; ++y , linestart += linesize ) + { + for ( int x = 0 ; x < the_width ; ++x ) + { + int index = x / 8 ; + int bit = x % 8 ; + int mask = 1 << bit ; + if ( linestart[index] & mask ) + { + SetCPixel( x , y , &colors[1] ) ; + } + else + { + SetCPixel( x , y , &colors[0] ) ; + } + } + } + UnlockPixels( GetGWorldPixMap( MAC_WXHBITMAP(M_BITMAPDATA->m_hBitmap) ) ) ; + + SetGWorld( origPort , origDevice ) ; + } + else + { + wxFAIL_MSG(wxT("multicolor BITMAPs not yet implemented")); + } +} + +wxBitmap::wxBitmap(int w, int h, int d) +{ + (void)Create(w, h, d); +} + +wxBitmap::wxBitmap(void *data, wxBitmapType type, int width, int height, int depth) +{ + (void) Create(data, type, width, height, depth); +} + +wxBitmap::wxBitmap(const wxString& filename, wxBitmapType type) +{ + LoadFile(filename, type); +} + +bool wxBitmap::CreateFromXpm(const char **bits) +{ + wxCHECK_MSG( bits != NULL, FALSE, wxT("invalid bitmap data") ) + wxXPMDecoder decoder; + wxImage img = decoder.ReadData(bits); + wxCHECK_MSG( img.Ok(), FALSE, wxT("invalid bitmap data") ) + *this = wxBitmap(img); + return TRUE; +} + +wxBitmap::wxBitmap(const char **bits) +{ + (void) CreateFromXpm(bits); +} + +wxBitmap::wxBitmap(char **bits) +{ + (void) CreateFromXpm((const char **)bits); +} + +wxBitmap wxBitmap::GetSubBitmap(const wxRect &rect) const +{ + wxCHECK_MSG( Ok() && + (rect.x >= 0) && (rect.y >= 0) && + (rect.x+rect.width <= GetWidth()) && + (rect.y+rect.height <= GetHeight()), + wxNullBitmap, wxT("invalid bitmap or bitmap region") ); + + + wxBitmap ret( rect.width, rect.height, GetDepth() ); + wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") ); + + GWorldPtr origPort; + GDHandle origDevice; + + GetGWorld( &origPort, &origDevice ); + + // Update the subbitmaps reference data + wxBitmapRefData *ref = (wxBitmapRefData *)ret.GetRefData(); + + ref->m_numColors = M_BITMAPDATA->m_numColors; +#if wxUSE_PALETTE + ref->m_bitmapPalette = M_BITMAPDATA->m_bitmapPalette; +#endif // wxUSE_PALETTE + ref->m_bitmapType = M_BITMAPDATA->m_bitmapType; + + // Copy sub region of this bitmap + if(M_BITMAPDATA->m_bitmapType == kMacBitmapTypePict) + { + printf("GetSubBitmap: Copy a region of a Pict structure - TODO\n"); + } + else if(M_BITMAPDATA->m_bitmapType == kMacBitmapTypeGrafWorld) + { + // Copy mask + if(GetMask()) + { + GWorldPtr submask, mask; + RGBColor color; + + mask = (GWorldPtr) GetMask()->GetMaskBitmap(); + submask = wxMacCreateGWorld(rect.width, rect.height, GetMask()->GetDepth() ); + LockPixels(GetGWorldPixMap(mask)); + LockPixels(GetGWorldPixMap(submask)); + + for(int yy = 0; yy < rect.height; yy++) + { + for(int xx = 0; xx < rect.width; xx++) + { + SetGWorld(mask, NULL); + GetCPixel(rect.x + xx, rect.y + yy, &color); + SetGWorld(submask, NULL); + SetCPixel(xx,yy, &color); + } + } + UnlockPixels(GetGWorldPixMap(mask)); + UnlockPixels(GetGWorldPixMap(submask)); + ref->m_bitmapMask = new wxMask; + ref->m_bitmapMask->SetMaskBitmap(submask); + } + + // Copy bitmap + if(GetHBITMAP()) + { + GWorldPtr subbitmap, bitmap; + RGBColor color; + + bitmap = (GWorldPtr) GetHBITMAP(); + subbitmap = (GWorldPtr) ref->m_hBitmap ; + LockPixels(GetGWorldPixMap(bitmap)); + LockPixels(GetGWorldPixMap(subbitmap)); + + for(int yy = 0; yy < rect.height; yy++) + { + for(int xx = 0; xx < rect.width; xx++) + { + SetGWorld(bitmap, NULL); + GetCPixel(rect.x + xx, rect.y + yy, &color); + SetGWorld(subbitmap, NULL); + SetCPixel(xx, yy, &color); + } + } + UnlockPixels(GetGWorldPixMap(bitmap)); + UnlockPixels(GetGWorldPixMap(subbitmap)); + } + } + SetGWorld( origPort, origDevice ); + + return ret; +} + +bool wxBitmap::Create(int w, int h, int d) +{ + UnRef(); + + m_refData = new wxBitmapRefData; + + M_BITMAPDATA->m_width = w; + M_BITMAPDATA->m_height = h; + M_BITMAPDATA->m_depth = d; + + M_BITMAPDATA->m_bitmapType = kMacBitmapTypeGrafWorld ; + M_BITMAPDATA->m_hBitmap = wxMacCreateGWorld( w , h , d ) ; + M_BITMAPDATA->m_ok = ( M_BITMAPDATA->m_hBitmap != NULL ) ; + return M_BITMAPDATA->m_ok; +} + +int wxBitmap::GetBitmapType() const +{ + wxCHECK_MSG( Ok(), kMacBitmapTypeUnknownType, wxT("invalid bitmap") ); + + return M_BITMAPDATA->m_bitmapType; +} + +void wxBitmap::SetHBITMAP(WXHBITMAP bmp) +{ + if (!M_BITMAPDATA) + m_refData = new wxBitmapRefData; + else + DisposeBitmapRefData( M_BITMAPDATA ) ; + + M_BITMAPDATA->m_bitmapType = kMacBitmapTypeGrafWorld ; + M_BITMAPDATA->m_hBitmap = bmp ; + M_BITMAPDATA->m_ok = ( M_BITMAPDATA->m_hBitmap != NULL ) ; +} + +void wxBitmap::SetHICON(WXHICON ico) +{ + if (!M_BITMAPDATA) + m_refData = new wxBitmapRefData; + else + DisposeBitmapRefData( M_BITMAPDATA ) ; + + M_BITMAPDATA->m_bitmapType = kMacBitmapTypeIcon ; + M_BITMAPDATA->m_hIcon = ico ; + M_BITMAPDATA->m_ok = ( M_BITMAPDATA->m_hIcon != NULL ) ; +} + +void wxBitmap::SetPict(WXHMETAFILE pict) +{ + if (!M_BITMAPDATA) + m_refData = new wxBitmapRefData; + else + DisposeBitmapRefData( M_BITMAPDATA ) ; + + M_BITMAPDATA->m_bitmapType = kMacBitmapTypePict ; + M_BITMAPDATA->m_hPict = pict ; + M_BITMAPDATA->m_ok = ( M_BITMAPDATA->m_hPict != NULL ) ; +} + +bool wxBitmap::LoadFile(const wxString& filename, wxBitmapType type) +{ + UnRef(); + + wxBitmapHandler *handler = FindHandler(type); + + if ( handler ) + { + m_refData = new wxBitmapRefData; + + return handler->LoadFile(this, filename, type, -1, -1); + } + else + { + wxImage loadimage(filename, type); + if (loadimage.Ok()) { + *this = loadimage; + return true; + } + } + wxLogWarning(wxT("no bitmap handler for type %d defined."), type); + return false; +} + +bool wxBitmap::Create(void *data, wxBitmapType type, int width, int height, int depth) +{ + UnRef(); + + m_refData = new wxBitmapRefData; + + wxBitmapHandler *handler = FindHandler(type); + + if ( handler == NULL ) { + wxLogWarning(wxT("no bitmap handler for type %d defined."), type); + + return FALSE; + } + + return handler->Create(this, data, type, width, height, depth); +} + +wxBitmap::wxBitmap(const wxImage& image, int depth) +{ + wxCHECK_RET( image.Ok(), wxT("invalid image") ) + wxCHECK_RET( depth == -1, wxT("invalid bitmap depth") ) + + m_refData = new wxBitmapRefData(); + + // width and height of the device-dependent bitmap + int width = image.GetWidth(); + int height = image.GetHeight(); + + // Create picture + + Create( width , height , 32 ) ; + + CGrafPtr origPort ; + GDHandle origDevice ; + + PixMapHandle pixMap = GetGWorldPixMap((GWorldPtr)GetHBITMAP()) ; + LockPixels( pixMap ); + + GetGWorld( &origPort , &origDevice ) ; + SetGWorld( (GWorldPtr) GetHBITMAP() , NULL ) ; + + // Render image + register unsigned char* data = image.GetData(); + char* destinationBase = GetPixBaseAddr( pixMap ); + register unsigned char* destination = (unsigned char*) destinationBase ; + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + *destination++ = 0 ; + *destination++ = *data++ ; + *destination++ = *data++ ; + *destination++ = *data++ ; + } + destinationBase += ((**pixMap).rowBytes & 0x7fff); + destination = (unsigned char*) destinationBase ; + } + if ( image.HasAlpha() ) + { + unsigned char *alpha = image.GetAlpha(); + + wxColour maskcolor(image.GetMaskRed(), image.GetMaskGreen(), image.GetMaskBlue()); + RGBColor color ; + wxBitmap maskBitmap ; + + maskBitmap.Create( width, height, 24); + LockPixels( GetGWorldPixMap( (GWorldPtr) maskBitmap.GetHBITMAP()) ); + SetGWorld( (GWorldPtr) maskBitmap.GetHBITMAP(), NULL); + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + memset( &color , 255 - *alpha , sizeof( color ) ); + SetCPixel(x,y, &color); + + alpha += 1 ; + } + } // for height + SetGWorld( (GWorldPtr) GetHBITMAP(), NULL); + SetMask(new wxMask( maskBitmap )); + UnlockPixels( GetGWorldPixMap( (GWorldPtr) maskBitmap.GetHBITMAP()) ); + } + else if ( image.HasMask() ) + { + data = image.GetData(); + + wxColour maskcolor(image.GetMaskRed(), image.GetMaskGreen(), image.GetMaskBlue()); + RGBColor white = { 0xffff, 0xffff, 0xffff }; + RGBColor black = { 0 , 0 , 0 }; + wxBitmap maskBitmap ; + + maskBitmap.Create( width, height, 1); + LockPixels( GetGWorldPixMap( (GWorldPtr) maskBitmap.GetHBITMAP()) ); + SetGWorld( (GWorldPtr) maskBitmap.GetHBITMAP(), NULL); + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + if ( data[0] == image.GetMaskRed() && data[1] == image.GetMaskGreen() && data[2] == image.GetMaskBlue() ) + { + SetCPixel(x,y, &white); + } + else { + SetCPixel(x,y, &black); + } + data += 3 ; + } + } // for height + SetGWorld( (GWorldPtr) GetHBITMAP(), NULL); + SetMask(new wxMask( maskBitmap )); + UnlockPixels( GetGWorldPixMap( (GWorldPtr) maskBitmap.GetHBITMAP()) ); + } + + UnlockPixels( GetGWorldPixMap( (GWorldPtr) GetHBITMAP()) ); + SetGWorld( origPort, origDevice ); +} + +wxImage wxBitmap::ConvertToImage() const +{ + wxImage image; + + wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") ); + + // create an wxImage object + int width = GetWidth(); + int height = GetHeight(); + image.Create( width, height ); + + unsigned char *data = image.GetData(); + + wxCHECK_MSG( data, wxNullImage, wxT("Could not allocate data for image") ); + + GWorldPtr origPort; + GDHandle origDevice; + RgnHandle maskRgn = NULL ; + GWorldPtr tempPort = NULL ; + int index; + RGBColor color; + // background color set to RGB(16,16,16) in consistent with wxGTK + unsigned char mask_r=16, mask_g=16, mask_b=16; + SInt16 r,g,b; + wxMask *mask = GetMask(); + + GetGWorld( &origPort, &origDevice ); + if ( GetBitmapType() != kMacBitmapTypeGrafWorld ) + { + tempPort = wxMacCreateGWorld( width , height , -1) ; + } + else + { + tempPort = (GWorldPtr) GetHBITMAP() ; + } + LockPixels(GetGWorldPixMap(tempPort)); + SetGWorld( tempPort, NULL); + if ( GetBitmapType() == kMacBitmapTypePict || GetBitmapType() == kMacBitmapTypeIcon ) + { + Rect bitmaprect = { 0 , 0 , height, width }; + if ( GetBitmapType() == kMacBitmapTypeIcon ) + { + ::PlotCIconHandle( &bitmaprect , atNone , ttNone , MAC_WXHICON(GetHICON()) ) ; + maskRgn = NewRgn() ; + BitMapToRegion( maskRgn , &(**(MAC_WXHICON(GetHICON()))).iconMask ) ; + } + else + ::DrawPicture( (PicHandle) GetPict(), &bitmaprect ) ; + } + // Copy data into image + index = 0; + for (int yy = 0; yy < height; yy++) + { + for (int xx = 0; xx < width; xx++) + { + GetCPixel(xx,yy, &color); + r = ((color.red ) >> 8); + g = ((color.green ) >> 8); + b = ((color.blue ) >> 8); + data[index ] = r; + data[index + 1] = g; + data[index + 2] = b; + if ( maskRgn ) + { + Point pt ; + pt.h = xx ; + pt.v = yy ; + if ( !PtInRgn( pt , maskRgn ) ) + { + data[index ] = mask_r; + data[index + 1] = mask_g; + data[index + 2] = mask_b; + } + } + else + { + if (mask) + { + if (mask->PointMasked(xx,yy)) + { + data[index ] = mask_r; + data[index + 1] = mask_g; + data[index + 2] = mask_b; + } + } + } + index += 3; + } + } + if (mask || maskRgn ) + { + image.SetMaskColour( mask_r, mask_g, mask_b ); + image.SetMask( true ); + } + + // Free resources + UnlockPixels(GetGWorldPixMap( tempPort )); + SetGWorld(origPort, origDevice); + if ( GetBitmapType() != kMacBitmapTypeGrafWorld ) + { + wxMacDestroyGWorld( tempPort ) ; + } + if ( maskRgn ) + { + DisposeRgn( maskRgn ) ; + } + + return image; +} + + +bool wxBitmap::SaveFile(const wxString& filename, wxBitmapType type, + const wxPalette *palette) const +{ + wxBitmapHandler *handler = FindHandler(type); + + if ( handler ) + { + return handler->SaveFile(this, filename, type, palette); + } + else + { + wxImage image = ConvertToImage(); + + return image.SaveFile(filename, type); + } + + wxLogWarning(wxT("no bitmap handler for type %d defined."), type); + return false; +} + +bool wxBitmap::Ok() const +{ + return (M_BITMAPDATA && M_BITMAPDATA->m_ok); +} + +int wxBitmap::GetHeight() const +{ + wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") ); + + return M_BITMAPDATA->m_height; +} + +int wxBitmap::GetWidth() const +{ + wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") ); + + return M_BITMAPDATA->m_width; +} + +int wxBitmap::GetDepth() const +{ + wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") ); + + return M_BITMAPDATA->m_depth; +} + +int wxBitmap::GetQuality() const +{ + wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") ); + + return M_BITMAPDATA->m_quality; +} + +wxMask *wxBitmap::GetMask() const +{ + wxCHECK_MSG( Ok(), (wxMask *) NULL, wxT("invalid bitmap") ); + + return M_BITMAPDATA->m_bitmapMask; +} + +void wxBitmap::SetWidth(int w) +{ + if (!M_BITMAPDATA) + m_refData = new wxBitmapRefData; + + M_BITMAPDATA->m_width = w; +} + +void wxBitmap::SetHeight(int h) +{ + if (!M_BITMAPDATA) + m_refData = new wxBitmapRefData; + + M_BITMAPDATA->m_height = h; +} + +void wxBitmap::SetDepth(int d) +{ + if (!M_BITMAPDATA) + m_refData = new wxBitmapRefData; + + M_BITMAPDATA->m_depth = d; +} + +void wxBitmap::SetQuality(int q) +{ + if (!M_BITMAPDATA) + m_refData = new wxBitmapRefData; + + M_BITMAPDATA->m_quality = q; +} + +void wxBitmap::SetOk(bool isOk) +{ + if (!M_BITMAPDATA) + m_refData = new wxBitmapRefData; + + M_BITMAPDATA->m_ok = isOk; +} + +#if wxUSE_PALETTE +wxPalette *wxBitmap::GetPalette() const +{ + wxCHECK_MSG( Ok(), NULL, wxT("Invalid bitmap GetPalette()") ); + + return &M_BITMAPDATA->m_bitmapPalette; +} + +void wxBitmap::SetPalette(const wxPalette& palette) +{ + if (!M_BITMAPDATA) + m_refData = new wxBitmapRefData; + + M_BITMAPDATA->m_bitmapPalette = palette ; +} +#endif // wxUSE_PALETTE + +void wxBitmap::SetMask(wxMask *mask) +{ + if (!M_BITMAPDATA) + m_refData = new wxBitmapRefData; + + // Remove existing mask if there is one. + delete M_BITMAPDATA->m_bitmapMask; + + M_BITMAPDATA->m_bitmapMask = mask ; +} + +WXHBITMAP wxBitmap::GetHBITMAP() const +{ + wxCHECK_MSG( Ok(), NULL, wxT("invalid bitmap") ); + + return MAC_WXHBITMAP(M_BITMAPDATA->m_hBitmap); +} + +WXHMETAFILE wxBitmap::GetPict( bool *created ) const +{ + wxCHECK_MSG( Ok(), NULL, wxT("invalid bitmap") ); + + PicHandle picture = NULL ; // This is the returned picture + if ( created ) + (*created) = false ; + // If bitmap already in Pict format return pointer + if(M_BITMAPDATA->m_bitmapType == kMacBitmapTypePict) { + return M_BITMAPDATA->m_hPict; + } + else if(M_BITMAPDATA->m_bitmapType != kMacBitmapTypeGrafWorld) { + // Invalid bitmap + return NULL; + } + else + { + if ( GetMask() ) + { + picture = wxMacCreatePict( MAC_WXHBITMAP(M_BITMAPDATA->m_hBitmap) , MAC_WXHBITMAP(GetMask()->GetMaskBitmap() ) ) ; + } + else + { + picture = wxMacCreatePict( MAC_WXHBITMAP(M_BITMAPDATA->m_hBitmap) , NULL ) ; + } + if ( created && picture ) + (*created) = true ; + } + return picture ; +} + +/* + * wxMask + */ + +wxMask::wxMask() + : m_maskBitmap(NULL) +{ +} + +// Construct a mask from a bitmap and a colour indicating +// the transparent area +wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour) + : m_maskBitmap(NULL) +{ + Create(bitmap, colour); +} + +// Construct a mask from a bitmap and a palette index indicating +// the transparent area +wxMask::wxMask(const wxBitmap& bitmap, int paletteIndex) + : m_maskBitmap(NULL) +{ + Create(bitmap, paletteIndex); +} + +// Construct a mask from a mono bitmap (copies the bitmap). +wxMask::wxMask(const wxBitmap& bitmap) + : m_maskBitmap(NULL) +{ + Create(bitmap); +} + +wxMask::~wxMask() +{ + if ( m_maskBitmap ) + { + wxMacDestroyGWorld( (GWorldPtr) m_maskBitmap ) ; + m_maskBitmap = NULL ; + } +} + +// Create a mask from a mono bitmap (copies the bitmap). +bool wxMask::Create(const wxBitmap& bitmap) +{ + if ( m_maskBitmap ) + { + wxMacDestroyGWorld( (GWorldPtr) m_maskBitmap ) ; + m_maskBitmap = NULL ; + } + wxCHECK_MSG( bitmap.GetBitmapType() == kMacBitmapTypeGrafWorld, false, + wxT("Cannot create mask from this bitmap type (TODO)")); + // other types would require a temporary bitmap. not yet implemented + + wxCHECK_MSG( bitmap.Ok(), false, wxT("Invalid bitmap")); + + m_depth = bitmap.GetDepth() ; + m_maskBitmap = wxMacCreateGWorld(bitmap.GetWidth(), bitmap.GetHeight(), bitmap.GetDepth() ); + Rect rect = { 0,0, bitmap.GetHeight(), bitmap.GetWidth() }; + + LockPixels( GetGWorldPixMap( (GWorldPtr) m_maskBitmap) ); + LockPixels( GetGWorldPixMap( (GWorldPtr) bitmap.GetHBITMAP()) ); + CopyBits(GetPortBitMapForCopyBits( (GWorldPtr) bitmap.GetHBITMAP()), + GetPortBitMapForCopyBits( (GWorldPtr) m_maskBitmap), + &rect, &rect, srcCopy, 0); + UnlockPixels( GetGWorldPixMap( (GWorldPtr) m_maskBitmap) ); + UnlockPixels( GetGWorldPixMap( (GWorldPtr) bitmap.GetHBITMAP()) ); + + return FALSE; +} + +// Create a mask from a bitmap and a palette index indicating +// the transparent area +bool wxMask::Create(const wxBitmap& bitmap, int paletteIndex) +{ + // TODO + wxCHECK_MSG( 0, false, wxT("wxMask::Create not yet implemented")); + return FALSE; +} + +// Create a mask from a bitmap and a colour indicating +// the transparent area +bool wxMask::Create(const wxBitmap& bitmap, const wxColour& colour) +{ + if ( m_maskBitmap ) + { + wxMacDestroyGWorld( (GWorldPtr) m_maskBitmap ) ; + m_maskBitmap = NULL ; + } + wxCHECK_MSG( bitmap.GetBitmapType() == kMacBitmapTypeGrafWorld, false, + wxT("Cannot create mask from this bitmap type (TODO)")); + // other types would require a temporary bitmap. not yet implemented + + wxCHECK_MSG( bitmap.Ok(), false, wxT("Illigal bitmap")); + + m_maskBitmap = wxMacCreateGWorld( bitmap.GetWidth() , bitmap.GetHeight() , 1 ); + m_depth = 1 ; + LockPixels( GetGWorldPixMap( (GWorldPtr) m_maskBitmap ) ); + LockPixels( GetGWorldPixMap( (GWorldPtr) bitmap.GetHBITMAP() ) ); + RGBColor maskColor = MAC_WXCOLORREF(colour.GetPixel()); + + // this is not very efficient, but I can't think + // of a better way of doing it + CGrafPtr origPort ; + GDHandle origDevice ; + RGBColor col; + RGBColor colors[2] = { + { 0xFFFF, 0xFFFF, 0xFFFF }, + { 0, 0, 0 }}; + + GetGWorld( &origPort , &origDevice ) ; + for (int w = 0; w < bitmap.GetWidth(); w++) + { + for (int h = 0; h < bitmap.GetHeight(); h++) + { + SetGWorld( (GWorldPtr) bitmap.GetHBITMAP(), NULL ) ; + GetCPixel( w , h , &col ) ; + SetGWorld( (GWorldPtr) m_maskBitmap , NULL ) ; + if (col.red == maskColor.red && col.green == maskColor.green && col.blue == maskColor.blue) + { + SetCPixel( w , h , &colors[0] ) ; + } + else + { + SetCPixel( w , h , &colors[1] ) ; + } + } + } + UnlockPixels( GetGWorldPixMap( (CGrafPtr) m_maskBitmap ) ) ; + UnlockPixels( GetGWorldPixMap( (GWorldPtr) bitmap.GetHBITMAP() ) ) ; + SetGWorld( origPort , origDevice ) ; + + return TRUE; +} + +bool wxMask::PointMasked(int x, int y) +{ + GWorldPtr origPort; + GDHandle origDevice; + RGBColor color; + bool masked = true; + + GetGWorld( &origPort, &origDevice); + + //Set port to mask and see if it masked (1) or not ( 0 ) + SetGWorld( (GWorldPtr) m_maskBitmap, NULL); + LockPixels(GetGWorldPixMap( (GWorldPtr) m_maskBitmap)); + GetCPixel(x,y, &color); + masked = !(color.red == 0 && color.green == 0 && color.blue == 0); + UnlockPixels(GetGWorldPixMap( (GWorldPtr) m_maskBitmap)); + + SetGWorld( origPort, origDevice); + + return masked; +} + +/* + * wxBitmapHandler + */ + +wxBitmapHandler::~wxBitmapHandler() +{ +} + +bool wxBitmapHandler::Create(wxBitmap *bitmap, void *data, long type, int width, int height, int depth) +{ + return FALSE; +} + +bool wxBitmapHandler::LoadFile(wxBitmap *bitmap, const wxString& name, long flags, + int desiredWidth, int desiredHeight) +{ + return FALSE; +} + +bool wxBitmapHandler::SaveFile(const wxBitmap *bitmap, const wxString& name, int type, const wxPalette *palette) +{ + return FALSE; +} + +/* + * Standard handlers + */ + +class WXDLLEXPORT wxPICTResourceHandler: public wxBitmapHandler +{ + DECLARE_DYNAMIC_CLASS(wxPICTResourceHandler) +public: + inline wxPICTResourceHandler() + { + m_name = wxT("Macintosh Pict resource"); + m_extension = wxEmptyString; + m_type = wxBITMAP_TYPE_PICT_RESOURCE; + }; + + virtual bool LoadFile(wxBitmap *bitmap, const wxString& name, long flags, + int desiredWidth, int desiredHeight); +}; +IMPLEMENT_DYNAMIC_CLASS(wxPICTResourceHandler, wxBitmapHandler) + +bool wxPICTResourceHandler::LoadFile(wxBitmap *bitmap, const wxString& name, long flags, + int desiredWidth, int desiredHeight) +{ + Str255 theName ; + wxMacStringToPascal( name , theName ) ; + + PicHandle thePict = (PicHandle ) GetNamedResource( 'PICT' , theName ) ; + if ( thePict ) + { + PictInfo theInfo ; + + GetPictInfo( thePict , &theInfo , 0 , 0 , systemMethod , 0 ) ; + DetachResource( (Handle) thePict ) ; + M_BITMAPHANDLERDATA->m_bitmapType = kMacBitmapTypePict ; + M_BITMAPHANDLERDATA->m_hPict = thePict ; + M_BITMAPHANDLERDATA->m_width = theInfo.sourceRect.right - theInfo.sourceRect.left ; + M_BITMAPHANDLERDATA->m_height = theInfo.sourceRect.bottom - theInfo.sourceRect.top ; + + M_BITMAPHANDLERDATA->m_depth = theInfo.depth ; + M_BITMAPHANDLERDATA->m_ok = true ; + M_BITMAPHANDLERDATA->m_numColors = theInfo.uniqueColors ; +// M_BITMAPHANDLERDATA->m_bitmapPalette; +// M_BITMAPHANDLERDATA->m_quality; + return TRUE ; + } + return FALSE ; +} + +void wxBitmap::InitStandardHandlers() +{ + AddHandler(new wxPICTResourceHandler) ; + AddHandler(new wxICONResourceHandler) ; +} + +// ---------------------------------------------------------------------------- +// raw bitmap access support +// ---------------------------------------------------------------------------- + +void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp) +{ + if ( !Ok() ) + { + // no bitmap, no data (raw or otherwise) + return NULL; + } + + if ( M_BITMAPDATA->m_bitmapType != kMacBitmapTypeGrafWorld ) + { + wxFAIL_MSG( _T("GetRawData() only supported for GWorlds") ); + + return NULL; + } + + GWorldPtr gworld = MAC_WXHBITMAP(M_BITMAPDATA->m_hBitmap); + PixMapHandle hPixMap = GetGWorldPixMap(gworld); + wxCHECK_MSG( hPixMap && *hPixMap, NULL, + _T("GetRawData(): failed to get PixMap from GWorld?") ); + + wxCHECK_MSG( (*hPixMap)->pixelSize == bpp, NULL, + _T("GetRawData(): pixel format mismatch") ); + + if ( !LockPixels(hPixMap) ) + { + wxFAIL_MSG( _T("failed to lock PixMap in GetRawData()") ); + + return NULL; + } + + data.m_width = GetWidth(); + data.m_height = GetHeight(); + data.m_stride = (*hPixMap)->rowBytes & 0x7fff; + + M_BITMAPDATA->m_hasAlpha = false; + + return GetPixBaseAddr(hPixMap); +} + +void wxBitmap::UngetRawData(wxPixelDataBase& dataBase) +{ + if ( !Ok() ) + return; + + if ( M_BITMAPDATA->m_hasAlpha ) + { + wxAlphaPixelData& data = (wxAlphaPixelData&)dataBase; + + int w = data.GetWidth(), + h = data.GetHeight(); + + wxBitmap bmpMask(GetWidth(), GetHeight(), 32); + wxAlphaPixelData dataMask(bmpMask, data.GetOrigin(), wxSize(w, h)); + wxAlphaPixelData::Iterator pMask(dataMask), + p(data); + for ( int y = 0; y < h; y++ ) + { + wxAlphaPixelData::Iterator rowStartMask = pMask, + rowStart = p; + + for ( int x = 0; x < w; x++ ) + { + const wxAlphaPixelData::Iterator::ChannelType + alpha = p.Alpha(); + + pMask.Red() = alpha; + pMask.Green() = alpha; + pMask.Blue() = alpha; + + ++p; + ++pMask; + } + + p = rowStart; + p.OffsetY(data, 1); + + pMask = rowStartMask; + pMask.OffsetY(dataMask, 1); + } + + SetMask(new wxMask(bmpMask)); + } + + GWorldPtr gworld = MAC_WXHBITMAP(M_BITMAPDATA->m_hBitmap); + PixMapHandle hPixMap = GetGWorldPixMap(gworld); + if ( hPixMap ) + { + UnlockPixels(hPixMap); + } +} + +void wxBitmap::UseAlpha() +{ + // remember that we are using alpha channel, we'll need to create a proper + // mask in UngetRawData() + M_BITMAPDATA->m_hasAlpha = true; +} + diff --git a/src/mac/classic/bmpbuttn.cpp b/src/mac/classic/bmpbuttn.cpp new file mode 100644 index 0000000000..f6ce4dd00c --- /dev/null +++ b/src/mac/classic/bmpbuttn.cpp @@ -0,0 +1,113 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: bmpbuttn.cpp +// Purpose: wxBitmapButton +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "bmpbuttn.h" +#endif + +#include "wx/window.h" +#include "wx/bmpbuttn.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxBitmapButton, wxButton) +#endif + +#include "wx/mac/uma.h" +#include "wx/bitmap.h" + +bool wxBitmapButton::Create(wxWindow *parent, wxWindowID id, const wxBitmap& bitmap, + const wxPoint& pos, + const wxSize& size, long style, + const wxValidator& validator, + const wxString& name) +{ + // since bitmapbuttonbase is subclass of button calling wxBitmapButtonBase::Create + // essentially creates an additional button + if ( !wxControl::Create(parent, id, pos, size, + style, validator, name) ) + return false; + + m_bmpNormal = bitmap; + + if (style & wxBU_AUTODRAW) + { + m_marginX = wxDEFAULT_BUTTON_MARGIN; + m_marginY = wxDEFAULT_BUTTON_MARGIN; + } + else + { + m_marginX = 0; + m_marginY = 0; + } + + int width = size.x; + int height = size.y; + + if ( bitmap.Ok() ) + { + wxSize newSize = DoGetBestSize(); + if ( width == -1 ) + width = newSize.x; + if ( height == -1 ) + height = newSize.y; + } + + Rect bounds ; + Str255 title ; + m_bmpNormal = bitmap; + wxBitmapRefData * bmap = NULL ; + + if ( m_bmpNormal.Ok() ) + bmap = (wxBitmapRefData*) ( m_bmpNormal.GetRefData()) ; + + MacPreControlCreate( parent , id , wxEmptyString , pos , wxSize( width , height ) ,style, validator , name , &bounds , title ) ; + + m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()) , &bounds , title , false , 0 , + kControlBehaviorOffsetContents + + ( bmap && bmap->m_bitmapType == kMacBitmapTypeIcon ? + kControlContentCIconHandle : kControlContentPictHandle ) , 0, + (( style & wxBU_AUTODRAW ) ? kControlBevelButtonSmallBevelProc : kControlBevelButtonNormalBevelProc ), (long) this ) ; + wxASSERT_MSG( (ControlHandle) m_macControl != NULL , wxT("No valid mac control") ) ; + + ControlButtonContentInfo info ; + wxMacCreateBitmapButton( &info , m_bmpNormal ) ; + if ( info.contentType != kControlNoContent ) + { + ::SetControlData( (ControlHandle) m_macControl , kControlButtonPart , kControlBevelButtonContentTag , sizeof(info) , (char*) &info ) ; + } + MacPostControlCreate() ; + + return TRUE; +} + +void wxBitmapButton::SetBitmapLabel(const wxBitmap& bitmap) +{ + m_bmpNormal = bitmap; + + ControlButtonContentInfo info ; + wxMacCreateBitmapButton( &info , m_bmpNormal ) ; + if ( info.contentType != kControlNoContent ) + { + ::SetControlData( (ControlHandle) m_macControl , kControlButtonPart , kControlBevelButtonContentTag , sizeof(info) , (char*) &info ) ; + } +} + + +wxSize wxBitmapButton::DoGetBestSize() const +{ + wxSize best; + if (m_bmpNormal.Ok()) + { + best.x = m_bmpNormal.GetWidth() + 2*m_marginX; + best.y = m_bmpNormal.GetHeight() + 2*m_marginY; + } + return best; +} diff --git a/src/mac/classic/brush.cpp b/src/mac/classic/brush.cpp new file mode 100644 index 0000000000..d484314a2c --- /dev/null +++ b/src/mac/classic/brush.cpp @@ -0,0 +1,229 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: brush.cpp +// Purpose: wxBrush +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "brush.h" +#endif + +#include "wx/setup.h" +#include "wx/utils.h" +#include "wx/brush.h" + +#include "wx/mac/private.h" + +#if !USE_SHARED_LIBRARIES +IMPLEMENT_DYNAMIC_CLASS(wxBrush, wxGDIObject) +#endif + +class WXDLLEXPORT wxBrushRefData: public wxGDIRefData +{ + friend class WXDLLEXPORT wxBrush; +public: + wxBrushRefData(); + wxBrushRefData(const wxBrushRefData& data); + ~wxBrushRefData(); + +protected: + wxMacBrushKind m_macBrushKind ; + int m_style; + wxBitmap m_stipple ; + wxColour m_colour; + + ThemeBrush m_macThemeBrush ; + + ThemeBackgroundKind m_macThemeBackground ; + Rect m_macThemeBackgroundExtent ; +}; + +#define M_BRUSHDATA ((wxBrushRefData *)m_refData) + +wxBrushRefData::wxBrushRefData() + : m_style(wxSOLID) +{ + m_macBrushKind = kwxMacBrushColour ; +} + +wxBrushRefData::wxBrushRefData(const wxBrushRefData& data) + : wxGDIRefData() + , m_style(data.m_style) +{ + m_stipple = data.m_stipple; + m_colour = data.m_colour; + m_macBrushKind = data.m_macBrushKind ; + m_macThemeBrush = data.m_macThemeBrush ; + m_macThemeBackground = data.m_macThemeBackground ; + m_macThemeBackgroundExtent = data.m_macThemeBackgroundExtent ; +} + +wxBrushRefData::~wxBrushRefData() +{ +} + +// Brushes +wxBrush::wxBrush() +{ +} + +wxBrush::~wxBrush() +{ +} + +wxBrush::wxBrush(const wxColour& col, int Style) +{ + m_refData = new wxBrushRefData; + + M_BRUSHDATA->m_colour = col; + M_BRUSHDATA->m_style = Style; + + RealizeResource(); +} + +wxBrush::wxBrush(const wxBitmap& stipple) +{ + m_refData = new wxBrushRefData; + + M_BRUSHDATA->m_colour = *wxBLACK; + M_BRUSHDATA->m_stipple = stipple; + + if (M_BRUSHDATA->m_stipple.GetMask()) + M_BRUSHDATA->m_style = wxSTIPPLE_MASK_OPAQUE; + else + M_BRUSHDATA->m_style = wxSTIPPLE; + + RealizeResource(); +} + +wxBrush::wxBrush(ThemeBrush macThemeBrush ) +{ + m_refData = new wxBrushRefData; + + M_BRUSHDATA->m_macBrushKind = kwxMacBrushTheme; + M_BRUSHDATA->m_macThemeBrush = macThemeBrush; + + RealizeResource(); +} +void wxBrush::Unshare() +{ + // Don't change shared data + if (!m_refData) + { + m_refData = new wxBrushRefData(); + } + else + { + wxBrushRefData* ref = new wxBrushRefData(*(wxBrushRefData*)m_refData); + UnRef(); + m_refData = ref; + } +} + +void wxBrush::SetColour(const wxColour& col) +{ + Unshare(); + M_BRUSHDATA->m_macBrushKind = kwxMacBrushColour; + M_BRUSHDATA->m_colour = col; + + RealizeResource(); +} + +void wxBrush::SetColour(unsigned char r, unsigned char g, unsigned char b) +{ + Unshare(); + + M_BRUSHDATA->m_macBrushKind = kwxMacBrushColour; + M_BRUSHDATA->m_colour.Set(r, g, b); + + RealizeResource(); +} + +void wxBrush::SetStyle(int Style) +{ + Unshare(); + + M_BRUSHDATA->m_macBrushKind = kwxMacBrushColour; + M_BRUSHDATA->m_style = Style; + + RealizeResource(); +} + +void wxBrush::SetStipple(const wxBitmap& Stipple) +{ + Unshare(); + + M_BRUSHDATA->m_macBrushKind = kwxMacBrushColour; + M_BRUSHDATA->m_stipple = Stipple; + + RealizeResource(); +} + +void wxBrush::SetMacTheme(ThemeBrush macThemeBrush) +{ + Unshare(); + + M_BRUSHDATA->m_macBrushKind = kwxMacBrushTheme; + M_BRUSHDATA->m_macThemeBrush = macThemeBrush; + + RealizeResource(); +} + +void wxBrush::SetMacThemeBackground(unsigned long macThemeBackground, const WXRECTPTR extent) +{ + Unshare(); + + M_BRUSHDATA->m_macBrushKind = kwxMacBrushThemeBackground; + M_BRUSHDATA->m_macThemeBackground = macThemeBackground; + M_BRUSHDATA->m_macThemeBackgroundExtent = *(Rect*)extent ; + RealizeResource(); +} + +bool wxBrush::RealizeResource() +{ + return TRUE; +} + +unsigned long wxBrush::GetMacThemeBackground( WXRECTPTR extent) const +{ + if ( M_BRUSHDATA && M_BRUSHDATA->m_macBrushKind == kwxMacBrushThemeBackground ) + { + if ( extent ) + *(Rect*)extent = M_BRUSHDATA->m_macThemeBackgroundExtent ; + return M_BRUSHDATA->m_macThemeBackground ; + } + else + { + return 0 ; + } +} + +short wxBrush::GetMacTheme() const +{ + return (M_BRUSHDATA ? ( M_BRUSHDATA->m_macBrushKind == kwxMacBrushTheme ? M_BRUSHDATA->m_macThemeBrush : kThemeBrushBlack) : kThemeBrushBlack); +} + +wxColour& wxBrush::GetColour() const +{ + return (M_BRUSHDATA ? M_BRUSHDATA->m_colour : wxNullColour); +} + +int wxBrush::GetStyle() const +{ + return (M_BRUSHDATA ? M_BRUSHDATA->m_style : 0); +} + +wxBitmap *wxBrush::GetStipple() const +{ + return (M_BRUSHDATA ? & M_BRUSHDATA->m_stipple : 0); +} + +wxMacBrushKind wxBrush::MacGetBrushKind() const +{ + return (M_BRUSHDATA ? M_BRUSHDATA->m_macBrushKind : kwxMacBrushColour); +} \ No newline at end of file diff --git a/src/mac/classic/button.cpp b/src/mac/classic/button.cpp new file mode 100644 index 0000000000..82e4e34c5f --- /dev/null +++ b/src/mac/classic/button.cpp @@ -0,0 +1,132 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: button.cpp +// Purpose: wxButton +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "button.h" +#endif + +#include "wx/defs.h" + +#include "wx/button.h" +#include "wx/panel.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxButton, wxControl) +#endif + +#include "wx/mac/uma.h" +// Button + +static const int kMacOSXHorizontalBorder = 2 ; +static const int kMacOSXVerticalBorder = 4 ; + +bool wxButton::Create(wxWindow *parent, wxWindowID id, const wxString& label, + const wxPoint& pos, + const wxSize& size, long style, + const wxValidator& validator, + const wxString& name) +{ + if ( !wxButtonBase::Create(parent, id, pos, size, style, validator, name) ) + return false; + + Rect bounds ; + Str255 title ; + + if ( UMAHasAquaLayout() ) + { + m_macHorizontalBorder = kMacOSXHorizontalBorder; + m_macVerticalBorder = kMacOSXVerticalBorder; + } + + MacPreControlCreate( parent , id , label , pos , size ,style, validator , name , &bounds , title ) ; + + m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()) , &bounds , title , false , 0 , 0 , 1, + kControlPushButtonProc , (long) this ) ; + wxASSERT_MSG( (ControlHandle) m_macControl != NULL , wxT("No valid mac control") ) ; + + MacPostControlCreate() ; + + return TRUE; +} + +void wxButton::SetDefault() +{ + wxWindow *parent = GetParent(); + wxButton *btnOldDefault = NULL; + if ( parent ) + { + btnOldDefault = wxDynamicCast(parent->GetDefaultItem(), + wxButton); + parent->SetDefaultItem(this); + } + + Boolean inData; + if ( btnOldDefault && btnOldDefault->m_macControl ) + { + inData = 0; + ::SetControlData( (ControlHandle) btnOldDefault->m_macControl , kControlButtonPart , + kControlPushButtonDefaultTag , sizeof( Boolean ) , (char*)(&inData) ) ; + } + if ( (ControlHandle) m_macControl ) + { + inData = 1; + ::SetControlData( (ControlHandle) m_macControl , kControlButtonPart , + kControlPushButtonDefaultTag , sizeof( Boolean ) , (char*)(&inData) ) ; + } +} + +wxSize wxButton::DoGetBestSize() const +{ + wxSize sz = GetDefaultSize() ; + + int wBtn = m_label.Length() * 8 + 12 + 2 * kMacOSXHorizontalBorder ; + + if (wBtn > sz.x) sz.x = wBtn; + + return sz ; +} + +wxSize wxButton::GetDefaultSize() +{ + int wBtn = 70 ; + int hBtn = 20 ; + + if ( UMAHasAquaLayout() ) + { + wBtn += 2 * kMacOSXHorizontalBorder ; + hBtn += 2 * kMacOSXVerticalBorder ; + } + + return wxSize(wBtn, hBtn); +} + +void wxButton::Command (wxCommandEvent & event) +{ + if ( (ControlHandle) m_macControl ) + { + HiliteControl( (ControlHandle) m_macControl , kControlButtonPart ) ; + unsigned long finalTicks ; + Delay( 8 , &finalTicks ) ; + HiliteControl( (ControlHandle) m_macControl , 0 ) ; + } + ProcessCommand (event); +} + +void wxButton::MacHandleControlClick( WXWidget WXUNUSED(control) , wxInt16 controlpart , bool WXUNUSED(mouseStillDown) ) +{ + if ( controlpart != kControlNoPart ) + { + wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, m_windowId ); + event.SetEventObject(this); + ProcessCommand(event); + } +} + diff --git a/src/mac/classic/carbrsrc.r b/src/mac/classic/carbrsrc.r new file mode 100644 index 0000000000..9326cc3b56 --- /dev/null +++ b/src/mac/classic/carbrsrc.r @@ -0,0 +1,7 @@ +// carbon for 9 +data 'carb' (0) { + $"0000" /* .. */ +}; + +// the plist resource should only be included in the application +// since it contains the bundle information and should not be duplicated diff --git a/src/mac/classic/checkbox.cpp b/src/mac/classic/checkbox.cpp new file mode 100644 index 0000000000..6e6aa299b2 --- /dev/null +++ b/src/mac/classic/checkbox.cpp @@ -0,0 +1,179 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: checkbox.cpp +// Purpose: wxCheckBox +// Author: Stefan Csomor +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "checkbox.h" +#endif + +#include "wx/defs.h" + +#include "wx/checkbox.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxCheckBox, wxControl) +IMPLEMENT_DYNAMIC_CLASS(wxBitmapCheckBox, wxCheckBox) +#endif + +#include "wx/mac/uma.h" + +// Single check box item +bool wxCheckBox::Create(wxWindow *parent, wxWindowID id, const wxString& label, + const wxPoint& pos, + const wxSize& size, long style, + const wxValidator& validator, + const wxString& name) +{ + if ( !wxCheckBoxBase::Create(parent, id, pos, size, style, validator, name) ) + return false; + + Rect bounds ; + Str255 title ; + + MacPreControlCreate( parent , id , label , pos , size ,style, validator , name , &bounds , title ) ; + + SInt16 maxValue = 1 /* kControlCheckboxCheckedValue */; + if (style & wxCHK_3STATE) + { + maxValue = 2 /* kControlCheckboxMixedValue */; + } + + m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()) , &bounds , title , false , 0 , 0 , maxValue, + kControlCheckBoxProc , (long) this ) ; + + MacPostControlCreate() ; + + return TRUE; +} + +void wxCheckBox::SetValue(bool val) +{ + if (val) + { + Set3StateValue(wxCHK_CHECKED); + } + else + { + Set3StateValue(wxCHK_UNCHECKED); + } +} + +bool wxCheckBox::GetValue() const +{ + return (DoGet3StateValue() != 0); +} + +void wxCheckBox::Command (wxCommandEvent & event) +{ + int state = event.GetInt(); + + wxCHECK_RET( (state == wxCHK_UNCHECKED) || (state == wxCHK_CHECKED) + || (state == wxCHK_UNDETERMINED), + wxT("event.GetInt() returned an invalid checkbox state") ); + + Set3StateValue((wxCheckBoxState) state); + + ProcessCommand(event); +} + +wxCheckBoxState wxCheckBox::DoGet3StateValue() const +{ + return (wxCheckBoxState) ::GetControl32BitValue( (ControlHandle) m_macControl ); +} + +void wxCheckBox::DoSet3StateValue(wxCheckBoxState val) +{ + ::SetControl32BitValue( (ControlHandle) m_macControl , (int) val) ; + MacRedrawControl() ; +} + +void wxCheckBox::MacHandleControlClick( WXWidget WXUNUSED(control), wxInt16 WXUNUSED(controlpart) , bool WXUNUSED(mouseStillDown) ) +{ + wxCommandEvent event(wxEVT_COMMAND_CHECKBOX_CLICKED, m_windowId ); + wxCheckBoxState state = Get3StateValue(); + + if (state == wxCHK_UNCHECKED) + { + state = wxCHK_CHECKED; + } + else if (state == wxCHK_CHECKED) + { + // If the style flag to allow the user setting the undetermined state + // is set, then set the state to undetermined. Otherwise set state to + // unchecked. + if ( Is3rdStateAllowedForUser() ) + { + state = wxCHK_UNDETERMINED; + } + else + { + state = wxCHK_UNCHECKED; + } + } + else if (state == wxCHK_UNDETERMINED) + { + state = wxCHK_UNCHECKED; + } + Set3StateValue(state); + + event.SetInt(state); + event.SetEventObject(this); + ProcessCommand(event); +} + +// Bitmap checkbox +bool wxBitmapCheckBox::Create(wxWindow *parent, wxWindowID id, + const wxBitmap *label, + const wxPoint& pos, + const wxSize& size, long style, + const wxValidator& validator, + const wxString& name) +{ + SetName(name); + SetValidator(validator); + m_windowStyle = style; + + if (parent) parent->AddChild(this); + + if ( id == -1 ) + m_windowId = NewControlId(); + else + m_windowId = id; + + // TODO: Create the bitmap checkbox + + return FALSE; +} + +void wxBitmapCheckBox::SetLabel(const wxBitmap *bitmap) +{ + // TODO + wxFAIL_MSG(wxT("wxBitmapCheckBox::SetLabel() not yet implemented")); +} + +void wxBitmapCheckBox::SetSize(int x, int y, int width, int height, int sizeFlags) +{ + wxControl::SetSize( x , y , width , height , sizeFlags ) ; +} + +void wxBitmapCheckBox::SetValue(bool val) +{ + // TODO + wxFAIL_MSG(wxT("wxBitmapCheckBox::SetValue() not yet implemented")); +} + +bool wxBitmapCheckBox::GetValue() const +{ + // TODO + wxFAIL_MSG(wxT("wxBitmapCheckBox::GetValue() not yet implemented")); + return FALSE; +} + + diff --git a/src/mac/classic/checklst.cpp b/src/mac/classic/checklst.cpp new file mode 100644 index 0000000000..c442bbdfcb --- /dev/null +++ b/src/mac/classic/checklst.cpp @@ -0,0 +1,453 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: checklst.cpp +// Purpose: implementation of wxCheckListBox class +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// headers & declarations +// ============================================================================ + +#ifdef __GNUG__ +#pragma implementation "checklst.h" +#endif + +#include "wx/defs.h" + +#if wxUSE_CHECKLISTBOX + +#include "wx/checklst.h" +#include "wx/arrstr.h" + +#include "wx/mac/uma.h" +#include + +// ============================================================================ +// implementation of wxCheckListBox +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxCheckListBox, wxListBox) + +const short kwxMacListWithVerticalScrollbar = 128 ; +const short kwxMacListItemHeight = 14 ; +const short kwxMacListCheckboxWidth = 14 ; + +#if PRAGMA_STRUCT_ALIGN + #pragma options align=mac68k +#elif PRAGMA_STRUCT_PACKPUSH + #pragma pack(push, 2) +#elif PRAGMA_STRUCT_PACK + #pragma pack(2) +#endif + +typedef struct { + unsigned short instruction; + void (*function)(); +} ldefRec, *ldefPtr, **ldefHandle; + +#if PRAGMA_STRUCT_ALIGN + #pragma options align=reset +#elif PRAGMA_STRUCT_PACKPUSH + #pragma pack(pop) +#elif PRAGMA_STRUCT_PACK + #pragma pack() +#endif + +extern "C" +{ +static pascal void wxMacCheckListDefinition( short message, Boolean isSelected, Rect *drawRect, + Cell cell, short dataOffset, short dataLength, + ListHandle listHandle ) ; +} + +static pascal void wxMacCheckListDefinition( short message, Boolean isSelected, Rect *drawRect, + Cell cell, short dataOffset, short dataLength, + ListHandle listHandle ) +{ + wxCheckListBox* list; + list = (wxCheckListBox*) GetControlReference( (ControlHandle) GetListRefCon(listHandle) ); + if ( list == NULL ) + return ; + + GrafPtr savePort; + GrafPtr grafPtr; + RgnHandle savedClipRegion; + SInt32 savedPenMode; + GetPort(&savePort); + SetPort((**listHandle).port); + grafPtr = (**listHandle).port ; + // typecast our refCon + + // Calculate the cell rect. + + switch( message ) { + case lInitMsg: + break; + + case lCloseMsg: + break; + + case lDrawMsg: + { + const wxString text = list->m_stringArray[cell.v] ; + int checked = list->m_checks[cell.v] ; + + // Save the current clip region, and set the clip region to the area we are about + // to draw. + + savedClipRegion = NewRgn(); + GetClip( savedClipRegion ); + + ClipRect( drawRect ); + EraseRect( drawRect ); + + const wxFont& font = list->GetFont(); + if ( font.Ok() ) + { + ::TextFont( font.GetMacFontNum() ) ; + ::TextSize( font.GetMacFontSize()) ; + ::TextFace( font.GetMacFontStyle() ) ; + } + + ThemeButtonDrawInfo info ; + info.state = kThemeStateActive ; + info.value = checked ? kThemeButtonOn : kThemeButtonOff ; + info.adornment = kThemeAdornmentNone ; + Rect checkRect = *drawRect ; + + + checkRect.left +=0 ; + checkRect.top +=0 ; + checkRect.right = checkRect.left + list->m_checkBoxWidth ; + checkRect.bottom = checkRect.top + list->m_checkBoxHeight ; + DrawThemeButton(&checkRect,kThemeCheckBox, + &info,NULL,NULL, NULL,0); + + MoveTo(drawRect->left + 2 + list->m_checkBoxWidth+2, drawRect->top + list->m_TextBaseLineOffset ); + + DrawText(text, 0 , text.Length()); + // If the cell is hilited, do the hilite now. Paint the cell contents with the + // appropriate QuickDraw transform mode. + + if( isSelected ) { + savedPenMode = GetPortPenMode( (CGrafPtr) grafPtr ); + SetPortPenMode( (CGrafPtr) grafPtr, hilitetransfermode ); + PaintRect( drawRect ); + SetPortPenMode( (CGrafPtr) grafPtr, savedPenMode ); + } + + // Restore the saved clip region. + + SetClip( savedClipRegion ); + DisposeRgn( savedClipRegion ); + } + break; + case lHiliteMsg: + + // Hilite or unhilite the cell. Paint the cell contents with the + // appropriate QuickDraw transform mode. + + GetPort( &grafPtr ); + savedPenMode = GetPortPenMode( (CGrafPtr) grafPtr ); + SetPortPenMode( (CGrafPtr) grafPtr, hilitetransfermode ); + PaintRect( drawRect ); + SetPortPenMode( (CGrafPtr) grafPtr, savedPenMode ); + break; + default : + break ; + } + SetPort(savePort); +} + +extern "C" void MacDrawStringCell(Rect *cellRect, Cell lCell, ListHandle theList, long refCon) ; + +static ListDefUPP macCheckListDefUPP = NULL ; + +// ---------------------------------------------------------------------------- +// creation +// ---------------------------------------------------------------------------- + +void wxCheckListBox::Init() +{ +} + +bool wxCheckListBox::Create(wxWindow *parent, + wxWindowID id, + const wxPoint &pos, + const wxSize &size, + const wxArrayString& choices, + long style, + const wxValidator& validator, + const wxString &name) +{ + wxCArrayString chs(choices); + + return Create(parent, id, pos, size, chs.GetCount(), chs.GetStrings(), + style, validator, name); +} + +bool wxCheckListBox::Create(wxWindow *parent, + wxWindowID id, + const wxPoint &pos, + const wxSize &size, + int n, + const wxString choices[], + long style, + const wxValidator& validator, + const wxString &name) +{ + if ( !wxCheckListBoxBase::Create(parent, id, pos, size, + n, choices, style, validator, name) ) + return false; + + m_noItems = 0 ; // this will be increased by our append command + m_selected = 0; + + m_checkBoxWidth = 12; + m_checkBoxHeight= 10; + + long h = m_checkBoxHeight ; +#if TARGET_CARBON + GetThemeMetric(kThemeMetricCheckBoxWidth,(long *)&m_checkBoxWidth); + GetThemeMetric(kThemeMetricCheckBoxHeight,&h); +#endif + + const wxFont& font = GetFont(); + + FontInfo finfo; + FetchFontInfo(font.GetMacFontNum(),font.GetMacFontSize(),font.GetMacFontStyle(),&finfo); + + m_TextBaseLineOffset= finfo.leading+finfo.ascent; + m_checkBoxHeight= finfo.leading+finfo.ascent+finfo.descent; + + if (m_checkBoxHeightMacGetRootWindow()), &bounds, false, 0, 1, false, true, + m_checkBoxHeight+2, 14, false, &listDef, (ControlRef *)&m_macControl ); + + GetControlData( (ControlHandle) m_macControl, kControlNoPart, kControlListBoxListHandleTag, + sizeof(ListHandle), (Ptr) &m_macList, &asize); + + SetControlReference( (ControlHandle) m_macControl, (long) this); + SetControlVisibility( (ControlHandle) m_macControl, false, false); + +#else + + long result ; + + wxStAppResource resload ; + m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()) , &bounds , title , false , + kwxMacListWithVerticalScrollbar , 0 , 0, + kControlListBoxProc , (long) this ) ; + ::GetControlData( (ControlHandle) m_macControl , kControlNoPart , kControlListBoxListHandleTag , + sizeof( ListHandle ) , (char*) &m_macList , &result ) ; + + HLock( (Handle) m_macList ) ; + ldefHandle ldef ; + ldef = (ldefHandle) NewHandle( sizeof(ldefRec) ) ; + if ( (**(ListHandle)m_macList).listDefProc != NULL ) + { + (**ldef).instruction = 0x4EF9; /* JMP instruction */ + (**ldef).function = (void(*)()) listDef.u.userProc; + (**(ListHandle)m_macList).listDefProc = (Handle) ldef ; + } + + Point pt = (**(ListHandle)m_macList).cellSize ; + pt.v = 14 ; + LCellSize( pt , (ListHandle)m_macList ) ; + LAddColumn( 1 , 0 , (ListHandle)m_macList ) ; +#endif + OptionBits options = 0; + if ( style & wxLB_MULTIPLE ) + { + options += lNoExtend ; + } + else if ( style & wxLB_EXTENDED ) + { + options += lExtendDrag ; + } + else + { + options = (OptionBits) lOnlyOne ; + } + SetListSelectionFlags((ListHandle)m_macList, options); + + MacPostControlCreate() ; + + for ( int i = 0 ; i < n ; i++ ) + { + Append( choices[i] ) ; + } + + LSetDrawingMode( true , (ListHandle) m_macList ) ; + + return TRUE; +} + +// ---------------------------------------------------------------------------- +// wxCheckListBox functions +// ---------------------------------------------------------------------------- + +bool wxCheckListBox::IsChecked(size_t item) const +{ + wxCHECK_MSG( item < m_checks.GetCount(), FALSE, + _T("invalid index in wxCheckListBox::IsChecked") ); + + return m_checks[item] != 0; +} + +void wxCheckListBox::Check(size_t item, bool check) +{ + wxCHECK_RET( item < m_checks.GetCount(), + _T("invalid index in wxCheckListBox::Check") ); + + // intermediate var is needed to avoid compiler warning with VC++ + bool isChecked = m_checks[item] != 0; + if ( check != isChecked ) + { + m_checks[item] = check; + + MacRedrawControl() ; + } +} + +// ---------------------------------------------------------------------------- +// methods forwarded to wxListBox +// ---------------------------------------------------------------------------- + +void wxCheckListBox::Delete(int n) +{ + wxCHECK_RET( n < GetCount(), _T("invalid index in wxListBox::Delete") ); + + wxListBox::Delete(n); + + m_checks.RemoveAt(n); +} + +int wxCheckListBox::DoAppend(const wxString& item) +{ + LSetDrawingMode( false , (ListHandle) m_macList ) ; + int pos = wxListBox::DoAppend(item); + + // the item is initially unchecked + m_checks.Insert(FALSE, pos); + LSetDrawingMode( true , (ListHandle) m_macList ) ; + + return pos; +} + +void wxCheckListBox::DoInsertItems(const wxArrayString& items, int pos) +{ + wxListBox::DoInsertItems(items, pos); + + size_t count = items.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + m_checks.Insert(FALSE, pos + n); + } +} + +void wxCheckListBox::DoSetItems(const wxArrayString& items, void **clientData) +{ + // call it first as it does DoClear() + wxListBox::DoSetItems(items, clientData); + + size_t count = items.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + m_checks.Add(FALSE); + } +} + +void wxCheckListBox::DoClear() +{ + m_checks.Empty(); +} + +BEGIN_EVENT_TABLE(wxCheckListBox, wxListBox) + EVT_CHAR(wxCheckListBox::OnChar) + EVT_LEFT_DOWN(wxCheckListBox::OnLeftClick) +END_EVENT_TABLE() + +// this will only work as soon as + +void wxCheckListBox::OnChar(wxKeyEvent& event) +{ + if ( event.GetKeyCode() == WXK_SPACE ) + { + int index = GetSelection() ; + if ( index >= 0 ) + { + Check(index, !IsChecked(index) ) ; + wxCommandEvent event(wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, GetId()); + event.SetInt(index); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); + } + } + else + event.Skip(); +} + +void wxCheckListBox::OnLeftClick(wxMouseEvent& event) +{ + // clicking on the item selects it, clicking on the checkmark toggles + if ( event.GetX() <= 20 /*check width*/ ) { + int lineheight ; + int topcell ; +#if TARGET_CARBON + Point pt ; + GetListCellSize( (ListHandle)m_macList , &pt ) ; + lineheight = pt.v ; + ListBounds visible ; + GetListVisibleCells( (ListHandle)m_macList , &visible ) ; + topcell = visible.top ; +#else + lineheight = (**(ListHandle)m_macList).cellSize.v ; + topcell = (**(ListHandle)m_macList).visible.top ; +#endif + size_t nItem = ((size_t)event.GetY()) / lineheight + topcell ; + + if ( nItem < (size_t)m_noItems ) + { + Check(nItem, !IsChecked(nItem) ) ; + wxCommandEvent event(wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, GetId()); + event.SetInt(nItem); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); + } + //else: it's not an error, just click outside of client zone + } + else { + // implement default behaviour: clicking on the item selects it + event.Skip(); + } +} + +#endif // wxUSE_CHECKLISTBOX diff --git a/src/mac/classic/choice.cpp b/src/mac/classic/choice.cpp new file mode 100644 index 0000000000..9f8494db9a --- /dev/null +++ b/src/mac/classic/choice.cpp @@ -0,0 +1,300 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: choice.cpp +// Purpose: wxChoice +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "choice.h" +#endif + +#include "wx/defs.h" +#include "wx/choice.h" +#include "wx/menu.h" +#include "wx/mac/uma.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxChoice, wxControl) +#endif + +extern MenuHandle NewUniqueMenu() ; + +wxChoice::~wxChoice() +{ + if ( HasClientObjectData() ) + { + size_t i, max = GetCount(); + + for ( i = 0; i < max; ++i ) + delete GetClientObject(i); + } + + // DeleteMenu( m_macPopUpMenuId ) ; + // DisposeMenu( m_macPopUpMenuHandle ) ; +} + +bool wxChoice::Create(wxWindow *parent, wxWindowID id, + const wxPoint& pos, + const wxSize& size, + const wxArrayString& choices, + long style, + const wxValidator& validator, + const wxString& name) +{ + wxCArrayString chs(choices); + + return Create(parent, id, pos, size, chs.GetCount(), chs.GetStrings(), + style, validator, name); +} + +bool wxChoice::Create(wxWindow *parent, wxWindowID id, + const wxPoint& pos, + const wxSize& size, + int n, const wxString choices[], + long style, + const wxValidator& validator, + const wxString& name) +{ + if ( !wxChoiceBase::Create(parent, id, pos, size, style, validator, name) ) + return false; + + Rect bounds ; + Str255 title ; + + MacPreControlCreate( parent , id , wxEmptyString , pos , size ,style, validator , name , &bounds , title ) ; + m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()) , &bounds , title , false , 0 , -12345 , 0 , + kControlPopupButtonProc + kControlPopupFixedWidthVariant , (long) this ) ; + + m_macPopUpMenuHandle = NewUniqueMenu() ; + SetControlData( (ControlHandle) m_macControl , kControlNoPart , kControlPopupButtonMenuHandleTag , sizeof( MenuHandle ) , (char*) &m_macPopUpMenuHandle) ; + SetControl32BitMinimum( (ControlHandle) m_macControl , 0 ) ; + SetControl32BitMaximum( (ControlHandle) m_macControl , 0) ; + if ( n > 0 ) + SetControl32BitValue( (ControlHandle) m_macControl , 1 ) ; + MacPostControlCreate() ; + // TODO wxCB_SORT + for ( int i = 0; i < n; i++ ) + { + Append(choices[i]); + } + return TRUE; +} + +// ---------------------------------------------------------------------------- +// adding/deleting items to/from the list +// ---------------------------------------------------------------------------- +int wxChoice::DoAppend(const wxString& item) +{ + UMAAppendMenuItem(MAC_WXHMENU( m_macPopUpMenuHandle ) , item, m_font.GetEncoding() ); + m_strings.Add( item ) ; + m_datas.Add( NULL ) ; + int index = m_strings.GetCount() - 1 ; + DoSetItemClientData( index , NULL ) ; + SetControl32BitMaximum( (ControlHandle) m_macControl , GetCount()) ; + return index ; +} + +int wxChoice::DoInsert(const wxString& item, int pos) +{ + wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into sorted list")); + wxCHECK_MSG((pos>=0) && (pos<=GetCount()), -1, wxT("invalid index")); + + if (pos == GetCount()) + return DoAppend(item); + + UMAAppendMenuItem(MAC_WXHMENU( m_macPopUpMenuHandle ) , item, m_font.GetEncoding() ); + m_strings.Insert( item, pos ) ; + m_datas.Insert( NULL, pos ) ; + DoSetItemClientData( pos , NULL ) ; + SetControl32BitMaximum( (ControlHandle) m_macControl , pos) ; + return pos ; +} + +void wxChoice::Delete(int n) +{ + wxCHECK_RET( n < GetCount(), wxT("invalid item index in wxChoice::Delete") ); + if ( HasClientObjectData() ) + { + delete GetClientObject(n); + } + ::DeleteMenuItem( MAC_WXHMENU(m_macPopUpMenuHandle) , n + 1) ; + m_strings.RemoveAt( n ) ; + m_datas.RemoveAt( n ) ; + SetControl32BitMaximum( (ControlHandle) m_macControl , GetCount()) ; +} + +void wxChoice::Clear() +{ + FreeData(); + for ( int i = 0 ; i < GetCount() ; i++ ) + { + ::DeleteMenuItem( MAC_WXHMENU(m_macPopUpMenuHandle) , 1 ) ; + } + m_strings.Empty() ; + m_datas.Empty() ; + SetControl32BitMaximum( (ControlHandle) m_macControl , 0 ) ; +} + +void wxChoice::FreeData() +{ + if ( HasClientObjectData() ) + { + size_t count = GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + delete GetClientObject(n); + } + } +} + +// ---------------------------------------------------------------------------- +// selection +// ---------------------------------------------------------------------------- +int wxChoice::GetSelection() const +{ + return GetControl32BitValue( (ControlHandle) m_macControl ) -1 ; +} + +void wxChoice::SetSelection(int n) +{ + SetControl32BitValue( (ControlHandle) m_macControl , n + 1 ) ; +} + +// ---------------------------------------------------------------------------- +// string list functions +// ---------------------------------------------------------------------------- + +int wxChoice::GetCount() const +{ + return m_strings.GetCount() ; +} + +int wxChoice::FindString(const wxString& s) const +{ + for( int i = 0 ; i < GetCount() ; i++ ) + { + if ( GetString( i ).IsSameAs(s, FALSE) ) + return i ; + } + return wxNOT_FOUND ; +} + +void wxChoice::SetString(int n, const wxString& s) +{ + wxFAIL_MSG(wxT("wxChoice::SetString() not yet implemented")); +#if 0 // should do this, but no Insert() so far + Delete(n); + Insert(n + 1, s); +#endif +} + +wxString wxChoice::GetString(int n) const +{ + wxCHECK_MSG( n >= 0 && (size_t)n < m_strings.GetCount(), _T(""), + _T("wxChoice::GetString(): invalid index") ); + + return m_strings[n] ; +} + +// ---------------------------------------------------------------------------- +// client data +// ---------------------------------------------------------------------------- +void wxChoice::DoSetItemClientData( int n, void* clientData ) +{ + wxCHECK_RET( n >= 0 && (size_t)n < m_datas.GetCount(), + wxT("invalid index in wxChoice::SetClientData") ); + + m_datas[n] = (char*) clientData ; +} + +void *wxChoice::DoGetItemClientData(int n) const +{ + wxCHECK_MSG( n >= 0 && (size_t)n < m_datas.GetCount(), NULL, + wxT("invalid index in wxChoice::GetClientData") ); + return (void *)m_datas[n]; +} + +void wxChoice::DoSetItemClientObject( int n, wxClientData* clientData ) +{ + DoSetItemClientData(n, clientData); +} + +wxClientData* wxChoice::DoGetItemClientObject( int n ) const +{ + return (wxClientData *)DoGetItemClientData(n); +} + +void wxChoice::MacHandleControlClick( WXWidget control , wxInt16 controlpart , bool WXUNUSED(mouseStillDown)) +{ + wxCommandEvent event(wxEVT_COMMAND_CHOICE_SELECTED, m_windowId ); + int n = GetSelection(); + // actually n should be made sure by the os to be a valid selection, but ... + if ( n > -1 ) + { + event.SetInt( n ); + event.SetString(GetStringSelection()); + event.SetEventObject(this); + if ( HasClientObjectData() ) + event.SetClientObject( GetClientObject(n) ); + else if ( HasClientUntypedData() ) + event.SetClientData( GetClientData(n) ); + ProcessCommand(event); + } +} + +wxSize wxChoice::DoGetBestSize() const +{ + int lbWidth = GetCount() > 0 ? 20 : 100; // some defaults + int lbHeight = 20; + int wLine; +#if TARGET_CARBON + long metric ; + GetThemeMetric(kThemeMetricPopupButtonHeight , &metric ); + lbHeight = metric ; +#endif + { + wxMacPortStateHelper st( UMAGetWindowPort( (WindowRef) MacGetRootWindow() ) ) ; + if ( m_font.Ok() ) + { + ::TextFont( m_font.GetMacFontNum() ) ; + ::TextSize( m_font.GetMacFontSize() ) ; + ::TextFace( m_font.GetMacFontStyle() ) ; + } + else + { + ::TextFont( kFontIDMonaco ) ; + ::TextSize( 9 ); + ::TextFace( 0 ) ; + } + // Find the widest line + for(int i = 0; i < GetCount(); i++) { + wxString str(GetString(i)); + #if wxUSE_UNICODE + Point bounds={0,0} ; + SInt16 baseline ; + ::GetThemeTextDimensions( wxMacCFStringHolder( str , m_font.GetEncoding() ) , + kThemeCurrentPortFont, + kThemeStateActive, + false, + &bounds, + &baseline ); + wLine = bounds.h ; + #else + wLine = ::TextWidth( str.c_str() , 0 , str.Length() ) ; + #endif + lbWidth = wxMax(lbWidth, wLine); + } + // Add room for the popup arrow + lbWidth += 2 * lbHeight ; + // And just a bit more + int cx = ::TextWidth( "X" , 0 , 1 ) ; + lbWidth += cx ; + + } + return wxSize(lbWidth, lbHeight); +} diff --git a/src/mac/classic/clipbrd.cpp b/src/mac/classic/clipbrd.cpp new file mode 100644 index 0000000000..e331d80f8e --- /dev/null +++ b/src/mac/classic/clipbrd.cpp @@ -0,0 +1,406 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: clipbrd.cpp +// Purpose: Clipboard functionality +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "clipbrd.h" +#endif + +#include "wx/app.h" +#include "wx/frame.h" +#include "wx/bitmap.h" +#include "wx/utils.h" +#include "wx/metafile.h" +#include "wx/clipbrd.h" +#include "wx/intl.h" +#include "wx/log.h" + +#ifndef __DARWIN__ +#include +#endif +#include "wx/mac/uma.h" + +#define wxUSE_DATAOBJ 1 + +#include + +// the trace mask we use with wxLogTrace() - call +// wxLog::AddTraceMask(TRACE_CLIPBOARD) to enable the trace messages from here +// (there will be a *lot* of them!) +static const wxChar *TRACE_CLIPBOARD = _T("clipboard"); + +void *wxGetClipboardData(wxDataFormat dataFormat, long *len) +{ +#if !TARGET_CARBON + OSErr err = noErr ; +#else + OSStatus err = noErr ; +#endif + void * data = NULL ; + Size byteCount; + + switch (dataFormat.GetType()) + { + case wxDF_OEMTEXT: + dataFormat = wxDF_TEXT; + // fall through + + case wxDF_TEXT: + break; + case wxDF_UNICODETEXT: + break; + case wxDF_BITMAP : + case wxDF_METAFILE : + break ; + default: + { + wxLogError(_("Unsupported clipboard format.")); + return NULL; + } + } + +#if TARGET_CARBON + ScrapRef scrapRef; + + err = GetCurrentScrap( &scrapRef ); + if ( err != noTypeErr && err != memFullErr ) + { + ScrapFlavorFlags flavorFlags; + + if (( err = GetScrapFlavorFlags( scrapRef, dataFormat.GetFormatId(), &flavorFlags )) == noErr) + { + if (( err = GetScrapFlavorSize( scrapRef, dataFormat.GetFormatId(), &byteCount )) == noErr) + { + Size allocSize = byteCount ; + if ( dataFormat.GetType() == wxDF_TEXT ) + allocSize += 1 ; + else if ( dataFormat.GetType() == wxDF_UNICODETEXT ) + allocSize += 2 ; + + data = new char[ allocSize ] ; + + if (( err = GetScrapFlavorData( scrapRef, dataFormat.GetFormatId(), &byteCount , data )) == noErr ) + { + *len = allocSize ; + if ( dataFormat.GetType() == wxDF_TEXT ) + ((char*)data)[byteCount] = 0 ; + if ( dataFormat.GetType() == wxDF_UNICODETEXT ) + ((wxChar*)data)[byteCount/2] = 0 ; + } + else + { + delete[] ((char *)data) ; + data = NULL ; + } + } + } + } + +#else + long offset ; + Handle datahandle = NewHandle(0) ; + HLock( datahandle ) ; + GetScrap( datahandle , dataFormat.GetFormatId() , &offset ) ; + HUnlock( datahandle ) ; + if ( GetHandleSize( datahandle ) > 0 ) + { + byteCount = GetHandleSize( datahandle ) ; + Size allocSize = byteCount ; + if ( dataFormat.GetType() == wxDF_TEXT ) + allocSize += 1 ; + else if ( dataFormat.GetType() == wxDF_UNICODETEXT ) + allocSize += 2 ; + + data = new char[ allocSize ] ; + + memcpy( (char*) data , (char*) *datahandle , byteCount ) ; + if ( dataFormat.GetType() == wxDF_TEXT ) + ((char*)data)[byteCount] = 0 ; + if ( dataFormat.GetType() == wxDF_UNICODETEXT ) + ((wxChar*)data)[byteCount/2] = 0 ; + *len = byteCount ; + } + DisposeHandle( datahandle ) ; +#endif + if ( err ) + { + wxLogSysError(_("Failed to get clipboard data.")); + + return NULL ; + } + + if ( dataFormat.GetType() == wxDF_TEXT ) + { + wxMacConvertNewlines10To13( (char*) data ) ; + } + + return data; +} + + +/* + * Generalized clipboard implementation by Matthew Flatt + */ + +IMPLEMENT_DYNAMIC_CLASS(wxClipboard, wxObject) + +wxClipboard::wxClipboard() +{ + m_open = false ; + m_data = NULL ; +} + +wxClipboard::~wxClipboard() +{ + if (m_data) + { + delete m_data; + m_data = (wxDataObject*) NULL; + } +} + +void wxClipboard::Clear() +{ + if (m_data) + { + delete m_data; + m_data = (wxDataObject*) NULL; + } +#if TARGET_CARBON + OSStatus err ; + err = ClearCurrentScrap( ); +#else + OSErr err ; + err = ZeroScrap( ); +#endif + if ( err ) + { + wxLogSysError(_("Failed to empty the clipboard.")); + } +} + +bool wxClipboard::Flush() +{ + return FALSE; +} + +bool wxClipboard::Open() +{ + wxCHECK_MSG( !m_open, FALSE, wxT("clipboard already open") ); + m_open = true ; + return true ; +} + +bool wxClipboard::IsOpened() const +{ + return m_open; +} + +bool wxClipboard::SetData( wxDataObject *data ) +{ + wxCHECK_MSG( m_open, FALSE, wxT("clipboard not open") ); + + wxCHECK_MSG( data, FALSE, wxT("data is invalid") ); + + Clear(); + // as we can only store one wxDataObject, this is the same in this + // implementation + return AddData( data ); +} + +bool wxClipboard::AddData( wxDataObject *data ) +{ + wxCHECK_MSG( m_open, FALSE, wxT("clipboard not open") ); + + wxCHECK_MSG( data, FALSE, wxT("data is invalid") ); + + /* we can only store one wxDataObject */ + Clear(); + + m_data = data; + + /* get formats from wxDataObjects */ + wxDataFormat *array = new wxDataFormat[ m_data->GetFormatCount() ]; + m_data->GetAllFormats( array ); + + for (size_t i = 0; i < m_data->GetFormatCount(); i++) + { + wxLogTrace( TRACE_CLIPBOARD, + wxT("wxClipboard now supports atom %s"), + array[i].GetId().c_str() ); + +#if !TARGET_CARBON + OSErr err = noErr ; +#else + OSStatus err = noErr ; +#endif + size_t sz = data->GetDataSize( array[i] ) ; + void* buf = malloc( sz + 1 ) ; + if ( buf ) + { + data->GetDataHere( array[i] , buf ) ; + OSType mactype = 0 ; + switch ( array[i].GetType() ) + { + case wxDF_TEXT: + case wxDF_OEMTEXT: + mactype = kScrapFlavorTypeText ; + break ; + #if wxUSE_UNICODE + case wxDF_UNICODETEXT : + mactype = kScrapFlavorTypeUnicode ; + break ; + #endif + #if wxUSE_DRAG_AND_DROP + case wxDF_METAFILE: + mactype = kScrapFlavorTypePicture ; + break ; + #endif + case wxDF_BITMAP: + case wxDF_DIB: + mactype = kScrapFlavorTypePicture ; + break ; + default: + break ; + } + UMAPutScrap( sz , mactype , buf ) ; + free( buf ) ; + } + } + + delete[] array; + + return true ; +} + +void wxClipboard::Close() +{ + wxCHECK_RET( m_open, wxT("clipboard not open") ); + + m_open = false ; + + // Get rid of cached object. If this is not done copying from another application will + // only work once + if (m_data) + { + delete m_data; + m_data = (wxDataObject*) NULL; + } + +} + +bool wxClipboard::IsSupported( const wxDataFormat &dataFormat ) +{ + if ( m_data ) + { + return m_data->IsSupported( dataFormat ) ; + } +#if TARGET_CARBON + OSStatus err = noErr; + ScrapRef scrapRef; + + err = GetCurrentScrap( &scrapRef ); + if ( err != noTypeErr && err != memFullErr ) + { + ScrapFlavorFlags flavorFlags; + Size byteCount; + + if (( err = GetScrapFlavorFlags( scrapRef, dataFormat.GetFormatId(), &flavorFlags )) == noErr) + { + if (( err = GetScrapFlavorSize( scrapRef, dataFormat.GetFormatId(), &byteCount )) == noErr) + { + return TRUE ; + } + } + } + return FALSE; + +#else + long offset ; + Handle datahandle = NewHandle(0) ; + HLock( datahandle ) ; + GetScrap( datahandle , dataFormat.GetFormatId() , &offset ) ; + HUnlock( datahandle ) ; + bool hasData = GetHandleSize( datahandle ) > 0 ; + DisposeHandle( datahandle ) ; + return hasData ; +#endif +} + +bool wxClipboard::GetData( wxDataObject& data ) +{ + wxCHECK_MSG( m_open, FALSE, wxT("clipboard not open") ); + + size_t formatcount = data.GetFormatCount() + 1 ; + wxDataFormat *array = new wxDataFormat[ formatcount ]; + array[0] = data.GetPreferredFormat(); + data.GetAllFormats( &array[1] ); + + bool transferred = false ; + + if ( m_data ) + { + for (size_t i = 0; !transferred && i < formatcount ; i++) + { + wxDataFormat format = array[i] ; + if ( m_data->IsSupported( format ) ) + { + int size = m_data->GetDataSize( format ); + transferred = true ; + + if (size == 0) + { + data.SetData(format , 0 , 0 ) ; + } + else + { + char *d = new char[size]; + m_data->GetDataHere( format , (void*) d ); + data.SetData( format , size , d ) ; + delete[] d ; + } + } + } + } + /* get formats from wxDataObjects */ + if ( !transferred ) + { + for (size_t i = 0; !transferred && i < formatcount ; i++) + { + wxDataFormat format = array[i] ; + + switch ( format.GetType() ) + { + case wxDF_TEXT : + case wxDF_OEMTEXT : + case wxDF_BITMAP : + case wxDF_METAFILE : + { + long len ; + char* s = (char*)wxGetClipboardData(format, &len ); + if ( s ) + { + data.SetData( format , len , s ) ; + delete [] s; + + transferred = true ; + } + } + break ; + + default : + break ; + } + } + } + + delete[] array ; + return transferred ; +} diff --git a/src/mac/classic/colordlg.cpp b/src/mac/classic/colordlg.cpp new file mode 100644 index 0000000000..3c8411319b --- /dev/null +++ b/src/mac/classic/colordlg.cpp @@ -0,0 +1,70 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: colordlg.cpp +// Purpose: wxColourDialog class. NOTE: you can use the generic class +// if you wish, instead of implementing this. +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "colordlg.h" +#endif + +#include "wx/mac/colordlg.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxColourDialog, wxDialog) +#endif + +#include "wx/mac/private.h" +#ifndef __DARWIN__ +#include +#endif + +/* + * wxColourDialog + */ + +wxColourDialog::wxColourDialog() +{ + m_dialogParent = NULL; +} + +wxColourDialog::wxColourDialog(wxWindow *parent, wxColourData *data) +{ + Create(parent, data); +} + +bool wxColourDialog::Create(wxWindow *parent, wxColourData *data) +{ + m_dialogParent = parent; + + if (data) + m_colourData = *data; + return TRUE; +} + +int wxColourDialog::ShowModal() +{ + Point where ; + RGBColor currentColor = *((RGBColor*)m_colourData.m_dataColour.GetPixel()) , newColor ; + + where.h = where.v = -1; + + if (GetColor( where, "\pSelect a new palette color.", ¤tColor, &newColor )) + { + m_colourData.m_dataColour.Set( (WXCOLORREF*) &newColor ) ; + return wxID_OK; + } + else + { + return wxID_CANCEL; + } + + return wxID_CANCEL; +} + diff --git a/src/mac/classic/colour.cpp b/src/mac/classic/colour.cpp new file mode 100644 index 0000000000..86487f7a35 --- /dev/null +++ b/src/mac/classic/colour.cpp @@ -0,0 +1,116 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: colour.cpp +// Purpose: wxColour class +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "colour.h" +#endif + +#include "wx/gdicmn.h" +#include "wx/colour.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxColour, wxObject) +#endif + +// Colour + +#include "wx/mac/private.h" + +static void wxComposeRGBColor( WXCOLORREF* color , int red, int blue, int green ) ; +static void wxComposeRGBColor( WXCOLORREF* color , int red, int blue, int green ) +{ + RGBColor* col = (RGBColor*) color ; + col->red = (red << 8) + red; + col->blue = (blue << 8) + blue; + col->green = (green << 8) + green; +} + +void wxColour::Init() +{ + m_isInit = false; + m_red = + m_blue = + m_green = 0; + + wxComposeRGBColor( &m_pixel , m_red , m_blue , m_green ) ; +} + +wxColour::wxColour (const wxColour& col) + : wxObject() +{ + m_red = col.m_red; + m_green = col.m_green; + m_blue = col.m_blue; + m_isInit = col.m_isInit; + + memcpy( &m_pixel , &col.m_pixel , 6 ) ; +} + +wxColour::wxColour (const wxColour* col) +{ + m_red = col->m_red; + m_green = col->m_green; + m_blue = col->m_blue; + m_isInit = col->m_isInit; + + memcpy( &m_pixel , &col->m_pixel , 6 ) ; +} + +wxColour& wxColour::operator =(const wxColour& col) +{ + m_red = col.m_red; + m_green = col.m_green; + m_blue = col.m_blue; + m_isInit = col.m_isInit; + + memcpy( &m_pixel , &col.m_pixel , 6 ) ; + + return *this; +} + +void wxColour::InitFromName(const wxString& name) +{ + if ( wxTheColourDatabase ) + { + wxColour col = wxTheColourDatabase->Find(name); + if ( col.Ok() ) + { + *this = col; + return; + } + } + + // leave invalid + Init(); +} + +wxColour::~wxColour () +{ +} + +void wxColour::Set (unsigned char r, unsigned char g, unsigned char b) +{ + m_red = r; + m_green = g; + m_blue = b; + m_isInit = true; + + wxComposeRGBColor( &m_pixel , m_red , m_blue , m_green ) ; +} + +void wxColour::Set( const WXCOLORREF* color ) +{ + RGBColor* col = (RGBColor*) color ; + memcpy( &m_pixel , color , 6 ) ; + m_red = col->red>>8 ; + m_blue = col->blue>>8 ; + m_green = col->green>>8 ; +} diff --git a/src/mac/classic/combobox.cpp b/src/mac/classic/combobox.cpp new file mode 100644 index 0000000000..27aa1a58de --- /dev/null +++ b/src/mac/classic/combobox.cpp @@ -0,0 +1,540 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: combobox.cpp +// Purpose: wxComboBox class +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "combobox.h" +#endif + +#include "wx/combobox.h" +#include "wx/button.h" +#include "wx/menu.h" +#include "wx/mac/uma.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxComboBox, wxControl) +#endif + +// composite combobox implementation by Dan "Bud" Keith bud@otsys.com + + +static int nextPopUpMenuId = 1000 ; +MenuHandle NewUniqueMenu() +{ + MenuHandle handle = NewMenu( nextPopUpMenuId , "\pMenu" ) ; + nextPopUpMenuId++ ; + return handle ; +} + + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// the margin between the text control and the choice +static const wxCoord MARGIN = 2; +static const int POPUPWIDTH = 18; +static const int POPUPHEIGHT = 23; + + +// ---------------------------------------------------------------------------- +// wxComboBoxText: text control forwards events to combobox +// ---------------------------------------------------------------------------- + +class wxComboBoxText : public wxTextCtrl +{ +public: + wxComboBoxText( wxComboBox * cb ) + : wxTextCtrl( cb , 1 ) + { + m_cb = cb; + } + +protected: + void OnChar( wxKeyEvent& event ) + { + if ( event.GetKeyCode() == WXK_RETURN ) + { + wxString value = GetValue(); + + if ( m_cb->GetCount() == 0 ) + { + // make Enter generate "selected" event if there is only one item + // in the combobox - without it, it's impossible to select it at + // all! + wxCommandEvent event( wxEVT_COMMAND_COMBOBOX_SELECTED, m_cb->GetId() ); + event.SetInt( 0 ); + event.SetString( value ); + event.SetEventObject( m_cb ); + m_cb->GetEventHandler()->ProcessEvent( event ); + } + else + { + // add the item to the list if it's not there yet + if ( m_cb->FindString(value) == wxNOT_FOUND ) + { + m_cb->Append(value); + m_cb->SetStringSelection(value); + + // and generate the selected event for it + wxCommandEvent event( wxEVT_COMMAND_COMBOBOX_SELECTED, m_cb->GetId() ); + event.SetInt( m_cb->GetCount() - 1 ); + event.SetString( value ); + event.SetEventObject( m_cb ); + m_cb->GetEventHandler()->ProcessEvent( event ); + } + + // This will invoke the dialog default action, such + // as the clicking the default button. + + wxWindow *parent = GetParent(); + while( parent && !parent->IsTopLevel() && parent->GetDefaultItem() == NULL ) { + parent = parent->GetParent() ; + } + if ( parent && parent->GetDefaultItem() ) + { + wxButton *def = wxDynamicCast(parent->GetDefaultItem(), + wxButton); + if ( def && def->IsEnabled() ) + { + wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() ); + event.SetEventObject(def); + def->Command(event); + return ; + } + } + + return; + } + } + + event.Skip(); + } + +private: + wxComboBox *m_cb; + + DECLARE_EVENT_TABLE() +}; + +BEGIN_EVENT_TABLE(wxComboBoxText, wxTextCtrl) + EVT_CHAR( wxComboBoxText::OnChar) +END_EVENT_TABLE() + +class wxComboBoxChoice : public wxChoice +{ +public: + wxComboBoxChoice(wxComboBox *cb, int style) + : wxChoice( cb , 1 ) + { + m_cb = cb; + } + +protected: + void OnChoice( wxCommandEvent& e ) + { + wxString s = e.GetString(); + + m_cb->DelegateChoice( s ); + wxCommandEvent event2(wxEVT_COMMAND_COMBOBOX_SELECTED, m_cb->GetId() ); + event2.SetInt(m_cb->GetSelection()); + event2.SetEventObject(m_cb); + event2.SetString(m_cb->GetStringSelection()); + m_cb->ProcessCommand(event2); + } + +private: + wxComboBox *m_cb; + + DECLARE_EVENT_TABLE() +}; + +BEGIN_EVENT_TABLE(wxComboBoxChoice, wxChoice) + EVT_CHOICE(-1, wxComboBoxChoice::OnChoice) +END_EVENT_TABLE() + +wxComboBox::~wxComboBox() +{ + // delete client objects + FreeData(); + + // delete the controls now, don't leave them alive even though they would + // still be eventually deleted by our parent - but it will be too late, the + // user code expects them to be gone now + if (m_text != NULL) { + delete m_text; + m_text = NULL; + } + if (m_choice != NULL) { + delete m_choice; + m_choice = NULL; + } +} + + +// ---------------------------------------------------------------------------- +// geometry +// ---------------------------------------------------------------------------- + +wxSize wxComboBox::DoGetBestSize() const +{ + wxSize size = m_choice->GetBestSize(); + + if ( m_text != NULL ) + { + wxSize sizeText = m_text->GetBestSize(); + + size.x = POPUPWIDTH + sizeText.x + MARGIN; + } + + return size; +} + +void wxComboBox::DoMoveWindow(int x, int y, int width, int height) { + height = POPUPHEIGHT; + + wxControl::DoMoveWindow(x, y, width, height); + + if ( m_text == NULL ) + { + m_choice->SetSize(0, 0 , width, -1); + } + else + { + wxCoord wText = width - POPUPWIDTH - MARGIN; + m_text->SetSize(0, 0, wText, height); + m_choice->SetSize(0 + wText + MARGIN, 0, POPUPWIDTH, -1); + } +} + + + +// ---------------------------------------------------------------------------- +// operations forwarded to the subcontrols +// ---------------------------------------------------------------------------- + +bool wxComboBox::Enable(bool enable) +{ + if ( !wxControl::Enable(enable) ) + return FALSE; + + return TRUE; +} + +bool wxComboBox::Show(bool show) +{ + if ( !wxControl::Show(show) ) + return FALSE; + + return TRUE; +} + +void wxComboBox::SetFocus() +{ + if ( m_text != NULL) { + m_text->SetFocus(); + } +} + + +void wxComboBox::DelegateTextChanged( const wxString& value ) +{ + SetStringSelection( value ); +} + + +void wxComboBox::DelegateChoice( const wxString& value ) +{ + SetStringSelection( value ); +} + + +bool wxComboBox::Create(wxWindow *parent, wxWindowID id, + const wxString& value, + const wxPoint& pos, + const wxSize& size, + const wxArrayString& choices, + long style, + const wxValidator& validator, + const wxString& name) +{ + wxCArrayString chs( choices ); + + return Create( parent, id, value, pos, size, chs.GetCount(), + chs.GetStrings(), style, validator, name ); +} + + +bool wxComboBox::Create(wxWindow *parent, wxWindowID id, + const wxString& value, + const wxPoint& pos, + const wxSize& size, + int n, const wxString choices[], + long style, + const wxValidator& validator, + const wxString& name) +{ + if ( !wxControl::Create(parent, id, wxDefaultPosition, wxDefaultSize, style , + wxDefaultValidator, name) ) + { + return FALSE; + } + + m_choice = new wxComboBoxChoice(this, style ); + + wxSize csize = size; + if ( style & wxCB_READONLY ) + { + m_text = NULL; + } + else + { + m_text = new wxComboBoxText(this); + if ( size.y == -1 ) { + csize.y = m_text->GetSize().y ; + } + } + + DoSetSize(pos.x, pos.y, csize.x, csize.y); + + for ( int i = 0 ; i < n ; i++ ) + { + m_choice->DoAppend( choices[ i ] ); + } + + return TRUE; +} + +wxString wxComboBox::GetValue() const +{ + wxString result; + + if ( m_text == NULL ) + { + result = m_choice->GetString( m_choice->GetSelection() ); + } + else + { + result = m_text->GetValue(); + } + + return result; +} + +void wxComboBox::SetValue(const wxString& value) +{ + int s = FindString (value); + if (s == wxNOT_FOUND && !HasFlag(wxCB_READONLY) ) + { + m_choice->Append(value) ; + } + SetStringSelection( value ) ; +} + +// Clipboard operations +void wxComboBox::Copy() +{ + if ( m_text != NULL ) + { + m_text->Copy(); + } +} + +void wxComboBox::Cut() +{ + if ( m_text != NULL ) + { + m_text->Cut(); + } +} + +void wxComboBox::Paste() +{ + if ( m_text != NULL ) + { + m_text->Paste(); + } +} + +void wxComboBox::SetEditable(bool editable) +{ + if ( ( m_text == NULL ) && editable ) + { + m_text = new wxComboBoxText( this ); + } + else if ( ( m_text != NULL ) && !editable ) + { + delete m_text; + m_text = NULL; + } + + int currentX, currentY; + GetPosition( ¤tX, ¤tY ); + + int currentW, currentH; + GetSize( ¤tW, ¤tH ); + + DoMoveWindow( currentX, currentY, currentW, currentH ); +} + +void wxComboBox::SetInsertionPoint(long pos) +{ + // TODO +} + +void wxComboBox::SetInsertionPointEnd() +{ + // TODO +} + +long wxComboBox::GetInsertionPoint() const +{ + // TODO + return 0; +} + +long wxComboBox::GetLastPosition() const +{ + // TODO + return 0; +} + +void wxComboBox::Replace(long from, long to, const wxString& value) +{ + // TODO +} + +void wxComboBox::Remove(long from, long to) +{ + // TODO +} + +void wxComboBox::SetSelection(long from, long to) +{ + // TODO +} + +int wxComboBox::DoAppend(const wxString& item) +{ + return m_choice->DoAppend( item ) ; +} + +int wxComboBox::DoInsert(const wxString& item, int pos) +{ + return m_choice->DoInsert( item , pos ) ; +} + +void wxComboBox::DoSetItemClientData(int n, void* clientData) +{ + return m_choice->DoSetItemClientData( n , clientData ) ; +} + +void* wxComboBox::DoGetItemClientData(int n) const +{ + return m_choice->DoGetItemClientData( n ) ; +} + +void wxComboBox::DoSetItemClientObject(int n, wxClientData* clientData) +{ + return m_choice->DoSetItemClientObject( n , clientData ) ; +} + +wxClientData* wxComboBox::DoGetItemClientObject(int n) const +{ + return m_choice->DoGetItemClientObject( n ) ; +} + +void wxComboBox::FreeData() +{ + if ( HasClientObjectData() ) + { + size_t count = GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + SetClientObject( n, NULL ); + } + } +} + +void wxComboBox::Delete(int n) +{ + // force client object deletion + if( HasClientObjectData() ) + SetClientObject( n, NULL ); + m_choice->Delete( n ); +} + +void wxComboBox::Clear() +{ + FreeData(); + m_choice->Clear(); +} + +int wxComboBox::GetSelection() const +{ + return m_choice->GetSelection(); +} + +void wxComboBox::SetSelection(int n) +{ + m_choice->SetSelection( n ); + + if ( m_text != NULL ) + { + m_text->SetValue( GetString( n ) ); + } +} + +int wxComboBox::FindString(const wxString& s) const +{ + return m_choice->FindString( s ); +} + +wxString wxComboBox::GetString(int n) const +{ + return m_choice->GetString( n ); +} + +wxString wxComboBox::GetStringSelection() const +{ + int sel = GetSelection (); + if (sel > -1) + return wxString(this->GetString (sel)); + else + return wxEmptyString; +} + +bool wxComboBox::SetStringSelection(const wxString& sel) +{ + int s = FindString (sel); + if (s > -1) + { + SetSelection (s); + return TRUE; + } + else + return FALSE; +} + +void wxComboBox::SetString(int n, const wxString& s) +{ + m_choice->SetString( n , s ) ; +} + + +void wxComboBox::MacHandleControlClick( WXWidget WXUNUSED(control) , wxInt16 WXUNUSED(controlpart) , bool WXUNUSED(mouseStillDown)) +{ + wxCommandEvent event(wxEVT_COMMAND_COMBOBOX_SELECTED, m_windowId ); + event.SetInt(GetSelection()); + event.SetEventObject(this); + event.SetString(GetStringSelection()); + ProcessCommand(event); +} + diff --git a/src/mac/classic/control.cpp b/src/mac/classic/control.cpp new file mode 100644 index 0000000000..473bdec9fd --- /dev/null +++ b/src/mac/classic/control.cpp @@ -0,0 +1,814 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: control.cpp +// Purpose: wxControl class +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "control.h" +#endif + +#include "wx/defs.h" + +#include "wx/control.h" +#include "wx/panel.h" +#include "wx/app.h" +#include "wx/dc.h" +#include "wx/dcclient.h" +#include "wx/notebook.h" +#include "wx/tabctrl.h" +#include "wx/radiobox.h" +#include "wx/spinbutt.h" +#include "wx/scrolbar.h" +#include "wx/button.h" +#include "wx/dialog.h" +#include "wx/statbox.h" +#include "wx/sizer.h" +#include "wx/stattext.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_ABSTRACT_CLASS(wxControl, wxWindow) + +BEGIN_EVENT_TABLE(wxControl, wxWindow) + EVT_MOUSE_EVENTS( wxControl::OnMouseEvent ) + EVT_PAINT( wxControl::OnPaint ) +END_EVENT_TABLE() +#endif + +#include "wx/mac/uma.h" +#include "wx/mac/private.h" + +// Item members + + +#if PRAGMA_STRUCT_ALIGN + #pragma options align=mac68k +#elif PRAGMA_STRUCT_PACKPUSH + #pragma pack(push, 2) +#elif PRAGMA_STRUCT_PACK + #pragma pack(2) +#endif + +typedef struct { + unsigned short instruction; + void (*function)(); +} cdefRec, *cdefPtr, **cdefHandle; + +#if PRAGMA_STRUCT_ALIGN + #pragma options align=reset +#elif PRAGMA_STRUCT_PACKPUSH + #pragma pack(pop) +#elif PRAGMA_STRUCT_PACK + #pragma pack() +#endif + +ControlActionUPP wxMacLiveScrollbarActionUPP = NULL ; +wxControl *wxFindControlFromMacControl(ControlHandle inControl ) ; + +pascal void wxMacLiveScrollbarActionProc( ControlHandle control , ControlPartCode partCode ) ; +pascal void wxMacLiveScrollbarActionProc( ControlHandle control , ControlPartCode partCode ) +{ + if ( partCode != 0) + { + wxControl* wx = (wxControl*) GetControlReference( control ) ; + if ( wx ) + { + wx->MacHandleControlClick( control , partCode , true /* stillDown */ ) ; + } + } +} + +ControlColorUPP wxMacSetupControlBackgroundUPP = NULL ; +ControlDefUPP wxMacControlActionUPP = NULL ; + +pascal SInt32 wxMacControlDefinition(SInt16 varCode, ControlRef theControl, ControlDefProcMessage message, SInt32 param) +{ + + wxControl* wx = (wxControl*) wxFindControlFromMacControl( theControl ) ; + if ( wx != NULL && wx->IsKindOf( CLASSINFO( wxControl ) ) ) + { + if( message == drawCntl ) + { + wxMacWindowClipper clip( wx ) ; + return InvokeControlDefUPP( varCode , theControl , message , param , (ControlDefUPP) wx->MacGetControlAction() ) ; + } + else + return InvokeControlDefUPP( varCode , theControl , message , param , (ControlDefUPP) wx->MacGetControlAction() ) ; + } + return NULL ; +} + +pascal OSStatus wxMacSetupControlBackground( ControlRef iControl , SInt16 iMessage , SInt16 iDepth , Boolean iIsColor ) +{ + OSStatus status = noErr ; + switch( iMessage ) + { + case kControlMsgSetUpBackground : + { + wxControl* wx = (wxControl*) GetControlReference( iControl ) ; + if ( wx != NULL && wx->IsKindOf( CLASSINFO( wxControl ) ) ) + { + wxDC::MacSetupBackgroundForCurrentPort( wx->MacGetBackgroundBrush() ) ; +#if TARGET_CARBON + // under classic this would lead to partial redraws + RgnHandle clip = NewRgn() ; + int x = 0 , y = 0; + + wx->MacWindowToRootWindow( &x,&y ) ; + CopyRgn( (RgnHandle) wx->MacGetVisibleRegion(false).GetWXHRGN() , clip ) ; + OffsetRgn( clip , x , y ) ; + SetClip( clip ) ; + DisposeRgn( clip ) ; +#endif + } + else + { + status = paramErr ; + } + } + break ; + default : + status = paramErr ; + break ; + } + return status ; +} + +wxControl::wxControl() +{ + m_macControl = NULL ; + m_macControlAction = NULL ; + m_macHorizontalBorder = 0 ; // additional pixels around the real control + m_macVerticalBorder = 0 ; + m_backgroundColour = *wxWHITE; + m_foregroundColour = *wxBLACK; + + if ( wxMacLiveScrollbarActionUPP == NULL ) + { +#if defined(UNIVERSAL_INTERFACES_VERSION) && (UNIVERSAL_INTERFACES_VERSION >= 0x0340) + wxMacLiveScrollbarActionUPP = NewControlActionUPP( wxMacLiveScrollbarActionProc ); +#else + wxMacLiveScrollbarActionUPP = NewControlActionProc( wxMacLiveScrollbarActionProc ) ; +#endif + } +} + +bool wxControl::Create(wxWindow *parent, wxWindowID id, + const wxPoint& pos, + const wxSize& size, long style, + const wxValidator& validator, + const wxString& name) +{ + m_macControl = NULL ; + m_macHorizontalBorder = 0 ; // additional pixels around the real control + m_macVerticalBorder = 0 ; + + bool rval = wxWindow::Create(parent, id, pos, size, style, name); + if ( parent ) + { + m_backgroundColour = parent->GetBackgroundColour() ; + m_foregroundColour = parent->GetForegroundColour() ; + } + if (rval) { +#if wxUSE_VALIDATORS + SetValidator(validator); +#endif + } + return rval; +} + +wxControl::~wxControl() +{ + m_isBeingDeleted = TRUE; + wxRemoveMacControlAssociation( this ) ; + // If we delete an item, we should initialize the parent panel, + // because it could now be invalid. + wxWindow *parent = GetParent() ; + if ( parent ) + { + if (parent->GetDefaultItem() == (wxButton*) this) + parent->SetDefaultItem(NULL); + } + if ( (ControlHandle) m_macControl ) + { + // in case the callback might be called during destruction + ::SetControlColorProc( (ControlHandle) m_macControl , NULL ) ; + ::DisposeControl( (ControlHandle) m_macControl ) ; + m_macControl = NULL ; + } +} + +void wxControl::SetLabel(const wxString& title) +{ + m_label = wxStripMenuCodes(title) ; + + if ( m_macControl ) + { + UMASetControlTitle( (ControlHandle) m_macControl , m_label , m_font.GetEncoding() ) ; + } + Refresh() ; +} + +wxSize wxControl::DoGetBestSize() const +{ + if ( (ControlHandle) m_macControl == NULL ) + return wxWindow::DoGetBestSize() ; + + Rect bestsize = { 0 , 0 , 0 , 0 } ; + short baselineoffset ; + int bestWidth, bestHeight ; + ::GetBestControlRect( (ControlHandle) m_macControl , &bestsize , &baselineoffset ) ; + + if ( EmptyRect( &bestsize ) ) + { + baselineoffset = 0; + bestsize.left = bestsize.top = 0 ; + bestsize.right = 16 ; + bestsize.bottom = 16 ; + if ( IsKindOf( CLASSINFO( wxScrollBar ) ) ) + { + bestsize.bottom = 16 ; + } + else if ( IsKindOf( CLASSINFO( wxSpinButton ) ) ) + { + bestsize.bottom = 24 ; + } + } + + bestWidth = bestsize.right - bestsize.left ; + + bestWidth += 2 * m_macHorizontalBorder ; + + bestHeight = bestsize.bottom - bestsize.top ; + if ( bestHeight < 10 ) + bestHeight = 13 ; + + bestHeight += 2 * m_macVerticalBorder; + + + return wxSize(bestWidth, bestHeight); +} + +bool wxControl::ProcessCommand (wxCommandEvent & event) +{ + // Tries: + // 1) OnCommand, starting at this window and working up parent hierarchy + // 2) OnCommand then calls ProcessEvent to search the event tables. + return GetEventHandler()->ProcessEvent(event); +} + +// ------------------------ +wxList *wxWinMacControlList = NULL; +wxControl *wxFindControlFromMacControl(ControlHandle inControl ) +{ + wxNode *node = wxWinMacControlList->Find((long)inControl); + if (!node) + return NULL; + return (wxControl *)node->GetData(); +} + +void wxAssociateControlWithMacControl(ControlHandle inControl, wxControl *control) +{ + // adding NULL WindowRef is (first) surely a result of an error and + // (secondly) breaks menu command processing + wxCHECK_RET( inControl != (ControlHandle) NULL, wxT("attempt to add a NULL WindowRef to window list") ); + + if ( !wxWinMacControlList->Find((long)inControl) ) + wxWinMacControlList->Append((long)inControl, control); +} + +void wxRemoveMacControlAssociation(wxControl *control) +{ + if ( wxWinMacControlList ) + wxWinMacControlList->DeleteObject(control); +} + +void wxControl::MacPreControlCreate( wxWindow *parent, wxWindowID id, wxString label , + const wxPoint& pos, + const wxSize& size, long style, + const wxValidator& validator, + const wxString& name , WXRECTPTR outBounds , unsigned char* maclabel ) +{ + m_label = label ; + + // These sizes will be adjusted in MacPostControlCreate + m_width = size.x ; + m_height = size.y ; + m_x = pos.x ; + m_y = pos.y ; + + ((Rect*)outBounds)->top = -10; + ((Rect*)outBounds)->left = -10; + ((Rect*)outBounds)->bottom = 0; + ((Rect*)outBounds)->right = 0; + + wxMacStringToPascal( wxStripMenuCodes(label) , maclabel ) ; +} + +void wxControl::MacPostControlCreate() +{ + wxASSERT_MSG( (ControlHandle) m_macControl != NULL , wxT("No valid mac control") ) ; + DoSetWindowVariant( m_windowVariant ) ; + /* + if ( IsKindOf( CLASSINFO( wxScrollBar ) ) ) + { + // no font + } + else if ( !UMAHasAquaLayout() && (IsKindOf( CLASSINFO( wxStaticBox ) ) || IsKindOf( CLASSINFO( wxRadioBox ) ) || IsKindOf( CLASSINFO( wxButton ) ) ) ) + { + ControlFontStyleRec controlstyle ; + controlstyle.flags = kControlUseFontMask ; + controlstyle.font = kControlFontSmallBoldSystemFont ; + + ::SetControlFontStyle( (ControlHandle) m_macControl , &controlstyle ) ; + } + else + { + ControlFontStyleRec controlstyle ; + controlstyle.flags = kControlUseFontMask ; + + if (IsKindOf( CLASSINFO( wxButton ) ) ) + controlstyle.font = kControlFontBigSystemFont ; // eventually kControlFontBigSystemFont ; + else + controlstyle.font = kControlFontSmallSystemFont ; + + ::SetControlFontStyle( (ControlHandle) m_macControl , &controlstyle ) ; + } + */ + ControlHandle container = (ControlHandle) GetParent()->MacGetContainerForEmbedding() ; + wxASSERT_MSG( container != NULL , wxT("No valid mac container control") ) ; + ::EmbedControl( (ControlHandle) m_macControl , container ) ; + m_macControlIsShown = MacIsReallyShown() ; + + wxAssociateControlWithMacControl( (ControlHandle) m_macControl , this ) ; + if ( wxMacSetupControlBackgroundUPP == NULL ) + { + wxMacSetupControlBackgroundUPP = NewControlColorUPP( wxMacSetupControlBackground ) ; + } + if ( wxMacControlActionUPP == NULL ) + { + wxMacControlActionUPP = NewControlDefUPP( wxMacControlDefinition ) ; + } + // The following block of code is responsible for crashes when switching + // back to windows, which can be seen in the dialogs sample. + // It is disabled until a proper solution can be found. +#if 0 +#if TARGET_CARBON +/* + only working under classic carbon + m_macControlAction = *(**(ControlHandle)m_macControl).contrlDefProc ; + (**(ControlHandle)m_macControl).contrlDefProc = (Handle) &wxMacControlActionUPP ; +*/ +#else + m_macControlAction = *(**(ControlHandle)m_macControl).contrlDefProc ; + + cdefHandle cdef ; + cdef = (cdefHandle) NewHandle( sizeof(cdefRec) ) ; + if ( (**(ControlHandle)m_macControl).contrlDefProc != NULL ) + { + (**cdef).instruction = 0x4EF9; /* JMP instruction */ + (**cdef).function = (void(*)()) wxMacControlActionUPP; + (**(ControlHandle)m_macControl).contrlDefProc = (Handle) cdef ; + } +#endif +#endif + SetControlColorProc( (ControlHandle) m_macControl , wxMacSetupControlBackgroundUPP ) ; + + // Adjust the controls size and position + wxPoint pos(m_x, m_y); + wxSize best_size( DoGetBestSize() ); + wxSize new_size( m_width, m_height ); + + m_x = m_y = m_width = m_height = -1; // Forces SetSize to move/size the control + + if (new_size.x == -1) { + new_size.x = best_size.x; + } + if (new_size.y == -1) { + new_size.y = best_size.y; + } + + SetSize(pos.x, pos.y, new_size.x, new_size.y); + +#if wxUSE_UNICODE + UMASetControlTitle( (ControlHandle) m_macControl , wxStripMenuCodes(m_label) , m_font.GetEncoding() ) ; +#endif + + if ( m_macControlIsShown ) + UMAShowControl( (ControlHandle) m_macControl ) ; + + SetCursor( *wxSTANDARD_CURSOR ) ; + + Refresh() ; +} + +void wxControl::MacAdjustControlRect() +{ + wxASSERT_MSG( (ControlHandle) m_macControl != NULL , wxT("No valid mac control") ) ; + if ( m_width == -1 || m_height == -1 ) + { + Rect bestsize = { 0 , 0 , 0 , 0 } ; + short baselineoffset ; + + ::GetBestControlRect( (ControlHandle) m_macControl , &bestsize , &baselineoffset ) ; + + if ( EmptyRect( &bestsize ) ) + { + baselineoffset = 0; + bestsize.left = bestsize.top = 0 ; + bestsize.right = 16 ; + bestsize.bottom = 16 ; + if ( IsKindOf( CLASSINFO( wxScrollBar ) ) ) + { + bestsize.bottom = 16 ; + } + else if ( IsKindOf( CLASSINFO( wxSpinButton ) ) ) + { + bestsize.bottom = 24 ; + } + } + + if ( m_width == -1 ) + { + if ( IsKindOf( CLASSINFO( wxButton ) ) ) + { + m_width = m_label.Length() * 8 + 12 ; + if ( m_width < 70 ) + m_width = 70 ; + } + else if ( IsKindOf( CLASSINFO( wxStaticText ) ) ) + { + m_width = m_label.Length() * 8 ; + } + else + m_width = bestsize.right - bestsize.left ; + + m_width += 2 * m_macHorizontalBorder + MacGetLeftBorderSize() + MacGetRightBorderSize() ; + } + if ( m_height == -1 ) + { + m_height = bestsize.bottom - bestsize.top ; + if ( m_height < 10 ) + m_height = 13 ; + + m_height += 2 * m_macVerticalBorder + MacGetTopBorderSize() + MacGetBottomBorderSize() ; + } + MacUpdateDimensions() ; + } +} + +WXWidget wxControl::MacGetContainerForEmbedding() +{ + if ( m_macControl ) + return m_macControl ; + + return wxWindow::MacGetContainerForEmbedding() ; +} + +void wxControl::MacUpdateDimensions() +{ + // actually in the current systems this should never be possible, but later reparenting + // may become a reality + + if ( (ControlHandle) m_macControl == NULL ) + return ; + + if ( GetParent() == NULL ) + return ; + + WindowRef rootwindow = (WindowRef) MacGetRootWindow() ; + if ( rootwindow == NULL ) + return ; + + Rect oldBounds ; + GetControlBounds( (ControlHandle) m_macControl , &oldBounds ) ; + + int new_x = m_x + MacGetLeftBorderSize() + m_macHorizontalBorder ; + int new_y = m_y + MacGetTopBorderSize() + m_macVerticalBorder ; + int new_width = m_width - MacGetLeftBorderSize() - MacGetRightBorderSize() - 2 * m_macHorizontalBorder ; + int new_height = m_height - MacGetTopBorderSize() - MacGetBottomBorderSize() - 2 * m_macVerticalBorder ; + + GetParent()->MacWindowToRootWindow( & new_x , & new_y ) ; + bool doMove = new_x != oldBounds.left || new_y != oldBounds.top ; + bool doResize = ( oldBounds.right - oldBounds.left ) != new_width || (oldBounds.bottom - oldBounds.top ) != new_height ; + if ( doMove || doResize ) + { + InvalWindowRect( rootwindow, &oldBounds ) ; + if ( doMove ) + { + UMAMoveControl( (ControlHandle) m_macControl , new_x , new_y ) ; + } + if ( doResize ) + { + UMASizeControl( (ControlHandle) m_macControl , new_width , new_height ) ; + } + } +} + +void wxControl::MacSuperChangedPosition() +{ + MacUpdateDimensions() ; + wxWindow::MacSuperChangedPosition() ; +} + +void wxControl::MacSuperEnabled( bool enabled ) +{ + Refresh(FALSE) ; + wxWindow::MacSuperEnabled( enabled ) ; +} + +void wxControl::MacSuperShown( bool show ) +{ + if ( (ControlHandle) m_macControl ) + { + if ( !show ) + { + if ( m_macControlIsShown ) + { + ::UMAHideControl( (ControlHandle) m_macControl ) ; + m_macControlIsShown = false ; + } + } + else + { + if ( MacIsReallyShown() && !m_macControlIsShown ) + { + ::UMAShowControl( (ControlHandle) m_macControl ) ; + m_macControlIsShown = true ; + } + } + } + + wxWindow::MacSuperShown( show ) ; +} + +void wxControl::DoSetSize(int x, int y, + int width, int height, + int sizeFlags ) +{ + wxWindow::DoSetSize( x , y ,width , height ,sizeFlags ) ; +#if 0 + { + Rect meta , control ; + GetControlBounds( (ControlHandle) m_macControl , &control ) ; + RgnHandle rgn = NewRgn() ; + GetControlRegion( (ControlHandle) m_macControl , kControlStructureMetaPart , rgn ) ; + GetRegionBounds( rgn , &meta ) ; + if ( !EmptyRect( &meta ) ) + { + wxASSERT( meta.left >= control.left - m_macHorizontalBorder ) ; + wxASSERT( meta.right <= control.right + m_macHorizontalBorder ) ; + wxASSERT( meta.top >= control.top - m_macVerticalBorder ) ; + wxASSERT( meta.bottom <= control.bottom + m_macVerticalBorder ) ; + } + DisposeRgn( rgn ) ; + } +#endif + return ; +} + +bool wxControl::Show(bool show) +{ + if ( !wxWindow::Show( show ) ) + return FALSE ; + + if ( (ControlHandle) m_macControl ) + { + if ( !show ) + { + if ( m_macControlIsShown ) + { + ::UMAHideControl( (ControlHandle) m_macControl ) ; + m_macControlIsShown = false ; + } + } + else + { + if ( MacIsReallyShown() && !m_macControlIsShown ) + { + ::UMAShowControl( (ControlHandle) m_macControl ) ; + m_macControlIsShown = true ; + } + } + } + return TRUE ; +} + +bool wxControl::Enable(bool enable) +{ + if ( !wxWindow::Enable(enable) ) + return FALSE; + + if ( (ControlHandle) m_macControl ) + { + if ( enable ) + UMAActivateControl( (ControlHandle) m_macControl ) ; + else + UMADeactivateControl( (ControlHandle) m_macControl ) ; + } + return TRUE ; +} + +void wxControl::Refresh(bool eraseBack, const wxRect *rect) +{ + wxWindow::Refresh( eraseBack , rect ) ; +} + +void wxControl::MacRedrawControl() +{ + if ( (ControlHandle) m_macControl && MacGetRootWindow() && m_macControlIsShown ) + { + wxClientDC dc(this) ; + wxMacPortSetter helper(&dc) ; + wxMacWindowClipper clipper(this) ; + wxDC::MacSetupBackgroundForCurrentPort( MacGetBackgroundBrush() ) ; + UMADrawControl( (ControlHandle) m_macControl ) ; + } +} + +void wxControl::OnPaint(wxPaintEvent& event) +{ + if ( (ControlHandle) m_macControl ) + { + wxPaintDC dc(this) ; + wxMacPortSetter helper(&dc) ; + wxMacWindowClipper clipper(this) ; + wxDC::MacSetupBackgroundForCurrentPort( MacGetBackgroundBrush() ) ; + UMADrawControl( (ControlHandle) m_macControl ) ; + } + else + { + event.Skip() ; + } +} +void wxControl::OnEraseBackground(wxEraseEvent& event) +{ + wxWindow::OnEraseBackground( event ) ; +} + +void wxControl::OnKeyDown( wxKeyEvent &event ) +{ + if ( (ControlHandle) m_macControl == NULL ) + return ; + +#if TARGET_CARBON + + char charCode ; + UInt32 keyCode ; + UInt32 modifiers ; + + GetEventParameter( (EventRef) wxTheApp->MacGetCurrentEvent(), kEventParamKeyMacCharCodes, typeChar, NULL,sizeof(char), NULL,&charCode ); + GetEventParameter( (EventRef) wxTheApp->MacGetCurrentEvent(), kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode ); + GetEventParameter((EventRef) wxTheApp->MacGetCurrentEvent(), kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); + + ::HandleControlKey( (ControlHandle) m_macControl , keyCode , charCode , modifiers ) ; + +#else + EventRecord *ev = (EventRecord*) wxTheApp->MacGetCurrentEvent() ; + short keycode ; + short keychar ; + keychar = short(ev->message & charCodeMask); + keycode = short(ev->message & keyCodeMask) >> 8 ; + + ::HandleControlKey( (ControlHandle) m_macControl , keycode , keychar , ev->modifiers ) ; +#endif +} + +void wxControl::OnMouseEvent( wxMouseEvent &event ) +{ + if ( (ControlHandle) m_macControl == NULL ) + { + event.Skip() ; + return ; + } + + if (event.GetEventType() == wxEVT_LEFT_DOWN || event.GetEventType() == wxEVT_LEFT_DCLICK ) + { + + int x = event.m_x ; + int y = event.m_y ; + + MacClientToRootWindow( &x , &y ) ; + + ControlHandle control ; + Point localwhere ; + SInt16 controlpart ; + + localwhere.h = x ; + localwhere.v = y ; + + short modifiers = 0; + + if ( !event.m_leftDown && !event.m_rightDown ) + modifiers |= btnState ; + + if ( event.m_shiftDown ) + modifiers |= shiftKey ; + + if ( event.m_controlDown ) + modifiers |= controlKey ; + + if ( event.m_altDown ) + modifiers |= optionKey ; + + if ( event.m_metaDown ) + modifiers |= cmdKey ; + { + control = (ControlHandle) m_macControl ; + if ( control && ::IsControlActive( control ) ) + { + { + controlpart = ::HandleControlClick( control , localwhere , modifiers , (ControlActionUPP) -1 ) ; + wxTheApp->s_lastMouseDown = 0 ; + if ( control && controlpart != kControlNoPart ) + { + MacHandleControlClick( control , controlpart , false /* mouse not down anymore */ ) ; + } + } + } + } + } + else + { + event.Skip() ; + } +} + +bool wxControl::MacCanFocus() const +{ + if ( (ControlHandle) m_macControl == NULL ) + return true ; + else + return false ; +} + +void wxControl::MacHandleControlClick( WXWidget control , wxInt16 controlpart , bool WXUNUSED( mouseStillDown ) ) +{ + wxASSERT_MSG( (ControlHandle) m_macControl != NULL , wxT("No valid mac control") ) ; +} + +void wxControl::DoSetWindowVariant( wxWindowVariant variant ) +{ + if ( m_macControl == NULL ) + { + wxWindow::SetWindowVariant( variant ) ; + return ; + + } + m_windowVariant = variant ; + + ControlSize size ; + ControlFontStyleRec fontStyle; + fontStyle.flags = kControlUseFontMask ; + + // we will get that from the settings later + // and make this NORMAL later, but first + // we have a few calculations that we must fix + + if ( variant == wxWINDOW_VARIANT_DEFAULT ) + { + if ( IsKindOf( CLASSINFO( wxScrollBar ) ) ) + variant = wxWINDOW_VARIANT_NORMAL ; + else + variant = wxWINDOW_VARIANT_SMALL ; + } + + switch ( variant ) + { + case wxWINDOW_VARIANT_NORMAL : + size = kControlSizeNormal; + fontStyle.font = kControlFontBigSystemFont; + break ; + case wxWINDOW_VARIANT_SMALL : + size = kControlSizeSmall; + fontStyle.font = kControlFontSmallSystemFont; + break ; + case wxWINDOW_VARIANT_MINI : + if (UMAGetSystemVersion() >= 0x1030 ) + { + size = 3 ; // not always defined in the header + fontStyle.font = -5 ; // not always defined in the header + } + else + { + size = kControlSizeSmall; + fontStyle.font = kControlFontSmallSystemFont; + } + break; + break ; + case wxWINDOW_VARIANT_LARGE : + size = kControlSizeLarge; + fontStyle.font = kControlFontBigSystemFont; + break ; + default: + wxFAIL_MSG(_T("unexpected window variant")); + break ; + } + ::SetControlData( (ControlHandle) m_macControl , kControlEntireControl, kControlSizeTag, sizeof( ControlSize ), &size ); + ::SetControlFontStyle( (ControlHandle) m_macControl , &fontStyle ); +} diff --git a/src/mac/classic/corersrc.r b/src/mac/classic/corersrc.r new file mode 100644 index 0000000000..676a4d3d2a --- /dev/null +++ b/src/mac/classic/corersrc.r @@ -0,0 +1,159 @@ +#ifdef __UNIX__ + #include +#else + #include + #if UNIVERSAL_INTERFACES_VERSION > 0x320 + #include + #endif +#endif + +resource 'ldes' ( 128 ) +{ + versionZero + { + 0 , + 0 , + 0 , + 0 , + hasVertScroll , + noHorizScroll , + 0 , + noGrowSpace , + } +} ; + +resource 'ldes' ( 129 ) +{ + versionZero + { + 0 , + 0 , + 0 , + 0 , + hasVertScroll , + hasHorizScroll , + 0 , + noGrowSpace , + } +} ; + +data 'CURS' (10) { + $"0000 03E0 0630 0808 1004 31C6 2362 2222" + $"2362 31C6 1004 0808 0630 03E0 0000 0000" + $"0000 03E0 07F0 0FF8 1FFC 3FFE 3FFE 3FFE" + $"3FFE 3FFE 1FFC 0FF8 07F0 03E0 0000 0000" + $"0007 0008" +}; + +data 'CURS' (11) { + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000" +}; + +data 'CURS' (12) { + $"00F0 0088 0108 0190 0270 0220 0440 0440" + $"0880 0880 1100 1E00 1C00 1800 1000 0000" + $"00F0 00F8 01F8 01F0 03F0 03E0 07C0 07C0" + $"0F80 0F80 1F00 1E00 1C00 1800 1000 0000" + $"000E 0003" +}; + +data 'CURS' (13) { + $"0000 1E00 2100 4080 4080 4080 4080 2180" + $"1FC0 00E0 0070 0038 001C 000E 0006 0000" + $"3F00 7F80 FFC0 FFC0 FFC0 FFC0 FFC0 7FC0" + $"3FE0 1FF0 00F8 007C 003E 001F 000F 0007" + $"0004 0004" +}; + +data 'CURS' (14) { + $"0000 07E0 1FF0 3838 3C0C 6E0E 6706 6386" + $"61C6 60E6 7076 303C 1C1C 0FF8 07E0 0000" + $"0540 0FF0 3FF8 3C3C 7E0E FF0F 6F86 E7C7" + $"63E6 E1F7 70FE 707E 3C3C 1FFC 0FF0 0540" + $"0007 0007" +}; + +data 'CURS' (15) { + $"0000 0380 0380 0380 0380 0380 0380 0FE0" + $"1FF0 1FF0 0000 1FF0 1FF0 1550 1550 1550" + $"07C0 07C0 07C0 07C0 07C0 07C0 0FE0 1FF0" + $"3FF8 3FF8 3FF8 3FF8 3FF8 3FF8 3FF8 3FF8" + $"000B 0007" +}; + +data 'CURS' (16) { + $"00C0 0140 0640 08C0 3180 47FE 8001 8001" + $"81FE 8040 01C0 0040 03C0 C080 3F80 0000" + $"00C0 01C0 07C0 0FC0 3F80 7FFE FFFF FFFF" + $"FFFE FFC0 FFC0 FFC0 FFC0 FF80 3F80 0000" + $"0006 000F" +}; + +data 'CURS' (17) { + $"0100 0280 0260 0310 018C 7FE3 8000 8000" + $"7F80 0200 0380 0200 03C0 0107 01F8 0000" + $"0100 0380 03E0 03F0 01FC 7FFF FFFF FFFF" + $"FFFF 03FF 03FF 03FF 03FF 01FF 01F8 0000" + $"0006 0000" +}; + +data 'CURS' (18) { + $"0000 4078 60FC 71CE 7986 7C06 7E0E 7F1C" + $"7FB8 7C30 6C30 4600 0630 0330 0300 0000" + $"C078 E0FC F1FE FBFF FFCF FF8F FF1F FFBE" + $"FFFC FE78 FF78 EFF8 CFF8 87F8 07F8 0300" + $"0001 0001" +}; + +data 'CURS' (19) { + $"0000 0002 0006 000E 001E 003E 007E 00FE" + $"01FE 003E 0036 0062 0060 00C0 00C0 0000" + $"0003 0007 000F 001F 003F 007F 00FF 01FF" + $"03FF 07FF 007F 00F7 00F3 01E1 01E0 01C0" + $"0001 000E" +}; + +data 'CURS' (20) { + $"0000 0080 01C0 03E0 0080 0080 0080 1FFC" + $"1FFC 0080 0080 0080 03E0 01C0 0080 0000" + $"0080 01C0 03E0 07F0 0FF8 01C0 3FFE 3FFE" + $"3FFE 3FFE 01C0 0FF8 07F0 03E0 01C0 0080" + $"0007 0008" +}; + +data 'CURS' (21) { + $"0000 0080 01C0 03E0 0080 0888 188C 3FFE" + $"188C 0888 0080 03E0 01C0 0080 0000 0000" + $"0080 01C0 03E0 07F0 0BE8 1DDC 3FFE 7FFF" + $"3FFE 1DDC 0BE8 07F0 03E0 01C0 0080 0000" + $"0007 0008" +}; + +data 'CURS' (22) { + $"0000 001E 000E 060E 0712 03A0 01C0 00E0" + $"0170 1238 1C18 1C00 1E00 0000 0000 0000" + $"007F 003F 0E1F 0F0F 0F97 07E3 03E1 21F0" + $"31F8 3A7C 3C3C 3E1C 3F00 3F80 0000 0000" + $"0006 0009" +}; + +data 'CURS' (23) { + $"0000 7800 7000 7060 48E0 05C0 0380 0700" + $"0E80 1C48 1838 0038 0078 0000 0000 0000" + $"FE00 FC00 F870 F0F0 E9F0 C7E0 87C0 0F84" + $"1F8C 3E5C 3C3C 387C 00FC 01FC 0000 0000" + $"0006 0006" +}; + +data 'CURS' (24) { + $"0006 000E 001C 0018 0020 0040 00F8 0004" + $"1FF4 200C 2AA8 1FF0 1F80 3800 6000 8000" + $"000F 001F 003E 007C 0070 00E0 01FC 3FF6" + $"7FF6 7FFE 7FFC 7FF8 3FF0 7FC0 F800 E000" + $"000A 0006" +}; + diff --git a/src/mac/classic/cursor.cpp b/src/mac/classic/cursor.cpp new file mode 100644 index 0000000000..b780a675c9 --- /dev/null +++ b/src/mac/classic/cursor.cpp @@ -0,0 +1,505 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: cursor.cpp +// Purpose: wxCursor class +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "cursor.h" +#endif + +#include "wx/defs.h" + +#include "wx/app.h" +#include "wx/cursor.h" +#include "wx/icon.h" +#include "wx/image.h" +#include "wx/xpmdecod.h" + +#include "wx/mac/private.h" + +#if !USE_SHARED_LIBRARIES +IMPLEMENT_DYNAMIC_CLASS(wxCursor, wxBitmap) +#endif + +const short kwxCursorBullseye = 10 ; +const short kwxCursorBlank = 11 ; +const short kwxCursorPencil = 12 ; +const short kwxCursorMagnifier = 13 ; +const short kwxCursorNoEntry = 14 ; +const short kwxCursorPaintBrush = 15 ; +const short kwxCursorPointRight = 16 ; +const short kwxCursorPointLeft = 17 ; +const short kwxCursorQuestionArrow = 18 ; +const short kwxCursorRightArrow = 19 ; +const short kwxCursorSizeNS = 20 ; +const short kwxCursorSize = 21 ; +const short kwxCursorSizeNESW = 22 ; +const short kwxCursorSizeNWSE = 23 ; +const short kwxCursorRoller = 24 ; + +wxCursor gMacCurrentCursor ; + +wxCursorRefData::wxCursorRefData() +{ + m_width = 16; + m_height = 16; + m_hCursor = NULL ; + m_disposeHandle = false ; + m_releaseHandle = false ; + m_isColorCursor = false ; + m_themeCursor = -1 ; +} + +wxCursorRefData::~wxCursorRefData() +{ + if ( m_isColorCursor ) + { + ::DisposeCCursor( (CCrsrHandle) m_hCursor ) ; + } + else if ( m_disposeHandle ) + { + ::DisposeHandle( (Handle ) m_hCursor ) ; + } + else if ( m_releaseHandle ) + { + // we don't release the resource since it may already + // be in use again + } +} + +// Cursors +wxCursor::wxCursor() +{ +} + +wxCursor::wxCursor(const char WXUNUSED(bits)[], int WXUNUSED(width), int WXUNUSED(height), + int WXUNUSED(hotSpotX), int WXUNUSED(hotSpotY), const char WXUNUSED(maskBits)[]) +{ +} + +wxCursor::wxCursor( const wxImage &image ) +{ + CreateFromImage( image ) ; +} + +wxCursor::wxCursor(const char **bits) +{ + (void) CreateFromXpm(bits); +} + +wxCursor::wxCursor(char **bits) +{ + (void) CreateFromXpm((const char **)bits); +} + +bool wxCursor::CreateFromXpm(const char **bits) +{ + wxCHECK_MSG( bits != NULL, FALSE, wxT("invalid cursor data") ) + wxXPMDecoder decoder; + wxImage img = decoder.ReadData(bits); + wxCHECK_MSG( img.Ok(), FALSE, wxT("invalid cursor data") ) + CreateFromImage( img ) ; + return TRUE; +} + +short GetCTabIndex( CTabHandle colors , RGBColor *col ) +{ + short retval = 0 ; + unsigned long bestdiff = 0xFFFF ; + for ( int i = 0 ; i < (**colors).ctSize ; ++i ) + { + unsigned long diff = abs(col->red - (**colors).ctTable[i].rgb.red ) + + abs(col->green - (**colors).ctTable[i].rgb.green ) + + abs(col->blue - (**colors).ctTable[i].rgb.blue ) ; + if ( diff < bestdiff ) + { + bestdiff = diff ; + retval = (**colors).ctTable[i].value ; + } + } + return retval ; +} + +void wxCursor::CreateFromImage(const wxImage & image) +{ + m_refData = new wxCursorRefData; + + wxImage image16 = image.Scale(16,16) ; + unsigned char * rgbBits = image16.GetData(); + + + int w = image16.GetWidth() ; + int h = image16.GetHeight() ; + bool bHasMask = image16.HasMask() ; + + int hotSpotX = image16.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X); + int hotSpotY = image16.GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y); + if (hotSpotX < 0 || hotSpotX >= w) + hotSpotX = 0; + if (hotSpotY < 0 || hotSpotY >= h) + hotSpotY = 0; + +#if 0 + // monochrome implementation + M_CURSORDATA->m_hCursor = NewHandle( sizeof( Cursor ) ) ; + M_CURSORDATA->m_disposeHandle = true ; + HLock( (Handle) M_CURSORDATA->m_hCursor ) ; + CursPtr cp = *(CursHandle)M_CURSORDATA->m_hCursor ; + memset( cp->data , 0 , sizeof( Bits16 ) ) ; + memset( cp->mask , 0 , sizeof( Bits16 ) ) ; + + unsigned char mr = image16.GetMaskRed() ; + unsigned char mg = image16.GetMaskGreen() ; + unsigned char mb = image16.GetMaskBlue() ; + for ( int y = 0 ; y < h ; ++y ) + { + short rowbits = 0 ; + short maskbits = 0 ; + + for ( int x = 0 ; x < w ; ++x ) + { + long pos = (y * w + x) * 3; + + unsigned char r = rgbBits[pos] ; + unsigned char g = rgbBits[pos+1] ; + unsigned char b = rgbBits[pos+2] ; + if ( bHasMask && r==mr && g==mg && b==mb ) + { + // masked area, does not appear anywhere + } + else + { + if ( (int)r + (int)g + (int)b < 0x0200 ) + { + rowbits |= ( 1 << (15-x) ) ; + } + maskbits |= ( 1 << (15-x) ) ; + } + } + cp->data[y] = rowbits ; + cp->mask[y] = maskbits ; + } + if ( !bHasMask ) + { + memcpy( cp->mask , cp->data , sizeof( Bits16) ) ; + } + cp->hotSpot.h = hotSpotX ; + cp->hotSpot.v = hotSpotY ; + HUnlock( (Handle) M_CURSORDATA->m_hCursor ) ; +#else + PixMapHandle pm = (PixMapHandle) NewHandleClear( sizeof (PixMap)) ; + short extent = 16 ; + short bytesPerPixel = 1 ; + short depth = 8 ; + Rect bounds = { 0 , 0 , extent , extent } ; + CCrsrHandle ch = (CCrsrHandle) NewHandleClear ( sizeof( CCrsr ) ) ; + CTabHandle newColors = GetCTable( 8 ) ; + HandToHand((Handle *) &newColors); + // set the values to the indices + for ( int i = 0 ; i < (**newColors).ctSize ; ++i ) + { + (**newColors).ctTable[i].value = i ; + } + HLock( (Handle) ch) ; + (**ch).crsrType = 0x8001 ; // color cursors + (**ch).crsrMap = pm ; + short bytesPerRow = bytesPerPixel * extent ; + + (**pm).baseAddr = 0; + (**pm).rowBytes = bytesPerRow | 0x8000; + (**pm).bounds = bounds; + (**pm).pmVersion = 0; + (**pm).packType = 0; + (**pm).packSize = 0; + (**pm).hRes = 0x00480000; /* 72 DPI default res */ + (**pm).vRes = 0x00480000; /* 72 DPI default res */ + (**pm).pixelSize = depth; + (**pm).pixelType = 0; + (**pm).cmpCount = 1; + (**pm).cmpSize = depth; + (**pm).pmTable = newColors; + + (**ch).crsrData = NewHandleClear( extent * bytesPerRow ) ; + (**ch).crsrXData = NULL ; + (**ch).crsrXValid = 0; + (**ch).crsrXHandle = NULL; + + (**ch).crsrHotSpot.h = hotSpotX ; + (**ch).crsrHotSpot.v = hotSpotY ; + (**ch).crsrXTable = NULL ; + (**ch).crsrID = GetCTSeed() ; + + memset( (**ch).crsr1Data , 0 , sizeof( Bits16 ) ) ; + memset( (**ch).crsrMask , 0 , sizeof( Bits16 ) ) ; + + unsigned char mr = image16.GetMaskRed() ; + unsigned char mg = image16.GetMaskGreen() ; + unsigned char mb = image16.GetMaskBlue() ; + for ( int y = 0 ; y < h ; ++y ) + { + short rowbits = 0 ; + short maskbits = 0 ; + + for ( int x = 0 ; x < w ; ++x ) + { + long pos = (y * w + x) * 3; + + unsigned char r = rgbBits[pos] ; + unsigned char g = rgbBits[pos+1] ; + unsigned char b = rgbBits[pos+2] ; + RGBColor col = { 0xFFFF ,0xFFFF, 0xFFFF } ; + + if ( bHasMask && r==mr && g==mg && b==mb ) + { + // masked area, does not appear anywhere + } + else + { + if ( (int)r + (int)g + (int)b < 0x0200 ) + { + rowbits |= ( 1 << (15-x) ) ; + } + maskbits |= ( 1 << (15-x) ) ; + + col = *((RGBColor*) wxColor( r , g , b ).GetPixel()) ; + } + *((*(**ch).crsrData) + y * bytesPerRow + x) = + GetCTabIndex( newColors , &col) ; + } + (**ch).crsr1Data[y] = rowbits ; + (**ch).crsrMask[y] = maskbits ; + } + if ( !bHasMask ) + { + memcpy( (**ch).crsrMask , (**ch).crsr1Data , sizeof( Bits16) ) ; + } + + HUnlock((Handle) ch) ; + M_CURSORDATA->m_hCursor = ch ; + M_CURSORDATA->m_isColorCursor = true ; +#endif +} + +wxCursor::wxCursor(const wxString& cursor_file, long flags, int hotSpotX, int hotSpotY) +{ + m_refData = new wxCursorRefData; + if ( flags == wxBITMAP_TYPE_MACCURSOR_RESOURCE ) + { + Str255 theName ; + wxMacStringToPascal( cursor_file , theName ) ; + + wxStAppResource resload ; + Handle resHandle = ::GetNamedResource( 'crsr' , theName ) ; + if ( resHandle ) + { + short theId = -1 ; + OSType theType ; + GetResInfo( resHandle , &theId , &theType , theName ) ; + ReleaseResource( resHandle ) ; + M_CURSORDATA->m_hCursor = GetCCursor( theId ) ; + if ( M_CURSORDATA->m_hCursor ) + M_CURSORDATA->m_isColorCursor = true ; + } + else + { + Handle resHandle = ::GetNamedResource( 'CURS' , theName ) ; + if ( resHandle ) + { + short theId = -1 ; + OSType theType ; + GetResInfo( resHandle , &theId , &theType , theName ) ; + ReleaseResource( resHandle ) ; + M_CURSORDATA->m_hCursor = GetCursor( theId ) ; + if ( M_CURSORDATA->m_hCursor ) + M_CURSORDATA->m_releaseHandle = true ; + } + } + } + else + { + wxImage image ; + image.LoadFile( cursor_file , flags ) ; + if( image.Ok() ) + { + image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X,hotSpotX ) ; + image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y,hotSpotY ) ; + delete m_refData ; + CreateFromImage(image) ; + } + } +} + +// Cursors by stock number +wxCursor::wxCursor(int cursor_type) +{ + m_refData = new wxCursorRefData; + + switch (cursor_type) + { + case wxCURSOR_COPY_ARROW: + M_CURSORDATA->m_themeCursor = kThemeCopyArrowCursor ; + break; + case wxCURSOR_WAIT: + M_CURSORDATA->m_themeCursor = kThemeWatchCursor ; + break; + case wxCURSOR_IBEAM: + M_CURSORDATA->m_themeCursor = kThemeIBeamCursor ; + break; + case wxCURSOR_CROSS: + M_CURSORDATA->m_themeCursor = kThemeCrossCursor; + break; + case wxCURSOR_SIZENWSE: + { + wxStAppResource resload ; + M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorSizeNWSE); + } + break; + case wxCURSOR_SIZENESW: + { + wxStAppResource resload ; + M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorSizeNESW); + } + break; + case wxCURSOR_SIZEWE: + { + M_CURSORDATA->m_themeCursor = kThemeResizeLeftRightCursor; + } + break; + case wxCURSOR_SIZENS: + { + wxStAppResource resload ; + M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorSizeNS); + } + break; + case wxCURSOR_SIZING: + { + wxStAppResource resload ; + M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorSize); + } + break; + case wxCURSOR_HAND: + { + M_CURSORDATA->m_themeCursor = kThemePointingHandCursor; + } + break; + case wxCURSOR_BULLSEYE: + { + wxStAppResource resload ; + M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorBullseye); + } + break; + case wxCURSOR_PENCIL: + { + wxStAppResource resload ; + M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorPencil); + } + break; + case wxCURSOR_MAGNIFIER: + { + wxStAppResource resload ; + M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorMagnifier); + } + break; + case wxCURSOR_NO_ENTRY: + { + wxStAppResource resload ; + M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorNoEntry); + } + break; + case wxCURSOR_WATCH: + { + M_CURSORDATA->m_themeCursor = kThemeWatchCursor; + break; + } + case wxCURSOR_PAINT_BRUSH: + { + wxStAppResource resload ; + M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorPaintBrush); + break; + } + case wxCURSOR_POINT_LEFT: + { + wxStAppResource resload ; + M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorPointLeft); + break; + } + case wxCURSOR_POINT_RIGHT: + { + wxStAppResource resload ; + M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorPointRight); + break; + } + case wxCURSOR_QUESTION_ARROW: + { + wxStAppResource resload ; + M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorQuestionArrow); + break; + } + case wxCURSOR_BLANK: + { + wxStAppResource resload ; + M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorBlank); + break; + } + case wxCURSOR_RIGHT_ARROW: + { + wxStAppResource resload ; + M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorRightArrow); + break; + } + case wxCURSOR_SPRAYCAN: + { + wxStAppResource resload ; + M_CURSORDATA->m_hCursor = ::GetCursor(kwxCursorRoller); + break; + } + case wxCURSOR_CHAR: + case wxCURSOR_ARROW: + case wxCURSOR_LEFT_BUTTON: + case wxCURSOR_RIGHT_BUTTON: + case wxCURSOR_MIDDLE_BUTTON: + default: + M_CURSORDATA->m_themeCursor = kThemeArrowCursor ; + break; + } + if ( M_CURSORDATA->m_themeCursor == -1 ) + M_CURSORDATA->m_releaseHandle = true ; +} + +void wxCursor::MacInstall() const +{ + gMacCurrentCursor = *this ; + if ( m_refData && M_CURSORDATA->m_themeCursor != -1 ) + { + SetThemeCursor( M_CURSORDATA->m_themeCursor ) ; + } + else if ( m_refData && M_CURSORDATA->m_hCursor ) + { + if ( M_CURSORDATA->m_isColorCursor ) + ::SetCCursor( (CCrsrHandle) M_CURSORDATA->m_hCursor ) ; + else + ::SetCursor( * (CursHandle) M_CURSORDATA->m_hCursor ) ; + } + else + { + SetThemeCursor( kThemeArrowCursor ) ; + } +} + +wxCursor::~wxCursor() +{ +} + +// Global cursor setting +void wxSetCursor(const wxCursor& cursor) +{ + cursor.MacInstall() ; +} + + diff --git a/src/mac/classic/data.cpp b/src/mac/classic/data.cpp new file mode 100644 index 0000000000..1f0bea00d2 --- /dev/null +++ b/src/mac/classic/data.cpp @@ -0,0 +1,25 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: mac/data.cpp +// Purpose: Various global Mac-specific data +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/event.h" + +#if wxUSE_SHARED_LIBRARY +///// Event tables (also must be in one, statically-linked file for shared libraries) + +// This is the base, wxEvtHandler 'bootstrap' code which is expanded manually here +const wxEventTable *wxEvtHandler::GetEventTable() const { return &wxEvtHandler::sm_eventTable; } + +const wxEventTable wxEvtHandler::sm_eventTable = + { NULL, &wxEvtHandler::sm_eventTableEntries[0] }; + +const wxEventTableEntry wxEvtHandler::sm_eventTableEntries[] = { { 0, 0, 0, NULL } }; +#endif + diff --git a/src/mac/classic/dataobj.cpp b/src/mac/classic/dataobj.cpp new file mode 100644 index 0000000000..64dc8053d0 --- /dev/null +++ b/src/mac/classic/dataobj.cpp @@ -0,0 +1,308 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: mac/dataobj.cpp +// Purpose: implementation of wxDataObject class +// Author: Stefan Csomor +// Modified by: +// Created: 10/21/99 +// RCS-ID: $Id$ +// Copyright: (c) 1999 Stefan Csomor +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#ifdef __GNUG__ + #pragma implementation "dataobj.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifndef WX_PRECOMP +#include "wx/intl.h" +#endif +#include "wx/defs.h" + +#include "wx/log.h" +#include "wx/dataobj.h" +#include "wx/mstream.h" +#include "wx/image.h" +#include "wx/mac/private.h" +#include + +// ---------------------------------------------------------------------------- +// functions +// ---------------------------------------------------------------------------- + +// ---------------------------------------------------------------------------- +// wxDataFormat +// ---------------------------------------------------------------------------- + +wxDataFormat::wxDataFormat() +{ + m_type = wxDF_INVALID; + m_format = 0; +} + +wxDataFormat::wxDataFormat( wxDataFormatId vType ) +{ + SetType(vType); +} + +wxDataFormat::wxDataFormat( const wxChar* zId) +{ + SetId(zId); +} + +wxDataFormat::wxDataFormat( const wxString& rId) +{ + SetId(rId); +} + +wxDataFormat::wxDataFormat( NativeFormat vFormat) +{ + SetId(vFormat); +} + +void wxDataFormat::SetType( wxDataFormatId Type ) +{ + m_type = Type; + + if (m_type == wxDF_TEXT ) + m_format = kScrapFlavorTypeText; + else if (m_type == wxDF_UNICODETEXT ) + m_format = kScrapFlavorTypeUnicode ; + else if (m_type == wxDF_BITMAP || m_type == wxDF_METAFILE ) + m_format = kScrapFlavorTypePicture; + else if (m_type == wxDF_FILENAME) + m_format = kDragFlavorTypeHFS ; + else + { + wxFAIL_MSG( wxT("invalid dataformat") ); + + // this is '????' but it can't be used in the code because ??' is + // parsed as a trigraph! + m_format = 0x3f3f3f3f; + } +} + +wxString wxDataFormat::GetId() const +{ + // note that m_format is not a pointer to string, it *is* itself a 4 + // character string + char text[5] ; + strncpy( text , (char*) &m_format , 4 ) ; + text[4] = 0 ; + + return wxString::FromAscii( text ) ; +} + +void wxDataFormat::SetId( NativeFormat format ) +{ + m_format = format; + + if (m_format == kScrapFlavorTypeText) + m_type = wxDF_TEXT; + else if (m_format == kScrapFlavorTypeUnicode ) + m_type = wxDF_UNICODETEXT; + else if (m_format == kScrapFlavorTypePicture) + m_type = wxDF_BITMAP; + else if (m_format == kDragFlavorTypeHFS ) + m_type = wxDF_FILENAME; + else + m_type = wxDF_PRIVATE; +} + +void wxDataFormat::SetId( const wxChar* zId ) +{ + m_type = wxDF_PRIVATE; + m_format = 0;// TODO: get the format gdk_atom_intern( wxMBSTRINGCAST tmp.mbc_str(), FALSE ); +} + +//------------------------------------------------------------------------- +// wxDataObject +//------------------------------------------------------------------------- + +wxDataObject::wxDataObject() +{ +} + +bool wxDataObject::IsSupportedFormat( + const wxDataFormat& rFormat +, Direction vDir +) const +{ + size_t nFormatCount = GetFormatCount(vDir); + + if (nFormatCount == 1) + { + return rFormat == GetPreferredFormat(); + } + else + { + wxDataFormat* pFormats = new wxDataFormat[nFormatCount]; + GetAllFormats( pFormats + ,vDir + ); + + size_t n; + + for (n = 0; n < nFormatCount; n++) + { + if (pFormats[n] == rFormat) + break; + } + + delete [] pFormats; + + // found? + return n < nFormatCount; + } +} + +// ---------------------------------------------------------------------------- +// wxFileDataObject +// ---------------------------------------------------------------------------- + +bool wxFileDataObject::GetDataHere( + void* pBuf +) const +{ + wxString sFilenames; + + for (size_t i = 0; i < m_filenames.GetCount(); i++) + { + sFilenames += m_filenames[i]; + sFilenames += (wxChar)0; + } + + memcpy(pBuf, sFilenames.mbc_str(), sFilenames.Len() + 1); + return TRUE; +} + +size_t wxFileDataObject::GetDataSize() const +{ + size_t nRes = 0; + + for (size_t i = 0; i < m_filenames.GetCount(); i++) + { + nRes += m_filenames[i].Len(); + nRes += 1; + } + + return nRes + 1; +} + +bool wxFileDataObject::SetData( + size_t WXUNUSED(nSize) +, const void* pBuf +) +{ + m_filenames.Empty(); + + AddFile(wxString::FromAscii((char*)pBuf)); + + return TRUE; +} + +void wxFileDataObject::AddFile( + const wxString& rFilename +) +{ + m_filenames.Add(rFilename); +} + +// ---------------------------------------------------------------------------- +// wxBitmapDataObject +// ---------------------------------------------------------------------------- + +wxBitmapDataObject::wxBitmapDataObject() +{ + Init(); +} + +wxBitmapDataObject::wxBitmapDataObject( + const wxBitmap& rBitmap +) +: wxBitmapDataObjectBase(rBitmap) +{ + Init(); + if ( m_bitmap.Ok() ) + { + m_pictHandle = m_bitmap.GetPict( &m_pictCreated ) ; + } +} + +wxBitmapDataObject::~wxBitmapDataObject() +{ + Clear(); +} + +void wxBitmapDataObject::SetBitmap( + const wxBitmap& rBitmap +) +{ + Clear(); + wxBitmapDataObjectBase::SetBitmap(rBitmap); + if ( m_bitmap.Ok() ) + { + m_pictHandle = m_bitmap.GetPict( &m_pictCreated ) ; + } +} + +void wxBitmapDataObject::Init() +{ + m_pictHandle = NULL ; + m_pictCreated = false ; +} + +void wxBitmapDataObject::Clear() +{ + if ( m_pictCreated && m_pictHandle ) + { + KillPicture( (PicHandle) m_pictHandle ) ; + } + m_pictHandle = NULL ; +} + +bool wxBitmapDataObject::GetDataHere( + void* pBuf +) const +{ + if (!m_pictHandle) + { + wxFAIL_MSG(wxT("attempt to copy empty bitmap failed")); + return FALSE; + } + memcpy(pBuf, *(Handle)m_pictHandle, GetHandleSize((Handle)m_pictHandle)); + return TRUE; +} + +size_t wxBitmapDataObject::GetDataSize() const +{ + return GetHandleSize((Handle)m_pictHandle) ; +} + +bool wxBitmapDataObject::SetData( + size_t nSize +, const void* pBuf +) +{ + Clear(); + PicHandle picHandle = (PicHandle) NewHandle( nSize ) ; + memcpy( *picHandle , pBuf , nSize ) ; + m_pictHandle = picHandle ; + m_pictCreated = false ; + Rect frame = (**picHandle).picFrame ; + + m_bitmap.SetPict( picHandle ) ; + m_bitmap.SetWidth( frame.right - frame.left ) ; + m_bitmap.SetHeight( frame.bottom - frame.top ) ; + return m_bitmap.Ok(); +} diff --git a/src/mac/classic/dc.cpp b/src/mac/classic/dc.cpp new file mode 100644 index 0000000000..d906bac5a4 --- /dev/null +++ b/src/mac/classic/dc.cpp @@ -0,0 +1,2297 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: dc.cpp +// Purpose: wxDC class +// Author: Stefan Csomor +// Modified by: +// Created: 01/02/97 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "dc.h" +#endif + +#include "wx/dc.h" +#include "wx/app.h" +#include "wx/mac/uma.h" +#include "wx/dcmemory.h" +#include "wx/dcprint.h" +#include "wx/region.h" +#include "wx/image.h" +#include "wx/log.h" + +#if __MSL__ >= 0x6000 +#include "math.h" +using namespace std ; +#endif + +#include "wx/mac/private.h" +#include +#include +#include +#include +#if !USE_SHARED_LIBRARY +IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject) +#endif + +//----------------------------------------------------------------------------- +// constants +//----------------------------------------------------------------------------- + +#define mm2inches 0.0393700787402 +#define inches2mm 25.4 +#define mm2twips 56.6929133859 +#define twips2mm 0.0176388888889 +#define mm2pt 2.83464566929 +#define pt2mm 0.352777777778 +#if !defined( __DARWIN__ ) || defined(__MWERKS__) +#ifndef M_PI +const double M_PI = 3.14159265358979 ; +#endif +#endif +const double RAD2DEG = 180.0 / M_PI; +const short kEmulatedMode = -1 ; +const short kUnsupportedMode = -2 ; + +extern TECObjectRef s_TECNativeCToUnicode ; + +// set to 0 if problems arise +#define wxMAC_EXPERIMENTAL_DC 1 + +wxMacPortSetter::wxMacPortSetter( const wxDC* dc ) : + m_ph( (GrafPtr) dc->m_macPort ) +{ + wxASSERT( dc->Ok() ) ; + m_dc = dc ; + dc->MacSetupPort(&m_ph) ; +} +wxMacPortSetter::~wxMacPortSetter() +{ + m_dc->MacCleanupPort(&m_ph) ; +} + +#if wxMAC_EXPERIMENTAL_DC +class wxMacFastPortSetter +{ +public : + wxMacFastPortSetter( const wxDC *dc ) + { + wxASSERT( dc->Ok() ) ; + GetPort( &m_oldPort ) ; + SetPort( (GrafPtr) dc->m_macPort ) ; + m_clipRgn = NewRgn() ; + GetClip( m_clipRgn ) ; + m_dc = dc ; + dc->MacSetupPort( NULL ) ; + } + ~wxMacFastPortSetter() + { + SetPort( (GrafPtr) m_dc->m_macPort ) ; + SetClip( m_clipRgn ) ; + SetPort( m_oldPort ) ; + m_dc->MacCleanupPort( NULL ) ; + DisposeRgn( m_clipRgn ) ; + } +private : + RgnHandle m_clipRgn ; + GrafPtr m_oldPort ; + const wxDC* m_dc ; +} ; + +#else +typedef wxMacPortSetter wxMacFastPortSetter ; +#endif + +#if 0 + +// start moving to a dual implementation for QD and CGContextRef + +class wxMacGraphicsContext +{ +public : + void DrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask ) = 0 ; + void SetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) = 0 ; + void SetClippingRegion( const wxRegion ®ion ) = 0 ; + void DestroyClippingRegion() = 0 ; + void SetTextForeground( const wxColour &col ) = 0 ; + void SetTextBackground( const wxColour &col ) = 0 ; + void SetLogicalScale( double x , double y ) = 0 ; + void SetUserScale( double x , double y ) = 0; +} ; + +class wxMacQuickDrawContext : public wxMacGraphicsContext +{ +public : +} ; + +#endif + +wxMacWindowClipper::wxMacWindowClipper( const wxWindow* win ) +{ + m_formerClip = NewRgn() ; + m_newClip = NewRgn() ; + GetClip( m_formerClip ) ; + + if ( win ) + { +#if 0 + // this clipping area was set to the parent window's drawing area, lead to problems + // with MacOSX controls drawing outside their wx' rectangle + RgnHandle insidergn = NewRgn() ; + int x = 0 , y = 0; + wxWindow *parent = win->GetParent() ; + parent->MacWindowToRootWindow( &x,&y ) ; + wxSize size = parent->GetSize() ; + SetRectRgn( insidergn , parent->MacGetLeftBorderSize() , parent->MacGetTopBorderSize() , + size.x - parent->MacGetRightBorderSize(), + size.y - parent->MacGetBottomBorderSize()) ; + CopyRgn( (RgnHandle) parent->MacGetVisibleRegion(false).GetWXHRGN() , m_newClip ) ; + SectRgn( m_newClip , insidergn , m_newClip ) ; + OffsetRgn( m_newClip , x , y ) ; + SetClip( m_newClip ) ; + DisposeRgn( insidergn ) ; +#else + int x = 0 , y = 0; + win->MacWindowToRootWindow( &x,&y ) ; + CopyRgn( (RgnHandle) ((wxWindow*)win)->MacGetVisibleRegion().GetWXHRGN() , m_newClip ) ; + OffsetRgn( m_newClip , x , y ) ; + SetClip( m_newClip ) ; +#endif + } +} + +wxMacWindowClipper::~wxMacWindowClipper() +{ + SetClip( m_formerClip ) ; + DisposeRgn( m_newClip ) ; + DisposeRgn( m_formerClip ) ; +} + +//----------------------------------------------------------------------------- +// Local functions +//----------------------------------------------------------------------------- +static inline double dmin(double a, double b) { return a < b ? a : b; } +static inline double dmax(double a, double b) { return a > b ? a : b; } +static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; } + +//----------------------------------------------------------------------------- +// wxDC +//----------------------------------------------------------------------------- +// this function emulates all wx colour manipulations, used to verify the implementation +// by setting the mode in the blitting functions to kEmulatedMode +void wxMacCalculateColour( int logical_func , const RGBColor &srcColor , RGBColor &dstColor ) ; + +void wxMacCalculateColour( int logical_func , const RGBColor &srcColor , RGBColor &dstColor ) +{ + switch ( logical_func ) + { + case wxAND: // src AND dst + dstColor.red = dstColor.red & srcColor.red ; + dstColor.green = dstColor.green & srcColor.green ; + dstColor.blue = dstColor.blue & srcColor.blue ; + break ; + case wxAND_INVERT: // (NOT src) AND dst + dstColor.red = dstColor.red & ~srcColor.red ; + dstColor.green = dstColor.green & ~srcColor.green ; + dstColor.blue = dstColor.blue & ~srcColor.blue ; + break ; + case wxAND_REVERSE:// src AND (NOT dst) + dstColor.red = ~dstColor.red & srcColor.red ; + dstColor.green = ~dstColor.green & srcColor.green ; + dstColor.blue = ~dstColor.blue & srcColor.blue ; + break ; + case wxCLEAR: // 0 + dstColor.red = 0 ; + dstColor.green = 0 ; + dstColor.blue = 0 ; + break ; + case wxCOPY: // src + dstColor.red = srcColor.red ; + dstColor.green = srcColor.green ; + dstColor.blue = srcColor.blue ; + break ; + case wxEQUIV: // (NOT src) XOR dst + dstColor.red = dstColor.red ^ ~srcColor.red ; + dstColor.green = dstColor.green ^ ~srcColor.green ; + dstColor.blue = dstColor.blue ^ ~srcColor.blue ; + break ; + case wxINVERT: // NOT dst + dstColor.red = ~dstColor.red ; + dstColor.green = ~dstColor.green ; + dstColor.blue = ~dstColor.blue ; + break ; + case wxNAND: // (NOT src) OR (NOT dst) + dstColor.red = ~dstColor.red | ~srcColor.red ; + dstColor.green = ~dstColor.green | ~srcColor.green ; + dstColor.blue = ~dstColor.blue | ~srcColor.blue ; + break ; + case wxNOR: // (NOT src) AND (NOT dst) + dstColor.red = ~dstColor.red & ~srcColor.red ; + dstColor.green = ~dstColor.green & ~srcColor.green ; + dstColor.blue = ~dstColor.blue & ~srcColor.blue ; + break ; + case wxNO_OP: // dst + break ; + case wxOR: // src OR dst + dstColor.red = dstColor.red | srcColor.red ; + dstColor.green = dstColor.green | srcColor.green ; + dstColor.blue = dstColor.blue | srcColor.blue ; + break ; + case wxOR_INVERT: // (NOT src) OR dst + dstColor.red = dstColor.red | ~srcColor.red ; + dstColor.green = dstColor.green | ~srcColor.green ; + dstColor.blue = dstColor.blue | ~srcColor.blue ; + break ; + case wxOR_REVERSE: // src OR (NOT dst) + dstColor.red = ~dstColor.red | srcColor.red ; + dstColor.green = ~dstColor.green | srcColor.green ; + dstColor.blue = ~dstColor.blue | srcColor.blue ; + break ; + case wxSET: // 1 + dstColor.red = 0xFFFF ; + dstColor.green = 0xFFFF ; + dstColor.blue = 0xFFFF ; + break ; + case wxSRC_INVERT: // (NOT src) + dstColor.red = ~srcColor.red ; + dstColor.green = ~srcColor.green ; + dstColor.blue = ~srcColor.blue ; + break ; + case wxXOR: // src XOR dst + dstColor.red = dstColor.red ^ srcColor.red ; + dstColor.green = dstColor.green ^ srcColor.green ; + dstColor.blue = dstColor.blue ^ srcColor.blue ; + break ; + } +} + +wxDC::wxDC() +{ + m_ok = FALSE; + m_colour = TRUE; + m_mm_to_pix_x = mm2pt; + m_mm_to_pix_y = mm2pt; + m_internalDeviceOriginX = 0; + m_internalDeviceOriginY = 0; + m_externalDeviceOriginX = 0; + m_externalDeviceOriginY = 0; + m_logicalScaleX = 1.0; + m_logicalScaleY = 1.0; + m_userScaleX = 1.0; + m_userScaleY = 1.0; + m_scaleX = 1.0; + m_scaleY = 1.0; + m_needComputeScaleX = FALSE; + m_needComputeScaleY = FALSE; + m_macPort = NULL ; + m_macMask = NULL ; + m_ok = FALSE ; + m_macFontInstalled = false ; + m_macBrushInstalled = false ; + m_macPenInstalled = false ; + m_macLocalOrigin.x = m_macLocalOrigin.y = 0 ; + m_macBoundaryClipRgn = NewRgn() ; + m_macCurrentClipRgn = NewRgn() ; + SetRectRgn( (RgnHandle) m_macBoundaryClipRgn , -32000 , -32000 , 32000 , 32000 ) ; + SetRectRgn( (RgnHandle) m_macCurrentClipRgn , -32000 , -32000 , 32000 , 32000 ) ; + m_pen = *wxBLACK_PEN; + m_font = *wxNORMAL_FONT; + m_brush = *wxWHITE_BRUSH; +#ifdef __WXDEBUG__ + // needed to debug possible errors with two active drawing methods at the same time on + // the same DC + m_macCurrentPortStateHelper = NULL ; +#endif + m_macATSUIStyle = NULL ; + m_macAliasWasEnabled = false; + m_macForegroundPixMap = NULL ; + m_macBackgroundPixMap = NULL ; +} + +wxDC::~wxDC(void) +{ + DisposeRgn( (RgnHandle) m_macBoundaryClipRgn ) ; + DisposeRgn( (RgnHandle) m_macCurrentClipRgn ) ; +} + +void wxDC::MacSetupPort(wxMacPortStateHelper* help) const +{ +#ifdef __WXDEBUG__ + wxASSERT( m_macCurrentPortStateHelper == NULL ) ; + m_macCurrentPortStateHelper = help ; +#endif + SetClip( (RgnHandle) m_macCurrentClipRgn); +#if ! wxMAC_EXPERIMENTAL_DC + m_macFontInstalled = false ; + m_macBrushInstalled = false ; + m_macPenInstalled = false ; +#endif +} +void wxDC::MacCleanupPort(wxMacPortStateHelper* help) const +{ +#ifdef __WXDEBUG__ + wxASSERT( m_macCurrentPortStateHelper == help ) ; + m_macCurrentPortStateHelper = NULL ; +#endif + if( m_macATSUIStyle ) + { + ::ATSUDisposeStyle((ATSUStyle)m_macATSUIStyle); + m_macATSUIStyle = NULL ; + } + if ( m_macAliasWasEnabled ) + { + SetAntiAliasedTextEnabled(m_macFormerAliasState, m_macFormerAliasSize); + m_macAliasWasEnabled = false ; + } + if ( m_macForegroundPixMap ) + { + Pattern blackColor ; + ::PenPat(GetQDGlobalsBlack(&blackColor)); + DisposePixPat( (PixPatHandle) m_macForegroundPixMap ) ; + m_macForegroundPixMap = NULL ; + } + if ( m_macBackgroundPixMap ) + { + Pattern whiteColor ; + ::BackPat(GetQDGlobalsWhite(&whiteColor)); + DisposePixPat( (PixPatHandle) m_macBackgroundPixMap ) ; + m_macBackgroundPixMap = NULL ; + } +} + +void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask ) +{ + wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( bmp.Ok(), wxT("invalid bitmap") ); + wxMacFastPortSetter helper(this) ; + wxCoord xx = XLOG2DEVMAC(x); + wxCoord yy = YLOG2DEVMAC(y); + wxCoord w = bmp.GetWidth(); + wxCoord h = bmp.GetHeight(); + wxCoord ww = XLOG2DEVREL(w); + wxCoord hh = YLOG2DEVREL(h); + // Set up drawing mode + short mode = (m_logicalFunction == wxCOPY ? srcCopy : + //m_logicalFunction == wxCLEAR ? WHITENESS : + //m_logicalFunction == wxSET ? BLACKNESS : + m_logicalFunction == wxINVERT ? hilite : + //m_logicalFunction == wxAND ? MERGECOPY : + m_logicalFunction == wxOR ? srcOr : + m_logicalFunction == wxSRC_INVERT ? notSrcCopy : + m_logicalFunction == wxXOR ? srcXor : + m_logicalFunction == wxOR_REVERSE ? notSrcOr : + //m_logicalFunction == wxAND_REVERSE ? SRCERASE : + //m_logicalFunction == wxSRC_OR ? srcOr : + //m_logicalFunction == wxSRC_AND ? SRCAND : + srcCopy ); + if ( bmp.GetBitmapType() == kMacBitmapTypePict ) { + Rect bitmaprect = { 0 , 0 , hh, ww }; + ::OffsetRect( &bitmaprect, xx, yy ) ; + ::DrawPicture( (PicHandle) bmp.GetPict(), &bitmaprect ) ; + } + else if ( bmp.GetBitmapType() == kMacBitmapTypeGrafWorld ) + { + GWorldPtr bmapworld = MAC_WXHBITMAP( bmp.GetHBITMAP() ); + PixMapHandle bmappixels ; + // Set foreground and background colours (for bitmaps depth = 1) + if(bmp.GetDepth() == 1) + { + RGBColor fore = MAC_WXCOLORREF(m_textForegroundColour.GetPixel()); + RGBColor back = MAC_WXCOLORREF(m_textBackgroundColour.GetPixel()); + RGBForeColor(&fore); + RGBBackColor(&back); + } + else + { + RGBColor white = { 0xFFFF, 0xFFFF,0xFFFF} ; + RGBColor black = { 0,0,0} ; + RGBForeColor( &black ) ; + RGBBackColor( &white ) ; + } + bmappixels = GetGWorldPixMap( bmapworld ) ; + wxCHECK_RET(LockPixels(bmappixels), + wxT("DoDrawBitmap: Unable to lock pixels")); + Rect source = { 0, 0, h, w }; + Rect dest = { yy, xx, yy + hh, xx + ww }; + if ( useMask && bmp.GetMask() ) + { + if( LockPixels(GetGWorldPixMap(MAC_WXHBITMAP(bmp.GetMask()->GetMaskBitmap())))) + { + CopyDeepMask + ( + GetPortBitMapForCopyBits(bmapworld), + GetPortBitMapForCopyBits(MAC_WXHBITMAP(bmp.GetMask()->GetMaskBitmap())), + GetPortBitMapForCopyBits( MAC_WXHBITMAP(m_macPort) ), + &source, &source, &dest, mode, NULL + ); + UnlockPixels(GetGWorldPixMap(MAC_WXHBITMAP(bmp.GetMask()->GetMaskBitmap()))); + } + } + else { + CopyBits( GetPortBitMapForCopyBits( bmapworld ), + GetPortBitMapForCopyBits( MAC_WXHBITMAP(m_macPort) ), + &source, &dest, mode, NULL ) ; + } + UnlockPixels( bmappixels ) ; + } + else if ( bmp.GetBitmapType() == kMacBitmapTypeIcon ) + { + Rect bitmaprect = { 0 , 0 , bmp.GetHeight(), bmp.GetWidth() } ; + OffsetRect( &bitmaprect, xx, yy ) ; + PlotCIconHandle( &bitmaprect , atNone , ttNone , MAC_WXHICON(bmp.GetHICON()) ) ; + } + m_macPenInstalled = false ; + m_macBrushInstalled = false ; + m_macFontInstalled = false ; +} + +void wxDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y ) +{ + wxCHECK_RET(Ok(), wxT("Invalid dc wxDC::DoDrawIcon")); + wxCHECK_RET(icon.Ok(), wxT("Invalid icon wxDC::DoDrawIcon")); + DoDrawBitmap( icon , x , y , icon.GetMask() != NULL ) ; +} + +void wxDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) +{ + wxCHECK_RET(Ok(), wxT("wxDC::DoSetClippingRegion Invalid DC")); + wxCoord xx, yy, ww, hh; + xx = XLOG2DEVMAC(x); + yy = YLOG2DEVMAC(y); + ww = XLOG2DEVREL(width); + hh = YLOG2DEVREL(height); + SetRectRgn( (RgnHandle) m_macCurrentClipRgn , xx , yy , xx + ww , yy + hh ) ; + SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ; + if( m_clipping ) + { + m_clipX1 = wxMax( m_clipX1 , xx ); + m_clipY1 = wxMax( m_clipY1 , yy ); + m_clipX2 = wxMin( m_clipX2, (xx + ww)); + m_clipY2 = wxMin( m_clipY2, (yy + hh)); + } + else + { + m_clipping = TRUE; + m_clipX1 = xx; + m_clipY1 = yy; + m_clipX2 = xx + ww; + m_clipY2 = yy + hh; + } +} + +void wxDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) +{ + wxCHECK_RET( Ok(), wxT("invalid window dc") ) ; + if (region.Empty()) + { + DestroyClippingRegion(); + return; + } + wxMacFastPortSetter helper(this) ; + wxCoord x, y, w, h; + region.GetBox( x, y, w, h ); + wxCoord xx, yy, ww, hh; + xx = XLOG2DEVMAC(x); + yy = YLOG2DEVMAC(y); + ww = XLOG2DEVREL(w); + hh = YLOG2DEVREL(h); + // if we have a scaling that we cannot map onto native regions + // we must use the box + if ( ww != w || hh != h ) + { + wxDC::DoSetClippingRegion( x, y, w, h ); + } + else + { + CopyRgn( (RgnHandle) region.GetWXHRGN() , (RgnHandle) m_macCurrentClipRgn ) ; + if ( xx != x || yy != y ) + { + OffsetRgn( (RgnHandle) m_macCurrentClipRgn , xx - x , yy - y ) ; + } + SectRgn( (RgnHandle) m_macCurrentClipRgn , (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ; + if( m_clipping ) + { + m_clipX1 = wxMax( m_clipX1 , xx ); + m_clipY1 = wxMax( m_clipY1 , yy ); + m_clipX2 = wxMin( m_clipX2, (xx + ww)); + m_clipY2 = wxMin( m_clipY2, (yy + hh)); + } + else + { + m_clipping = TRUE; + m_clipX1 = xx; + m_clipY1 = yy; + m_clipX2 = xx + ww; + m_clipY2 = yy + hh; + } + } +} + +void wxDC::DestroyClippingRegion() +{ + wxMacFastPortSetter helper(this) ; + CopyRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ; + m_clipping = FALSE; +} + +void wxDC::DoGetSizeMM( int* width, int* height ) const +{ + int w = 0; + int h = 0; + GetSize( &w, &h ); + *width = long( double(w) / (m_scaleX*m_mm_to_pix_x) ); + *height = long( double(h) / (m_scaleY*m_mm_to_pix_y) ); +} + +void wxDC::SetTextForeground( const wxColour &col ) +{ + wxCHECK_RET(Ok(), wxT("Invalid DC")); + m_textForegroundColour = col; + m_macFontInstalled = false ; +} + +void wxDC::SetTextBackground( const wxColour &col ) +{ + wxCHECK_RET(Ok(), wxT("Invalid DC")); + m_textBackgroundColour = col; + m_macFontInstalled = false ; +} + +void wxDC::SetMapMode( int mode ) +{ + switch (mode) + { + case wxMM_TWIPS: + SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y ); + break; + case wxMM_POINTS: + SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y ); + break; + case wxMM_METRIC: + SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y ); + break; + case wxMM_LOMETRIC: + SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 ); + break; + default: + case wxMM_TEXT: + SetLogicalScale( 1.0, 1.0 ); + break; + } + if (mode != wxMM_TEXT) + { + m_needComputeScaleX = TRUE; + m_needComputeScaleY = TRUE; + } +} + +void wxDC::SetUserScale( double x, double y ) +{ + // allow negative ? -> no + m_userScaleX = x; + m_userScaleY = y; + ComputeScaleAndOrigin(); +} + +void wxDC::SetLogicalScale( double x, double y ) +{ + // allow negative ? + m_logicalScaleX = x; + m_logicalScaleY = y; + ComputeScaleAndOrigin(); +} + +void wxDC::SetLogicalOrigin( wxCoord x, wxCoord y ) +{ + m_logicalOriginX = x * m_signX; // is this still correct ? + m_logicalOriginY = y * m_signY; + ComputeScaleAndOrigin(); +} + +void wxDC::SetDeviceOrigin( wxCoord x, wxCoord y ) +{ + m_externalDeviceOriginX = x; + m_externalDeviceOriginY = y; + ComputeScaleAndOrigin(); +} + +#if 0 +void wxDC::SetInternalDeviceOrigin( long x, long y ) +{ + m_internalDeviceOriginX = x; + m_internalDeviceOriginY = y; + ComputeScaleAndOrigin(); +} +void wxDC::GetInternalDeviceOrigin( long *x, long *y ) +{ + if (x) *x = m_internalDeviceOriginX; + if (y) *y = m_internalDeviceOriginY; +} +#endif + +void wxDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp ) +{ + m_signX = (xLeftRight ? 1 : -1); + m_signY = (yBottomUp ? -1 : 1); + ComputeScaleAndOrigin(); +} + +wxSize wxDC::GetPPI() const +{ + return wxSize(72, 72); +} + +int wxDC::GetDepth() const +{ + if ( IsPortColor( (CGrafPtr) m_macPort ) ) + { + return ( (**GetPortPixMap( (CGrafPtr) m_macPort)).pixelSize ) ; + } + return 1 ; +} + +void wxDC::ComputeScaleAndOrigin() +{ + // CMB: copy scale to see if it changes + double origScaleX = m_scaleX; + double origScaleY = m_scaleY; + m_scaleX = m_logicalScaleX * m_userScaleX; + m_scaleY = m_logicalScaleY * m_userScaleY; + m_deviceOriginX = m_internalDeviceOriginX + m_externalDeviceOriginX; + m_deviceOriginY = m_internalDeviceOriginY + m_externalDeviceOriginY; + // CMB: if scale has changed call SetPen to recalulate the line width + if (m_scaleX != origScaleX || m_scaleY != origScaleY) + { + // this is a bit artificial, but we need to force wxDC to think + // the pen has changed + wxPen* pen = & GetPen(); + wxPen tempPen; + m_pen = tempPen; + SetPen(* pen); + } +} + +void wxDC::SetPalette( const wxPalette& palette ) +{ +} + +void wxDC::SetBackgroundMode( int mode ) +{ + m_backgroundMode = mode ; +} + +void wxDC::SetFont( const wxFont &font ) +{ + m_font = font; + m_macFontInstalled = false ; +} + +void wxDC::SetPen( const wxPen &pen ) +{ + if ( m_pen == pen ) + return ; + m_pen = pen; + m_macPenInstalled = false ; +} + +void wxDC::SetBrush( const wxBrush &brush ) +{ + if (m_brush == brush) + return; + m_brush = brush; + m_macBrushInstalled = false ; +} + +void wxDC::SetBackground( const wxBrush &brush ) +{ + if (m_backgroundBrush == brush) + return; + m_backgroundBrush = brush; + if (!m_backgroundBrush.Ok()) + return; + m_macBrushInstalled = false ; +} + +void wxDC::SetLogicalFunction( int function ) +{ + if (m_logicalFunction == function) + return; + m_logicalFunction = function ; + m_macFontInstalled = false ; + m_macBrushInstalled = false ; + m_macPenInstalled = false ; +} + +extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y, + const wxColour & col, int style); + +bool wxDC::DoFloodFill(wxCoord x, wxCoord y, + const wxColour& col, int style) +{ + return wxDoFloodFill(this, x, y, col, style); +} + +bool wxDC::DoGetPixel( wxCoord x, wxCoord y, wxColour *col ) const +{ + wxCHECK_MSG( Ok(), false, wxT("wxDC::DoGetPixel Invalid DC") ); + wxMacFastPortSetter helper(this) ; + RGBColor colour; + GetCPixel( XLOG2DEVMAC(x), YLOG2DEVMAC(y), &colour ); + // Convert from Mac colour to wx + col->Set( colour.red >> 8, + colour.green >> 8, + colour.blue >> 8); + return true ; +} + +void wxDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 ) +{ + wxCHECK_RET(Ok(), wxT("Invalid DC")); + wxMacFastPortSetter helper(this) ; + if (m_pen.GetStyle() != wxTRANSPARENT) + { + MacInstallPen() ; + wxCoord offset = ( (m_pen.GetWidth() == 0 ? 1 : + m_pen.GetWidth() ) * (wxCoord)m_scaleX - 1) / 2; + wxCoord xx1 = XLOG2DEVMAC(x1) - offset; + wxCoord yy1 = YLOG2DEVMAC(y1) - offset; + wxCoord xx2 = XLOG2DEVMAC(x2) - offset; + wxCoord yy2 = YLOG2DEVMAC(y2) - offset; + if ((m_pen.GetCap() == wxCAP_ROUND) && + (m_pen.GetWidth() <= 1)) + { + // Implement LAST_NOT for MAC at least for + // orthogonal lines. RR. + if (xx1 == xx2) + { + if (yy1 < yy2) + yy2--; + if (yy1 > yy2) + yy2++; + } + if (yy1 == yy2) + { + if (xx1 < xx2) + xx2--; + if (xx1 > xx2) + xx2++; + } + } + ::MoveTo(xx1, yy1); + ::LineTo(xx2, yy2); + } +} + +void wxDC::DoCrossHair( wxCoord x, wxCoord y ) +{ + wxCHECK_RET( Ok(), wxT("wxDC::DoCrossHair Invalid window dc") ); + wxMacFastPortSetter helper(this) ; + if (m_pen.GetStyle() != wxTRANSPARENT) + { + int w = 0; + int h = 0; + GetSize( &w, &h ); + wxCoord xx = XLOG2DEVMAC(x); + wxCoord yy = YLOG2DEVMAC(y); + MacInstallPen(); + ::MoveTo( XLOG2DEVMAC(0), yy ); + ::LineTo( XLOG2DEVMAC(w), yy ); + ::MoveTo( xx, YLOG2DEVMAC(0) ); + ::LineTo( xx, YLOG2DEVMAC(h) ); + CalcBoundingBox(x, y); + CalcBoundingBox(x+w, y+h); + } +} + +/* +* To draw arcs properly the angles need to be converted from the WX style: +* Angles start on the +ve X axis and go anti-clockwise (As you would draw on +* a normal axis on paper). +* TO +* the Mac style: +* Angles start on the +ve y axis and go clockwise. +*/ + +static double wxConvertWXangleToMACangle(double angle) +{ + double newAngle = 90 - angle ; + if ( newAngle < 0 ) + newAngle += 360 ; + return newAngle ; +} + +void wxDC::DoDrawArc( wxCoord x1, wxCoord y1, + wxCoord x2, wxCoord y2, + wxCoord xc, wxCoord yc ) +{ + wxCHECK_RET(Ok(), wxT("wxDC::DoDrawArc Invalid DC")); + wxMacFastPortSetter helper(this) ; + wxCoord xx1 = XLOG2DEVMAC(x1); + wxCoord yy1 = YLOG2DEVMAC(y1); + wxCoord xx2 = XLOG2DEVMAC(x2); + wxCoord yy2 = YLOG2DEVMAC(y2); + wxCoord xxc = XLOG2DEVMAC(xc); + wxCoord yyc = YLOG2DEVMAC(yc); + double dx = xx1 - xxc; + double dy = yy1 - yyc; + double radius = sqrt((double)(dx*dx+dy*dy)); + wxCoord rad = (wxCoord)radius; + double radius1, radius2; + if (xx1 == xx2 && yy1 == yy2) + { + radius1 = 0.0; + radius2 = 360.0; + } + else if (radius == 0.0) + { + radius1 = radius2 = 0.0; + } + else + { + radius1 = (xx1 - xxc == 0) ? + (yy1 - yyc < 0) ? 90.0 : -90.0 : + -atan2(double(yy1-yyc), double(xx1-xxc)) * RAD2DEG; + radius2 = (xx2 - xxc == 0) ? + (yy2 - yyc < 0) ? 90.0 : -90.0 : + -atan2(double(yy2-yyc), double(xx2-xxc)) * RAD2DEG; + } + wxCoord alpha2 = wxCoord(radius2 - radius1); + wxCoord alpha1 = wxCoord(wxConvertWXangleToMACangle(radius1)); + if( (xx1 > xx2) || (yy1 > yy2) ) { + alpha2 *= -1; + } + Rect r = { yyc - rad, xxc - rad, yyc + rad, xxc + rad }; + if(m_brush.GetStyle() != wxTRANSPARENT) { + MacInstallBrush(); + PaintArc(&r, alpha1, alpha2); + } + if(m_pen.GetStyle() != wxTRANSPARENT) { + MacInstallPen(); + FrameArc(&r, alpha1, alpha2); + } +} + +void wxDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord w, wxCoord h, + double sa, double ea ) +{ + wxCHECK_RET(Ok(), wxT("wxDC::DoDrawEllepticArc Invalid DC")); + wxMacFastPortSetter helper(this) ; + Rect r; + double angle = sa - ea; // Order important Mac in opposite direction to wx + // we have to make sure that the filling is always counter-clockwise + if ( angle > 0 ) + angle -= 360 ; + wxCoord xx = XLOG2DEVMAC(x); + wxCoord yy = YLOG2DEVMAC(y); + wxCoord ww = m_signX * XLOG2DEVREL(w); + wxCoord hh = m_signY * YLOG2DEVREL(h); + // handle -ve width and/or height + if (ww < 0) { ww = -ww; xx = xx - ww; } + if (hh < 0) { hh = -hh; yy = yy - hh; } + sa = wxConvertWXangleToMACangle(sa); + r.top = yy; + r.left = xx; + r.bottom = yy + hh; + r.right = xx + ww; + if(m_brush.GetStyle() != wxTRANSPARENT) { + MacInstallBrush(); + PaintArc(&r, (short)sa, (short)angle); + } + if(m_pen.GetStyle() != wxTRANSPARENT) { + MacInstallPen(); + FrameArc(&r, (short)sa, (short)angle); + } +} + +void wxDC::DoDrawPoint( wxCoord x, wxCoord y ) +{ + wxCHECK_RET(Ok(), wxT("Invalid DC")); + wxMacFastPortSetter helper(this) ; + if (m_pen.GetStyle() != wxTRANSPARENT) + { + wxCoord xx1 = XLOG2DEVMAC(x); + wxCoord yy1 = YLOG2DEVMAC(y); + RGBColor pencolor = MAC_WXCOLORREF( m_pen.GetColour().GetPixel()); + ::SetCPixel( xx1,yy1,&pencolor) ; + CalcBoundingBox(x, y); + } +} + +void wxDC::DoDrawLines(int n, wxPoint points[], + wxCoord xoffset, wxCoord yoffset) +{ + wxCHECK_RET(Ok(), wxT("Invalid DC")); + wxMacFastPortSetter helper(this) ; + if (m_pen.GetStyle() == wxTRANSPARENT) + return; + MacInstallPen() ; + wxCoord offset = ( (m_pen.GetWidth() == 0 ? 1 : + m_pen.GetWidth() ) * (wxCoord)m_scaleX - 1) / 2 ; + wxCoord x1, x2 , y1 , y2 ; + x1 = XLOG2DEVMAC(points[0].x + xoffset); + y1 = YLOG2DEVMAC(points[0].y + yoffset); + ::MoveTo(x1 - offset, y1 - offset ); + for (int i = 0; i < n-1; i++) + { + x2 = XLOG2DEVMAC(points[i+1].x + xoffset); + y2 = YLOG2DEVMAC(points[i+1].y + yoffset); + ::LineTo( x2 - offset, y2 - offset ); + } +} + +void wxDC::DoDrawPolygon(int n, wxPoint points[], + wxCoord xoffset, wxCoord yoffset, + int fillStyle ) +{ + wxCHECK_RET(Ok(), wxT("Invalid DC")); + wxMacFastPortSetter helper(this) ; + wxCoord x1, x2 , y1 , y2 ; + if ( m_brush.GetStyle() == wxTRANSPARENT && m_pen.GetStyle() == wxTRANSPARENT ) + return ; + PolyHandle polygon = OpenPoly(); + x2 = x1 = XLOG2DEVMAC(points[0].x + xoffset); + y2 = y1 = YLOG2DEVMAC(points[0].y + yoffset); + ::MoveTo(x1,y1); + for (int i = 1; i < n; i++) + { + x2 = XLOG2DEVMAC(points[i].x + xoffset); + y2 = YLOG2DEVMAC(points[i].y + yoffset); + ::LineTo(x2, y2); + } + // close the polyline if necessary + if ( x1 != x2 || y1 != y2 ) + { + ::LineTo(x1,y1 ) ; + } + ClosePoly(); + if (m_brush.GetStyle() != wxTRANSPARENT) + { + MacInstallBrush(); + ::PaintPoly( polygon ); + } + if (m_pen.GetStyle() != wxTRANSPARENT) + { + MacInstallPen() ; + ::FramePoly( polygon ) ; + } + KillPoly( polygon ); +} + +void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height) +{ + wxCHECK_RET(Ok(), wxT("Invalid DC")); + wxMacFastPortSetter helper(this) ; + wxCoord xx = XLOG2DEVMAC(x); + wxCoord yy = YLOG2DEVMAC(y); + wxCoord ww = m_signX * XLOG2DEVREL(width); + wxCoord hh = m_signY * YLOG2DEVREL(height); + // CMB: draw nothing if transformed w or h is 0 + if (ww == 0 || hh == 0) + return; + // CMB: handle -ve width and/or height + if (ww < 0) + { + ww = -ww; + xx = xx - ww; + } + if (hh < 0) + { + hh = -hh; + yy = yy - hh; + } + Rect rect = { yy , xx , yy + hh , xx + ww } ; + if (m_brush.GetStyle() != wxTRANSPARENT) + { + MacInstallBrush() ; + ::PaintRect( &rect ) ; + } + if (m_pen.GetStyle() != wxTRANSPARENT) + { + MacInstallPen() ; + ::FrameRect( &rect ) ; + } +} + +void wxDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y, + wxCoord width, wxCoord height, + double radius) +{ + wxCHECK_RET(Ok(), wxT("Invalid DC")); + wxMacFastPortSetter helper(this) ; + if (radius < 0.0) + radius = - radius * ((width < height) ? width : height); + wxCoord xx = XLOG2DEVMAC(x); + wxCoord yy = YLOG2DEVMAC(y); + wxCoord ww = m_signX * XLOG2DEVREL(width); + wxCoord hh = m_signY * YLOG2DEVREL(height); + // CMB: draw nothing if transformed w or h is 0 + if (ww == 0 || hh == 0) + return; + // CMB: handle -ve width and/or height + if (ww < 0) + { + ww = -ww; + xx = xx - ww; + } + if (hh < 0) + { + hh = -hh; + yy = yy - hh; + } + Rect rect = { yy , xx , yy + hh , xx + ww } ; + if (m_brush.GetStyle() != wxTRANSPARENT) + { + MacInstallBrush() ; + ::PaintRoundRect( &rect , int(radius * 2) , int(radius * 2) ) ; + } + if (m_pen.GetStyle() != wxTRANSPARENT) + { + MacInstallPen() ; + ::FrameRoundRect( &rect , int(radius * 2) , int(radius * 2) ) ; + } +} + +void wxDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height) +{ + wxCHECK_RET(Ok(), wxT("Invalid DC")); + wxMacFastPortSetter helper(this) ; + wxCoord xx = XLOG2DEVMAC(x); + wxCoord yy = YLOG2DEVMAC(y); + wxCoord ww = m_signX * XLOG2DEVREL(width); + wxCoord hh = m_signY * YLOG2DEVREL(height); + // CMB: draw nothing if transformed w or h is 0 + if (ww == 0 || hh == 0) + return; + // CMB: handle -ve width and/or height + if (ww < 0) + { + ww = -ww; + xx = xx - ww; + } + if (hh < 0) + { + hh = -hh; + yy = yy - hh; + } + Rect rect = { yy , xx , yy + hh , xx + ww } ; + if (m_brush.GetStyle() != wxTRANSPARENT) + { + MacInstallBrush() ; + ::PaintOval( &rect ) ; + } + if (m_pen.GetStyle() != wxTRANSPARENT) + { + MacInstallPen() ; + ::FrameOval( &rect ) ; + } +} + +bool wxDC::CanDrawBitmap(void) const +{ + return true ; +} + +bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height, + wxDC *source, wxCoord xsrc, wxCoord ysrc, int logical_func , bool useMask, + wxCoord xsrcMask, wxCoord ysrcMask ) +{ + wxCHECK_MSG(Ok(), false, wxT("wxDC::DoBlit Illegal dc")); + wxCHECK_MSG(source->Ok(), false, wxT("wxDC::DoBlit Illegal source DC")); + if ( logical_func == wxNO_OP ) + return TRUE ; + if (xsrcMask == -1 && ysrcMask == -1) + { + xsrcMask = xsrc; ysrcMask = ysrc; + } + // correct the parameter in case this dc does not have a mask at all + if ( useMask && !source->m_macMask ) + useMask = false ; + Rect srcrect , dstrect ; + srcrect.top = source->YLOG2DEVMAC(ysrc) ; + srcrect.left = source->XLOG2DEVMAC(xsrc) ; + srcrect.right = source->XLOG2DEVMAC(xsrc + width ) ; + srcrect.bottom = source->YLOG2DEVMAC(ysrc + height) ; + dstrect.top = YLOG2DEVMAC(ydest) ; + dstrect.left = XLOG2DEVMAC(xdest) ; + dstrect.bottom = YLOG2DEVMAC(ydest + height ) ; + dstrect.right = XLOG2DEVMAC(xdest + width ) ; + short mode = kUnsupportedMode ; + bool invertDestinationFirst = false ; + switch ( logical_func ) + { + case wxAND: // src AND dst + mode = adMin ; // ok + break ; + case wxAND_INVERT: // (NOT src) AND dst + mode = notSrcOr ; // ok + break ; + case wxAND_REVERSE:// src AND (NOT dst) + invertDestinationFirst = true ; + mode = srcOr ; + break ; + case wxCLEAR: // 0 + mode = kEmulatedMode ; + break ; + case wxCOPY: // src + mode = srcCopy ; // ok + break ; + case wxEQUIV: // (NOT src) XOR dst + mode = srcXor ; // ok + break ; + case wxINVERT: // NOT dst + mode = kEmulatedMode ; //or hilite ; + break ; + case wxNAND: // (NOT src) OR (NOT dst) + invertDestinationFirst = true ; + mode = srcBic ; + break ; + case wxNOR: // (NOT src) AND (NOT dst) + invertDestinationFirst = true ; + mode = notSrcOr ; + break ; + case wxNO_OP: // dst + mode = kEmulatedMode ; // this has already been handled upon entry + break ; + case wxOR: // src OR dst + mode = notSrcBic ; + break ; + case wxOR_INVERT: // (NOT src) OR dst + mode = srcBic ; + break ; + case wxOR_REVERSE: // src OR (NOT dst) + invertDestinationFirst = true ; + mode = notSrcBic ; + break ; + case wxSET: // 1 + mode = kEmulatedMode ; + break ; + case wxSRC_INVERT: // (NOT src) + mode = notSrcCopy ; // ok + break ; + case wxXOR: // src XOR dst + mode = notSrcXor ; // ok + break ; + default : + break ; + } + if ( mode == kUnsupportedMode ) + { + wxFAIL_MSG(wxT("unsupported blitting mode" )); + return FALSE ; + } + CGrafPtr sourcePort = (CGrafPtr) source->m_macPort ; + PixMapHandle bmappixels = GetGWorldPixMap( sourcePort ) ; + if ( LockPixels(bmappixels) ) + { + wxMacFastPortSetter helper(this) ; + if ( source->GetDepth() == 1 ) + { + RGBForeColor( &MAC_WXCOLORREF(m_textForegroundColour.GetPixel()) ) ; + RGBBackColor( &MAC_WXCOLORREF(m_textBackgroundColour.GetPixel()) ) ; + } + else + { + // the modes need this, otherwise we'll end up having really nice colors... + RGBColor white = { 0xFFFF, 0xFFFF,0xFFFF} ; + RGBColor black = { 0,0,0} ; + RGBForeColor( &black ) ; + RGBBackColor( &white ) ; + } + if ( useMask && source->m_macMask ) + { + if ( mode == srcCopy ) + { + if ( LockPixels( GetGWorldPixMap( MAC_WXHBITMAP(source->m_macMask) ) ) ) + { + CopyMask( GetPortBitMapForCopyBits( sourcePort ) , + GetPortBitMapForCopyBits( MAC_WXHBITMAP(source->m_macMask) ) , + GetPortBitMapForCopyBits( MAC_WXHBITMAP(m_macPort) ) , + &srcrect, &srcrect , &dstrect ) ; + UnlockPixels( GetGWorldPixMap( MAC_WXHBITMAP(source->m_macMask) ) ) ; + } + } + else + { + RgnHandle clipRgn = NewRgn() ; + LockPixels( GetGWorldPixMap( MAC_WXHBITMAP(source->m_macMask) ) ) ; + BitMapToRegion( clipRgn , (BitMap*) *GetGWorldPixMap( MAC_WXHBITMAP(source->m_macMask) ) ) ; + UnlockPixels( GetGWorldPixMap( MAC_WXHBITMAP(source->m_macMask) ) ) ; + OffsetRgn( clipRgn , -srcrect.left + dstrect.left, -srcrect.top + dstrect.top ) ; + if ( mode == kEmulatedMode ) + { + Pattern pat ; + ::PenPat(GetQDGlobalsBlack(&pat)); + if ( logical_func == wxSET ) + { + RGBColor col= { 0xFFFF, 0xFFFF, 0xFFFF } ; + ::RGBForeColor( &col ) ; + ::PaintRgn( clipRgn ) ; + } + else if ( logical_func == wxCLEAR ) + { + RGBColor col= { 0x0000, 0x0000, 0x0000 } ; + ::RGBForeColor( &col ) ; + ::PaintRgn( clipRgn ) ; + } + else if ( logical_func == wxINVERT ) + { + MacInvertRgn( clipRgn ) ; + } + else + { + for ( int y = 0 ; y < srcrect.right - srcrect.left ; ++y ) + { + for ( int x = 0 ; x < srcrect.bottom - srcrect.top ; ++x ) + { + Point dstPoint = { dstrect.top + y , dstrect.left + x } ; + Point srcPoint = { srcrect.top + y , srcrect.left + x } ; + if ( PtInRgn( dstPoint , clipRgn ) ) + { + RGBColor srcColor ; + RGBColor dstColor ; + SetPort( (GrafPtr) sourcePort ) ; + GetCPixel( srcPoint.h , srcPoint.v , &srcColor) ; + SetPort( (GrafPtr) m_macPort ) ; + GetCPixel( dstPoint.h , dstPoint.v , &dstColor ) ; + wxMacCalculateColour( logical_func , srcColor , dstColor ) ; + SetCPixel( dstPoint.h , dstPoint.v , &dstColor ) ; + } + } + } + } + } + else + { + if ( invertDestinationFirst ) + { + MacInvertRgn( clipRgn ) ; + } + CopyBits( GetPortBitMapForCopyBits( sourcePort ) , + GetPortBitMapForCopyBits( MAC_WXHBITMAP(m_macPort) ) , + &srcrect, &dstrect, mode, clipRgn ) ; + } + DisposeRgn( clipRgn ) ; + } + } + else + { + RgnHandle clipRgn = NewRgn() ; + SetRectRgn( clipRgn , dstrect.left , dstrect.top , dstrect.right , dstrect.bottom ) ; + if ( mode == kEmulatedMode ) + { + Pattern pat ; + ::PenPat(GetQDGlobalsBlack(&pat)); + if ( logical_func == wxSET ) + { + RGBColor col= { 0xFFFF, 0xFFFF, 0xFFFF } ; + ::RGBForeColor( &col ) ; + ::PaintRgn( clipRgn ) ; + } + else if ( logical_func == wxCLEAR ) + { + RGBColor col= { 0x0000, 0x0000, 0x0000 } ; + ::RGBForeColor( &col ) ; + ::PaintRgn( clipRgn ) ; + } + else if ( logical_func == wxINVERT ) + { + MacInvertRgn( clipRgn ) ; + } + else + { + for ( int y = 0 ; y < srcrect.right - srcrect.left ; ++y ) + { + for ( int x = 0 ; x < srcrect.bottom - srcrect.top ; ++x ) + { + Point dstPoint = { dstrect.top + y , dstrect.left + x } ; + Point srcPoint = { srcrect.top + y , srcrect.left + x } ; + { + RGBColor srcColor ; + RGBColor dstColor ; + SetPort( (GrafPtr) sourcePort ) ; + GetCPixel( srcPoint.h , srcPoint.v , &srcColor) ; + SetPort( (GrafPtr) m_macPort ) ; + GetCPixel( dstPoint.h , dstPoint.v , &dstColor ) ; + wxMacCalculateColour( logical_func , srcColor , dstColor ) ; + SetCPixel( dstPoint.h , dstPoint.v , &dstColor ) ; + } + } + } + } + } + else + { + if ( invertDestinationFirst ) + { + MacInvertRgn( clipRgn ) ; + } + CopyBits( GetPortBitMapForCopyBits( sourcePort ) , + GetPortBitMapForCopyBits( MAC_WXHBITMAP(m_macPort) ) , + &srcrect, &dstrect, mode, NULL ) ; + } + DisposeRgn( clipRgn ) ; + } + UnlockPixels( bmappixels ) ; + } + m_macPenInstalled = false ; + m_macBrushInstalled = false ; + m_macFontInstalled = false ; + return TRUE; +} + +#ifndef FixedToInt +// as macro in FixMath.h for 10.3 +inline Fixed IntToFixed( int inInt ) +{ + return (((SInt32) inInt) << 16); +} + +inline int FixedToInt( Fixed inFixed ) +{ + return (((SInt32) inFixed) >> 16); +} +#endif + +void wxDC::DoDrawRotatedText(const wxString& str, wxCoord x, wxCoord y, + double angle) +{ + wxCHECK_RET( Ok(), wxT("wxDC::DoDrawRotatedText Invalid window dc") ); + + if (angle == 0.0 ) + { + DrawText(str, x, y); + return; + } + + if ( str.Length() == 0 ) + return ; + + wxMacFastPortSetter helper(this) ; + MacInstallFont() ; + + if ( 0 ) + { + m_macFormerAliasState = IsAntiAliasedTextEnabled(&m_macFormerAliasSize); + SetAntiAliasedTextEnabled(true, SInt16(m_scaleY * m_font.GetMacFontSize())); + m_macAliasWasEnabled = true ; + } + OSStatus status = noErr ; + ATSUTextLayout atsuLayout ; + UniCharCount chars = str.Length() ; +#if wxUSE_UNICODE + status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) (const wxChar*) str , 0 , str.Length() , str.Length() , 1 , + &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ; +#else + wxWCharBuffer wchar = str.wc_str( wxConvLocal ) ; + int wlen = wxWcslen( wchar.data() ) ; + status = ::ATSUCreateTextLayoutWithTextPtr( (UniCharArrayPtr) wchar.data() , 0 , wlen , wlen , 1 , + &chars , (ATSUStyle*) &m_macATSUIStyle , &atsuLayout ) ; +#endif + wxASSERT_MSG( status == noErr , wxT("couldn't create the layout of the rotated text") ); + int iAngle = int( angle ); + int drawX = XLOG2DEVMAC(x) ; + int drawY = YLOG2DEVMAC(y) ; + + ATSUTextMeasurement textBefore ; + ATSUTextMeasurement textAfter ; + ATSUTextMeasurement ascent ; + ATSUTextMeasurement descent ; + + + if ( abs(iAngle) > 0 ) + { + Fixed atsuAngle = IntToFixed( iAngle ) ; + ATSUAttributeTag atsuTags[] = + { + kATSULineRotationTag , + } ; + ByteCount atsuSizes[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] = + { + sizeof( Fixed ) , + } ; + ATSUAttributeValuePtr atsuValues[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] = + { + &atsuAngle , + } ; + status = ::ATSUSetLayoutControls(atsuLayout , sizeof(atsuTags)/sizeof(ATSUAttributeTag), + atsuTags, atsuSizes, atsuValues ) ; + } + status = ::ATSUMeasureText( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd, + &textBefore , &textAfter, &ascent , &descent ); + + drawX += (int)(sin(angle/RAD2DEG) * FixedToInt(ascent)); + drawY += (int)(cos(angle/RAD2DEG) * FixedToInt(ascent)); + status = ::ATSUDrawText( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd, + IntToFixed(drawX) , IntToFixed(drawY) ); + wxASSERT_MSG( status == noErr , wxT("couldn't draw the rotated text") ); + Rect rect ; + status = ::ATSUMeasureTextImage( atsuLayout, kATSUFromTextBeginning, kATSUToTextEnd, + IntToFixed(drawX) , IntToFixed(drawY) , &rect ); + wxASSERT_MSG( status == noErr , wxT("couldn't measure the rotated text") ); + OffsetRect( &rect , -m_macLocalOrigin.x , -m_macLocalOrigin.y ) ; + CalcBoundingBox(XDEV2LOG(rect.left), YDEV2LOG(rect.top) ); + CalcBoundingBox(XDEV2LOG(rect.right), YDEV2LOG(rect.bottom) ); + ::ATSUDisposeTextLayout(atsuLayout); +} + +void wxDC::DoDrawText(const wxString& strtext, wxCoord x, wxCoord y) +{ + wxCHECK_RET(Ok(), wxT("wxDC::DoDrawText Invalid DC")); + + wxMacFastPortSetter helper(this) ; + long xx = XLOG2DEVMAC(x); + long yy = YLOG2DEVMAC(y); +#if TARGET_CARBON + bool useDrawThemeText = ( DrawThemeTextBox != (void*) kUnresolvedCFragSymbolAddress ) ; + if ( UMAGetSystemVersion() < 0x1000 || IsKindOf(CLASSINFO( wxPrinterDC ) ) || m_font.GetNoAntiAliasing() ) + useDrawThemeText = false ; +#endif + MacInstallFont() ; + if ( 0 ) + { + m_macFormerAliasState = IsAntiAliasedTextEnabled(&m_macFormerAliasSize); + SetAntiAliasedTextEnabled(true, 8); + m_macAliasWasEnabled = true ; + } + FontInfo fi ; + ::GetFontInfo( &fi ) ; +#if TARGET_CARBON + if ( !useDrawThemeText ) +#endif + yy += fi.ascent ; + ::MoveTo( xx , yy ); + if ( m_backgroundMode == wxTRANSPARENT ) + { + ::TextMode( srcOr) ; + } + else + { + ::TextMode( srcCopy ) ; + } + int length = strtext.Length() ; + + int laststop = 0 ; + int i = 0 ; + int line = 0 ; + { +#if 0 // we don't have to do all that here + while( i < length ) + { + if( strtext[i] == 13 || strtext[i] == 10) + { + wxString linetext = strtext.Mid( laststop , i - laststop ) ; +#if TARGET_CARBON + if ( useDrawThemeText ) + { + Rect frame = { yy + line*(fi.descent + fi.ascent + fi.leading) ,xx , yy + (line+1)*(fi.descent + fi.ascent + fi.leading) , xx + 10000 } ; + wxMacCFStringHolder mString( linetext , m_font.GetEncoding() ) ; + if ( m_backgroundMode != wxTRANSPARENT ) + { + Point bounds={0,0} ; + Rect background = frame ; + SInt16 baseline ; + ::GetThemeTextDimensions( mString, + kThemeCurrentPortFont, + kThemeStateActive, + false, + &bounds, + &baseline ); + background.right = background.left + bounds.h ; + background.bottom = background.top + bounds.v ; + ::EraseRect( &background ) ; + } + ::DrawThemeTextBox( mString, + kThemeCurrentPortFont, + kThemeStateActive, + false, + &frame, + teJustLeft, + nil ); + line++ ; + } + else +#endif + { + wxCharBuffer text = linetext.mb_str(wxConvLocal) ; + ::DrawText( text , 0 , strlen(text) ) ; + if ( m_backgroundMode != wxTRANSPARENT ) + { + Point bounds={0,0} ; + Rect background = frame ; + SInt16 baseline ; + ::GetThemeTextDimensions( mString, + kThemeCurrentPortFont, + kThemeStateActive, + false, + &bounds, + &baseline ); + background.right = background.left + bounds.h ; + background.bottom = background.top + bounds.v ; + ::EraseRect( &background ) ; + } + line++ ; + ::MoveTo( xx , yy + line*(fi.descent + fi.ascent + fi.leading) ); + } + laststop = i+1 ; + } + i++ ; + } + wxString linetext = strtext.Mid( laststop , i - laststop ) ; +#endif // 0 + wxString linetext = strtext ; +#if TARGET_CARBON + if ( useDrawThemeText ) + { + Rect frame = { yy + line*(fi.descent + fi.ascent + fi.leading) ,xx , yy + (line+1)*(fi.descent + fi.ascent + fi.leading) , xx + 10000 } ; + wxMacCFStringHolder mString( linetext , m_font.GetEncoding()) ; + + if ( m_backgroundMode != wxTRANSPARENT ) + { + Point bounds={0,0} ; + Rect background = frame ; + SInt16 baseline ; + ::GetThemeTextDimensions( mString, + kThemeCurrentPortFont, + kThemeStateActive, + false, + &bounds, + &baseline ); + background.right = background.left + bounds.h ; + background.bottom = background.top + bounds.v ; + ::EraseRect( &background ) ; + } + ::DrawThemeTextBox( mString, + kThemeCurrentPortFont, + kThemeStateActive, + false, + &frame, + teJustLeft, + nil ); + } + else +#endif + { + wxCharBuffer text = linetext.mb_str(wxConvLocal) ; + if ( m_backgroundMode != wxTRANSPARENT ) + { + Rect frame = { yy - fi.ascent + line*(fi.descent + fi.ascent + fi.leading) ,xx , yy - fi.ascent + (line+1)*(fi.descent + fi.ascent + fi.leading) , xx + 10000 } ; + short width = ::TextWidth( text , 0 , strlen(text) ) ; + frame.right = frame.left + width ; + + ::EraseRect( &frame ) ; + } + ::DrawText( text , 0 , strlen(text) ) ; + } + } + ::TextMode( srcOr ) ; +} + +bool wxDC::CanGetTextExtent() const +{ + wxCHECK_MSG(Ok(), false, wxT("Invalid DC")); + return true ; +} + +void wxDC::DoGetTextExtent( const wxString &strtext, wxCoord *width, wxCoord *height, + wxCoord *descent, wxCoord *externalLeading , + wxFont *theFont ) const +{ + wxCHECK_RET(Ok(), wxT("Invalid DC")); + wxMacFastPortSetter helper(this) ; + wxFont formerFont = m_font ; + if ( theFont ) + { + // work around the constness + *((wxFont*)(&m_font)) = *theFont ; + } + MacInstallFont() ; + FontInfo fi ; + ::GetFontInfo( &fi ) ; +#if TARGET_CARBON + bool useGetThemeText = ( GetThemeTextDimensions != (void*) kUnresolvedCFragSymbolAddress ) ; + if ( UMAGetSystemVersion() < 0x1000 || IsKindOf(CLASSINFO( wxPrinterDC ) ) || ((wxFont*)&m_font)->GetNoAntiAliasing() ) + useGetThemeText = false ; +#endif + if ( height ) + *height = YDEV2LOGREL( fi.descent + fi.ascent ) ; + if ( descent ) + *descent =YDEV2LOGREL( fi.descent ); + if ( externalLeading ) + *externalLeading = YDEV2LOGREL( fi.leading ) ; + int length = strtext.Length() ; + + int laststop = 0 ; + int i = 0 ; + int curwidth = 0 ; + if ( width ) + { + *width = 0 ; +#if 0 // apparently we don't have to do all that + while( i < length ) + { + if( strtext[i] == 13 || strtext[i] == 10) + { + wxString linetext = strtext.Mid( laststop , i - laststop ) ; + if ( height ) + *height += YDEV2LOGREL( fi.descent + fi.ascent + fi.leading ) ; +#if TARGET_CARBON + if ( useGetThemeText ) + { + Point bounds={0,0} ; + SInt16 baseline ; + wxMacCFStringHolder mString( linetext , m_font.GetEncoding() ) ; + ::GetThemeTextDimensions( mString, + kThemeCurrentPortFont, + kThemeStateActive, + false, + &bounds, + &baseline ); + curwidth = bounds.h ; + } + else +#endif + { + wxCharBuffer text = linetext.mb_str(wxConvLocal) ; + curwidth = ::TextWidth( text , 0 , strlen(text) ) ; + } + if ( curwidth > *width ) + *width = XDEV2LOGREL( curwidth ) ; + laststop = i+1 ; + } + i++ ; + } + + wxString linetext = strtext.Mid( laststop , i - laststop ) ; +#endif // 0 + wxString linetext = strtext ; +#if TARGET_CARBON + if ( useGetThemeText ) + { + Point bounds={0,0} ; + SInt16 baseline ; + wxMacCFStringHolder mString( linetext , m_font.GetEncoding() ) ; + ::GetThemeTextDimensions( mString, + kThemeCurrentPortFont, + kThemeStateActive, + false, + &bounds, + &baseline ); + curwidth = bounds.h ; + } + else +#endif + { + wxCharBuffer text = linetext.mb_str(wxConvLocal) ; + curwidth = ::TextWidth( text , 0 , strlen(text) ) ; + } + if ( curwidth > *width ) + *width = XDEV2LOGREL( curwidth ) ; + } + if ( theFont ) + { + // work around the constness + *((wxFont*)(&m_font)) = formerFont ; + m_macFontInstalled = false ; + } +} + + +bool wxDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const +{ + wxCHECK_MSG(Ok(), false, wxT("Invalid DC")); + + widths.Empty(); + widths.Add(0, text.Length()); + + if (text.Length() == 0) + return false; + + wxMacFastPortSetter helper(this) ; + MacInstallFont() ; +#if TARGET_CARBON + bool useGetThemeText = ( GetThemeTextDimensions != (void*) kUnresolvedCFragSymbolAddress ) ; + if ( UMAGetSystemVersion() < 0x1000 || IsKindOf(CLASSINFO( wxPrinterDC ) ) || ((wxFont*)&m_font)->GetNoAntiAliasing() ) + useGetThemeText = false ; + + if ( useGetThemeText ) + { + // If anybody knows how to do this more efficiently yet still handle + // the fractional glyph widths that may be present when using AA + // fonts, please change it. Currently it is measuring from the + // begining of the string for each succeding substring, which is much + // slower than this should be. + for (size_t i=0; iGetNoAntiAliasing() ) + useGetThemeText = false ; +#endif + char text[] = "g" ; +#if TARGET_CARBON + if ( useGetThemeText ) + { + Point bounds={0,0} ; + SInt16 baseline ; + CFStringRef mString = CFStringCreateWithBytes( NULL , (UInt8*) text , 1 , CFStringGetSystemEncoding(), false ) ; + ::GetThemeTextDimensions( mString, + kThemeCurrentPortFont, + kThemeStateActive, + false, + &bounds, + &baseline ); + CFRelease( mString ) ; + width = bounds.h ; + } + else +#endif + { + width = ::TextWidth( text , 0 , 1 ) ; + } + return YDEV2LOGREL(width) ; +} + +wxCoord wxDC::GetCharHeight(void) const +{ + wxCHECK_MSG(Ok(), 1, wxT("Invalid DC")); + wxMacFastPortSetter helper(this) ; + MacInstallFont() ; + FontInfo fi ; + ::GetFontInfo( &fi ) ; + return YDEV2LOGREL( fi.descent + fi.ascent ); +} + +void wxDC::Clear(void) +{ + wxCHECK_RET(Ok(), wxT("Invalid DC")); + wxMacFastPortSetter helper(this) ; + Rect rect = { -31000 , -31000 , 31000 , 31000 } ; + if (m_backgroundBrush.GetStyle() != wxTRANSPARENT) + { + ::PenNormal() ; + //MacInstallBrush() ; + MacSetupBackgroundForCurrentPort( m_backgroundBrush ) ; + ::EraseRect( &rect ) ; + } +} + +void wxDC::MacInstallFont() const +{ + wxCHECK_RET(Ok(), wxT("Invalid DC")); + // if ( m_macFontInstalled ) + // return ; + Pattern blackColor ; + MacSetupBackgroundForCurrentPort(m_backgroundBrush) ; + if ( m_font.Ok() ) + { + ::TextFont( m_font.GetMacFontNum() ) ; + ::TextSize( (short)(m_scaleY * m_font.GetMacFontSize()) ) ; + ::TextFace( m_font.GetMacFontStyle() ) ; + m_macFontInstalled = true ; + m_macBrushInstalled = false ; + m_macPenInstalled = false ; + RGBColor forecolor = MAC_WXCOLORREF( m_textForegroundColour.GetPixel()); + RGBColor backcolor = MAC_WXCOLORREF( m_textBackgroundColour.GetPixel()); + ::RGBForeColor( &forecolor ); + ::RGBBackColor( &backcolor ); + } + else + { + FontFamilyID fontId ; + Str255 fontName ; + SInt16 fontSize ; + Style fontStyle ; + GetThemeFont(kThemeSmallSystemFont , GetApplicationScript() , fontName , &fontSize , &fontStyle ) ; + GetFNum( fontName, &fontId ); + ::TextFont( fontId ) ; + ::TextSize( short(m_scaleY * fontSize) ) ; + ::TextFace( fontStyle ) ; + // todo reset after spacing changes - or store the current spacing somewhere + m_macFontInstalled = true ; + m_macBrushInstalled = false ; + m_macPenInstalled = false ; + RGBColor forecolor = MAC_WXCOLORREF( m_textForegroundColour.GetPixel()); + RGBColor backcolor = MAC_WXCOLORREF( m_textBackgroundColour.GetPixel()); + ::RGBForeColor( &forecolor ); + ::RGBBackColor( &backcolor ); + } + short mode = patCopy ; + // todo : + switch( m_logicalFunction ) + { + case wxCOPY: // src + mode = patCopy ; + break ; + case wxINVERT: // NOT dst + ::PenPat(GetQDGlobalsBlack(&blackColor)); + mode = patXor ; + break ; + case wxXOR: // src XOR dst + mode = patXor ; + break ; + case wxOR_REVERSE: // src OR (NOT dst) + mode = notPatOr ; + break ; + case wxSRC_INVERT: // (NOT src) + mode = notPatCopy ; + break ; + case wxAND: // src AND dst + mode = adMin ; + break ; + // unsupported TODO + case wxCLEAR: // 0 + case wxAND_REVERSE:// src AND (NOT dst) + case wxAND_INVERT: // (NOT src) AND dst + case wxNO_OP: // dst + case wxNOR: // (NOT src) AND (NOT dst) + case wxEQUIV: // (NOT src) XOR dst + case wxOR_INVERT: // (NOT src) OR dst + case wxNAND: // (NOT src) OR (NOT dst) + case wxOR: // src OR dst + case wxSET: // 1 + // case wxSRC_OR: // source _bitmap_ OR destination + // case wxSRC_AND: // source _bitmap_ AND destination + break ; + } + ::PenMode( mode ) ; + OSStatus status = noErr ; + Fixed atsuSize = IntToFixed( int(m_scaleY * m_font.GetMacFontSize()) ) ; + Style qdStyle = m_font.GetMacFontStyle() ; + ATSUFontID atsuFont = m_font.GetMacATSUFontID() ; + status = ::ATSUCreateStyle((ATSUStyle *)&m_macATSUIStyle) ; + wxASSERT_MSG( status == noErr , wxT("couldn't create ATSU style") ) ; + ATSUAttributeTag atsuTags[] = + { + kATSUFontTag , + kATSUSizeTag , + // kATSUColorTag , + // kATSUBaselineClassTag , + kATSUVerticalCharacterTag, + kATSUQDBoldfaceTag , + kATSUQDItalicTag , + kATSUQDUnderlineTag , + kATSUQDCondensedTag , + kATSUQDExtendedTag , + } ; + ByteCount atsuSizes[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] = + { + sizeof( ATSUFontID ) , + sizeof( Fixed ) , + // sizeof( RGBColor ) , + // sizeof( BslnBaselineClass ) , + sizeof( ATSUVerticalCharacterType), + sizeof( Boolean ) , + sizeof( Boolean ) , + sizeof( Boolean ) , + sizeof( Boolean ) , + sizeof( Boolean ) , + } ; + Boolean kTrue = true ; + Boolean kFalse = false ; + //BslnBaselineClass kBaselineDefault = kBSLNHangingBaseline ; + ATSUVerticalCharacterType kHorizontal = kATSUStronglyHorizontal; + ATSUAttributeValuePtr atsuValues[sizeof(atsuTags)/sizeof(ATSUAttributeTag)] = + { + &atsuFont , + &atsuSize , + // &MAC_WXCOLORREF( m_textForegroundColour.GetPixel() ) , + // &kBaselineDefault , + &kHorizontal, + (qdStyle & bold) ? &kTrue : &kFalse , + (qdStyle & italic) ? &kTrue : &kFalse , + (qdStyle & underline) ? &kTrue : &kFalse , + (qdStyle & condense) ? &kTrue : &kFalse , + (qdStyle & extend) ? &kTrue : &kFalse , + } ; + status = ::ATSUSetAttributes((ATSUStyle)m_macATSUIStyle, sizeof(atsuTags)/sizeof(ATSUAttributeTag) , + atsuTags, atsuSizes, atsuValues); + wxASSERT_MSG( status == noErr , wxT("couldn't set create ATSU style") ) ; +} + +Pattern gPatterns[] = +{ // hatch patterns + { { 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } } , + { { 0x01 , 0x02 , 0x04 , 0x08 , 0x10 , 0x20 , 0x40 , 0x80 } } , + { { 0x80 , 0x40 , 0x20 , 0x10 , 0x08 , 0x04 , 0x02 , 0x01 } } , + { { 0x10 , 0x10 , 0x10 , 0xFF , 0x10 , 0x10 , 0x10 , 0x10 } } , + { { 0x00 , 0x00 , 0x00 , 0xFF , 0x00 , 0x00 , 0x00 , 0x00 } } , + { { 0x10 , 0x10 , 0x10 , 0x10 , 0x10 , 0x10 , 0x10 , 0x10 } } , + { { 0x81 , 0x42 , 0x24 , 0x18 , 0x18 , 0x24 , 0x42 , 0x81 } } , + // dash patterns + { { 0xCC , 0x99 , 0x33 , 0x66 , 0xCC , 0x99 , 0x33 , 0x66 } } , // DOT + { { 0xFE , 0xFD , 0xFB , 0xF7 , 0xEF , 0xDF , 0xBF , 0x7F } } , // LONG_DASH + { { 0xEE , 0xDD , 0xBB , 0x77 , 0xEE , 0xDD , 0xBB , 0x77 } } , // SHORT_DASH + { { 0xDE , 0xBD , 0x7B , 0xF6 , 0xED , 0xDB , 0xB7 , 0x6F } } , // DOT_DASH +} ; + +static void wxMacGetPattern(int penStyle, Pattern *pattern) +{ + int index = 0; // solid pattern by default + switch(penStyle) + { + // hatches + case wxBDIAGONAL_HATCH: index = 1; break; + case wxFDIAGONAL_HATCH: index = 2; break; + case wxCROSS_HATCH: index = 3; break; + case wxHORIZONTAL_HATCH: index = 4; break; + case wxVERTICAL_HATCH: index = 5; break; + case wxCROSSDIAG_HATCH: index = 6; break; + // dashes + case wxDOT: index = 7; break; + case wxLONG_DASH: index = 8; break; + case wxSHORT_DASH: index = 9; break; + case wxDOT_DASH: index = 10; break; + } + *pattern = gPatterns[index]; +} + +void wxDC::MacInstallPen() const +{ + wxCHECK_RET(Ok(), wxT("Invalid DC")); + //Pattern blackColor; + // if ( m_macPenInstalled ) + // return ; + RGBColor forecolor = MAC_WXCOLORREF( m_pen.GetColour().GetPixel()); + RGBColor backcolor = MAC_WXCOLORREF( m_backgroundBrush.GetColour().GetPixel()); + ::RGBForeColor( &forecolor ); + ::RGBBackColor( &backcolor ); + ::PenNormal() ; + int penWidth = (int) (m_pen.GetWidth() * m_scaleX) ; ; + // null means only one pixel, at whatever resolution + if ( penWidth == 0 ) + penWidth = 1 ; + ::PenSize(penWidth, penWidth); + + int penStyle = m_pen.GetStyle(); + Pattern pat; + if (penStyle == wxUSER_DASH) + { + // FIXME: there should be exactly 8 items in the dash + wxDash* dash ; + int number = m_pen.GetDashes(&dash) ; + int index = 0; + for ( int i = 0 ; i < 8 ; ++i ) + { + pat.pat[i] = dash[index] ; + if (index < number - 1) + index++; + } + } + else + { + wxMacGetPattern(penStyle, &pat); + } + ::PenPat(&pat); + + short mode = patCopy ; + // todo : + switch( m_logicalFunction ) + { + case wxCOPY: // only foreground color, leave background (thus not patCopy) + mode = patOr ; + break ; + case wxINVERT: // NOT dst + // ::PenPat(GetQDGlobalsBlack(&blackColor)); + mode = patXor ; + break ; + case wxXOR: // src XOR dst + mode = patXor ; + break ; + case wxOR_REVERSE: // src OR (NOT dst) + mode = notPatOr ; + break ; + case wxSRC_INVERT: // (NOT src) + mode = notPatCopy ; + break ; + case wxAND: // src AND dst + mode = adMin ; + break ; + // unsupported TODO + case wxCLEAR: // 0 + case wxAND_REVERSE:// src AND (NOT dst) + case wxAND_INVERT: // (NOT src) AND dst + case wxNO_OP: // dst + case wxNOR: // (NOT src) AND (NOT dst) + case wxEQUIV: // (NOT src) XOR dst + case wxOR_INVERT: // (NOT src) OR dst + case wxNAND: // (NOT src) OR (NOT dst) + case wxOR: // src OR dst + case wxSET: // 1 + // case wxSRC_OR: // source _bitmap_ OR destination + // case wxSRC_AND: // source _bitmap_ AND destination + break ; + } + ::PenMode( mode ) ; + m_macPenInstalled = true ; + m_macBrushInstalled = false ; + m_macFontInstalled = false ; +} + +void wxDC::MacSetupBackgroundForCurrentPort(const wxBrush& background ) +{ + Pattern whiteColor ; + switch( background.MacGetBrushKind() ) + { + case kwxMacBrushTheme : + { + ::SetThemeBackground( background.GetMacTheme() , wxDisplayDepth() , true ) ; + break ; + } + case kwxMacBrushThemeBackground : + { + Rect extent ; + ThemeBackgroundKind bg = background.GetMacThemeBackground( &extent ) ; + ::ApplyThemeBackground( bg , &extent ,kThemeStateActive , wxDisplayDepth() , true ) ; + break ; + } + case kwxMacBrushColour : + { + ::RGBBackColor( &MAC_WXCOLORREF( background.GetColour().GetPixel()) ); + int brushStyle = background.GetStyle(); + if (brushStyle == wxSOLID) + ::BackPat(GetQDGlobalsWhite(&whiteColor)); + else if (IS_HATCH(brushStyle)) + { + Pattern pat ; + wxMacGetPattern(brushStyle, &pat); + ::BackPat(&pat); + } + else + { + ::BackPat(GetQDGlobalsWhite(&whiteColor)); + } + break ; + } + } +} + +void wxDC::MacInstallBrush() const +{ + wxCHECK_RET(Ok(), wxT("Invalid DC")); + Pattern blackColor ; + // if ( m_macBrushInstalled ) + // return ; + // foreground + bool backgroundTransparent = (GetBackgroundMode() == wxTRANSPARENT) ; + ::RGBForeColor( &MAC_WXCOLORREF( m_brush.GetColour().GetPixel()) ); + ::RGBBackColor( &MAC_WXCOLORREF( m_backgroundBrush.GetColour().GetPixel()) ); + int brushStyle = m_brush.GetStyle(); + if (brushStyle == wxSOLID) + { + ::PenPat(GetQDGlobalsBlack(&blackColor)); + } + else if (IS_HATCH(brushStyle)) + { + Pattern pat ; + wxMacGetPattern(brushStyle, &pat); + ::PenPat(&pat); + } + else if ( m_brush.GetStyle() == wxSTIPPLE || m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE ) + { + // we force this in order to be compliant with wxMSW + backgroundTransparent = false ; + // for these the text fore (and back for MASK_OPAQUE) colors are used + wxBitmap* bitmap = m_brush.GetStipple() ; + int width = bitmap->GetWidth() ; + int height = bitmap->GetHeight() ; + GWorldPtr gw = NULL ; + if ( m_brush.GetStyle() == wxSTIPPLE ) + gw = MAC_WXHBITMAP(bitmap->GetHBITMAP()) ; + else + gw = MAC_WXHBITMAP(bitmap->GetMask()->GetMaskBitmap()) ; + PixMapHandle gwpixmaphandle = GetGWorldPixMap( gw ) ; + LockPixels( gwpixmaphandle ) ; + bool isMonochrome = !IsPortColor( gw ) ; + if ( !isMonochrome ) + { + if ( (**gwpixmaphandle).pixelSize == 1 ) + isMonochrome = true ; + } + if ( isMonochrome && width == 8 && height == 8 ) + { + ::RGBForeColor( &MAC_WXCOLORREF( m_textForegroundColour.GetPixel()) ); + ::RGBForeColor( &MAC_WXCOLORREF( m_textBackgroundColour.GetPixel()) ); + BitMap* gwbitmap = (BitMap*) *gwpixmaphandle ; // since the color depth is 1 it is a BitMap + UInt8 *gwbits = (UInt8*) gwbitmap->baseAddr ; + int alignment = gwbitmap->rowBytes & 0x7FFF ; + Pattern pat ; + for ( int i = 0 ; i < 8 ; ++i ) + { + pat.pat[i] = gwbits[i*alignment+0] ; + } + UnlockPixels( GetGWorldPixMap( gw ) ) ; + ::PenPat( &pat ) ; + } + else + { + // this will be the code to handle power of 2 patterns, we will have to arrive at a nice + // caching scheme before putting this into production + Handle image; + long imageSize; + PixPatHandle pixpat = NewPixPat() ; + CopyPixMap(gwpixmaphandle, (**pixpat).patMap); + imageSize = GetPixRowBytes((**pixpat).patMap) * + ((**(**pixpat).patMap).bounds.bottom - + (**(**pixpat).patMap).bounds.top); + PtrToHand( (**gwpixmaphandle).baseAddr, &image, imageSize ); + (**pixpat).patData = image; + if ( isMonochrome ) + { + CTabHandle ctable = ((**((**pixpat).patMap)).pmTable) ; + ColorSpecPtr ctspec = (ColorSpecPtr) &(**ctable).ctTable ; + if ( ctspec[0].rgb.red == 0x0000 ) + { + ctspec[1].rgb = MAC_WXCOLORREF( m_textBackgroundColour.GetPixel()) ; + ctspec[0].rgb = MAC_WXCOLORREF( m_textForegroundColour.GetPixel()) ; + } + else + { + ctspec[0].rgb = MAC_WXCOLORREF( m_textBackgroundColour.GetPixel()) ; + ctspec[1].rgb = MAC_WXCOLORREF( m_textForegroundColour.GetPixel()) ; + } + ::CTabChanged( ctable ) ; + } + ::PenPixPat(pixpat); + m_macForegroundPixMap = pixpat ; + } + UnlockPixels( gwpixmaphandle ) ; + } + else + { + ::PenPat(GetQDGlobalsBlack(&blackColor)); + } + short mode = patCopy ; + switch( m_logicalFunction ) + { + case wxCOPY: // src + if ( backgroundTransparent ) + mode = patOr ; + else + mode = patCopy ; + break ; + case wxINVERT: // NOT dst + if ( !backgroundTransparent ) + { + ::PenPat(GetQDGlobalsBlack(&blackColor)); + } + mode = patXor ; + break ; + case wxXOR: // src XOR dst + mode = patXor ; + break ; + case wxOR_REVERSE: // src OR (NOT dst) + mode = notPatOr ; + break ; + case wxSRC_INVERT: // (NOT src) + mode = notPatCopy ; + break ; + case wxAND: // src AND dst + mode = adMin ; + break ; + // unsupported TODO + case wxCLEAR: // 0 + case wxAND_REVERSE:// src AND (NOT dst) + case wxAND_INVERT: // (NOT src) AND dst + case wxNO_OP: // dst + case wxNOR: // (NOT src) AND (NOT dst) + case wxEQUIV: // (NOT src) XOR dst + case wxOR_INVERT: // (NOT src) OR dst + case wxNAND: // (NOT src) OR (NOT dst) + case wxOR: // src OR dst + case wxSET: // 1 + // case wxSRC_OR: // source _bitmap_ OR destination + // case wxSRC_AND: // source _bitmap_ AND destination + break ; + } + ::PenMode( mode ) ; + m_macBrushInstalled = true ; + m_macPenInstalled = false ; + m_macFontInstalled = false ; +} + +// --------------------------------------------------------------------------- +// coordinates transformations +// --------------------------------------------------------------------------- + +wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const +{ + return ((wxDC *)this)->XDEV2LOG(x); +} + +wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const +{ + return ((wxDC *)this)->YDEV2LOG(y); +} + +wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const +{ + return ((wxDC *)this)->XDEV2LOGREL(x); +} + +wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const +{ + return ((wxDC *)this)->YDEV2LOGREL(y); +} + +wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const +{ + return ((wxDC *)this)->XLOG2DEV(x); +} + +wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const +{ + return ((wxDC *)this)->YLOG2DEV(y); +} + +wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const +{ + return ((wxDC *)this)->XLOG2DEVREL(x); +} + +wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const +{ + return ((wxDC *)this)->YLOG2DEVREL(y); +} diff --git a/src/mac/classic/dcclient.cpp b/src/mac/classic/dcclient.cpp new file mode 100644 index 0000000000..f28c6dc576 --- /dev/null +++ b/src/mac/classic/dcclient.cpp @@ -0,0 +1,175 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: dcclient.cpp +// Purpose: wxClientDC class +// Author: Stefan Csomor +// Modified by: +// Created: 01/02/97 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "dcclient.h" +#endif + +#include "wx/dcclient.h" +#include "wx/dcmemory.h" +#include "wx/region.h" +#include "wx/window.h" +#include "wx/toplevel.h" +#include +#include "wx/mac/private.h" + +//----------------------------------------------------------------------------- +// constants +//----------------------------------------------------------------------------- + +#define RAD2DEG 57.2957795131 + +//----------------------------------------------------------------------------- +// wxPaintDC +//----------------------------------------------------------------------------- + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC) +IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC) +IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxWindowDC) +#endif + +/* + * wxWindowDC + */ + +#include "wx/mac/uma.h" + +wxWindowDC::wxWindowDC() +{ + m_window = NULL ; +} + +wxWindowDC::wxWindowDC(wxWindow *window) +{ + m_window = window ; + wxTopLevelWindowMac* rootwindow = window->MacGetTopLevelWindow() ; + WindowRef windowref = (WindowRef) rootwindow->MacGetWindowRef() ; + + int x , y ; + x = y = 0 ; + window->MacWindowToRootWindow( &x , &y ) ; + m_macLocalOrigin.x = x ; + m_macLocalOrigin.y = y ; + CopyRgn( (RgnHandle) window->MacGetVisibleRegion().GetWXHRGN() , (RgnHandle) m_macBoundaryClipRgn ) ; + OffsetRgn( (RgnHandle) m_macBoundaryClipRgn , m_macLocalOrigin.x , m_macLocalOrigin.y ) ; + CopyRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ; + m_macPort = UMAGetWindowPort( windowref ) ; + m_ok = TRUE ; + SetBackground(window->MacGetBackgroundBrush()); +} + +wxWindowDC::~wxWindowDC() +{ +} + +void wxWindowDC::DoGetSize( int* width, int* height ) const +{ + wxCHECK_RET( m_window, _T("GetSize() doesn't work without window") ); + + m_window->GetSize(width, height); +} + +/* + * wxClientDC + */ + +wxClientDC::wxClientDC() +{ + m_window = NULL ; +} + +wxClientDC::wxClientDC(wxWindow *window) +{ + m_window = window ; + wxTopLevelWindowMac* rootwindow = window->MacGetTopLevelWindow() ; + if (!rootwindow) + return; + WindowRef windowref = (WindowRef) rootwindow->MacGetWindowRef() ; + wxPoint origin = window->GetClientAreaOrigin() ; + wxSize size = window->GetClientSize() ; + int x , y ; + x = origin.x ; + y = origin.y ; + window->MacWindowToRootWindow( &x , &y ) ; + m_macLocalOrigin.x = x ; + m_macLocalOrigin.y = y ; + SetRectRgn( (RgnHandle) m_macBoundaryClipRgn , origin.x , origin.y , origin.x + size.x , origin.y + size.y ) ; + SectRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) window->MacGetVisibleRegion().GetWXHRGN() , (RgnHandle) m_macBoundaryClipRgn ) ; + OffsetRgn( (RgnHandle) m_macBoundaryClipRgn , -origin.x , -origin.y ) ; + OffsetRgn( (RgnHandle) m_macBoundaryClipRgn , m_macLocalOrigin.x , m_macLocalOrigin.y ) ; + CopyRgn( (RgnHandle) m_macBoundaryClipRgn ,(RgnHandle) m_macCurrentClipRgn ) ; + m_macPort = UMAGetWindowPort( windowref ) ; + + m_ok = TRUE ; + SetBackground(window->MacGetBackgroundBrush()); + SetFont( window->GetFont() ) ; +} + +wxClientDC::~wxClientDC() +{ +} + +void wxClientDC::DoGetSize(int *width, int *height) const +{ + wxCHECK_RET( m_window, _T("GetSize() doesn't work without window") ); + + m_window->GetClientSize( width, height ); +} + + +/* + * wxPaintDC + */ + +wxPaintDC::wxPaintDC() +{ + m_window = NULL ; +} + +wxPaintDC::wxPaintDC(wxWindow *window) +{ + m_window = window ; + wxTopLevelWindowMac* rootwindow = window->MacGetTopLevelWindow() ; + WindowRef windowref = (WindowRef) rootwindow->MacGetWindowRef() ; + wxPoint origin = window->GetClientAreaOrigin() ; + wxSize size = window->GetClientSize() ; + int x , y ; + x = origin.x ; + y = origin.y ; + window->MacWindowToRootWindow( &x , &y ) ; + m_macLocalOrigin.x = x ; + m_macLocalOrigin.y = y ; + SetRectRgn( (RgnHandle) m_macBoundaryClipRgn , origin.x , origin.y , origin.x + size.x , origin.y + size.y ) ; + SectRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) window->MacGetVisibleRegion().GetWXHRGN() , (RgnHandle) m_macBoundaryClipRgn ) ; + OffsetRgn( (RgnHandle) m_macBoundaryClipRgn , -origin.x , -origin.y ) ; + SectRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) window->GetUpdateRegion().GetWXHRGN() , (RgnHandle) m_macBoundaryClipRgn ) ; + OffsetRgn( (RgnHandle) m_macBoundaryClipRgn , m_macLocalOrigin.x , m_macLocalOrigin.y ) ; + CopyRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ; + m_macPort = UMAGetWindowPort( windowref ) ; + + m_ok = TRUE ; + SetBackground(window->MacGetBackgroundBrush()); + SetFont( window->GetFont() ) ; +} + +wxPaintDC::~wxPaintDC() +{ +} + +void wxPaintDC::DoGetSize(int *width, int *height) const +{ + wxCHECK_RET( m_window, _T("GetSize() doesn't work without window") ); + + m_window->GetClientSize( width, height ); +} + + diff --git a/src/mac/classic/dcmemory.cpp b/src/mac/classic/dcmemory.cpp new file mode 100644 index 0000000000..e850a59e4d --- /dev/null +++ b/src/mac/classic/dcmemory.cpp @@ -0,0 +1,100 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: dcmemory.cpp +// Purpose: wxMemoryDC class +// Author: Stefan Csomor +// Modified by: +// Created: 01/02/97 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "dcmemory.h" +#endif + +#include "wx/dcmemory.h" +#include "wx/mac/private.h" + +//----------------------------------------------------------------------------- +// wxMemoryDC +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC,wxPaintDC) + +wxMemoryDC::wxMemoryDC(void) +: m_selected() +{ + m_ok = TRUE; + SetBackground(*wxWHITE_BRUSH); + SetBrush(*wxWHITE_BRUSH); + SetPen(*wxBLACK_PEN); + m_ok = FALSE; +}; + +wxMemoryDC::wxMemoryDC( wxDC *WXUNUSED(dc) ) +: m_selected() +{ + m_ok = TRUE; + SetBackground(*wxWHITE_BRUSH); + SetBrush(*wxWHITE_BRUSH); + SetPen(*wxBLACK_PEN); + m_ok = FALSE; +}; + +wxMemoryDC::~wxMemoryDC() +{ + if ( m_selected.Ok() ) + { + UnlockPixels( GetGWorldPixMap(MAC_WXHBITMAP(m_selected.GetHBITMAP())) ); + } +}; + +void wxMemoryDC::SelectObject( const wxBitmap& bitmap ) +{ + if ( m_selected.Ok() ) + { + UnlockPixels( GetGWorldPixMap(MAC_WXHBITMAP(m_selected.GetHBITMAP())) ); + } + m_selected = bitmap; + if (m_selected.Ok()) + { + if ( m_selected.GetHBITMAP() ) + { + m_macPort = (GrafPtr) m_selected.GetHBITMAP() ; + LockPixels( GetGWorldPixMap( (CGrafPtr) m_macPort ) ) ; + wxMask * mask = bitmap.GetMask() ; + if ( mask ) + { + m_macMask = mask->GetMaskBitmap() ; + } + SetRectRgn( (RgnHandle) m_macBoundaryClipRgn , 0 , 0 , m_selected.GetWidth() , m_selected.GetHeight() ) ; + CopyRgn( (RgnHandle) m_macBoundaryClipRgn ,(RgnHandle) m_macCurrentClipRgn ) ; + m_ok = TRUE ; + } + else + { + m_ok = FALSE; + } + } + else + { + m_ok = FALSE; + } +} + +void wxMemoryDC::DoGetSize( int *width, int *height ) const +{ + if (m_selected.Ok()) + { + if (width) (*width) = m_selected.GetWidth(); + if (height) (*height) = m_selected.GetHeight(); + } + else + { + if (width) (*width) = 0; + if (height) (*height) = 0; + } +} + + diff --git a/src/mac/classic/dcprint.cpp b/src/mac/classic/dcprint.cpp new file mode 100644 index 0000000000..e875cb0387 --- /dev/null +++ b/src/mac/classic/dcprint.cpp @@ -0,0 +1,416 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: dcprint.cpp +// Purpose: wxPrinterDC class +// Author: Julian Smart +// Modified by: +// Created: 01/02/97 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "dcprint.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#endif + +#include "wx/dcprint.h" +#include "wx/msgdlg.h" +#include +#include "wx/mac/uma.h" +#include "wx/mac/private/print.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_CLASS(wxPrinterDC, wxDC) +#endif + +class wxNativePrinterDC +{ +public : + wxNativePrinterDC() {} + virtual ~wxNativePrinterDC() {} + virtual bool StartDoc( wxPrinterDC* dc , const wxString& message ) = 0; + virtual void EndDoc( wxPrinterDC* dc ) = 0; + virtual void StartPage( wxPrinterDC* dc ) = 0; + virtual void EndPage( wxPrinterDC* dc ) = 0; + virtual wxCoord GetMaxX() const = 0 ; + virtual wxCoord GetMaxY() const = 0 ; + // returns 0 in case of no Error, otherwise platform specific error codes + virtual wxUint32 GetStatus() const = 0 ; + bool Ok() { return GetStatus() == 0 ; } + + static wxNativePrinterDC* Create(wxPrintData* data) ; +} ; + +#if TARGET_CARBON + +class wxMacCarbonPrinterDC : public wxNativePrinterDC +{ +public : + wxMacCarbonPrinterDC( wxPrintData* data ) ; + ~wxMacCarbonPrinterDC() ; + virtual bool StartDoc( wxPrinterDC* dc , const wxString& message ) ; + virtual void EndDoc( wxPrinterDC* dc ) ; + virtual void StartPage( wxPrinterDC* dc ) ; + virtual void EndPage( wxPrinterDC* dc ) ; + virtual wxCoord GetMaxX() const { return m_maxX ; } + virtual wxCoord GetMaxY() const { return m_maxY ; } + virtual wxUint32 GetStatus() const { return m_err ; } +private : + GrafPtr m_macPrintFormerPort ; + wxCoord m_maxX ; + wxCoord m_maxY ; + OSStatus m_err ; +} ; + +wxMacCarbonPrinterDC::wxMacCarbonPrinterDC( wxPrintData* data ) +{ + ::GetPort( & m_macPrintFormerPort ) ; + + m_err = noErr ; + wxMacCarbonPrintData *native = (wxMacCarbonPrintData*) data->m_nativePrintData ; + + PMRect rPage; + m_err = PMGetAdjustedPageRect(native->m_macPageFormat, &rPage); + if ( m_err != noErr ) + return; + + m_maxX = wxCoord(rPage.right - rPage.left) ; + m_maxY = wxCoord(rPage.bottom - rPage.top); +} + +wxMacCarbonPrinterDC::~wxMacCarbonPrinterDC() +{ + // nothing to release from print data, as wxPrinterDC has all data in its wxPrintData member + ::SetPort( m_macPrintFormerPort ) ; +} + +wxNativePrinterDC* wxNativePrinterDC::Create(wxPrintData* data) +{ + return new wxMacCarbonPrinterDC(data) ; +} + +bool wxMacCarbonPrinterDC::StartDoc( wxPrinterDC* dc , const wxString& WXUNUSED(message) ) +{ + if ( m_err ) + return false ; + + wxMacCarbonPrintData *native = (wxMacCarbonPrintData*) dc->GetPrintData().m_nativePrintData ; + + m_err = PMSessionBeginDocument(native->m_macPrintSession, + native->m_macPrintSettings, + native->m_macPageFormat); + if ( m_err != noErr ) + return false; + + PMRect rPage; + m_err = PMGetAdjustedPageRect(native->m_macPageFormat, &rPage); + if ( m_err != noErr ) + return false; + + m_maxX = (wxCoord)(rPage.right - rPage.left); + m_maxY = (wxCoord)(rPage.bottom - rPage.top); + return true ; +} + +void wxMacCarbonPrinterDC::EndDoc( wxPrinterDC* dc ) +{ + if ( m_err ) + return ; + + wxMacCarbonPrintData *native = (wxMacCarbonPrintData*) dc->GetPrintData().m_nativePrintData ; + + m_err = PMSessionEndDocument(native->m_macPrintSession); +} + +void wxMacCarbonPrinterDC::StartPage( wxPrinterDC* dc ) +{ + if ( m_err ) + return ; + + wxMacCarbonPrintData *native = (wxMacCarbonPrintData*) dc->GetPrintData().m_nativePrintData ; + + m_err = PMSessionBeginPage(native->m_macPrintSession, + native->m_macPageFormat, + nil); + + if ( m_err == noErr ) + { + m_err = PMSessionGetGraphicsContext(native->m_macPrintSession, + nil, + (void**) &dc->m_macPort ); + } + + if ( m_err != noErr ) + { + PMSessionEndPage(native->m_macPrintSession); + PMSessionEndDocument(native->m_macPrintSession); + } + else + { + PMRect rPage; + + m_err = PMGetAdjustedPageRect(native->m_macPageFormat, &rPage); + if ( !m_err ) + { + dc->m_macLocalOrigin.x = (int) rPage.left; + dc->m_macLocalOrigin.y = (int) rPage.top; + } + // since this is a non-critical error, we set the flag back + m_err = noErr ; + } +} + +void wxMacCarbonPrinterDC::EndPage( wxPrinterDC* dc ) +{ + if ( m_err ) + return ; + + wxMacCarbonPrintData *native = (wxMacCarbonPrintData*) dc->GetPrintData().m_nativePrintData ; + + m_err = PMSessionEndPage(native->m_macPrintSession); + if ( m_err != noErr ) + { + PMSessionEndDocument(native->m_macPrintSession); + } +} + +#else + +class wxMacClassicPrinterDC : public wxNativePrinterDC +{ +public : + wxMacClassicPrinterDC( wxPrintData* data ) ; + ~wxMacClassicPrinterDC() ; + virtual bool StartDoc( wxPrinterDC* dc , const wxString& message ) ; + virtual void EndDoc( wxPrinterDC* dc ) ; + virtual void StartPage( wxPrinterDC* dc ) ; + virtual void EndPage( wxPrinterDC* dc ) ; + virtual wxCoord GetMaxX() const { return m_maxX ; } + virtual wxCoord GetMaxY() const { return m_maxY ; } + virtual wxUint32 GetStatus() const { return m_err ; } +private : + GrafPtr m_macPrintFormerPort ; + TPPrPort m_macPrintingPort ; + OSErr m_err ; + long m_maxX ; + long m_maxY ; +} ; + +wxNativePrinterDC* wxNativePrinterDC::Create(wxPrintData* data) +{ + return new wxMacClassicPrinterDC(data) ; +} + +wxMacClassicPrinterDC::wxMacClassicPrinterDC(wxPrintData* data) +{ + ::GetPort( &m_macPrintFormerPort ) ; + m_err = noErr ; + ::UMAPrOpen() ; + m_err = PrError() ; + if ( m_err != noErr ) + return; + + wxMacClassicPrintData *native = (wxMacClassicPrintData*) data->m_nativePrintData ; + + if ( ::PrValidate( native->m_macPrintSettings ) ) + { + // the driver has changed in the mean time, should we pop up a page setup dialog ? + if ( !::PrStlDialog( native->m_macPrintSettings ) ) + { + m_err = -1 ; + return; + } + } + m_err = PrError() ; + + if ( m_err == noErr ) + { + m_maxX = (**native->m_macPrintSettings).prInfo.rPage.right - (**native->m_macPrintSettings).prInfo.rPage.left ; + m_maxY = (**native->m_macPrintSettings).prInfo.rPage.bottom - (**native->m_macPrintSettings).prInfo.rPage.top ; + } +} + +wxMacClassicPrinterDC::~wxMacClassicPrinterDC() +{ + ::UMAPrClose() ; + ::SetPort( LMGetWMgrPort() ) ; +} + +bool wxMacClassicPrinterDC::StartDoc( wxPrinterDC* dc , const wxString& WXUNUSED(message) ) +{ + if ( m_err ) + return false ; + + wxMacClassicPrintData *native = (wxMacClassicPrintData*) dc->GetPrintData().m_nativePrintData ; + m_macPrintingPort = ::PrOpenDoc( native->m_macPrintSettings , NULL , NULL ) ; + m_err = PrError() ; + if ( m_err ) + return false ; + + // sets current port + dc->m_macPort = (GrafPtr ) m_macPrintingPort ; + m_maxX = (**native->m_macPrintSettings).prInfo.rPage.right - (**native->m_macPrintSettings).prInfo.rPage.left ; + m_maxY = (**native->m_macPrintSettings).prInfo.rPage.bottom - (**native->m_macPrintSettings).prInfo.rPage.top ; + return true ; +} + +void wxMacClassicPrinterDC::EndDoc( wxPrinterDC* dc ) +{ + if ( m_err ) + return ; + + PrCloseDoc( m_macPrintingPort ) ; + m_err = PrError() ; +} + +void wxMacClassicPrinterDC::StartPage( wxPrinterDC* dc ) +{ + if ( m_err ) + return ; + + wxMacClassicPrintData *native = (wxMacClassicPrintData*) dc->GetPrintData().m_nativePrintData ; + + PrOpenPage( m_macPrintingPort , NULL ) ; + dc->m_macLocalOrigin.x = (**native->m_macPrintSettings).rPaper.left ; + dc->m_macLocalOrigin.y = (**native->m_macPrintSettings).rPaper.top ; + // m_macPrintingPort is now the current port + Rect clip = { -32000 , -32000 , 32000 , 32000 } ; + ::ClipRect( &clip ) ; + m_err = PrError() ; + if ( m_err != noErr ) + ::PrCloseDoc( m_macPrintingPort ) ; +} + +void wxMacClassicPrinterDC::EndPage( wxPrinterDC* dc ) +{ + if ( m_err ) + return ; + + PrClosePage( m_macPrintingPort ) ; + m_err = PrError() ; + if ( m_err != noErr ) + ::PrCloseDoc( m_macPrintingPort ) ; +} + +#endif + +wxPrinterDC::wxPrinterDC(const wxPrintData& printdata) +{ + m_ok = FALSE ; + m_printData = printdata ; + m_printData.ConvertToNative() ; + m_nativePrinterDC = wxNativePrinterDC::Create( &m_printData ) ; + if ( m_nativePrinterDC ) + { + m_ok = m_nativePrinterDC->Ok() ; + + if ( !m_ok ) + { + wxString message ; + message.Printf( wxT("Print Error %u"), m_nativePrinterDC->GetStatus() ) ; + wxMessageDialog dialog( NULL , message , wxEmptyString, wxICON_HAND | wxOK) ; + dialog.ShowModal(); + } + } +} + +wxPrinterDC::~wxPrinterDC(void) +{ + delete m_nativePrinterDC ; +} + +bool wxPrinterDC::StartDoc( const wxString& message ) +{ + wxASSERT_MSG( Ok() , wxT("Called wxPrinterDC::StartDoc from an invalid object") ) ; + + if ( !m_ok ) + return false ; + + if ( m_nativePrinterDC->StartDoc(this, message ) ) + { + // in case we have to do additional things when successful + } + m_ok = m_nativePrinterDC->Ok() ; + if ( !m_ok ) + { + wxString message ; + message.Printf( wxT("Print Error %u"), m_nativePrinterDC->GetStatus() ) ; + wxMessageDialog dialog( NULL , message , wxEmptyString, wxICON_HAND | wxOK) ; + dialog.ShowModal(); + } + + return m_ok ; +} + +void wxPrinterDC::EndDoc(void) +{ + if ( !m_ok ) + return ; + + m_nativePrinterDC->EndDoc( this ) ; + m_ok = m_nativePrinterDC->Ok() ; + + if ( !m_ok ) + { + wxString message ; + message.Printf( wxT("Print Error %u"), m_nativePrinterDC->GetStatus() ) ; + wxMessageDialog dialog( NULL , message , wxEmptyString, wxICON_HAND | wxOK) ; + dialog.ShowModal(); + } +} + +void wxPrinterDC::StartPage(void) +{ + if ( !m_ok ) + return ; + + m_logicalFunction = wxCOPY; + // m_textAlignment = wxALIGN_TOP_LEFT; + m_backgroundMode = wxTRANSPARENT; + + m_textForegroundColour = *wxBLACK; + m_textBackgroundColour = *wxWHITE; + m_pen = *wxBLACK_PEN; + m_font = *wxNORMAL_FONT; + m_brush = *wxTRANSPARENT_BRUSH; + m_backgroundBrush = *wxWHITE_BRUSH; + + m_macFontInstalled = false ; + m_macBrushInstalled = false ; + m_macPenInstalled = false ; + + m_nativePrinterDC->StartPage(this) ; + m_ok = m_nativePrinterDC->Ok() ; + +} + +void wxPrinterDC::EndPage(void) +{ + if ( !m_ok ) + return ; + + m_nativePrinterDC->EndPage(this) ; + m_ok = m_nativePrinterDC->Ok() ; +} + +void wxPrinterDC::DoGetSize(int *width, int *height) const +{ + wxCHECK_RET( m_ok , _T("GetSize() doesn't work without a valid wxPrinterDC") ); + + if ( width ) + * width = m_nativePrinterDC->GetMaxX() ; + if ( height ) + * height = m_nativePrinterDC->GetMaxY() ; +} + + diff --git a/src/mac/classic/dcscreen.cpp b/src/mac/classic/dcscreen.cpp new file mode 100644 index 0000000000..03d769a05b --- /dev/null +++ b/src/mac/classic/dcscreen.cpp @@ -0,0 +1,63 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: dcscreen.cpp +// Purpose: wxScreenDC class +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "dcscreen.h" +#endif + +#include "wx/dcscreen.h" +#include "wx/mac/uma.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxScreenDC, wxWindowDC) +#endif + +// Create a DC representing the whole screen +wxScreenDC::wxScreenDC() +{ +#if TARGET_CARBON + m_macPort = GetQDGlobalsThePort() ; + GrafPtr port ; + GetPort( &port ) ; + SetPort( (GrafPtr) m_macPort ) ; + Point pt = { 0,0 } ; + LocalToGlobal( &pt ) ; + SetPort( port ) ; + m_macLocalOrigin.x = -pt.h ; + m_macLocalOrigin.y = -pt.v ; +#else + m_macPort = LMGetWMgrPort() ; + m_macLocalOrigin.x = 0 ; + m_macLocalOrigin.y = 0 ; +#endif + m_ok = TRUE ; + BitMap screenBits; + GetQDGlobalsScreenBits( &screenBits ); + m_minX = screenBits.bounds.left ; + #if TARGET_CARBON + SInt16 height ; + GetThemeMenuBarHeight( &height ) ; + m_minY = screenBits.bounds.top + height ; + #else + m_minY = screenBits.bounds.top + LMGetMBarHeight() ; + #endif + m_maxX = screenBits.bounds.right ; + m_maxY = screenBits.bounds.bottom ; + MacSetRectRgn( (RgnHandle) m_macBoundaryClipRgn , m_minX , m_minY , m_maxX , m_maxY ) ; + OffsetRgn( (RgnHandle) m_macBoundaryClipRgn , m_macLocalOrigin.x , m_macLocalOrigin.y ) ; + CopyRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ; +} + +wxScreenDC::~wxScreenDC() +{ + // TODO +} + diff --git a/src/mac/classic/dialog.cpp b/src/mac/classic/dialog.cpp new file mode 100644 index 0000000000..f29ed3e59e --- /dev/null +++ b/src/mac/classic/dialog.cpp @@ -0,0 +1,268 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: dialog.cpp +// Purpose: wxDialog class +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "dialog.h" +#endif + +#include "wx/dialog.h" +#include "wx/utils.h" +#include "wx/frame.h" +#include "wx/app.h" +#include "wx/settings.h" + +#include "wx/mac/uma.h" + +// Lists to keep track of windows, so we can disable/enable them +// for modal dialogs +wxList wxModalDialogs; +//wxList wxModelessWindows; // Frames and modeless dialogs +extern wxList wxPendingDelete; + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxDialog, wxTopLevelWindow) + +BEGIN_EVENT_TABLE(wxDialog, wxDialogBase) + EVT_BUTTON(wxID_OK, wxDialog::OnOK) + EVT_BUTTON(wxID_APPLY, wxDialog::OnApply) + EVT_BUTTON(wxID_CANCEL, wxDialog::OnCancel) + + EVT_CHAR_HOOK(wxDialog::OnCharHook) + + EVT_SYS_COLOUR_CHANGED(wxDialog::OnSysColourChanged) + + EVT_CLOSE(wxDialog::OnCloseWindow) +END_EVENT_TABLE() + +#endif + +wxDialog::wxDialog() +{ + m_isShown = FALSE; + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)); +} + +bool wxDialog::Create(wxWindow *parent, wxWindowID id, + const wxString& title, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)); + + + if ( !wxTopLevelWindow::Create(parent, id, title, pos, size, style, name) ) + return FALSE; + + MacCreateRealWindow( title , pos , size , MacRemoveBordersFromStyle(style) & ~(wxYES|wxOK|wxNO|wxCANCEL) , name ) ; + + m_macWindowBackgroundTheme = kThemeBrushDialogBackgroundActive ; + SetThemeWindowBackground( (WindowRef) m_macWindow , m_macWindowBackgroundTheme , false ) ; + + return TRUE; +} + +void wxDialog::SetModal(bool flag) +{ + if ( flag ) + { + m_windowStyle |= wxDIALOG_MODAL; + + wxModelessWindows.DeleteObject(this); +#if TARGET_CARBON + SetWindowModality( (WindowRef) MacGetWindowRef() , kWindowModalityAppModal , NULL ) ; +#endif + } + else + { + m_windowStyle &= ~wxDIALOG_MODAL; + + wxModelessWindows.Append(this); + } +} + +wxDialog::~wxDialog() +{ + m_isBeingDeleted = TRUE; + Show(FALSE); +} + +// By default, pressing escape cancels the dialog , on mac command-stop does the same thing +void wxDialog::OnCharHook(wxKeyEvent& event) +{ + if (( event.m_keyCode == WXK_ESCAPE || + ( event.m_keyCode == '.' && event.MetaDown() ) ) + && FindWindow(wxID_CANCEL) ) + { + // Behaviour changed in 2.0: we'll send a Cancel message + // to the dialog instead of Close. + wxCommandEvent cancelEvent(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL); + cancelEvent.SetEventObject( this ); + GetEventHandler()->ProcessEvent(cancelEvent); + + return; + } + // We didn't process this event. + event.Skip(); +} + +bool wxDialog::IsModal() const +{ + return (GetWindowStyleFlag() & wxDIALOG_MODAL) != 0; +} + + +bool wxDialog::IsModalShowing() const +{ + return wxModalDialogs.Find((wxDialog *)this) != NULL; // const_cast +} + +bool wxDialog::Show(bool show) +{ + if ( !wxDialogBase::Show(show) ) + { + // nothing to do + return FALSE; + } + + if ( show ) + { + // usually will result in TransferDataToWindow() being called + InitDialog(); + } + + if ( IsModal() ) + { + if ( show ) + { + DoShowModal(); + } + else // end of modal dialog + { + // this will cause IsModalShowing() return FALSE and our local + // message loop will terminate + wxModalDialogs.DeleteObject(this); + } + } + + return TRUE; +} + +#if !TARGET_CARBON +extern bool s_macIsInModalLoop ; +#endif + +void wxDialog::DoShowModal() +{ + wxCHECK_RET( !IsModalShowing(), _T("DoShowModal() called twice") ); + + wxModalDialogs.Append(this); + +#if TARGET_CARBON + BeginAppModalStateForWindow( (WindowRef) MacGetWindowRef()) ; +#else + // TODO : test whether parent gets disabled + bool formerModal = s_macIsInModalLoop ; + s_macIsInModalLoop = true ; +#endif + while ( IsModalShowing() ) + { + wxTheApp->MacDoOneEvent() ; + // calls process idle itself + } + +#if TARGET_CARBON + EndAppModalStateForWindow( (WindowRef) MacGetWindowRef() ) ; +#else + // TODO probably reenable the parent window if any + s_macIsInModalLoop = formerModal ; +#endif +} + + +// Replacement for Show(TRUE) for modal dialogs - returns return code +int wxDialog::ShowModal() +{ + if ( !IsModal() ) + { + SetModal(TRUE); + } + + Show(TRUE); + return GetReturnCode(); +} + +// NB: this function (surprizingly) may be called for both modal and modeless +// dialogs and should work for both of them +void wxDialog::EndModal(int retCode) +{ + SetReturnCode(retCode); + Show(FALSE); +} + +// Standard buttons +void wxDialog::OnOK(wxCommandEvent& WXUNUSED(event)) +{ + if ( Validate() && TransferDataFromWindow() ) + { + EndModal(wxID_OK); + } +} + +void wxDialog::OnApply(wxCommandEvent& WXUNUSED(event)) +{ + if (Validate()) + TransferDataFromWindow(); + // TODO probably need to disable the Apply button until things change again +} + +void wxDialog::OnCancel(wxCommandEvent& WXUNUSED(event)) +{ + EndModal(wxID_CANCEL); +} + +void wxDialog::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) +{ + // We'll send a Cancel message by default, + // which may close the dialog. + // Check for looping if the Cancel event handler calls Close(). + + // Note that if a cancel button and handler aren't present in the dialog, + // nothing will happen when you close the dialog via the window manager, or + // via Close(). + // We wouldn't want to destroy the dialog by default, since the dialog may have been + // created on the stack. + // However, this does mean that calling dialog->Close() won't delete the dialog + // unless the handler for wxID_CANCEL does so. So use Destroy() if you want to be + // sure to destroy the dialog. + // The default OnCancel (above) simply ends a modal dialog, and hides a modeless dialog. + + static wxList closing; + + if ( closing.Member(this) ) + return; + + closing.Append(this); + + wxCommandEvent cancelEvent(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL); + cancelEvent.SetEventObject( this ); + GetEventHandler()->ProcessEvent(cancelEvent); // This may close the dialog + + closing.DeleteObject(this); +} + +void wxDialog::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event)) +{ + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)); + Refresh(); +} + diff --git a/src/mac/classic/dirdlg.cpp b/src/mac/classic/dirdlg.cpp new file mode 100644 index 0000000000..0b4c7df195 --- /dev/null +++ b/src/mac/classic/dirdlg.cpp @@ -0,0 +1,146 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: dirdlg.cpp +// Purpose: wxDirDialog +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "dirdlg.h" +#endif + +#include "wx/defs.h" +#include "wx/utils.h" +#include "wx/dialog.h" +#include "wx/dirdlg.h" + +#include "wx/cmndata.h" + +#include "wx/mac/private.h" + +#ifdef __DARWIN__ + #include +#else + #include +#endif + +#if !USE_SHARED_LIBRARY +IMPLEMENT_CLASS(wxDirDialog, wxDialog) +#endif + +wxDirDialog::wxDirDialog(wxWindow *parent, + const wxString& message, + const wxString& defaultPath, + long style, + const wxPoint& WXUNUSED(pos), + const wxSize& WXUNUSED(size), + const wxString& WXUNUSED(name)) +{ + wxASSERT_MSG( NavServicesAvailable() , wxT("Navigation Services are not running") ) ; + m_message = message; + m_dialogStyle = style; + m_parent = parent; + m_path = defaultPath; +} + +int wxDirDialog::ShowModal() +{ + NavDialogOptions mNavOptions; + NavObjectFilterUPP mNavFilterUPP = NULL; + NavPreviewUPP mNavPreviewUPP = NULL ; + NavReplyRecord mNavReply; + AEDesc* mDefaultLocation = NULL ; + bool mSelectDefault = false ; + + ::NavGetDefaultDialogOptions(&mNavOptions); + + mNavFilterUPP = nil; + mNavPreviewUPP = nil; + mSelectDefault = false; + mNavReply.validRecord = false; + mNavReply.replacing = false; + mNavReply.isStationery = false; + mNavReply.translationNeeded = false; + mNavReply.selection.descriptorType = typeNull; + mNavReply.selection.dataHandle = nil; + mNavReply.keyScript = smSystemScript; + mNavReply.fileTranslation = nil; + + // Set default location, the location + // that's displayed when the dialog + // first appears + + if ( mDefaultLocation ) { + + if (mSelectDefault) { + mNavOptions.dialogOptionFlags |= kNavSelectDefaultLocation; + } else { + mNavOptions.dialogOptionFlags &= ~kNavSelectDefaultLocation; + } + } + + OSErr err = ::NavChooseFolder( + mDefaultLocation, + &mNavReply, + &mNavOptions, + NULL, + mNavFilterUPP, + 0L); // User Data + + if ( (err != noErr) && (err != userCanceledErr) ) { + m_path = wxT("") ; + return wxID_CANCEL ; + } + + if (mNavReply.validRecord) { // User chose a folder + + FSSpec folderInfo; + FSSpec outFileSpec ; + AEDesc specDesc ; + + OSErr err = ::AECoerceDesc( &mNavReply.selection , typeFSS, &specDesc); + if ( err != noErr ) { + m_path = wxT("") ; + return wxID_CANCEL ; + } + folderInfo = **(FSSpec**) specDesc.dataHandle; + if (specDesc.dataHandle != nil) { + ::AEDisposeDesc(&specDesc); + } + +// mNavReply.GetFileSpec(folderInfo); + + // The FSSpec from NavChooseFolder is NOT the file spec + // for the folder. The parID field is actually the DirID + // of the folder itself, not the folder's parent, and + // the name field is empty. We must call PBGetCatInfo + // to get the parent DirID and folder name + + Str255 name; + CInfoPBRec thePB; // Directory Info Parameter Block + thePB.dirInfo.ioCompletion = nil; + thePB.dirInfo.ioVRefNum = folderInfo.vRefNum; // Volume is right + thePB.dirInfo.ioDrDirID = folderInfo.parID; // Folder's DirID + thePB.dirInfo.ioNamePtr = name; + thePB.dirInfo.ioFDirIndex = -1; // Lookup using Volume and DirID + + err = ::PBGetCatInfoSync(&thePB); + if ( err != noErr ) { + m_path = wxT("") ; + return wxID_CANCEL ; + } + // Create cannonical FSSpec + ::FSMakeFSSpec(thePB.dirInfo.ioVRefNum, thePB.dirInfo.ioDrParID, + name, &outFileSpec); + + // outFolderDirID = thePB.dirInfo.ioDrDirID; + m_path = wxMacFSSpec2MacFilename( &outFileSpec ) ; + return wxID_OK ; + } + return wxID_CANCEL; +} + diff --git a/src/mac/classic/dirmac.cpp b/src/mac/classic/dirmac.cpp new file mode 100644 index 0000000000..0afc3b5cb3 --- /dev/null +++ b/src/mac/classic/dirmac.cpp @@ -0,0 +1,322 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: msw/dir.cpp +// Purpose: wxDir implementation for Mac +// Author: Stefan Csomor +// Modified by: +// Created: 08.12.99 +// RCS-ID: $Id$ +// Copyright: (c) 1999 Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#ifdef __GNUG__ + #pragma implementation "dir.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" +#endif // PCH + +#include "wx/dir.h" +#include "wx/filefn.h" // for wxPathExists() + +#ifndef __DARWIN__ + #include +#endif + +#include "wx/mac/private.h" + +#ifdef __DARWIN__ +# include "MoreFilesX.h" +#else +# include "MoreFiles.h" +# include "MoreFilesExtras.h" +#endif + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +#ifndef MAX_PATH + #define MAX_PATH 260 // from VC++ headers +#endif + +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- + +#define M_DIR ((wxDirData *)m_data) + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// this class stores everything we need to enumerate the files +class wxDirData +{ +public: + wxDirData(const wxString& dirname); + ~wxDirData(); + + void SetFileSpec(const wxString& filespec) { m_filespec = filespec; } + void SetFlags(int flags) { m_flags = flags; } + + bool Read(wxString *filename); // reads the next + void Rewind() ; + + const wxString& GetName() const { return m_dirname; } + bool Ok() const { return m_ok; } + +private: + CInfoPBRec m_CPB ; + wxInt16 m_index ; + long m_dirId ; + Str255 m_name ; + Boolean m_isDir ; + + wxString m_dirname; + wxString m_filespec; + + int m_flags; + bool m_ok; +}; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxDirData +// ---------------------------------------------------------------------------- + +wxDirData::wxDirData(const wxString& dirname) + : m_dirname(dirname) +{ + m_ok = false; + + OSErr err; + + // throw away the trailing slashes + size_t n = m_dirname.length(); + wxCHECK_RET( n, _T("empty dir name in wxDir") ); + + while ( n > 0 && wxIsPathSeparator(m_dirname[--n]) ) + ; + + m_dirname.Truncate(n + 1); + +#ifdef __DARWIN__ + FSRef theRef; + + // get the FSRef associated with the POSIX path + err = FSPathMakeRef((const UInt8 *) m_dirname.c_str(), &theRef, NULL); + FSGetVRefNum(&theRef, &(m_CPB.hFileInfo.ioVRefNum)); + + err = FSGetNodeID( &theRef , &m_dirId , &m_isDir ) ; +#else + FSSpec fsspec ; + + wxMacFilename2FSSpec( m_dirname , &fsspec ) ; + m_CPB.hFileInfo.ioVRefNum = fsspec.vRefNum ; + + err = FSpGetDirectoryID( &fsspec , &m_dirId , &m_isDir ) ; +#endif + //wxASSERT_MSG( (err == noErr) || (err == nsvErr) , wxT("Error accessing directory " + m_dirname)) ; + if ( (err == noErr) || (err == nsvErr)) + m_ok = true; + else + wxLogError(wxString(wxT("Error accessing directory ")) + m_dirname); + + m_CPB.hFileInfo.ioNamePtr = m_name ; + m_index = 0 ; +} + +wxDirData::~wxDirData() +{ +} + +void wxDirData::Rewind() +{ + m_index = 0 ; +} + +bool wxDirData::Read(wxString *filename) +{ + if ( !m_isDir ) + return FALSE ; + + wxString result; + + short err = noErr ; + + while ( err == noErr ) + { + m_index++ ; + m_CPB.dirInfo.ioFDirIndex = m_index; + m_CPB.dirInfo.ioDrDirID = m_dirId; /* we need to do this every time */ + err = PBGetCatInfoSync((CInfoPBPtr)&m_CPB); + if ( err != noErr ) + break ; + + // its hidden but we don't want it + if ( ( m_CPB.hFileInfo.ioFlFndrInfo.fdFlags & kIsInvisible ) && !(m_flags & wxDIR_HIDDEN) ) + continue ; +#ifdef __DARWIN__ + // under X, names that start with '.' are hidden + if ( ( m_name[1] == '.' ) && !(m_flags & wxDIR_HIDDEN) ) + continue; +#endif +#if TARGET_CARBON + // under X thats the way the mounting points look like + if ( ( m_CPB.dirInfo.ioDrDirID == 0 ) && ( m_flags & wxDIR_DIRS) ) + break ; +#endif + // we have a directory + if ( ( m_CPB.dirInfo.ioFlAttrib & ioDirMask) != 0 && (m_flags & wxDIR_DIRS) ) + break ; + + // its a file but we don't want it + if ( ( m_CPB.dirInfo.ioFlAttrib & ioDirMask) == 0 && !(m_flags & wxDIR_FILES ) ) + continue ; + + wxString file = wxMacMakeStringFromPascal( m_name ) ; + if ( m_filespec.IsEmpty() || m_filespec == wxT("*.*") || m_filespec == wxT("*") ) + { + } + else if ( m_filespec.Length() > 1 && m_filespec.Left(1) == wxT("*") ) + { + if ( file.Right( m_filespec.Length() - 1 ).Upper() != m_filespec.Mid(1).Upper() ) + { + continue ; + } + } + else if ( m_filespec.Length() > 1 && m_filespec.Right(1) == wxT("*") ) + { + if ( file.Left( m_filespec.Length() - 1 ).Upper() != m_filespec.Left( m_filespec.Length() - 1 ).Upper() ) + { + continue ; + } + } + else if ( file.Upper() != m_filespec.Upper() ) + { + continue ; + } + + break ; + } + if ( err != noErr ) + { + return FALSE ; + } + + *filename = wxMacMakeStringFromPascal( m_name ) ; + + return TRUE; +} + +// ---------------------------------------------------------------------------- +// wxDir helpers +// ---------------------------------------------------------------------------- + +/* static */ +bool wxDir::Exists(const wxString& dir) +{ + return wxPathExists(dir); +} + +// ---------------------------------------------------------------------------- +// wxDir construction/destruction +// ---------------------------------------------------------------------------- + +wxDir::wxDir(const wxString& dirname) +{ + m_data = NULL; + + (void)Open(dirname); +} + +bool wxDir::Open(const wxString& dirname) +{ + delete M_DIR; + m_data = new wxDirData(dirname); + if (m_data->Ok()) + return TRUE; + else + { + delete m_data; + m_data = NULL; + return FALSE; + } +} + +bool wxDir::IsOpened() const +{ + return m_data != NULL; +} + +wxString wxDir::GetName() const +{ + wxString name; + if ( m_data ) + { + name = M_DIR->GetName(); + if ( !name.empty() && (name.Last() == _T('/')) ) + { + // chop off the last (back)slash + name.Truncate(name.length() - 1); + } + } + + return name; +} + +wxDir::~wxDir() +{ + if (M_DIR != NULL) { + delete M_DIR; + m_data = NULL; + } +} + +// ---------------------------------------------------------------------------- +// wxDir enumerating +// ---------------------------------------------------------------------------- + +bool wxDir::GetFirst(wxString *filename, + const wxString& filespec, + int flags) const +{ + wxCHECK_MSG( IsOpened(), FALSE, _T("must wxDir::Open() first") ); + + M_DIR->Rewind(); + + M_DIR->SetFileSpec(filespec); + M_DIR->SetFlags(flags); + + return GetNext(filename); +} + +bool wxDir::GetNext(wxString *filename) const +{ + wxCHECK_MSG( IsOpened(), FALSE, _T("must wxDir::Open() first") ); + + wxCHECK_MSG( filename, FALSE, _T("bad pointer in wxDir::GetNext()") ); + + return M_DIR->Read(filename); +} diff --git a/src/mac/classic/display.cpp b/src/mac/classic/display.cpp new file mode 100644 index 0000000000..8786306211 --- /dev/null +++ b/src/mac/classic/display.cpp @@ -0,0 +1,446 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: display.cpp +// Purpose: Mac implementation of wxDisplay class +// Author: Brian Victor +// Modified by: Royce Mitchell III & Ryan Norton +// Created: 06/21/02 +// RCS-ID: $Id$ +// Copyright: (c) wxWindows team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ + #pragma implementation "display.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_DISPLAY + +#ifndef WX_PRECOMP + #include "wx/dynarray.h" + #include "wx/log.h" + #include "wx/msgdlg.h" +#endif + +#ifdef __DARWIN__ + #include +#else + #include + #include + #include + #include //for VDSwitchInfoRec + #include +#endif + +#include "wx/display.h" +#include "wx/gdicmn.h" +#include "wx/string.h" + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +class wxDisplayMacPriv +{ +public: + GDHandle m_hndl; +}; + +size_t wxDisplayBase::GetCount() +{ + GDHandle hndl; + size_t num = 0; + hndl = DMGetFirstScreenDevice(true); + while(hndl) + { + num++; + hndl = DMGetNextScreenDevice(hndl, true); + } + return num; +} + +int wxDisplayBase::GetFromPoint(const wxPoint &p) +{ + GDHandle hndl; + size_t num = 0; + hndl = DMGetFirstScreenDevice(true); + while(hndl) + { + Rect screenrect = (*hndl)->gdRect; + if (p.x >= screenrect.left && + p.x <= screenrect.right && + p.y >= screenrect.top && + p.y <= screenrect.bottom) + { + return num; + } + num++; + hndl = DMGetNextScreenDevice(hndl, true); + } + return -1; +} + +wxDisplay::wxDisplay(size_t index) : wxDisplayBase ( index ), + m_priv ( new wxDisplayMacPriv() ) +{ + GDHandle hndl; + hndl = DMGetFirstScreenDevice(true); + m_priv->m_hndl = NULL; + while(hndl) + { + if (index == 0) + { + m_priv->m_hndl = hndl; + } + index--; + hndl = DMGetNextScreenDevice(hndl, true); + } +} + +wxRect wxDisplay::GetGeometry() const +{ + if (!(m_priv)) return wxRect(0, 0, 0, 0); + if (!(m_priv->m_hndl)) return wxRect(0, 0, 0, 0); + Rect screenrect = (*(m_priv->m_hndl))->gdRect; + return wxRect( screenrect.left, screenrect.top, + screenrect.right - screenrect.left, screenrect.bottom - screenrect.top); +} + +int wxDisplay::GetDepth() const +{ + if (!(m_priv)) return 0; + if (!(m_priv->m_hndl)) return 0; + + // This cryptic looking code is based on Apple's sample code: + // http://developer.apple.com/samplecode/Sample_Code/Graphics_2D/GDevVideo/Gen.cp.htm + + //RN - according to the docs + //gdPMap is a bitmap-type representation of the GDevice, and all + //0x0000FFFF does is get the lower 16 bits of pixelSize. However, + //since pixelSize is only 16 bits (a short)... + return ((*(*(m_priv->m_hndl))->gdPMap)->pixelSize) & 0x0000FFFF; +} + +wxString wxDisplay::GetName() const +{ + // Macs don't name their displays... + return wxEmptyString; +} + +struct DMModeIteratorRec +{ + wxArrayVideoModes* pModes; + const wxVideoMode* pMatchMode; +}; + +pascal void DMModeListIteratorProc ( void* pData, + DMListIndexType nIndex, + DMDisplayModeListEntryPtr pInfo) +{ + DMModeIteratorRec* pInfoData = (DMModeIteratorRec*) pData; + + //Note that in testing the refresh rate is always 0 on my ibook - RN + int refresh = (int) Fix2Long(pInfo->displayModeResolutionInfo->csRefreshRate); + + for(unsigned long i = 0; i < pInfo->displayModeDepthBlockInfo->depthBlockCount; ++i) + { +#define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock + + if (wxVideoMode((int) pInfo->displayModeResolutionInfo->csHorizontalPixels, + (int) pInfo->displayModeResolutionInfo->csVerticalLines, + (int) pDBI->vpPixelSize, + refresh).Matches(*pInfoData->pMatchMode) ) + { + pInfoData->pModes->Add(wxVideoMode((int) pInfo->displayModeResolutionInfo->csHorizontalPixels, + (int) pInfo->displayModeResolutionInfo->csVerticalLines, + (int) pDBI->vpPixelSize, + refresh)); + } +#undef pDBI + } +} + +struct DMModeInfoRec +{ + const wxVideoMode* pMode; + VDSwitchInfoRec sMode; + bool bMatched; +}; + +pascal void DMModeInfoProc ( void* pData, + DMListIndexType nIndex, + DMDisplayModeListEntryPtr pInfo) +{ + DMModeInfoRec* pInfoData = (DMModeInfoRec*) pData; + Fixed refresh = Long2Fix(pInfoData->pMode->refresh); + + for(unsigned long i = 0; i < pInfo->displayModeDepthBlockInfo->depthBlockCount; ++i) + { +#define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock + if (pInfoData->pMode->w == (int&) pInfo->displayModeResolutionInfo->csHorizontalPixels && + pInfoData->pMode->h == (int&) pInfo->displayModeResolutionInfo->csVerticalLines && + pInfoData->pMode->bpp == (int) pDBI->vpPixelSize && + refresh == pInfo->displayModeResolutionInfo->csRefreshRate) + { + memcpy(&pInfoData->sMode, pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthSwitchInfo, + sizeof(VDSwitchInfoRec)); + pInfoData->sMode.csMode = pDBI->vpPixelSize; + pInfoData->bMatched = true; + break; + } +#undef pDBI + } +} + +struct DMModeTransRec +{ + wxVideoMode Mode; + const VDSwitchInfoRec* psMode; + bool bMatched; +}; + +pascal void DMModeTransProc ( void* pData, + DMListIndexType nIndex, + DMDisplayModeListEntryPtr pInfo) +{ + DMModeTransRec* pInfoData = (DMModeTransRec*) pData; + + for(unsigned long i = 0; i < pInfo->displayModeDepthBlockInfo->depthBlockCount; ++i) + { +#define pDBI pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthVPBlock + if (pInfoData->psMode->csData == pInfo->displayModeDepthBlockInfo->depthVPBlock[i].depthSwitchInfo->csData) + { + pInfoData->Mode = wxVideoMode((int) pInfo->displayModeResolutionInfo->csHorizontalPixels, + (int) pInfo->displayModeResolutionInfo->csVerticalLines, + (int) pDBI->vpPixelSize, + (int) Fix2Long(pInfo->displayModeResolutionInfo->csRefreshRate) ); + pInfoData->bMatched = true; + break; + } +#undef pDBI + } +} + +wxArrayVideoModes + wxDisplay::GetModes(const wxVideoMode& mode) const +{ + + wxArrayVideoModes Modes; + + unsigned long dwDMVer; + Gestalt(gestaltDisplayMgrVers, (long*) &dwDMVer); + + //Check DM version (for backward compatibility only - 7.5.3+ use 2.0) + if (dwDMVer >= 0x020000) //version 2? + { + + DMListIndexType nNumModes; + DMListType pModes; + DMDisplayModeListIteratorUPP uppMLI; + DisplayIDType nDisplayID; + + wxASSERT(DMGetDisplayIDByGDevice(m_priv->m_hndl, &nDisplayID, false) == noErr); + //Create a new list... + wxASSERT_MSG(DMNewDisplayModeList(nDisplayID, NULL, NULL, &nNumModes, &pModes) == noErr, wxT("Could not create a new display mode list") ); + + uppMLI = NewDMDisplayModeListIteratorUPP(DMModeListIteratorProc); + wxASSERT(uppMLI); + + DMModeIteratorRec sModeInfo; + sModeInfo.pModes = &Modes; + sModeInfo.pMatchMode = &mode; + for (DMListIndexType i = 0; i < nNumModes; ++i) + { + wxASSERT(DMGetIndexedDisplayModeFromList(pModes, i, NULL, + uppMLI, &sModeInfo) == noErr); + } + DisposeDMDisplayModeListIteratorUPP(uppMLI); + wxASSERT(DMDisposeList(pModes) == noErr); + } + else //DM 1.0, 1.2, 1.x + { + wxLogSysError(wxString::Format(wxT("Display Manager Version %u Not Supported! Present? %s"), + (unsigned int) dwDMVer / 0x10000, + (dwDMVer & (1 << gestaltDisplayMgrPresent) ? wxT("Yes") : wxT("No")) ) + ); + } + + return Modes; +} + +wxVideoMode wxDisplay::GetCurrentMode() const +{ + unsigned long dwDMVer; + wxVideoMode RetMode; + + Gestalt(gestaltDisplayMgrVers, (long*) &dwDMVer); + //Check DM version (for backward compatibility only - 7.5.3+ use 2.0) + if (dwDMVer >= 0x020000) //version 2? + { + VDSwitchInfoRec sMode; //Note - csMode member also contains the bit depth + if (DMGetDisplayMode(m_priv->m_hndl, &sMode) == noErr) + { + DMListIndexType nNumModes; + DMListType pModes; + DMDisplayModeListIteratorUPP uppMLI; + DisplayIDType nDisplayID; + + wxASSERT(DMGetDisplayIDByGDevice(m_priv->m_hndl, &nDisplayID, false) == noErr); + //Create a new list... + wxASSERT_MSG(DMNewDisplayModeList(nDisplayID, NULL, NULL, &nNumModes, &pModes) == noErr, + wxT("Could not create a new display mode list") ); + + uppMLI = NewDMDisplayModeListIteratorUPP(DMModeTransProc); + wxASSERT(uppMLI); + + DMModeTransRec sModeInfo; + sModeInfo.bMatched = false; + sModeInfo.psMode = &sMode; + for (DMListIndexType i = 0; i < nNumModes; ++i) + { + wxASSERT(DMGetIndexedDisplayModeFromList(pModes, i, NULL, + uppMLI, &sModeInfo) == noErr); + + if ( sModeInfo.bMatched == true ) + { + RetMode = sModeInfo.Mode; + break; + } + } + + DisposeDMDisplayModeListIteratorUPP(uppMLI); + wxASSERT(DMDisposeList(pModes) == noErr); + } + else //Can't get current mode? + { + wxLogSysError(wxString::Format(wxT("Couldn't obtain current display mode!!!\ndwDMVer:%u"), + (unsigned int) dwDMVer)); + } + } + else //DM ver 1 + { + wxLogSysError(wxString::Format(wxT("Display Manager Version %u Not Supported! Present? %s"), + (unsigned int) dwDMVer / 0x10000, + (dwDMVer & (1 << gestaltDisplayMgrPresent) ? wxT("Yes") : wxT("No")) ) + ); + } + + return RetMode; +} + +bool wxDisplay::ChangeMode(const wxVideoMode& mode) +{ + unsigned long dwDMVer; + Gestalt(gestaltDisplayMgrVers, (long*)&dwDMVer); + if (GetCount() == 1 || dwDMVer >= 0x020000) + { + if (mode == wxDefaultVideoMode) + { +//#ifndef __DARWIN__ +// Handle hDisplayState; +// if (DMBeginConfigureDisplays(&hDisplayState) != noErr) +// { +// wxLogSysError(wxT("Could not lock display for display mode changing!")); +// return false; +// } +// wxASSERT( DMUseScreenPrefs(true, hDisplayState) == noErr); +// DMEndConfigureDisplays(hDisplayState); +// return true; +//#else + //hmmmmm.... + return true; +//#endif + } + + //0 & NULL for params 2 & 3 of DMSetVideoMode signal it to use defaults (current mode) + //DM 2.0+ doesn't use params 2 & 3 of DMSetDisplayMode + //so we have to use this icky structure + VDSwitchInfoRec sMode; + memset(&sMode, 0, sizeof(VDSwitchInfoRec) ); + + DMListIndexType nNumModes; + DMListType pModes; + DMDisplayModeListIteratorUPP uppMLI; + DisplayIDType nDisplayID; + + wxASSERT(DMGetDisplayIDByGDevice(m_priv->m_hndl, &nDisplayID, false) == noErr); + //Create a new list... + wxASSERT_MSG(DMNewDisplayModeList(nDisplayID, NULL, NULL, &nNumModes, &pModes) == noErr, + wxT("Could not create a new display mode list") ); + + uppMLI = NewDMDisplayModeListIteratorUPP(DMModeInfoProc); + wxASSERT(uppMLI); + + DMModeInfoRec sModeInfo; + sModeInfo.bMatched = false; + sModeInfo.pMode = &mode; + unsigned int i; + for(i = 0; i < nNumModes; ++i) + { + wxASSERT(DMGetIndexedDisplayModeFromList(pModes, i, NULL, + uppMLI, &sModeInfo) == noErr); + if (sModeInfo.bMatched == true) + { + sMode = sModeInfo.sMode; + break; + } + } + if(i == nNumModes) + return false; + + DisposeDMDisplayModeListIteratorUPP(uppMLI); + wxASSERT(DMDisposeList(pModes) == noErr); + + // For the really paranoid - + // unsigned long flags; + // Boolean bok; + // wxASSERT(noErr == DMCheckDisplayMode(m_priv->m_hndl, sMode.csData, + // sMode.csMode, &flags, NULL, &bok)); + // wxASSERT(bok); + + Handle hDisplayState; + if (DMBeginConfigureDisplays(&hDisplayState) != noErr) + { + wxLogSysError(wxT("Could not lock display for display mode changing!")); + return false; + } + + unsigned long dwBPP = (unsigned long) mode.bpp; + if (DMSetDisplayMode(m_priv->m_hndl, sMode.csData, + (unsigned long*) &(dwBPP), NULL + //(unsigned long) &sMode + , hDisplayState + ) != noErr) + { + DMEndConfigureDisplays(hDisplayState); + wxMessageBox(wxString::Format(wxT("Could not set the display mode"))); + return false; + } + DMEndConfigureDisplays(hDisplayState); + } + else //DM 1.0, 1.2, 1.x + { + wxLogSysError(wxString::Format(wxT("Monitor gravitation not supported yet. dwDMVer:%u"), + (unsigned int) dwDMVer)); + return false; + } + + return true; +} + +wxDisplay::~wxDisplay() +{ + if ( m_priv ) + { + delete m_priv; + m_priv = 0; + } +} + +#endif // wxUSE_DISPLAY diff --git a/src/mac/classic/dnd.cpp b/src/mac/classic/dnd.cpp new file mode 100644 index 0000000000..22ced39ede --- /dev/null +++ b/src/mac/classic/dnd.cpp @@ -0,0 +1,607 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: dnd.cpp +// Purpose: wxDropTarget, wxDropSource, wxDataObject implementation +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) 1998 Stefan Csomor +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "dnd.h" +#endif + +#include "wx/defs.h" + +#if wxUSE_DRAG_AND_DROP + +#include "wx/dnd.h" +#include "wx/window.h" +#include "wx/toplevel.h" +#include "wx/app.h" +#include "wx/gdicmn.h" +#include "wx/mac/private.h" + +// ---------------------------------------------------------------------------- +// global +// ---------------------------------------------------------------------------- + +void wxMacEnsureTrackingHandlersInstalled() ; + +typedef struct +{ + wxWindow* m_currentTargetWindow ; + wxDropTarget* m_currentTarget ; + wxDropSource* m_currentSource ; +} MacTrackingGlobals ; + +MacTrackingGlobals gTrackingGlobals ; + +//---------------------------------------------------------------------------- +// wxDropTarget +//---------------------------------------------------------------------------- + +wxDropTarget::wxDropTarget( wxDataObject *data ) + : wxDropTargetBase( data ) +{ + wxMacEnsureTrackingHandlersInstalled() ; +} + +wxDragResult wxDropTarget::OnDragOver( wxCoord WXUNUSED(x), + wxCoord WXUNUSED(y), + wxDragResult def ) +{ + + return CurrentDragHasSupportedFormat() ? def : wxDragNone; +} + +bool wxDropTarget::OnDrop( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y) ) +{ + if (!m_dataObject) + return FALSE; + + return CurrentDragHasSupportedFormat() ; +} + +wxDragResult wxDropTarget::OnData( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), + wxDragResult def ) +{ + if (!m_dataObject) + return wxDragNone; + + if (!CurrentDragHasSupportedFormat()) + return wxDragNone; + + return GetData() ? def : wxDragNone; +} + +bool wxDropTarget::CurrentDragHasSupportedFormat() +{ + bool supported = false ; + if ( gTrackingGlobals.m_currentSource != NULL ) + { + wxDataObject* data = gTrackingGlobals.m_currentSource->GetDataObject() ; + + if ( data ) + { + size_t formatcount = data->GetFormatCount() ; + wxDataFormat *array = new wxDataFormat[ formatcount ]; + data->GetAllFormats( array ); + for (size_t i = 0; !supported && i < formatcount ; i++) + { + wxDataFormat format = array[i] ; + if ( m_dataObject->IsSupported( format ) ) + { + supported = true ; + break ; + } + } + delete[] array ; + } + } + if ( !supported ) + { + UInt16 items ; + OSErr result; + CountDragItems((DragReference)m_currentDrag, &items); + for (UInt16 index = 1; index <= items && supported == false ; ++index) + { + ItemReference theItem; + FlavorType theType ; + UInt16 flavors = 0 ; + GetDragItemReferenceNumber((DragReference)m_currentDrag, index, &theItem); + CountDragItemFlavors( (DragReference)m_currentDrag, theItem , &flavors ) ; + for ( UInt16 flavor = 1 ; flavor <= flavors ; ++flavor ) + { + result = GetFlavorType((DragReference)m_currentDrag, theItem, flavor , &theType); + if ( m_dataObject->IsSupportedFormat( wxDataFormat( theType ) ) ) + { + supported = true ; + break ; + } + } + } + } + return supported ; +} + +bool wxDropTarget::GetData() +{ + if (!m_dataObject) + return FALSE; + + if ( !CurrentDragHasSupportedFormat() ) + return FALSE ; + + bool transferred = false ; + if ( gTrackingGlobals.m_currentSource != NULL ) + { + wxDataObject* data = gTrackingGlobals.m_currentSource->GetDataObject() ; + + if ( data ) + { + size_t formatcount = data->GetFormatCount() ; + wxDataFormat *array = new wxDataFormat[ formatcount ]; + data->GetAllFormats( array ); + for (size_t i = 0; !transferred && i < formatcount ; i++) + { + wxDataFormat format = array[i] ; + if ( m_dataObject->IsSupported( format ) ) + { + int size = data->GetDataSize( format ); + transferred = true ; + + if (size == 0) + { + m_dataObject->SetData(format , 0 , 0 ) ; + } + else + { + char *d = new char[size]; + data->GetDataHere( format , (void*) d ); + m_dataObject->SetData( format , size , d ) ; + delete[] d ; + } + } + } + delete[] array ; + } + } + if ( !transferred ) + { + UInt16 items ; + OSErr result; + bool firstFileAdded = false ; + CountDragItems((DragReference)m_currentDrag, &items); + for (UInt16 index = 1; index <= items; ++index) + { + ItemReference theItem; + FlavorType theType ; + UInt16 flavors = 0 ; + GetDragItemReferenceNumber((DragReference)m_currentDrag, index, &theItem); + CountDragItemFlavors( (DragReference)m_currentDrag, theItem , &flavors ) ; + for ( UInt16 flavor = 1 ; flavor <= flavors ; ++flavor ) + { + result = GetFlavorType((DragReference)m_currentDrag, theItem, flavor , &theType); + wxDataFormat format(theType) ; + if ( m_dataObject->IsSupportedFormat( format ) ) + { + FlavorFlags theFlags; + result = GetFlavorFlags((DragReference)m_currentDrag, theItem, theType, &theFlags); + if (result == noErr) + { + Size dataSize ; + Ptr theData ; + GetFlavorDataSize((DragReference)m_currentDrag, theItem, theType, &dataSize); + if ( theType == 'TEXT' ) + { + // this increment is only valid for allocating, on the next GetFlavorData + // call it is reset again to the original value + dataSize++ ; + } + theData = new char[dataSize]; + GetFlavorData((DragReference)m_currentDrag, theItem, theType, (void*) theData, &dataSize, 0L); + if( theType == 'TEXT' ) + { + theData[dataSize]=0 ; + wxString convert( theData , wxConvLocal ) ; + m_dataObject->SetData( format, convert.Length() * sizeof(wxChar), (const wxChar*) convert ); + } + else if ( theType == kDragFlavorTypeHFS ) + { + HFSFlavor* theFile = (HFSFlavor*) theData ; + wxString name = wxMacFSSpec2MacFilename( &theFile->fileSpec ) ; + if ( firstFileAdded ) + ((wxFileDataObject*)m_dataObject)->AddFile( name ) ; + else + { + ((wxFileDataObject*)m_dataObject)->SetData( 0 , name.c_str() ) ; + firstFileAdded = true ; + } + } + else + { + m_dataObject->SetData( format, dataSize, theData ); + } + delete[] theData; + } + break ; + } + } + } + } + return TRUE ; +} + +//------------------------------------------------------------------------- +// wxDropSource +//------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// drag request + +wxDropSource::wxDropSource(wxWindow *win, + const wxCursor &cursorCopy, + const wxCursor &cursorMove, + const wxCursor &cursorStop) + : wxDropSourceBase(cursorCopy, cursorMove, cursorStop) +{ + wxMacEnsureTrackingHandlersInstalled() ; + m_window = win; +} + +wxDropSource::wxDropSource(wxDataObject& data, + wxWindow *win, + const wxCursor &cursorCopy, + const wxCursor &cursorMove, + const wxCursor &cursorStop) + : wxDropSourceBase(cursorCopy, cursorMove, cursorStop) +{ + wxMacEnsureTrackingHandlersInstalled() ; + SetData( data ); + m_window = win; +} + +wxDropSource::~wxDropSource() +{ +} + + +wxDragResult wxDropSource::DoDragDrop(int WXUNUSED(flags)) +{ + wxASSERT_MSG( m_data, wxT("Drop source: no data") ); + + if (!m_data) + return (wxDragResult) wxDragNone; + + if (m_data->GetFormatCount() == 0) + return (wxDragResult) wxDragNone; + + OSErr result; + DragReference theDrag; + RgnHandle dragRegion; + if ((result = NewDrag(&theDrag))) + { + return wxDragNone ; + } + // add data to drag + size_t formatCount = m_data->GetFormatCount() ; + wxDataFormat *formats = new wxDataFormat[formatCount] ; + m_data->GetAllFormats( formats ) ; + ItemReference theItem = 1 ; + for ( size_t i = 0 ; i < formatCount ; ++i ) + { + size_t dataSize = m_data->GetDataSize( formats[i] ) ; + Ptr dataPtr = new char[dataSize] ; + m_data->GetDataHere( formats[i] , dataPtr ) ; + OSType type = formats[i].GetFormatId() ; + if ( type == 'TEXT' ) + { + dataSize-- ; + dataPtr[ dataSize ] = 0 ; + wxString st( (wxChar*) dataPtr ) ; + wxCharBuffer buf = st.mb_str( wxConvLocal) ; + AddDragItemFlavor(theDrag, theItem, type , buf.data(), strlen(buf), 0); + } + else if (type == kDragFlavorTypeHFS ) + { + HFSFlavor theFlavor ; + OSErr err = noErr; + CInfoPBRec cat; + + wxMacFilename2FSSpec( dataPtr , &theFlavor.fileSpec ) ; + + cat.hFileInfo.ioNamePtr = theFlavor.fileSpec.name; + cat.hFileInfo.ioVRefNum = theFlavor.fileSpec.vRefNum; + cat.hFileInfo.ioDirID = theFlavor.fileSpec.parID; + cat.hFileInfo.ioFDirIndex = 0; + err = PBGetCatInfoSync(&cat); + if (err == noErr ) + { + theFlavor.fdFlags = cat.hFileInfo.ioFlFndrInfo.fdFlags; + if (theFlavor.fileSpec.parID == fsRtParID) { + theFlavor.fileCreator = 'MACS'; + theFlavor.fileType = 'disk'; + } else if ((cat.hFileInfo.ioFlAttrib & ioDirMask) != 0) { + theFlavor.fileCreator = 'MACS'; + theFlavor.fileType = 'fold'; + } else { + theFlavor.fileCreator = cat.hFileInfo.ioFlFndrInfo.fdCreator; + theFlavor.fileType = cat.hFileInfo.ioFlFndrInfo.fdType; + } + AddDragItemFlavor(theDrag, theItem, type , &theFlavor, sizeof(theFlavor), 0); + } + } + else + { + AddDragItemFlavor(theDrag, theItem, type , dataPtr, dataSize, 0); + } + delete[] dataPtr ; + } + delete[] formats ; + + dragRegion = NewRgn(); + RgnHandle tempRgn = NewRgn() ; + + EventRecord* ev = NULL ; +#if !TARGET_CARBON // TODO + ev = (EventRecord*) wxTheApp->MacGetCurrentEvent() ; +#else + EventRecord rec ; + ev = &rec ; + wxMacConvertEventToRecord( (EventRef) wxTheApp->MacGetCurrentEvent() , &rec ) ; +#endif + const short dragRegionOuterBoundary = 10 ; + const short dragRegionInnerBoundary = 9 ; + + SetRectRgn( dragRegion , ev->where.h - dragRegionOuterBoundary , + ev->where.v - dragRegionOuterBoundary , + ev->where.h + dragRegionOuterBoundary , + ev->where.v + dragRegionOuterBoundary ) ; + + SetRectRgn( tempRgn , ev->where.h - dragRegionInnerBoundary , + ev->where.v - dragRegionInnerBoundary , + ev->where.h + dragRegionInnerBoundary , + ev->where.v + dragRegionInnerBoundary ) ; + + DiffRgn( dragRegion , tempRgn , dragRegion ) ; + DisposeRgn( tempRgn ) ; + + // TODO:work with promises in order to return data only when drag + // was successfully completed + + gTrackingGlobals.m_currentSource = this ; + result = TrackDrag(theDrag, ev , dragRegion); + DisposeRgn(dragRegion); + DisposeDrag(theDrag); + gTrackingGlobals.m_currentSource = NULL ; + + KeyMap keymap; + GetKeys(keymap); + bool optionDown = keymap[1] & 4; + wxDragResult dndresult = optionDown ? wxDragCopy : wxDragMove; + return dndresult; +} + +bool wxDropSource::MacInstallDefaultCursor(wxDragResult effect) +{ + const wxCursor& cursor = GetCursor(effect); + if ( cursor.Ok() ) + { + cursor.MacInstall() ; + + return TRUE; + } + else + { + return FALSE; + } +} + +bool gTrackingGlobalsInstalled = false ; + +// passing the globals via refcon is not needed by the CFM and later architectures anymore +// but I'll leave it in there, just in case... + +pascal OSErr wxMacWindowDragTrackingHandler(DragTrackingMessage theMessage, WindowPtr theWindow, + void *handlerRefCon, DragReference theDrag) ; +pascal OSErr wxMacWindowDragReceiveHandler(WindowPtr theWindow, void *handlerRefCon, +DragReference theDrag) ; + +void wxMacEnsureTrackingHandlersInstalled() +{ + if( !gTrackingGlobalsInstalled ) + { + OSErr result; + + result = InstallTrackingHandler(NewDragTrackingHandlerUPP(wxMacWindowDragTrackingHandler), 0L,&gTrackingGlobals); + wxASSERT( result == noErr ) ; + result = InstallReceiveHandler(NewDragReceiveHandlerUPP(wxMacWindowDragReceiveHandler), 0L, &gTrackingGlobals); + wxASSERT( result == noErr ) ; + + gTrackingGlobalsInstalled = true ; + } +} + +pascal OSErr wxMacWindowDragTrackingHandler(DragTrackingMessage theMessage, WindowPtr theWindow, + void *handlerRefCon, DragReference theDrag) +{ + MacTrackingGlobals* trackingGlobals = (MacTrackingGlobals*) handlerRefCon; + Point mouse, localMouse; + DragAttributes attributes; + GetDragAttributes(theDrag, &attributes); + wxTopLevelWindowMac* toplevel = wxFindWinFromMacWindow( theWindow ) ; + + KeyMap keymap; + GetKeys(keymap); + bool optionDown = keymap[1] & 4; + wxDragResult result = optionDown ? wxDragCopy : wxDragMove; + + switch(theMessage) + { + case kDragTrackingEnterHandler: + break; + case kDragTrackingLeaveHandler: + break; + case kDragTrackingEnterWindow: + trackingGlobals->m_currentTargetWindow = NULL ; + trackingGlobals->m_currentTarget = NULL ; + break; + case kDragTrackingInWindow: + if (toplevel == NULL) + break; + + GetDragMouse(theDrag, &mouse, 0L); + localMouse = mouse; + GlobalToLocal(&localMouse); + + + +// if (attributes & kDragHasLeftSenderWindow) + { + wxPoint point(localMouse.h , localMouse.v) ; + wxWindow *win = NULL ; + toplevel->MacGetWindowFromPointSub( point , &win ) ; + int localx , localy ; + localx = localMouse.h ; + localy = localMouse.v ; + //TODO : should we use client coordinates + if ( win ) + win->MacRootWindowToWindow( &localx , &localy ) ; + if ( win != trackingGlobals->m_currentTargetWindow ) + { + if ( trackingGlobals->m_currentTargetWindow ) + { + // this window is left + if ( trackingGlobals->m_currentTarget ) + { + HideDragHilite(theDrag); + trackingGlobals->m_currentTarget->SetCurrentDrag( theDrag ) ; + trackingGlobals->m_currentTarget->OnLeave() ; + trackingGlobals->m_currentTarget = NULL; + trackingGlobals->m_currentTargetWindow = NULL ; + } + } + if ( win ) + { + // this window is entered + trackingGlobals->m_currentTargetWindow = win ; + trackingGlobals->m_currentTarget = win->GetDropTarget() ; + { + + if ( trackingGlobals->m_currentTarget ) + { + trackingGlobals->m_currentTarget->SetCurrentDrag( theDrag ) ; + result = trackingGlobals->m_currentTarget->OnEnter( + localx , localy , result ) ; + } + + + if ( result != wxDragNone ) + { + int x , y ; + x = y = 0 ; + win->MacWindowToRootWindow( &x , &y ) ; + RgnHandle hiliteRgn = NewRgn() ; + SetRectRgn( hiliteRgn , x , y , x+win->GetSize().x ,y+win->GetSize().y) ; + ShowDragHilite(theDrag, hiliteRgn, true); + DisposeRgn( hiliteRgn ) ; + } + } + } + } + else + { + if( trackingGlobals->m_currentTarget ) + { + trackingGlobals->m_currentTarget->SetCurrentDrag( theDrag ) ; + trackingGlobals->m_currentTarget->OnDragOver( + localx , localy , result ) ; + } + } + + // set cursor for OnEnter and OnDragOver + if ( trackingGlobals->m_currentSource && trackingGlobals->m_currentSource->GiveFeedback( result ) == FALSE ) + { + if ( trackingGlobals->m_currentSource->MacInstallDefaultCursor( result ) == FALSE ) + { + switch( result ) + { + case wxDragCopy : + { + wxCursor cursor(wxCURSOR_COPY_ARROW) ; + cursor.MacInstall() ; + } + break ; + case wxDragMove : + { + wxCursor cursor(wxCURSOR_ARROW) ; + cursor.MacInstall() ; + } + break ; + case wxDragNone : + { + wxCursor cursor(wxCURSOR_NO_ENTRY) ; + cursor.MacInstall() ; + } + break ; + + case wxDragError: + case wxDragLink: + case wxDragCancel: + // put these here to make gcc happy + ; + } + } + } + + } + // MyTrackItemUnderMouse(localMouse, theWindow); + break; + case kDragTrackingLeaveWindow: + if (trackingGlobals->m_currentTarget) + { + trackingGlobals->m_currentTarget->SetCurrentDrag( theDrag ) ; + trackingGlobals->m_currentTarget->OnLeave() ; + HideDragHilite(theDrag); + trackingGlobals->m_currentTarget = NULL ; + } + trackingGlobals->m_currentTargetWindow = NULL ; + break; + } + return(noErr); +} + +pascal OSErr wxMacWindowDragReceiveHandler(WindowPtr theWindow, + void *handlerRefCon, + DragReference theDrag) +{ + MacTrackingGlobals* trackingGlobals = (MacTrackingGlobals*) handlerRefCon; + if ( trackingGlobals->m_currentTarget ) + { + Point mouse,localMouse ; + int localx,localy ; + + trackingGlobals->m_currentTarget->SetCurrentDrag( theDrag ) ; + GetDragMouse(theDrag, &mouse, 0L); + localMouse = mouse; + GlobalToLocal(&localMouse); + localx = localMouse.h ; + localy = localMouse.v ; + //TODO : should we use client coordinates + if ( trackingGlobals->m_currentTargetWindow ) + trackingGlobals->m_currentTargetWindow->MacRootWindowToWindow( &localx , &localy ) ; + if ( trackingGlobals->m_currentTarget->OnDrop( localx , localy ) ) + { + KeyMap keymap; + GetKeys(keymap); + bool optionDown = keymap[1] & 4; + wxDragResult result = optionDown ? wxDragCopy : wxDragMove; + trackingGlobals->m_currentTarget->OnData( localx , localy , result ) ; + } + } + return(noErr); +} +#endif diff --git a/src/mac/classic/filedlg.cpp b/src/mac/classic/filedlg.cpp new file mode 100644 index 0000000000..59807f398d --- /dev/null +++ b/src/mac/classic/filedlg.cpp @@ -0,0 +1,647 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: filedlg.cpp +// Purpose: wxFileDialog +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "filedlg.h" +#endif + +#include "wx/defs.h" +#include "wx/app.h" +#include "wx/utils.h" +#include "wx/dialog.h" +#include "wx/filedlg.h" +#include "wx/intl.h" +#include "wx/tokenzr.h" +#include "wx/filename.h" + +#ifndef __DARWIN__ + #include "PLStringFuncs.h" +#endif + +#if !USE_SHARED_LIBRARY +IMPLEMENT_CLASS(wxFileDialog, wxFileDialogBase) +#endif + +// begin wxmac + +#include "wx/mac/private.h" + +#include + +#ifdef __DARWIN__ +# include "MoreFilesX.h" +#else +# include "MoreFiles.h" +# include "MoreFilesExtras.h" +#endif + +extern bool gUseNavServices ; + +// the data we need to pass to our standard file hook routine +// includes a pointer to the dialog, a pointer to the standard +// file reply record (so we can inspect the current selection) +// and a copy of the "previous" file spec of the reply record +// so we can see if the selection has changed + +struct OpenUserDataRec { + int currentfilter ; + bool saveMode ; + wxArrayString name ; + wxArrayString extensions ; + wxArrayLong filtermactypes ; + wxString defaultLocation; +#if TARGET_CARBON + CFArrayRef menuitems ; +#else + NavMenuItemSpecArrayHandle menuitems ; +#endif +}; + +typedef struct OpenUserDataRec +OpenUserDataRec, *OpenUserDataRecPtr; + +static pascal void NavEventProc( + NavEventCallbackMessage inSelector, + NavCBRecPtr ioParams, + NavCallBackUserData ioUserData); + +#if TARGET_CARBON + static NavEventUPP sStandardNavEventFilter = NewNavEventUPP(NavEventProc); +#else + static NavEventUPP sStandardNavEventFilter = NewNavEventProc(NavEventProc); +#endif + +static pascal void +NavEventProc( + NavEventCallbackMessage inSelector, + NavCBRecPtr ioParams, + NavCallBackUserData ioUserData ) +{ + OpenUserDataRec * data = ( OpenUserDataRec *) ioUserData ; + if (inSelector == kNavCBEvent) { +#if TARGET_CARBON +#else + wxTheApp->MacHandleOneEvent(ioParams->eventData.eventDataParms.event); +#endif + } + else if ( inSelector == kNavCBStart ) + { +#if TARGET_CARBON + if (data && !(data->defaultLocation).IsEmpty()) + { + // Set default location for the modern Navigation APIs + // Apple Technical Q&A 1151 + FSSpec theFSSpec; + wxMacFilename2FSSpec(data->defaultLocation, &theFSSpec); + AEDesc theLocation = {typeNull, NULL}; + if (noErr == ::AECreateDesc(typeFSS, &theFSSpec, sizeof(FSSpec), &theLocation)) + ::NavCustomControl(ioParams->context, kNavCtlSetLocation, (void *) &theLocation); + } +#else + if ( data->menuitems ) + NavCustomControl(ioParams->context, kNavCtlSelectCustomType, &(*data->menuitems)[data->currentfilter]); +#endif + } + else if ( inSelector == kNavCBPopupMenuSelect ) + { + NavMenuItemSpec * menu = (NavMenuItemSpec *) ioParams->eventData.eventDataParms.param ; +#if TARGET_CARBON +#else + if ( menu->menuCreator == 'WXNG' ) +#endif + { + data->currentfilter = menu->menuType ; + if ( data->saveMode ) + { + int i = menu->menuType ; + wxString extension = data->extensions[i].AfterLast('.') ; + extension.MakeLower() ; + wxString sfilename ; + +#if TARGET_CARBON + wxMacCFStringHolder cfString( NavDialogGetSaveFileName( ioParams->context ) , false ); + sfilename = cfString.AsString() ; +#else + Str255 filename ; + // get the current filename + NavCustomControl(ioParams->context, kNavCtlGetEditFileName, &filename); + sfilename = wxMacMakeStringFromPascal( filename ) ; +#endif + + int pos = sfilename.Find('.', true) ; + if ( pos != wxNOT_FOUND ) + { + sfilename = sfilename.Left(pos+1)+extension ; +#if TARGET_CARBON + cfString.Assign( sfilename , wxFONTENCODING_DEFAULT ) ; + NavDialogSetSaveFileName( ioParams->context , cfString ) ; +#else + wxMacStringToPascal( sfilename , filename ) ; + NavCustomControl(ioParams->context, kNavCtlSetEditFileName, &filename); +#endif + } + } + } + } +} + + +void MakeUserDataRec(OpenUserDataRec *myData , const wxString& filter ) +{ + myData->menuitems = NULL ; + myData->currentfilter = 0 ; + myData->saveMode = false ; + + if ( filter && filter[0] ) + { + wxString filter2(filter) ; + int filterIndex = 0; + bool isName = true ; + wxString current ; + for( unsigned int i = 0; i < filter2.Len() ; i++ ) + { + if( filter2.GetChar(i) == wxT('|') ) + { + if( isName ) { + myData->name.Add( current ) ; + } + else { + myData->extensions.Add( current.MakeUpper() ) ; + ++filterIndex ; + } + isName = !isName ; + current = wxEmptyString ; + } + else + { + current += filter2.GetChar(i) ; + } + } + // we allow for compatibility reason to have a single filter expression (like *.*) without + // an explanatory text, in that case the first part is name and extension at the same time + + wxASSERT_MSG( filterIndex == 0 || !isName , wxT("incorrect format of format string") ) ; + if ( current.IsEmpty() ) + myData->extensions.Add( myData->name[filterIndex] ) ; + else + myData->extensions.Add( current.MakeUpper() ) ; + if ( filterIndex == 0 || isName ) + myData->name.Add( current.MakeUpper() ) ; + + ++filterIndex ; + + const size_t extCount = myData->extensions.GetCount(); + for ( size_t i = 0 ; i < extCount; i++ ) + { + wxUint32 fileType; + wxUint32 creator; + wxString extension = myData->extensions[i]; + + if (extension.GetChar(0) == '*') + extension = extension.Mid(1); // Remove leading * + + if (extension.GetChar(0) == '.') + { + extension = extension.Mid(1); // Remove leading . + } + + if (wxFileName::MacFindDefaultTypeAndCreator( extension, &fileType, &creator )) + { + myData->filtermactypes.Add( (OSType)fileType ); + } + else + { + myData->filtermactypes.Add( '****' ) ; // We'll fail safe if it's not recognized + } + } + } +} + +static Boolean CheckFile( const wxString &filename , OSType type , OpenUserDataRecPtr data) +{ + wxString file(filename) ; + file.MakeUpper() ; + + if ( data->extensions.GetCount() > 0 ) + { + //for ( int i = 0 ; i < data->numfilters ; ++i ) + int i = data->currentfilter ; + if ( data->extensions[i].Right(2) == wxT(".*") ) + return true ; + + { + if ( type == (OSType)data->filtermactypes[i] ) + return true ; + + wxStringTokenizer tokenizer( data->extensions[i] , wxT(";") ) ; + while( tokenizer.HasMoreTokens() ) + { + wxString extension = tokenizer.GetNextToken() ; + if ( extension.GetChar(0) == '*' ) + extension = extension.Mid(1) ; + + if ( file.Len() >= extension.Len() && extension == file.Right(extension.Len() ) ) + return true ; + } + } + return false ; + } + return true ; +} + +#ifndef __DARWIN__ +static pascal Boolean CrossPlatformFileFilter(CInfoPBPtr myCInfoPBPtr, void *dataPtr) +{ + OpenUserDataRecPtr data = (OpenUserDataRecPtr) dataPtr ; + // return true if this item is invisible or a file + + Boolean visibleFlag; + Boolean folderFlag; + + visibleFlag = ! (myCInfoPBPtr->hFileInfo.ioFlFndrInfo.fdFlags & kIsInvisible); + folderFlag = (myCInfoPBPtr->hFileInfo.ioFlAttrib & 0x10); + + // because the semantics of the filter proc are "true means don't show + // it" we need to invert the result that we return + + if ( !visibleFlag ) + return true ; + + if ( !folderFlag ) + { + wxString file = wxMacMakeStringFromPascal( myCInfoPBPtr->hFileInfo.ioNamePtr ) ; + return !CheckFile( file , myCInfoPBPtr->hFileInfo.ioFlFndrInfo.fdType , data ) ; + } + + return false ; +} +#endif + +// end wxmac + +wxFileDialog::wxFileDialog(wxWindow *parent, const wxString& message, + const wxString& defaultDir, const wxString& defaultFileName, const wxString& wildCard, + long style, const wxPoint& pos) + :wxFileDialogBase(parent, message, defaultDir, defaultFileName, wildCard, style, pos) +{ + wxASSERT_MSG( NavServicesAvailable() , wxT("Navigation Services are not running") ) ; +} + +pascal Boolean CrossPlatformFilterCallback ( + AEDesc *theItem, + void *info, + void *callBackUD, + NavFilterModes filterMode +) +{ + bool display = true; + OpenUserDataRecPtr data = (OpenUserDataRecPtr) callBackUD ; + + if (filterMode == kNavFilteringBrowserList) + { + NavFileOrFolderInfo* theInfo = (NavFileOrFolderInfo*) info ; + if ( !theInfo->isFolder ) + { + if (theItem->descriptorType == typeFSS ) + { + FSSpec spec; + memcpy( &spec , *theItem->dataHandle , sizeof(FSSpec) ) ; + wxString file = wxMacMakeStringFromPascal( spec.name ) ; + display = CheckFile( file , theInfo->fileAndFolder.fileInfo.finderInfo.fdType , data ) ; + } + #if TARGET_CARBON + else if ( theItem->descriptorType == typeFSRef ) + { + FSRef fsref ; + memcpy( &fsref , *theItem->dataHandle , sizeof(FSRef) ) ; + + + + CFURLRef fullURLRef; + fullURLRef = ::CFURLCreateFromFSRef(NULL, &fsref); +#ifdef __UNIX__ + CFURLPathStyle pathstyle = kCFURLPOSIXPathStyle; +#else + CFURLPathStyle pathstyle = kCFURLHFSPathStyle; +#endif + CFStringRef cfString = CFURLCopyFileSystemPath(fullURLRef, pathstyle); + ::CFRelease( fullURLRef ) ; + wxString file = wxMacCFStringHolder(cfString).AsString(wxFont::GetDefaultEncoding()); + + display = CheckFile( file , theInfo->fileAndFolder.fileInfo.finderInfo.fdType , data ) ; + } +#endif + } + } + + return display; +} + +int wxFileDialog::ShowModal() +{ +#if TARGET_CARBON + OSErr err; + NavDialogCreationOptions dialogCreateOptions; + // set default options + ::NavGetDefaultDialogCreationOptions(&dialogCreateOptions); + + // this was always unset in the old code + dialogCreateOptions.optionFlags &= ~kNavSelectDefaultLocation; + + wxMacCFStringHolder message(m_message, m_font.GetEncoding()); + dialogCreateOptions.windowTitle = message; + + wxMacCFStringHolder defaultFileName(m_fileName, m_font.GetEncoding()); + dialogCreateOptions.saveFileName = defaultFileName; + + + NavDialogRef dialog; + NavObjectFilterUPP navFilterUPP = NULL; + CFArrayRef cfArray = NULL; // for popupExtension + OpenUserDataRec myData; + myData.defaultLocation = m_dir; + + if (m_dialogStyle & wxSAVE) + { + dialogCreateOptions.optionFlags |= kNavNoTypePopup; + dialogCreateOptions.optionFlags |= kNavDontAutoTranslate; + dialogCreateOptions.optionFlags |= kNavDontAddTranslateItems; + + // The extension is important + dialogCreateOptions.optionFlags |= kNavPreserveSaveFileExtension; + + err = ::NavCreatePutFileDialog(&dialogCreateOptions, + 'TEXT', + 'TEXT', + sStandardNavEventFilter, + &myData, // for defaultLocation + &dialog); + } + else + { + MakeUserDataRec(&myData , m_wildCard); + size_t numfilters = myData.extensions.GetCount(); + if (numfilters > 0) + { + CFMutableArrayRef popup = CFArrayCreateMutable( kCFAllocatorDefault , + numfilters , &kCFTypeArrayCallBacks ) ; + dialogCreateOptions.popupExtension = popup ; + myData.menuitems = dialogCreateOptions.popupExtension ; + for ( size_t i = 0 ; i < numfilters ; ++i ) + { + CFArrayAppendValue( popup , (CFStringRef) wxMacCFStringHolder( myData.name[i] , m_font.GetEncoding() ) ) ; + } + } + + navFilterUPP = NewNavObjectFilterUPP(CrossPlatformFilterCallback); + err = ::NavCreateGetFileDialog(&dialogCreateOptions, + NULL, // NavTypeListHandle + sStandardNavEventFilter, + NULL, // NavPreviewUPP + navFilterUPP, + (void *) &myData, // inClientData + &dialog); + } + + if (err == noErr) + err = ::NavDialogRun(dialog); + + // clean up filter related data, etc. + if (navFilterUPP) + ::DisposeNavObjectFilterUPP(navFilterUPP); + if (cfArray) + ::CFRelease(cfArray); + + if (err != noErr) + return wxID_CANCEL; + + NavReplyRecord navReply; + err = ::NavDialogGetReply(dialog, &navReply); + if (err == noErr && navReply.validRecord) + { + AEKeyword theKeyword; + DescType actualType; + Size actualSize; + FSRef theFSRef; + wxString thePath ; + long count; + ::AECountItems(&navReply.selection , &count); + for (long i = 1; i <= count; ++i) + { + err = ::AEGetNthPtr(&(navReply.selection), i, typeFSRef, &theKeyword, &actualType, + &theFSRef, sizeof(theFSRef), &actualSize); + if (err != noErr) + break; + + CFURLRef fullURLRef; + if (m_dialogStyle & wxSAVE) + { + CFURLRef parentURLRef = ::CFURLCreateFromFSRef(NULL, &theFSRef); + + if (parentURLRef) + { + fullURLRef = + ::CFURLCreateCopyAppendingPathComponent(NULL, + parentURLRef, + navReply.saveFileName, + false); + ::CFRelease(parentURLRef); + } + } + else + { + fullURLRef = ::CFURLCreateFromFSRef(NULL, &theFSRef); + } +#ifdef __UNIX__ + CFURLPathStyle pathstyle = kCFURLPOSIXPathStyle; +#else + CFURLPathStyle pathstyle = kCFURLHFSPathStyle; +#endif + CFStringRef cfString = CFURLCopyFileSystemPath(fullURLRef, pathstyle); + thePath = wxMacCFStringHolder(cfString).AsString(m_font.GetEncoding()); + if (!thePath) + { + ::NavDisposeReply(&navReply); + return wxID_CANCEL; + } + m_path = thePath; + m_paths.Add(m_path); + m_fileName = wxFileNameFromPath(m_path); + m_fileNames.Add(m_fileName); + } + // set these to the first hit + m_path = m_paths[0]; + m_fileName = wxFileNameFromPath(m_path); + m_dir = wxPathOnly(m_path); + } + ::NavDisposeReply(&navReply); + + return (err == noErr) ? wxID_OK : wxID_CANCEL; +#else // TARGET_CARBON + + NavDialogOptions mNavOptions; + NavObjectFilterUPP mNavFilterUPP = NULL; + NavPreviewUPP mNavPreviewUPP = NULL ; + NavReplyRecord mNavReply; + AEDesc mDefaultLocation ; + bool mSelectDefault = false ; + OSStatus err = noErr ; + // setup dialog + + mNavFilterUPP = nil; + mNavPreviewUPP = nil; + mSelectDefault = false; + mDefaultLocation.descriptorType = typeNull; + mDefaultLocation.dataHandle = nil; + + NavGetDefaultDialogOptions(&mNavOptions); + wxMacStringToPascal( m_message , (StringPtr)mNavOptions.message ) ; + wxMacStringToPascal( m_fileName , (StringPtr)mNavOptions.savedFileName ) ; + + // Set default location, the location + // that's displayed when the dialog + // first appears + + FSSpec location ; + wxMacFilename2FSSpec( m_dir , &location ) ; + + err = ::AECreateDesc(typeFSS, &location, sizeof(FSSpec), &mDefaultLocation ); + + if ( mDefaultLocation.dataHandle ) + { + if (mSelectDefault) + { + mNavOptions.dialogOptionFlags |= kNavSelectDefaultLocation; + } else { + mNavOptions.dialogOptionFlags &= ~kNavSelectDefaultLocation; + } + } + + memset( &mNavReply , 0 , sizeof( mNavReply ) ) ; + mNavReply.validRecord = false; + mNavReply.replacing = false; + mNavReply.isStationery = false; + mNavReply.translationNeeded = false; + mNavReply.selection.descriptorType = typeNull; + mNavReply.selection.dataHandle = nil; + mNavReply.keyScript = smSystemScript; + mNavReply.fileTranslation = nil; + mNavReply.version = kNavReplyRecordVersion ; + + // zero all data + + m_path = wxEmptyString ; + m_fileName = wxEmptyString ; + m_paths.Empty(); + m_fileNames.Empty(); + + OpenUserDataRec myData; + MakeUserDataRec( &myData , m_wildCard ) ; + myData.currentfilter = m_filterIndex ; + if ( myData.extensions.GetCount() > 0 ) + { + mNavOptions.popupExtension = (NavMenuItemSpecArrayHandle) NewHandle( sizeof( NavMenuItemSpec ) * myData.extensions.GetCount() ) ; + myData.menuitems = mNavOptions.popupExtension ; + for ( size_t i = 0 ; i < myData.extensions.GetCount() ; ++i ) + { + (*mNavOptions.popupExtension)[i].version = kNavMenuItemSpecVersion ; + (*mNavOptions.popupExtension)[i].menuCreator = 'WXNG' ; + // TODO : according to the new docs -1 to 10 are reserved for the OS + (*mNavOptions.popupExtension)[i].menuType = i ; + wxMacStringToPascal( myData.name[i] , (StringPtr)(*mNavOptions.popupExtension)[i].menuItemName ) ; + } + } + if ( m_dialogStyle & wxSAVE ) + { + myData.saveMode = true ; + + mNavOptions.dialogOptionFlags |= kNavDontAutoTranslate ; + mNavOptions.dialogOptionFlags |= kNavDontAddTranslateItems ; + + err = ::NavPutFile( + &mDefaultLocation, + &mNavReply, + &mNavOptions, + sStandardNavEventFilter , + NULL, + kNavGenericSignature, + &myData); // User Data + m_filterIndex = myData.currentfilter ; + } + else + { + myData.saveMode = false ; + + mNavFilterUPP = NewNavObjectFilterUPP( CrossPlatformFilterCallback ) ; + if ( m_dialogStyle & wxMULTIPLE ) + mNavOptions.dialogOptionFlags |= kNavAllowMultipleFiles ; + else + mNavOptions.dialogOptionFlags &= ~kNavAllowMultipleFiles ; + + err = ::NavGetFile( + &mDefaultLocation, + &mNavReply, + &mNavOptions, + sStandardNavEventFilter , + mNavPreviewUPP, + mNavFilterUPP, + NULL , + &myData); + m_filterIndex = myData.currentfilter ; + } + + DisposeNavObjectFilterUPP(mNavFilterUPP); + if ( mDefaultLocation.dataHandle != nil ) + { + ::AEDisposeDesc(&mDefaultLocation); + } + + if ( (err != noErr) && (err != userCanceledErr) ) { + return wxID_CANCEL ; + } + + if (mNavReply.validRecord) + { + FSSpec outFileSpec ; + AEDesc specDesc ; + AEKeyword keyWord ; + + long count ; + ::AECountItems( &mNavReply.selection , &count ) ; + for ( long i = 1 ; i <= count ; ++i ) + { + OSErr err = ::AEGetNthDesc( &mNavReply.selection , i , typeFSS, &keyWord , &specDesc); + if ( err != noErr ) + { + m_path = wxT("") ; + return wxID_CANCEL ; + } + outFileSpec = **(FSSpec**) specDesc.dataHandle; + if (specDesc.dataHandle != nil) { + ::AEDisposeDesc(&specDesc); + } + m_path = wxMacFSSpec2MacFilename( &outFileSpec ) ; + + m_paths.Add( m_path ) ; + m_fileName = wxFileNameFromPath(m_path); + m_fileNames.Add(m_fileName); + } + // set these to the first hit + m_path = m_paths[ 0 ] ; + m_fileName = wxFileNameFromPath(m_path); + m_dir = wxPathOnly(m_path); + NavDisposeReply( &mNavReply ) ; + return wxID_OK ; + } + return wxID_CANCEL; +#endif // TARGET_CARBON +} + diff --git a/src/mac/classic/font.cpp b/src/mac/classic/font.cpp new file mode 100644 index 0000000000..ef0ecc73b6 --- /dev/null +++ b/src/mac/classic/font.cpp @@ -0,0 +1,446 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: font.cpp +// Purpose: wxFont class +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "font.h" +#endif + +#include "wx/defs.h" +#include "wx/string.h" +#include "wx/font.h" +#include "wx/fontutil.h" +#include "wx/gdicmn.h" +#include "wx/utils.h" + +#include "wx/fontutil.h" + +#include "wx/mac/private.h" +#include + +#if !USE_SHARED_LIBRARIES +IMPLEMENT_DYNAMIC_CLASS(wxFont, wxGDIObject) +#endif + +class WXDLLEXPORT wxFontRefData: public wxGDIRefData +{ + friend class WXDLLEXPORT wxFont; +public: + wxFontRefData() + : m_fontId(0) + , m_pointSize(10) + , m_family(wxDEFAULT) + , m_style(wxNORMAL) + , m_weight(wxNORMAL) + , m_underlined(FALSE) + , m_faceName(wxT("Geneva")) + , m_encoding(wxFONTENCODING_DEFAULT) + , m_macFontNum(0) + , m_macFontSize(0) + , m_macFontStyle(0) + , m_macATSUFontID() + { + Init(10, wxDEFAULT, wxNORMAL, wxNORMAL, FALSE, + wxT("Geneva"), wxFONTENCODING_DEFAULT); + } + + wxFontRefData(const wxFontRefData& data) + : wxGDIRefData() + , m_fontId(data.m_fontId) + , m_pointSize(data.m_pointSize) + , m_family(data.m_family) + , m_style(data.m_style) + , m_weight(data.m_weight) + , m_underlined(data.m_underlined) + , m_faceName(data.m_faceName) + , m_encoding(data.m_encoding) + , m_macFontNum(data.m_macFontNum) + , m_macFontSize(data.m_macFontSize) + , m_macFontStyle(data.m_macFontStyle) + , m_macATSUFontID(data.m_macATSUFontID) + { + Init(data.m_pointSize, data.m_family, data.m_style, data.m_weight, + data.m_underlined, data.m_faceName, data.m_encoding); + } + + wxFontRefData(int size, + int family, + int style, + int weight, + bool underlined, + const wxString& faceName, + wxFontEncoding encoding) + : m_fontId(0) + , m_pointSize(size) + , m_family(family) + , m_style(style) + , m_weight(weight) + , m_underlined(underlined) + , m_faceName(faceName) + , m_encoding(encoding) + , m_macFontNum(0) + , m_macFontSize(0) + , m_macFontStyle(0) + , m_macATSUFontID(0) + { + Init(size, family, style, weight, underlined, faceName, encoding); + } + + virtual ~wxFontRefData(); + void SetNoAntiAliasing( bool no = TRUE ) { m_noAA = no; } + bool GetNoAntiAliasing() { return m_noAA; } + +protected: + // common part of all ctors + void Init(int size, + int family, + int style, + int weight, + bool underlined, + const wxString& faceName, + wxFontEncoding encoding); + + // font characterstics + int m_fontId; + int m_pointSize; + int m_family; + int m_style; + int m_weight; + bool m_underlined; + wxString m_faceName; + wxFontEncoding m_encoding; + bool m_noAA; // No anti-aliasing + +public: + short m_macFontNum; + short m_macFontSize; + unsigned char m_macFontStyle; + wxUint32 m_macATSUFontID; + + wxNativeFontInfo m_info; + +public: + void MacFindFont() ; +}; +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxFontRefData +// ---------------------------------------------------------------------------- + +void wxFontRefData::Init(int pointSize, + int family, + int style, + int weight, + bool underlined, + const wxString& faceName, + wxFontEncoding encoding) +{ + m_style = style; + m_pointSize = pointSize; + m_family = family; + m_style = style; + m_weight = weight; + m_underlined = underlined; + m_faceName = faceName; + m_encoding = encoding; + + m_macFontNum = 0 ; + m_macFontSize = 0; + m_macFontStyle = 0; + m_fontId = 0; + m_noAA = FALSE; +} + +wxFontRefData::~wxFontRefData() +{ +} + +void wxFontRefData::MacFindFont() +{ + if( m_faceName.Length() == 0 ) + { + switch( m_family ) + { + case wxDEFAULT : + m_macFontNum = ::GetAppFont() ; + break ; + case wxDECORATIVE : + ::GetFNum( "\pTimes" , &m_macFontNum) ; + break ; + case wxROMAN : + ::GetFNum( "\pTimes" , &m_macFontNum) ; + break ; + case wxSCRIPT : + ::GetFNum( "\pTimes" , &m_macFontNum) ; + break ; + case wxSWISS : + ::GetFNum( "\pGeneva" , &m_macFontNum) ; + break ; + case wxMODERN : + ::GetFNum( "\pMonaco" , &m_macFontNum) ; + break ; + } + Str255 name ; + GetFontName( m_macFontNum , name ) ; + m_faceName = wxMacMakeStringFromPascal( name ) ; + } + else + { + if ( m_faceName == wxT("systemfont") ) + m_macFontNum = ::GetSysFont() ; + else if ( m_faceName == wxT("applicationfont") ) + m_macFontNum = ::GetAppFont() ; + else + { + Str255 fontname ; + wxMacStringToPascal( m_faceName , fontname ) ; + ::GetFNum( fontname, &m_macFontNum); + } + } + + m_macFontStyle = 0; + if (m_weight == wxBOLD) + m_macFontStyle |= bold; + if (m_style == wxITALIC || m_style == wxSLANT) + m_macFontStyle |= italic; + if (m_underlined) + m_macFontStyle |= underline; + m_macFontSize = m_pointSize ; + + //TODO:if we supply the style as an additional parameter we must make a testing + //sequence in order to degrade gracefully while trying to maintain most of the style + //information, meanwhile we just take the normal font and apply the features after +#ifdef __WXDEBUG__ + OSStatus status = +#endif // __WXDEBUG__ + ::ATSUFONDtoFontID(m_macFontNum, normal /*qdStyle*/, (UInt32*)&m_macATSUFontID); + /* + status = ATSUFindFontFromName ( (Ptr) m_faceName , strlen( m_faceName ) , + kFontFullName, kFontMacintoshPlatform, kFontRomanScript , kFontNoLanguage , (UInt32*)&m_macATSUFontID ) ; + */ + wxASSERT_MSG( status == noErr , wxT("couldn't retrieve font identifier") ) ; +} + +// ---------------------------------------------------------------------------- +// wxFont +// ---------------------------------------------------------------------------- + +void wxFont::Init() +{ +} + +bool wxFont::Create(const wxNativeFontInfo& info) +{ + return Create(info.pointSize, info.family, info.style, info.weight, + info.underlined, info.faceName, info.encoding); +} + +wxFont::wxFont(const wxString& fontdesc) +{ + wxNativeFontInfo info; + if ( info.FromString(fontdesc) ) + (void)Create(info); +} + +bool wxFont::Create(int pointSize, + int family, + int style, + int weight, + bool underlined, + const wxString& faceName, + wxFontEncoding encoding) +{ + UnRef(); + m_refData = new wxFontRefData(pointSize, family, style, weight, + underlined, faceName, encoding); + + RealizeResource(); + + return TRUE; +} + +wxFont::~wxFont() +{ +} + +bool wxFont::RealizeResource() +{ + M_FONTDATA->MacFindFont() ; + return TRUE; +} + +void wxFont::SetEncoding(wxFontEncoding encoding) +{ + Unshare(); + + M_FONTDATA->m_encoding = encoding; + + RealizeResource(); +} + +void wxFont::Unshare() +{ + // Don't change shared data + if (!m_refData) + { + m_refData = new wxFontRefData(); + } + else + { + wxFontRefData* ref = new wxFontRefData(*(wxFontRefData*)m_refData); + UnRef(); + m_refData = ref; + } +} + +void wxFont::SetPointSize(int pointSize) +{ + Unshare(); + + M_FONTDATA->m_pointSize = pointSize; + + RealizeResource(); +} + +void wxFont::SetFamily(int family) +{ + Unshare(); + + M_FONTDATA->m_family = family; + + RealizeResource(); +} + +void wxFont::SetStyle(int style) +{ + Unshare(); + + M_FONTDATA->m_style = style; + + RealizeResource(); +} + +void wxFont::SetWeight(int weight) +{ + Unshare(); + + M_FONTDATA->m_weight = weight; + + RealizeResource(); +} + +void wxFont::SetFaceName(const wxString& faceName) +{ + Unshare(); + + M_FONTDATA->m_faceName = faceName; + + RealizeResource(); +} + +void wxFont::SetUnderlined(bool underlined) +{ + Unshare(); + + M_FONTDATA->m_underlined = underlined; + + RealizeResource(); +} + +void wxFont::SetNoAntiAliasing( bool no ) +{ + Unshare(); + + M_FONTDATA->SetNoAntiAliasing( no ); + + RealizeResource(); +} + +// ---------------------------------------------------------------------------- +// accessors +// ---------------------------------------------------------------------------- + +// TODO: insert checks everywhere for M_FONTDATA == NULL! + +int wxFont::GetPointSize() const +{ + return M_FONTDATA->m_pointSize; +} + +int wxFont::GetFamily() const +{ + return M_FONTDATA->m_family; +} + +int wxFont::GetStyle() const +{ + return M_FONTDATA->m_style; +} + +int wxFont::GetWeight() const +{ + return M_FONTDATA->m_weight; +} + +bool wxFont::GetUnderlined() const +{ + return M_FONTDATA->m_underlined; +} + +wxString wxFont::GetFaceName() const +{ + wxString str; + if ( M_FONTDATA ) + str = M_FONTDATA->m_faceName ; + return str; +} + +wxFontEncoding wxFont::GetEncoding() const +{ + return M_FONTDATA->m_encoding; +} + +bool wxFont::GetNoAntiAliasing() +{ + return M_FONTDATA->m_noAA; +} + +short wxFont::GetMacFontNum() const +{ + return M_FONTDATA->m_macFontNum; +} + +short wxFont::GetMacFontSize() const +{ + return M_FONTDATA->m_macFontSize; +} + +wxByte wxFont::GetMacFontStyle() const +{ + return M_FONTDATA->m_macFontStyle; +} + +wxUint32 wxFont::GetMacATSUFontID() const +{ + return M_FONTDATA->m_macATSUFontID; +} + +const wxNativeFontInfo *wxFont::GetNativeFontInfo() const +{ + wxCHECK_MSG( Ok(), NULL, wxT("invalid font") ); + + M_FONTDATA->m_info.InitFromFont(*this); + + return &(M_FONTDATA->m_info); +} + diff --git a/src/mac/classic/fontdlg.cpp b/src/mac/classic/fontdlg.cpp new file mode 100644 index 0000000000..03c894c553 --- /dev/null +++ b/src/mac/classic/fontdlg.cpp @@ -0,0 +1,54 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: fontdlg.cpp +// Purpose: wxFontDialog class. NOTE: you can use the generic class +// if you wish, instead of implementing this. +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "fontdlg.h" +#endif + +#include "wx/mac/fontdlg.h" +#include "wx/cmndata.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxFontDialog, wxDialog) +#endif + +/* + * wxFontDialog + */ + +wxFontDialog::wxFontDialog() +{ + m_dialogParent = NULL; +} + +wxFontDialog::wxFontDialog(wxWindow *parent, const wxFontData& data) +{ + Create(parent, data); +} + +bool wxFontDialog::Create(wxWindow *parent, const wxFontData& data) +{ + m_dialogParent = parent; + + m_fontData = data; + + // TODO: you may need to do dialog creation here, unless it's + // done in ShowModal. + return TRUE; +} + +int wxFontDialog::ShowModal() +{ + // TODO: show (maybe create) the dialog + return wxID_CANCEL; +} + diff --git a/src/mac/classic/fontenum.cpp b/src/mac/classic/fontenum.cpp new file mode 100644 index 0000000000..467bc95442 --- /dev/null +++ b/src/mac/classic/fontenum.cpp @@ -0,0 +1,173 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: mac/fontenum.cpp +// Purpose: wxFontEnumerator class for MacOS +// Author: Stefan Csomor +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#ifdef __GNUG__ + #pragma implementation "fontenum.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/font.h" +#endif + +#include "wx/fontenum.h" +#include "wx/fontutil.h" +#include "wx/fontmap.h" +#include "wx/fontutil.h" +#include "wx/encinfo.h" + +#include "wx/mac/private.h" + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +class wxFontEnumeratorHelper +{ +public: + wxFontEnumeratorHelper(wxFontEnumerator *fontEnum); + + // control what exactly are we enumerating + bool SetEncoding(wxFontEncoding encoding); + void SetFixedOnly(bool fixedOnly) + { m_fixedOnly = fixedOnly; } + + // call to start enumeration + void DoEnumerate(); + +private: + // the object we forward calls to OnFont() to + wxFontEnumerator *m_fontEnum; + + // if != -1, enum only fonts which have this encoding + int m_charset; + + // if not empty, enum only the fonts with this facename + wxString m_facename; + + // if TRUE, enum only fixed fonts + bool m_fixedOnly; +}; +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxFontEnumeratorHelper +// ---------------------------------------------------------------------------- + +wxFontEnumeratorHelper::wxFontEnumeratorHelper(wxFontEnumerator *fontEnum) +{ + m_fontEnum = fontEnum; + m_charset = -1; + m_fixedOnly = FALSE; +} + +bool wxFontEnumeratorHelper::SetEncoding(wxFontEncoding encoding) +{ + wxNativeEncodingInfo info; + if ( !wxGetNativeFontEncoding(encoding, &info) ) + { + if ( !wxFontMapper::Get()->GetAltForEncoding(encoding, &info) ) + { + // no such encodings at all + return FALSE; + } + } + m_charset = info.charset; + m_facename = info.facename; + + return TRUE; +} + +void wxFontEnumeratorHelper::DoEnumerate() +{ + MenuHandle menu ; + Str255 p_name ; + + short lines ; + + menu = NewMenu( 32000 , "\pFont" ) ; + AppendResMenu( menu , 'FONT' ) ; + lines = CountMenuItems( menu ) ; + + for ( int i = 1 ; i < lines+1 ; i ++ ) + { + GetMenuItemText( menu , i , p_name ) ; + wxString c_name = wxMacMakeStringFromPascal(p_name) ; + + /* + + if ( m_fixedOnly ) + { + // check that it's a fixed pitch font (there is *no* error here, the + // flag name is misleading!) + if ( tm->tmPitchAndFamily & TMPF_FIXED_PITCH ) + { + // not a fixed pitch font + return TRUE; + } + } + + if ( m_charset != -1 ) + { + // check that we have the right encoding + if ( lf->lfCharSet != m_charset ) + { + return TRUE; + } + } + + */ + m_fontEnum->OnFacename( c_name ) ; + } + DisposeMenu( menu ) ; +} + +// ---------------------------------------------------------------------------- +// wxFontEnumerator +// ---------------------------------------------------------------------------- + +bool wxFontEnumerator::EnumerateFacenames(wxFontEncoding encoding, + bool fixedWidthOnly) +{ + wxFontEnumeratorHelper fe(this); + if ( fe.SetEncoding(encoding) ) + { + fe.SetFixedOnly(fixedWidthOnly); + + fe.DoEnumerate(); + } + // else: no such fonts, unknown encoding + + return TRUE; +} + +bool wxFontEnumerator::EnumerateEncodings(const wxString& family) +{ + wxFAIL_MSG(wxT("wxFontEnumerator::EnumerateEncodings() not yet implemented")); + + return TRUE; +} diff --git a/src/mac/classic/fontutil.cpp b/src/mac/classic/fontutil.cpp new file mode 100644 index 0000000000..1aa2298245 --- /dev/null +++ b/src/mac/classic/fontutil.cpp @@ -0,0 +1,117 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: msw/fontutil.cpp +// Purpose: font-related helper functions for wxMSW +// Author: Vadim Zeitlin +// Modified by: +// Created: 05.11.99 +// RCS-ID: $Id$ +// Copyright: (c) 1999 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#ifdef __GNUG__ + #pragma implementation "fontutil.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/log.h" + #include "wx/intl.h" +#endif //WX_PRECOMP + +#include "wx/fontutil.h" +#include "wx/fontmap.h" +#include "wx/encinfo.h" + +#include "wx/tokenzr.h" + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxNativeEncodingInfo +// ---------------------------------------------------------------------------- + +// convert to/from the string representation: format is +// facename[;charset] + +bool wxNativeEncodingInfo::FromString(const wxString& s) +{ + wxStringTokenizer tokenizer(s, _T(";")); + + facename = tokenizer.GetNextToken(); + if ( !facename ) + return FALSE; + + wxString tmp = tokenizer.GetNextToken(); + if ( !tmp ) + { + // default charset (don't use DEFAULT_CHARSET though because of subtle + // Windows 9x/NT differences in handling it) + charset = 0; + } + else + { + if ( wxSscanf(tmp, _T("%u"), &charset) != 1 ) + { + // should be a number! + return FALSE; + } + } + + return TRUE; +} + +wxString wxNativeEncodingInfo::ToString() const +{ + wxString s(facename); + if ( charset != 0 ) + { + s << _T(';') << charset; + } + + return s; +} + +// ---------------------------------------------------------------------------- +// helper functions +// ---------------------------------------------------------------------------- + +bool wxGetNativeFontEncoding(wxFontEncoding encoding, + wxNativeEncodingInfo *info) +{ + wxCHECK_MSG( info, FALSE, _T("bad pointer in wxGetNativeFontEncoding") ); + + if ( encoding == wxFONTENCODING_DEFAULT ) + { + encoding = wxFont::GetDefaultEncoding(); + } + + info->encoding = encoding ; + + return TRUE; +} + +bool wxTestFontEncoding(const wxNativeEncodingInfo& info) +{ + // basically we should be able to support every encoding via the OS + return true ; +} + + diff --git a/src/mac/classic/frame.cpp b/src/mac/classic/frame.cpp new file mode 100644 index 0000000000..b56f24712b --- /dev/null +++ b/src/mac/classic/frame.cpp @@ -0,0 +1,338 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: frame.cpp +// Purpose: wxFrame +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "frame.h" +#endif + +#include "wx/frame.h" +#include "wx/statusbr.h" +#include "wx/toolbar.h" +#include "wx/menuitem.h" +#include "wx/menu.h" +#include "wx/dcclient.h" +#include "wx/dialog.h" +#include "wx/settings.h" +#include "wx/app.h" + +#include "wx/mac/uma.h" + +extern wxWindowList wxModelessWindows; +extern wxList wxPendingDelete; + +#if !USE_SHARED_LIBRARY +BEGIN_EVENT_TABLE(wxFrame, wxFrameBase) + EVT_ACTIVATE(wxFrame::OnActivate) + // EVT_MENU_HIGHLIGHT_ALL(wxFrame::OnMenuHighlight) + EVT_SYS_COLOUR_CHANGED(wxFrame::OnSysColourChanged) +// EVT_IDLE(wxFrame::OnIdle) +// EVT_CLOSE(wxFrame::OnCloseWindow) +END_EVENT_TABLE() + +IMPLEMENT_DYNAMIC_CLASS(wxFrame, wxTopLevelWindow) +#endif + +#define WX_MAC_STATUSBAR_HEIGHT 15 +// ---------------------------------------------------------------------------- +// creation/destruction +// ---------------------------------------------------------------------------- + +void wxFrame::Init() +{ + m_frameMenuBar = NULL; + +#if wxUSE_TOOLBAR + m_frameToolBar = NULL ; +#endif + m_frameStatusBar = NULL; + m_winLastFocused = NULL ; + + m_iconized = FALSE; + +#if wxUSE_TOOLTIPS + m_hwndToolTip = 0; +#endif +} + +wxPoint wxFrame::GetClientAreaOrigin() const +{ + // on mac we are at position -1,-1 with the control + wxPoint pt(0, 0); + +#if wxUSE_TOOLBAR + if ( GetToolBar() ) + { + int w, h; + GetToolBar()->GetSize(& w, & h); + + if ( GetToolBar()->GetWindowStyleFlag() & wxTB_VERTICAL ) + { + pt.x += w - 1; + } + else + { + pt.y += h - 1 ; + } + } +#endif // wxUSE_TOOLBAR + + return pt; +} + +bool wxFrame::Create(wxWindow *parent, + wxWindowID id, + const wxString& title, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE)); + + if ( !wxTopLevelWindow::Create(parent, id, title, pos, size, style, name) ) + return FALSE; + + MacCreateRealWindow( title, pos , size , MacRemoveBordersFromStyle(style) , name ) ; + + m_macWindowBackgroundTheme = kThemeBrushDocumentWindowBackground ; + SetThemeWindowBackground( (WindowRef) m_macWindow , m_macWindowBackgroundTheme , false ) ; + + wxModelessWindows.Append(this); + + return TRUE; +} + +wxFrame::~wxFrame() +{ + m_isBeingDeleted = TRUE; + DeleteAllBars(); +} + + +bool wxFrame::Enable(bool enable) +{ + if ( !wxWindow::Enable(enable) ) + return FALSE; + + if ( m_frameMenuBar && m_frameMenuBar == wxMenuBar::MacGetInstalledMenuBar() ) + { + int iMaxMenu = m_frameMenuBar->GetMenuCount(); + for ( int i = 0 ; i < iMaxMenu ; ++ i ) + { + m_frameMenuBar->EnableTop( i , enable ) ; + } + } + + return TRUE; +} + +wxStatusBar *wxFrame::OnCreateStatusBar(int number, long style, wxWindowID id, + const wxString& name) +{ + wxStatusBar *statusBar = NULL; + + statusBar = new wxStatusBar(this, id, + style, name); + statusBar->SetSize( 100 , 15 ) ; + statusBar->SetFieldsCount(number); + return statusBar; +} + +void wxFrame::PositionStatusBar() +{ + if (m_frameStatusBar ) + { + int w, h; + GetClientSize(&w, &h); + int sw, sh; + m_frameStatusBar->GetSize(&sw, &sh); + + // Since we wish the status bar to be directly under the client area, + // we use the adjusted sizes without using wxSIZE_NO_ADJUSTMENTS. + m_frameStatusBar->SetSize(0, h, w, sh); + } +} + +// Responds to colour changes, and passes event on to children. +void wxFrame::OnSysColourChanged(wxSysColourChangedEvent& event) +{ + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE)); + Refresh(); + + if ( m_frameStatusBar ) + { + wxSysColourChangedEvent event2; + event2.SetEventObject( m_frameStatusBar ); + m_frameStatusBar->ProcessEvent(event2); + } + + // Propagate the event to the non-top-level children + wxWindow::OnSysColourChanged(event); +} + + +// Default activation behaviour - set the focus for the first child +// subwindow found. +void wxFrame::OnActivate(wxActivateEvent& event) +{ + if ( !event.GetActive() ) + { + // remember the last focused child if it is our child + m_winLastFocused = FindFocus(); + + // so we NULL it out if it's a child from some other frame + wxWindow *win = m_winLastFocused; + while ( win ) + { + if ( win->IsTopLevel() ) + { + if ( win != this ) + { + m_winLastFocused = NULL; + } + + break; + } + + win = win->GetParent(); + } + + event.Skip(); + } + else + { + // restore focus to the child which was last focused + wxWindow *parent = m_winLastFocused ? m_winLastFocused->GetParent() + : NULL; + if ( !parent ) + { + parent = this; + } + + wxSetFocusToChild(parent, &m_winLastFocused); + + if ( m_frameMenuBar != NULL ) + { + m_frameMenuBar->MacInstallMenuBar() ; + } + else if (wxTheApp->GetTopWindow() && wxTheApp->GetTopWindow()->IsKindOf(CLASSINFO(wxFrame))) + { + // Trying toplevel frame menbar + if( ((wxFrame*)wxTheApp->GetTopWindow())->GetMenuBar() ) + ((wxFrame*)wxTheApp->GetTopWindow())->GetMenuBar()->MacInstallMenuBar(); + } + } +} + +void wxFrame::DetachMenuBar() +{ + if ( m_frameMenuBar ) + { + m_frameMenuBar->UnsetInvokingWindow(); + } + + wxFrameBase::DetachMenuBar(); +} + +void wxFrame::AttachMenuBar( wxMenuBar *menuBar ) +{ + wxFrameBase::AttachMenuBar(menuBar); + + if (m_frameMenuBar) + { + m_frameMenuBar->SetInvokingWindow( this ); + } +} + +void wxFrame::DoGetClientSize(int *x, int *y) const +{ + wxWindow::DoGetClientSize( x , y ) ; + +#if wxUSE_STATUSBAR + if ( GetStatusBar() && y ) + { + int statusX, statusY; + GetStatusBar()->GetClientSize(&statusX, &statusY); + *y -= statusY; + } +#endif // wxUSE_STATUSBAR + + wxPoint pt(GetClientAreaOrigin()); + if ( y ) + *y -= pt.y; + if ( x ) + *x -= pt.x; +} + +void wxFrame::DoSetClientSize(int clientwidth, int clientheight) +{ + int currentclientwidth , currentclientheight ; + int currentwidth , currentheight ; + + GetClientSize( ¤tclientwidth , ¤tclientheight ) ; + GetSize( ¤twidth , ¤theight ) ; + + // find the current client size + + // Find the difference between the entire window (title bar and all) + // and the client area; add this to the new client size to move the + // window + + DoSetSize( -1 , -1 , currentwidth + clientwidth - currentclientwidth , + currentheight + clientheight - currentclientheight , wxSIZE_USE_EXISTING ) ; +} + + +#if wxUSE_TOOLBAR +wxToolBar* wxFrame::CreateToolBar(long style, wxWindowID id, const wxString& name) +{ + if ( wxFrameBase::CreateToolBar(style, id, name) ) + { + PositionToolBar(); + } + + return m_frameToolBar; +} + +void wxFrame::PositionToolBar() +{ + int cw, ch; + + cw = m_width ; + ch = m_height ; + + if ( GetStatusBar() ) + { + int statusX, statusY; + GetStatusBar()->GetClientSize(&statusX, &statusY); + ch -= statusY; + } + + if (GetToolBar()) + { + int tw, th; + GetToolBar()->GetSize(& tw, & th); + + if (GetToolBar()->GetWindowStyleFlag() & wxTB_VERTICAL) + { + // Use the 'real' position. wxSIZE_NO_ADJUSTMENTS + // means, pretend we don't have toolbar/status bar, so we + // have the original client size. + GetToolBar()->SetSize(-1, -1, tw, ch + 2 , wxSIZE_NO_ADJUSTMENTS | wxSIZE_ALLOW_MINUS_ONE ); + } + else + { + // Use the 'real' position + GetToolBar()->SetSize(-1, -1, cw + 2, th, wxSIZE_NO_ADJUSTMENTS | wxSIZE_ALLOW_MINUS_ONE ); + } + } +} +#endif diff --git a/src/mac/classic/gauge.cpp b/src/mac/classic/gauge.cpp new file mode 100644 index 0000000000..01a557e17c --- /dev/null +++ b/src/mac/classic/gauge.cpp @@ -0,0 +1,95 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: gauge.cpp +// Purpose: wxGauge class +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "gauge.h" +#endif + +#include "wx/gauge.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxGauge, wxControl) +#endif + +#include "wx/mac/uma.h" + +bool wxGauge::Create(wxWindow *parent, wxWindowID id, + int range, + const wxPoint& pos, + const wxSize& s, + long style, + const wxValidator& validator, + const wxString& name) +{ + if ( !wxGaugeBase::Create(parent, id, range, pos, s, style, validator, name) ) + return false; + + wxSize size = s ; + Rect bounds ; + Str255 title ; + m_rangeMax = range ; + m_gaugePos = 0 ; + + if ( size.x == wxDefaultSize.x && size.y == wxDefaultSize.y) + { + size = wxSize( 200 , 16 ) ; + } + + MacPreControlCreate( parent , id , wxEmptyString , pos , size ,style & 0xE0FFFFFF /* no borders on mac */ , validator , name , &bounds , title ) ; + + m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()) , &bounds , title , false , 0 , 0 , range, + kControlProgressBarProc , (long) this ) ; + + MacPostControlCreate() ; + + return TRUE; +} + +void wxGauge::SetShadowWidth(int w) +{ +} + +void wxGauge::SetBezelFace(int w) +{ +} + +void wxGauge::SetRange(int r) +{ + m_rangeMax = r; + ::SetControl32BitMaximum( (ControlHandle) m_macControl , m_rangeMax ) ; +} + +void wxGauge::SetValue(int pos) +{ + m_gaugePos = pos; + ::SetControl32BitValue( (ControlHandle) m_macControl , m_gaugePos ) ; +} + +int wxGauge::GetShadowWidth() const +{ + return 0; +} + +int wxGauge::GetBezelFace() const +{ + return 0; +} + +int wxGauge::GetRange() const +{ + return m_rangeMax; +} + +int wxGauge::GetValue() const +{ + return m_gaugePos; +} + diff --git a/src/mac/classic/gdiobj.cpp b/src/mac/classic/gdiobj.cpp new file mode 100644 index 0000000000..528c5a7efe --- /dev/null +++ b/src/mac/classic/gdiobj.cpp @@ -0,0 +1,22 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: gdiobj.cpp +// Purpose: wxGDIObject class +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "gdiobj.h" +#endif + +#include "wx/gdiobj.h" + +#if !USE_SHARED_LIBRARIES +IMPLEMENT_DYNAMIC_CLASS(wxGDIObject, wxObject) +#endif + +// TODO: Nothing to do, unless you want to. diff --git a/src/mac/classic/glcanvas.cpp b/src/mac/classic/glcanvas.cpp new file mode 100644 index 0000000000..e208531ff4 --- /dev/null +++ b/src/mac/classic/glcanvas.cpp @@ -0,0 +1,385 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: glcanvas.cpp +// Purpose: wxGLCanvas, for using OpenGL with wxWindows under Macintosh +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "glcanvas.h" +#endif + +#include "wx/wxprec.h" + +#if defined(__BORLANDC__) +#pragma hdrstop +#endif + +#include "wx/setup.h" + +#if wxUSE_GLCANVAS + +#ifndef WX_PRECOMP +#include "wx/frame.h" +#endif + +#include "wx/settings.h" +#include "wx/log.h" + +#include "wx/glcanvas.h" +#include "wx/mac/uma.h" + +// DLL options compatibility check: +#include "wx/build.h" +WX_CHECK_BUILD_OPTIONS("wxGL") + +/* +* GLContext implementation +*/ + +wxGLContext::wxGLContext( + AGLPixelFormat fmt, wxGLCanvas *win, + const wxPalette& palette, + const wxGLContext *other /* for sharing display lists */ + ) +{ + m_window = win; + + m_drawable = (AGLDrawable) UMAGetWindowPort(MAC_WXHWND(win->MacGetRootWindow())); + + m_glContext = aglCreateContext(fmt, other ? other->m_glContext : NULL); + wxCHECK_RET( m_glContext, wxT("Couldn't create OpenGl context") ); + + GLboolean b; + b = aglSetDrawable(m_glContext, m_drawable); + wxCHECK_RET( b, wxT("Couldn't bind OpenGl context") ); + aglEnable(m_glContext , AGL_BUFFER_RECT ) ; + b = aglSetCurrentContext(m_glContext); + wxCHECK_RET( b, wxT("Couldn't activate OpenGl context") ); +} + +wxGLContext::~wxGLContext() +{ + if (m_glContext) + { + aglSetCurrentContext(NULL); + aglDestroyContext(m_glContext); + } +} + +void wxGLContext::SwapBuffers() +{ + if (m_glContext) + { + aglSwapBuffers(m_glContext); + } +} + +void wxGLContext::SetCurrent() +{ + if (m_glContext) + { + aglSetCurrentContext(m_glContext); + } +} + +void wxGLContext::Update() +{ + if (m_glContext) + { + aglUpdateContext(m_glContext); + } +} + +void wxGLContext::SetColour(const wxChar *colour) +{ + wxColour col = wxTheColourDatabase->Find(colour); + if (col.Ok()) + { + float r = (float)(col.Red()/256.0); + float g = (float)(col.Green()/256.0); + float b = (float)(col.Blue()/256.0); + glColor3f( r, g, b); + } +} + + +/* +* wxGLCanvas implementation +*/ + +IMPLEMENT_CLASS(wxGLCanvas, wxWindow) + +BEGIN_EVENT_TABLE(wxGLCanvas, wxWindow) + EVT_SIZE(wxGLCanvas::OnSize) +END_EVENT_TABLE() + +wxGLCanvas::wxGLCanvas(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, long style, const wxString& name, + int *attribList, const wxPalette& palette) +{ + Create(parent, NULL, id, pos, size, style, name, attribList, palette); +} + +wxGLCanvas::wxGLCanvas( wxWindow *parent, + const wxGLContext *shared, wxWindowID id, + const wxPoint& pos, const wxSize& size, long style, const wxString& name, + int *attribList, const wxPalette& palette ) +{ + Create(parent, shared, id, pos, size, style, name, attribList, palette); +} + +wxGLCanvas::wxGLCanvas( wxWindow *parent, const wxGLCanvas *shared, wxWindowID id, + const wxPoint& pos, const wxSize& size, long style, const wxString& name, + int *attribList, const wxPalette& palette ) +{ + Create(parent, shared ? shared->GetContext() : NULL, id, pos, size, style, name, attribList, palette); +} + +wxGLCanvas::~wxGLCanvas() +{ + if (m_glContext != NULL) { + delete m_glContext; + m_glContext = NULL; + } +} + +static AGLPixelFormat ChoosePixelFormat(const int *attribList) +{ + GLint data[512]; + GLint defaultAttribs[] = { AGL_RGBA, + AGL_DOUBLEBUFFER, + AGL_MINIMUM_POLICY, + AGL_DEPTH_SIZE, 1, // use largest available depth buffer + AGL_RED_SIZE, 1, + AGL_GREEN_SIZE, 1, + AGL_BLUE_SIZE, 1, + AGL_ALPHA_SIZE, 0, + AGL_NONE }; + GLint *attribs; + if (!attribList) + { + attribs = defaultAttribs; + } + else + { + int arg=0, p=0; + + data[p++] = AGL_MINIMUM_POLICY; // make _SIZE tags behave more like GLX + while( (attribList[arg]!=0) && (p<512) ) + { + switch( attribList[arg++] ) + { + case WX_GL_RGBA: data[p++] = AGL_RGBA; break; + case WX_GL_BUFFER_SIZE: + data[p++]=AGL_BUFFER_SIZE; data[p++]=attribList[arg++]; break; + case WX_GL_LEVEL: + data[p++]=AGL_LEVEL; data[p++]=attribList[arg++]; break; + case WX_GL_DOUBLEBUFFER: data[p++] = AGL_DOUBLEBUFFER; break; + case WX_GL_STEREO: data[p++] = AGL_STEREO; break; + case WX_GL_AUX_BUFFERS: + data[p++]=AGL_AUX_BUFFERS; data[p++]=attribList[arg++]; break; + case WX_GL_MIN_RED: + data[p++]=AGL_RED_SIZE; data[p++]=attribList[arg++]; break; + case WX_GL_MIN_GREEN: + data[p++]=AGL_GREEN_SIZE; data[p++]=attribList[arg++]; break; + case WX_GL_MIN_BLUE: + data[p++]=AGL_BLUE_SIZE; data[p++]=attribList[arg++]; break; + case WX_GL_MIN_ALPHA: + data[p++]=AGL_ALPHA_SIZE; data[p++]=attribList[arg++]; break; + case WX_GL_DEPTH_SIZE: + data[p++]=AGL_DEPTH_SIZE; data[p++]=attribList[arg++]; break; + case WX_GL_STENCIL_SIZE: + data[p++]=AGL_STENCIL_SIZE; data[p++]=attribList[arg++]; break; + case WX_GL_MIN_ACCUM_RED: + data[p++]=AGL_ACCUM_RED_SIZE; data[p++]=attribList[arg++]; break; + case WX_GL_MIN_ACCUM_GREEN: + data[p++]=AGL_ACCUM_GREEN_SIZE; data[p++]=attribList[arg++]; break; + case WX_GL_MIN_ACCUM_BLUE: + data[p++]=AGL_ACCUM_BLUE_SIZE; data[p++]=attribList[arg++]; break; + case WX_GL_MIN_ACCUM_ALPHA: + data[p++]=AGL_ACCUM_ALPHA_SIZE; data[p++]=attribList[arg++]; break; + default: + break; + } + } + data[p] = 0; + + attribs = data; + } + + return aglChoosePixelFormat(NULL, 0, attribs); +} + +bool wxGLCanvas::Create(wxWindow *parent, const wxGLContext *shared, wxWindowID id, + const wxPoint& pos, const wxSize& size, long style, const wxString& name, + int *attribList, const wxPalette& palette) +{ + wxWindow::Create( parent, id, pos, size, style, name ); + + AGLPixelFormat fmt = ChoosePixelFormat(attribList); + wxCHECK_MSG( fmt, false, wxT("Couldn't create OpenGl pixel format") ); + + m_glContext = new wxGLContext(fmt, this, palette, shared); + m_macCanvasIsShown = true ; + aglDestroyPixelFormat(fmt); + + return true; +} + +void wxGLCanvas::SwapBuffers() +{ + if (m_glContext) + m_glContext->SwapBuffers(); +} + +void wxGLCanvas::UpdateContext() +{ + if (m_glContext) + m_glContext->Update(); +} + +void wxGLCanvas::SetViewport() +{ + // viewport is initially set to entire port + // adjust glViewport to just this window + int x = 0 ; + int y = 0 ; + + wxWindow* iter = this ; + while( iter->GetParent() ) + { + iter = iter->GetParent() ; + } + + if ( iter && iter->IsTopLevel() ) + { + MacClientToRootWindow( &x , &y ) ; + int width, height; + GetClientSize(& width, & height); + Rect bounds ; + GetWindowPortBounds( MAC_WXHWND(MacGetRootWindow()) , &bounds ) ; + GLint parms[4] ; + parms[0] = x ; + parms[1] = bounds.bottom - bounds.top - ( y + height ) ; + parms[2] = width ; + parms[3] = height ; + + if ( !m_macCanvasIsShown ) + parms[0] += 20000 ; + aglSetInteger( m_glContext->m_glContext , AGL_BUFFER_RECT , parms ) ; + } +} + +void wxGLCanvas::OnSize(wxSizeEvent& event) +{ + MacUpdateView() ; +} + +void wxGLCanvas::MacUpdateView() +{ + if (m_glContext) + { + UpdateContext(); + m_glContext->SetCurrent(); + SetViewport(); + } +} + +void wxGLCanvas::MacSuperChangedPosition() +{ + MacUpdateView() ; + wxWindow::MacSuperChangedPosition() ; +} + +void wxGLCanvas::MacTopLevelWindowChangedPosition() +{ + MacUpdateView() ; + wxWindow::MacTopLevelWindowChangedPosition() ; +} + +void wxGLCanvas::SetCurrent() +{ + if (m_glContext) + { + m_glContext->SetCurrent(); + } +} + +void wxGLCanvas::SetColour(const wxChar *colour) +{ + if (m_glContext) + m_glContext->SetColour(colour); +} + +bool wxGLCanvas::Show(bool show) +{ + if ( !wxWindow::Show( show ) ) + return FALSE ; + + if ( !show ) + { + if ( m_macCanvasIsShown ) + { + m_macCanvasIsShown = false ; + SetViewport() ; + } + } + else + { + if ( MacIsReallyShown() && !m_macCanvasIsShown ) + { + m_macCanvasIsShown = true ; + SetViewport() ; + } + } + return TRUE ; +} + +void wxGLCanvas::MacSuperShown( bool show ) +{ + if ( !show ) + { + if ( m_macCanvasIsShown ) + { + m_macCanvasIsShown = false ; + SetViewport() ; + } + } + else + { + if ( MacIsReallyShown() && !m_macCanvasIsShown ) + { + m_macCanvasIsShown = true ; + SetViewport() ; + } + } + + wxWindow::MacSuperShown( show ) ; +} + +//--------------------------------------------------------------------------- +// wxGLApp +//--------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxGLApp, wxApp) + +bool wxGLApp::InitGLVisual(int *attribList) +{ + AGLPixelFormat fmt = ChoosePixelFormat(attribList); + if (fmt != NULL) { + aglDestroyPixelFormat(fmt); + return true; + } else + return false; +} + +wxGLApp::~wxGLApp(void) +{ +} + +#endif // wxUSE_GLCANVAS diff --git a/src/mac/classic/gsocket.c b/src/mac/classic/gsocket.c new file mode 100644 index 0000000000..9e3ba3079a --- /dev/null +++ b/src/mac/classic/gsocket.c @@ -0,0 +1,1653 @@ +/* ------------------------------------------------------------------------- + * Project: GSocket (Generic Socket) for WX + * Name: gsocket.c + * Authors: Guilhem Lavaux, + * Guillermo Rodriguez Garcia (maintainer) + * Stefan CSomor + * Purpose: GSocket main mac file + * CVSID: $Id$ + * ------------------------------------------------------------------------- + */ + +/* + * PLEASE don't put C++ comments here - this is a C source file. + */ + +#ifndef __GSOCKET_STANDALONE__ +#include "wx/setup.h" +#include "wx/platform.h" +#endif + +#if wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) + +#ifdef __DARWIN__ + #include + + #ifndef FALSE + #define FALSE 0 + #endif + #ifndef TRUE + #define TRUE 1 + #endif +#else + #include + #define OTUNIXERRORS 1 + #include + #include + #include +#endif +#if TARGET_CARBON && !defined(OTAssert) + #define OTAssert( str , cond ) /* does not exists in Carbon */ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * INADDR_BROADCAST is identical to INADDR_NONE which is not defined + * on all unices. INADDR_BROADCAST should be fine to indicate an error. + */ +#ifndef INADDR_BROADCAST +#define INADDR_BROADCAST 0xFFFFFFFFUL +#endif +#ifndef INADDR_NONE +#define INADDR_NONE INADDR_BROADCAST +#endif +#ifndef INADDR_ANY +#define INADDR_ANY 0x0UL +#endif +#ifndef __GSOCKET_STANDALONE__ + +#include "wx/mac/macnotfy.h" +#include "wx/mac/gsockmac.h" +#include "wx/gsocket.h" + +#else + +#include "gsockmac.h" +#include "gsocket.h" + +#endif /* __GSOCKET_STANDALONE__ */ + +void wxCYield() ; +#ifdef __WXDEBUG__ +#define qDebug 1 +#define qDebug2 1 +extern pascal void OTDebugStr(const char* str); +#endif +#ifndef __DARWIN__ + #include +#endif +InetSvcRef gInetSvcRef = 0 ; +int gOTInited = 0 ; +OTNotifyUPP gOTNotifierUPP = NULL ; + +OSStatus DoNegotiateIPReuseAddrOption(EndpointRef ep, Boolean enableReuseIPMode); + +/* Input: ep - endpointref on which to negotiate the option + enableReuseIPMode - desired option setting - true/false + Return: kOTNoError indicates that the option was successfully negotiated + OSStatus is an error if < 0, otherwise, the status field is + returned and is > 0. + + IMPORTANT NOTE: The endpoint is assumed to be in synchronous more, otherwise + this code will not function as desired +*/ + + +OSStatus DoNegotiateIPReuseAddrOption(EndpointRef ep, Boolean enableReuseIPMode) + +{ + UInt8 buf[kOTFourByteOptionSize]; // define buffer for fourByte Option size + TOption* opt; // option ptr to make items easier to access + TOptMgmt req; + TOptMgmt ret; + OSStatus err; + + if (!OTIsSynchronous(ep)) + { + return (-1); + } + opt = (TOption*)buf; // set option ptr to buffer + req.opt.buf = buf; + req.opt.len = sizeof(buf); + req.flags = T_NEGOTIATE; // negotiate for option + + ret.opt.buf = buf; + ret.opt.maxlen = kOTFourByteOptionSize; + + opt->level = INET_IP; // dealing with an IP Level function +#ifdef __DARWIN__ + opt->name = kIP_REUSEADDR; +#else + opt->name = IP_REUSEADDR; +#endif + opt->len = kOTFourByteOptionSize; + opt->status = 0; + *(UInt32*)opt->value = enableReuseIPMode; // set the desired option level, true or false + + err = OTOptionManagement(ep, &req, &ret); + + // if no error then return the option status value + if (err == kOTNoError) + { + if (opt->status != T_SUCCESS) + err = opt->status; + else + err = kOTNoError; + } + + return err; +} + + +pascal void OTInetEventHandler(void*s, OTEventCode event, OTResult, void *cookie) ; +pascal void OTInetEventHandler(void*s, OTEventCode event, OTResult result, void *cookie) +{ + int wakeUp = true ; + GSocket* sock = (GSocket*) s ; + + if ( event == kOTSyncIdleEvent ) + { + YieldToAnyThread() ; + return ; + } + + if ( s ) + { + wxMacAddEvent( sock->m_mac_events , _GSocket_Internal_Proc , event , s , wakeUp ) ; + } + + return; +} + +static void SetDefaultEndpointModes(EndpointRef ep , void *data ) + // This routine sets the supplied endpoint into the default + // mode used in this application. The specifics are: + // blocking, synchronous, and using synch idle events with + // the standard YieldingNotifier. +{ + OSStatus junk = kOTNoError ; + OTAssert ("SetDefaultEndpointModes:invalid ref", ep != kOTInvalidEndpointRef ) ; + junk = OTSetAsynchronous(ep); + OTAssert("SetDefaultEndpointModes: Could not set asynchronous", junk == noErr); +/* + junk = OTSetBlocking(ep); + OTAssert("SetDefaultEndpointModes: Could not set blocking", junk == noErr); + junk = OTSetSynchronous(ep); + OTAssert("SetDefaultEndpointModes: Could not set synchronous", junk == noErr); + junk = OTSetBlocking(ep); + OTAssert("SetDefaultEndpointModes: Could not set blocking", junk == noErr); +*/ + junk = OTInstallNotifier(ep, gOTNotifierUPP, data); + OTAssert("SetDefaultEndpointModes: Could not install notifier", junk == noErr); +/* + junk = OTUseSyncIdleEvents(ep, true); + OTAssert("SetDefaultEndpointModes: Could not use sync idle events", junk == noErr); +*/ +} + +/* Global initialisers */ + +void GSocket_SetGUIFunctions(struct GSocketGUIFunctionsTable *table) +{ + // do nothing, wxMac doesn't have wxBase-GUI separation yet +} + +int GSocket_Init() +{ + return TRUE; +} + +int GSocket_Verify_Inited() ; +int GSocket_Verify_Inited() +{ + OSStatus err ; +#if TARGET_CARBON + // Marc Newsam: added the clientcontext variable + // however, documentation is unclear how this works + OTClientContextPtr clientcontext; + + if ( gInetSvcRef ) + return TRUE ; + + InitOpenTransportInContext(kInitOTForApplicationMask, &clientcontext); + gOTInited = 1 ; + gInetSvcRef = OTOpenInternetServicesInContext(kDefaultInternetServicesPath, + NULL, &err, clientcontext); +#else + if ( gInetSvcRef ) + return TRUE ; + + InitOpenTransport() ; + gOTInited = 1 ; + gInetSvcRef = OTOpenInternetServices(kDefaultInternetServicesPath, NULL, &err); +#endif + if ( gInetSvcRef == NULL || err != kOTNoError ) + { + OTAssert("Could not open Inet Services", err == noErr); + return FALSE ; + } + gOTNotifierUPP = NewOTNotifyUPP( OTInetEventHandler ) ; + return TRUE ; +} + +void GSocket_Cleanup() +{ + if ( gOTInited != 0 ) + { + if ( gInetSvcRef != NULL ) + OTCloseProvider( gInetSvcRef ); + #if TARGET_CARBON + CloseOpenTransportInContext( NULL ) ; + #else + CloseOpenTransport() ; + #endif + if ( gOTNotifierUPP ) + DisposeOTNotifyUPP( gOTNotifierUPP ) ; + } +} + +/* Constructors / Destructors for GSocket */ + +GSocket *GSocket_new() +{ + + int i; + GSocket *socket; + + if ( GSocket_Verify_Inited() == FALSE ) + return NULL ; + + socket = (GSocket *)malloc(sizeof(GSocket)); + + if (socket == NULL) + return NULL; + + socket->m_endpoint = NULL ; + for (i=0;im_cbacks[i] = NULL; + } + socket->m_detected = 0; + socket->m_local = NULL; + socket->m_peer = NULL; + socket->m_error = GSOCK_NOERROR; + socket->m_server = FALSE; + socket->m_stream = TRUE; + socket->m_non_blocking = FALSE; + socket->m_timeout = 1*1000; + /* 10 sec * 1000 millisec */ + socket->m_takesEvents = TRUE ; + socket->m_mac_events = wxMacGetNotifierTable() ; + return socket; +} + +void GSocket_destroy(GSocket *socket) +{ + assert(socket != NULL); + + /* Check that the socket is really shutdowned */ + if (socket->m_endpoint != kOTInvalidEndpointRef) + GSocket_Shutdown(socket); + + + /* Destroy private addresses */ + if (socket->m_local) + GAddress_destroy(socket->m_local); + + if (socket->m_peer) + GAddress_destroy(socket->m_peer); + + /* Destroy the socket itself */ + free(socket); +} + +/* GSocket_Shutdown: + * Disallow further read/write operations on this socket, close + * the fd and disable all callbacks. + */ +void GSocket_Shutdown(GSocket *socket) +{ + OSStatus err ; + int evt; + + assert(socket != NULL); + + /* If socket has been created, shutdown it */ + if (socket->m_endpoint != kOTInvalidEndpointRef ) + { + err = OTSndOrderlyDisconnect( socket->m_endpoint ) ; + if ( err != kOTNoError ) + { + + } + err = OTRcvOrderlyDisconnect( socket->m_endpoint ) ; + err = OTUnbind( socket->m_endpoint ) ; + err = OTCloseProvider( socket->m_endpoint ) ; + socket->m_endpoint = kOTInvalidEndpointRef ; + } + + /* Disable GUI callbacks */ + for (evt = 0; evt < GSOCK_MAX_EVENT; evt++) + socket->m_cbacks[evt] = NULL; + + socket->m_detected = 0; + _GSocket_Disable_Events(socket); + wxMacRemoveAllNotifiersForData( wxMacGetNotifierTable() , socket ) ; +} + + +/* Address handling */ + +/* GSocket_SetLocal: + * GSocket_GetLocal: + * GSocket_SetPeer: + * GSocket_GetPeer: + * Set or get the local or peer address for this socket. The 'set' + * functions return GSOCK_NOERROR on success, an error code otherwise. + * The 'get' functions return a pointer to a GAddress object on success, + * or NULL otherwise, in which case they set the error code of the + * corresponding GSocket. + * + * Error codes: + * GSOCK_INVSOCK - the socket is not valid. + * GSOCK_INVADDR - the address is not valid. + */ +GSocketError GSocket_SetLocal(GSocket *socket, GAddress *address) +{ + assert(socket != NULL); + + /* the socket must be initialized, or it must be a server */ + if ((socket->m_endpoint != kOTInvalidEndpointRef && !socket->m_server)) + { + socket->m_error = GSOCK_INVSOCK; + return GSOCK_INVSOCK; + } + + /* check address */ + if (address == NULL || address->m_family == GSOCK_NOFAMILY) + { + socket->m_error = GSOCK_INVADDR; + return GSOCK_INVADDR; + } + + if (socket->m_local) + GAddress_destroy(socket->m_local); + + socket->m_local = GAddress_copy(address); + + return GSOCK_NOERROR; +} + +GSocketError GSocket_SetPeer(GSocket *socket, GAddress *address) +{ + assert(socket != NULL); + + /* check address */ + if (address == NULL || address->m_family == GSOCK_NOFAMILY) + { + socket->m_error = GSOCK_INVADDR; + return GSOCK_INVADDR; + } + + if (socket->m_peer) + GAddress_destroy(socket->m_peer); + + socket->m_peer = GAddress_copy(address); + + return GSOCK_NOERROR; +} + +GAddress *GSocket_GetLocal(GSocket *socket) +{ + GAddress *address = NULL ; + GSocketError err; + InetAddress loc ; + + assert(socket != NULL); + + /* try to get it from the m_local var first */ + if (socket->m_local) + return GAddress_copy(socket->m_local); + + /* else, if the socket is initialized, try getsockname */ + if (socket->m_endpoint == kOTInvalidEndpointRef) + { + socket->m_error = GSOCK_INVSOCK; + return NULL; + } + + +/* we do not support multihoming with this code at the moment + OTGetProtAddress will have to be used then - but we don't have a handy + method to use right now +*/ + { + InetInterfaceInfo info; + OTInetGetInterfaceInfo(&info, kDefaultInetInterface); + loc.fHost = info.fAddress ; + loc.fPort = 0 ; + loc.fAddressType = AF_INET ; + } + + /* got a valid address from getsockname, create a GAddress object */ + address = GAddress_new(); + if (address == NULL) + { + socket->m_error = GSOCK_MEMERR; + return NULL; + } + + err = _GAddress_translate_from(address, &loc); + if (err != GSOCK_NOERROR) + { + GAddress_destroy(address); + socket->m_error = err; + return NULL; + } + + return address; +} + +GAddress *GSocket_GetPeer(GSocket *socket) +{ + assert(socket != NULL); + + /* try to get it from the m_peer var */ + if (socket->m_peer) + return GAddress_copy(socket->m_peer); + + return NULL; +} + +/* Server specific parts */ + +/* GSocket_SetServer: + * Sets up this socket as a server. The local address must have been + * set with GSocket_SetLocal() before GSocket_SetServer() is called. + * Returns GSOCK_NOERROR on success, one of the following otherwise: + * + * Error codes: + * GSOCK_INVSOCK - the socket is in use. + * GSOCK_INVADDR - the local address has not been set. + * GSOCK_IOERR - low-level error. + */ +GSocketError GSocket_SetServer(GSocket *sck) +{ + assert(sck != NULL); + + /* must not be in use */ + if (sck->m_endpoint != kOTInvalidEndpointRef ) + { + sck->m_error = GSOCK_INVSOCK; + return GSOCK_INVSOCK; + } + + /* the local addr must have been set */ + if (!sck->m_local) + { + sck->m_error = GSOCK_INVADDR; + return GSOCK_INVADDR; + } + + /* Initialize all fields */ + sck->m_stream = TRUE; + sck->m_server = TRUE; + sck->m_oriented = TRUE; + +// TODO +#if 0 + /* Create the socket */ + sck->m_endpoint = socket(sck->m_local->m_realfamily, SOCK_STREAM, 0); + socket_set_ref( sck->m_endpoint , (unsigned long) &gMacNetEvents , (unsigned long) sck ) ; + if (sck->m_endpoint == kOTInvalidEndpointRef) + { + sck->m_error = GSOCK_IOERR; + return GSOCK_IOERR; + } + + ioctl(sck->m_endpoint, FIONBIO, &arg); + _GSocket_Enable_Events(sck); + + /* Bind to the local address, + * retrieve the actual address bound, + * and listen up to 5 connections. + */ + if ((bind(sck->m_endpoint, sck->m_local->m_addr, sck->m_local->m_len) != 0) || + (getsockname(sck->m_endpoint, + sck->m_local->m_addr, + (SOCKLEN_T *) &sck->m_local->m_len) != 0) || + (listen(sck->m_endpoint, 5) != 0)) + { + close(sck->m_endpoint); + sck->m_endpoint = -1; + sck->m_error = GSOCK_IOERR; + return GSOCK_IOERR; + } +#endif + return GSOCK_NOERROR; +} + +/* GSocket_WaitConnection: + * Waits for an incoming client connection. Returns a pointer to + * a GSocket object, or NULL if there was an error, in which case + * the last error field will be updated for the calling GSocket. + * + * Error codes (set in the calling GSocket) + * GSOCK_INVSOCK - the socket is not valid or not a server. + * GSOCK_TIMEDOUT - timeout, no incoming connections. + * GSOCK_WOULDBLOCK - the call would block and the socket is nonblocking. + * GSOCK_MEMERR - couldn't allocate memory. + * GSOCK_IOERR - low-level error. + */ +GSocket *GSocket_WaitConnection(GSocket *socket) +{ + GSocket *connection = NULL ; + + assert(socket != NULL); + + /* Reenable CONNECTION events */ + socket->m_detected &= ~GSOCK_CONNECTION_FLAG; + + /* If the socket has already been created, we exit immediately */ + if (socket->m_endpoint == kOTInvalidEndpointRef || !socket->m_server) + { + socket->m_error = GSOCK_INVSOCK; + return NULL; + } + + /* Create a GSocket object for the new connection */ + connection = GSocket_new(); + + if (!connection) + { + socket->m_error = GSOCK_MEMERR; + return NULL; + } + + /* Wait for a connection (with timeout) */ + if (_GSocket_Input_Timeout(socket) == GSOCK_TIMEDOUT) + { + GSocket_destroy(connection); + /* socket->m_error set by _GSocket_Input_Timeout */ + return NULL; + } + +// TODO +#if 0 + connection->m_endpoint = accept(socket->m_endpoint, &from, (SOCKLEN_T *) &fromlen); +#endif + + if (connection->m_endpoint == kOTInvalidEndpointRef ) + { + if (errno == EWOULDBLOCK) + socket->m_error = GSOCK_WOULDBLOCK; + else + socket->m_error = GSOCK_IOERR; + + GSocket_destroy(connection); + return NULL; + } + + /* Initialize all fields */ + connection->m_server = FALSE; + connection->m_stream = TRUE; + connection->m_oriented = TRUE; + + /* Setup the peer address field */ + connection->m_peer = GAddress_new(); + if (!connection->m_peer) + { + GSocket_destroy(connection); + socket->m_error = GSOCK_MEMERR; + return NULL; + } + // TODO + #if 0 + err = _GAddress_translate_from(connection->m_peer, &from, fromlen); + if (err != GSOCK_NOERROR) + { + GAddress_destroy(connection->m_peer); + GSocket_destroy(connection); + socket->m_error = err; + return NULL; + } + + ioctl(connection->m_endpoint, FIONBIO, &arg); +#endif + _GSocket_Enable_Events(connection); + + return connection; +} + +/* Datagram sockets */ + +/* GSocket_SetNonOriented: + * Sets up this socket as a non-connection oriented (datagram) socket. + * Before using this function, the local address must have been set + * with GSocket_SetLocal(), or the call will fail. Returns GSOCK_NOERROR + * on success, or one of the following otherwise. + * + * Error codes: + * GSOCK_INVSOCK - the socket is in use. + * GSOCK_INVADDR - the local address has not been set. + * GSOCK_IOERR - low-level error. + */ +GSocketError GSocket_SetNonOriented(GSocket *sck) +{ + assert(sck != NULL); + + if (sck->m_endpoint != kOTInvalidEndpointRef ) + { + sck->m_error = GSOCK_INVSOCK; + return GSOCK_INVSOCK; + } + + if (!sck->m_local) + { + sck->m_error = GSOCK_INVADDR; + return GSOCK_INVADDR; + } + + /* Initialize all fields */ + sck->m_stream = FALSE; + sck->m_server = FALSE; + sck->m_oriented = FALSE; + + /* Create the socket */ + +// TODO +#if 0 + sck->m_endpoint = socket(sck->m_local->m_realfamily, SOCK_DGRAM, 0); + socket_set_ref( sck->m_endpoint , (unsigned long) &gMacNetEvents , (unsigned long) sck ) ; +#endif + if (sck->m_endpoint == kOTInvalidEndpointRef ) + { + sck->m_error = GSOCK_IOERR; + return GSOCK_IOERR; + } + +// TODO +#if 0 + ioctl(sck->m_endpoint, FIONBIO, &arg); +#endif + _GSocket_Enable_Events(sck); + + /* Bind to the local address, + * and retrieve the actual address bound. + */ +// TODO +#if 0 + if ((bind(sck->m_endpoint, sck->m_local->m_addr, sck->m_local->m_len) != 0) || + (getsockname(sck->m_endpoint, + sck->m_local->m_addr, + (SOCKLEN_T *) &sck->m_local->m_len) != 0)) + { + close(sck->m_endpoint); + sck->m_endpoint = -1; + sck->m_error = GSOCK_IOERR; + return GSOCK_IOERR; + } +#endif + return GSOCK_NOERROR; +} + +/* Client specific parts */ + +/* GSocket_Connect: + * For stream (connection oriented) sockets, GSocket_Connect() tries + * to establish a client connection to a server using the peer address + * as established with GSocket_SetPeer(). Returns GSOCK_NOERROR if the + * connection has been succesfully established, or one of the error + * codes listed below. Note that for nonblocking sockets, a return + * value of GSOCK_WOULDBLOCK doesn't mean a failure. The connection + * request can be completed later; you should use GSocket_Select() + * to poll for GSOCK_CONNECTION | GSOCK_LOST, or wait for the + * corresponding asynchronous events. + * + * For datagram (non connection oriented) sockets, GSocket_Connect() + * just sets the peer address established with GSocket_SetPeer() as + * default destination. + * + * Error codes: + * GSOCK_INVSOCK - the socket is in use or not valid. + * GSOCK_INVADDR - the peer address has not been established. + * GSOCK_TIMEDOUT - timeout, the connection failed. + * GSOCK_WOULDBLOCK - connection in progress (nonblocking sockets only) + * GSOCK_MEMERR - couldn't allocate memory. + * GSOCK_IOERR - low-level error. + */ +GSocketError GSocket_Connect(GSocket *sck, GSocketStream stream) +{ + InetAddress addr ; + TEndpointInfo info; + OSStatus err = kOTNoError; + TCall peer ; + + assert(sck != NULL); + + /* Enable CONNECTION events (needed for nonblocking connections) */ + sck->m_detected &= ~GSOCK_CONNECTION_FLAG; + + if (sck->m_endpoint != kOTInvalidEndpointRef ) + { + sck->m_error = GSOCK_INVSOCK; + return GSOCK_INVSOCK; + } + + if (!sck->m_peer) + { + sck->m_error = GSOCK_INVADDR; + return GSOCK_INVADDR; + } + + /* Streamed or dgram socket? */ + sck->m_stream = (stream == GSOCK_STREAMED); + sck->m_oriented = TRUE; + sck->m_server = FALSE; + + /* Create the socket */ +#if TARGET_CARBON + sck->m_endpoint = + OTOpenEndpointInContext( OTCreateConfiguration( kTCPName) , 0 , &info , &err , NULL ) ; +#else + sck->m_endpoint = + OTOpenEndpoint( OTCreateConfiguration( kTCPName) , 0 , &info , &err ) ; +#endif + if ( sck->m_endpoint == kOTInvalidEndpointRef || err != kOTNoError ) + { + sck->m_endpoint = kOTInvalidEndpointRef ; + sck->m_error = GSOCK_IOERR; + return GSOCK_IOERR; + } + err = OTBind( sck->m_endpoint , nil , nil ) ; + if ( err != kOTNoError ) + { + return GSOCK_IOERR; + } + SetDefaultEndpointModes( sck->m_endpoint , sck ) ; +// TODO +#if 0 + ioctl(sck->m_endpoint, FIONBIO, &arg); +#endif + _GSocket_Enable_Events(sck); + + _GAddress_translate_to( sck->m_peer , &addr ) ; + memset( &peer , 0 , sizeof( TCall ) ) ; + peer.addr.len = sizeof( InetAddress ) ; + peer.addr.buf = (unsigned char*) &addr ; + err = OTConnect( sck->m_endpoint , &peer , nil ) ; + if ( err != noErr ) + { + /* If connect failed with EINPROGRESS and the GSocket object + * is in blocking mode, we select() for the specified timeout + * checking for writability to see if the connection request + * completes. + */ + + if ((err == kOTNoDataErr ) && (!sck->m_non_blocking)) + { + if (_GSocket_Output_Timeout(sck) == GSOCK_TIMEDOUT) + { + OTSndOrderlyDisconnect( sck->m_endpoint ) ; + sck->m_endpoint = kOTInvalidEndpointRef ; + /* sck->m_error is set in _GSocket_Output_Timeout */ + return GSOCK_TIMEDOUT; + } + else + { +/* + int error; + SOCKLEN_T len = sizeof(error); + + getsockopt(sck->m_endpoint, SOL_SOCKET, SO_ERROR, (void*) &error, &len); + + if (!error) +*/ + return GSOCK_NOERROR; + } + } + + /* If connect failed with EINPROGRESS and the GSocket object + * is set to nonblocking, we set m_error to GSOCK_WOULDBLOCK + * (and return GSOCK_WOULDBLOCK) but we don't close the socket; + * this way if the connection completes, a GSOCK_CONNECTION + * event will be generated, if enabled. + */ + if ((err == kOTNoDataErr) && (sck->m_non_blocking)) + { + sck->m_error = GSOCK_WOULDBLOCK; + return GSOCK_WOULDBLOCK; + } + + /* If connect failed with an error other than EINPROGRESS, + * then the call to GSocket_Connect has failed. + */ + OTSndOrderlyDisconnect( sck->m_endpoint ) ; + + sck->m_endpoint = kOTInvalidEndpointRef ; + sck->m_error = GSOCK_IOERR; + return GSOCK_IOERR; + } +// OTInetEventHandler(sck, T_CONNECT , kOTNoError , NULL ) ; + return GSOCK_NOERROR; +} + +/* Generic IO */ + +/* Like recv(), send(), ... */ +int GSocket_Read(GSocket *socket, char *buffer, int size) +{ + int ret = 0 ; + + assert(socket != NULL); + + /* Reenable INPUT events */ + socket->m_detected &= ~GSOCK_INPUT_FLAG; + + if (socket->m_endpoint == kOTInvalidEndpointRef || socket->m_server) + { + socket->m_error = GSOCK_INVSOCK; + return -1; + } + + /* If the socket is blocking, wait for data (with a timeout) */ + if (_GSocket_Input_Timeout(socket) == GSOCK_TIMEDOUT) + return -1; + + /* Read the data */ + if (socket->m_stream) + ret = _GSocket_Recv_Stream(socket, buffer, size); + else + ret = _GSocket_Recv_Dgram(socket, buffer, size); + + if (ret == -1) + { + if (errno == EWOULDBLOCK) + socket->m_error = GSOCK_WOULDBLOCK; + else + socket->m_error = GSOCK_IOERR; + } + + return ret; +} + +int GSocket_Write(GSocket *socket, const char *buffer, int size) +{ + int ret; + + assert(socket != NULL); + + if (socket->m_endpoint == kOTInvalidEndpointRef || socket->m_server) + { + socket->m_error = GSOCK_INVSOCK; + return -1; + } + + /* If the socket is blocking, wait for writability (with a timeout) */ + if (_GSocket_Output_Timeout(socket) == GSOCK_TIMEDOUT) + return -1; + + /* Write the data */ + if (socket->m_stream) + ret = _GSocket_Send_Stream(socket, buffer, size); + else + ret = _GSocket_Send_Dgram(socket, buffer, size); + + if (ret == -1) + { + if (errno == EWOULDBLOCK) + socket->m_error = GSOCK_WOULDBLOCK; + else + socket->m_error = GSOCK_IOERR; + + /* Only reenable OUTPUT events after an error (just like WSAAsyncSelect + * in MSW). Once the first OUTPUT event is received, users can assume + * that the socket is writable until a read operation fails. Only then + * will further OUTPUT events be posted. + */ + socket->m_detected &= ~GSOCK_OUTPUT_FLAG; + return -1; + } + + return ret; +} + +/* GSocket_Select: + * Polls the socket to determine its status. This function will + * check for the events specified in the 'flags' parameter, and + * it will return a mask indicating which operations can be + * performed. This function won't block, regardless of the + * mode (blocking | nonblocking) of the socket. + */ +GSocketEventFlags GSocket_Select(GSocket *socket, GSocketEventFlags flags) +{ + assert(socket != NULL); + wxMacProcessNotifierEvents() ; + /* + state = OTGetEndpointState(socket->m_endpoint); + + if ( ( flags & GSOCK_INPUT_FLAG ) && ! ( socket->m_detected & GSOCK_INPUT_FLAG ) ) + { + size_t sz = 0 ; + OTCountDataBytes( socket->m_endpoint , &sz ) ; + if ( state == T_INCON || sz > 0 ) + { + socket->m_detected |= GSOCK_INPUT_FLAG ; + (socket->m_cbacks[GSOCK_INPUT])(socket, GSOCK_INPUT, socket->m_data[GSOCK_INPUT]); + } + } + if ( ( flags & GSOCK_INPUT_FLAG ) && ! ( socket->m_detected & GSOCK_OUTPUT_FLAG ) ) + { + if ( state == T_DATAXFER || state == T_INREL ) + { + socket->m_detected |=GSOCK_OUTPUT_FLAG ; + (socket->m_cbacks[GSOCK_OUTPUT])(socket, GSOCK_OUTPUT, socket->m_data[GSOCK_OUTPUT]); + } + } + */ + return ( flags & socket->m_detected ) ; +} + +/* Flags */ + +/* GSocket_SetNonBlocking: + * Sets the socket to non-blocking mode. All IO calls will return + * immediately. + */ +void GSocket_SetNonBlocking(GSocket *socket, int non_block) +{ + assert(socket != NULL); + + socket->m_non_blocking = non_block; +} + +/* GSocket_SetTimeout: + * Sets the timeout for blocking calls. Time is expressed in + * milliseconds. + */ +void GSocket_SetTimeout(GSocket *socket, unsigned long millisec) +{ + assert(socket != NULL); + +// this is usually set too high and we have not yet been able to detect a closed +// stream, thus we leave the 10 sec timeout +// socket->m_timeout = millisec; +} + +/* GSocket_GetError: + * Returns the last error occured for this socket. Note that successful + * operations do not clear this back to GSOCK_NOERROR, so use it only + * after an error. + */ +GSocketError GSocket_GetError(GSocket *socket) +{ + assert(socket != NULL); + + return socket->m_error; +} + +/* Callbacks */ + +/* GSOCK_INPUT: + * There is data to be read in the input buffer. If, after a read + * operation, there is still data available, the callback function will + * be called again. + * GSOCK_OUTPUT: + * The socket is available for writing. That is, the next write call + * won't block. This event is generated only once, when the connection is + * first established, and then only if a call failed with GSOCK_WOULDBLOCK, + * when the output buffer empties again. This means that the app should + * assume that it can write since the first OUTPUT event, and no more + * OUTPUT events will be generated unless an error occurs. + * GSOCK_CONNECTION: + * Connection succesfully established, for client sockets, or incoming + * client connection, for server sockets. Wait for this event (also watch + * out for GSOCK_LOST) after you issue a nonblocking GSocket_Connect() call. + * GSOCK_LOST: + * The connection is lost (or a connection request failed); this could + * be due to a failure, or due to the peer closing it gracefully. + */ + +/* GSocket_SetCallback: + * Enables the callbacks specified by 'flags'. Note that 'flags' + * may be a combination of flags OR'ed toghether, so the same + * callback function can be made to accept different events. + * The callback function must have the following prototype: + * + * void function(GSocket *socket, GSocketEvent event, char *cdata) + */ +void GSocket_SetCallback(GSocket *socket, GSocketEventFlags flags, + GSocketCallback callback, char *cdata) +{ + int count; + + assert(socket != NULL); + + for (count = 0; count < GSOCK_MAX_EVENT; count++) + { + if ((flags & (1 << count)) != 0) + { + socket->m_cbacks[count] = callback; + socket->m_data[count] = cdata; + } + } +} + +/* GSocket_UnsetCallback: + * Disables all callbacks specified by 'flags', which may be a + * combination of flags OR'ed toghether. + */ +void GSocket_UnsetCallback(GSocket *socket, GSocketEventFlags flags) +{ + int count; + + assert(socket != NULL); + + for (count = 0; count < GSOCK_MAX_EVENT; count++) + { + if ((flags & (1 << count)) != 0) + { + socket->m_cbacks[count] = NULL; + socket->m_data[count] = NULL; + } + } +} + + +#define CALL_CALLBACK(socket, event) { \ + _GSocket_Disable(socket, event); \ + if (socket->m_cbacks[event]) \ + socket->m_cbacks[event](socket, event, socket->m_data[event]); \ +} + +int _GSocket_Recv_Stream(GSocket *socket, char *buffer, int size) +{ + OTFlags flags ; + OTResult res ; + OTByteCount sz = 0 ; + + OTCountDataBytes( socket->m_endpoint , &sz ) ; + if ( size > (int)sz ) + size = sz ; + res = OTRcv( socket->m_endpoint , buffer , size , &flags ) ; + if ( res < 0 ) + { + return -1 ; + } + + // we simulate another read event if there are still bytes + if ( socket->m_takesEvents ) + { + OTByteCount sz = 0 ; + OTCountDataBytes( socket->m_endpoint , &sz ) ; + if ( sz > 0 ) + { + socket->m_detected |= GSOCK_INPUT_FLAG ; + (socket->m_cbacks[GSOCK_INPUT])(socket, GSOCK_INPUT, socket->m_data[GSOCK_INPUT]); + } + } + return res ; +} + +int _GSocket_Recv_Dgram(GSocket *socket, char *buffer, int size) +{ +// TODO + int ret = -1; +#if 0 + struct sockaddr from; + SOCKLEN_T fromlen = sizeof(from); + GSocketError err; + + fromlen = sizeof(from); + + ret = recvfrom(socket->m_endpoint, buffer, size, 0, &from, (SOCKLEN_T *) &fromlen); + + if (ret == -1) + return -1; + + /* Translate a system address into a GSocket address */ + if (!socket->m_peer) + { + socket->m_peer = GAddress_new(); + if (!socket->m_peer) + { + socket->m_error = GSOCK_MEMERR; + return -1; + } + } + err = _GAddress_translate_from(socket->m_peer, &from, fromlen); + if (err != GSOCK_NOERROR) + { + GAddress_destroy(socket->m_peer); + socket->m_peer = NULL; + socket->m_error = err; + return -1; + } +#endif + return ret; +} + +int _GSocket_Send_Stream(GSocket *socket, const char *buffer, int size) +{ + OTFlags flags = 0 ; + OTResult res ; + + res = OTSnd( socket->m_endpoint , (void*) buffer , size , flags ) ; + return res ; +} + +int _GSocket_Send_Dgram(GSocket *socket, const char *buffer, int size) +{ + int ret = -1 ; +// TODO +#if 0 + struct sockaddr *addr; + int len ; + GSocketError err; + + if (!socket->m_peer) + { + socket->m_error = GSOCK_INVADDR; + return -1; + } + + err = _GAddress_translate_to(socket->m_peer, &addr, &len); + if (err != GSOCK_NOERROR) + { + socket->m_error = err; + return -1; + } + + ret = sendto(socket->m_endpoint, buffer, size, 0, addr, len); + + /* Frees memory allocated from _GAddress_translate_to */ + free(addr); +#endif + return ret; +} + + +/* + * ------------------------------------------------------------------------- + * GAddress + * ------------------------------------------------------------------------- + */ + +/* CHECK_ADDRESS verifies that the current family is either GSOCK_NOFAMILY + * or GSOCK_*family*, and if it is GSOCK_NOFAMILY, it initalizes address + * to be a GSOCK_*family*. In other cases, it returns GSOCK_INVADDR. + */ +#define CHECK_ADDRESS(address, family, retval) \ +{ \ + if (address->m_family == GSOCK_NOFAMILY) \ + if (_GAddress_Init_##family(address) != GSOCK_NOERROR) \ + return address->m_error; \ + if (address->m_family != GSOCK_##family) \ + { \ + address->m_error = GSOCK_INVADDR; \ + return retval; \ + } \ +} + +GAddress *GAddress_new() +{ + GAddress *address; + + if ((address = (GAddress *) malloc(sizeof(GAddress))) == NULL) + return NULL; + + address->m_family = GSOCK_NOFAMILY; + address->m_host = INADDR_NONE ; + address->m_port = 0 ; + + return address; +} + +GAddress *GAddress_copy(GAddress *address) +{ + GAddress *addr2; + + assert(address != NULL); + + if ((addr2 = (GAddress *) malloc(sizeof(GAddress))) == NULL) + return NULL; + + memcpy(addr2, address, sizeof(GAddress)); + return addr2; +} + +void GAddress_destroy(GAddress *address) +{ + assert(address != NULL); + + free(address); +} + +void GAddress_SetFamily(GAddress *address, GAddressType type) +{ + assert(address != NULL); + + address->m_family = type; +} + +GAddressType GAddress_GetFamily(GAddress *address) +{ + assert(address != NULL); + + return address->m_family; +} + +GSocketError _GAddress_translate_from(GAddress *address, + InetAddress *addr) +{ + switch (addr->fAddressType) + { + case AF_INET: + address->m_family = GSOCK_INET; + break; +#ifdef AF_INET6 + case AF_INET6: + address->m_family = GSOCK_INET6; + break; +#endif + default: + { + address->m_error = GSOCK_INVOP; + return GSOCK_INVOP; + } + } + address->m_host = addr->fHost ; + address->m_port = addr->fPort ; + return GSOCK_NOERROR; +} + +GSocketError _GAddress_translate_to(GAddress *address, + InetAddress *addr) +{ + if ( GSocket_Verify_Inited() == FALSE ) + return GSOCK_IOERR ; + memset(addr, 0 , sizeof(struct InetAddress)); + OTInitInetAddress( addr , address->m_port , address->m_host ) ; + return GSOCK_NOERROR; +} + +/* + * ------------------------------------------------------------------------- + * Internet address family + * ------------------------------------------------------------------------- + */ + +GSocketError _GAddress_Init_INET(GAddress *address) +{ + address->m_family = GSOCK_INET; + address->m_host = kOTAnyInetAddress ; + + return GSOCK_NOERROR; +} + +GSocketError GAddress_INET_SetHostName(GAddress *address, const char *hostname) +{ + InetHostInfo hinfo ; + OSStatus ret ; + + if ( GSocket_Verify_Inited() == FALSE ) + return GSOCK_IOERR ; + + assert(address != NULL); + + CHECK_ADDRESS(address, INET, GSOCK_INVADDR); + ret = OTInetStringToAddress( gInetSvcRef , (char*) hostname , &hinfo ) ; + if ( ret != kOTNoError ) + { + address->m_host = INADDR_NONE ; + address->m_error = GSOCK_NOHOST; + return GSOCK_NOHOST; + } + address->m_host = hinfo.addrs[0] ; + return GSOCK_NOERROR; +} + +GSocketError GAddress_INET_SetAnyAddress(GAddress *address) +{ + return GAddress_INET_SetHostAddress(address, INADDR_ANY); +} + +GSocketError GAddress_INET_SetHostAddress(GAddress *address, + unsigned long hostaddr) +{ + assert(address != NULL); + + CHECK_ADDRESS(address, INET, GSOCK_INVADDR); + + address->m_host = hostaddr ; + + return GSOCK_NOERROR; +} + +struct service_entry +{ + char * name ; + unsigned short port ; + char * protocol ; +} ; +typedef struct service_entry service_entry ; + +service_entry gServices[] = +{ + { "http" , 80 , "tcp" } +} ; + +GSocketError GAddress_INET_SetPortName(GAddress *address, const char *port, + const char *protocol) +{ + size_t i ; + + assert(address != NULL); + CHECK_ADDRESS(address, INET, GSOCK_INVADDR); + + if (!port) + { + address->m_error = GSOCK_INVPORT; + return GSOCK_INVPORT; + } + for ( i = 0 ; i < sizeof( gServices) / sizeof( service_entry ) ; ++i ) + { + if ( strcmp( port , gServices[i].name ) == 0 ) + { + if ( protocol == NULL || strcmp( protocol , gServices[i].protocol ) ) + { + address->m_port = gServices[i].port ; + return GSOCK_NOERROR; + } + } + } + + if (isdigit(port[0])) + { + address->m_port = atoi(port); + return GSOCK_NOERROR; + } + + address->m_error = GSOCK_INVPORT; + return GSOCK_INVPORT; +} + +GSocketError GAddress_INET_SetPort(GAddress *address, unsigned short port) +{ + assert(address != NULL); + CHECK_ADDRESS(address, INET, GSOCK_INVADDR); + address->m_port = port ; + + return GSOCK_NOERROR; +} + +GSocketError GAddress_INET_GetHostName(GAddress *address, char *hostname, size_t sbuf) +{ + InetDomainName name ; + if ( GSocket_Verify_Inited() == FALSE ) + return GSOCK_IOERR ; + + assert(address != NULL); + CHECK_ADDRESS(address, INET, GSOCK_INVADDR); + + OTInetAddressToName( gInetSvcRef , address->m_host , name ) ; + strncpy( hostname , name , sbuf ) ; + return GSOCK_NOERROR; +} + +unsigned long GAddress_INET_GetHostAddress(GAddress *address) +{ + assert(address != NULL); + CHECK_ADDRESS(address, INET, 0); + + return address->m_host; +} + +unsigned short GAddress_INET_GetPort(GAddress *address) +{ + assert(address != NULL); + CHECK_ADDRESS(address, INET, 0); + + return address->m_port; +} + +void _GSocket_Enable_Events(GSocket *socket) +{ + if ( socket->m_takesEvents ) + return ; + + { + OTResult state ; + socket->m_takesEvents = TRUE ; + state = OTGetEndpointState(socket->m_endpoint); + + { + OTByteCount sz = 0 ; + OTCountDataBytes( socket->m_endpoint , &sz ) ; + if ( state == T_INCON || sz > 0 ) + { + socket->m_detected |= GSOCK_INPUT_FLAG ; + (socket->m_cbacks[GSOCK_INPUT])(socket, GSOCK_INPUT, socket->m_data[GSOCK_INPUT]); + } + } + { + if ( state == T_DATAXFER || state == T_INREL ) + { + socket->m_detected |=GSOCK_OUTPUT_FLAG ; + (socket->m_cbacks[GSOCK_OUTPUT])(socket, GSOCK_OUTPUT, socket->m_data[GSOCK_OUTPUT]); + } + } + } +} + +void _GSocket_Disable_Events(GSocket *socket) +{ + socket->m_takesEvents = FALSE ; +} + +/* _GSocket_Input_Timeout: + * For blocking sockets, wait until data is available or + * until timeout ellapses. + */ +GSocketError _GSocket_Input_Timeout(GSocket *socket) +{ + if ( !socket->m_non_blocking ) + { + UnsignedWide now , start ; + short formerTakesEvents = socket->m_takesEvents ; + Microseconds(&start); + now = start ; + socket->m_takesEvents = FALSE ; + + while( (now.hi * 4294967296.0 + now.lo) - (start.hi * 4294967296.0 + start.lo) < socket->m_timeout * 1000.0 ) + { + OTResult state ; + OTByteCount sz = 0 ; + state = OTGetEndpointState(socket->m_endpoint); + + OTCountDataBytes( socket->m_endpoint , &sz ) ; + if ( state == T_INCON || sz > 0 ) + { + socket->m_takesEvents = formerTakesEvents ; + return GSOCK_NOERROR; + } + Microseconds(&now); + } + socket->m_takesEvents = formerTakesEvents ; + socket->m_error = GSOCK_TIMEDOUT; + return GSOCK_TIMEDOUT; + } + return GSOCK_NOERROR; +} + +/* _GSocket_Output_Timeout: + * For blocking sockets, wait until data can be sent without + * blocking or until timeout ellapses. + */ +GSocketError _GSocket_Output_Timeout(GSocket *socket) +{ + if ( !socket->m_non_blocking ) + { + UnsignedWide now , start ; + short formerTakesEvents = socket->m_takesEvents ; + Microseconds(&start); + now = start ; + socket->m_takesEvents = FALSE ; + + while( (now.hi * 4294967296.0 + now.lo) - (start.hi * 4294967296.0 + start.lo) < socket->m_timeout * 1000.0 ) + { + OTResult state ; + state = OTGetEndpointState(socket->m_endpoint); + + if ( state == T_DATAXFER || state == T_INREL ) + { + socket->m_takesEvents = formerTakesEvents ; + return GSOCK_NOERROR; + } + Microseconds(&now); + } + socket->m_takesEvents = formerTakesEvents ; + socket->m_error = GSOCK_TIMEDOUT; + return GSOCK_TIMEDOUT; + } + return GSOCK_NOERROR; +} + +/* GSOCK_INPUT: + * There is data to be read in the input buffer. If, after a read + * operation, there is still data available, the callback function will + * be called again. + * GSOCK_OUTPUT: + * The socket is available for writing. That is, the next write call + * won't block. This event is generated only once, when the connection is + * first established, and then only if a call failed with GSOCK_WOULDBLOCK, + * when the output buffer empties again. This means that the app should + * assume that it can write since the first OUTPUT event, and no more + * OUTPUT events will be generated unless an error occurs. + * GSOCK_CONNECTION: + * Connection succesfully established, for client sockets, or incoming + * client connection, for server sockets. Wait for this event (also watch + * out for GSOCK_LOST) after you issue a nonblocking GSocket_Connect() call. + * GSOCK_LOST: + * The connection is lost (or a connection request failed); this could + * be due to a failure, or due to the peer closing it gracefully. + */ + +void _GSocket_Internal_Proc(unsigned long e , void* d ) +{ + + GSocket * socket = (GSocket*) d ; + OTEventCode ev = (OTEventCode) e ; + GSocketEvent event; + GSocketEvent event2; + GSocketCallback cback; + char *data; + GSocketCallback cback2; + char *data2; + + if ( !socket ) + return ; + event = GSOCK_MAX_EVENT ; + event2 = GSOCK_MAX_EVENT ; + cback = NULL; + data = NULL; + cback2 = NULL; + data2 = NULL; + + /* Check that the socket still exists (it has not been + * destroyed) and for safety, check that the m_endpoint field + * is what we expect it to be. + */ + if ((socket != NULL) && (socket->m_takesEvents)) + { + switch (ev) + { + case T_LISTEN : + event = GSOCK_CONNECTION ; + break ; + case T_CONNECT : + event = GSOCK_CONNECTION ; + event2 = GSOCK_OUTPUT ; + { + TCall retCall; + + retCall.addr.buf = NULL; + retCall.addr.maxlen = 0; + retCall.opt.buf = NULL; + retCall.opt.maxlen = 0; + retCall.udata.buf = NULL; + retCall.udata.maxlen= 0; + OTRcvConnect( socket->m_endpoint , &retCall ) ; + } + break ; + case T_DISCONNECT : + event = GSOCK_LOST ; + break ; + case T_GODATA : + case T_GOEXDATA : + event = GSOCK_OUTPUT ; + break ; + case T_DATA : + event = GSOCK_INPUT ; + break ; + case T_EXDATA : + event = GSOCK_INPUT ; + break ; + } + if (event != GSOCK_MAX_EVENT) + { + cback = socket->m_cbacks[event]; + data = socket->m_data[event]; + + if (event == GSOCK_LOST) + socket->m_detected = GSOCK_LOST_FLAG; + else + socket->m_detected |= (1 << event); + } + if (event2 != GSOCK_MAX_EVENT) + { + cback2 = socket->m_cbacks[event2]; + data2 = socket->m_data[event2]; + + if (event2 == GSOCK_LOST) + socket->m_detected = GSOCK_LOST_FLAG; + else + socket->m_detected |= (1 << event2); + } + } + + /* OK, we can now leave the critical section because we have + * already obtained the callback address (we make no further + * accesses to socket->whatever). However, the app should + * be prepared to handle events from a socket that has just + * been closed! + */ + + if (cback != NULL) + (cback)(socket, event, data); + if (cback2 != NULL) + (cback2)(socket, event2, data2); + +} + +/* Hack added for Mac OS X */ +GSocketError GAddress_UNIX_GetPath(GAddress *addr, char *path, size_t buf) +{ + return GSOCK_INVADDR; +} + +GSocketError GAddress_UNIX_SetPath(GAddress *addr, const char *path) +{ + return GSOCK_INVADDR; +} + +#endif /* wxUSE_SOCKETS || defined(__GSOCKET_STANDALONE__) */ diff --git a/src/mac/classic/gsockosx.c b/src/mac/classic/gsockosx.c new file mode 100644 index 0000000000..614ed425c8 --- /dev/null +++ b/src/mac/classic/gsockosx.c @@ -0,0 +1,181 @@ +/* ------------------------------------------------------------------------- + * Project: GSocket (Generic Socket) for WX + * Name: gsockosx.c + * Purpose: GSocket: Mac OS X mach-o part + * CVSID: $Id$ + * Mac code by Brian Victor, February 2002. Email comments to bhv1@psu.edu + * ------------------------------------------------------------------------- */ + +#include "wx/setup.h" + +#if wxUSE_SOCKETS + +#include +#include "wx/gsocket.h" +#include "wx/unix/gsockunx.h" + +#include + +#define ALL_CALLBACK_TYPES (kCFSocketReadCallBack | kCFSocketWriteCallBack | kCFSocketConnectCallBack) + +struct MacGSocketData +{ + CFSocketRef socket; + CFRunLoopSourceRef source; +}; + +void Mac_Socket_Callback(CFSocketRef s, CFSocketCallBackType callbackType, + CFDataRef address, const void* data, void* info) +{ + GSocket* socket = (GSocket*)info; + struct MacGSocketData* macdata; + macdata = (struct MacGSocketData*)socket->m_gui_dependent; + if (!macdata) return; + switch (callbackType) + { + case kCFSocketConnectCallBack: + assert(!socket->m_server); + socket->m_functions->Detected_Write(socket); + break; + case kCFSocketReadCallBack: + socket->m_functions->Detected_Read(socket); + break; + case kCFSocketWriteCallBack: + socket->m_functions->Detected_Write(socket); + break; + default: + break; /* We shouldn't get here. */ + } +} + +struct MacGSocketData* _GSocket_Get_Mac_Socket(GSocket *socket) +{ + /* If socket is already created, returns a pointer to the data */ + /* Otherwise, creates socket and returns the pointer */ + CFSocketContext cont; + struct MacGSocketData* data = (struct MacGSocketData*)socket->m_gui_dependent; + + if (data && data->source) return data; + + /* CFSocket has not been created, create it: */ + if (socket->m_fd < 0 || !data) return NULL; + cont.version = 0; cont.retain = NULL; + cont.release = NULL; cont.copyDescription = NULL; + cont.info = socket; + + CFSocketRef cf = CFSocketCreateWithNative(NULL, socket->m_fd, + ALL_CALLBACK_TYPES, Mac_Socket_Callback, &cont); + CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(NULL, cf, 0); + assert(source); + socket->m_gui_dependent = (char*)data; + + /* Keep the source and the socket around. */ + data->source = source; + data->socket = cf; + + return data; +} + +int _GSocket_GUI_Init(void) +{ + return 1; +} + +void _GSocket_GUI_Cleanup(void) +{ +} + +int _GSocket_GUI_Init_Socket(GSocket *socket) +{ + struct MacGSocketData *data = malloc(sizeof(struct MacGSocketData)); + if (data) + { + socket->m_gui_dependent = (char*)data; + data->socket = NULL; + data->source = NULL; + return 1; + } + return 0; +} + +void _GSocket_GUI_Destroy_Socket(GSocket *socket) +{ + struct MacGSocketData *data = (struct MacGSocketData*)(socket->m_gui_dependent); + if (data) + { + CFRelease(data->socket); + free(data); + } +} + +void _GSocket_Install_Callback(GSocket *socket, GSocketEvent event) +{ + int c; + struct MacGSocketData* data = _GSocket_Get_Mac_Socket(socket); + if (!data) return; + switch (event) + { + case GSOCK_CONNECTION: + if(socket->m_server) + c = kCFSocketReadCallBack; + else + c = kCFSocketConnectCallBack; + break; + case GSOCK_LOST: + case GSOCK_INPUT: + c = kCFSocketReadCallBack; + break; + case GSOCK_OUTPUT: + c = kCFSocketWriteCallBack; + break; + default: + c = 0; + } + CFSocketEnableCallBacks(data->socket, c); +} + +void _GSocket_Uninstall_Callback(GSocket *socket, GSocketEvent event) +{ + int c; + struct MacGSocketData* data = _GSocket_Get_Mac_Socket(socket); + if (!data) return; + switch (event) + { + case GSOCK_CONNECTION: + if(socket->m_server) + c = kCFSocketReadCallBack; + else + c = kCFSocketConnectCallBack; + break; + case GSOCK_LOST: + case GSOCK_INPUT: + c = kCFSocketReadCallBack; + break; + case GSOCK_OUTPUT: + c = kCFSocketWriteCallBack; + break; + default: + c = 0; + } + CFSocketDisableCallBacks(data->socket, c); +} + +void _GSocket_Enable_Events(GSocket *socket) +{ + struct MacGSocketData* data = _GSocket_Get_Mac_Socket(socket); + if (!data) return; + + CFRunLoopAddSource(CFRunLoopGetCurrent(), data->source, kCFRunLoopDefaultMode); +} + +void _GSocket_Disable_Events(GSocket *socket) +{ + struct MacGSocketData* data = _GSocket_Get_Mac_Socket(socket); + if (!data) return; + + /* CFSocketInvalidate does CFRunLoopRemoveSource anyway */ + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), data->source, kCFRunLoopCommonModes); + CFSocketInvalidate(data->socket); +} + +#endif // wxUSE_SOCKETS diff --git a/src/mac/classic/gsockosx.cpp b/src/mac/classic/gsockosx.cpp new file mode 100644 index 0000000000..614ed425c8 --- /dev/null +++ b/src/mac/classic/gsockosx.cpp @@ -0,0 +1,181 @@ +/* ------------------------------------------------------------------------- + * Project: GSocket (Generic Socket) for WX + * Name: gsockosx.c + * Purpose: GSocket: Mac OS X mach-o part + * CVSID: $Id$ + * Mac code by Brian Victor, February 2002. Email comments to bhv1@psu.edu + * ------------------------------------------------------------------------- */ + +#include "wx/setup.h" + +#if wxUSE_SOCKETS + +#include +#include "wx/gsocket.h" +#include "wx/unix/gsockunx.h" + +#include + +#define ALL_CALLBACK_TYPES (kCFSocketReadCallBack | kCFSocketWriteCallBack | kCFSocketConnectCallBack) + +struct MacGSocketData +{ + CFSocketRef socket; + CFRunLoopSourceRef source; +}; + +void Mac_Socket_Callback(CFSocketRef s, CFSocketCallBackType callbackType, + CFDataRef address, const void* data, void* info) +{ + GSocket* socket = (GSocket*)info; + struct MacGSocketData* macdata; + macdata = (struct MacGSocketData*)socket->m_gui_dependent; + if (!macdata) return; + switch (callbackType) + { + case kCFSocketConnectCallBack: + assert(!socket->m_server); + socket->m_functions->Detected_Write(socket); + break; + case kCFSocketReadCallBack: + socket->m_functions->Detected_Read(socket); + break; + case kCFSocketWriteCallBack: + socket->m_functions->Detected_Write(socket); + break; + default: + break; /* We shouldn't get here. */ + } +} + +struct MacGSocketData* _GSocket_Get_Mac_Socket(GSocket *socket) +{ + /* If socket is already created, returns a pointer to the data */ + /* Otherwise, creates socket and returns the pointer */ + CFSocketContext cont; + struct MacGSocketData* data = (struct MacGSocketData*)socket->m_gui_dependent; + + if (data && data->source) return data; + + /* CFSocket has not been created, create it: */ + if (socket->m_fd < 0 || !data) return NULL; + cont.version = 0; cont.retain = NULL; + cont.release = NULL; cont.copyDescription = NULL; + cont.info = socket; + + CFSocketRef cf = CFSocketCreateWithNative(NULL, socket->m_fd, + ALL_CALLBACK_TYPES, Mac_Socket_Callback, &cont); + CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(NULL, cf, 0); + assert(source); + socket->m_gui_dependent = (char*)data; + + /* Keep the source and the socket around. */ + data->source = source; + data->socket = cf; + + return data; +} + +int _GSocket_GUI_Init(void) +{ + return 1; +} + +void _GSocket_GUI_Cleanup(void) +{ +} + +int _GSocket_GUI_Init_Socket(GSocket *socket) +{ + struct MacGSocketData *data = malloc(sizeof(struct MacGSocketData)); + if (data) + { + socket->m_gui_dependent = (char*)data; + data->socket = NULL; + data->source = NULL; + return 1; + } + return 0; +} + +void _GSocket_GUI_Destroy_Socket(GSocket *socket) +{ + struct MacGSocketData *data = (struct MacGSocketData*)(socket->m_gui_dependent); + if (data) + { + CFRelease(data->socket); + free(data); + } +} + +void _GSocket_Install_Callback(GSocket *socket, GSocketEvent event) +{ + int c; + struct MacGSocketData* data = _GSocket_Get_Mac_Socket(socket); + if (!data) return; + switch (event) + { + case GSOCK_CONNECTION: + if(socket->m_server) + c = kCFSocketReadCallBack; + else + c = kCFSocketConnectCallBack; + break; + case GSOCK_LOST: + case GSOCK_INPUT: + c = kCFSocketReadCallBack; + break; + case GSOCK_OUTPUT: + c = kCFSocketWriteCallBack; + break; + default: + c = 0; + } + CFSocketEnableCallBacks(data->socket, c); +} + +void _GSocket_Uninstall_Callback(GSocket *socket, GSocketEvent event) +{ + int c; + struct MacGSocketData* data = _GSocket_Get_Mac_Socket(socket); + if (!data) return; + switch (event) + { + case GSOCK_CONNECTION: + if(socket->m_server) + c = kCFSocketReadCallBack; + else + c = kCFSocketConnectCallBack; + break; + case GSOCK_LOST: + case GSOCK_INPUT: + c = kCFSocketReadCallBack; + break; + case GSOCK_OUTPUT: + c = kCFSocketWriteCallBack; + break; + default: + c = 0; + } + CFSocketDisableCallBacks(data->socket, c); +} + +void _GSocket_Enable_Events(GSocket *socket) +{ + struct MacGSocketData* data = _GSocket_Get_Mac_Socket(socket); + if (!data) return; + + CFRunLoopAddSource(CFRunLoopGetCurrent(), data->source, kCFRunLoopDefaultMode); +} + +void _GSocket_Disable_Events(GSocket *socket) +{ + struct MacGSocketData* data = _GSocket_Get_Mac_Socket(socket); + if (!data) return; + + /* CFSocketInvalidate does CFRunLoopRemoveSource anyway */ + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), data->source, kCFRunLoopCommonModes); + CFSocketInvalidate(data->socket); +} + +#endif // wxUSE_SOCKETS diff --git a/src/mac/classic/helpxxxx.cpp b/src/mac/classic/helpxxxx.cpp new file mode 100644 index 0000000000..7d0e4d1531 --- /dev/null +++ b/src/mac/classic/helpxxxx.cpp @@ -0,0 +1,84 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: helpxxxx.cpp +// Purpose: Help system: native implementation +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "helpxxxx.h" +#endif + +#include "wx/stubs/helpxxxx.h" + +#include + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxXXXXHelpController, wxHelpControllerBase) +#endif + +wxXXXXHelpController::wxXXXXHelpController() +{ + m_helpFile = ""; +} + +wxXXXXHelpController::~wxXXXXHelpController() +{ +} + +bool wxXXXXHelpController::Initialize(const wxString& filename) +{ + m_helpFile = filename; + // TODO any other inits + return TRUE; +} + +bool wxXXXXHelpController::LoadFile(const wxString& file) +{ + m_helpFile = file; + // TODO + return TRUE; +} + +bool wxXXXXHelpController::DisplayContents() +{ + // TODO + return FALSE; +} + +bool wxXXXXHelpController::DisplaySection(int section) +{ + // TODO + return FALSE; +} + +bool wxXXXXHelpController::DisplayBlock(long block) +{ + // TODO + return FALSE; +} + +bool wxXXXXHelpController::KeywordSearch(const wxString& k, + wxHelpSearchMode WXUNUSED(mode)) +{ + if (m_helpFile == "") return FALSE; + + // TODO + return FALSE; +} + +// Can't close the help window explicitly in WinHelp +bool wxXXXXHelpController::Quit() +{ + // TODO + return FALSE; +} + +void wxXXXXHelpController::OnQuit() +{ +} + diff --git a/src/mac/classic/hid.cpp b/src/mac/classic/hid.cpp new file mode 100644 index 0000000000..f4ce8a1874 --- /dev/null +++ b/src/mac/classic/hid.cpp @@ -0,0 +1,417 @@ +#include "hid.h" + +#define wxFORCECHECK_MSG(arg, msg) \ +{\ + if (arg) \ + {\ + wxLogSysError(wxString::Format(wxT("Message:%s\nHID: %s failed!"), wxT(msg), wxT(#arg)));\ + return false;\ + }\ +} +#define wxIOCHECK(arg, msg) wxFORCECHECK_MSG(arg != kIOReturnSuccess, msg) +#define wxKERNCHECK(arg, msg) wxFORCECHECK_MSG(arg != KERN_SUCCESS, msg) +#define wxSCHECK(arg, msg) wxFORCECHECK_MSG(arg != S_OK, msg) + +void CFShowTypeIDDescription(CFTypeRef pData) +{ + if(!pData) + { + wxMessageBox("AHHH!"); + return; + } + + wxMessageBox( + CFStringGetCStringPtr( + CFCopyTypeIDDescription(CFGetTypeID(pData)),CFStringGetSystemEncoding() + ) + ); +} + +// ============================================================================ +// implementation +// ============================================================================ + + +bool wxHIDDevice::Create (const int& nClass, const int& nType) +{ + //Create the mach port + wxIOCHECK(IOMasterPort(bootstrap_port, &m_pPort), "Could not create mach port"); + + //Dictionary that will hold first + //the matching dictionary for determining which kind of devices we want, + //then later some registry properties from an iterator (see below) + CFMutableDictionaryRef pDictionary; + + //Create a dictionary + //The call to IOServiceMatching filters down the + //the services we want to hid services (and also eats the + //dictionary up for us (consumes one reference)) + wxASSERT((pDictionary = IOServiceMatching(kIOHIDDeviceKey)) != NULL ); + + //Here we'll filter down the services to what we want + if (nType != -1) + { + CFNumberRef pType = CFNumberCreate(kCFAllocatorDefault, + kCFNumberIntType, &nType); + CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsageKey), pType); + CFRelease(pType); + } + if (nClass != -1) + { + CFNumberRef pClass = CFNumberCreate(kCFAllocatorDefault, + kCFNumberIntType, &nClass); + CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsagePageKey), pClass); + CFRelease(pClass); + } + + //Now get the maching services + io_iterator_t pIterator; + wxIOCHECK(IOServiceGetMatchingServices(m_pPort, pDictionary, &pIterator), "No Matching HID Services"); + wxASSERT(pIterator != NULL); + + //Now we iterate through them + io_object_t pObject; + while ( (pObject = IOIteratorNext(pIterator)) != NULL) + { + wxASSERT(IORegistryEntryCreateCFProperties(pObject, &pDictionary, + kCFAllocatorDefault, kNilOptions) == KERN_SUCCESS); + + //Just for sanity :) + wxASSERT(CFGetTypeID(CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductKey))) == CFStringGetTypeID()); + + //Get [product] name + m_szName = CFStringGetCStringPtr ( + (CFStringRef) CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductKey)), + CFStringGetSystemEncoding() + ); + + // + //Now the hard part - in order to scan things we need "cookies" - + // + wxCFArray CookieArray = CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDElementKey)); + BuildCookies(CookieArray); + if (m_ppQueue != NULL) + wxASSERT((*m_ppQueue)->start(m_ppQueue) == S_OK); + + //Create the interface (good grief - long function names!) + SInt32 nScore; + IOCFPlugInInterface** ppPlugin; + wxIOCHECK(IOCreatePlugInInterfaceForService(pObject, kIOHIDDeviceUserClientTypeID, + kIOCFPlugInInterfaceID, &ppPlugin, &nScore), ""); + + //Now, the final thing we can check before we fall back to asserts + //(because the dtor only checks if the device is ok, so if anything + //fails from now on the dtor will delete the device anyway, so we can't break from this). + + //Get the HID interface from the plugin to the mach port + wxSCHECK((*ppPlugin)->QueryInterface(ppPlugin, + CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (void**) &m_ppDevice), ""); + + //release the plugin + (*ppPlugin)->Release(ppPlugin); + + //open the HID interface... + wxASSERT((*m_ppDevice)->open(m_ppDevice, 0) == S_OK); + + //cleanup + CFRelease(pDictionary); + IOObjectRelease(pObject); + break; + } + //iterator cleanup + IOObjectRelease(pIterator); + + return true; +}//end Create() + +void wxHIDDevice::AddCookie(CFTypeRef Data, const int& i) +{ + CFNumberGetValue( + (CFNumberRef) CFDictionaryGetValue ( (CFDictionaryRef) Data + , CFSTR(kIOHIDElementCookieKey) + ), + kCFNumberIntType, + &m_pCookies[i] + ); +} + +void wxHIDDevice::AddCookieInQueue(CFTypeRef Data, const int& i) +{ + AddCookie(Data, i); + wxASSERT((*m_ppQueue)->addElement(m_ppQueue, m_pCookies[i], 0) == S_OK);//3rd Param flags (none yet) +} + +void wxHIDDevice::InitCookies(const size_t& dwSize, bool bQueue) +{ + m_pCookies = new IOHIDElementCookie[dwSize]; + if (bQueue) + { + wxASSERT( m_ppQueue != NULL); + wxASSERT( (m_ppQueue = (*m_ppDevice)->allocQueue(m_ppDevice)) != NULL); + wxASSERT( (*m_ppQueue)->create(m_ppQueue, 0, 512) == S_OK); //Param 2, flags, none yet + } +} + +bool wxHIDDevice::IsActive(const int& nIndex) +{ + wxASSERT(m_pCookies[nIndex] != NULL); + IOHIDEventStruct Event; + (*m_ppDevice)->getElementValue(m_ppDevice, m_pCookies[nIndex], &Event); + return !!Event.value; +} + + +wxHIDDevice::~wxHIDDevice() +{ + if (m_ppDevice != NULL) + { + (*m_ppDevice)->close(m_ppDevice); + (*m_ppDevice)->Release(m_ppDevice); + mach_port_deallocate(mach_task_self(), m_pPort); + } + + if (m_pCookies != NULL) + { + delete [] m_pCookies; + if (m_ppQueue != NULL) + { + (*m_ppQueue)->stop(m_ppQueue); + (*m_ppQueue)->dispose(m_ppQueue); + (*m_ppQueue)->Release(m_ppQueue); + } + } +} +/* +enum +{ + kHIDUsage_KeyboardHyphen = 0x2D, + kHIDUsage_KeyboardEqualSign = 0x2E, + kHIDUsage_KeyboardOpenBracket = 0x2F, + kHIDUsage_KeyboardCloseBracket = 0x30, + kHIDUsage_KeyboardBackslash = 0x31, //* \ or | * + kHIDUsage_KeyboardNonUSPound = 0x32, /* Non-US # or _ * + kHIDUsage_KeyboardSemicolon = 0x33, /* ; or : * + kHIDUsage_KeyboardQuote = 0x34, /* ' or " * + kHIDUsage_KeyboardGraveAccentAndTilde = 0x35, /* Grave Accent and Tilde * + kHIDUsage_KeyboardComma = 0x36, /* , or < * + kHIDUsage_KeyboardPeriod = 0x37, /* . or > * + kHIDUsage_KeyboardSlash = 0x38, /* / or ? * + kHIDUsage_KeyboardCapsLock = 0x39, /* Caps Lock * + + kHIDUsage_KeyboardPrintScreen = 0x46, /* Print Screen * + kHIDUsage_KeyboardScrollLock = 0x47, /* Scroll Lock * + kHIDUsage_KeyboardPause = 0x48, /* Pause * + kHIDUsage_KeyboardInsert = 0x49, /* Insert * + kHIDUsage_KeyboardHome = 0x4A, /* Home * + kHIDUsage_KeyboardDeleteForward = 0x4C, /* Delete Forward * + + kHIDUsage_KeyboardUpArrow + kHIDUsage_KeypadNumLock + kHIDUsage_KeypadSlash + kHIDUsage_KeypadAsterisk + kHIDUsage_KeypadHyphen + kHIDUsage_KeypadPlus + kHIDUsage_KeypadEnter + kHIDUsage_KeypadPeriod + kHIDUsage_KeyboardNonUSBackslash + kHIDUsage_KeyboardApplication + kHIDUsage_KeyboardPower + kHIDUsage_KeypadEqualSign +}; +/* + enum wxKeyCode + { + + WXK_START = 300, + WXK_LBUTTON, + WXK_RBUTTON, + WXK_CANCEL, + WXK_MBUTTON, + WXK_CLEAR, + WXK_SHIFT, + WXK_ALT, + WXK_CONTROL, + WXK_MENU, + WXK_PAUSE, + WXK_PRIOR, * Page up * + WXK_NEXT, * Page down * + WXK_END, + WXK_HOME, + WXK_LEFT, + WXK_UP, + WXK_RIGHT, + WXK_DOWN, + WXK_SELECT, + WXK_PRINT, + WXK_EXECUTE, + WXK_SNAPSHOT, + WXK_INSERT, + WXK_HELP, + WXK_MULTIPLY, + WXK_ADD, + WXK_SEPARATOR, + WXK_SUBTRACT, + WXK_DECIMAL, + WXK_DIVIDE, + WXK_PAGEUP, + WXK_PAGEDOWN, + + WXK_NUMPAD_SPACE, + WXK_NUMPAD_TAB, + WXK_NUMPAD_ENTER, + WXK_NUMPAD_HOME, + WXK_NUMPAD_LEFT, + WXK_NUMPAD_UP, + WXK_NUMPAD_RIGHT, + WXK_NUMPAD_DOWN, + WXK_NUMPAD_PRIOR, + WXK_NUMPAD_PAGEUP, + WXK_NUMPAD_NEXT, + WXK_NUMPAD_PAGEDOWN, + WXK_NUMPAD_END, + WXK_NUMPAD_BEGIN, + WXK_NUMPAD_INSERT, + WXK_NUMPAD_DELETE, + WXK_NUMPAD_EQUAL, + WXK_NUMPAD_MULTIPLY, + WXK_NUMPAD_ADD, + WXK_NUMPAD_SEPARATOR, + WXK_NUMPAD_SUBTRACT, + WXK_NUMPAD_DECIMAL, + WXK_NUMPAD_DIVIDE, + + WXK_WINDOWS_LEFT, + WXK_WINDOWS_RIGHT, + WXK_WINDOWS_MENU , + WXK_COMMAND + }; + + */ +enum +{ + WXK_RSHIFT = 400, + WXK_RALT, + WXK_RCONTROL, + WXK_RMENU + +}; + +bool wxHIDKeyboard::Create() +{ + return wxHIDDevice::Create(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard); +} + +void wxHIDKeyboard::BuildCookies(wxCFArray& Array) +{ + Array = CFDictionaryGetValue((CFDictionaryRef)Array[0], CFSTR(kIOHIDElementKey)); + InitCookies(500); + int i, + nUsage; + for (i = 0; i < Array.Count(); ++i) + { + CFNumberGetValue( + (CFNumberRef) CFDictionaryGetValue((CFDictionaryRef) Array[i], CFSTR(kIOHIDElementUsageKey)), + kCFNumberLongType, &nUsage); + + if (nUsage >= kHIDUsage_KeyboardA && nUsage <= kHIDUsage_KeyboardZ) + AddCookie(Array[i], 'A' + (nUsage - kHIDUsage_KeyboardA) ); + else if (nUsage >= kHIDUsage_Keyboard1 && nUsage <= kHIDUsage_Keyboard9) + AddCookie(Array[i], '1' + (nUsage - kHIDUsage_Keyboard1) ); + else if (nUsage >= kHIDUsage_KeyboardF1 && nUsage <= kHIDUsage_KeyboardF12) + AddCookie(Array[i], WXK_F1 + (nUsage - kHIDUsage_KeyboardF1) ); + else if (nUsage >= kHIDUsage_KeyboardF13 && nUsage <= kHIDUsage_KeyboardF24) + AddCookie(Array[i], WXK_F13 + (nUsage - kHIDUsage_KeyboardF13) ); + else if (nUsage >= kHIDUsage_Keypad1 && nUsage <= kHIDUsage_Keypad9) + AddCookie(Array[i], WXK_NUMPAD1 + (nUsage - kHIDUsage_Keypad1) ); + else switch (nUsage) + { + //0's (wx & ascii go 0-9, but HID goes 1-0) + case kHIDUsage_Keyboard0: + AddCookie(Array[i],'0'); + break; + case kHIDUsage_Keypad0: + AddCookie(Array[i],WXK_NUMPAD0); + break; + + //Basic + case kHIDUsage_KeyboardReturnOrEnter: + AddCookie(Array[i], WXK_RETURN); + break; + case kHIDUsage_KeyboardEscape: + AddCookie(Array[i], WXK_ESCAPE); + break; + case kHIDUsage_KeyboardDeleteOrBackspace: + AddCookie(Array[i], WXK_BACK); + break; + case kHIDUsage_KeyboardTab: + AddCookie(Array[i], WXK_TAB); + break; + case kHIDUsage_KeyboardSpacebar: + AddCookie(Array[i], WXK_SPACE); + break; + case kHIDUsage_KeyboardPageUp: + AddCookie(Array[i], WXK_PRIOR); + break; + case kHIDUsage_KeyboardEnd: + AddCookie(Array[i], WXK_END); + break; + case kHIDUsage_KeyboardPageDown: + AddCookie(Array[i], WXK_NEXT); + break; + case kHIDUsage_KeyboardRightArrow: + AddCookie(Array[i], WXK_RIGHT); + break; + case kHIDUsage_KeyboardLeftArrow: + AddCookie(Array[i], WXK_LEFT); + break; + case kHIDUsage_KeyboardDownArrow: + AddCookie(Array[i], WXK_DOWN); + break; + case kHIDUsage_KeyboardUpArrow: + AddCookie(Array[i], WXK_UP); + break; + + //LEDS + case kHIDUsage_KeyboardCapsLock: + AddCookie(Array[i],WXK_CAPITAL); + break; + case kHIDUsage_KeypadNumLock: + AddCookie(Array[i],WXK_NUMLOCK); + break; + case kHIDUsage_KeyboardScrollLock: + AddCookie(Array[i],WXK_SCROLL); + break; + + //Menu keys, Shift, other specials + case kHIDUsage_KeyboardLeftControl: + AddCookie(Array[i],WXK_CONTROL); + break; + case kHIDUsage_KeyboardLeftShift: + AddCookie(Array[i],WXK_SHIFT); + break; + case kHIDUsage_KeyboardLeftAlt: + AddCookie(Array[i],WXK_ALT); + break; + case kHIDUsage_KeyboardLeftGUI: + AddCookie(Array[i],WXK_MENU); + break; + case kHIDUsage_KeyboardRightControl: + AddCookie(Array[i],WXK_RCONTROL); + break; + case kHIDUsage_KeyboardRightShift: + AddCookie(Array[i],WXK_RSHIFT); + break; + case kHIDUsage_KeyboardRightAlt: + AddCookie(Array[i],WXK_RALT); + break; + case kHIDUsage_KeyboardRightGUI: + AddCookie(Array[i],WXK_RMENU); + break; + + //Default + default: + //not in wx keycodes - do nothing.... + break; + } + } +}//end buildcookies diff --git a/src/mac/classic/icon.cpp b/src/mac/classic/icon.cpp new file mode 100644 index 0000000000..bd1937bc2a --- /dev/null +++ b/src/mac/classic/icon.cpp @@ -0,0 +1,132 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: icon.cpp +// Purpose: wxIcon class +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "icon.h" +#endif + +#include "wx/icon.h" + +#if !USE_SHARED_LIBRARIES +IMPLEMENT_DYNAMIC_CLASS(wxIcon, wxBitmap) +#endif + +#include "wx/mac/private.h" + + +/* + * Icons + */ + +wxIcon::wxIcon() +{ +} + +wxIcon::wxIcon(const char bits[], int width, int height) : + wxBitmap(bits, width, height) +{ + +} + +wxIcon::wxIcon( const char **bits ) : + wxBitmap(bits) +{ +} + +wxIcon::wxIcon( char **bits ) : + wxBitmap(bits) +{ +} + +wxIcon::wxIcon(const wxString& icon_file, int flags, + int desiredWidth, int desiredHeight) +{ + LoadFile(icon_file, (wxBitmapType) flags, desiredWidth, desiredHeight); +} + +wxIcon::~wxIcon() +{ +} + +bool wxIcon::LoadFile(const wxString& filename, wxBitmapType type, + int desiredWidth, int desiredHeight) +{ + UnRef(); + + m_refData = new wxBitmapRefData; + + wxBitmapHandler *handler = FindHandler((wxBitmapType)type); + + if ( handler ) + return handler->LoadFile(this, filename, type, desiredWidth, desiredHeight); + else + return FALSE; +} + +void wxIcon::CopyFromBitmap(const wxBitmap& bmp) +{ + wxIcon *icon = (wxIcon*)(&bmp); + *this = *icon; +} + +IMPLEMENT_DYNAMIC_CLASS(wxICONResourceHandler, wxBitmapHandler) + +bool wxICONResourceHandler::LoadFile(wxBitmap *bitmap, const wxString& name, long flags, + int desiredWidth, int desiredHeight) +{ + short theId = -1 ; + if ( name == wxT("wxICON_INFORMATION") ) + { + theId = kNoteIcon ; + } + else if ( name == wxT("wxICON_QUESTION") ) + { + theId = kCautionIcon ; + } + else if ( name == wxT("wxICON_WARNING") ) + { + theId = kCautionIcon ; + } + else if ( name == wxT("wxICON_ERROR") ) + { + theId = kStopIcon ; + } + else + { + Str255 theName ; + OSType theType ; + wxMacStringToPascal( name , theName ) ; + + Handle resHandle = GetNamedResource( 'cicn' , theName ) ; + if ( resHandle != 0L ) + { + GetResInfo( resHandle , &theId , &theType , theName ) ; + ReleaseResource( resHandle ) ; + } + } + if ( theId != -1 ) + { + CIconHandle theIcon = (CIconHandle ) GetCIcon( theId ) ; + if ( theIcon ) + { + M_BITMAPHANDLERDATA->m_hIcon = theIcon ; + M_BITMAPHANDLERDATA->m_width = 32 ; + M_BITMAPHANDLERDATA->m_height = 32 ; + + M_BITMAPHANDLERDATA->m_depth = 8 ; + M_BITMAPHANDLERDATA->m_ok = true ; + M_BITMAPHANDLERDATA->m_numColors = 256 ; + M_BITMAPHANDLERDATA->m_bitmapType = kMacBitmapTypeIcon ; + return TRUE ; + } + } + return FALSE ; +} diff --git a/src/mac/classic/joystick.cpp b/src/mac/classic/joystick.cpp new file mode 100644 index 0000000000..156b9b2657 --- /dev/null +++ b/src/mac/classic/joystick.cpp @@ -0,0 +1,286 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: joystick.cpp +// Purpose: wxJoystick class +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "joystick.h" +#endif + +#include "wx/setup.h" + +#include "wx/joystick.h" + +#if wxUSE_JOYSTICK + +IMPLEMENT_DYNAMIC_CLASS(wxJoystick, wxObject) + +// Attributes +//////////////////////////////////////////////////////////////////////////// + +wxPoint wxJoystick::GetPosition() const +{ + // TODO + return wxPoint(0, 0); +} + +int wxJoystick::GetZPosition() const +{ + // TODO + return 0; +} + +int wxJoystick::GetButtonState() const +{ + // TODO + return 0; +} + +int wxJoystick::GetPOVPosition() const +{ + // TODO + return 0; +} + +int wxJoystick::GetPOVCTSPosition() const +{ + // TODO + return 0; +} + +int wxJoystick::GetRudderPosition() const +{ + // TODO + return 0; +} + +int wxJoystick::GetUPosition() const +{ + // TODO + return 0; +} + +int wxJoystick::GetVPosition() const +{ + // TODO + return 0; +} + +int wxJoystick::GetMovementThreshold() const +{ + // TODO + return 0; +} + +void wxJoystick::SetMovementThreshold(int threshold) +{ + // TODO +} + +// Capabilities +//////////////////////////////////////////////////////////////////////////// + +bool wxJoystick::IsOk() const +{ + // TODO + return FALSE; +} + +int wxJoystick::GetNumberJoysticks() const +{ + // TODO + return 0; +} + +int wxJoystick::GetManufacturerId() const +{ + // TODO + return 0; +} + +int wxJoystick::GetProductId() const +{ + // TODO + return 0; +} + +wxString wxJoystick::GetProductName() const +{ + // TODO + return wxString(wxT("")); +} + +int wxJoystick::GetXMin() const +{ + // TODO + return 0; +} + +int wxJoystick::GetYMin() const +{ + // TODO + return 0; +} + +int wxJoystick::GetZMin() const +{ + // TODO + return 0; +} + +int wxJoystick::GetXMax() const +{ + // TODO + return 0; +} + +int wxJoystick::GetYMax() const +{ + // TODO + return 0; +} + +int wxJoystick::GetZMax() const +{ + // TODO + return 0; +} + +int wxJoystick::GetNumberButtons() const +{ + // TODO + return 0; +} + +int wxJoystick::GetNumberAxes() const +{ + // TODO + return 0; +} + +int wxJoystick::GetMaxButtons() const +{ + // TODO + return 0; +} + +int wxJoystick::GetMaxAxes() const +{ + // TODO + return 0; +} + +int wxJoystick::GetPollingMin() const +{ + // TODO + return 0; +} + +int wxJoystick::GetPollingMax() const +{ + // TODO + return 0; +} + +int wxJoystick::GetRudderMin() const +{ + // TODO + return 0; +} + +int wxJoystick::GetRudderMax() const +{ + // TODO + return 0; +} + +int wxJoystick::GetUMin() const +{ + // TODO + return 0; +} + +int wxJoystick::GetUMax() const +{ + // TODO + return 0; +} + +int wxJoystick::GetVMin() const +{ + // TODO + return 0; +} + +int wxJoystick::GetVMax() const +{ + // TODO + return 0; +} + +bool wxJoystick::HasRudder() const +{ + // TODO + return FALSE; +} + +bool wxJoystick::HasZ() const +{ + // TODO + return FALSE; +} + +bool wxJoystick::HasU() const +{ + // TODO + return FALSE; +} + +bool wxJoystick::HasV() const +{ + // TODO + return FALSE; +} + +bool wxJoystick::HasPOV() const +{ + // TODO + return FALSE; +} + +bool wxJoystick::HasPOV4Dir() const +{ + // TODO + return FALSE; +} + +bool wxJoystick::HasPOVCTS() const +{ + // TODO + return FALSE; +} + +// Operations +//////////////////////////////////////////////////////////////////////////// + +bool wxJoystick::SetCapture(wxWindow* win, int pollingFreq) +{ + // TODO + return FALSE; +} + +bool wxJoystick::ReleaseCapture() +{ + // TODO + return FALSE; +} + +#endif + // wxUSE_JOYSTICK + diff --git a/src/mac/classic/listbox.cpp b/src/mac/classic/listbox.cpp new file mode 100644 index 0000000000..8322a7a2f2 --- /dev/null +++ b/src/mac/classic/listbox.cpp @@ -0,0 +1,1023 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: listbox.cpp +// Purpose: wxListBox +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "listbox.h" +#endif + +#include "wx/app.h" +#include "wx/listbox.h" +#include "wx/button.h" +#include "wx/settings.h" +#include "wx/toplevel.h" +#include "wx/dynarray.h" +#include "wx/log.h" + +#include "wx/utils.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControl) + +BEGIN_EVENT_TABLE(wxListBox, wxControl) + EVT_SIZE( wxListBox::OnSize ) + EVT_CHAR( wxListBox::OnChar ) +END_EVENT_TABLE() +#endif + +#include "wx/mac/uma.h" + +#if PRAGMA_STRUCT_ALIGN + #pragma options align=mac68k +#elif PRAGMA_STRUCT_PACKPUSH + #pragma pack(push, 2) +#elif PRAGMA_STRUCT_PACK + #pragma pack(2) +#endif + +typedef struct { + unsigned short instruction; + void (*function)(); +} ldefRec, *ldefPtr, **ldefHandle; + +#if PRAGMA_STRUCT_ALIGN + #pragma options align=reset +#elif PRAGMA_STRUCT_PACKPUSH + #pragma pack(pop) +#elif PRAGMA_STRUCT_PACK + #pragma pack() +#endif + +#if TARGET_CARBON +const short kwxMacListItemHeight = 19 ; +#else +const short kwxMacListItemHeight = 14 ; +#endif + +extern "C" +{ +static pascal void wxMacListDefinition( short message, Boolean isSelected, Rect *drawRect, + Cell cell, short dataOffset, short dataLength, + ListHandle listHandle ) ; +} + +static pascal void wxMacListDefinition( short message, Boolean isSelected, Rect *drawRect, + Cell cell, short dataOffset, short dataLength, + ListHandle listHandle ) +{ + wxListBox* list; + list = (wxListBox*) GetControlReference( (ControlHandle) GetListRefCon(listHandle) ); + if ( list == NULL ) + return ; + + GrafPtr savePort; + GrafPtr grafPtr; + RgnHandle savedClipRegion; + SInt32 savedPenMode; + GetPort(&savePort); + SetPort((**listHandle).port); + grafPtr = (**listHandle).port ; + // typecast our refCon + + // Calculate the cell rect. + + switch( message ) { + case lInitMsg: + break; + + case lCloseMsg: + break; + + case lDrawMsg: + { + const wxString linetext = list->m_stringArray[cell.v] ; + + // Save the current clip region, and set the clip region to the area we are about + // to draw. + + savedClipRegion = NewRgn(); + GetClip( savedClipRegion ); + + ClipRect( drawRect ); + EraseRect( drawRect ); + + const wxFont& font = list->GetFont(); + if ( font.Ok() ) + { + ::TextFont( font.GetMacFontNum() ) ; + ::TextSize( font.GetMacFontSize() ) ; + ::TextFace( font.GetMacFontStyle() ) ; + } + else + { + ::TextFont( kFontIDMonaco ) ; + ::TextSize( 9 ); + ::TextFace( 0 ) ; + } + +#if TARGET_CARBON + { + Rect frame = { drawRect->top, drawRect->left + 4, + drawRect->top + kwxMacListItemHeight, drawRect->right + 10000 } ; + CFMutableStringRef mString = CFStringCreateMutableCopy( NULL , 0 , wxMacCFStringHolder(linetext , list->GetFont().GetEncoding()) ) ; + ::TruncateThemeText( mString , kThemeCurrentPortFont, kThemeStateActive, drawRect->right - drawRect->left , truncEnd , NULL ) ; + ::DrawThemeTextBox( mString, + kThemeCurrentPortFont, + kThemeStateActive, + false, + &frame, + teJustLeft, + nil ); + CFRelease( mString ) ; + } +#else + { + wxCharBuffer text = linetext.mb_str( wxConvLocal) ; + MoveTo(drawRect->left + 4 , drawRect->top + 10 ); + DrawText(text, 0 , strlen(text) ); + } +#endif + // If the cell is hilited, do the hilite now. Paint the cell contents with the + // appropriate QuickDraw transform mode. + + if( isSelected ) { + savedPenMode = GetPortPenMode( (CGrafPtr) grafPtr ); + SetPortPenMode( (CGrafPtr)grafPtr, hilitetransfermode ); + PaintRect( drawRect ); + SetPortPenMode( (CGrafPtr)grafPtr, savedPenMode ); + } + + // Restore the saved clip region. + + SetClip( savedClipRegion ); + DisposeRgn( savedClipRegion ); + } + break; + case lHiliteMsg: + + // Hilite or unhilite the cell. Paint the cell contents with the + // appropriate QuickDraw transform mode. + + GetPort( &grafPtr ); + savedPenMode = GetPortPenMode( (CGrafPtr)grafPtr ); + SetPortPenMode( (CGrafPtr)grafPtr, hilitetransfermode ); + PaintRect( drawRect ); + SetPortPenMode( (CGrafPtr)grafPtr, savedPenMode ); + break; + default : + break ; + } + SetPort(savePort); +} + +extern "C" void MacDrawStringCell(Rect *cellRect, Cell lCell, ListHandle theList, long refCon) ; +// resources ldef ids +const short kwxMacListWithVerticalScrollbar = 128 ; +const short kwxMacListWithVerticalAndHorizontalScrollbar = 129 ; + +// ============================================================================ +// list box control implementation +// ============================================================================ + +// Listbox item +wxListBox::wxListBox() +{ + m_noItems = 0; + m_selected = 0; + m_macList = NULL ; +} + +static ListDefUPP macListDefUPP = NULL ; + +bool wxListBox::Create(wxWindow *parent, wxWindowID id, + const wxPoint& pos, + const wxSize& size, + const wxArrayString& choices, + long style, + const wxValidator& validator, + const wxString& name) +{ + wxCArrayString chs(choices); + + return Create(parent, id, pos, size, chs.GetCount(), chs.GetStrings(), + style, validator, name); +} + +bool wxListBox::Create(wxWindow *parent, wxWindowID id, + const wxPoint& pos, + const wxSize& size, + int n, const wxString choices[], + long style, + const wxValidator& validator, + const wxString& name) +{ + if ( !wxListBoxBase::Create(parent, id, pos, size, style & ~(wxHSCROLL|wxVSCROLL), validator, name) ) + return false; + + m_noItems = 0 ; // this will be increased by our append command + m_selected = 0; + + Rect bounds ; + Str255 title ; + + MacPreControlCreate( parent , id , wxEmptyString , pos , size ,style, validator , name , &bounds , title ) ; + + ListDefSpec listDef; + listDef.defType = kListDefUserProcType; + if ( macListDefUPP == NULL ) + { + macListDefUPP = NewListDefUPP( wxMacListDefinition ); + } + listDef.u.userProc = macListDefUPP ; + + Str255 fontName ; + SInt16 fontSize ; + Style fontStyle ; +#if TARGET_CARBON + GetThemeFont(kThemeViewsFont , GetApplicationScript() , fontName , &fontSize , &fontStyle ) ; +#else + GetFontName( kFontIDMonaco , fontName ) ; + fontSize = 9 ; + fontStyle = normal ; +#endif + SetFont( wxFont (fontSize, wxSWISS, wxNORMAL, wxNORMAL , false , wxMacMakeStringFromPascal( fontName ) ) ) ; +#if TARGET_CARBON + Size asize; + + + CreateListBoxControl( MAC_WXHWND(parent->MacGetRootWindow()), &bounds, false, 0, 1, (style & wxLB_HSCROLL), true, + kwxMacListItemHeight, kwxMacListItemHeight, false, &listDef, (ControlRef *)&m_macControl ); + + GetControlData( (ControlHandle) m_macControl, kControlNoPart, kControlListBoxListHandleTag, + sizeof(ListHandle), (Ptr) &m_macList, &asize); + + SetControlReference( (ControlHandle) m_macControl, (long) this); + SetControlVisibility( (ControlHandle) m_macControl, false, false); + +#else + + long result ; + wxStAppResource resload ; + m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()) , &bounds , title , false , + (style & wxLB_HSCROLL) ? kwxMacListWithVerticalAndHorizontalScrollbar : kwxMacListWithVerticalScrollbar , + 0 , 0, kControlListBoxProc , (long) this ) ; + ::GetControlData( (ControlHandle) m_macControl , kControlNoPart , kControlListBoxListHandleTag , + sizeof( ListHandle ) , (char*) &m_macList , &result ) ; + + HLock( (Handle) m_macList ) ; + ldefHandle ldef ; + ldef = (ldefHandle) NewHandle( sizeof(ldefRec) ) ; + if ( (**(ListHandle)m_macList).listDefProc != NULL ) + { + (**ldef).instruction = 0x4EF9; /* JMP instruction */ + (**ldef).function = (void(*)()) listDef.u.userProc; + (**(ListHandle)m_macList).listDefProc = (Handle) ldef ; + } + + Point pt = (**(ListHandle)m_macList).cellSize ; + pt.v = kwxMacListItemHeight ; + LCellSize( pt , (ListHandle)m_macList ) ; + LAddColumn( 1 , 0 , (ListHandle)m_macList ) ; +#endif + OptionBits options = 0; + if ( style & wxLB_MULTIPLE ) + { + options += lExtendDrag + lUseSense ; + } + else if ( style & wxLB_EXTENDED ) + { + // default behaviour + } + else + { + options = (OptionBits) lOnlyOne ; + } + SetListSelectionFlags((ListHandle)m_macList, options); + + for ( int i = 0 ; i < n ; i++ ) + { + Append( choices[i] ) ; + } + + MacPostControlCreate() ; + + LSetDrawingMode( true , (ListHandle)m_macList ) ; + + return TRUE; +} + +wxListBox::~wxListBox() +{ + FreeData() ; + // avoid access during destruction + SetControlReference( (ControlHandle) m_macControl , NULL ) ; + if ( m_macList ) + { +#if !TARGET_CARBON + DisposeHandle( (**(ListHandle)m_macList).listDefProc ) ; + (**(ListHandle)m_macList).listDefProc = NULL ; +#endif + m_macList = NULL ; + } +} + +void wxListBox::FreeData() +{ +#if wxUSE_OWNER_DRAWN + if ( m_windowStyle & wxLB_OWNERDRAW ) + { + size_t uiCount = m_aItems.Count(); + while ( uiCount-- != 0 ) { + delete m_aItems[uiCount]; + m_aItems[uiCount] = NULL; + } + + m_aItems.Clear(); + } + else +#endif // wxUSE_OWNER_DRAWN + if ( HasClientObjectData() ) + { + for ( size_t n = 0; n < (size_t)m_noItems; n++ ) + { + delete GetClientObject(n); + } + } +} + +void wxListBox::DoSetSize(int x, int y, + int width, int height, + int sizeFlags ) +{ + wxControl::DoSetSize( x , y , width , height , sizeFlags ) ; +#if TARGET_CARBON + Rect bounds ; + GetControlBounds( (ControlHandle) m_macControl , &bounds ) ; + ControlRef control = GetListVerticalScrollBar( (ListHandle)m_macList ) ; + if ( control ) + { + Rect scrollbounds ; + GetControlBounds( control , &scrollbounds ) ; + if( scrollbounds.right != bounds.right + 1 ) + { + UMAMoveControl( control , bounds.right - (scrollbounds.right - scrollbounds.left) + 1 , + scrollbounds.top ) ; + } + } +#endif +} +void wxListBox::DoSetFirstItem(int N) +{ + MacScrollTo( N ) ; +} + +void wxListBox::Delete(int N) +{ + wxCHECK_RET( N >= 0 && N < m_noItems, + wxT("invalid index in wxListBox::Delete") ); + +#if wxUSE_OWNER_DRAWN + delete m_aItems[N]; + m_aItems.RemoveAt(N); +#else // !wxUSE_OWNER_DRAWN + if ( HasClientObjectData() ) + { + delete GetClientObject(N); + } +#endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN + m_stringArray.RemoveAt( N ) ; + m_dataArray.RemoveAt( N ) ; + m_noItems --; + + MacDelete( N ) ; +} + +int wxListBox::DoAppend(const wxString& item) +{ + int index = m_noItems ; + m_stringArray.Add( item ) ; + m_dataArray.Add( NULL ); + m_noItems ++; + DoSetItemClientData( index , NULL ) ; + MacAppend( item ) ; + + return index ; +} + +void wxListBox::DoSetItems(const wxArrayString& choices, void** clientData) +{ + MacSetRedraw( false ) ; + Clear() ; + int n = choices.GetCount(); + + for( int i = 0 ; i < n ; ++i ) + { + if ( clientData ) + { +#if wxUSE_OWNER_DRAWN + wxASSERT_MSG(clientData[i] == NULL, + wxT("Can't use client data with owner-drawn listboxes")); +#else // !wxUSE_OWNER_DRAWN + Append( choices[i] , clientData[i] ) ; +#endif + } + else + Append( choices[i] ) ; + } + +#if wxUSE_OWNER_DRAWN + if ( m_windowStyle & wxLB_OWNERDRAW ) { + // first delete old items + size_t ui = m_aItems.Count(); + while ( ui-- != 0 ) { + delete m_aItems[ui]; + m_aItems[ui] = NULL; + } + m_aItems.Empty(); + + // then create new ones + for ( ui = 0; ui < (size_t)m_noItems; ui++ ) { + wxOwnerDrawn *pNewItem = CreateItem(ui); + pNewItem->SetName(choices[ui]); + m_aItems.Add(pNewItem); + } + } +#endif // wxUSE_OWNER_DRAWN + MacSetRedraw( true ) ; +} + +bool wxListBox::HasMultipleSelection() const +{ + return (m_windowStyle & wxLB_MULTIPLE) || (m_windowStyle & wxLB_EXTENDED); +} + +int wxListBox::FindString(const wxString& s) const +{ + + if ( s.Right(1) == wxT("*") ) + { + wxString search = s.Left( s.Length() - 1 ) ; + int len = search.Length() ; + Str255 s1 , s2 ; + wxMacStringToPascal( search , s2 ) ; + + for ( int i = 0 ; i < m_noItems ; ++ i ) + { + wxMacStringToPascal( m_stringArray[i].Left( len ) , s1 ) ; + + if ( EqualString( s1 , s2 , false , false ) ) + return i ; + } + if ( s.Left(1) == wxT("*") && s.Length() > 1 ) + { + wxString st = s ; + st.MakeLower() ; + for ( int i = 0 ; i < m_noItems ; ++i ) + { + if ( GetString(i).Lower().Matches(st) ) + return i ; + } + } + + } + else + { + Str255 s1 , s2 ; + + wxMacStringToPascal( s , s2 ) ; + + for ( int i = 0 ; i < m_noItems ; ++ i ) + { + wxMacStringToPascal( m_stringArray[i] , s1 ) ; + + if ( EqualString( s1 , s2 , false , false ) ) + return i ; + } + } + return -1; +} + +void wxListBox::Clear() +{ + FreeData(); + m_noItems = 0; + m_stringArray.Empty() ; + m_dataArray.Empty() ; + MacClear() ; +} + +void wxListBox::SetSelection(int N, bool select) +{ + wxCHECK_RET( N >= 0 && N < m_noItems, + wxT("invalid index in wxListBox::SetSelection") ); + MacSetSelection( N , select ) ; + GetSelections( m_selectionPreImage ) ; +} + +bool wxListBox::IsSelected(int N) const +{ + wxCHECK_MSG( N >= 0 && N < m_noItems, FALSE, + wxT("invalid index in wxListBox::Selected") ); + + return MacIsSelected( N ) ; +} + +void *wxListBox::DoGetItemClientData(int N) const +{ + wxCHECK_MSG( N >= 0 && N < m_noItems, NULL, + wxT("invalid index in wxListBox::GetClientData")); + + return (void *)m_dataArray[N]; +} + +wxClientData *wxListBox::DoGetItemClientObject(int N) const +{ + return (wxClientData *) DoGetItemClientData( N ) ; +} + +void wxListBox::DoSetItemClientData(int N, void *Client_data) +{ + wxCHECK_RET( N >= 0 && N < m_noItems, + wxT("invalid index in wxListBox::SetClientData") ); + +#if wxUSE_OWNER_DRAWN + if ( m_windowStyle & wxLB_OWNERDRAW ) + { + // client data must be pointer to wxOwnerDrawn, otherwise we would crash + // in OnMeasure/OnDraw. + wxFAIL_MSG(wxT("Can't use client data with owner-drawn listboxes")); + } +#endif // wxUSE_OWNER_DRAWN + wxASSERT_MSG( m_dataArray.GetCount() >= (size_t) N , wxT("invalid client_data array") ) ; + + if ( m_dataArray.GetCount() > (size_t) N ) + { + m_dataArray[N] = (char*) Client_data ; + } + else + { + m_dataArray.Add( (char*) Client_data ) ; + } +} + +void wxListBox::DoSetItemClientObject(int n, wxClientData* clientData) +{ + DoSetItemClientData(n, clientData); +} + +// Return number of selections and an array of selected integers +int wxListBox::GetSelections(wxArrayInt& aSelections) const +{ + return MacGetSelections( aSelections ) ; +} + +// Get single selection, for single choice list items +int wxListBox::GetSelection() const +{ + return MacGetSelection() ; +} + +// Find string for position +wxString wxListBox::GetString(int N) const +{ + return m_stringArray[N] ; +} + +void wxListBox::DoInsertItems(const wxArrayString& items, int pos) +{ + wxCHECK_RET( pos >= 0 && pos <= m_noItems, + wxT("invalid index in wxListBox::InsertItems") ); + + int nItems = items.GetCount(); + + for ( int i = 0 ; i < nItems ; i++ ) + { + m_stringArray.Insert( items[i] , pos + i ) ; + m_dataArray.Insert( NULL , pos + i ) ; + MacInsert( pos + i , items[i] ) ; + } + + m_noItems += nItems; +} + +void wxListBox::SetString(int N, const wxString& s) +{ + m_stringArray[N] = s ; + MacSet( N , s ) ; +} + +wxSize wxListBox::DoGetBestSize() const +{ + int lbWidth = 100; // some defaults + int lbHeight = 110; + int wLine; + + { + wxMacPortStateHelper st( UMAGetWindowPort( (WindowRef) MacGetRootWindow() ) ) ; + + if ( m_font.Ok() ) + { + ::TextFont( m_font.GetMacFontNum() ) ; + ::TextSize( m_font.GetMacFontSize() ) ; + ::TextFace( m_font.GetMacFontStyle() ) ; + } + else + { + ::TextFont( kFontIDMonaco ) ; + ::TextSize( 9 ); + ::TextFace( 0 ) ; + } + + // Find the widest line + for(int i = 0; i < GetCount(); i++) { + wxString str(GetString(i)); + #if wxUSE_UNICODE + Point bounds={0,0} ; + SInt16 baseline ; + ::GetThemeTextDimensions( wxMacCFStringHolder( str , m_font.GetEncoding() ) , + kThemeCurrentPortFont, + kThemeStateActive, + false, + &bounds, + &baseline ); + wLine = bounds.h ; + #else + wLine = ::TextWidth( str.c_str() , 0 , str.Length() ) ; + #endif + lbWidth = wxMax(lbWidth, wLine); + } + + // Add room for the scrollbar + lbWidth += wxSystemSettings::GetMetric(wxSYS_VSCROLL_X); + + // And just a bit more + int cy = 12 ; + int cx = ::TextWidth( "X" , 0 , 1 ) ; + lbWidth += cx ; + + // don't make the listbox too tall (limit height to around 10 items) but don't + // make it too small neither + lbHeight = (cy+4) * wxMin(wxMax(GetCount(), 3), 10); + } + return wxSize(lbWidth, lbHeight); +} + +int wxListBox::GetCount() const +{ + return m_noItems; +} + +void wxListBox::SetupColours() +{ + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); + SetForegroundColour(GetParent()->GetForegroundColour()); +} + +void wxListBox::Refresh(bool eraseBack, const wxRect *rect) +{ + wxControl::Refresh( eraseBack , rect ) ; + // MacRedrawControl() ; +} + +#if wxUSE_OWNER_DRAWN + +class wxListBoxItem : public wxOwnerDrawn +{ +public: + wxListBoxItem(const wxString& str = ""); +}; + +wxListBoxItem::wxListBoxItem(const wxString& str) : wxOwnerDrawn(str, FALSE) +{ + // no bitmaps/checkmarks + SetMarginWidth(0); +} + +wxOwnerDrawn *wxListBox::CreateItem(size_t n) +{ + return new wxListBoxItem(); +} + +#endif //USE_OWNER_DRAWN + +// ============================================================================ +// list box control implementation +// ============================================================================ + +/* +void MacDrawStringCell(Rect *cellRect, Cell lCell, ListHandle theList, long refCon) +{ +wxListBox* list; +// typecast our refCon +list = (wxListBox*)refCon; + + MoveTo(cellRect->left + 4 , cellRect->top + 10 ); + const wxString text = list->m_stringArray[lCell.v] ; + ::TextFont( kFontIDMonaco ) ; + ::TextSize( 9 ); + ::TextFace( 0 ) ; + DrawText(text, 0 , text.Length()); + + } +*/ +void wxListBox::MacDelete( int N ) +{ + LDelRow( 1 , N , (ListHandle)m_macList) ; + Refresh(); +} + +void wxListBox::MacInsert( int n , const wxString& text) +{ + Cell cell = { 0 , 0 } ; + cell.v = n ; + LAddRow( 1 , cell.v , (ListHandle)m_macList ) ; + // LSetCell(text, strlen(text), cell, m_macList); + Refresh(); +} + +void wxListBox::MacAppend( const wxString& text) +{ + Cell cell = { 0 , 0 } ; + cell.v = (**(ListHandle)m_macList).dataBounds.bottom ; + LAddRow( 1 , cell.v , (ListHandle)m_macList ) ; + // LSetCell(text, strlen(text), cell, m_macList); + Refresh(); +} + +void wxListBox::MacClear() +{ + LDelRow( (**(ListHandle)m_macList).dataBounds.bottom , 0 ,(ListHandle) m_macList ) ; + Refresh(); +} + +void wxListBox::MacSetSelection( int n , bool select ) +{ + Cell cell = { 0 , 0 } ; + if ( ! (m_windowStyle & wxLB_MULTIPLE) ) + { + if ( LGetSelect( true , &cell , (ListHandle)m_macList ) ) + { + LSetSelect( false , cell , (ListHandle)m_macList ) ; + } + } + + cell.v = n ; + LSetSelect( select , cell , (ListHandle)m_macList ) ; + LAutoScroll( (ListHandle)m_macList ) ; + Refresh(); +} + +bool wxListBox::MacIsSelected( int n ) const +{ + Cell cell = { 0 , 0 } ; + cell.v = n ; + return LGetSelect( false , &cell , (ListHandle)m_macList ) ; +} + +void wxListBox::MacDestroy() +{ + // DisposeExtLDEFInfo( m_macList ) ; +} + +int wxListBox::MacGetSelection() const +{ + Cell cell = { 0 , 0 } ; + if ( LGetSelect( true , &cell , (ListHandle)m_macList ) ) + return cell.v ; + else + return -1 ; +} + +int wxListBox::MacGetSelections( wxArrayInt& aSelections ) const +{ + int no_sel = 0 ; + + aSelections.Empty(); + + Cell cell = { 0 , 0 } ; + cell.v = 0 ; + + while ( LGetSelect( true , &cell ,(ListHandle) m_macList ) ) + { + aSelections.Add( cell.v ) ; + no_sel++ ; + cell.v++ ; + } + return no_sel ; +} + +void wxListBox::MacSet( int n , const wxString& text ) +{ + // our implementation does not store anything in the list + // so we just have to redraw + Cell cell = { 0 , 0 } ; + cell.v = n ; + // LSetCell(text, strlen(text), cell, m_macList); + Refresh(); +} + +void wxListBox::MacScrollTo( int n ) +{ + // TODO implement scrolling +} + +void wxListBox::OnSize( wxSizeEvent &event) +{ + Point pt; + +#if TARGET_CARBON + GetListCellSize((ListHandle)m_macList, &pt); +#else + pt = (**(ListHandle)m_macList).cellSize ; +#endif + pt.h = m_width - 15 ; + LCellSize( pt , (ListHandle)m_macList ) ; +} + +void wxListBox::MacHandleControlClick( WXWidget control , wxInt16 controlpart , bool WXUNUSED(mouseStillDown)) +{ + Boolean wasDoubleClick = false ; + long result ; + + ::GetControlData( (ControlHandle) m_macControl , kControlNoPart , kControlListBoxDoubleClickTag , sizeof( wasDoubleClick ) , (char*) &wasDoubleClick , &result ) ; + if ( !wasDoubleClick ) + { + MacDoClick() ; + } + else + { + MacDoDoubleClick() ; + } +} + +void wxListBox::MacSetRedraw( bool doDraw ) +{ + LSetDrawingMode( doDraw , (ListHandle)m_macList ) ; + +} + +void wxListBox::MacDoClick() +{ + wxArrayInt aSelections; + int n ; + size_t count = GetSelections(aSelections); + + if ( count == m_selectionPreImage.GetCount() ) + { + bool hasChanged = false ; + for ( size_t i = 0 ; i < count ; ++i ) + { + if ( aSelections[i] != m_selectionPreImage[i] ) + { + hasChanged = true ; + break ; + } + } + if ( !hasChanged ) + { + return ; + } + } + + m_selectionPreImage = aSelections; + + wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, m_windowId); + event.SetEventObject( this ); + + if ( count > 0 ) + { + n = aSelections[0]; + if ( HasClientObjectData() ) + event.SetClientObject( GetClientObject(n) ); + else if ( HasClientUntypedData() ) + event.SetClientData( GetClientData(n) ); + event.SetString( GetString(n) ); + } + else + { + n = -1; + } + + event.m_commandInt = n; + + GetEventHandler()->ProcessEvent(event); +} + +void wxListBox::MacDoDoubleClick() +{ + wxCommandEvent event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, m_windowId); + event.SetEventObject( this ); + GetEventHandler()->ProcessEvent(event) ; +} + +void wxListBox::OnChar(wxKeyEvent& event) +{ + if ( event.GetKeyCode() == WXK_RETURN || event.GetKeyCode() == WXK_NUMPAD_ENTER) + { + wxWindow* parent = GetParent() ; + while( parent && !parent->IsTopLevel() && parent->GetDefaultItem() == NULL ) + parent = parent->GetParent() ; + + if ( parent && parent->GetDefaultItem() ) + { + wxButton *def = wxDynamicCast(parent->GetDefaultItem(), + wxButton); + if ( def && def->IsEnabled() ) + { + wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() ); + event.SetEventObject(def); + def->Command(event); + return ; + } + } + event.Skip() ; + } + /* generate wxID_CANCEL if command-. or has been pressed (typically in dialogs) */ + else if (event.GetKeyCode() == WXK_ESCAPE || (event.GetKeyCode() == '.' && event.MetaDown() ) ) + { + // FIXME: look in ancestors, not just parent. + wxWindow* win = GetParent()->FindWindow( wxID_CANCEL ) ; + if (win) + { + wxCommandEvent new_event(wxEVT_COMMAND_BUTTON_CLICKED,wxID_CANCEL); + new_event.SetEventObject( win ); + win->GetEventHandler()->ProcessEvent( new_event ); + } + } + else if ( event.GetKeyCode() == WXK_TAB ) + { + wxNavigationKeyEvent new_event; + new_event.SetEventObject( this ); + new_event.SetDirection( !event.ShiftDown() ); + /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */ + new_event.SetWindowChange( event.ControlDown() ); + new_event.SetCurrentFocus( this ); + if ( !GetEventHandler()->ProcessEvent( new_event ) ) + event.Skip() ; + } + else if ( event.GetKeyCode() == WXK_DOWN || event.GetKeyCode() == WXK_UP ) + { + // perform the default key handling first + wxControl::OnKeyDown( event ) ; + + wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, m_windowId); + event.SetEventObject( this ); + + wxArrayInt aSelections; + int n, count = GetSelections(aSelections); + if ( count > 0 ) + { + n = aSelections[0]; + if ( HasClientObjectData() ) + event.SetClientObject( GetClientObject(n) ); + else if ( HasClientUntypedData() ) + event.SetClientData( GetClientData(n) ); + event.SetString( GetString(n) ); + } + else + { + n = -1; + } + + event.m_commandInt = n; + + GetEventHandler()->ProcessEvent(event); + } + else + { + if ( event.GetTimestamp() > m_lastTypeIn + 60 ) + { + m_typeIn = wxEmptyString ; + } + m_lastTypeIn = event.GetTimestamp() ; + m_typeIn += (char) event.GetKeyCode() ; + int line = FindString(wxT("*")+m_typeIn+wxT("*")) ; + if ( line >= 0 ) + { + if ( GetSelection() != line ) + { + SetSelection(line) ; + wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, m_windowId); + event.SetEventObject( this ); + + if ( HasClientObjectData() ) + event.SetClientObject( GetClientObject( line ) ); + else if ( HasClientUntypedData() ) + event.SetClientData( GetClientData(line) ); + event.SetString( GetString(line) ); + + event.m_commandInt = line ; + + GetEventHandler()->ProcessEvent(event); + } + } + } +} + diff --git a/src/mac/classic/macnotfy.cpp b/src/mac/classic/macnotfy.cpp new file mode 100644 index 0000000000..690f83b214 --- /dev/null +++ b/src/mac/classic/macnotfy.cpp @@ -0,0 +1,162 @@ +/* ------------------------------------------------------------------------- + * Project: Mac Notifier Support + * Name: macnotfy.c + * Author: Stefan CSomor + * Purpose: Mac Notifier main file + * CVSID: $Id$ + * ------------------------------------------------------------------------- + */ + +#include "wx/wx.h" + +#include "wx/mac/private.h" + +#include "wx/mac/macnotfy.h" + +const short kMaxEvents = 1000 ; + +struct wxMacNotificationEvents +{ + short top ; + short bottom ; + + wxMacNotificationProcPtr proc[kMaxEvents] ; + unsigned long events[kMaxEvents] ; + void* data[kMaxEvents] ; +} ; + +typedef struct wxMacNotificationEvents wxMacNotificationEvents ; +static wxMacNotificationEvents gMacNotificationEvents ; + +static ProcessSerialNumber gAppProcess ; + +void wxMacWakeUp() +{ + ProcessSerialNumber psn ; + Boolean isSame ; + psn.highLongOfPSN = 0 ; + psn.lowLongOfPSN = kCurrentProcess ; + SameProcess( &gAppProcess , &psn , &isSame ) ; + if ( isSame ) + { +#if TARGET_CARBON + EventRef dummyEvent ; + OSStatus err = MacCreateEvent(nil, 'WXMC', 'WXMC', GetCurrentEventTime(), + kEventAttributeNone, &dummyEvent); + if (err == noErr) + { + err = PostEventToQueue(GetMainEventQueue(), dummyEvent, + kEventPriorityHigh); + } +#else + PostEvent( nullEvent , 0 ) ; +#endif + } + else + { + WakeUpProcess( &gAppProcess ) ; + } +} + +void wxMacCreateNotifierTable() +{ + GetCurrentProcess(&gAppProcess); + gMacNotificationEvents.top = 0 ; + gMacNotificationEvents.bottom = 0 ; + for ( int i = 0 ; i < kMaxEvents ; ++i ) + { + gMacNotificationEvents.proc[i] = NULL ; + gMacNotificationEvents.events[i] = NULL ; + gMacNotificationEvents.data[i] = NULL ; + } +} + +void wxMacDestroyNotifierTable() +{ +} + +wxMacNotifierTableRef wxMacGetNotifierTable() +{ + return (wxMacNotifierTableRef) &gMacNotificationEvents ; +} + +void wxMacAddEvent( + wxMacNotifierTableRef table , + wxMacNotificationProcPtr handler , + unsigned long event , + void* data , + short wakeUp ) +{ + wxMacNotificationEvents *e = (wxMacNotificationEvents *) table ; + wxASSERT_MSG( handler != NULL , wxT("illegal notification proc ptr") ) ; + /* this should be protected eventually */ + short index = e->top++ ; + + if ( e->top == kMaxEvents ) + e->top = 0 ; + + e->proc[index] = handler ; + e->events[index] = event ; + e->data[index] = data ; + if ( wakeUp ) + wxMacWakeUp() ; +} + +bool gInProcessing = false ; + +void wxMacRemoveAllNotifiersForData( wxMacNotifierTableRef table , void* data ) +{ + wxMacNotificationEvents *e = (wxMacNotificationEvents *) table ; + /* this should be protected eventually */ + short index = e->bottom ; + + while ( e->top != index ) + { + if ( e->data[index] == data ) + e->data[index] = NULL ; + index++ ; + if ( index == kMaxEvents ) + index = 0 ; + } +} + +void wxMacProcessNotifierEvents() +{ + // if ( gInProcessing ) + // return ; + + gInProcessing = true ; + if ( gMacNotificationEvents.top != gMacNotificationEvents.bottom ) + { + // we only should process the notifiers that were here when we entered it + // otherwise we might never get out... + short count = gMacNotificationEvents.top - gMacNotificationEvents.bottom ; + if ( count < 0 ) + count += kMaxEvents ; + + while ( count-- ) + { + // consume event at bottom + short index = gMacNotificationEvents.bottom++ ; + if ( gMacNotificationEvents.bottom == kMaxEvents ) + gMacNotificationEvents.bottom = 0 ; + void* data = gMacNotificationEvents.data[index] ; + unsigned long event = gMacNotificationEvents.events[index] ; + wxMacNotificationProcPtr handler = gMacNotificationEvents.proc[index] ; + + gMacNotificationEvents.data[index] = NULL ; + gMacNotificationEvents.events[index] = NULL ; + gMacNotificationEvents.proc[index] = NULL ; + + if ( handler ) + handler( event , data ) ; + } + } + gInProcessing = false ; +} + +void wxMacProcessNotifierAndPendingEvents() +{ + wxMacProcessNotifierEvents() ; + wxTheApp->ProcessPendingEvents() ; +} diff --git a/src/mac/classic/main.cpp b/src/mac/classic/main.cpp new file mode 100644 index 0000000000..ad5bd33263 --- /dev/null +++ b/src/mac/classic/main.cpp @@ -0,0 +1,12 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: main.cpp +// Purpose: Entry point +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// We don't put main() in the library any more. GD. diff --git a/src/mac/classic/mdi.cpp b/src/mac/classic/mdi.cpp new file mode 100644 index 0000000000..add9482e11 --- /dev/null +++ b/src/mac/classic/mdi.cpp @@ -0,0 +1,395 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: mdi.cpp +// Purpose: MDI classes +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "mdi.h" +#endif + +#include "wx/mdi.h" +#include "wx/menu.h" +#include "wx/settings.h" +#include "wx/log.h" + +#include "wx/mac/private.h" +#include "wx/mac/uma.h" + +extern wxWindowList wxModelessWindows; + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame, wxFrame) +IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame, wxFrame) +IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow, wxWindow) + +BEGIN_EVENT_TABLE(wxMDIParentFrame, wxFrame) + EVT_ACTIVATE(wxMDIParentFrame::OnActivate) + EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged) +END_EVENT_TABLE() + +BEGIN_EVENT_TABLE(wxMDIClientWindow, wxWindow) + EVT_SCROLL(wxMDIClientWindow::OnScroll) +END_EVENT_TABLE() + +#endif + +static const int IDM_WINDOWTILE = 4001; +static const int IDM_WINDOWTILEHOR = 4001; +static const int IDM_WINDOWCASCADE = 4002; +static const int IDM_WINDOWICONS = 4003; +static const int IDM_WINDOWNEXT = 4004; +static const int IDM_WINDOWTILEVERT = 4005; +static const int IDM_WINDOWPREV = 4006; + +// This range gives a maximum of 500 MDI children. Should be enough :-) +static const int wxFIRST_MDI_CHILD = 4100; +static const int wxLAST_MDI_CHILD = 4600; + +// Status border dimensions +static const int wxTHICK_LINE_BORDER = 3; + +// Parent frame + +wxMDIParentFrame::wxMDIParentFrame() +{ + m_clientWindow = NULL; + m_currentChild = NULL; + m_windowMenu = (wxMenu*) NULL; + m_parentFrameActive = TRUE; +} + +bool wxMDIParentFrame::Create(wxWindow *parent, + wxWindowID id, + const wxString& title, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + m_clientWindow = NULL; + m_currentChild = NULL; + + // this style can be used to prevent a window from having the standard MDI + // "Window" menu + if ( style & wxFRAME_NO_WINDOW_MENU ) + { + m_windowMenu = (wxMenu *)NULL; + style -= wxFRAME_NO_WINDOW_MENU ; + } + else // normal case: we have the window menu, so construct it + { + m_windowMenu = new wxMenu; + + m_windowMenu->Append(IDM_WINDOWCASCADE, wxT("&Cascade")); + m_windowMenu->Append(IDM_WINDOWTILEHOR, wxT("Tile &Horizontally")); + m_windowMenu->Append(IDM_WINDOWTILEVERT, wxT("Tile &Vertically")); + m_windowMenu->AppendSeparator(); + m_windowMenu->Append(IDM_WINDOWICONS, wxT("&Arrange Icons")); + m_windowMenu->Append(IDM_WINDOWNEXT, wxT("&Next")); + } + + wxFrame::Create( parent , id , title , pos , size , style , name ) ; + m_parentFrameActive = TRUE; + + OnCreateClient(); + + return TRUE; +} + +wxMDIParentFrame::~wxMDIParentFrame() +{ + DestroyChildren(); + // already delete by DestroyChildren() +#if wxUSE_TOOLBAR + m_frameToolBar = NULL; +#endif +#if wxUSE_STATUSBAR + m_frameStatusBar = NULL; +#endif + m_clientWindow = NULL ; + + if (m_windowMenu) + { + delete m_windowMenu; + m_windowMenu = (wxMenu*) NULL; + } + + if ( m_clientWindow ) + { + delete m_clientWindow; + m_clientWindow = NULL ; + } +} + + +void wxMDIParentFrame::SetMenuBar(wxMenuBar *menu_bar) +{ + wxFrame::SetMenuBar( menu_bar ) ; +} + +void wxMDIParentFrame::MacActivate(long timestamp, bool activating) +{ + wxLogDebug(wxT("MDI PARENT=%p MacActivate(0x%08lx,%s)"),this,timestamp,activating?wxT("ACTIV"):wxT("deact")); + if(activating) + { + if(s_macDeactivateWindow && s_macDeactivateWindow->GetParent()==this) + { + wxLogDebug(wxT("child had been scheduled for deactivation, rehighlighting")); + UMAHighlightAndActivateWindow((WindowRef)s_macDeactivateWindow->MacGetWindowRef(), true); + wxLogDebug(wxT("done highliting child")); + s_macDeactivateWindow = NULL; + } + else if(s_macDeactivateWindow == this) + { + wxLogDebug(wxT("Avoided deactivation/activation of this=%p"), this); + s_macDeactivateWindow = NULL; + } + else // window to deactivate is NULL or is not us or one of our kids + { + // activate kid instead + if(m_currentChild) + m_currentChild->MacActivate(timestamp,activating); + else + wxFrame::MacActivate(timestamp,activating); + } + } + else + { + // We were scheduled for deactivation, and now we do it. + if(s_macDeactivateWindow==this) + { + s_macDeactivateWindow = NULL; + if(m_currentChild) + m_currentChild->MacActivate(timestamp,activating); + wxFrame::MacActivate(timestamp,activating); + } + else // schedule ourselves for deactivation + { + if(s_macDeactivateWindow) + wxLogDebug(wxT("window=%p SHOULD have been deactivated, oh well!"),s_macDeactivateWindow); + wxLogDebug(wxT("Scheduling delayed MDI Parent deactivation")); + s_macDeactivateWindow = this; + } + } +} + +void wxMDIParentFrame::OnActivate(wxActivateEvent& event) +{ + event.Skip(); +} + +// Returns the active MDI child window +wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const +{ + return m_currentChild ; +} + +// Create the client window class (don't Create the window, +// just return a new class) +wxMDIClientWindow *wxMDIParentFrame::OnCreateClient() +{ + m_clientWindow = new wxMDIClientWindow( this ); + return m_clientWindow; +} + +// Responds to colour changes, and passes event on to children. +void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent& event) +{ + // TODO + + // Propagate the event to the non-top-level children + wxFrame::OnSysColourChanged(event); +} + +// MDI operations +void wxMDIParentFrame::Cascade() +{ + // TODO +} + +void wxMDIParentFrame::Tile() +{ + // TODO +} + +void wxMDIParentFrame::ArrangeIcons() +{ + // TODO +} + +void wxMDIParentFrame::ActivateNext() +{ + // TODO +} + +void wxMDIParentFrame::ActivatePrevious() +{ + // TODO +} + +// Child frame + +wxMDIChildFrame::wxMDIChildFrame() +{ + Init() ; +} +void wxMDIChildFrame::Init() +{ +} + +bool wxMDIChildFrame::Create(wxMDIParentFrame *parent, + wxWindowID id, + const wxString& title, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + SetName(name); + + if ( id > -1 ) + m_windowId = id; + else + m_windowId = (int)NewControlId(); + + if (parent) parent->AddChild(this); + + MacCreateRealWindow( title, pos , size , MacRemoveBordersFromStyle(style) , name ) ; + + m_macWindowBackgroundTheme = kThemeBrushDocumentWindowBackground ; + SetThemeWindowBackground( (WindowRef) m_macWindow , m_macWindowBackgroundTheme , false ) ; + + wxModelessWindows.Append(this); + return FALSE; +} + +wxMDIChildFrame::~wxMDIChildFrame() +{ + wxMDIParentFrame *mdiparent = wxDynamicCast(m_parent, wxMDIParentFrame); + wxASSERT(mdiparent); + if(mdiparent->m_currentChild == this) + mdiparent->m_currentChild = NULL; + DestroyChildren(); + // already delete by DestroyChildren() +#if wxUSE_TOOLBAR + m_frameToolBar = NULL; +#endif +#if wxUSE_STATUSBAR + m_frameStatusBar = NULL; +#endif +} + +void wxMDIChildFrame::SetMenuBar(wxMenuBar *menu_bar) +{ + return wxFrame::SetMenuBar( menu_bar ) ; +} + +void wxMDIChildFrame::MacActivate(long timestamp, bool activating) +{ + wxLogDebug(wxT("MDI child=%p MacActivate(0x%08lx,%s)"),this,timestamp,activating?wxT("ACTIV"):wxT("deact")); + wxMDIParentFrame *mdiparent = wxDynamicCast(m_parent, wxMDIParentFrame); + wxASSERT(mdiparent); + if(activating) + { + if(s_macDeactivateWindow == m_parent) + { + wxLogDebug(wxT("parent had been scheduled for deactivation, rehighlighting")); + UMAHighlightAndActivateWindow((WindowRef)s_macDeactivateWindow->MacGetWindowRef(), true); + wxLogDebug(wxT("done highliting parent")); + s_macDeactivateWindow = NULL; + } + else if((mdiparent->m_currentChild==this) || !s_macDeactivateWindow) + mdiparent->wxFrame::MacActivate(timestamp,activating); + + if(mdiparent->m_currentChild && mdiparent->m_currentChild!=this) + mdiparent->m_currentChild->wxFrame::MacActivate(timestamp,false); + mdiparent->m_currentChild = this; + + if(s_macDeactivateWindow==this) + { + wxLogDebug(wxT("Avoided deactivation/activation of this=%p"),this); + s_macDeactivateWindow=NULL; + } + else + wxFrame::MacActivate(timestamp, activating); + } + else + { + // We were scheduled for deactivation, and now we do it. + if(s_macDeactivateWindow==this) + { + s_macDeactivateWindow = NULL; + wxFrame::MacActivate(timestamp,activating); + if(mdiparent->m_currentChild==this) + mdiparent->wxFrame::MacActivate(timestamp,activating); + } + else // schedule ourselves for deactivation + { + if(s_macDeactivateWindow) + wxLogDebug(wxT("window=%p SHOULD have been deactivated, oh well!"),s_macDeactivateWindow); + wxLogDebug(wxT("Scheduling delayed deactivation")); + s_macDeactivateWindow = this; + } + } +} + +// MDI operations +void wxMDIChildFrame::Maximize() +{ + wxFrame::Maximize() ; +} + +void wxMDIChildFrame::Restore() +{ + wxFrame::Restore() ; +} + +void wxMDIChildFrame::Activate() +{ +} + +//----------------------------------------------------------------------------- +// wxMDIClientWindow +//----------------------------------------------------------------------------- + +wxMDIClientWindow::wxMDIClientWindow() +{ +} + +wxMDIClientWindow::~wxMDIClientWindow() +{ + DestroyChildren(); +} + +bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, long style) +{ + + m_windowId = (int)NewControlId(); + + if ( parent ) + { + parent->AddChild(this); + } + m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE); + + wxModelessWindows.Append(this); + return TRUE; +} + +// Get size *available for subwindows* i.e. excluding menu bar. +void wxMDIClientWindow::DoGetClientSize(int *x, int *y) const +{ + wxDisplaySize( x , y ) ; +} + +// Explicitly call default scroll behaviour +void wxMDIClientWindow::OnScroll(wxScrollEvent& event) +{ +} + diff --git a/src/mac/classic/menu.cpp b/src/mac/classic/menu.cpp new file mode 100644 index 0000000000..9a04c36935 --- /dev/null +++ b/src/mac/classic/menu.cpp @@ -0,0 +1,881 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: menu.cpp +// Purpose: wxMenu, wxMenuBar, wxMenuItem +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "menu.h" +#pragma implementation "menuitem.h" +#endif + +// ============================================================================ +// headers & declarations +// ============================================================================ + +// wxWindows headers +// ----------------- + +#include "wx/app.h" +#include "wx/menu.h" +#include "wx/menuitem.h" +#include "wx/window.h" +#include "wx/log.h" +#include "wx/utils.h" +#include "wx/frame.h" + +#include "wx/mac/uma.h" + +// other standard headers +// ---------------------- +#include + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler) +IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler) +#endif + +// the (popup) menu title has this special id +static const int idMenuTitle = -2; +static MenuItemIndex firstUserHelpMenuItem = 0 ; + +const short kwxMacMenuBarResource = 1 ; +const short kwxMacAppleMenuId = 1 ; + +// ============================================================================ +// implementation +// ============================================================================ +static void wxMenubarUnsetInvokingWindow( wxMenu *menu ) ; +static void wxMenubarSetInvokingWindow( wxMenu *menu, wxWindow *win ); + +// Menus + +// Construct a menu with optional title (then use append) + +#ifdef __DARWIN__ +short wxMenu::s_macNextMenuId = 3 ; +#else +short wxMenu::s_macNextMenuId = 2 ; +#endif + +void wxMenu::Init() +{ + m_doBreak = FALSE; + m_startRadioGroup = -1; + + // create the menu + m_macMenuId = s_macNextMenuId++; + m_hMenu = UMANewMenu(m_macMenuId, m_title, wxFont::GetDefaultEncoding() ); + + if ( !m_hMenu ) + { + wxLogLastError(wxT("UMANewMenu failed")); + } + + // if we have a title, insert it in the beginning of the menu + if ( !!m_title ) + { + Append(idMenuTitle, m_title) ; + AppendSeparator() ; + } +} + +wxMenu::~wxMenu() +{ + if (MAC_WXHMENU(m_hMenu)) + ::DisposeMenu(MAC_WXHMENU(m_hMenu)); +} + +void wxMenu::Break() +{ + // not available on the mac platform +} + +void wxMenu::Attach(wxMenuBarBase *menubar) +{ + wxMenuBase::Attach(menubar); + + EndRadioGroup(); +} + +// function appends a new item or submenu to the menu +// append a new item or submenu to the menu +bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos) +{ + wxASSERT_MSG( pItem != NULL, wxT("can't append NULL item to the menu") ); + + if ( pItem->IsSeparator() ) + { + if ( pos == (size_t)-1 ) + MacAppendMenu(MAC_WXHMENU(m_hMenu), "\p-"); + else + MacInsertMenuItem(MAC_WXHMENU(m_hMenu), "\p-" , pos); + } + else + { + wxMenu *pSubMenu = pItem->GetSubMenu() ; + if ( pSubMenu != NULL ) + { + wxASSERT_MSG( pSubMenu->m_hMenu != NULL , wxT("invalid submenu added")); + pSubMenu->m_menuParent = this ; + + if (wxMenuBar::MacGetInstalledMenuBar() == m_menuBar) + { + pSubMenu->MacBeforeDisplay( true ) ; + } + + if ( pos == (size_t)-1 ) + UMAAppendSubMenuItem(MAC_WXHMENU(m_hMenu), pItem->GetText(), wxFont::GetDefaultEncoding() , pSubMenu->m_macMenuId); + else + UMAInsertSubMenuItem(MAC_WXHMENU(m_hMenu), pItem->GetText(), wxFont::GetDefaultEncoding() , pos, pSubMenu->m_macMenuId); + pItem->UpdateItemBitmap() ; + pItem->UpdateItemStatus() ; + } + else + { + if ( pos == (size_t)-1 ) + { + UMAAppendMenuItem(MAC_WXHMENU(m_hMenu), wxT("a") , wxFont::GetDefaultEncoding() ); + pos = CountMenuItems(MAC_WXHMENU(m_hMenu)) ; + } + else + { + // MacOS counts menu items from 1 and inserts after, therefore having the + // same effect as wx 0 based and inserting before, we must correct pos + // after however for updates to be correct + UMAInsertMenuItem(MAC_WXHMENU(m_hMenu), wxT("a"), wxFont::GetDefaultEncoding(), pos); + pos += 1 ; + } + + SetMenuItemCommandID( MAC_WXHMENU(m_hMenu) , pos , pItem->GetId() ) ; + pItem->UpdateItemText() ; + pItem->UpdateItemBitmap() ; + pItem->UpdateItemStatus() ; + + if ( pItem->GetId() == idMenuTitle ) + { + UMAEnableMenuItem(MAC_WXHMENU(m_hMenu) , pos , false ) ; + } + } + } + // if we're already attached to the menubar, we must update it + if ( IsAttached() ) + { + m_menuBar->Refresh(); + } + return TRUE ; +} + +void wxMenu::EndRadioGroup() +{ + // we're not inside a radio group any longer + m_startRadioGroup = -1; +} + +wxMenuItem* wxMenu::DoAppend(wxMenuItem *item) +{ + wxCHECK_MSG( item, NULL, _T("NULL item in wxMenu::DoAppend") ); + + bool check = FALSE; + + if ( item->GetKind() == wxITEM_RADIO ) + { + int count = GetMenuItemCount(); + + if ( m_startRadioGroup == -1 ) + { + // start a new radio group + m_startRadioGroup = count; + + // for now it has just one element + item->SetAsRadioGroupStart(); + item->SetRadioGroupEnd(m_startRadioGroup); + + // ensure that we have a checked item in the radio group + check = TRUE; + } + else // extend the current radio group + { + // we need to update its end item + item->SetRadioGroupStart(m_startRadioGroup); + wxMenuItemList::Node *node = GetMenuItems().Item(m_startRadioGroup); + + if ( node ) + { + node->GetData()->SetRadioGroupEnd(count); + } + else + { + wxFAIL_MSG( _T("where is the radio group start item?") ); + } + } + } + else // not a radio item + { + EndRadioGroup(); + } + + if ( !wxMenuBase::DoAppend(item) || !DoInsertOrAppend(item) ) + { + return NULL; + } + + if ( check ) + { + // check the item initially + item->Check(TRUE); + } + + return item; +} + +wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item) +{ + if (wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos)) + return item; + else + return NULL; +} + +wxMenuItem *wxMenu::DoRemove(wxMenuItem *item) +{ + // we need to find the items position in the child list + size_t pos; + wxMenuItemList::Node *node = GetMenuItems().GetFirst(); + for ( pos = 0; node; pos++ ) + { + if ( node->GetData() == item ) + break; + + node = node->GetNext(); + } + + // DoRemove() (unlike Remove) can only be called for existing item! + wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") ); + + ::DeleteMenuItem(MAC_WXHMENU(m_hMenu) , pos + 1); + + if ( IsAttached() ) + { + // otherwise, the change won't be visible + m_menuBar->Refresh(); + } + + // and from internal data structures + return wxMenuBase::DoRemove(item); +} + +void wxMenu::SetTitle(const wxString& label) +{ + m_title = label ; + UMASetMenuTitle(MAC_WXHMENU(m_hMenu) , label , wxFont::GetDefaultEncoding() ) ; +} +bool wxMenu::ProcessCommand(wxCommandEvent & event) +{ + bool processed = FALSE; + + // Try the menu's event handler + if ( !processed && GetEventHandler()) + { + processed = GetEventHandler()->ProcessEvent(event); + } + + // Try the window the menu was popped up from (and up through the + // hierarchy) + wxWindow *win = GetInvokingWindow(); + if ( !processed && win ) + processed = win->GetEventHandler()->ProcessEvent(event); + + return processed; +} + + +// --------------------------------------------------------------------------- +// other +// --------------------------------------------------------------------------- + +wxWindow *wxMenu::GetWindow() const +{ + if ( m_invokingWindow != NULL ) + return m_invokingWindow; + else if ( m_menuBar != NULL) + return (wxWindow *) m_menuBar->GetFrame(); + + return NULL; +} + +// helper functions returning the mac menu position for a certain item, note that this is +// mac-wise 1 - based, i.e. the first item has index 1 whereas on MSWin it has pos 0 + +int wxMenu::MacGetIndexFromId( int id ) +{ + size_t pos; + wxMenuItemList::Node *node = GetMenuItems().GetFirst(); + for ( pos = 0; node; pos++ ) + { + if ( node->GetData()->GetId() == id ) + break; + + node = node->GetNext(); + } + + if (!node) + return 0; + + return pos + 1 ; +} + +int wxMenu::MacGetIndexFromItem( wxMenuItem *pItem ) +{ + size_t pos; + wxMenuItemList::Node *node = GetMenuItems().GetFirst(); + for ( pos = 0; node; pos++ ) + { + if ( node->GetData() == pItem ) + break; + + node = node->GetNext(); + } + + if (!node) + return 0; + + return pos + 1 ; +} + +void wxMenu::MacEnableMenu( bool bDoEnable ) +{ + UMAEnableMenuItem(MAC_WXHMENU(m_hMenu) , 0 , bDoEnable ) ; + + ::DrawMenuBar() ; +} + +// MacOS needs to know about submenus somewhere within this menu +// before it can be displayed , also hide special menu items like preferences +// that are handled by the OS +void wxMenu::MacBeforeDisplay( bool isSubMenu ) +{ + wxMenuItem* previousItem = NULL ; + size_t pos ; + wxMenuItemList::Node *node; + wxMenuItem *item; + for (pos = 0, node = GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++) + { + item = (wxMenuItem *)node->GetData(); + wxMenu* subMenu = item->GetSubMenu() ; + if (subMenu) + { + subMenu->MacBeforeDisplay( true ) ; + } + else + { + #if TARGET_CARBON + if ( UMAGetSystemVersion() >= 0x1000 ) + { + if ( item->GetId() == wxApp::s_macPreferencesMenuItemId || item->GetId() == wxApp::s_macExitMenuItemId) + { + ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ) , pos + 1, kMenuItemAttrHidden, 0 ); + if ( GetMenuItems().GetCount() == pos + 1 && + previousItem != NULL && + previousItem->IsSeparator() ) + { + ChangeMenuItemAttributes( MAC_WXHMENU( GetHMenu() ) , pos , kMenuItemAttrHidden, 0 ); + } + } + } + #endif + } + previousItem = item ; + } + + if ( isSubMenu ) + ::InsertMenu(MAC_WXHMENU( GetHMenu()), -1); + +} +// undo all changes from the MacBeforeDisplay call +void wxMenu::MacAfterDisplay( bool isSubMenu ) +{ + if ( isSubMenu ) + ::DeleteMenu(MacGetMenuId()); + + wxMenuItem* previousItem = NULL ; + int pos ; + wxMenuItemList::Node *node; + wxMenuItem *item; + for (pos = 0, node = GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++) + { + item = (wxMenuItem *)node->GetData(); + wxMenu* subMenu = item->GetSubMenu() ; + if (subMenu) + { + subMenu->MacAfterDisplay( true ) ; + } + else + { + // no need to undo hidings + } + previousItem = item ; + } +} + +// Menu Bar + +/* + +Mac Implementation note : + +The Mac has only one global menubar, so we attempt to install the currently +active menubar from a frame, we currently don't take into account mdi-frames +which would ask for menu-merging + +Secondly there is no mac api for changing a menubar that is not the current +menubar, so we have to wait for preparing the actual menubar until the +wxMenubar is to be used + +We can in subsequent versions use MacInstallMenuBar to provide some sort of +auto-merge for MDI in case this will be necessary + +*/ + +wxMenuBar* wxMenuBar::s_macInstalledMenuBar = NULL ; +wxMenuBar* wxMenuBar::s_macCommonMenuBar = NULL ; + +void wxMenuBar::Init() +{ + m_eventHandler = this; + m_menuBarFrame = NULL; + m_invokingWindow = (wxWindow*) NULL; +} + +wxMenuBar::wxMenuBar() +{ + Init(); +} + +wxMenuBar::wxMenuBar( long WXUNUSED(style) ) +{ + Init(); +} + + +wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[]) +{ + Init(); + + m_titles.Alloc(count); + + for ( int i = 0; i < count; i++ ) + { + m_menus.Append(menus[i]); + m_titles.Add(titles[i]); + + menus[i]->Attach(this); + } +} + +wxMenuBar::~wxMenuBar() +{ + if (s_macCommonMenuBar == this) + s_macCommonMenuBar = NULL; + if (s_macInstalledMenuBar == this) + { + ::ClearMenuBar(); + s_macInstalledMenuBar = NULL; + } + +} + +void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground), const wxRect *WXUNUSED(rect)) +{ + wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") ); + + DrawMenuBar(); +} + +void wxMenuBar::MacInstallMenuBar() +{ + if ( s_macInstalledMenuBar == this ) + return ; + + wxStAppResource resload ; + + Handle menubar = ::GetNewMBar( kwxMacMenuBarResource ) ; + wxString message ; + wxCHECK_RET( menubar != NULL, wxT("can't read MBAR resource") ); + ::SetMenuBar( menubar ) ; +#if TARGET_API_MAC_CARBON + ::DisposeMenuBar( menubar ) ; +#else + ::DisposeHandle( menubar ) ; +#endif + +#if TARGET_API_MAC_OS8 + MenuHandle menu = ::GetMenuHandle( kwxMacAppleMenuId ) ; + if ( CountMenuItems( menu ) == 2 ) + { + ::AppendResMenu(menu, 'DRVR'); + } +#endif + + // clean-up the help menu before adding new items + MenuHandle mh = NULL ; + if ( UMAGetHelpMenu( &mh , &firstUserHelpMenuItem) == noErr ) + { + for ( int i = CountMenuItems( mh ) ; i >= firstUserHelpMenuItem ; --i ) + { + DeleteMenuItem( mh , i ) ; + } + } + else + { + mh = NULL ; + } +#if TARGET_CARBON + if ( UMAGetSystemVersion() >= 0x1000 && wxApp::s_macPreferencesMenuItemId) + { + wxMenuItem *item = FindItem( wxApp::s_macPreferencesMenuItemId , NULL ) ; + if ( item == NULL || !(item->IsEnabled()) ) + DisableMenuCommand( NULL , kHICommandPreferences ) ; + else + EnableMenuCommand( NULL , kHICommandPreferences ) ; + } +#endif + for (size_t i = 0; i < m_menus.GetCount(); i++) + { + wxMenuItemList::Node *node; + wxMenuItem *item; + int pos ; + wxMenu* menu = m_menus[i] , *subMenu = NULL ; + + if( m_titles[i] == wxT("?") || m_titles[i] == wxT("&?") || m_titles[i] == wxApp::s_macHelpMenuTitleName ) + { + if ( mh == NULL ) + { + continue ; + } + + for (pos = 0 , node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext(), pos++) + { + item = (wxMenuItem *)node->GetData(); + subMenu = item->GetSubMenu() ; + if (subMenu) + { + // we don't support hierarchical menus in the help menu yet + } + else + { + if ( item->IsSeparator() ) + { + if ( mh ) + MacAppendMenu(mh, "\p-" ); + } + else + { + wxAcceleratorEntry* entry = wxGetAccelFromString( item->GetText() ) ; + + if ( item->GetId() == wxApp::s_macAboutMenuItemId ) + { + UMASetMenuItemText( GetMenuHandle( kwxMacAppleMenuId ) , 1 , item->GetText() , wxFont::GetDefaultEncoding() ); + UMAEnableMenuItem( GetMenuHandle( kwxMacAppleMenuId ) , 1 , true ); + SetMenuItemCommandID( GetMenuHandle( kwxMacAppleMenuId ) , 1 , item->GetId() ) ; + UMASetMenuItemShortcut( GetMenuHandle( kwxMacAppleMenuId ) , 1 , entry ) ; + } + else + { + if ( mh ) + { + UMAAppendMenuItem(mh, item->GetText() , wxFont::GetDefaultEncoding(), entry); + SetMenuItemCommandID( mh , CountMenuItems(mh) , item->GetId() ) ; + } + } + + delete entry ; + } + } + } + } + else + { + UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , m_titles[i], m_font.GetEncoding() ) ; + m_menus[i]->MacBeforeDisplay(false) ; + ::InsertMenu(MAC_WXHMENU(m_menus[i]->GetHMenu()), 0); + } + } + ::DrawMenuBar() ; + s_macInstalledMenuBar = this; +} + +void wxMenuBar::EnableTop(size_t pos, bool enable) +{ + wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") ); + m_menus[pos]->MacEnableMenu( enable ) ; + Refresh(); +} + +void wxMenuBar::SetLabelTop(size_t pos, const wxString& label) +{ + wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") ); + + m_titles[pos] = label; + + if ( !IsAttached() ) + { + return; + } + + m_menus[pos]->SetTitle( label ) ; + if (wxMenuBar::s_macInstalledMenuBar == this) // are we currently installed ? + { + ::SetMenuBar( GetMenuBar() ) ; + ::InvalMenuBar() ; + } +} + +wxString wxMenuBar::GetLabelTop(size_t pos) const +{ + wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString, + wxT("invalid menu index in wxMenuBar::GetLabelTop") ); + + return m_titles[pos]; +} + +int wxMenuBar::FindMenu(const wxString& title) +{ + wxString menuTitle = wxStripMenuCodes(title); + + size_t count = GetMenuCount(); + for ( size_t i = 0; i < count; i++ ) + { + wxString title = wxStripMenuCodes(m_titles[i]); + if ( menuTitle == title ) + return i; + } + + return wxNOT_FOUND; + +} + + +// --------------------------------------------------------------------------- +// wxMenuBar construction +// --------------------------------------------------------------------------- + +// --------------------------------------------------------------------------- +// wxMenuBar construction +// --------------------------------------------------------------------------- + +wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title) +{ + wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title); + if ( !menuOld ) + return FALSE; + m_titles[pos] = title; + + if ( IsAttached() ) + { + if (s_macInstalledMenuBar == this) + { + menuOld->MacAfterDisplay( false ) ; + ::DeleteMenu( menuOld->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ; + { + menu->MacBeforeDisplay( false ) ; + UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title , m_font.GetEncoding() ) ; + if ( pos == m_menus.GetCount() - 1) + { + ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ; + } + else + { + ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ; + } + } + } + + Refresh(); + } + + return menuOld; +} + +bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title) +{ + if ( !wxMenuBarBase::Insert(pos, menu, title) ) + return FALSE; + + m_titles.Insert(title, pos); + + UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title , m_font.GetEncoding() ) ; + + if ( IsAttached() && s_macInstalledMenuBar == this ) + { + if (s_macInstalledMenuBar == this) + { + menu->MacBeforeDisplay( false ) ; + if ( pos == (size_t) -1 || pos + 1 == m_menus.GetCount() ) + { + ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ; + } + else + { + ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , m_menus[pos+1]->MacGetMenuId() ) ; + } + } + Refresh(); + } + + return TRUE; +} + +wxMenu *wxMenuBar::Remove(size_t pos) +{ + wxMenu *menu = wxMenuBarBase::Remove(pos); + if ( !menu ) + return NULL; + + if ( IsAttached() ) + { + if (s_macInstalledMenuBar == this) + { + ::DeleteMenu( menu->MacGetMenuId() /* m_menus[pos]->MacGetMenuId() */ ) ; + } + + Refresh(); + } + + m_titles.RemoveAt(pos); + + return menu; +} + +bool wxMenuBar::Append(wxMenu *menu, const wxString& title) +{ + WXHMENU submenu = menu ? menu->GetHMenu() : 0; + wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") ); + + if ( !wxMenuBarBase::Append(menu, title) ) + return FALSE; + + m_titles.Add(title); + + UMASetMenuTitle( MAC_WXHMENU(menu->GetHMenu()) , title , m_font.GetEncoding() ) ; + + if ( IsAttached() ) + { + if (s_macInstalledMenuBar == this) + { + ::InsertMenu( MAC_WXHMENU(menu->GetHMenu()) , 0 ) ; + } + + Refresh(); + } + + // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables + // adding menu later on. + if (m_invokingWindow) + wxMenubarSetInvokingWindow( menu, m_invokingWindow ); + + return TRUE; +} + +static void wxMenubarUnsetInvokingWindow( wxMenu *menu ) +{ + menu->SetInvokingWindow( (wxWindow*) NULL ); + + wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst(); + while (node) + { + wxMenuItem *menuitem = node->GetData(); + if (menuitem->IsSubMenu()) + wxMenubarUnsetInvokingWindow( menuitem->GetSubMenu() ); + node = node->GetNext(); + } +} + +static void wxMenubarSetInvokingWindow( wxMenu *menu, wxWindow *win ) +{ + menu->SetInvokingWindow( win ); + + wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst(); + while (node) + { + wxMenuItem *menuitem = node->GetData(); + if (menuitem->IsSubMenu()) + wxMenubarSetInvokingWindow( menuitem->GetSubMenu() , win ); + node = node->GetNext(); + } +} + +void wxMenuBar::UnsetInvokingWindow() +{ + m_invokingWindow = (wxWindow*) NULL; + wxMenuList::Node *node = m_menus.GetFirst(); + while (node) + { + wxMenu *menu = node->GetData(); + wxMenubarUnsetInvokingWindow( menu ); + node = node->GetNext(); + } +} + +void wxMenuBar::SetInvokingWindow(wxFrame *frame) +{ + m_invokingWindow = frame; + wxMenuList::Node *node = m_menus.GetFirst(); + while (node) + { + wxMenu *menu = node->GetData(); + wxMenubarSetInvokingWindow( menu, frame ); + node = node->GetNext(); + } +} + +void wxMenuBar::Detach() +{ + wxMenuBarBase::Detach() ; +} + +void wxMenuBar::Attach(wxFrame *frame) +{ + wxMenuBarBase::Attach( frame ) ; +} +// --------------------------------------------------------------------------- +// wxMenuBar searching for menu items +// --------------------------------------------------------------------------- + +// Find the itemString in menuString, and return the item id or wxNOT_FOUND +int wxMenuBar::FindMenuItem(const wxString& menuString, + const wxString& itemString) const +{ + wxString menuLabel = wxStripMenuCodes(menuString); + size_t count = GetMenuCount(); + for ( size_t i = 0; i < count; i++ ) + { + wxString title = wxStripMenuCodes(m_titles[i]); + if ( menuString == title ) + return m_menus[i]->FindItem(itemString); + } + + return wxNOT_FOUND; +} + +wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const +{ + if ( itemMenu ) + *itemMenu = NULL; + + wxMenuItem *item = NULL; + size_t count = GetMenuCount(); + for ( size_t i = 0; !item && (i < count); i++ ) + { + item = m_menus[i]->FindItem(id, itemMenu); + } + + return item; +} + + diff --git a/src/mac/classic/menuitem.cpp b/src/mac/classic/menuitem.cpp new file mode 100644 index 0000000000..6cc3aa1a79 --- /dev/null +++ b/src/mac/classic/menuitem.cpp @@ -0,0 +1,283 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: menuitem.cpp +// Purpose: wxMenuItem implementation +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// headers & declarations +// ============================================================================ + +#include "wx/app.h" +#include "wx/menu.h" +#include "wx/menuitem.h" + +#include "wx/mac/uma.h" +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// dynamic classes implementation +// ---------------------------------------------------------------------------- + +#if !USE_SHARED_LIBRARY + IMPLEMENT_DYNAMIC_CLASS(wxMenuItem, wxObject) +#endif //USE_SHARED_LIBRARY + +// ---------------------------------------------------------------------------- +// wxMenuItem +// ---------------------------------------------------------------------------- + +// +// ctor & dtor +// ----------- + +wxMenuItem::wxMenuItem(wxMenu *pParentMenu, + int id, + const wxString& text, + const wxString& strHelp, + wxItemKind kind, + wxMenu *pSubMenu) + : wxMenuItemBase(pParentMenu, id, text, strHelp, kind, pSubMenu) +{ + // TO DISCUSS on dev : whether we can veto id 0 + // wxASSERT_MSG( id != 0 || pSubMenu != NULL , wxT("A MenuItem ID of Zero does not work under Mac") ) ; + + // In other languages there is no difference in naming the Exit/Quit menu item between MacOS and Windows guidelines + // therefore these item must not be translated + if ( wxStripMenuCodes(m_text).Upper() == wxT("EXIT") ) + { + m_text =wxT("Quit\tCtrl+Q") ; + } + + m_radioGroup.start = -1; + m_isRadioGroupStart = FALSE; +} + +wxMenuItem::~wxMenuItem() +{ +} + +// change item state +// ----------------- + +void wxMenuItem::SetBitmap(const wxBitmap& bitmap) +{ + m_bitmap = bitmap; + UpdateItemBitmap() ; +} + +void wxMenuItem::UpdateItemBitmap() +{ + if ( !m_parentMenu ) + return ; + + MenuHandle mhandle = MAC_WXHMENU(m_parentMenu->GetHMenu()) ; + MenuItemIndex index = m_parentMenu->MacGetIndexFromItem( this ) ; + if( mhandle == NULL || index == 0) + return ; + + if ( m_bitmap.Ok() ) + { + ControlButtonContentInfo info ; + wxMacCreateBitmapButton( &info , m_bitmap , kControlContentCIconHandle ) ; + if ( info.contentType != kControlNoContent ) + { + if ( info.contentType == kControlContentCIconHandle ) + SetMenuItemIconHandle( mhandle , index , + kMenuColorIconType , (Handle) info.u.cIconHandle ) ; + } + + } +} + +void wxMenuItem::UpdateItemStatus() +{ + if ( !m_parentMenu ) + return ; + +#if TARGET_CARBON + if ( UMAGetSystemVersion() >= 0x1000 && GetId() == wxApp::s_macPreferencesMenuItemId) + { + if ( !IsEnabled() ) + DisableMenuCommand( NULL , kHICommandPreferences ) ; + else + EnableMenuCommand( NULL , kHICommandPreferences ) ; + } + if ( UMAGetSystemVersion() >= 0x1000 && GetId() == wxApp::s_macExitMenuItemId) + { + if ( !IsEnabled() ) + DisableMenuCommand( NULL , kHICommandQuit ) ; + else + EnableMenuCommand( NULL , kHICommandQuit ) ; + } +#endif + { + MenuHandle mhandle = MAC_WXHMENU(m_parentMenu->GetHMenu()) ; + MenuItemIndex index = m_parentMenu->MacGetIndexFromItem( this ) ; + if( mhandle == NULL || index == 0) + return ; + + UMAEnableMenuItem( mhandle , index , m_isEnabled ) ; + if ( IsCheckable() && IsChecked() ) + ::SetItemMark( mhandle , index , 0x12 ) ; // checkmark + else + ::SetItemMark( mhandle , index , 0 ) ; // no mark + + UMASetMenuItemText( mhandle , index , m_text , wxFont::GetDefaultEncoding() ) ; + wxAcceleratorEntry *entry = wxGetAccelFromString( m_text ) ; + UMASetMenuItemShortcut( mhandle , index , entry ) ; + delete entry ; + } +} + +void wxMenuItem::UpdateItemText() +{ + if ( !m_parentMenu ) + return ; + + MenuHandle mhandle = MAC_WXHMENU(m_parentMenu->GetHMenu()) ; + MenuItemIndex index = m_parentMenu->MacGetIndexFromItem( this ) ; + if( mhandle == NULL || index == 0) + return ; + + UMASetMenuItemText( mhandle , index , m_text , wxFont::GetDefaultEncoding() ) ; + wxAcceleratorEntry *entry = wxGetAccelFromString( m_text ) ; + UMASetMenuItemShortcut( mhandle , index , entry ) ; + delete entry ; +} + + +void wxMenuItem::Enable(bool bDoEnable) +{ + if ( m_isEnabled != bDoEnable ) + { + wxMenuItemBase::Enable( bDoEnable ) ; + UpdateItemStatus() ; + } +} +void wxMenuItem::UncheckRadio() +{ + if ( m_isChecked ) + { + wxMenuItemBase::Check( false ) ; + UpdateItemStatus() ; + } +} + +void wxMenuItem::Check(bool bDoCheck) +{ + wxCHECK_RET( IsCheckable(), wxT("only checkable items may be checked") ); + + if ( m_isChecked != bDoCheck ) + { + if ( GetKind() == wxITEM_RADIO ) + { + if ( bDoCheck ) + { + wxMenuItemBase::Check( bDoCheck ) ; + UpdateItemStatus() ; + + // get the index of this item in the menu + const wxMenuItemList& items = m_parentMenu->GetMenuItems(); + int pos = items.IndexOf(this); + wxCHECK_RET( pos != wxNOT_FOUND, + _T("menuitem not found in the menu items list?") ); + + // get the radio group range + int start, + end; + + if ( m_isRadioGroupStart ) + { + // we already have all information we need + start = pos; + end = m_radioGroup.end; + } + else // next radio group item + { + // get the radio group end from the start item + start = m_radioGroup.start; + end = items.Item(start)->GetData()->m_radioGroup.end; + } + + // also uncheck all the other items in this radio group + wxMenuItemList::Node *node = items.Item(start); + for ( int n = start; n <= end && node; n++ ) + { + if ( n != pos ) + { + ((wxMenuItem*)node->GetData())->UncheckRadio(); + } + node = node->GetNext(); + } + } + } + else + { + wxMenuItemBase::Check( bDoCheck ) ; + UpdateItemStatus() ; + } + } +} + +void wxMenuItem::SetText(const wxString& text) +{ + // don't do anything if label didn't change + if ( m_text == text ) + return; + + wxMenuItemBase::SetText(text); + + UpdateItemText() ; +} + +// radio group stuff +// ----------------- + +void wxMenuItem::SetAsRadioGroupStart() +{ + m_isRadioGroupStart = TRUE; +} + +void wxMenuItem::SetRadioGroupStart(int start) +{ + wxASSERT_MSG( !m_isRadioGroupStart, + _T("should only be called for the next radio items") ); + + m_radioGroup.start = start; +} + +void wxMenuItem::SetRadioGroupEnd(int end) +{ + wxASSERT_MSG( m_isRadioGroupStart, + _T("should only be called for the first radio item") ); + + m_radioGroup.end = end; +} + +// ---------------------------------------------------------------------------- +// wxMenuItemBase +// ---------------------------------------------------------------------------- + +/* static */ +wxString wxMenuItemBase::GetLabelFromText(const wxString& text) +{ + return wxStripMenuCodes(text); +} + +wxMenuItem *wxMenuItemBase::New(wxMenu *parentMenu, + int id, + const wxString& name, + const wxString& help, + wxItemKind kind, + wxMenu *subMenu) +{ + return new wxMenuItem(parentMenu, id, name, help, kind, subMenu); +} diff --git a/src/mac/classic/metafile.cpp b/src/mac/classic/metafile.cpp new file mode 100644 index 0000000000..594fe43af5 --- /dev/null +++ b/src/mac/classic/metafile.cpp @@ -0,0 +1,219 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: metafile.cpp +// Purpose: wxMetaFile, wxMetaFileDC etc. These classes are optional. +// Author: Stefan Csomor +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "metafile.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/setup.h" +#endif + +#if wxUSE_METAFILE + +#ifndef WX_PRECOMP +#include "wx/utils.h" +#include "wx/app.h" +#endif + +#include "wx/metafile.h" +#include "wx/clipbrd.h" + +#include "wx/mac/private.h" + +#include +#include + +extern bool wxClipboardIsOpen; + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxMetafile, wxObject) +IMPLEMENT_ABSTRACT_CLASS(wxMetafileDC, wxDC) +#endif + +/* + * Metafiles + * Currently, the only purpose for making a metafile is to put + * it on the clipboard. + */ + +wxMetafileRefData::wxMetafileRefData(void) +{ + m_metafile = 0; +} + +wxMetafileRefData::~wxMetafileRefData(void) +{ + if (m_metafile) + { + KillPicture( (PicHandle) m_metafile ) ; + m_metafile = 0; + } +} + +wxMetaFile::wxMetaFile(const wxString& file) +{ + m_refData = new wxMetafileRefData; + + + M_METAFILEDATA->m_metafile = 0; + wxASSERT_MSG( file.IsEmpty() , wxT("no file based metafile support yet") ) ; +/* + if (!file.IsNull() && (file.Cmp("") == 0)) + M_METAFILEDATA->m_metafile = (WXHANDLE) GetMetaFile(file); +*/ +} + +wxMetaFile::~wxMetaFile() +{ +} + +bool wxMetaFile::SetClipboard(int width, int height) +{ +#if wxUSE_DRAG_AND_DROP + //TODO finishi this port , we need the data obj first + if (!m_refData) + return FALSE; + + bool alreadyOpen=wxTheClipboard->IsOpened() ; + if (!alreadyOpen) + { + wxTheClipboard->Open(); + wxTheClipboard->Clear(); + } + wxDataObject *data = + new wxMetafileDataObject( *this) ; + bool success = wxTheClipboard->SetData(data); + if (!alreadyOpen) + wxTheClipboard->Close(); + return (bool) success; +#endif + return TRUE ; +} + +void wxMetafile::SetHMETAFILE(WXHMETAFILE mf) +{ + if (!m_refData) + m_refData = new wxMetafileRefData; + if ( M_METAFILEDATA->m_metafile ) + KillPicture( (PicHandle) M_METAFILEDATA->m_metafile ) ; + + M_METAFILEDATA->m_metafile = mf; +} + +bool wxMetaFile::Play(wxDC *dc) +{ + if (!m_refData) + return FALSE; + + if (!dc->Ok() ) + return FALSE; + + { + wxMacPortSetter helper( dc ) ; + PicHandle pict = (PicHandle) GetHMETAFILE() ; + DrawPicture( pict , &(**pict).picFrame ) ; + } + return TRUE; +} + +wxSize wxMetaFile::GetSize() const +{ + wxSize size = wxDefaultSize ; + if ( Ok() ) + { + PicHandle pict = (PicHandle) GetHMETAFILE() ; + Rect &r = (**pict).picFrame ; + size.x = r.right - r.left ; + size.y = r.bottom - r.top ; + } + + return size; +} + +/* + * Metafile device context + * + */ + +// New constructor that takes origin and extent. If you use this, don't +// give origin/extent arguments to wxMakeMetaFilePlaceable. + +wxMetaFileDC::wxMetaFileDC(const wxString& filename , + int width , int height , + const wxString& WXUNUSED(description) ) +{ + wxASSERT_MSG( width == 0 || height == 0 , _T("no arbitration of metafilesize supported") ) ; + wxASSERT_MSG( filename.IsEmpty() , _T("no file based metafile support yet")) ; + + m_metaFile = new wxMetaFile(filename) ; + Rect r={0,0,height,width} ; + + RectRgn( (RgnHandle) m_macBoundaryClipRgn , &r ) ; + CopyRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ; + + m_metaFile->SetHMETAFILE( OpenPicture( &r ) ) ; + ::GetPort( (GrafPtr*) &m_macPort ) ; + m_ok = TRUE ; + + SetMapMode(wxMM_TEXT); +} + +wxMetaFileDC::~wxMetaFileDC() +{ +} + +void wxMetaFileDC::DoGetSize(int *width, int *height) const +{ + wxCHECK_RET( m_metaFile , _T("GetSize() doesn't work without a metafile") ); + + wxSize sz = m_metaFile->GetSize() ; + if (width) (*width) = sz.x; + if (height) (*height) = sz.y; +} + +wxMetaFile *wxMetaFileDC::Close() +{ + ClosePicture() ; + return m_metaFile; +} + +#if wxUSE_DATAOBJ +size_t wxMetafileDataObject::GetDataSize() const +{ + return GetHandleSize( (Handle) (*((wxMetafile*)&m_metafile)).GetHMETAFILE() ) ; +} + +bool wxMetafileDataObject::GetDataHere(void *buf) const +{ + memcpy( buf , (*(PicHandle)(*((wxMetafile*)&m_metafile)).GetHMETAFILE()) , + GetHandleSize( (Handle) (*((wxMetafile*)&m_metafile)).GetHMETAFILE() ) ) ; + return true ; +} + +bool wxMetafileDataObject::SetData(size_t len, const void *buf) +{ + Handle handle = NewHandle( len ) ; + SetHandleSize( handle , len ) ; + memcpy( *handle , buf , len ) ; + m_metafile.SetHMETAFILE( handle ) ; + return true ; +} +#endif + +#endif diff --git a/src/mac/classic/mimetmac.cpp b/src/mac/classic/mimetmac.cpp new file mode 100644 index 0000000000..1ea83612c2 --- /dev/null +++ b/src/mac/classic/mimetmac.cpp @@ -0,0 +1,228 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: mac/mimetype.cpp +// Purpose: classes and functions to manage MIME types +// Author: Vadim Zeitlin +// Modified by: +// Created: 23.09.98 +// RCS-ID: $Id$ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence (part of wxExtra library) +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "mimetype.h" +#endif + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/defs.h" +#endif + +#ifndef WX_PRECOMP + #include "wx/string.h" + #if wxUSE_GUI + #include "wx/icon.h" + #endif +#endif //WX_PRECOMP + + +#include "wx/log.h" +#include "wx/file.h" +#include "wx/intl.h" +#include "wx/dynarray.h" +#include "wx/confbase.h" + +#include "wx/mac/mimetype.h" + +// other standard headers +#include + +// in case we're compiling in non-GUI mode +class WXDLLEXPORT wxIcon; + +bool wxFileTypeImpl::SetCommand(const wxString& cmd, const wxString& verb, bool overwriteprompt) +{ + return FALSE; +} + +bool wxFileTypeImpl::SetDefaultIcon(const wxString& strIcon, int index) +{ + return FALSE; +} + +bool wxFileTypeImpl::GetCommand(wxString *command, const char *verb) const +{ + return FALSE; +} + +// @@ this function is half implemented +bool wxFileTypeImpl::GetExtensions(wxArrayString& extensions) +{ + return FALSE; +} + +bool wxFileTypeImpl::GetMimeType(wxString *mimeType) const +{ + if ( m_strFileType.Length() > 0 ) + { + *mimeType = m_strFileType ; + return TRUE ; + } + else + return FALSE; +} + +bool wxFileTypeImpl::GetMimeTypes(wxArrayString& mimeTypes) const +{ + wxString s; + + if (GetMimeType(&s)) + { + mimeTypes.Clear(); + mimeTypes.Add(s); + return TRUE; + } + else + return FALSE; +} + +bool wxFileTypeImpl::GetIcon(wxIconLocation *WXUNUSED(icon)) const +{ + // no such file type or no value or incorrect icon entry + return FALSE; +} + +bool wxFileTypeImpl::GetDescription(wxString *desc) const +{ + return FALSE; +} + +size_t +wxFileTypeImpl::GetAllCommands(wxArrayString * verbs, wxArrayString * commands, + const wxFileType::MessageParameters& params) const +{ + wxFAIL_MSG( _T("wxFileTypeImpl::GetAllCommands() not yet implemented") ); + return 0; +} + +void +wxMimeTypesManagerImpl::Initialize(int mailcapStyles, const wxString& extraDir) +{ + wxFAIL_MSG( _T("wxMimeTypesManagerImpl::Initialize() not yet implemented") ); +} + +void +wxMimeTypesManagerImpl::ClearData() +{ + wxFAIL_MSG( _T("wxMimeTypesManagerImpl::ClearData() not yet implemented") ); +} + +// extension -> file type +wxFileType * +wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString& e) +{ + wxString ext = e ; + ext = ext.Lower() ; + if ( ext == wxT("txt") ) + { + wxFileType *fileType = new wxFileType; + fileType->m_impl->SetFileType(wxT("text/text")); + fileType->m_impl->SetExt(ext); + return fileType; + } + else if ( ext == wxT("htm") || ext == wxT("html") ) + { + wxFileType *fileType = new wxFileType; + fileType->m_impl->SetFileType(wxT("text/html")); + fileType->m_impl->SetExt(ext); + return fileType; + } + else if ( ext == wxT("gif") ) + { + wxFileType *fileType = new wxFileType; + fileType->m_impl->SetFileType(wxT("image/gif")); + fileType->m_impl->SetExt(ext); + return fileType; + } + else if ( ext == wxT("png" )) + { + wxFileType *fileType = new wxFileType; + fileType->m_impl->SetFileType(wxT("image/png")); + fileType->m_impl->SetExt(ext); + return fileType; + } + else if ( ext == wxT("jpg" )|| ext == wxT("jpeg") ) + { + wxFileType *fileType = new wxFileType; + fileType->m_impl->SetFileType(wxT("image/jpeg")); + fileType->m_impl->SetExt(ext); + return fileType; + } + else if ( ext == wxT("bmp") ) + { + wxFileType *fileType = new wxFileType; + fileType->m_impl->SetFileType(wxT("image/bmp")); + fileType->m_impl->SetExt(ext); + return fileType; + } + else if ( ext == wxT("tif") || ext == wxT("tiff") ) + { + wxFileType *fileType = new wxFileType; + fileType->m_impl->SetFileType(wxT("image/tiff")); + fileType->m_impl->SetExt(ext); + return fileType; + } + else if ( ext == wxT("xpm") ) + { + wxFileType *fileType = new wxFileType; + fileType->m_impl->SetFileType(wxT("image/xpm")); + fileType->m_impl->SetExt(ext); + return fileType; + } + else if ( ext == wxT("xbm") ) + { + wxFileType *fileType = new wxFileType; + fileType->m_impl->SetFileType(wxT("image/xbm")); + fileType->m_impl->SetExt(ext); + return fileType; + } + + // unknown extension + return NULL; +} + +// MIME type -> extension -> file type +wxFileType * +wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString& mimeType) +{ + return NULL; +} + +size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxArrayString& mimetypes) +{ + // VZ: don't know anything about this for Mac + wxFAIL_MSG( _T("wxMimeTypesManagerImpl::EnumAllFileTypes() not yet implemented") ); + + return 0; +} + +wxFileType * +wxMimeTypesManagerImpl::Associate(const wxFileTypeInfo& ftInfo) +{ + wxFAIL_MSG( _T("wxMimeTypesManagerImpl::Associate() not yet implemented") ); + + return NULL; +} + +bool +wxMimeTypesManagerImpl::Unassociate(wxFileType *ft) +{ + return FALSE; +} + diff --git a/src/mac/classic/minifram.cpp b/src/mac/classic/minifram.cpp new file mode 100644 index 0000000000..6b49b9bdc7 --- /dev/null +++ b/src/mac/classic/minifram.cpp @@ -0,0 +1,22 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: minifram.cpp +// Purpose: wxMiniFrame. Optional; identical to wxFrame if not supported. +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "minifram.h" +#endif + +#include "wx/minifram.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame, wxFrame) +#endif + + diff --git a/src/mac/classic/msgdlg.cpp b/src/mac/classic/msgdlg.cpp new file mode 100644 index 0000000000..73548ad9f2 --- /dev/null +++ b/src/mac/classic/msgdlg.cpp @@ -0,0 +1,262 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: msgdlg.cpp +// Purpose: wxMessageDialog +// Author: Stefan Csomor +// Modified by: +// Created: 04/01/98 +// RCS-ID: $$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "msgdlg.h" +#endif + +#include "wx/app.h" +#include "wx/msgdlg.h" +#include "wx/intl.h" +#include "wx/mac/uma.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_CLASS(wxMessageDialog, wxDialog) +#endif + +wxMessageDialog::wxMessageDialog(wxWindow *parent, const wxString& message, const wxString& caption, + long style, const wxPoint& pos) +{ + m_caption = caption; + m_message = message; + m_dialogStyle = style; + m_parent = parent; +} + +int wxMessageDialog::ShowModal() +{ + int resultbutton = wxID_CANCEL ; + + short result ; + + wxASSERT_MSG( ( m_dialogStyle & 0x3F ) != wxYES , wxT("this style is not supported on mac") ) ; + + AlertType alertType = kAlertPlainAlert ; + if (m_dialogStyle & wxICON_EXCLAMATION) + alertType = kAlertNoteAlert ; + else if (m_dialogStyle & wxICON_HAND) + alertType = kAlertStopAlert ; + else if (m_dialogStyle & wxICON_INFORMATION) + alertType = kAlertNoteAlert ; + else if (m_dialogStyle & wxICON_QUESTION) + alertType = kAlertCautionAlert ; + +#if TARGET_CARBON + if ( UMAGetSystemVersion() >= 0x1000 ) + { + AlertStdCFStringAlertParamRec param ; + wxMacCFStringHolder cfNoString(_("No") , m_font.GetEncoding()) ; + wxMacCFStringHolder cfYesString( _("Yes") , m_font.GetEncoding()) ; + + wxMacCFStringHolder cfTitle(m_caption , m_font.GetEncoding()); + wxMacCFStringHolder cfText(m_message , m_font.GetEncoding()); + + param.movable = true; + param.flags = 0 ; + + bool skipDialog = false ; + + if (m_dialogStyle & wxYES_NO) + { + if (m_dialogStyle & wxCANCEL) + { + param.defaultText = cfYesString ; + param.cancelText = (CFStringRef) kAlertDefaultCancelText; + param.otherText = cfNoString ; + param.helpButton = false ; + param.defaultButton = kAlertStdAlertOKButton; + param.cancelButton = kAlertStdAlertCancelButton; + } + else + { + param.defaultText = cfYesString ; + param.cancelText = NULL; + param.otherText = cfNoString ; + param.helpButton = false ; + param.defaultButton = kAlertStdAlertOKButton; + param.cancelButton = 0; + } + } + // the msw implementation even shows an ok button if it is not specified, we'll do the same + else + { + if (m_dialogStyle & wxCANCEL) + { + // thats a cancel missing + param.defaultText = (CFStringRef) kAlertDefaultOKText ; + param.cancelText = (CFStringRef) kAlertDefaultCancelText ; + param.otherText = NULL; + param.helpButton = false ; + param.defaultButton = kAlertStdAlertOKButton; + param.cancelButton = 0; + } + else + { + param.defaultText = (CFStringRef) kAlertDefaultOKText ; + param.cancelText = NULL; + param.otherText = NULL; + param.helpButton = false ; + param.defaultButton = kAlertStdAlertOKButton; + param.cancelButton = 0; + } + } + /* + else + { + skipDialog = true ; + } + */ + + param.position = kWindowDefaultPosition; + if ( !skipDialog ) + { + DialogRef alertRef ; + CreateStandardAlert( alertType , cfTitle , cfText , ¶m , &alertRef ) ; + RunStandardAlert( alertRef , NULL , &result ) ; + } + if ( skipDialog ) + return wxID_CANCEL ; + } + else +#endif + { + AlertStdAlertParamRec param; + + Str255 yesPString ; + Str255 noPString ; + + Str255 pascalTitle ; + Str255 pascalText ; + wxMacStringToPascal( m_caption , pascalTitle ) ; + wxMacStringToPascal( _("Yes") , yesPString ) ; + wxMacStringToPascal( _("No") , noPString ) ; + wxMacStringToPascal( m_message , pascalText ) ; + + param.movable = true; + param.filterProc = NULL ; + if (m_dialogStyle & wxYES_NO) + { + if (m_dialogStyle & wxCANCEL) + { + param.defaultText = yesPString ; + param.cancelText = (StringPtr) kAlertDefaultCancelText; + param.otherText = noPString ; + param.helpButton = false ; + param.defaultButton = kAlertStdAlertOKButton; + param.cancelButton = kAlertStdAlertCancelButton; + } + else + { + param.defaultText = yesPString ; + param.cancelText = NULL; + param.otherText = noPString ; + param.helpButton = false ; + param.defaultButton = kAlertStdAlertOKButton; + param.cancelButton = 0; + } + } + else if (m_dialogStyle & wxOK) + { + if (m_dialogStyle & wxCANCEL) + { + param.defaultText = (StringPtr) kAlertDefaultOKText ; + param.cancelText = (StringPtr) kAlertDefaultCancelText ; + param.otherText = NULL; + param.helpButton = false ; + param.defaultButton = kAlertStdAlertOKButton; + param.cancelButton = 0; + } + else + { + param.defaultText = (StringPtr) kAlertDefaultOKText ; + param.cancelText = NULL; + param.otherText = NULL; + param.helpButton = false ; + param.defaultButton = kAlertStdAlertOKButton; + param.cancelButton = 0; + } + } + else + { + return resultbutton ; + } + + param.position = 0; + + StandardAlert( alertType, pascalTitle, pascalText, ¶m, &result ); + } + + if (m_dialogStyle & wxOK) + { + if (m_dialogStyle & wxCANCEL) + { + //TODO add Cancelbutton + switch( result ) + { + case 1 : + resultbutton = wxID_OK ; + break ; + case 2 : + break ; + case 3 : + break ; + } + } + else + { + switch( result ) + { + case 1 : + resultbutton = wxID_OK ; + break ; + case 2 : + break ; + case 3 : + break ; + } + } + } + else if (m_dialogStyle & wxYES_NO) + { + if (m_dialogStyle & wxCANCEL) + { + switch( result ) + { + case 1 : + resultbutton = wxID_YES ; + break ; + case 2 : + resultbutton = wxID_CANCEL ; + break ; + case 3 : + resultbutton = wxID_NO ; + break ; + } + } + else + { + switch( result ) + { + case 1 : + resultbutton = wxID_YES ; + break ; + case 2 : + break ; + case 3 : + resultbutton = wxID_NO ; + break ; + } + } + } + + return resultbutton ; +} + diff --git a/src/mac/classic/notebmac.cpp b/src/mac/classic/notebmac.cpp new file mode 100644 index 0000000000..9aa4fdf5b9 --- /dev/null +++ b/src/mac/classic/notebmac.cpp @@ -0,0 +1,729 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: notebook.cpp +// Purpose: implementation of wxNotebook +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "notebook.h" +#endif + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- +#include "wx/app.h" +#include "wx/string.h" +#include "wx/log.h" +#include "wx/imaglist.h" +#include "wx/image.h" +#include "wx/notebook.h" +#include "wx/mac/uma.h" +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- + +// check that the page index is valid +#define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount()) + + +// ---------------------------------------------------------------------------- +// event table +// ---------------------------------------------------------------------------- + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING) + +BEGIN_EVENT_TABLE(wxNotebook, wxControl) + EVT_NOTEBOOK_PAGE_CHANGED(-1, wxNotebook::OnSelChange) + EVT_MOUSE_EVENTS(wxNotebook::OnMouse) + + EVT_SIZE(wxNotebook::OnSize) + EVT_SET_FOCUS(wxNotebook::OnSetFocus) + EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey) +END_EVENT_TABLE() + +IMPLEMENT_DYNAMIC_CLASS(wxNotebook, wxControl) +IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent, wxCommandEvent) + +// ============================================================================ +// implementation +// ============================================================================ + +// The Appearance Manager docs show using tab controls in either edge to edge +// mode, or inset. I think edge to edge conforms better to the other ports, +// and inset mode is better accomplished with space around the wxNotebook rather +// than within it. --Robin + +// CS : had to switch off tight spacing due to 10.3 problems +#define wxMAC_EDGE_TO_EDGE 0 + +static inline int wxMacTabMargin(long nbStyle, long side) +{ + static int tabMargin = -1; + static int otherMargin = -1; + + if ( tabMargin == -1) + { + if ( UMAHasAquaLayout() ) + { + tabMargin = 26; // From Appearance Manager docs for small tab control dimensions +#if wxMAC_EDGE_TO_EDGE + otherMargin = 0; +#else +// otherMargin = 20; + // JACS - this seems fine on 10.3; 20 is way too much + otherMargin = 8; +#endif + } + else + { + tabMargin = 30; +#if wxMAC_EDGE_TO_EDGE + otherMargin = 0; +#else + otherMargin = 16; +#endif + } + } + + // If the style matches the side asked for then return the tab margin, + // but we have to special case wxNB_TOP since it is zero... + if ( side == wxNB_TOP) + { + if ( nbStyle != 0 && nbStyle & (wxNB_LEFT|wxNB_RIGHT|wxNB_BOTTOM)) + { + return otherMargin; + } + else + { + return tabMargin; + } + } + else if ( nbStyle & side) + return tabMargin; + else + return otherMargin; +} + +static inline int wxMacTabLeftMargin(long style) +{ + return wxMacTabMargin(style, wxNB_LEFT); +} + +static inline int wxMacTabTopMargin(long style) +{ + return wxMacTabMargin(style, wxNB_TOP); +} + +static inline int wxMacTabRightMargin(long style) +{ + return wxMacTabMargin(style, wxNB_RIGHT); +} + +static inline int wxMacTabBottomMargin(long style) +{ + return wxMacTabMargin(style, wxNB_BOTTOM); +} + +// ---------------------------------------------------------------------------- +// wxNotebook construction +// ---------------------------------------------------------------------------- + +// common part of all ctors +void wxNotebook::Init() +{ + if ( UMAHasAquaLayout() ) + { + // Should these depend on wxMAC_EDGE_TO_EDGE too? + m_macHorizontalBorder = 7; + m_macVerticalBorder = 8; + } + + m_nSelection = -1; +} + +// default for dynamic class +wxNotebook::wxNotebook() +{ + Init(); +} + +// the same arguments as for wxControl +wxNotebook::wxNotebook(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + Init(); + + Create(parent, id, pos, size, style, name); +} + +// Create() function +bool wxNotebook::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + if ( !wxNotebookBase::Create(parent, id, pos, size, style, name) ) + return false; + + Rect bounds ; + Str255 title ; + + MacPreControlCreate( parent , id , wxEmptyString , pos , size ,style, wxDefaultValidator , name , &bounds , title ) ; + + int tabstyle = kControlTabSmallNorthProc ; + if ( HasFlag(wxNB_LEFT) ) + tabstyle = kControlTabSmallWestProc ; + else if ( HasFlag( wxNB_RIGHT ) ) + tabstyle = kControlTabSmallEastProc ; + else if ( HasFlag( wxNB_BOTTOM ) ) + tabstyle = kControlTabSmallSouthProc ; + + + m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()) , &bounds , title , false , 0 , 0 , 1, + tabstyle , (long) this ) ; + + MacPostControlCreate() ; + return TRUE ; +} + +// dtor +wxNotebook::~wxNotebook() +{ +} + +// ---------------------------------------------------------------------------- +// wxNotebook accessors +// ---------------------------------------------------------------------------- + +void wxNotebook::SetPadding(const wxSize& padding) +{ + // unsupported by OS +} + +void wxNotebook::SetTabSize(const wxSize& sz) +{ + // unsupported by OS +} + +void wxNotebook::SetPageSize(const wxSize& size) +{ + SetSize( CalcSizeFromPage( size ) ); +} + +wxSize wxNotebook::CalcSizeFromPage(const wxSize& sizePage) const +{ + wxSize sizeTotal = sizePage; + sizeTotal.x += 2 * m_macHorizontalBorder + wxMacTabLeftMargin(GetWindowStyle()) + + wxMacTabRightMargin(GetWindowStyle()) ; + sizeTotal.y += 2 * m_macVerticalBorder + wxMacTabTopMargin(GetWindowStyle()) + + wxMacTabBottomMargin(GetWindowStyle()) ; + + return sizeTotal; +} + +wxSize wxNotebook::DoGetBestSize() const +{ + // calculate the max page size + wxSize size(0, 0); + + size_t count = GetPageCount(); + if ( count ) + { + for ( size_t n = 0; n < count; n++ ) + { + wxSize sizePage = m_pages[n]->GetSize(); + + if ( size.x < sizePage.x ) + size.x = sizePage.x; + if ( size.y < sizePage.y ) + size.y = sizePage.y; + } + } + else // no pages + { + // use some arbitrary default size + size.x = + size.y = 100; + } + + return CalcSizeFromPage(size); +} + +int wxNotebook::SetSelection(size_t nPage) +{ + wxCHECK_MSG( IS_VALID_PAGE(nPage), -1, wxT("notebook page out of range") ); + + if ( int(nPage) != m_nSelection ) + { + wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, m_windowId); + event.SetSelection(nPage); + event.SetOldSelection(m_nSelection); + event.SetEventObject(this); + if ( !GetEventHandler()->ProcessEvent(event) || event.IsAllowed() ) + { + // program allows the page change + event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED); + (void)GetEventHandler()->ProcessEvent(event); + + ChangePage(m_nSelection, nPage); + } + } + + return m_nSelection; +} + +bool wxNotebook::SetPageText(size_t nPage, const wxString& strText) +{ + wxASSERT( IS_VALID_PAGE(nPage) ); + + wxNotebookPage *page = m_pages[nPage]; + page->SetLabel(strText); + MacSetupTabs(); + + return true; +} + +wxString wxNotebook::GetPageText(size_t nPage) const +{ + wxASSERT( IS_VALID_PAGE(nPage) ); + + wxNotebookPage *page = m_pages[nPage]; + return page->GetLabel(); +} + +int wxNotebook::GetPageImage(size_t nPage) const +{ + wxCHECK_MSG( IS_VALID_PAGE(nPage), -1, _T("invalid notebook page") ); + + return m_images[nPage]; +} + +bool wxNotebook::SetPageImage(size_t nPage, int nImage) +{ + wxCHECK_MSG( IS_VALID_PAGE(nPage), FALSE, _T("invalid notebook page") ); + + wxCHECK_MSG( m_imageList && nImage < m_imageList->GetImageCount(), FALSE, + _T("invalid image index in SetPageImage()") ); + + if ( nImage != m_images[nPage] ) + { + // if the item didn't have an icon before or, on the contrary, did have + // it but has lost it now, its size will change - but if the icon just + // changes, it won't + m_images[nPage] = nImage; + + MacSetupTabs() ; + } + + return TRUE; +} + +// ---------------------------------------------------------------------------- +// wxNotebook operations +// ---------------------------------------------------------------------------- + +// remove one page from the notebook, without deleting the window +wxNotebookPage* wxNotebook::DoRemovePage(size_t nPage) +{ + wxCHECK( IS_VALID_PAGE(nPage), NULL ); + wxNotebookPage* page = m_pages[nPage] ; + m_pages.RemoveAt(nPage); + + MacSetupTabs(); + + if(m_nSelection >= (int)GetPageCount()) { + m_nSelection = GetPageCount() - 1; + } + if(m_nSelection >= 0) { + m_pages[m_nSelection]->Show(true); + } + return page; +} + +// remove all pages +bool wxNotebook::DeleteAllPages() +{ + WX_CLEAR_ARRAY(m_pages) ; + MacSetupTabs(); + m_nSelection = -1 ; + return TRUE; +} + + +// same as AddPage() but does it at given position +bool wxNotebook::InsertPage(size_t nPage, + wxNotebookPage *pPage, + const wxString& strText, + bool bSelect, + int imageId) +{ + if ( !wxNotebookBase::InsertPage(nPage, pPage, strText, bSelect, imageId) ) + return false; + + wxASSERT_MSG( pPage->GetParent() == this, + _T("notebook pages must have notebook as parent") ); + + // don't show pages by default (we'll need to adjust their size first) + pPage->Show( false ) ; + + pPage->SetLabel(strText); + + m_images.Insert(imageId, nPage); + + MacSetupTabs(); + + wxRect rect = GetPageRect() ; + pPage->SetSize(rect); + if ( pPage->GetAutoLayout() ) { + pPage->Layout(); + } + + + // now deal with the selection + // --------------------------- + + // if the inserted page is before the selected one, we must update the + // index of the selected page + + if ( int(nPage) <= m_nSelection ) + { + m_nSelection++; + // while this still is the same page showing, we need to update the tabs + SetControl32BitValue( (ControlHandle) m_macControl , m_nSelection + 1 ) ; + } + + // some page should be selected: either this one or the first one if there + // is still no selection + int selNew = -1; + if ( bSelect ) + selNew = nPage; + else if ( m_nSelection == -1 ) + selNew = 0; + + if ( selNew != -1 ) + SetSelection(selNew); + + return true; +} + +/* Added by Mark Newsam +* When a page is added or deleted to the notebook this function updates +* information held in the m_macControl so that it matches the order +* the user would expect. +*/ +void wxNotebook::MacSetupTabs() +{ + SetControl32BitMaximum( (ControlHandle) m_macControl , GetPageCount() ) ; + + wxNotebookPage *page; + ControlTabInfoRec info; + + const size_t countPages = GetPageCount(); + for(size_t ii = 0; ii < countPages; ii++) + { + page = m_pages[ii]; + info.version = 0; + info.iconSuiteID = 0; + wxMacStringToPascal( page->GetLabel() , info.name ) ; + + SetControlData( (ControlHandle) m_macControl, ii+1, kControlTabInfoTag, + sizeof( ControlTabInfoRec) , (char*) &info ) ; + SetTabEnabled( (ControlHandle) m_macControl , ii+1 , true ) ; +#if TARGET_CARBON + if ( GetImageList() && GetPageImage(ii) >= 0 && UMAGetSystemVersion() >= 0x1020 ) + { + // tab controls only support very specific types of images, therefore we are doing an odyssee + // accross the icon worlds (even Apple DTS did not find a shorter path) + // in order not to pollute the icon registry we put every icon into (OSType) 1 and immediately + // afterwards Unregister it (IconRef is ref counted, so it will stay on the tab even if we + // unregister it) in case this will ever lead to having the same icon everywhere add some kind + // of static counter + const wxBitmap* bmap = GetImageList()->GetBitmap( GetPageImage(ii ) ) ; + if ( bmap ) + { + wxBitmap scaledBitmap ; + if ( bmap->GetWidth() != 16 || bmap->GetHeight() != 16 ) + { + scaledBitmap = wxBitmap( bmap->ConvertToImage().Scale(16,16) ) ; + bmap = &scaledBitmap ; + } + ControlButtonContentInfo info ; + wxMacCreateBitmapButton( &info , *bmap , kControlContentPictHandle) ; + IconFamilyHandle iconFamily = (IconFamilyHandle) NewHandle(0) ; + OSErr err = SetIconFamilyData( iconFamily, 'PICT' , (Handle) info.u.picture ) ; + wxASSERT_MSG( err == noErr , wxT("Error when adding bitmap") ) ; + IconRef iconRef ; + err = RegisterIconRefFromIconFamily( 'WXNG' , (OSType) 1, iconFamily, &iconRef ) ; + wxASSERT_MSG( err == noErr , wxT("Error when adding bitmap") ) ; + info.contentType = kControlContentIconRef ; + info.u.iconRef = iconRef ; + SetControlData( (ControlHandle) m_macControl, ii+1,kControlTabImageContentTag, + sizeof( info ), (Ptr)&info ); + wxASSERT_MSG( err == noErr , wxT("Error when setting icon on tab") ) ; + if ( UMAGetSystemVersion() < 0x1030 ) + { + UnregisterIconRef( 'WXNG' , (OSType) 1 ) ; + } + + ReleaseIconRef( iconRef ) ; + DisposeHandle( (Handle) iconFamily ) ; + } + } +#endif + } + Rect bounds; + GetControlBounds((ControlHandle)m_macControl, &bounds); + InvalWindowRect((WindowRef)MacGetRootWindow(), &bounds); +} + +wxRect wxNotebook::GetPageRect() const +{ + // fit the notebook page to the tab control's display area + int w, h; + GetSize(&w, &h); + + return wxRect( + wxMacTabLeftMargin(GetWindowStyle()) + m_macHorizontalBorder, + wxMacTabTopMargin(GetWindowStyle()) + m_macVerticalBorder, + w - wxMacTabLeftMargin(GetWindowStyle()) - wxMacTabRightMargin(GetWindowStyle()) - 2*m_macHorizontalBorder, + h - wxMacTabTopMargin(GetWindowStyle()) - wxMacTabBottomMargin(GetWindowStyle()) - 2*m_macVerticalBorder); +} +// ---------------------------------------------------------------------------- +// wxNotebook callbacks +// ---------------------------------------------------------------------------- + +// @@@ OnSize() is used for setting the font when it's called for the first +// time because doing it in ::Create() doesn't work (for unknown reasons) +void wxNotebook::OnSize(wxSizeEvent& event) +{ + + unsigned int nCount = m_pages.Count(); + wxRect rect = GetPageRect() ; + for ( unsigned int nPage = 0; nPage < nCount; nPage++ ) { + wxNotebookPage *pPage = m_pages[nPage]; + pPage->SetSize(rect); + if ( pPage->GetAutoLayout() ) { + pPage->Layout(); + } + } + + // Processing continues to next OnSize + event.Skip(); +} + +void wxNotebook::OnSelChange(wxNotebookEvent& event) +{ + // is it our tab control? + if ( event.GetEventObject() == this ) + ChangePage(event.GetOldSelection(), event.GetSelection()); + + // we want to give others a chance to process this message as well + event.Skip(); +} + +void wxNotebook::OnSetFocus(wxFocusEvent& event) +{ + // set focus to the currently selected page if any + if ( m_nSelection != -1 ) + m_pages[m_nSelection]->SetFocus(); + + event.Skip(); +} + +void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event) +{ + if ( event.IsWindowChange() ) { + // change pages + AdvanceSelection(event.GetDirection()); + } + else { + // we get this event in 2 cases + // + // a) one of our pages might have generated it because the user TABbed + // out from it in which case we should propagate the event upwards and + // our parent will take care of setting the focus to prev/next sibling + // + // or + // + // b) the parent panel wants to give the focus to us so that we + // forward it to our selected page. We can't deal with this in + // OnSetFocus() because we don't know which direction the focus came + // from in this case and so can't choose between setting the focus to + // first or last panel child + wxWindow *parent = GetParent(); + // the cast is here to fic a GCC ICE + if ( ((wxWindow*)event.GetEventObject()) == parent ) + { + // no, it doesn't come from child, case (b): forward to a page + if ( m_nSelection != -1 ) + { + // so that the page knows that the event comes from it's parent + // and is being propagated downwards + event.SetEventObject(this); + + wxWindow *page = m_pages[m_nSelection]; + if ( !page->GetEventHandler()->ProcessEvent(event) ) + { + page->SetFocus(); + } + //else: page manages focus inside it itself + } + else + { + // we have no pages - still have to give focus to _something_ + SetFocus(); + } + } + else + { + // it comes from our child, case (a), pass to the parent + if ( parent ) { + event.SetCurrentFocus(this); + parent->GetEventHandler()->ProcessEvent(event); + } + } + } +} + +// ---------------------------------------------------------------------------- +// wxNotebook base class virtuals +// ---------------------------------------------------------------------------- + +#if wxUSE_CONSTRAINTS + +// override these 2 functions to do nothing: everything is done in OnSize + +void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse)) +{ + // don't set the sizes of the pages - their correct size is not yet known + wxControl::SetConstraintSizes(FALSE); +} + +bool wxNotebook::DoPhase(int WXUNUSED(nPhase)) +{ + return TRUE; +} + +#endif // wxUSE_CONSTRAINTS + +void wxNotebook::Command(wxCommandEvent& event) +{ + wxFAIL_MSG(wxT("wxNotebook::Command not implemented")); +} + +// ---------------------------------------------------------------------------- +// wxNotebook helper functions +// ---------------------------------------------------------------------------- + +// hide the currently active panel and show the new one +void wxNotebook::ChangePage(int nOldSel, int nSel) +{ + if ( nOldSel != -1 ) + { + m_pages[nOldSel]->Show(FALSE); + } + + if ( nSel != -1 ) + { + wxNotebookPage *pPage = m_pages[nSel]; + pPage->Show(TRUE); + pPage->SetFocus(); + } + + m_nSelection = nSel; + SetControl32BitValue( (ControlHandle) m_macControl , m_nSelection + 1 ) ; +} + + +void wxNotebook::OnMouse( wxMouseEvent &event ) +{ + if ( (ControlHandle) m_macControl == NULL ) + { + event.Skip() ; + return ; + } + + if (event.GetEventType() == wxEVT_LEFT_DOWN || event.GetEventType() == wxEVT_LEFT_DCLICK ) + { + int x = event.m_x ; + int y = event.m_y ; + + MacClientToRootWindow( &x , &y ) ; + + ControlHandle control ; + Point localwhere ; + SInt16 controlpart ; + + localwhere.h = x ; + localwhere.v = y ; + + short modifiers = 0; + + if ( !event.m_leftDown && !event.m_rightDown ) + modifiers |= btnState ; + + if ( event.m_shiftDown ) + modifiers |= shiftKey ; + + if ( event.m_controlDown ) + modifiers |= controlKey ; + + if ( event.m_altDown ) + modifiers |= optionKey ; + + if ( event.m_metaDown ) + modifiers |= cmdKey ; + + control = (ControlHandle) m_macControl ; + if ( control && ::IsControlActive( control ) ) + { + { + wxNotebookEvent changing(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, m_windowId, + ::GetControl32BitValue(control) - 1, m_nSelection); + changing.SetEventObject(this); + GetEventHandler()->ProcessEvent(changing); + + if(changing.IsAllowed()) + { + controlpart = ::HandleControlClick(control, localwhere, modifiers, + (ControlActionUPP) -1); + wxTheApp->s_lastMouseDown = 0 ; + + wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, m_windowId, + ::GetControl32BitValue(control) - 1, m_nSelection); + event.SetEventObject(this); + + GetEventHandler()->ProcessEvent(event); + } + } + } + } +} + + +void wxNotebook::MacHandleControlClick( WXWidget control , wxInt16 controlpart , bool WXUNUSED( mouseStillDown ) ) +{ +#if 0 + wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, m_windowId , ::GetControl32BitValue((ControlHandle)m_macControl) - 1, m_nSelection); + event.SetEventObject(this); + + ProcessEvent(event); +#endif +} + diff --git a/src/mac/classic/palette.cpp b/src/mac/classic/palette.cpp new file mode 100644 index 0000000000..60a0de6a8a --- /dev/null +++ b/src/mac/classic/palette.cpp @@ -0,0 +1,118 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: palette.cpp +// Purpose: wxPalette +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "palette.h" +#endif + +#include "wx/defs.h" + +#if wxUSE_PALETTE + +#include "wx/palette.h" + +#if !USE_SHARED_LIBRARIES +IMPLEMENT_DYNAMIC_CLASS(wxPalette, wxGDIObject) +#endif + +/* + * Palette + * + */ + +wxPaletteRefData::wxPaletteRefData() +{ + m_palette = NULL ; + m_count = 0 ; +} + +wxPaletteRefData::~wxPaletteRefData() +{ + if (m_palette != NULL) { + delete[] m_palette ; + m_palette = NULL; + } +} + +wxPalette::wxPalette() +{ +} + +wxPalette::wxPalette(int n, const unsigned char *red, const unsigned char *green, const unsigned char *blue) +{ + Create(n, red, green, blue); +} + +wxPalette::~wxPalette() +{ +} + +bool wxPalette::Create(int n, const unsigned char *red, const unsigned char *green, const unsigned char *blue) +{ + UnRef(); + + m_refData = new wxPaletteRefData; + + M_PALETTEDATA->m_count = n ; + M_PALETTEDATA->m_palette = new wxColour[n] ; + + for ( int i = 0 ; i < n ; ++i) + { + M_PALETTEDATA->m_palette[i].Set( red[i] , green[i] , blue[i] ) ; + } + + return FALSE; +} + +int wxPalette::GetPixel(const unsigned char red, const unsigned char green, const unsigned char blue) const +{ + if ( !m_refData ) + return -1; + + long bestdiff = 3 * 256 ; + long bestpos = 0 ; + long currentdiff ; + + for ( int i = 0 ; i < M_PALETTEDATA->m_count ; ++i ) + { + const wxColour& col = &M_PALETTEDATA->m_palette[i] ; + currentdiff = abs ( col.Red() - red ) + abs( col.Green() - green ) + abs ( col.Blue() - blue ) ; + if ( currentdiff < bestdiff ) + { + bestdiff = currentdiff ; + bestpos = i ; + if ( bestdiff == 0 ) + break ; + } + } + + return bestpos; +} + +bool wxPalette::GetRGB(int index, unsigned char *red, unsigned char *green, unsigned char *blue) const +{ + if ( !m_refData ) + return FALSE; + + if (index < 0 || index >= M_PALETTEDATA->m_count) + return FALSE; + + const wxColour& col = &M_PALETTEDATA->m_palette[index] ; + *red = col.Red() ; + *green = col.Green() ; + *blue = col.Blue() ; + + return TRUE; +} + +#endif +// wxUSE_PALETTE + diff --git a/src/mac/classic/pen.cpp b/src/mac/classic/pen.cpp new file mode 100644 index 0000000000..fea55ab34e --- /dev/null +++ b/src/mac/classic/pen.cpp @@ -0,0 +1,186 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: pen.cpp +// Purpose: wxPen +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "pen.h" +#endif + +#include "wx/setup.h" +#include "wx/utils.h" +#include "wx/pen.h" + +#if !USE_SHARED_LIBRARIES +IMPLEMENT_DYNAMIC_CLASS(wxPen, wxGDIObject) +#endif + +wxPenRefData::wxPenRefData() +{ + m_style = wxSOLID; + m_width = 1; + m_join = wxJOIN_ROUND ; + m_cap = wxCAP_ROUND ; + m_nbDash = 0 ; + m_dash = 0 ; +} + +wxPenRefData::wxPenRefData(const wxPenRefData& data) +: wxGDIRefData() +{ + m_style = data.m_style; + m_width = data.m_width; + m_join = data.m_join; + m_cap = data.m_cap; + m_nbDash = data.m_nbDash; + m_dash = data.m_dash; + m_colour = data.m_colour; +} + +wxPenRefData::~wxPenRefData() +{ +} + +// Pens + +wxPen::wxPen() +{ +} + +wxPen::~wxPen() +{ +} + +// Should implement Create +wxPen::wxPen(const wxColour& col, int Width, int Style) +{ + m_refData = new wxPenRefData; + + M_PENDATA->m_colour = col; + M_PENDATA->m_width = Width; + M_PENDATA->m_style = Style; + M_PENDATA->m_join = wxJOIN_ROUND ; + M_PENDATA->m_cap = wxCAP_ROUND ; + M_PENDATA->m_nbDash = 0 ; + M_PENDATA->m_dash = 0 ; + + RealizeResource(); +} + +wxPen::wxPen(const wxBitmap& stipple, int Width) +{ + m_refData = new wxPenRefData; + + M_PENDATA->m_stipple = stipple; + M_PENDATA->m_width = Width; + M_PENDATA->m_style = wxSTIPPLE; + M_PENDATA->m_join = wxJOIN_ROUND ; + M_PENDATA->m_cap = wxCAP_ROUND ; + M_PENDATA->m_nbDash = 0 ; + M_PENDATA->m_dash = 0 ; + + RealizeResource(); +} + +void wxPen::Unshare() +{ + // Don't change shared data + if (!m_refData) + { + m_refData = new wxPenRefData(); + } + else + { + wxPenRefData* ref = new wxPenRefData(*(wxPenRefData*)m_refData); + UnRef(); + m_refData = ref; + } +} + +void wxPen::SetColour(const wxColour& col) +{ + Unshare(); + + M_PENDATA->m_colour = col; + + RealizeResource(); +} + +void wxPen::SetColour(unsigned char r, unsigned char g, unsigned char b) +{ + Unshare(); + + M_PENDATA->m_colour.Set(r, g, b); + + RealizeResource(); +} + +void wxPen::SetWidth(int Width) +{ + Unshare(); + + M_PENDATA->m_width = Width; + + RealizeResource(); +} + +void wxPen::SetStyle(int Style) +{ + Unshare(); + + M_PENDATA->m_style = Style; + + RealizeResource(); +} + +void wxPen::SetStipple(const wxBitmap& Stipple) +{ + Unshare(); + + M_PENDATA->m_stipple = Stipple; + M_PENDATA->m_style = wxSTIPPLE; + + RealizeResource(); +} + +void wxPen::SetDashes(int nb_dashes, const wxDash *Dash) +{ + Unshare(); + + M_PENDATA->m_nbDash = nb_dashes; + M_PENDATA->m_dash = (wxDash *)Dash; + + RealizeResource(); +} + +void wxPen::SetJoin(int Join) +{ + Unshare(); + + M_PENDATA->m_join = Join; + + RealizeResource(); +} + +void wxPen::SetCap(int Cap) +{ + Unshare(); + + M_PENDATA->m_cap = Cap; + + RealizeResource(); +} + +bool wxPen::RealizeResource() +{ + // nothing to do here for mac + return TRUE; +} + + diff --git a/src/mac/classic/pnghand.cpp b/src/mac/classic/pnghand.cpp new file mode 100644 index 0000000000..f25141d7e9 --- /dev/null +++ b/src/mac/classic/pnghand.cpp @@ -0,0 +1,904 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: pnghand.cpp +// Purpose: Implements a PNG reader class + handler +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +# pragma implementation "pngread.h" +# pragma implementation "pnghand.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +# pragma hdrstop +#endif + +#include +#include +#include + +#if wxUSE_IOSTREAMH +# include +#else +# include +#endif + +#ifndef __DARWIN__ +# include +#endif +#include "wx/msgdlg.h" +#include "wx/palette.h" +#include "wx/bitmap.h" +#include "wx/mac/pnghand.h" +#include "wx/mac/pngread.h" +#include "wx/mac/private.h" + +extern "C" { +#include "png.h" +} + +extern "C" void png_read_init PNGARG((png_structp png_ptr)); +extern "C" void png_write_init PNGARG((png_structp png_ptr)); + +extern CTabHandle wxMacCreateColorTable( int numColors ) ; +extern void wxMacDestroyColorTable( CTabHandle colors ) ; +extern void wxMacSetColorTableEntry( CTabHandle newColors , int index , int red , int green , int blue ) ; +extern GWorldPtr wxMacCreateGWorld( int width , int height , int depth ) ; +extern void wxMacDestroyGWorld( GWorldPtr gw ) ; + +void +ima_png_error(png_struct *png_ptr, char *message) +{ + wxMessageBox(wxString::FromAscii(message), wxT("PNG error")); + longjmp(png_ptr->jmpbuf, 1); +} + + +// static wxGifReaderIter* iter; +wxPalette *wxCopyPalette(const wxPalette *cmap); + +wxPNGReader::wxPNGReader(void) +{ + filetype = 0; + RawImage = NULL; // Image data + + Width = 0; Height = 0; // Dimensions + Depth = 0; // (bits x pixel) + ColorType = 0; // Bit 1 = Palette used + // Bit 2 = Color used + // Bit 3 = Alpha used + + EfeWidth = 0; // Efective Width + + lpbi = NULL; + bgindex = -1; + m_palette = 0; + imageOK = FALSE; +} + +wxPNGReader::wxPNGReader ( char* ImageFileName ) +{ + imageOK = FALSE; + filetype = 0; + RawImage = NULL; // Image data + + Width = 0; Height = 0; // Dimensions + Depth = 0; // (bits x pixel) + ColorType = 0; // Bit 1 = m_palette used + // Bit 2 = Color used + // Bit 3 = Alpha used + + EfeWidth = 0; // Efective Width + + lpbi = NULL; + bgindex = -1; + m_palette = 0; + + imageOK = ReadFile (ImageFileName); +} + +void +wxPNGReader::Create(int width, int height, int depth, int colortype) +{ + Width = width; Height = height; Depth = depth; + ColorType = (colortype>=0) ? colortype: ((Depth>8) ? COLORTYPE_COLOR: 0); + delete m_palette; + m_palette = NULL; + delete[] RawImage; + RawImage = NULL; + + if (lpbi) { + wxMacDestroyGWorld( (GWorldPtr) lpbi ) ; + } + lpbi = wxMacCreateGWorld( Width , Height , Depth); + if (lpbi) + { + EfeWidth = (long)(((long)Width*Depth + 31) / 32) * 4; + int bitwidth = width ; + if ( EfeWidth > bitwidth ) + bitwidth = EfeWidth ; + + RawImage = (byte*) new char[ ( bitwidth * Height * ((Depth+7)>>3) ) ]; + imageOK = TRUE; + } +} + +wxPNGReader::~wxPNGReader ( ) +{ + if (RawImage != NULL) { + delete[] RawImage ; + RawImage = NULL; + } + if (lpbi) { + wxMacDestroyGWorld( (GWorldPtr) lpbi ) ; + lpbi = NULL; + } + if (m_palette != NULL) { + delete m_palette; + m_palette = NULL; + } +} + + +int wxPNGReader::GetIndex(int x, int y) +{ + if (!Inside(x, y) || (Depth>8)) return -1; + + ImagePointerType ImagePointer = RawImage + EfeWidth*y + (x*Depth >> 3); + int index = (int)(*ImagePointer); + return index; +} + +bool wxPNGReader::GetRGB(int x, int y, byte* r, byte* g, byte* b) +{ + if (!Inside(x, y)) return FALSE; + + if (m_palette) { + return m_palette->GetRGB(GetIndex(x, y), r, g, b); + /* PALETTEENTRY entry; + ::GetPaletteEntries((HPALETTE) m_palette->GetHPALETTE(), GetIndex(x, y), 1, &entry); + *r = entry.peRed; + *g = entry.peGreen; + *b = entry.peBlue; */ + } else { + ImagePointerType ImagePointer = RawImage + EfeWidth*y + (x*Depth >> 3); + *b = ImagePointer[0]; + *g = ImagePointer[1]; + *r = ImagePointer[2]; + } + return TRUE; +} + + +bool wxPNGReader::SetIndex(int x, int y, int index) +{ + if (!Inside(x, y) || (Depth>8)) return FALSE; + + ImagePointerType ImagePointer = RawImage + EfeWidth*y + (x*Depth >> 3); + *ImagePointer = index; + + return TRUE; +} + +bool wxPNGReader::SetRGB(int x, int y, byte r, byte g, byte b) +{ + if (!Inside(x, y)) return FALSE; + + if (ColorType & COLORTYPE_PALETTE) + { + if (!m_palette) return FALSE; + SetIndex(x, y, m_palette->GetPixel(r, g, b)); + + } else { + ImagePointerType ImagePointer = RawImage + EfeWidth*y + (x*Depth >> 3); + ImagePointer[0] = b; + ImagePointer[1] = g; + ImagePointer[2] = r; + } + + return TRUE; +} + +bool wxPNGReader::SetPalette(wxPalette* colourmap) +{ + delete m_palette ; + if (!colourmap) + return FALSE; + ColorType |= (COLORTYPE_PALETTE | COLORTYPE_COLOR); + m_palette = new wxPalette( *colourmap ); + return true ; + // return (DibSetUsage(lpbi, (HPALETTE) m_palette->GetHPALETTE(), WXIMA_COLORS ) != 0); +} + +bool +wxPNGReader::SetPalette(int n, byte *r, byte *g, byte *b) +{ + delete m_palette ; + m_palette = new wxPalette(); + if (!m_palette) + return FALSE; + + if (!g) g = r; + if (!b) b = g; + m_palette->Create(n, r, g, b); + ColorType |= (COLORTYPE_PALETTE | COLORTYPE_COLOR); + return true ; + // return (DibSetUsage(lpbi, (HPALETTE) m_palette->GetHPALETTE(), WXIMA_COLORS ) != 0); +} + +bool +wxPNGReader::SetPalette(int n, rgb_color_struct *rgb_struct) +{ + delete m_palette ; + m_palette = new wxPalette(); + if (!m_palette) + return FALSE; + + byte r[256], g[256], b[256]; + + for(int i=0; iCreate(n, r, g, b); + ColorType |= (COLORTYPE_PALETTE | COLORTYPE_COLOR); + return true ; + // return (DibSetUsage(lpbi, (HPALETTE) m_palette->GetHPALETTE(), WXIMA_COLORS ) != 0); +} + +void wxPNGReader::NullData() +{ + if (lpbi) { + wxMacDestroyGWorld( (GWorldPtr) lpbi ) ; + lpbi = NULL; + } + if (m_palette != NULL) { + delete m_palette; + m_palette = NULL; + } +} + +wxBitmap* wxPNGReader::GetBitmap(void) +{ + wxBitmap *bitmap = new wxBitmap; + if ( InstantiateBitmap(bitmap) ) + return bitmap; + else + { + delete bitmap; + return NULL; + } +} + +bool wxPNGReader::InstantiateBitmap(wxBitmap *bitmap) +{ + if ( lpbi ) + { + bitmap->SetHBITMAP((WXHBITMAP) lpbi); + bitmap->SetWidth(GetWidth()); + bitmap->SetHeight(GetHeight()); + bitmap->SetDepth(GetDepth()); + if ( GetDepth() > 1 && m_palette ) + bitmap->SetPalette(*m_palette); + bitmap->SetOk(TRUE); + + + // Make a mask if appropriate + /* + if ( bgindex > -1 ) + { + wxMask *mask = CreateMask(); + bitmap->SetMask(mask); + } + */ + lpbi = NULL ; // bitmap has taken over ownership + return TRUE; + } + else + { + return FALSE; + } + /* + HDC dc = ::CreateCompatibleDC(NULL); + + if (dc) + { + // tmpBitmap is a dummy, to satisfy ::CreateCompatibleDC (it + // is a memory dc that must have a bitmap selected into it) + HDC dc2 = GetDC(NULL); + HBITMAP tmpBitmap = ::CreateCompatibleBitmap(dc2, GetWidth(), GetHeight()); + ReleaseDC(NULL, dc2); + HBITMAP oldBitmap = (HBITMAP) ::SelectObject(dc, tmpBitmap); + + if ( m_palette ) + { + HPALETTE oldPal = ::SelectPalette(dc, (HPALETTE) m_palette->GetHPALETTE(), FALSE); + ::RealizePalette(dc); + } + + HBITMAP hBitmap = ::CreateDIBitmap(dc, lpbi, + CBM_INIT, RawImage, (LPBITMAPINFO) lpbi, DIB_PAL_COLORS); + + ::SelectPalette(dc, NULL, TRUE); + ::SelectObject(dc, oldBitmap); + ::DeleteObject(tmpBitmap); + ::DeleteDC(dc); + + if ( hBitmap ) + { + bitmap->SetHBITMAP((WXHBITMAP) hBitmap); + bitmap->SetWidth(GetWidth()); + bitmap->SetHeight(GetHeight()); + bitmap->SetDepth(GetDepth()); + if ( GetDepth() > 1 && m_palette ) + bitmap->SetPalette(*m_palette); + bitmap->SetOk(TRUE); + + + // Make a mask if appropriate + if ( bgindex > -1 ) + { + wxMask *mask = CreateMask(); + bitmap->SetMask(mask); + } + return TRUE; + } + else + { + return FALSE; + } + } + else + { + return FALSE; + } + */ + return false ; +} + +wxPalette *wxCopyPalette(const wxPalette *cmap) +{ + wxPalette *newCmap = new wxPalette( *cmap ) ; + return newCmap; +} + +wxMask *wxPNGReader::CreateMask(void) +{ +/* +HBITMAP hBitmap = ::CreateBitmap(GetWidth(), GetHeight(), 1, 1, NULL); + + HDC dc = ::CreateCompatibleDC(NULL); + HBITMAP oldBitmap = (HBITMAP) ::SelectObject(dc, hBitmap); + + int bgIndex = GetBGIndex(); + + int x,y; + + for (x=0; xSetMaskBitmap((WXHBITMAP) hBitmap); + return mask; + */ + return NULL ; +} + +bool wxPNGReader::ReadFile(char * ImageFileName) +{ + int number_passes; + + if (ImageFileName) + strcpy(filename, ImageFileName); + + FILE *fp; + png_struct *png_ptr; + png_info *info_ptr; + wxPNGReaderIter iter(this); + + /* open the file */ + fp = fopen( ImageFileName , "rb" ); + + if (!fp) + return FALSE; + + /* allocate the necessary structures */ + png_ptr = new (png_struct); + if (!png_ptr) + { + fclose(fp); + return FALSE; + } + + info_ptr = new (png_info); + if (!info_ptr) + { + fclose(fp); + delete png_ptr; + return FALSE; + } + /* set error handling */ + if (setjmp(png_ptr->jmpbuf)) + { + png_read_destroy(png_ptr, info_ptr, (png_info *)0); + fclose(fp); + delete png_ptr; + delete info_ptr; + + /* If we get here, we had a problem reading the file */ + return FALSE; + } + //png_set_error(ima_png_error, NULL); + + /* initialize the structures, info first for error handling */ + png_info_init(info_ptr); + png_read_init(png_ptr); + + /* set up the input control */ + png_init_io(png_ptr, fp); + + /* read the file information */ + png_read_info(png_ptr, info_ptr); + + /* allocate the memory to hold the image using the fields + of png_info. */ + png_color_16 my_background={ 0, 31, 127, 255, 0 }; + + if (info_ptr->valid & PNG_INFO_bKGD) + { + png_set_background(png_ptr, &(info_ptr->background), + PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + if ( info_ptr->num_palette > 0 ) + bgindex = info_ptr->background.index; + } + else { + png_set_background(png_ptr, &my_background, + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + + // Added by JACS: guesswork! + if ( info_ptr->num_trans != 0 ) + bgindex = info_ptr->num_trans - 1 ; + } + + /* tell libpng to strip 16 bit depth files down to 8 bits */ + if (info_ptr->bit_depth == 16) + png_set_strip_16(png_ptr); + + int pixel_depth=(info_ptr->pixel_depth<24) ? info_ptr->pixel_depth: 24; + Create(info_ptr->width, info_ptr->height, pixel_depth, + info_ptr->color_type); + + if (info_ptr->num_palette>0) + { + SetPalette((int)info_ptr->num_palette, (rgb_color_struct*)info_ptr->palette); + } + + int row_stride = info_ptr->width * ((pixel_depth+7)>>3); + // printf("P = %d D = %d RS= %d ", info_ptr->num_palette, info_ptr->pixel_depth,row_stride); + // printf("CT = %d TRS = %d BD= %d ", info_ptr->color_type, info_ptr->valid & PNG_INFO_tRNS,info_ptr->bit_depth); + + byte *row_pointers = new byte[row_stride]; + + /* turn on interlace handling */ + if (info_ptr->interlace_type) + number_passes = png_set_interlace_handling(png_ptr); + else + number_passes = 1; + // printf("NP = %d ", number_passes); + + for (int pass=0; pass< number_passes; pass++) + { + iter.upset(); + int y=0; + CGrafPtr origPort ; + GDHandle origDevice ; + + GetGWorld( &origPort , &origDevice ) ; + // ignore shapedc + SetGWorld( (GWorldPtr) lpbi , NULL ) ; + do + { + // (unsigned char *)iter.GetRow(); + if (info_ptr->interlace_type) + { + if (pass>0) + iter.GetRow(row_pointers, row_stride); + png_read_row(png_ptr, row_pointers, NULL); + } + else + png_read_row(png_ptr, row_pointers, NULL); + + if ( info_ptr->palette ) + { + if ( pixel_depth == 8 ) + { + for ( size_t i = 0 ; i < info_ptr->width ; ++i ) + { + png_color_struct* color ; + RGBColor col ; + + int index = row_pointers[i] ; + color = &info_ptr->palette[index] ; + col.red = (((int)color->red) << 8) | ((int)color->red) ; + col.green = (((int)color->green) << 8) | ((int)color->green) ; + col.blue = (((int)color->blue) << 8) | ((int)color->blue) ; + SetCPixel( i, y, &col); + } + /* + png_color_struct* color ; + RGBColor col ; + unsigned char* p = &row_pointers[0] ; + PenNormal() ; + MoveTo( 0 , y ) ; + int index = *p ; + color = &info_ptr->palette[index] ; + col.red = (color->red << 8) | color->red ; + col.green = (color->green << 8) | color->green ; + col.blue = (color->blue << 8) | color->blue ; + RGBForeColor( &col ) ; + col.red = col.green = col.blue = 0xFFFF ; + RGBBackColor( &col ) ; + for ( int i = 0 ; i < info_ptr->width ; ++i , ++p) + { + if ( *p != index ) + { + LineTo( i , y ) ; + index = *p ; + color = &info_ptr->palette[index] ; + col.red = (((int)color->red) << 8) | ((int)color->red) ; + col.green = (((int)color->green) << 8) | ((int)color->green) ; + col.blue = (((int)color->blue) << 8) | ((int)color->blue) ; + RGBForeColor( &col ) ; + } + } + LineTo( info_ptr->width , y ) ; + */ + } + else + { + for ( size_t i = 0 ; i < info_ptr->width ; ++i ) + { + png_color_struct* color ; + RGBColor col ; + + int byte = ( i * pixel_depth ) / 8 ; + int offset = ( 8 - pixel_depth ) - ( i * pixel_depth ) % 8 ; + + int index = ( row_pointers[byte] >> offset ) & ( 0xFF >> ( 8 - pixel_depth ) ); + color = &info_ptr->palette[index] ; + col.red = (((int)color->red) << 8) | ((int)color->red) ; + col.green = (((int)color->green) << 8) | ((int)color->green) ; + col.blue = (((int)color->blue) << 8) | ((int)color->blue) ; + SetCPixel( i, y, &col); + } + } + } + else + { + for ( size_t i = 0 ; i < info_ptr->width ; ++i ) + { + png_color_struct* color ; + RGBColor col ; + color =(png_color_struct*) (&row_pointers[i*3]) ; + col.red = (((int)color->red) << 8) | ((int)color->red) ; + col.green = (((int)color->green) << 8) | ((int)color->green) ; + col.blue = (((int)color->blue) << 8) | ((int)color->blue) ; + SetCPixel( i, y, &col); + } + } + if (number_passes) + iter.SetRow(row_pointers, row_stride); + y++; + } + while(iter.PrevRow()); + SetGWorld( origPort , origDevice ) ; + + // printf("Y=%d ",y); + } + delete[] row_pointers; + + /* read the rest of the file, getting any additional chunks + in info_ptr */ + png_read_end(png_ptr, info_ptr); + + /* clean up after the read, and free any memory allocated */ + png_read_destroy(png_ptr, info_ptr, (png_info *)0); + + /* free the structures */ + delete png_ptr; + delete info_ptr; + + /* close the file */ + fclose(fp); + + /* that's it */ + return TRUE; +} + + +/* write a png file */ + +bool wxPNGReader::SaveFile(char * ImageFileName) +{ + if (ImageFileName) + strcpy(filename, ImageFileName); + + wxPNGReaderIter iter(this); + FILE *fp; + png_struct *png_ptr; + png_info *info_ptr; + + /* open the file */ + fp = fopen(filename, "wb"); + if (!fp) + return FALSE; + + /* allocate the necessary structures */ + png_ptr = new (png_struct); + if (!png_ptr) + { + fclose(fp); + return FALSE; + } + + info_ptr = new (png_info); + if (!info_ptr) + { + fclose(fp); + delete png_ptr; + return FALSE; + } + + /* set error handling */ + if (setjmp(png_ptr->jmpbuf)) + { + png_write_destroy(png_ptr); + fclose(fp); + delete png_ptr; + delete info_ptr; + + /* If we get here, we had a problem reading the file */ + return FALSE; + } + //png_set_error(ima_png_error, NULL); + + // printf("writig pg %s ", filename); + /* initialize the structures */ + png_info_init(info_ptr); + png_write_init(png_ptr); + + int row_stride = GetWidth() * ((GetDepth()+7)>>3); + /* set up the output control */ + png_init_io(png_ptr, fp); + + /* set the file information here */ + info_ptr->width = GetWidth(); + info_ptr->height = GetHeight(); + info_ptr->pixel_depth = GetDepth(); + info_ptr->channels = (GetDepth()>8) ? 3: 1; + info_ptr->bit_depth = GetDepth()/info_ptr->channels; + info_ptr->color_type = GetColorType(); + info_ptr->compression_type = info_ptr->filter_type = info_ptr->interlace_type=0; + info_ptr->valid = 0; + info_ptr->rowbytes = row_stride; + + + // printf("P = %d D = %d RS= %d GD= %d CH= %d ", info_ptr->pixel_depth, info_ptr->bit_depth, row_stride, GetDepth(), info_ptr->channels); + /* set the palette if there is one */ + if ((GetColorType() & COLORTYPE_PALETTE) && GetPalette()) + { + // printf("writing paleta[%d %d %x]",GetColorType() ,COLORTYPE_PALETTE, GetPalette()); + info_ptr->valid |= PNG_INFO_PLTE; + info_ptr->palette = new png_color[256]; + info_ptr->num_palette = 256; + for (int i=0; i<256; i++) + GetPalette()->GetRGB(i, &info_ptr->palette[i].red, &info_ptr->palette[i].green, &info_ptr->palette[i].blue); + } + // printf("Paleta [%d %d %x]",GetColorType() ,COLORTYPE_PALETTE, GetPalette()); + + + /* optional significant bit chunk */ + // info_ptr->valid |= PNG_INFO_sBIT; + // info_ptr->sig_bit = true_bit_depth; + + /* optional gamma chunk */ + // info_ptr->valid |= PNG_INFO_gAMA; + // info_ptr->gamma = gamma; + + /* other optional chunks */ + + /* write the file information */ + png_write_info(png_ptr, info_ptr); + + /* set up the transformations you want. Note that these are + all optional. Only call them if you want them */ + + /* shift the pixels up to a legal bit depth and fill in + as appropriate to correctly scale the image */ + // png_set_shift(png_ptr, &(info_ptr->sig_bit)); + + /* pack pixels into bytes */ + // png_set_packing(png_ptr); + + /* flip bgr pixels to rgb */ + // png_set_bgr(png_ptr); + + /* swap bytes of 16 bit files to most significant bit first */ + // png_set_swap(png_ptr); + + /* get rid of filler bytes, pack rgb into 3 bytes */ + // png_set_rgbx(png_ptr); + + /* If you are only writing one row at a time, this works */ + + byte *row_pointers = new byte[row_stride]; + iter.upset(); + do { + // (unsigned char *)iter.GetRow(); + iter.GetRow(row_pointers, row_stride); + png_write_row(png_ptr, row_pointers); + } while(iter.PrevRow()); + + delete[] row_pointers; + + /* write the rest of the file */ + png_write_end(png_ptr, info_ptr); + + /* clean up after the write, and free any memory allocated */ + png_write_destroy(png_ptr); + + /* if you malloced the palette, free it here */ + if (info_ptr->palette) + delete[] (info_ptr->palette); + + /* free the structures */ + delete png_ptr; + delete info_ptr; + + /* close the file */ + fclose(fp); + + /* that's it */ + return TRUE; +} + +static int Power(int x, int y) +{ + int z = 1; + int i; + for ( i = 0; i < y; i++) + { + z *= x; + } + return z; +} + +static char hexArray[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', +'C', 'D', 'E', 'F' }; + +static void DecToHex(int dec, char *buf) +{ + int firstDigit = (int)(dec/16.0); + int secondDigit = (int)(dec - (firstDigit*16.0)); + buf[0] = hexArray[firstDigit]; + buf[1] = hexArray[secondDigit]; + buf[2] = 0; +} + + +bool wxPNGReader::SaveXPM(char *filename, char *name) +{ + char nameStr[256]; + if ( name ) + strcpy(nameStr, name); + else + { + wxString str = wxString::FromAscii(filename) ; + wxStripExtension( str ) ; + strcpy(nameStr, str.ToAscii() ); + } + + if ( GetDepth() > 4 ) + { + // Only a depth of 4 and below allowed + return FALSE; + } + + if ( !GetPalette() ) + return FALSE; + + wxSTD ofstream str(filename); + if ( str.bad() ) + return FALSE; + + int noColours = Power(2, GetDepth()); + + // Output header + str << "/* XPM */\n"; + str << "static char * " << nameStr << "_xpm[] = {\n"; + str << "\"" << GetWidth() << " " << GetHeight() << " " << noColours << " 1\",\n"; + + // Output colourmap + int base = 97 ; // start from 'a' + + unsigned char red, green, blue; + char hexBuf[4]; + int i; + for ( i = 0; i < noColours; i ++) + { + str << "\"" << (char)(base + i) << " c #"; + GetPalette()->GetRGB(i, &red, &green, &blue); + DecToHex(red, hexBuf); + str << hexBuf; + DecToHex(green, hexBuf); + str << hexBuf; + DecToHex(blue, hexBuf); + str << hexBuf; + str << "\",\n"; + } + + // Output the data + int x, y; + for ( y = 0; y < GetHeight(); y++) + { + str << "\""; + for ( x = 0; x < GetWidth(); x++) + { + int index = GetIndex(x, y); + str << (char)(base + index) ; + } + str << "\",\n"; + } + + str << "};\n"; + str.flush(); + + return TRUE; +} + + +IMPLEMENT_DYNAMIC_CLASS(wxPNGFileHandler, wxBitmapHandler) + +bool wxPNGFileHandler::LoadFile(wxBitmap *bitmap, const wxString& name, long flags, + int desiredWidth, int desiredHeight) +{ + wxPNGReader reader; + if (reader.ReadFile( (char*)(const char*) name.ToAscii() ) ) + { + return reader.InstantiateBitmap(bitmap); + } + else + return FALSE; +} + +bool wxPNGFileHandler::SaveFile(const wxBitmap *bitmap, const wxString& name, int type, const wxPalette *pal) +{ + return FALSE; +} + diff --git a/src/mac/classic/printdlg.cpp b/src/mac/classic/printdlg.cpp new file mode 100644 index 0000000000..89f2789250 --- /dev/null +++ b/src/mac/classic/printdlg.cpp @@ -0,0 +1,124 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: printdlg.cpp +// Purpose: wxPrintDialog, wxPageSetupDialog +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "printdlg.h" +#endif + +#include "wx/object.h" +#include "wx/printdlg.h" +#include "wx/dcprint.h" +#include "wx/msgdlg.h" +#include "wx/mac/private/print.h" + +// Use generic page setup dialog: use your own native one if one exists. + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxPrintDialog, wxDialog) +IMPLEMENT_CLASS(wxPageSetupDialog, wxDialog) +#endif + +wxPrintDialog::wxPrintDialog() +{ + m_dialogParent = NULL; + m_printerDC = NULL; + m_destroyDC = TRUE; +} + +wxPrintDialog::wxPrintDialog(wxWindow *p, wxPrintDialogData* data) +{ + Create(p, data); +} + +wxPrintDialog::wxPrintDialog(wxWindow *p, wxPrintData* data) +{ + wxPrintDialogData data2; + if ( data ) + data2 = *data; + + Create(p, &data2); +} + +bool wxPrintDialog::Create(wxWindow *p, wxPrintDialogData* data) +{ + m_dialogParent = p; + m_printerDC = NULL; + m_destroyDC = TRUE; + + if ( data ) + m_printDialogData = *data; + + return TRUE; +} + +wxPrintDialog::~wxPrintDialog() +{ + if (m_destroyDC && m_printerDC) { + delete m_printerDC; + m_printerDC = NULL; + } +} + +int wxPrintDialog::ShowModal() +{ + m_printDialogData.ConvertToNative() ; + int result = m_printDialogData.GetPrintData().m_nativePrintData->ShowPrintDialog() ; + if ( result == wxID_OK ) + m_printDialogData.ConvertFromNative() ; + + return result ; +} + +wxDC *wxPrintDialog::GetPrintDC() +{ + return new wxPrinterDC( m_printDialogData.GetPrintData() ) ; +} + +/* +* wxPageSetupDialog +*/ + +wxPageSetupDialog::wxPageSetupDialog(): +wxDialog() +{ + m_dialogParent = NULL; +} + +wxPageSetupDialog::wxPageSetupDialog(wxWindow *p, wxPageSetupData *data): +wxDialog() +{ + Create(p, data); +} + +bool wxPageSetupDialog::Create(wxWindow *p, wxPageSetupData *data) +{ + m_dialogParent = p; + + if (data) + m_pageSetupData = (*data); + + return TRUE; +} + +wxPageSetupDialog::~wxPageSetupDialog() +{ +} + +int wxPageSetupDialog::ShowModal() +{ + m_pageSetupData.ConvertToNative() ; + int result = m_pageSetupData.GetPrintData().m_nativePrintData->ShowPageSetupDialog() ; + if (result == wxID_OK ) + m_pageSetupData.ConvertFromNative() ; + + return result ; +} + diff --git a/src/mac/classic/printmac.cpp b/src/mac/classic/printmac.cpp new file mode 100644 index 0000000000..a053eb7d80 --- /dev/null +++ b/src/mac/classic/printmac.cpp @@ -0,0 +1,781 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: printwin.cpp +// Purpose: wxMacPrinter framework +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "printwin.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#include "wx/defs.h" + +#ifndef WX_PRECOMP +#include "wx/utils.h" +#include "wx/dc.h" +#include "wx/app.h" +#include "wx/msgdlg.h" +#endif + +#include "wx/mac/uma.h" + +#include "wx/mac/printmac.h" +#include "wx/mac/private/print.h" + +#define mm2pt 2.83464566929 +#define pt2mm 0.352777777778 + +#include "wx/dcprint.h" +#include "wx/printdlg.h" + +#include + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxMacPrinter, wxPrinterBase) +IMPLEMENT_CLASS(wxMacPrintPreview, wxPrintPreviewBase) +#endif + +#if TARGET_CARBON + +wxNativePrintData* wxNativePrintData::Create() +{ + return new wxMacCarbonPrintData() ; +} + +wxMacCarbonPrintData::wxMacCarbonPrintData() +{ + m_macPageFormat = kPMNoPageFormat; + m_macPrintSettings = kPMNoPrintSettings; + m_macPrintSession = kPMNoReference ; + ValidateOrCreate() ; +} + +wxMacCarbonPrintData::~wxMacCarbonPrintData() +{ + if (m_macPageFormat != kPMNoPageFormat) + { + (void)PMRelease(m_macPageFormat); + m_macPageFormat = kPMNoPageFormat; + } + + if (m_macPrintSettings != kPMNoPrintSettings) + { + (void)PMRelease(m_macPrintSettings); + m_macPrintSettings = kPMNoPrintSettings; + } + + if ( m_macPrintSession != kPMNoReference ) + { + (void)PMRelease(m_macPrintSession); + m_macPrintSession = kPMNoReference; + } +} + +void wxMacCarbonPrintData::ValidateOrCreate() +{ + OSStatus err = noErr ; + if ( m_macPrintSession == kPMNoReference ) + { + err = PMCreateSession( (PMPrintSession *) &m_macPrintSession ) ; + } + // Set up a valid PageFormat object. + if ( m_macPageFormat == kPMNoPageFormat) + { + err = PMCreatePageFormat((PMPageFormat *) &m_macPageFormat); + + // Note that PMPageFormat is not session-specific, but calling + // PMSessionDefaultPageFormat assigns values specific to the printer + // associated with the current printing session. + if ((err == noErr) && + ( m_macPageFormat != kPMNoPageFormat)) + { + err = PMSessionDefaultPageFormat((PMPrintSession) m_macPrintSession, + (PMPageFormat) m_macPageFormat); + } + } + else + { + err = PMSessionValidatePageFormat((PMPrintSession) m_macPrintSession, + (PMPageFormat) m_macPageFormat, + kPMDontWantBoolean); + } + + // Set up a valid PrintSettings object. + if ( m_macPrintSettings == kPMNoPrintSettings) + { + err = PMCreatePrintSettings((PMPrintSettings *) &m_macPrintSettings); + + // Note that PMPrintSettings is not session-specific, but calling + // PMSessionDefaultPrintSettings assigns values specific to the printer + // associated with the current printing session. + if ((err == noErr) && + ( m_macPrintSettings != kPMNoPrintSettings)) + { + err = PMSessionDefaultPrintSettings((PMPrintSession) m_macPrintSession, + (PMPrintSettings) m_macPrintSettings); + } + } + else + { + err = PMSessionValidatePrintSettings((PMPrintSession) m_macPrintSession, + (PMPrintSettings) m_macPrintSettings, + kPMDontWantBoolean); + } +} + +void wxMacCarbonPrintData::TransferFrom( wxPrintData* data ) +{ + ValidateOrCreate() ; + PMSetCopies( (PMPrintSettings) m_macPrintSettings , data->GetNoCopies() , false ) ; + PMSetOrientation( (PMPageFormat) m_macPageFormat , ( data->GetOrientation() == wxLANDSCAPE ) ? + kPMLandscape : kPMPortrait , false ) ; + // collate cannot be set +#if 0 // not yet tested + if ( m_printerName.Length() > 0 ) + PMSessionSetCurrentPrinter( (PMPrintSession) m_macPrintSession , wxMacCFStringHolder( m_printerName , wxFont::GetDefaultEncoding() ) ) ; +#endif + PMColorMode color ; + PMGetColorMode( (PMPrintSettings) m_macPrintSettings, &color ) ; + if ( data->GetColour() ) + { + if ( color == kPMBlackAndWhite ) + PMSetColorMode( (PMPrintSettings) m_macPrintSettings, kPMColor ) ; + } + else + PMSetColorMode( (PMPrintSettings) m_macPrintSettings, kPMBlackAndWhite ) ; + + // PMDuplexMode not yet accessible via API + // PMQualityMode not yet accessible via API + // todo paperSize +} + +void wxMacCarbonPrintData::TransferTo( wxPrintData* data ) +{ + OSStatus err = noErr ; + + UInt32 copies ; + err = PMGetCopies( m_macPrintSettings , &copies ) ; + if ( err == noErr ) + data->SetNoCopies( copies ) ; + + PMOrientation orientation ; + err = PMGetOrientation( m_macPageFormat , &orientation ) ; + if ( err == noErr ) + { + if ( orientation == kPMPortrait || orientation == kPMReversePortrait ) + data->SetOrientation( wxPORTRAIT ); + else + data->SetOrientation( wxLANDSCAPE ); + } + + // collate cannot be set +#if 0 + { + wxMacCFStringHolder name ; + PMPrinter printer ; + PMSessionGetCurrentPrinter( m_macPrintSession , + &printer ) ; + m_printerName = name.AsString() ; + } +#endif + + PMColorMode color ; + err = PMGetColorMode( m_macPrintSettings, &color ) ; + if ( err == noErr ) + data->SetColour( !(color == kPMBlackAndWhite) ) ; + + // PMDuplexMode not yet accessible via API + // PMQualityMode not yet accessible via API + // todo paperSize + PMRect rPaper; + err = PMGetUnadjustedPaperRect( m_macPageFormat, &rPaper); + if ( err == noErr ) + { + data->SetPaperSize( wxSize ( + (int)(( rPaper.right - rPaper.left ) * pt2mm + 0.5 ) , + (int)(( rPaper.bottom - rPaper.top ) * pt2mm + 0.5 ) ) ); + } +} + +void wxMacCarbonPrintData::TransferFrom( wxPageSetupData *data ) +{ + // should we setup the page rect here ? + // since MacOS sometimes has two same paper rects with different + // page rects we could make it roundtrip safe perhaps +#if TARGET_CARBON +#else +#endif +} + +void wxMacCarbonPrintData::TransferTo( wxPageSetupData* data ) +{ + PMRect rPaper; + OSStatus err = PMGetUnadjustedPaperRect(m_macPageFormat, &rPaper); + if ( err == noErr ) + { + PMRect rPage ; + err = PMGetUnadjustedPageRect(m_macPageFormat , &rPage ) ; + if ( err == noErr ) + { + data->SetMinMarginTopLeft( wxPoint ( + (int)(((double) rPage.left - rPaper.left ) * pt2mm) , + (int)(((double) rPage.top - rPaper.top ) * pt2mm) ) ) ; + + data->SetMinMarginBottomRight( wxPoint ( + (wxCoord)(((double) rPaper.right - rPage.right ) * pt2mm), + (wxCoord)(((double) rPaper.bottom - rPage.bottom ) * pt2mm)) ) ; + } + } +} + +void wxMacCarbonPrintData::TransferTo( wxPrintDialogData* data ) +{ + UInt32 minPage , maxPage ; + PMGetPageRange( m_macPrintSettings , &minPage , &maxPage ) ; + data->SetMinPage( minPage ) ; + data->SetMaxPage( maxPage ) ; + UInt32 copies ; + PMGetCopies( m_macPrintSettings , &copies ) ; + data->SetNoCopies( copies ) ; + UInt32 from , to ; + PMGetFirstPage( m_macPrintSettings , &from ) ; + PMGetLastPage( m_macPrintSettings , &to ) ; + data->SetFromPage( from ) ; + data->SetToPage( to ) ; +} + +void wxMacCarbonPrintData::TransferFrom( wxPrintDialogData* data ) +{ + PMSetPageRange( m_macPrintSettings , data->GetMinPage() , data->GetMaxPage() ) ; + PMSetCopies( m_macPrintSettings , data->GetNoCopies() , false ) ; + PMSetFirstPage( m_macPrintSettings , data->GetFromPage() , false ) ; + + int toPage = data->GetToPage(); + if (toPage < 1) + toPage = data->GetFromPage(); + PMSetLastPage( m_macPrintSettings , toPage , false ) ; +} + +void wxMacCarbonPrintData::CopyFrom( wxNativePrintData* d ) +{ + wxMacCarbonPrintData *data = (wxMacCarbonPrintData*) d ; + if ( data->m_macPrintSession != kPMNoReference ) + PMRetain( data->m_macPrintSession ) ; + if ( m_macPrintSession != kPMNoReference ) + { + PMRelease( m_macPrintSession ) ; + m_macPrintSession = kPMNoReference ; + } + if ( data->m_macPrintSession != kPMNoReference ) + m_macPrintSession = data->m_macPrintSession ; + + if ( data->m_macPrintSettings != kPMNoPrintSettings ) + PMRetain( data->m_macPrintSettings ) ; + if ( m_macPrintSettings != kPMNoPrintSettings ) + { + PMRelease( m_macPrintSettings ) ; + m_macPrintSettings = kPMNoPrintSettings ; + } + if ( data->m_macPrintSettings != kPMNoPrintSettings ) + m_macPrintSettings = data->m_macPrintSettings ; + + if ( data->m_macPageFormat != kPMNoPageFormat ) + PMRetain( data->m_macPageFormat ) ; + if ( m_macPageFormat != kPMNoPageFormat ) + { + PMRelease( m_macPageFormat ) ; + m_macPageFormat = kPMNoPageFormat ; + } + if ( data->m_macPageFormat != kPMNoPageFormat ) + m_macPageFormat = data->m_macPageFormat ; +} + +int wxMacCarbonPrintData::ShowPrintDialog() +{ + int result = wxID_CANCEL ; + OSErr err = noErr ; + wxString message ; + + Boolean accepted; + + { + // Display the Print dialog. + if (err == noErr) + { + err = PMSessionPrintDialog( m_macPrintSession, + m_macPrintSettings, + m_macPageFormat, + &accepted); + if ((err == noErr) && !accepted) + { + err = kPMCancel; // user clicked Cancel button + } + } + if ( err == noErr ) + { + result = wxID_OK ; + } + } + if ((err != noErr) && (err != kPMCancel)) + { + message.Printf( wxT("Print Error %d"), err ) ; + wxMessageDialog dialog( NULL , message , wxEmptyString, wxICON_HAND | wxOK) ; + dialog.ShowModal(); + } + + return result ; +} + +int wxMacCarbonPrintData::ShowPageSetupDialog() +{ + int result = wxID_CANCEL ; + OSErr err = noErr ; + wxString message ; + + Boolean accepted; + { + // Display the Page Setup dialog. + if (err == noErr) + { + err = PMSessionPageSetupDialog( m_macPrintSession, + m_macPageFormat, + &accepted); + if ((err == noErr) && !accepted) + { + err = kPMCancel; // user clicked Cancel button + } + } + + // If the user did not cancel, flatten and save the PageFormat object + // with our document. + if (err == noErr) { + result = wxID_OK ; + } + } + if ((err != noErr) && (err != kPMCancel)) + { + message.Printf( wxT("Print Error %d"), err ) ; + wxMessageDialog dialog( NULL , message , wxEmptyString, wxICON_HAND | wxOK) ; + dialog.ShowModal(); + } + + return result ; +} + +#else + +wxNativePrintData* wxNativePrintData::Create() +{ + return new wxMacClassicPrintData() ; +} + +wxMacClassicPrintData::wxMacClassicPrintData() +{ + m_macPrintSettings = NULL ; + ValidateOrCreate() ; +} + +wxMacClassicPrintData::~wxMacClassicPrintData() +{ + wxASSERT( m_macPrintSettings ); + DisposeHandle( (Handle) m_macPrintSettings ) ; +} + +void wxMacClassicPrintData::ValidateOrCreate() +{ + if ( m_macPrintSettings == NULL ) + { + m_macPrintSettings = (THPrint) NewHandleClear( sizeof( TPrint ) ); + (**m_macPrintSettings).iPrVersion = 0; // something invalid + + (**m_macPrintSettings).prInfo.iHRes = 72; + (**m_macPrintSettings).prInfo.iVRes = 72; + Rect r1 = { 0, 0, 8*72 - 2 * 18, 11*72 - 2 * 36 }; + (**m_macPrintSettings).prInfo.rPage = r1;// must have its top left & (0,0) + + Rect r2 = { -18, -36, 8*72 - 18, 11*72 - 36 }; + (**m_macPrintSettings).rPaper = r2; + (**m_macPrintSettings).prStl.iPageV = 11 * 120 ; // 11 inches in 120th of an inch + (**m_macPrintSettings).prStl.iPageH = 8 * 120 ; // 8 inches in 120th of an inch + } + else + { + } +} + +void wxMacClassicPrintData::TransferFrom( wxPrintData* data ) +{ + ValidateOrCreate() ; + (**m_macPrintSettings).prJob.iCopies = data->GetNoCopies() ; + // on mac the paper rect has a negative top left corner, because the page rect (printable area) is at 0,0 + // if all printing data is consolidated in on structure we will be able to set additional infos about pages +} + +void wxMacClassicPrintData::TransferTo( wxPrintData* data ) +{ + data->SetNoCopies( (**m_macPrintSettings).prJob.iCopies ); + data->SetPaperSize( wxSize( + ((double) (**m_macPrintSettings).rPaper.right - (**m_macPrintSettings).rPaper.left ) * pt2mm , + ((double) (**m_macPrintSettings).rPaper.bottom - (**m_macPrintSettings).rPaper.top ) * pt2mm ) ) ; +} + +void wxMacClassicPrintData::TransferFrom( wxPageSetupData *data ) +{ +} + +void wxMacClassicPrintData::TransferTo( wxPageSetupData* data ) +{ + data->SetMinMarginTopLeft( wxPoint( + ((double) (**m_macPrintSettings).prInfo.rPage.left -(**m_macPrintSettings).rPaper.left ) * pt2mm , + ((double) (**m_macPrintSettings).prInfo.rPage.top -(**m_macPrintSettings).rPaper.top ) * pt2mm ) ) ; + data->SetMinMarginBottomRight( wxPoint( + ((double) (**m_macPrintSettings).rPaper.right - (**m_macPrintSettings).prInfo.rPage.right ) * pt2mm , + ((double)(**m_macPrintSettings).rPaper.bottom - (**m_macPrintSettings).prInfo.rPage.bottom ) * pt2mm ) ) ; +} + +void wxMacClassicPrintData::TransferFrom( wxPrintDialogData* data ) +{ + int toPage = data->GetToPage(); + if (toPage < 1) + toPage = data->GetFromPage(); + (**m_macPrintSettings).prJob.iFstPage = data->GetFromPage() ; + (**m_macPrintSettings).prJob.iLstPage = toPage; +} + +void wxMacClassicPrintData::TransferTo( wxPrintDialogData* data ) +{ + data->SetFromPage( (**m_macPrintSettings).prJob.iFstPage ) ; + data->SetToPage( (**m_macPrintSettings).prJob.iLstPage ) ; +} + +void wxMacClassicPrintData::CopyFrom( wxNativePrintData* data ) +{ + DisposeHandle( (Handle) m_macPrintSettings ) ; + m_macPrintSettings = ((wxMacClassicPrintData*)data)->m_macPrintSettings; + HandToHand( (Handle*) &m_macPrintSettings ); +} + +int wxMacClassicPrintData::ShowPrintDialog() +{ + int result = wxID_CANCEL ; + OSErr err = noErr ; + wxString message ; + + err = ::UMAPrOpen() ; + if ( err == noErr ) + { + if ( ::PrJobDialog( m_macPrintSettings ) ) + { + result = wxID_OK ; + } + + } + else + { + message.Printf( wxT("Print Error %d"), err ) ; + wxMessageDialog dialog( NULL , message , wxT(""), wxICON_HAND | wxOK) ; + dialog.ShowModal(); + } + ::UMAPrClose() ; + + return result ; +} + +int wxMacClassicPrintData::ShowPageSetupDialog() +{ + int result = wxID_CANCEL ; + OSErr err = noErr ; + wxString message ; + + err = ::UMAPrOpen() ; + if ( err == noErr ) + { + if ( ::PrStlDialog( m_macPrintSettings ) ) + { + result = wxID_OK ; + } + + } + else + { + message.Printf( wxT("Print Error %d"), err ) ; + wxMessageDialog dialog( NULL , message , wxEmptyString , wxICON_HAND | wxOK) ; + dialog.ShowModal(); + } + ::UMAPrClose() ; + return result ; +} + +#endif + +/* +* Printer +*/ + +wxMacPrinter::wxMacPrinter(wxPrintDialogData *data): +wxPrinterBase(data) +{ +} + +wxMacPrinter::~wxMacPrinter(void) +{ +} + +bool wxMacPrinter::Print(wxWindow *parent, wxPrintout *printout, bool prompt) +{ + sm_abortIt = FALSE; + sm_abortWindow = NULL; + + if (!printout) + return FALSE; + + printout->SetIsPreview(FALSE); + if (m_printDialogData.GetMinPage() < 1) + m_printDialogData.SetMinPage(1); + if (m_printDialogData.GetMaxPage() < 1) + m_printDialogData.SetMaxPage(9999); + + // Create a suitable device context + wxDC *dc = NULL; + if (prompt) + { + wxPrintDialog dialog(parent, & m_printDialogData); + if (dialog.ShowModal() == wxID_OK) + { + dc = dialog.GetPrintDC(); + m_printDialogData = dialog.GetPrintDialogData(); + } + } + else + { + dc = new wxPrinterDC( m_printDialogData.GetPrintData() ) ; + } + + + // May have pressed cancel. + if (!dc || !dc->Ok()) + { + if (dc) delete dc; + return FALSE; + } + + // on the mac we have always pixels as addressing mode with 72 dpi + + printout->SetPPIScreen(72, 72); + printout->SetPPIPrinter(72, 72); + + // Set printout parameters + printout->SetDC(dc); + + int w, h; + wxCoord ww, hh; + dc->GetSize(&w, &h); + printout->SetPageSizePixels((int)w, (int)h); + dc->GetSizeMM(&ww, &hh); + printout->SetPageSizeMM((int)ww, (int)hh); + + // Create an abort window + wxBeginBusyCursor(); + + printout->OnPreparePrinting(); + + // Get some parameters from the printout, if defined + int fromPage, toPage; + int minPage, maxPage; + printout->GetPageInfo(&minPage, &maxPage, &fromPage, &toPage); + + if (maxPage == 0) + { + wxEndBusyCursor(); + return FALSE; + } + + // Only set min and max, because from and to have been + // set by the user + m_printDialogData.SetMinPage(minPage); + m_printDialogData.SetMaxPage(maxPage); + + wxWindow *win = CreateAbortWindow(parent, printout); + wxSafeYield(win,true); + + if (!win) + { + wxEndBusyCursor(); + wxMessageBox(wxT("Sorry, could not create an abort dialog."), wxT("Print Error"), wxOK, parent); + delete dc; + return FALSE; + } + sm_abortWindow = win; + sm_abortWindow->Show(TRUE); + wxSafeYield(win,true); + + printout->OnBeginPrinting(); + + bool keepGoing = TRUE; + + int copyCount; + for (copyCount = 1; copyCount <= m_printDialogData.GetNoCopies(); copyCount ++) + { + if (!printout->OnBeginDocument(m_printDialogData.GetFromPage(), m_printDialogData.GetToPage())) + { + wxEndBusyCursor(); + wxMessageBox(wxT("Could not start printing."), wxT("Print Error"), wxOK, parent); + break; + } + if (sm_abortIt) + break; + + int pn; + for (pn = m_printDialogData.GetFromPage(); keepGoing && (pn <= m_printDialogData.GetToPage()) && printout->HasPage(pn); + pn++) + { + if (sm_abortIt) + { + keepGoing = FALSE; + break; + } + else + { +#if TARGET_CARBON + if ( UMAGetSystemVersion() >= 0x1000 ) +#endif + { + GrafPtr thePort ; + GetPort( &thePort ) ; + wxSafeYield(win,true); + SetPort( thePort ) ; + } + dc->StartPage(); + keepGoing = printout->OnPrintPage(pn); + dc->EndPage(); + } + } + printout->OnEndDocument(); + } + + printout->OnEndPrinting(); + + if (sm_abortWindow) + { + sm_abortWindow->Show(FALSE); + delete sm_abortWindow; + sm_abortWindow = NULL; + } + + wxEndBusyCursor(); + + delete dc; + + return TRUE; +} + +wxDC* wxMacPrinter::PrintDialog(wxWindow *parent) +{ + wxDC* dc = (wxDC*) NULL; + + wxPrintDialog dialog(parent, & m_printDialogData); + int ret = dialog.ShowModal(); + + if (ret == wxID_OK) + { + dc = dialog.GetPrintDC(); + m_printDialogData = dialog.GetPrintDialogData(); + } + + return dc; +} + +bool wxMacPrinter::Setup(wxWindow *parent) +{ + wxPrintDialog dialog(parent, & m_printDialogData); + dialog.GetPrintDialogData().SetSetupDialog(TRUE); + + int ret = dialog.ShowModal(); + + if (ret == wxID_OK) + { + m_printDialogData = dialog.GetPrintDialogData(); + } + + return (ret == wxID_OK); +} + +/* +* Print preview +*/ + +wxMacPrintPreview::wxMacPrintPreview(wxPrintout *printout, + wxPrintout *printoutForPrinting, + wxPrintDialogData *data) + : wxPrintPreviewBase(printout, printoutForPrinting, data) +{ + DetermineScaling(); +} + +wxMacPrintPreview::wxMacPrintPreview(wxPrintout *printout, wxPrintout *printoutForPrinting, wxPrintData *data): +wxPrintPreviewBase(printout, printoutForPrinting, data) +{ + DetermineScaling(); +} + +wxMacPrintPreview::~wxMacPrintPreview(void) +{ +} + +bool wxMacPrintPreview::Print(bool interactive) +{ + if (!m_printPrintout) + return FALSE; + wxMacPrinter printer(&m_printDialogData); + return printer.Print(m_previewFrame, m_printPrintout, interactive); +} + +void wxMacPrintPreview::DetermineScaling(void) +{ + int screenWidth , screenHeight ; + wxDisplaySize( &screenWidth , &screenHeight ) ; + + m_previewPrintout->SetPPIScreen( 72 , 72 ) ; + m_previewPrintout->SetPPIPrinter( 72 , 72 ) ; + m_previewPrintout->SetPageSizeMM( (int) (8.0 * 25.6), (int) (11.0 * 25.6) ); + m_previewPrintout->SetPageSizePixels( 8 * 72 , 11 * 72 ) ; + m_pageWidth = 8 * 72 ; + m_pageHeight = 11 * 72 ; + m_previewScale = 1 ; + + // Get a device context for the currently selected printer + wxPrinterDC printerDC(m_printDialogData.GetPrintData()); + if (printerDC.Ok()) + { + int x , y ; + wxCoord ww, hh; + printerDC.GetSizeMM(&ww, &hh); + printerDC.GetSize( &x , &y ) ; + m_previewPrintout->SetPageSizeMM((int)ww, (int)hh); + m_previewPrintout->SetPageSizePixels( x , y) ; + m_pageWidth = x ; + m_pageHeight = y ; + m_isOk = true ; + } + else + { + m_isOk = false ; + } + // At 100%, the page should look about page-size on the screen. + // m_previewScale = (float)((float)screenWidth/(float)printerWidth); + // m_previewScale = m_previewScale * (float)((float)screenXRes/(float)printerXRes); + + m_previewScale = 1 ; +} diff --git a/src/mac/classic/radiobox.cpp b/src/mac/classic/radiobox.cpp new file mode 100644 index 0000000000..103d68ca44 --- /dev/null +++ b/src/mac/classic/radiobox.cpp @@ -0,0 +1,580 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: radiobox.cpp +// Purpose: wxRadioBox +// Author: Stefan Csomor +// Modified by: JS Lair (99/11/15) first implementation +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "radioboxbase.h" +#pragma implementation "radiobox.h" +#endif + +//------------------------------------------------------------------------------------- +// headers +//------------------------------------------------------------------------------------- + +#include "wx/defs.h" +#include "wx/arrstr.h" + +#include "wx/radiobox.h" +#include "wx/radiobut.h" +#include "wx/mac/uma.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxRadioBox, wxControl) +#endif + +//------------------------------------------------------------------------------------- +// Â¥ wxRadioBox() +//------------------------------------------------------------------------------------- +// Default constructor +BEGIN_EVENT_TABLE(wxRadioBox, wxControl) +EVT_RADIOBUTTON( -1 , wxRadioBox::OnRadioButton ) +END_EVENT_TABLE() + +void wxRadioBox::OnRadioButton( wxCommandEvent &outer ) +{ + if ( outer.IsChecked() ) + { + wxCommandEvent event(wxEVT_COMMAND_RADIOBOX_SELECTED, m_windowId); + int i = GetSelection() ; + event.SetInt( i ); + event.SetString( GetString( i ) ); + event.SetEventObject( this ); + ProcessCommand(event); + } +} + +wxRadioBox::wxRadioBox() +{ + m_noItems = 0; + m_noRowsOrCols = 0; + m_majorDim = 0 ; + m_radioButtonCycle = NULL; +} + +//------------------------------------------------------------------------------------- +// Â¥ wxRadioBox(wxWindow*, wxWindowID, const wxString&, const wxPoint&, +// const wxSize&, int, const wxString[], int, long, +// const wxValidator&, const wxString&) +//------------------------------------------------------------------------------------- +// Contructor, creating and showing a radiobox +// +// inline defined +// + +//------------------------------------------------------------------------------------- +// Â¥ ~wxRadioBox +//------------------------------------------------------------------------------------- +// Destructor, destroying the radiobox item + +wxRadioBox::~wxRadioBox() +{ + m_isBeingDeleted = TRUE; + + wxRadioButton *next,*current; + + current=m_radioButtonCycle->NextInCycle(); + next=current->NextInCycle(); + while (current!=m_radioButtonCycle) { + delete current; + current=next; + next=current->NextInCycle(); + } + delete current; +} + +//------------------------------------------------------------------------------------- +// Â¥ Create +//------------------------------------------------------------------------------------- +// Create the radiobox for two-step construction + +bool wxRadioBox::Create(wxWindow *parent, wxWindowID id, const wxString& label, + const wxPoint& pos, const wxSize& size, + const wxArrayString& choices, + int majorDim, long style, + const wxValidator& val, const wxString& name) +{ + wxCArrayString chs(choices); + + return Create(parent, id, label, pos, size, chs.GetCount(), + chs.GetStrings(), majorDim, style, val, name); +} + +bool wxRadioBox::Create(wxWindow *parent, wxWindowID id, const wxString& label, + const wxPoint& pos, const wxSize& size, + int n, const wxString choices[], + int majorDim, long style, + const wxValidator& val, const wxString& name) +{ + if ( !wxControl::Create(parent, id, pos, size, style, val, name) ) + return false; + + int i; + + m_noItems = n; + m_noRowsOrCols = majorDim; + m_radioButtonCycle = NULL; + + if (majorDim==0) + m_majorDim = n ; + else + m_majorDim = majorDim ; + + + Rect bounds ; + Str255 title ; + + MacPreControlCreate( parent , id , wxStripMenuCodes(label) , pos , size ,style, val , name , &bounds , title ) ; + + m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()) , &bounds , title , false , 0 , 0 , 1, + kControlGroupBoxTextTitleProc , (long) this ) ; + + for (i = 0; i < n; i++) + { + wxRadioButton *radBtn = new wxRadioButton + ( + this, + wxID_ANY, + wxStripMenuCodes(choices[i]), + wxPoint(5,20*i+10), + wxDefaultSize, + i == 0 ? wxRB_GROUP : 0 + ); + if ( i == 0 ) + m_radioButtonCycle = radBtn ; + // m_radioButtonCycle=radBtn->AddInCycle(m_radioButtonCycle); + } + + SetSelection(0); + MacPostControlCreate() ; + + return TRUE; +} + + +//------------------------------------------------------------------------------------- +// Â¥ Enable(bool) +//------------------------------------------------------------------------------------- +// Enables or disables the entire radiobox + +bool wxRadioBox::Enable(bool enable) +{ + int i; + wxRadioButton *current; + + if (!wxControl::Enable(enable)) + return false; + + current = m_radioButtonCycle; + for (i = 0; i < m_noItems; i++) { + current->Enable(enable); + current = current->NextInCycle(); + } + return true; +} + +//------------------------------------------------------------------------------------- +// Â¥ Enable(int, bool) +//------------------------------------------------------------------------------------- +// Enables or disables an given button + +void wxRadioBox::Enable(int item, bool enable) +{ + int i; + wxRadioButton *current; + + if ((item < 0) || (item >= m_noItems)) + return; + + i = 0; + current = m_radioButtonCycle; + while (i != item) { + i++; + current = current->NextInCycle(); + } + current->Enable(enable); +} + +//------------------------------------------------------------------------------------- +// Â¥ GetLabel() +//------------------------------------------------------------------------------------- +// Returns the radiobox label + +wxString wxRadioBox::GetLabel() const +{ + return wxControl::GetLabel(); +} + +//------------------------------------------------------------------------------------- +// Â¥ GetLabel(int) +//------------------------------------------------------------------------------------- +// Returns the label for the given button + +wxString wxRadioBox::GetString(int item) const +{ + int i; + wxRadioButton *current; + + if ((item < 0) || (item >= m_noItems)) + return wxEmptyString; + + i = 0; + current = m_radioButtonCycle; + while (i != item) { + i++; + current = current->NextInCycle(); + } + return current->GetLabel(); +} + +//------------------------------------------------------------------------------------- +// Â¥ GetSelection +//------------------------------------------------------------------------------------- +// Returns the zero-based position of the selected button + +int wxRadioBox::GetSelection() const +{ + int i; + wxRadioButton *current; + + i=0; + current=m_radioButtonCycle; + while (!current->GetValue()) { + i++; + current=current->NextInCycle(); + } + + return i; +} + +//------------------------------------------------------------------------------------- +// Â¥ Number +//------------------------------------------------------------------------------------- +// Returns the number of buttons in the radiobox +// +// inline defined +// + +//------------------------------------------------------------------------------------- +// Â¥ SetLabel(const wxString&) +//------------------------------------------------------------------------------------- +// Sets the radiobox label + +void wxRadioBox::SetLabel(const wxString& label) +{ + return wxControl::SetLabel(label); +} + +//------------------------------------------------------------------------------------- +// Â¥ SetLabel(int, const wxString&) +//------------------------------------------------------------------------------------- +// Sets the label of a given button + +void wxRadioBox::SetString(int item,const wxString& label) +{ + int i; + wxRadioButton *current; + + if ((item < 0) || (item >= m_noItems)) + return; + i=0; + current=m_radioButtonCycle; + while (i!=item) { + i++; + current=current->NextInCycle(); + } + return current->SetLabel(label); +} + +//------------------------------------------------------------------------------------- +// Â¥ SetSelection +//------------------------------------------------------------------------------------- +// Sets a button by passing the desired position. This does not cause +// wxEVT_COMMAND_RADIOBOX_SELECTED event to get emitted + +void wxRadioBox::SetSelection(int item) +{ + int i; + wxRadioButton *current; + + if ((item < 0) || (item >= m_noItems)) + return; + i=0; + current=m_radioButtonCycle; + while (i!=item) { + i++; + current=current->NextInCycle(); + } + current->SetValue(true); + +} + +//------------------------------------------------------------------------------------- +// Â¥ Show(bool) +//------------------------------------------------------------------------------------- +// Shows or hides the entire radiobox + +bool wxRadioBox::Show(bool show) +{ + int i; + wxRadioButton *current; + + wxControl::Show(show); + + current=m_radioButtonCycle; + for (i=0;iShow(show); + current=current->NextInCycle(); + } + return true; +} + +//------------------------------------------------------------------------------------- +// Â¥ Show(int, bool) +//------------------------------------------------------------------------------------- +// Shows or hides the given button + +void wxRadioBox::Show(int item, bool show) +{ + int i; + wxRadioButton *current; + + if ((item < 0) || (item >= m_noItems)) + return; + i=0; + current=m_radioButtonCycle; + while (i!=item) { + i++; + current=current->NextInCycle(); + } + current->Show(show); +} + +//------------------------------------------------------------------------------------- +// Â¥ Command +//------------------------------------------------------------------------------------- +// Simulates the effect of the user issuing a command to the item + +void wxRadioBox::Command (wxCommandEvent & event) +{ + SetSelection (event.GetInt()); + ProcessCommand (event); +} + +//------------------------------------------------------------------------------------- +// Â¥ SetFocus +//------------------------------------------------------------------------------------- +// Sets the selected button to receive keyboard input + +void wxRadioBox::SetFocus() +{ + int i; + wxRadioButton *current; + + i=0; + current=m_radioButtonCycle; + while (!current->GetValue()) { + i++; + current=current->NextInCycle(); + } + current->SetFocus(); +} + + +//------------------------------------------------------------------------------------- +// Â¥ DoSetSize +//------------------------------------------------------------------------------------- +// Simulates the effect of the user issuing a command to the item + +#define RADIO_SIZE 20 + +void wxRadioBox::DoSetSize(int x, int y, int width, int height, int sizeFlags) +{ + int i; + wxRadioButton *current; + + // define the position + + int x_current, y_current; + int x_offset,y_offset; + int widthOld, heightOld; + GetSize(&widthOld, &heightOld); + + x_offset = x; + y_offset = y; + GetPosition(&x_current, &y_current); + if ((x == -1) && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE)) + x_offset = x_current; + if ((y == -1)&& !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE)) + y_offset = y_current; + + // define size + + int charWidth,charHeight; + int maxWidth,maxHeight; + int eachWidth[128],eachHeight[128]; + int totWidth,totHeight; + + SetFont(GetParent()->GetFont()); + GetTextExtent(wxT("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), &charWidth, &charHeight); + charWidth/=52; + + maxWidth=-1; + maxHeight=-1; + for (i = 0 ; i < m_noItems; i++) + { + GetTextExtent(GetString(i), &eachWidth[i], &eachHeight[i]); + eachWidth[i] = (int)(eachWidth[i] + RADIO_SIZE); + eachHeight[i] = (int)((3*eachHeight[i])/2); + if (maxWidth= 0x1030 ) + { + //need to add a few more pixels for the top border on panther + y_start = y_start + 5; //how many exactly should this be to meet the HIG? + } + x_offset = x_start; + y_offset = y_start; + + current=m_radioButtonCycle; + for ( i = 0 ; i < m_noItems; i++) + { + if (i&&((i%m_majorDim)==0)) // not to do for the zero button! + { + if (m_windowStyle & wxRA_VERTICAL) + { + x_offset += maxWidth + charWidth; + y_offset = y_start; + } + else + { + x_offset = x_start; + y_offset += maxHeight ; /*+ charHeight/2;*/ + } + } + + current->SetSize(x_offset,y_offset,eachWidth[i],eachHeight[i]); + current=current->NextInCycle(); + + if (m_windowStyle & wxRA_SPECIFY_ROWS) + y_offset += maxHeight ; /*+ charHeight/2;*/ + else + x_offset += maxWidth + charWidth; + } +} + +wxSize wxRadioBox::DoGetBestSize() const +{ + int charWidth, charHeight; + int maxWidth, maxHeight; + int eachWidth, eachHeight; + int totWidth, totHeight; + + wxFont font = GetParent()->GetFont(); + GetTextExtent(wxT("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), + &charWidth, &charHeight, NULL, NULL, &font); + charWidth /= 52; + + maxWidth = -1; + maxHeight = -1; + + for (int i = 0 ; i < m_noItems; i++) + { + GetTextExtent(GetString(i), &eachWidth, &eachHeight); + eachWidth = (int)(eachWidth + RADIO_SIZE) ; + eachHeight = (int)((3 * eachHeight) / 2); + if (maxWidth < eachWidth) maxWidth = eachWidth; + if (maxHeight < eachHeight) maxHeight = eachHeight; + } + + totHeight = GetRowCount() * (maxHeight + charHeight/2) + charHeight ; + totWidth = GetColumnCount() * (maxWidth + charWidth) + charWidth; + + if ( UMAGetSystemVersion() >= 0x1030 ) + { + //need to add a few more pixels for the static boxborder on panther + totHeight = totHeight + 10; //how many exactly should this be to meet the HIG? + } + // handle radio box title as well + GetTextExtent(GetTitle(), &eachWidth, NULL); + eachWidth = (int)(eachWidth + RADIO_SIZE) + 3 * charWidth ; + if (totWidth < eachWidth) + totWidth = eachWidth; + + return wxSize(totWidth, totHeight); +} +//------------------------------------------------------------------------------------- +// Â¥ GetNumVer +//------------------------------------------------------------------------------------- +// return the number of buttons in the vertical direction + +int wxRadioBox::GetRowCount() const +{ + if ( m_windowStyle & wxRA_SPECIFY_ROWS ) + { + return m_majorDim; + } + else + { + return (m_noItems + m_majorDim - 1)/m_majorDim; + } +} + +//------------------------------------------------------------------------------------- +// Â¥ GetNumHor +//------------------------------------------------------------------------------------- +// return the number of buttons in the horizontal direction + +int wxRadioBox::GetColumnCount() const +{ + if ( m_windowStyle & wxRA_SPECIFY_ROWS ) + { + return (m_noItems + m_majorDim - 1)/m_majorDim; + } + else + { + return m_majorDim; + } +} + + + + + diff --git a/src/mac/classic/radiobut.cpp b/src/mac/classic/radiobut.cpp new file mode 100644 index 0000000000..991c8be68f --- /dev/null +++ b/src/mac/classic/radiobut.cpp @@ -0,0 +1,150 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: radiobut.cpp +// Purpose: wxRadioButton +// Author: AUTHOR +// Modified by: JS Lair (99/11/15) adding the cyclic groupe notion for radiobox +// Created: ??/??/98 +// RCS-ID: $Id$ +// Copyright: (c) AUTHOR +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "radiobut.h" +#endif + +#include "wx/defs.h" + +#include "wx/radiobut.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxRadioButton, wxControl) +#endif + +#include "wx/mac/uma.h" + +bool wxRadioButton::Create(wxWindow *parent, wxWindowID id, + const wxString& label, + const wxPoint& pos, + const wxSize& size, long style, + const wxValidator& validator, + const wxString& name) +{ + if ( !wxControl::Create(parent, id, pos, size, style, validator, name) ) + return false; + + Rect bounds ; + Str255 title ; + + MacPreControlCreate( parent , id , label , pos , size ,style, validator , name , &bounds , title ) ; + + m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()) , &bounds , title , false , 0 , 0 , 1, + kControlRadioButtonProc , (long) this ) ; + + MacPostControlCreate() ; + + m_cycle = this ; + + if (HasFlag(wxRB_GROUP)) + { + AddInCycle( NULL ) ; + } + else + { + /* search backward for last group start */ + wxRadioButton *chief = (wxRadioButton*) NULL; + wxWindowList::Node *node = parent->GetChildren().GetLast(); + while (node) + { + wxWindow *child = node->GetData(); + if (child->IsKindOf( CLASSINFO( wxRadioButton ) ) ) + { + chief = (wxRadioButton*) child; + if (child->HasFlag(wxRB_GROUP)) break; + } + node = node->GetPrevious(); + } + AddInCycle( chief ) ; + } + return TRUE; +} + +void wxRadioButton::SetValue(bool val) +{ + wxRadioButton *cycle; + if ( GetControl32BitValue( (ControlHandle) m_macControl ) == val ) + return ; + + ::SetControl32BitValue( (ControlHandle) m_macControl , val ) ; + if (val) + { + cycle=this->NextInCycle(); + if (cycle!=NULL) { + while (cycle!=this) { + cycle->SetValue(false); + cycle=cycle->NextInCycle(); + } + } + } + MacRedrawControl() ; +} + +bool wxRadioButton::GetValue() const +{ + return ::GetControl32BitValue( (ControlHandle) m_macControl ) ; +} + +void wxRadioButton::Command (wxCommandEvent & event) +{ + SetValue ( (event.GetInt() != 0) ); + ProcessCommand (event); +} + +void wxRadioButton::MacHandleControlClick( WXWidget control , wxInt16 controlpart , bool WXUNUSED(mouseStillDown)) +{ + if ( GetValue() ) + return ; + + wxRadioButton *cycle, *old = NULL ; + cycle=this->NextInCycle(); + if (cycle!=NULL) { + while (cycle!=this) { + if ( cycle->GetValue() ) { + old = cycle ; + cycle->SetValue(false); + } + cycle=cycle->NextInCycle(); + } + } + + SetValue(true) ; + + if ( old ) { + wxCommandEvent event(wxEVT_COMMAND_RADIOBUTTON_SELECTED, old->m_windowId ); + event.SetEventObject(old); + event.SetInt( false ); + old->ProcessCommand(event); + } + wxCommandEvent event2(wxEVT_COMMAND_RADIOBUTTON_SELECTED, m_windowId ); + event2.SetEventObject(this); + event2.SetInt( true ); + ProcessCommand(event2); +} + +wxRadioButton *wxRadioButton::AddInCycle(wxRadioButton *cycle) +{ + wxRadioButton *next,*current; + + if (cycle==NULL) { + m_cycle=this; + return(this); + } + else { + current=cycle; + while ((next=current->m_cycle)!=cycle) + current=current->m_cycle; + m_cycle=cycle; + current->m_cycle=this; + return(cycle); + } +} diff --git a/src/mac/classic/region.cpp b/src/mac/classic/region.cpp new file mode 100644 index 0000000000..a3cf8cef7b --- /dev/null +++ b/src/mac/classic/region.cpp @@ -0,0 +1,437 @@ +///////////////////////////////////////////////////////////////////////////// +// File: region.cpp +// Purpose: Region class +// Author: Stefan Csomor +// Created: Fri Oct 24 10:46:34 MET 1997 +// RCS-ID: $Id$ +// Copyright: (c) 1997 Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "region.h" +#endif + +#include "wx/region.h" +#include "wx/gdicmn.h" +#include "wx/mac/uma.h" + +#if !USE_SHARED_LIBRARY + IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject) + IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject) +#endif + +//----------------------------------------------------------------------------- +// wxRegionRefData implementation +//----------------------------------------------------------------------------- + +class WXDLLEXPORT wxRegionRefData : public wxGDIRefData { +public: + wxRegionRefData() + { + m_macRgn = NewRgn() ; + } + + wxRegionRefData(const wxRegionRefData& data) + : wxGDIRefData() + { + m_macRgn = NewRgn() ; + CopyRgn( data.m_macRgn , m_macRgn ) ; + } + + ~wxRegionRefData() + { + DisposeRgn( m_macRgn ) ; + } + RgnHandle m_macRgn ; +}; + +#define M_REGION (((wxRegionRefData*)m_refData)->m_macRgn) +#define OTHER_M_REGION(a) (((wxRegionRefData*)(a.m_refData))->m_macRgn) + +//----------------------------------------------------------------------------- +// wxRegion +//----------------------------------------------------------------------------- + +/*! + * Create an empty region. + */ +wxRegion::wxRegion() +{ + m_refData = new wxRegionRefData; +} + +wxRegion::wxRegion(WXHRGN hRegion ) +{ + m_refData = new wxRegionRefData; + CopyRgn( (RgnHandle) hRegion , (RgnHandle) M_REGION ) ; +} + +wxRegion::wxRegion(long x, long y, long w, long h) +{ + m_refData = new wxRegionRefData; + SetRectRgn( (RgnHandle) M_REGION , x , y , x+w , y+h ) ; +} + +wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight) +{ + m_refData = new wxRegionRefData; + SetRectRgn( (RgnHandle) M_REGION , topLeft.x , topLeft.y , bottomRight.x , bottomRight.y ) ; +} + +wxRegion::wxRegion(const wxRect& rect) +{ + m_refData = new wxRegionRefData; + SetRectRgn( (RgnHandle) M_REGION , rect.x , rect.y , rect.x+rect.width , rect.y+rect.height ) ; +} + +/*! + * Destroy the region. + */ +wxRegion::~wxRegion() +{ + // m_refData unrefed in ~wxObject +} + +//----------------------------------------------------------------------------- +//# Modify region +//----------------------------------------------------------------------------- + +//! Clear current region +void wxRegion::Clear() +{ + UnRef(); +} + +//! Combine rectangle (x, y, w, h) with this. +bool wxRegion::Combine(long x, long y, long width, long height, wxRegionOp op) +{ + // Don't change shared data + if (!m_refData) + { + m_refData = new wxRegionRefData(); + } + else if (m_refData->GetRefCount() > 1) + { + wxRegionRefData* ref = (wxRegionRefData*)m_refData; + UnRef(); + m_refData = new wxRegionRefData(*ref); + } + RgnHandle rgn = NewRgn() ; + SetRectRgn( rgn , x , y, x+width,y + height ) ; + + switch (op) + { + case wxRGN_AND: + SectRgn( M_REGION , rgn , M_REGION ) ; + break ; + case wxRGN_OR: + UnionRgn( M_REGION , rgn , M_REGION ) ; + break ; + case wxRGN_XOR: + XorRgn( M_REGION , rgn , M_REGION ) ; + break ; + case wxRGN_DIFF: + DiffRgn( M_REGION , rgn , M_REGION ) ; + break ; + case wxRGN_COPY: + default: + CopyRgn( rgn ,M_REGION ) ; + break ; + } + + DisposeRgn( rgn ) ; + + return TRUE; +} + +//! Union /e region with this. +bool wxRegion::Combine(const wxRegion& region, wxRegionOp op) +{ + if (region.Empty()) + return FALSE; + + // Don't change shared data + if (!m_refData) { + m_refData = new wxRegionRefData(); + } + else if (m_refData->GetRefCount() > 1) + { + wxRegionRefData* ref = (wxRegionRefData*)m_refData; + UnRef(); + m_refData = new wxRegionRefData(*ref); + } + + switch (op) + { + case wxRGN_AND: + SectRgn( M_REGION , OTHER_M_REGION(region) , M_REGION ) ; + break ; + case wxRGN_OR: + UnionRgn( M_REGION , OTHER_M_REGION(region) , M_REGION ) ; + break ; + case wxRGN_XOR: + XorRgn( M_REGION , OTHER_M_REGION(region) , M_REGION ) ; + break ; + case wxRGN_DIFF: + DiffRgn( M_REGION , OTHER_M_REGION(region) , M_REGION ) ; + break ; + case wxRGN_COPY: + default: + CopyRgn( OTHER_M_REGION(region) ,M_REGION ) ; + break ; + } + + return TRUE; +} + +bool wxRegion::Combine(const wxRect& rect, wxRegionOp op) +{ + return Combine(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight(), op); +} + +//----------------------------------------------------------------------------- +//# Information on region +//----------------------------------------------------------------------------- + +// Outer bounds of region +void wxRegion::GetBox(wxCoord& x, wxCoord& y, wxCoord& w, wxCoord& h) const +{ + if (m_refData) + { + Rect box ; + GetRegionBounds( M_REGION , &box ) ; + x = box.left ; + y = box.top ; + w = box.right - box.left ; + h = box.bottom - box.top ; + } + else + { + x = y = w = h = 0; + } +} + +wxRect wxRegion::GetBox() const +{ + wxCoord x, y, w, h; + GetBox(x, y, w, h); + return wxRect(x, y, w, h); +} + +// Is region empty? +bool wxRegion::Empty() const +{ + return EmptyRgn( M_REGION ) ; +} + +const WXHRGN wxRegion::GetWXHRGN() const +{ + return M_REGION ; +} + +//----------------------------------------------------------------------------- +//# Tests +//----------------------------------------------------------------------------- + +// Does the region contain the point (x,y)? +wxRegionContain wxRegion::Contains(long x, long y) const +{ + if (!m_refData) + return wxOutRegion; + + // TODO. Return wxInRegion if within region. + if (0) + return wxInRegion; + return wxOutRegion; +} + +// Does the region contain the point pt? +wxRegionContain wxRegion::Contains(const wxPoint& pt) const +{ + if (!m_refData) + return wxOutRegion; + + Point p = { pt.y , pt.x } ; + if (PtInRgn( p , M_REGION ) ) + return wxInRegion; + + return wxOutRegion; +} + +// Does the region contain the rectangle (x, y, w, h)? +wxRegionContain wxRegion::Contains(long x, long y, long w, long h) const +{ + if (!m_refData) + return wxOutRegion; + + Rect rect = { y , x , y + h , x + w } ; + if (RectInRgn( &rect , M_REGION ) ) + return wxInRegion; + else + return wxOutRegion; +} + +// Does the region contain the rectangle rect +wxRegionContain wxRegion::Contains(const wxRect& rect) const +{ + if (!m_refData) + return wxOutRegion; + + long x, y, w, h; + x = rect.x; + y = rect.y; + w = rect.GetWidth(); + h = rect.GetHeight(); + return Contains(x, y, w, h); +} + +/////////////////////////////////////////////////////////////////////////////// +// // +// wxRegionIterator // +// // +/////////////////////////////////////////////////////////////////////////////// + +/*! + * Initialize empty iterator + */ +wxRegionIterator::wxRegionIterator() + : m_current(0), m_numRects(0), m_rects(NULL) +{ +} + +wxRegionIterator::~wxRegionIterator() +{ + if (m_rects) { + delete[] m_rects; + m_rects = NULL; + } +} + +wxRegionIterator::wxRegionIterator(const wxRegionIterator& iterator) + : wxObject() + , m_current(iterator.m_current) + , m_numRects(0) + , m_rects(NULL) +{ + SetRects(iterator.m_numRects, iterator.m_rects); +} + +wxRegionIterator& wxRegionIterator::operator=(const wxRegionIterator& iterator) +{ + m_current = iterator.m_current; + SetRects(iterator.m_numRects, iterator.m_rects); + return *this; +} + +/*! + * Set iterator rects for region + */ +void wxRegionIterator::SetRects(long numRects, wxRect *rects) +{ + if (m_rects) { + delete[] m_rects; + m_rects = NULL; + } + if (rects) + { + int i; + m_rects = new wxRect[numRects]; + for (i = 0; i < numRects; i++) + m_rects[i] = rects[i]; + } + m_numRects = numRects; +} + +/*! + * Initialize iterator for region + */ +wxRegionIterator::wxRegionIterator(const wxRegion& region) +{ + m_rects = NULL; + + Reset(region); +} + +/*! + * Reset iterator for a new /e region. + */ +void wxRegionIterator::Reset(const wxRegion& region) +{ + m_current = 0; + m_region = region; + + if (m_rects) { + delete[] m_rects; + m_rects = NULL; + } + + if (m_region.Empty()) + m_numRects = 0; + else + { + // we cannot dissolve it into rects on mac + m_rects = new wxRect[1]; + Rect rect ; + GetRegionBounds( OTHER_M_REGION( region ) , &rect ) ; + m_rects[0].x = rect.left; + m_rects[0].y = rect.top; + m_rects[0].width = rect.right - rect.left; + m_rects[0].height = rect.bottom - rect.top; + m_numRects = 1; + } +} + +/*! + * Increment iterator. The rectangle returned is the one after the + * incrementation. + */ +wxRegionIterator& wxRegionIterator::operator ++ () +{ + if (m_current < m_numRects) + ++m_current; + return *this; +} + +/*! + * Increment iterator. The rectangle returned is the one before the + * incrementation. + */ +wxRegionIterator wxRegionIterator::operator ++ (int) +{ + wxRegionIterator previous(*this); + + if (m_current < m_numRects) + ++m_current; + + return previous; +} + +long wxRegionIterator::GetX() const +{ + if (m_current < m_numRects) + return m_rects[m_current].x; + return 0; +} + +long wxRegionIterator::GetY() const +{ + if (m_current < m_numRects) + return m_rects[m_current].y; + return 0; +} + +long wxRegionIterator::GetW() const +{ + if (m_current < m_numRects) + return m_rects[m_current].width ; + return 0; +} + +long wxRegionIterator::GetH() const +{ + if (m_current < m_numRects) + return m_rects[m_current].height; + return 0; +} + diff --git a/src/mac/classic/renderer.cpp b/src/mac/classic/renderer.cpp new file mode 100644 index 0000000000..8555ef47e3 --- /dev/null +++ b/src/mac/classic/renderer.cpp @@ -0,0 +1,283 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: mac/renderer.cpp +// Purpose: implementation of wxRendererNative for Mac +// Author: Vadim Zeitlin +// Modified by: +// Created: 20.07.2003 +// RCS-ID: $Id$ +// Copyright: (c) 2003 Vadim Zeitlin +// License: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/dc.h" + #include "wx/bitmap.h" + #include "wx/settings.h" +#endif //WX_PRECOMP + +#include "wx/renderer.h" + +// ---------------------------------------------------------------------------- +// wxRendererMac: our wxRendererNative implementation +// ---------------------------------------------------------------------------- + +class WXDLLEXPORT wxRendererMac : public wxDelegateRendererNative +{ +public: + // draw the header control button (used by wxListCtrl) + virtual void DrawHeaderButton(wxWindow *win, + wxDC& dc, + const wxRect& rect, + int flags = 0); + + // draw the expanded/collapsed icon for a tree control item + virtual void DrawTreeItemButton(wxWindow *win, + wxDC& dc, + const wxRect& rect, + int flags = 0); + + // draw a (vertical) sash + virtual void DrawSplitterSash(wxWindow *win, + wxDC& dc, + const wxSize& size, + wxCoord position, + wxOrientation orient, + int flags = 0); + +private: + // the tree buttons + wxBitmap m_bmpTreeExpanded, + m_bmpTreeCollapsed; +}; + +// ---------------------------------------------------------------------------- +// Aqua arrows +// ---------------------------------------------------------------------------- + +/* XPM */ +static const char *aqua_arrow_right_xpm[] = { +/* columns rows colors chars-per-pixel */ +"13 11 4 1", +" c None", +"b c #C0C0C0", +"c c #707070", +"d c #A0A0A0", +/* pixels */ +" b ", +" ddb ", +" cccdb ", +" cccccd ", +" ccccccdb ", +" ccccccccd", +" ccccccdb ", +" cccccb ", +" cccdb ", +" ddb ", +" b " +}; + +/* XPM */ +static const char *aqua_arrow_down_xpm[] = { +/* columns rows colors chars-per-pixel */ +"13 11 4 1", +" c None", +"b c #C0C0C0", +"c c #707070", +"d c #A0A0A0", +/* pixels */ +" ", +" ", +" bdcccccccdb ", +" dcccccccd ", +" bcccccccb ", +" dcccccd ", +" bcccccb ", +" bcccd ", +" dcd ", +" bcb ", +" d " +}; + +// ============================================================================ +// implementation +// ============================================================================ + +/* static */ +wxRendererNative& wxRendererNative::GetDefault() +{ + static wxRendererMac s_rendererMac; + + return s_rendererMac; +} + +void +wxRendererMac::DrawHeaderButton(wxWindow *win, + wxDC& dc, + const wxRect& rect, + int WXUNUSED(flags)) +{ + const int CORNER = 1; + + const wxCoord x = rect.x-1, + y = rect.y-1, + w = rect.width, + h = rect.height; + + int major,minor; + wxGetOsVersion( &major, &minor ); + + dc.SetBrush( *wxTRANSPARENT_BRUSH ); + + if (major >= 10) + { + dc.SetPen( wxPen( wxColour( 0xC5 , 0xC5 , 0xC5 ) , 1 , wxSOLID ) ); + dc.DrawRectangle( x, y+CORNER, 1, h-CORNER ); // left + // The right border is overdrawn by the left border of the right neighbouring + // header (to maintain a proper single pixel border). Except for the + // rightmost header of the listctrl. + dc.DrawRectangle( x+w+(CORNER*2), y+CORNER, 1, h-CORNER ); // right + dc.SetPen( wxPen( wxColour( 0xB1 , 0xB1 , 0xB1 ) , 1 , wxSOLID ) ); + dc.DrawRectangle( x, y+h, w+(CORNER*3), 1 ); // bottom + dc.DrawRectangle( x, y, w+(CORNER*3), 1 ); // top + + // Do a fill of the interior for background: + dc.SetPen( wxPen( wxColour( 0xF6 , 0xF6 , 0xF6 ) , 1 , wxSOLID ) ); + dc.DrawRectangle( x+CORNER, y+CORNER, w+CORNER, h-CORNER ); + + // Do the gradient fill: + static int grayValues[] = + { + 0xF6, 0xF2, 0xEF, 0xED, 0xED, 0xEB, 0xEA, 0xEA, 0xE8, + 0xE8, 0xE2, 0xE5, 0xE8, 0xEB, 0xEF, 0xF2, 0xFD + }; + int i; + for (i=0; i < h && i < (int)WXSIZEOF(grayValues); i++) + { + dc.SetPen( wxPen( wxColour( grayValues[i] , grayValues[i] , grayValues[i] ), + 1 , wxSOLID ) ); + dc.DrawRectangle( x+CORNER, y+CORNER+i, w+CORNER, 1 ); + } + } + else + { + dc.SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNSHADOW ) , 1 , wxSOLID ) ); + dc.DrawLine( x+w-CORNER+1, y, x+w, y+h ); // right (outer) + dc.DrawRectangle( x, y+h, w+1, 1 ); // bottom (outer) + + wxPen pen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID ); + + dc.SetPen( pen ); + dc.DrawLine( x+w-CORNER, y, x+w-1, y+h ); // right (inner) + dc.DrawRectangle( x+1, y+h-1, w-2, 1 ); // bottom (inner) + + dc.SetPen( *wxWHITE_PEN ); + dc.DrawRectangle( x, y, w-CORNER+1, 1 ); // top (outer) + dc.DrawRectangle( x, y, 1, h ); // left (outer) + dc.DrawLine( x, y+h-1, x+1, y+h-1 ); + dc.DrawLine( x+w-1, y, x+w-1, y+1 ); + } +} + +void +wxRendererMac::DrawTreeItemButton(wxWindow *win, + wxDC& dc, + const wxRect& rect, + int flags) +{ + // init the buttons on demand + if ( !m_bmpTreeExpanded.Ok() ) + { + m_bmpTreeExpanded = wxBitmap(aqua_arrow_down_xpm); + m_bmpTreeCollapsed = wxBitmap(aqua_arrow_right_xpm); + } + + // draw them + + // VZ: this is the old code from treectlg.cpp which apparently doesn't work + // but I kept it here just in case it is needed -- if not, please + // remove it +#if 0 // def __WXMAC__ + wxMacPortSetter helper(&dc) ; + wxMacWindowClipper clipper(this) ; + wxDC::MacSetupBackgroundForCurrentPort( MacGetBackgroundBrush() ) ; + + int loc_x = x - 5 ; + int loc_y = y_mid - 6 ; + MacWindowToRootWindow( & loc_x , & loc_y ) ; + Rect bounds = { loc_y , loc_x , loc_y + 18 , loc_x + 12 } ; + ThemeButtonDrawInfo info = { kThemeStateActive , item->IsExpanded() ? kThemeDisclosureDown : kThemeDisclosureRight , + kThemeAdornmentNone }; + DrawThemeButton( &bounds, kThemeDisclosureButton , + &info , NULL , NULL , NULL , NULL ) ; +#else // 1 + dc.DrawBitmap(flags & wxCONTROL_EXPANDED ? m_bmpTreeExpanded + : m_bmpTreeCollapsed, + rect.x, rect.y, true /* use mask */); +#endif // 0/1 +} + +void +wxRendererMac::DrawSplitterSash(wxWindow *win, + wxDC& dc, + const wxSize& size, + wxCoord position, + wxOrientation orient, + int WXUNUSED(flags)) +{ + // VZ: we have to somehow determine if we're drawing a normal sash or + // a brushed metal one as they look quite differently... this is + // completely bogus anyhow, of course (TODO) + +#if 0 + dc.SetPen(*wxLIGHT_GREY_PEN); + dc.SetBrush(*wxWHITE_BRUSH); + if ( orient == wxVERTICAL ) + dc.DrawRectangle(position, 0, 7, size.y); + else + dc.DrawRectangle(0, position, size.x, 7); +#else + // Do the gradient fill: + static int grayValues[] = + { + 0xA0, 0xF6, 0xED, 0xE4, 0xE2, 0xD0, 0xA0 + }; + dc.SetBrush( *wxTRANSPARENT_BRUSH ); + if ( orient == wxVERTICAL ) + { + int i; + for (i=0; i < (int)WXSIZEOF(grayValues); i++) + { + dc.SetPen( wxPen( wxColour( grayValues[i] , grayValues[i] , grayValues[i] ), + 1 , wxSOLID ) ); + dc.DrawRectangle( position+i, 0, 1, size.y ); + } + } + else + { + int i; + for (i=0; i < (int)WXSIZEOF(grayValues); i++) + { + dc.SetPen( wxPen( wxColour( grayValues[i] , grayValues[i] , grayValues[i] ), + 1 , wxSOLID ) ); + dc.DrawRectangle( 0, position+i, size.x, 1 ); + } + } +#endif +} + diff --git a/src/mac/classic/scrolbar.cpp b/src/mac/classic/scrolbar.cpp new file mode 100644 index 0000000000..3b08c25ecc --- /dev/null +++ b/src/mac/classic/scrolbar.cpp @@ -0,0 +1,184 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: scrolbar.cpp +// Purpose: wxScrollBar +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "scrolbar.h" +#endif + +#include "wx/defs.h" + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" +#endif // WX_PRECOMP + +#include "wx/scrolbar.h" +#include "wx/mac/uma.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxScrollBar, wxControl) + +BEGIN_EVENT_TABLE(wxScrollBar, wxControl) +END_EVENT_TABLE() + +#endif + +extern ControlActionUPP wxMacLiveScrollbarActionUPP ; + +// Scrollbar +bool wxScrollBar::Create(wxWindow *parent, wxWindowID id, + const wxPoint& pos, + const wxSize& size, long style, + const wxValidator& validator, + const wxString& name) +{ + if ( !wxControl::Create(parent, id, pos, size, style, validator, name) ) + return FALSE; + + Rect bounds ; + Str255 title ; + + MacPreControlCreate( parent , id , wxEmptyString , pos , size ,style, validator , name , &bounds , title ) ; + + m_macControl = ::NewControl(MAC_WXHWND(parent->MacGetRootWindow()) , + &bounds , title , false , 0 , 0 , 100, + kControlScrollBarLiveProc , (long) this) ; + + wxASSERT_MSG( (ControlHandle) m_macControl != NULL , wxT("No valid mac control") ) ; + + ::SetControlAction( (ControlHandle) m_macControl , wxMacLiveScrollbarActionUPP ) ; + + MacPostControlCreate() ; + + return TRUE; +} + +wxScrollBar::~wxScrollBar() +{ +} + +void wxScrollBar::SetThumbPosition(int viewStart) +{ + ::SetControl32BitValue( (ControlHandle) m_macControl , viewStart ) ; +} + +int wxScrollBar::GetThumbPosition() const +{ + return ::GetControl32BitValue( (ControlHandle) m_macControl ) ; +} + +void wxScrollBar::SetScrollbar(int position, int thumbSize, int range, int pageSize, + bool refresh) +{ + m_pageSize = pageSize; + m_viewSize = thumbSize; + m_objectSize = range; + + int range1 = wxMax((m_objectSize - m_viewSize), 0) ; + + SetControl32BitMaximum( (ControlHandle) m_macControl , range1 ) ; + SetControl32BitMinimum( (ControlHandle) m_macControl , 0 ) ; + SetControl32BitValue( (ControlHandle) m_macControl , position ) ; + + if ( UMAGetAppearanceVersion() >= 0x0110 ) + { + if ( SetControlViewSize != (void*) kUnresolvedCFragSymbolAddress ) + { + SetControlViewSize( (ControlHandle) m_macControl , m_viewSize ) ; + } + } + if ( refresh ) + MacRedrawControl() ; +} + + +void wxScrollBar::Command(wxCommandEvent& event) +{ + SetThumbPosition(event.m_commandInt); + ProcessCommand(event); +} + +void wxScrollBar::MacHandleControlClick( WXWidget control , wxInt16 controlpart , bool mouseStillDown ) +{ + if ( (ControlHandle) m_macControl == NULL ) + return ; + + int position = GetControl32BitValue( (ControlHandle) m_macControl) ; + int minPos = GetControl32BitMinimum( (ControlHandle) m_macControl) ; + int maxPos = GetControl32BitMaximum( (ControlHandle) m_macControl) ; + + wxEventType scrollEvent = wxEVT_NULL; + int nScrollInc = 0; + + // all events have already been reported during mouse down, except for THUMBRELEASE + if ( !mouseStillDown && controlpart !=kControlIndicatorPart ) + return ; + + switch( controlpart ) + { + case kControlUpButtonPart : + nScrollInc = -1; + scrollEvent = wxEVT_SCROLL_LINEUP; + break ; + case kControlDownButtonPart : + nScrollInc = 1; + scrollEvent = wxEVT_SCROLL_LINEDOWN; + break ; + case kControlPageUpPart : + nScrollInc = -m_pageSize; + scrollEvent = wxEVT_SCROLL_PAGEUP; + break ; + case kControlPageDownPart : + nScrollInc = m_pageSize; + scrollEvent = wxEVT_SCROLL_PAGEDOWN; + break ; + case kControlIndicatorPart : + nScrollInc = 0 ; + if ( mouseStillDown ) + scrollEvent = wxEVT_SCROLL_THUMBTRACK; + else + scrollEvent = wxEVT_SCROLL_THUMBRELEASE; + break ; + default : + wxFAIL_MSG(wxT("illegal scrollbar selector")); + break ; + } + + int new_pos = position + nScrollInc; + + if (new_pos < minPos) + new_pos = minPos; + if (new_pos > maxPos) + new_pos = maxPos; + if ( nScrollInc ) + SetThumbPosition(new_pos); + + wxScrollEvent event(scrollEvent, m_windowId); + if ( m_windowStyle & wxHORIZONTAL ) + { + event.SetOrientation( wxHORIZONTAL ) ; + } + else + { + event.SetOrientation( wxVERTICAL ) ; + } + event.SetPosition(new_pos); + event.SetEventObject( this ); + wxWindow* window = GetParent() ; + if (window && window->MacIsWindowScrollbar(this) ) + { + // this is hardcoded + window->MacOnScroll(event); + } + else + GetEventHandler()->ProcessEvent(event); +} + diff --git a/src/mac/classic/settings.cpp b/src/mac/classic/settings.cpp new file mode 100644 index 0000000000..4ddb2a4582 --- /dev/null +++ b/src/mac/classic/settings.cpp @@ -0,0 +1,279 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: settings.cpp +// Purpose: wxSettings +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "settings.h" +#endif + +#include "wx/settings.h" +#include "wx/gdicmn.h" +#include "wx/utils.h" + +#include "wx/mac/uma.h" + +// ---------------------------------------------------------------------------- +// wxSystemSettingsNative +// ---------------------------------------------------------------------------- + +// ---------------------------------------------------------------------------- +// colours +// ---------------------------------------------------------------------------- + +wxColour wxSystemSettingsNative::GetColour(wxSystemColour index) +{ + int major,minor; + wxGetOsVersion( &major, &minor ); + + switch( index ) + { + case wxSYS_COLOUR_SCROLLBAR : + case wxSYS_COLOUR_BACKGROUND: + case wxSYS_COLOUR_ACTIVECAPTION: + case wxSYS_COLOUR_INACTIVECAPTION: + case wxSYS_COLOUR_MENU: + case wxSYS_COLOUR_WINDOW: + case wxSYS_COLOUR_WINDOWFRAME: + case wxSYS_COLOUR_ACTIVEBORDER: + case wxSYS_COLOUR_INACTIVEBORDER: + case wxSYS_COLOUR_BTNFACE: + case wxSYS_COLOUR_MENUBAR: + return wxColor( 0xDD , 0xDD , 0xDD ) ; + break ; + + case wxSYS_COLOUR_LISTBOX : + { + if (major >= 10) + return *wxWHITE ; + else + return wxColor( 0xEE , 0xEE , 0xEE ) ; + break ; + } + case wxSYS_COLOUR_BTNSHADOW: + if (major >= 10) + return wxColor( 0xBE , 0xBE , 0xBE ) ; + else + return wxColor( 0x44 , 0x44 , 0x44 ) ; + break ; + + case wxSYS_COLOUR_BTNTEXT: + case wxSYS_COLOUR_MENUTEXT: + case wxSYS_COLOUR_WINDOWTEXT: + case wxSYS_COLOUR_CAPTIONTEXT: + case wxSYS_COLOUR_INFOTEXT: + case wxSYS_COLOUR_INACTIVECAPTIONTEXT: + return *wxBLACK; + break ; + case wxSYS_COLOUR_HIGHLIGHT: + { + RGBColor hilite ; + LMGetHiliteRGB(&hilite) ; + return wxColor( hilite.red >> 8 , hilite.green >> 8 , hilite.blue >> 8 ) ; + } + break ; + case wxSYS_COLOUR_BTNHIGHLIGHT: + case wxSYS_COLOUR_GRAYTEXT: + return wxColor( 0xCC , 0xCC , 0xCC ) ; + break ; + + case wxSYS_COLOUR_3DDKSHADOW: + return wxColor( 0x44 , 0x44 , 0x44 ) ; + break ; + case wxSYS_COLOUR_3DLIGHT: + return wxColor( 0xCC , 0xCC , 0xCC ) ; + break ; + case wxSYS_COLOUR_HIGHLIGHTTEXT : + { + RGBColor hilite ; + LMGetHiliteRGB(&hilite) ; + if ( ( hilite.red + hilite.green + hilite.blue ) == 0 ) + return *wxWHITE ; + else + return *wxBLACK ; + } + break ; + case wxSYS_COLOUR_INFOBK : + case wxSYS_COLOUR_APPWORKSPACE: + return *wxWHITE ; + break ; + + case wxSYS_COLOUR_HOTLIGHT: + case wxSYS_COLOUR_GRADIENTACTIVECAPTION: + case wxSYS_COLOUR_GRADIENTINACTIVECAPTION: + case wxSYS_COLOUR_MENUHILIGHT: + // TODO + return *wxBLACK; + + case wxSYS_COLOUR_MAX: + wxFAIL_MSG( _T("unknown system colour index") ); + break ; + } + return *wxWHITE; +} + +// ---------------------------------------------------------------------------- +// fonts +// ---------------------------------------------------------------------------- + +wxFont wxSystemSettingsNative::GetFont(wxSystemFont index) +{ + switch (index) + { + case wxSYS_ANSI_VAR_FONT : + case wxSYS_SYSTEM_FONT : + case wxSYS_DEVICE_DEFAULT_FONT : + case wxSYS_DEFAULT_GUI_FONT : + { + return *wxSMALL_FONT ; + } ; + break ; + case wxSYS_OEM_FIXED_FONT : + case wxSYS_ANSI_FIXED_FONT : + case wxSYS_SYSTEM_FIXED_FONT : + default : + { + return *wxNORMAL_FONT ; + } ; + break ; + + } + return *wxNORMAL_FONT; +} + +// ---------------------------------------------------------------------------- +// system metrics/features +// ---------------------------------------------------------------------------- + +// Get a system metric, e.g. scrollbar size +int wxSystemSettingsNative::GetMetric(wxSystemMetric index) +{ + int value; + + switch ( index) + { + case wxSYS_MOUSE_BUTTONS: + // we emulate a two button mouse (ctrl + click = right button ) + return 2; + case wxSYS_BORDER_X: + // TODO + return 0; + case wxSYS_BORDER_Y: + // TODO + return 0; + case wxSYS_CURSOR_X: + // TODO + return 0; + case wxSYS_CURSOR_Y: + // TODO + return 0; + case wxSYS_DCLICK_X: + // TODO + return 0; + case wxSYS_DCLICK_Y: + // TODO + return 0; + case wxSYS_DRAG_X: + // TODO + return 0; + case wxSYS_DRAG_Y: + // TODO + return 0; + case wxSYS_EDGE_X: + // TODO + return 0; + case wxSYS_EDGE_Y: + // TODO + return 0; + case wxSYS_HSCROLL_ARROW_X: + return 16; + case wxSYS_HSCROLL_ARROW_Y: + return 16; + case wxSYS_HTHUMB_X: + return 16; + case wxSYS_ICON_X: + // TODO + return 0; + case wxSYS_ICON_Y: + // TODO + return 0; + case wxSYS_ICONSPACING_X: + // TODO + return 0; + case wxSYS_ICONSPACING_Y: + // TODO + return 0; + case wxSYS_WINDOWMIN_X: + // TODO + return 0; + case wxSYS_WINDOWMIN_Y: + // TODO + return 0; + case wxSYS_SCREEN_X: + wxDisplaySize(&value, NULL); + return value; + case wxSYS_SCREEN_Y: + wxDisplaySize(NULL, &value); + return value; + case wxSYS_FRAMESIZE_X: + // TODO + return 0; + case wxSYS_FRAMESIZE_Y: + // TODO + return 0; + case wxSYS_SMALLICON_X: + // TODO + return 0; + case wxSYS_SMALLICON_Y: + // TODO + return 0; + case wxSYS_HSCROLL_Y: + return 16; + case wxSYS_VSCROLL_X: + return 16; + case wxSYS_VSCROLL_ARROW_X: + return 16; + case wxSYS_VSCROLL_ARROW_Y: + return 16; + case wxSYS_VTHUMB_Y: + return 16; + case wxSYS_CAPTION_Y: + // TODO + return 0; + case wxSYS_MENU_Y: + // TODO + return 0; + case wxSYS_NETWORK_PRESENT: + // TODO + return 0; + case wxSYS_PENWINDOWS_PRESENT: + return 0; + case wxSYS_SHOW_SOUNDS: + // TODO + return 0; + case wxSYS_SWAP_BUTTONS: + return 0; + default: + return 0; + } + return 0; +} + +bool wxSystemSettingsNative::HasFeature(wxSystemFeature index) +{ + switch (index) + { + case wxSYS_CAN_ICONIZE_FRAME: + case wxSYS_CAN_DRAW_FRAME_DECORATIONS: + return TRUE; + + default: + return FALSE; + } +} diff --git a/src/mac/classic/slider.cpp b/src/mac/classic/slider.cpp new file mode 100644 index 0000000000..4bd4bab532 --- /dev/null +++ b/src/mac/classic/slider.cpp @@ -0,0 +1,433 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: slider.cpp +// Purpose: wxSlider +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "slider.h" +#endif + +#include "wx/slider.h" +#include "wx/mac/uma.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxSlider, wxControl) + +BEGIN_EVENT_TABLE(wxSlider, wxControl) +END_EVENT_TABLE() +#endif + + // The dimensions of the different styles of sliders (From Aqua document) +#define wxSLIDER_DIMENSIONACROSS 15 +#define wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS 24 +#define wxSLIDER_DIMENSIONACROSS_ARROW 18 + +// Distance between slider and text +#define wxSLIDER_BORDERTEXT 5 + +/* NB! The default orientation for a slider is horizontal however if the user specifies + * some slider styles but dosen't specify the orientation we have to assume he wants a + * horizontal one. Therefore in this file when testing for the sliders orientation + * vertical is tested for if this is not set then we use the horizontal one + * eg. if(GetWindowStyle() & wxSL_VERTICAL) {} else { horizontal case }> + */ + + // Slider + wxSlider::wxSlider() +{ + m_pageSize = 1; + m_lineSize = 1; + m_rangeMax = 0; + m_rangeMin = 0; + m_tickFreq = 0; +} + +extern ControlActionUPP wxMacLiveScrollbarActionUPP ; + +bool wxSlider::Create(wxWindow *parent, wxWindowID id, + int value, int minValue, int maxValue, + const wxPoint& pos, + const wxSize& size, long style, + const wxValidator& validator, + const wxString& name) +{ + if ( !wxControl::Create(parent, id, pos, size, style, validator, name) ) + return false; + + Rect bounds ; + Str255 title ; + SInt16 procID; + + m_macMinimumStatic = NULL ; + m_macMaximumStatic = NULL ; + m_macValueStatic = NULL ; + + + m_lineSize = 1; + m_tickFreq = 0; + + m_rangeMax = maxValue; + m_rangeMin = minValue; + + m_pageSize = (int)((maxValue-minValue)/10); + + MacPreControlCreate( parent, id, wxEmptyString, pos, size, style, + validator, name, &bounds, title ); + + procID = kControlSliderProc + kControlSliderLiveFeedback; + if(style & wxSL_AUTOTICKS) { + procID += kControlSliderHasTickMarks; + } + + + m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()), &bounds, title, false, + value, minValue, maxValue, procID, (long) this); + + wxASSERT_MSG( (ControlHandle) m_macControl != NULL , wxT("No valid mac control") ) ; + + ::SetControlAction( (ControlHandle) m_macControl , wxMacLiveScrollbarActionUPP ) ; + + if(style & wxSL_LABELS) + { + m_macMinimumStatic = new wxStaticText( this, -1, wxEmptyString ); + m_macMaximumStatic = new wxStaticText( this, -1, wxEmptyString ); + m_macValueStatic = new wxStaticText( this, -1, wxEmptyString ); + SetRange(minValue, maxValue); + SetValue(value); + } + + else { + m_macMinimumStatic = NULL ; + m_macMaximumStatic = NULL ; + m_macValueStatic = NULL ; + } + + if(style & wxSL_VERTICAL) { + SetSizeHints(10, -1, 10, -1); // Forces SetSize to use the proper width + } + else { + SetSizeHints(-1, 10, -1, 10); // Forces SetSize to use the proper height + } + // NB! SetSizeHints is overloaded by wxSlider and will substitute 10 with the + // proper dimensions, it also means other people cannot bugger the slider with + // other values + + MacPostControlCreate() ; + + return true; +} + +wxSlider::~wxSlider() +{ +} + +int wxSlider::GetValue() const +{ + return GetControl32BitValue( (ControlHandle) m_macControl) ; +} + +void wxSlider::SetValue(int value) +{ + wxString valuestring ; + valuestring.Printf( wxT("%d") , value ) ; + if ( m_macValueStatic ) + m_macValueStatic->SetLabel( valuestring ) ; + SetControl32BitValue( (ControlHandle) m_macControl , value ) ; +} + +void wxSlider::SetRange(int minValue, int maxValue) +{ + wxString value; + + m_rangeMin = minValue; + m_rangeMax = maxValue; + + SetControl32BitMinimum( (ControlHandle) m_macControl, m_rangeMin); + SetControl32BitMaximum( (ControlHandle) m_macControl, m_rangeMax); + + if(m_macMinimumStatic) { + value.Printf(wxT("%d"), m_rangeMin); + m_macMinimumStatic->SetLabel(value); + } + if(m_macMaximumStatic) { + value.Printf(wxT("%d"), m_rangeMax); + m_macMaximumStatic->SetLabel(value); + } + SetValue(m_rangeMin); +} + +// For trackbars only +void wxSlider::SetTickFreq(int n, int pos) +{ + // TODO + m_tickFreq = n; +} + +void wxSlider::SetPageSize(int pageSize) +{ + // TODO + m_pageSize = pageSize; +} + +int wxSlider::GetPageSize() const +{ + return m_pageSize; +} + +void wxSlider::ClearSel() +{ + // TODO +} + +void wxSlider::ClearTicks() +{ + // TODO +} + +void wxSlider::SetLineSize(int lineSize) +{ + m_lineSize = lineSize; + // TODO +} + +int wxSlider::GetLineSize() const +{ + // TODO + return 0; +} + +int wxSlider::GetSelEnd() const +{ + // TODO + return 0; +} + +int wxSlider::GetSelStart() const +{ + // TODO + return 0; +} + +void wxSlider::SetSelection(int minPos, int maxPos) +{ + // TODO +} + +void wxSlider::SetThumbLength(int len) +{ + // TODO +} + +int wxSlider::GetThumbLength() const +{ + // TODO + return 0; +} + +void wxSlider::SetTick(int tickPos) +{ + // TODO +} + +void wxSlider::Command (wxCommandEvent & event) +{ + SetValue (event.GetInt()); + ProcessCommand (event); +} + +void wxSlider::MacHandleControlClick( WXWidget control , wxInt16 controlpart, bool mouseStillDown ) +{ + SInt16 value = ::GetControl32BitValue( (ControlHandle) m_macControl ) ; + + SetValue( value ) ; + + wxEventType scrollEvent = wxEVT_NULL ; + + if ( mouseStillDown ) + scrollEvent = wxEVT_SCROLL_THUMBTRACK; + else + scrollEvent = wxEVT_SCROLL_THUMBRELEASE; + + wxScrollEvent event(scrollEvent, m_windowId); + event.SetPosition(value); + event.SetEventObject( this ); + GetEventHandler()->ProcessEvent(event); + + wxCommandEvent cevent( wxEVT_COMMAND_SLIDER_UPDATED, m_windowId ); + cevent.SetInt( value ); + cevent.SetEventObject( this ); + + GetEventHandler()->ProcessEvent( cevent ); +} + +/* This is overloaded in wxSlider so that the proper width/height will always be used +* for the slider different values would cause redrawing and mouse detection problems */ +void wxSlider::SetSizeHints( int minW, int minH, + int maxW , int maxH , + int incW , int incH ) +{ + wxSize size = GetBestSize(); + + if(GetWindowStyle() & wxSL_VERTICAL) { + wxWindow::SetSizeHints(size.x, minH, size.x, maxH, incW, incH); + } + else { + wxWindow::SetSizeHints(minW, size.y, maxW, size.y, incW, incH); + } +} + +wxSize wxSlider::DoGetBestSize() const +{ + wxSize size; + int textwidth, textheight; + + if(GetWindowStyle() & wxSL_LABELS) + { + wxString text; + int ht, wd; + + // Get maximum text label width and height + text.Printf(wxT("%d"), m_rangeMin); + GetTextExtent(text, &textwidth, &textheight); + text.Printf(wxT("%d"), m_rangeMax); + GetTextExtent(text, &wd, &ht); + if(ht > textheight) { + textheight = ht; + } + if (wd > textwidth) { + textwidth = wd; + } + } + + if(GetWindowStyle() & wxSL_VERTICAL) + { + if(GetWindowStyle() & wxSL_AUTOTICKS) { + size.x = wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS; + } + else { + size.x = wxSLIDER_DIMENSIONACROSS_ARROW; + } + if(GetWindowStyle() & wxSL_LABELS) { + size.x += textwidth + wxSLIDER_BORDERTEXT; + } + size.y = 150; + } + else + { + if(GetWindowStyle() & wxSL_AUTOTICKS) { + size.y = wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS; + } + else { + size.y = wxSLIDER_DIMENSIONACROSS_ARROW; + } + if(GetWindowStyle() & wxSL_LABELS) { + size.y += textheight + wxSLIDER_BORDERTEXT; + } + size.x = 150; + } + return size; +} + +void wxSlider::DoSetSize(int x, int y, int width, int height, int sizeFlags) +{ + wxControl::DoSetSize( x, y , width , height ,sizeFlags ) ; +} + +void wxSlider::MacUpdateDimensions() +{ + // actually in the current systems this should never be possible, but later reparenting + // may become a reality + + if ( (ControlHandle) m_macControl == NULL ) + return ; + + if ( GetParent() == NULL ) + return ; + + WindowRef rootwindow = (WindowRef) MacGetRootWindow() ; + if ( rootwindow == NULL ) + return ; + + int xborder, yborder; + int minValWidth, maxValWidth, textwidth, textheight; + int sliderBreadth; + + xborder = yborder = 0; + + if (GetWindowStyle() & wxSL_LABELS) + { + wxString text; + int ht; + + // Get maximum text label width and height + text.Printf(wxT("%d"), m_rangeMin); + GetTextExtent(text, &minValWidth, &textheight); + text.Printf(wxT("%d"), m_rangeMax); + GetTextExtent(text, &maxValWidth, &ht); + if(ht > textheight) { + textheight = ht; + } + textwidth = (minValWidth > maxValWidth ? minValWidth : maxValWidth); + + xborder = textwidth + wxSLIDER_BORDERTEXT; + yborder = textheight + wxSLIDER_BORDERTEXT; + + // Get slider breadth + if(GetWindowStyle() & wxSL_AUTOTICKS) { + sliderBreadth = wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS; + } + else { + sliderBreadth = wxSLIDER_DIMENSIONACROSS_ARROW; + } + + if(GetWindowStyle() & wxSL_VERTICAL) + { + m_macMinimumStatic->Move(sliderBreadth + wxSLIDER_BORDERTEXT, + m_height - yborder - textheight); + m_macMaximumStatic->Move(sliderBreadth + wxSLIDER_BORDERTEXT, 0); + m_macValueStatic->Move(0, m_height - textheight); + } + else + { + m_macMinimumStatic->Move(0, sliderBreadth + wxSLIDER_BORDERTEXT); + m_macMaximumStatic->Move(m_width - xborder - maxValWidth / 2, + sliderBreadth + wxSLIDER_BORDERTEXT); + m_macValueStatic->Move(m_width - textwidth, 0); + } + } + + Rect oldBounds ; + GetControlBounds( (ControlHandle) m_macControl , &oldBounds ) ; + + int new_x = m_x + MacGetLeftBorderSize() + m_macHorizontalBorder ; + int new_y = m_y + MacGetTopBorderSize() + m_macVerticalBorder ; + int new_width = m_width - MacGetLeftBorderSize() - MacGetRightBorderSize() - 2 * m_macHorizontalBorder - xborder ; + int new_height = m_height - MacGetTopBorderSize() - MacGetBottomBorderSize() - 2 * m_macVerticalBorder - yborder ; + + GetParent()->MacWindowToRootWindow( & new_x , & new_y ) ; + bool doMove = new_x != oldBounds.left || new_y != oldBounds.top ; + bool doResize = ( oldBounds.right - oldBounds.left ) != new_width || (oldBounds.bottom - oldBounds.top ) != new_height ; + if ( doMove || doResize ) + { + InvalWindowRect( rootwindow, &oldBounds ) ; + if ( doMove ) + { + UMAMoveControl( (ControlHandle) m_macControl , new_x , new_y ) ; + } + if ( doResize ) + { + UMASizeControl( (ControlHandle) m_macControl , new_width , new_height ) ; + } + } +} + +void wxSlider::DoMoveWindow(int x, int y, int width, int height) +{ + wxControl::DoMoveWindow(x,y,width,height) ; +} diff --git a/src/mac/classic/sound.cpp b/src/mac/classic/sound.cpp new file mode 100644 index 0000000000..d6d13bb595 --- /dev/null +++ b/src/mac/classic/sound.cpp @@ -0,0 +1,243 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: sound.cpp +// Purpose: wxSound class implementation: optional +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "sound.h" +#endif + +#include "wx/object.h" +#include "wx/string.h" +#include "wx/sound.h" + +#if wxUSE_SOUND + +#ifdef __WXMAC__ +#include "wx/mac/private.h" +#ifndef __DARWIN__ +#include +#endif +#endif + +wxSound::wxSound() + : m_sndChan(0), m_hSnd(NULL), m_waveLength(0), m_isResource(true) +{ +} + +wxSound::wxSound(const wxString& sFileName, bool isResource) + : m_sndChan(0), m_hSnd(NULL), m_waveLength(0), m_isResource(true) +{ + Create(sFileName, isResource); +} + + +wxSound::~wxSound() +{ + FreeData(); +} + +wxSound::wxSound(int size, const wxByte* data) + : m_sndChan(0), m_hSnd(NULL), m_waveLength(0), m_isResource(false) +{ + //TODO convert data +} + +bool wxSound::Create(const wxString& fileName, bool isResource) +{ + bool ret = false; + m_sndname = fileName; + m_isResource = isResource; + + if (m_isResource) + ret = true; + else + { /* + if (sndChan) + { // we're playing + FSClose(SndRefNum); + SndRefNum = 0; + SndDisposeChannel(sndChan, TRUE); + free(sndChan); + sndChan = 0; + KillTimer(0,timerID); + } + + if (!lpSnd) + return true; + + if (_access(lpSnd,0)) // no file, no service + return false; + + // Allocate SndChannel + sndChan = (SndChannelPtr) malloc (sizeof(SndChannel)); + + if (!sndChan) + return false; + + sndChan->qLength = 128; + + if (noErr != SndNewChannel (&sndChan, sampledSynth, initMono | initNoInterp, 0)) + { + free(sndChan); + sndChan = 0; + return false; + } + + if (!(SndRefNum = MacOpenSndFile ((char *)lpSnd))) + { + SndDisposeChannel(sndChan, TRUE); + free(sndChan); + sndChan = 0; + + return false; + } + + bool async = false; + + if (fdwSound & SND_ASYNC) + async = true; + + if (SndStartFilePlay(sndChan, SndRefNum, 0, 81920, 0, 0, 0, async) != noErr) + { + FSClose (SndRefNum); + SndRefNum = 0; + SndDisposeChannel (sndChan, TRUE); + free (sndChan); + sndChan = 0; + return false; + } + + if (async) + { // haven't finish yet + timerID = SetTimer(0, 0, 250, TimerCallBack); + } + else + { + FSClose (SndRefNum); + SndRefNum = 0; + SndDisposeChannel (sndChan, TRUE); + free (sndChan); + sndChan = 0; + }*/ + } + + return ret; +} + + +//don't know what to do with looped, wth +bool wxSound::DoPlay(unsigned flags) const +{ + bool ret = false; + + if (m_isResource) + { + Str255 snd ; + wxMacStringToPascal( m_sndname , snd ) ; + SndListHandle hSnd; + + hSnd = (SndListHandle) GetNamedResource('snd ', snd); + + if ((hSnd != NULL) && (SndPlay((SndChannelPtr)m_sndChan, (SndListHandle) hSnd, (flags & wxSOUND_ASYNC)) == noErr)) + ret = true; + } + + return ret; +} + + +bool wxSound::FreeData() +{ + bool ret = false; + + if (m_isResource) + { + m_sndname.Empty(); + ret = true; + } + else + { + //TODO, + } + + return ret; +} + + +//code below is from an old implementation used for telinfo with MSVC crossplatform support +//technology proceeds, so it would be the wisest to drop this code, but it's left here just +//for the sake of a reference. BTW: Wave files can now be played with QT, starting from V3 + +/*static short MacOpenSndFile (char * path) +{ + VolumeParam vp; + FSSpec fspec; + Str255 name; + char *c; + + // first, get the volume reference number for the file. Start by + // making a Pstring with just the volume name + strcpy ((char *) name, path); + if (c = strchr ((char *) name, ':')) + { + c++; + *c = '\0'; + } + + c2pstr ((char *) name); + vp.ioCompletion = 0; + vp.ioVolIndex = -1; + vp.ioNamePtr = name; + vp.ioVRefNum = 0; + + if (PBGetVInfo((ParamBlockRec *)&vp, 0) != noErr) + return 0; + + // next, buld an FSSpec for the file + strcpy ((char *) name, path); + c2pstr ((char *) name); + if (FSMakeFSSpec (vp.ioVRefNum, 0, name, &fspec) != noErr) + return 0; + + short frefnum; + // now open the file, and return it's reference number + if (FSpOpenDF(&fspec, fsRdPerm, &frefnum) != noErr) + return 0; + + return frefnum; +} + + +void TimerCallBack(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime) +{ + if(!sndChan) + { + KillTimer(0,timerID); + return; + } + + SCStatus scstat; + + if (noErr == SndChannelStatus (sndChan, sizeof (SCStatus), &scstat)) { + if (scstat.scChannelPaused || scstat.scChannelBusy) + return; // not done yet + } + + // either error or done. + FSClose (SndRefNum); + SndRefNum = 0; + SndDisposeChannel (sndChan, TRUE); + free (sndChan); + sndChan = 0; + KillTimer(0,timerID); +}*/ + + +#endif diff --git a/src/mac/classic/spinbutt.cpp b/src/mac/classic/spinbutt.cpp new file mode 100644 index 0000000000..f8dcca8bd9 --- /dev/null +++ b/src/mac/classic/spinbutt.cpp @@ -0,0 +1,182 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: spinbutt.cpp +// Purpose: wxSpinButton +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "spinbutt.h" +#pragma implementation "spinbuttbase.h" +#endif + +#include "wx/spinbutt.h" +#include "wx/mac/uma.h" + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxWin macros +// ---------------------------------------------------------------------------- + +#if !USE_SHARED_LIBRARY + IMPLEMENT_DYNAMIC_CLASS(wxSpinButton, wxControl) + IMPLEMENT_DYNAMIC_CLASS(wxSpinEvent, wxScrollEvent) +#endif + +wxSpinButton::wxSpinButton() + : wxSpinButtonBase() +{ +} + +bool wxSpinButton::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, + long style, const wxString& name) +{ + if ( !wxSpinButtonBase::Create(parent, id, pos, size, + style, wxDefaultValidator, name) ) + return false; + + m_min = 0; + m_max = 100; + + if (!parent) + return FALSE; + + Rect bounds ; + Str255 title ; + + MacPreControlCreate( parent , id , wxEmptyString , pos , size ,style,*( (wxValidator*) NULL ) , name , &bounds , title ) ; + + m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()) , &bounds , title , false , 0 , 0 , 100, + kControlLittleArrowsProc , (long) this ) ; + + wxASSERT_MSG( (ControlHandle) m_macControl != NULL , wxT("No valid mac control") ) ; + + MacPostControlCreate() ; + + return TRUE; +} + +wxSpinButton::~wxSpinButton() +{ +} + +// Attributes +//////////////////////////////////////////////////////////////////////////// + +int wxSpinButton::GetMin() const +{ + return m_min; +} + +int wxSpinButton::GetMax() const +{ + return m_max; +} + +int wxSpinButton::GetValue() const +{ + return m_value; +} + +void wxSpinButton::SetValue(int val) +{ + m_value = val ; +} + +void wxSpinButton::SetRange(int minVal, int maxVal) +{ + m_min = minVal; + m_max = maxVal; + SetControl32BitMaximum( (ControlHandle) m_macControl , maxVal ) ; + SetControl32BitMinimum((ControlHandle) m_macControl , minVal ) ; +} + +void wxSpinButton::MacHandleValueChanged( int inc ) +{ + + wxEventType scrollEvent = wxEVT_NULL; + int oldValue = m_value ; + + m_value = oldValue + inc; + + if (m_value < m_min) + { + if ( m_windowStyle & wxSP_WRAP ) + m_value = m_max; + else + m_value = m_min; + } + + if (m_value > m_max) + { + if ( m_windowStyle & wxSP_WRAP ) + m_value = m_min; + else + m_value = m_max; + } + + if ( m_value - oldValue == -1 ) + scrollEvent = wxEVT_SCROLL_LINEDOWN ; + else if ( m_value - oldValue == 1 ) + scrollEvent = wxEVT_SCROLL_LINEUP ; + else + scrollEvent = wxEVT_SCROLL_THUMBTRACK ; + + wxSpinEvent event(scrollEvent, m_windowId); + + event.SetPosition(m_value); + event.SetEventObject( this ); + if ((GetEventHandler()->ProcessEvent( event )) && + !event.IsAllowed() ) + { + m_value = oldValue ; + } + SetControl32BitValue( (ControlHandle) m_macControl , m_value ) ; + + /* always send a thumbtrack event */ + if (scrollEvent != wxEVT_SCROLL_THUMBTRACK) + { + scrollEvent = wxEVT_SCROLL_THUMBTRACK; + wxSpinEvent event2( scrollEvent, GetId()); + event2.SetPosition( m_value ); + event2.SetEventObject( this ); + GetEventHandler()->ProcessEvent( event2 ); + } +} + +void wxSpinButton::MacHandleControlClick( WXWidget control , wxInt16 controlpart , bool WXUNUSED(mouseStillDown)) +{ + if ( (ControlHandle) m_macControl == NULL ) + return ; + + int nScrollInc = 0; + + switch( controlpart ) + { + case kControlUpButtonPart : + nScrollInc = 1; + break ; + case kControlDownButtonPart : + nScrollInc = -1; + break ; + } + MacHandleValueChanged( nScrollInc ) ; + +} + +// ---------------------------------------------------------------------------- +// size calculation +// ---------------------------------------------------------------------------- + +wxSize wxSpinButton::DoGetBestSize() const +{ + return wxSize(16,24); +} + diff --git a/src/mac/classic/spinctrl.cpp b/src/mac/classic/spinctrl.cpp new file mode 100644 index 0000000000..22553d47f1 --- /dev/null +++ b/src/mac/classic/spinctrl.cpp @@ -0,0 +1,333 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: spinbutt.cpp +// Purpose: wxSpinCtrl +// Author: Robert +// Modified by: Mark Newsam (Based on GTK file) +// RCS-ID: $Id$ +// Copyright: (c) Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "spinctlg.h" +#endif + +#include "wx/defs.h" + +#ifndef WX_PRECOMP + #include "wx/textctrl.h" +#endif //WX_PRECOMP + +#if wxUSE_SPINCTRL + +#include "wx/spinbutt.h" +#include "wx/spinctrl.h" + + +#include "wx/spinctrl.h" + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// the margin between the text control and the spin +static const wxCoord MARGIN = 2; + +// ---------------------------------------------------------------------------- +// wxSpinCtrlText: text control used by spin control +// ---------------------------------------------------------------------------- + +class wxSpinCtrlText : public wxTextCtrl +{ +public: + wxSpinCtrlText(wxSpinCtrl *spin, const wxString& value) + : wxTextCtrl(spin , -1, value) + { + m_spin = spin; + } + +protected: + void OnTextChange(wxCommandEvent& event) + { + int val; + if ( m_spin->GetTextValue(&val) ) + { + m_spin->GetSpinButton()->SetValue(val); + } + + event.Skip(); + } + + bool ProcessEvent(wxEvent &event) + { + // Hand button down events to wxSpinCtrl. Doesn't work. + if (event.GetEventType() == wxEVT_LEFT_DOWN && m_spin->ProcessEvent( event )) + return TRUE; + + return wxTextCtrl::ProcessEvent( event ); + } + +private: + wxSpinCtrl *m_spin; + + DECLARE_EVENT_TABLE() +}; + +BEGIN_EVENT_TABLE(wxSpinCtrlText, wxTextCtrl) + EVT_TEXT(-1, wxSpinCtrlText::OnTextChange) +END_EVENT_TABLE() + +// ---------------------------------------------------------------------------- +// wxSpinCtrlButton: spin button used by spin control +// ---------------------------------------------------------------------------- + +class wxSpinCtrlButton : public wxSpinButton +{ +public: + wxSpinCtrlButton(wxSpinCtrl *spin, int style) + : wxSpinButton(spin ) + { + m_spin = spin; + + SetWindowStyle(style | wxSP_VERTICAL); + } + +protected: + void OnSpinButton(wxSpinEvent& eventSpin) + { +#if defined(__WXMAC__) || defined(__WXMOTIF__) + m_spin->SetTextValue(eventSpin.GetPosition()); + + wxCommandEvent event(wxEVT_COMMAND_SPINCTRL_UPDATED, m_spin->GetId()); + event.SetEventObject(m_spin); + event.SetInt(eventSpin.GetPosition()); + + m_spin->GetEventHandler()->ProcessEvent(event); +#else + m_spin->SetTextValue(eventSpin.GetPosition()); + eventSpin.Skip(); +#endif + } + +private: + wxSpinCtrl *m_spin; + + DECLARE_EVENT_TABLE() +}; + +BEGIN_EVENT_TABLE(wxSpinCtrlButton, wxSpinButton) + EVT_SPIN(-1, wxSpinCtrlButton::OnSpinButton) +END_EVENT_TABLE() + +IMPLEMENT_DYNAMIC_CLASS(wxSpinCtrl, wxControl) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxSpinCtrl creation +// ---------------------------------------------------------------------------- + +void wxSpinCtrl::Init() +{ + m_text = NULL; + m_btn = NULL; +} + +bool wxSpinCtrl::Create(wxWindow *parent, + wxWindowID id, + const wxString& value, + const wxPoint& pos, + const wxSize& size, + long style, + int min, + int max, + int initial, + const wxString& name) +{ + if ( !wxControl::Create(parent, id, wxDefaultPosition, wxDefaultSize, style, + wxDefaultValidator, name) ) + { + return FALSE; + } + + // the string value overrides the numeric one (for backwards compatibility + // reasons and also because it is simpler to satisfy the string value which + // comes much sooner in the list of arguments and leave the initial + // parameter unspecified) + if ( !value.empty() ) + { + long l; + if ( value.ToLong(&l) ) + initial = l; + } + + wxSize csize = size ; + m_text = new wxSpinCtrlText(this, value); + m_btn = new wxSpinCtrlButton(this, style); + + m_btn->SetRange(min, max); + m_btn->SetValue(initial); + + if ( size.y == -1 ) { + csize.y = m_text->GetSize().y ; + } + DoSetSize(pos.x , pos.y , csize.x, csize.y); + + return TRUE; +} + +wxSpinCtrl::~wxSpinCtrl() +{ + // delete the controls now, don't leave them alive even though they would + // still be eventually deleted by our parent - but it will be too late, the + // user code expects them to be gone now + delete m_text; + m_text = NULL ; + delete m_btn; + m_btn = NULL ; +} + +// ---------------------------------------------------------------------------- +// geometry +// ---------------------------------------------------------------------------- + +wxSize wxSpinCtrl::DoGetBestSize() const +{ + wxSize sizeBtn = m_btn->GetBestSize(), + sizeText = m_text->GetBestSize(); + + return wxSize(sizeBtn.x + sizeText.x + MARGIN, sizeText.y); +} + +void wxSpinCtrl::DoMoveWindow(int x, int y, int width, int height) +{ + wxControl::DoMoveWindow(x, y, width, height); + + // position the subcontrols inside the client area + wxSize sizeBtn = m_btn->GetSize(); + + wxCoord wText = width - sizeBtn.x; + m_text->SetSize(0, 0, wText, height); + m_btn->SetSize(0 + wText + MARGIN, 0, -1, -1); +} + +// ---------------------------------------------------------------------------- +// operations forwarded to the subcontrols +// ---------------------------------------------------------------------------- + +bool wxSpinCtrl::Enable(bool enable) +{ + if ( !wxControl::Enable(enable) ) + return FALSE; + return TRUE; +} + +bool wxSpinCtrl::Show(bool show) +{ + if ( !wxControl::Show(show) ) + return FALSE; + return TRUE; +} + +// ---------------------------------------------------------------------------- +// value and range access +// ---------------------------------------------------------------------------- + +bool wxSpinCtrl::GetTextValue(int *val) const +{ + long l; + if ( !m_text->GetValue().ToLong(&l) ) + { + // not a number at all + return FALSE; + } + + if ( l < GetMin() || l > GetMax() ) + { + // out of range + return FALSE; + } + + *val = l; + + return TRUE; +} + +int wxSpinCtrl::GetValue() const +{ + return m_btn ? m_btn->GetValue() : 0; +} + +int wxSpinCtrl::GetMin() const +{ + return m_btn ? m_btn->GetMin() : 0; +} + +int wxSpinCtrl::GetMax() const +{ + return m_btn ? m_btn->GetMax() : 0; +} + +// ---------------------------------------------------------------------------- +// changing value and range +// ---------------------------------------------------------------------------- + +void wxSpinCtrl::SetTextValue(int val) +{ + wxCHECK_RET( m_text, _T("invalid call to wxSpinCtrl::SetTextValue") ); + + m_text->SetValue(wxString::Format(_T("%d"), val)); + + // select all text + m_text->SetSelection(0, -1); + + // and give focus to the control! + // m_text->SetFocus(); Why???? TODO. +} + +void wxSpinCtrl::SetValue(int val) +{ + wxCHECK_RET( m_btn, _T("invalid call to wxSpinCtrl::SetValue") ); + + SetTextValue(val); + + m_btn->SetValue(val); +} + +void wxSpinCtrl::SetValue(const wxString& text) +{ + wxCHECK_RET( m_text, _T("invalid call to wxSpinCtrl::SetValue") ); + + long val; + if ( text.ToLong(&val) && ((val > INT_MIN) && (val < INT_MAX)) ) + { + SetValue((int)val); + } + else // not a number at all or out of range + { + m_text->SetValue(text); + m_text->SetSelection(0, -1); + } +} + +void wxSpinCtrl::SetRange(int min, int max) +{ + wxCHECK_RET( m_btn, _T("invalid call to wxSpinCtrl::SetRange") ); + + m_btn->SetRange(min, max); +} + +void wxSpinCtrl::SetSelection(long from, long to) +{ + // if from and to are both -1, it means (in wxWindows) that all text should + // be selected + if ( (from == -1) && (to == -1) ) + { + from = 0; + } + m_text->SetSelection(from, to); +} + +#endif // wxUSE_SPINCTRL diff --git a/src/mac/classic/statbmp.cpp b/src/mac/classic/statbmp.cpp new file mode 100644 index 0000000000..68bc4efa6a --- /dev/null +++ b/src/mac/classic/statbmp.cpp @@ -0,0 +1,86 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: statbmp.cpp +// Purpose: wxStaticBitmap +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ + #pragma implementation "statbmp.h" +#endif + +#include "wx/defs.h" + +#include "wx/statbmp.h" +#include "wx/dcclient.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxStaticBitmap, wxControl) +#endif + +/* + * wxStaticBitmap + */ + +BEGIN_EVENT_TABLE(wxStaticBitmap, wxStaticBitmapBase) + EVT_PAINT(wxStaticBitmap::OnPaint) +END_EVENT_TABLE() + +bool wxStaticBitmap::Create(wxWindow *parent, wxWindowID id, + const wxBitmap& bitmap, + const wxPoint& pos, + const wxSize& s, + long style, + const wxString& name) +{ + SetName(name); + wxSize size = s ; + if ( bitmap.Ok() ) + { + if ( size.x == -1 ) + size.x = bitmap.GetWidth() ; + if ( size.y == -1 ) + size.y = bitmap.GetHeight() ; + } + + m_backgroundColour = parent->GetBackgroundColour() ; + m_foregroundColour = parent->GetForegroundColour() ; + + m_bitmap = bitmap; + if ( id == -1 ) + m_windowId = (int)NewControlId(); + else + m_windowId = id; + + m_windowStyle = style; + + bool ret = wxControl::Create( parent, id, pos, size, style , wxDefaultValidator , name ); + SetBestSize( size ) ; + + return ret; +} + +void wxStaticBitmap::SetBitmap(const wxBitmap& bitmap) +{ + m_bitmap = bitmap; + SetSize(wxSize(bitmap.GetWidth(), bitmap.GetHeight())); + Refresh() ; +} + +void wxStaticBitmap::OnPaint( wxPaintEvent& WXUNUSED(event) ) +{ + wxPaintDC dc(this); + PrepareDC(dc); + + dc.DrawBitmap( m_bitmap , 0 , 0 , TRUE ) ; +} + +wxSize wxStaticBitmap::DoGetBestSize() const +{ + return wxWindow::DoGetBestSize() ; +} + diff --git a/src/mac/classic/statbox.cpp b/src/mac/classic/statbox.cpp new file mode 100644 index 0000000000..13c7daf669 --- /dev/null +++ b/src/mac/classic/statbox.cpp @@ -0,0 +1,56 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: statbox.cpp +// Purpose: wxStaticBox +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "statbox.h" +#endif + +#include "wx/defs.h" + +#include "wx/statbox.h" +#include "wx/mac/uma.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxStaticBox, wxControl) + +BEGIN_EVENT_TABLE(wxStaticBox, wxControl) + EVT_ERASE_BACKGROUND(wxStaticBox::OnEraseBackground) +END_EVENT_TABLE() + +#endif + +/* + * Static box + */ + +bool wxStaticBox::Create(wxWindow *parent, wxWindowID id, + const wxString& label, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + if ( !wxControl::Create(parent, id, pos, size, + style, wxDefaultValidator, name) ) + return false; + + Rect bounds ; + Str255 title ; + + MacPreControlCreate( parent , id , label , pos , size ,style, wxDefaultValidator , name , &bounds , title ) ; + + m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()) , &bounds , title , false , 0 , 0 , 1, + kControlGroupBoxTextTitleProc , (long) this ) ; + + MacPostControlCreate() ; + + return TRUE; +} diff --git a/src/mac/classic/statbrma.cpp b/src/mac/classic/statbrma.cpp new file mode 100644 index 0000000000..b2dba2135d --- /dev/null +++ b/src/mac/classic/statbrma.cpp @@ -0,0 +1,155 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: statbar.cpp +// Purpose: native implementation of wxStatusBar (optional) +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) 1998 Stefan Csomor +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "statbrma.h" +#endif + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/statusbr.h" +#include "wx/dc.h" +#include "wx/dcclient.h" + +BEGIN_EVENT_TABLE(wxStatusBarMac, wxStatusBarGeneric) + EVT_PAINT(wxStatusBarMac::OnPaint) +END_EVENT_TABLE() + +#ifdef __WXMAC__ +#include "wx/mac/private.h" +#endif + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxStatusBarMac class +// ---------------------------------------------------------------------------- + +wxStatusBarMac::wxStatusBarMac() +{ + SetParent(NULL); +} + +wxStatusBarMac::~wxStatusBarMac() +{ +} + +bool wxStatusBarMac::Create(wxWindow *parent, wxWindowID id, + long style , + const wxString& name) +{ + return wxStatusBarGeneric::Create( parent , id , style , name ) ; +} + +void wxStatusBarMac::DrawFieldText(wxDC& dc, int i) +{ + int leftMargin = 2; + + wxRect rect; + GetFieldRect(i, rect); + + if ( !IsWindowHilited( MAC_WXHWND( MacGetRootWindow() ) ) ) + { + dc.SetTextForeground( wxColour( 0x80 , 0x80 , 0x80 ) ) ; + } + + wxString text(GetStatusText(i)); + + long x, y; + + dc.GetTextExtent(text, &x, &y); + + int xpos = rect.x + leftMargin + 1 ; + int ypos = 1 ; + + dc.SetClippingRegion(rect.x, 0, rect.width, m_height); + + dc.DrawText(text, xpos, ypos); + + dc.DestroyClippingRegion(); +} + +void wxStatusBarMac::DrawField(wxDC& dc, int i) +{ + DrawFieldText(dc, i); +} + +void wxStatusBarMac::SetStatusText(const wxString& text, int number) +{ + wxCHECK_RET( (number >= 0) && (number < m_nFields), + _T("invalid status bar field index") ); + + m_statusStrings[number] = text; + wxRect rect; + GetFieldRect(number, rect); + rect.y=0; + rect.height = m_height ; + Refresh( TRUE , &rect ) ; + Update(); +} + +void wxStatusBarMac::OnPaint(wxPaintEvent& WXUNUSED(event) ) +{ + wxPaintDC dc(this); + dc.Clear() ; + + int major,minor; + wxGetOsVersion( &major, &minor ); + + if ( IsWindowHilited( MAC_WXHWND( MacGetRootWindow() ) ) ) + { + wxPen white( wxWHITE , 1 , wxSOLID ) ; + if (major >= 10) + { + //Finder statusbar border color: (Project builder similar is 9B9B9B) + dc.SetPen(wxPen(wxColour(0xB1,0xB1,0xB1),1,wxSOLID)); + } + else + { + wxPen black( wxBLACK , 1 , wxSOLID ) ; + dc.SetPen(black); + } + dc.DrawLine(0, 0 , + m_width , 0); + dc.SetPen(white); + dc.DrawLine(0, 1 , + m_width , 1); + } + else + { + if (major >= 10) + //Finder statusbar border color: (Project builder similar is 9B9B9B) + dc.SetPen(wxPen(wxColour(0xB1,0xB1,0xB1),1,wxSOLID)); + else + dc.SetPen(wxPen(wxColour(0x80,0x80,0x80),1,wxSOLID)); + + dc.DrawLine(0, 0 , + m_width , 0); + } + + int i; + if ( GetFont().Ok() ) + dc.SetFont(GetFont()); + dc.SetBackgroundMode(wxTRANSPARENT); + + for ( i = 0; i < m_nFields; i ++ ) + DrawField(dc, i); +} + +void wxStatusBarMac::MacSuperEnabled( bool enabled ) +{ + Refresh(FALSE) ; + wxWindow::MacSuperEnabled( enabled ) ; +} diff --git a/src/mac/classic/statline.cpp b/src/mac/classic/statline.cpp new file mode 100644 index 0000000000..52f3d40733 --- /dev/null +++ b/src/mac/classic/statline.cpp @@ -0,0 +1,61 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: generic/statline.cpp +// Purpose: a generic wxStaticLine class +// Author: Vadim Zeitlin +// Created: 28.06.99 +// Version: $Id$ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#ifdef __GNUG__ + #pragma implementation "statline.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/statline.h" +#include "wx/statbox.h" + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxStaticLine, wxControl) + +// ---------------------------------------------------------------------------- +// wxStaticLine +// ---------------------------------------------------------------------------- + +bool wxStaticLine::Create( wxWindow *parent, + wxWindowID id, + const wxPoint &pos, + const wxSize &size, + long style, + const wxString &name) +{ + if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) ) + return FALSE; + + // ok, this is ugly but it's better than nothing: use a thin static box to + // emulate static line + + wxSize sizeReal = AdjustSize(size); + +// m_statbox = new wxStaticBox(parent, id, wxT(""), pos, sizeReal, style, name); + + return TRUE; +} diff --git a/src/mac/classic/statlmac.cpp b/src/mac/classic/statlmac.cpp new file mode 100644 index 0000000000..a7a116ba57 --- /dev/null +++ b/src/mac/classic/statlmac.cpp @@ -0,0 +1,67 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: generic/statline.cpp +// Purpose: a generic wxStaticLine class +// Author: Vadim Zeitlin +// Created: 28.06.99 +// Version: $Id$ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#ifdef __GNUG__ + #pragma implementation "statline.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/statline.h" +#include "wx/statbox.h" + +#include "wx/mac/uma.h" + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxStaticLine, wxControl) + +// ---------------------------------------------------------------------------- +// wxStaticLine +// ---------------------------------------------------------------------------- + +bool wxStaticLine::Create( wxWindow *parent, + wxWindowID id, + const wxPoint &pos, + const wxSize &size, + long style, + const wxString &name) +{ + if ( !wxStaticLineBase::Create(parent, id, pos, size, + style, wxDefaultValidator, name) ) + return false; + + Rect bounds ; + Str255 title ; + + MacPreControlCreate( parent , id , wxEmptyString , pos , size ,style, wxDefaultValidator , name , &bounds , title ) ; + + m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()) , &bounds , title , false , 0 , 0 , 1, + kControlSeparatorLineProc , (long) this ) ; + + MacPostControlCreate() ; + + return TRUE; +} diff --git a/src/mac/classic/stattext.cpp b/src/mac/classic/stattext.cpp new file mode 100644 index 0000000000..1c0facdbf7 --- /dev/null +++ b/src/mac/classic/stattext.cpp @@ -0,0 +1,262 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: stattext.cpp +// Purpose: wxStaticText +// Author: Stefan Csomor +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "stattext.h" +#endif + +#include "wx/app.h" +#include "wx/stattext.h" +#include "wx/notebook.h" +#include "wx/tabctrl.h" +#include "wx/dc.h" +#include "wx/dcclient.h" +#include "wx/utils.h" +#include "wx/settings.h" + +#include + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxStaticText, wxControl) +#endif + +#include "wx/mac/uma.h" + +BEGIN_EVENT_TABLE(wxStaticText, wxStaticTextBase) + EVT_PAINT(wxStaticText::OnPaint) +END_EVENT_TABLE() + +bool wxStaticText::Create(wxWindow *parent, wxWindowID id, + const wxString& label, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + m_label = wxStripMenuCodes(label) ; + + if ( !wxControl::Create( parent, id, pos, size, style, + wxDefaultValidator , name ) ) + { + return false; + } + + SetBestSize( size ) ; + + return true; +} + +const wxString punct = wxT(" ,.-;:!?"); + +void wxStaticText::DrawParagraph(wxDC &dc, wxString paragraph, int &y) +{ + long width, height ; + + if (paragraph.Length() == 0) + { + // empty line + dc.GetTextExtent( wxT("H"), &width, &height ); + y += height; + + return; + } + + int x = 0 ; + + bool linedrawn = true; + while( paragraph.Length() > 0 ) + { + dc.GetTextExtent( paragraph , &width , &height ) ; + + if ( width > m_width ) + { + for ( size_t p = paragraph.Length() - 1 ; p > 0 ; --p ) + { + if ((punct.Find(paragraph[p]) != wxNOT_FOUND) || !linedrawn) + { + int blank = (paragraph[p] == ' ') ? 0 : 1; + + dc.GetTextExtent( paragraph.Left(p + blank) , &width , &height ) ; + + if ( width <= m_width ) + { + int pos = x ; + if ( HasFlag( wxALIGN_CENTER ) ) + { + pos += ( m_width - width ) / 2 ; + } + else if ( HasFlag( wxALIGN_RIGHT ) ) + { + pos += ( m_width - width ) ; + } + + dc.DrawText( paragraph.Left(p + blank), pos , y) ; + y += height ; + paragraph = paragraph.Mid(p+1) ; + linedrawn = true; + break ; + } + } + } + + linedrawn = false; + } + else + { + int pos = x ; + if ( HasFlag( wxALIGN_CENTER ) ) + { + pos += ( m_width - width ) / 2 ; + } + else if ( HasFlag( wxALIGN_RIGHT ) ) + { + pos += ( m_width - width ) ; + } + + dc.DrawText( paragraph, pos , y) ; + paragraph=wxEmptyString; + y += height ; + } + } +} + +void wxStaticText::OnDraw( wxDC &dc ) +{ + if (m_width <= 0 || m_height <= 0) + return; + /* + dc.Clear() ; + wxRect rect(0,0,m_width,m_height) ; + dc.SetFont(*wxSMALL_FONT) ; + + dc.DrawRectangle(rect) ; + */ + if ( !IsWindowHilited( (WindowRef) MacGetRootWindow() ) && + ( GetBackgroundColour() == wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE ) + || GetBackgroundColour() == wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE) ) ) + { + dc.SetTextForeground( wxColour( 0x80 , 0x80 , 0x80 ) ) ; + } + else + { + dc.SetTextForeground( GetForegroundColour() ) ; + } + + wxString paragraph; + size_t i = 0 ; + wxString text = m_label; + int y = 0 ; + while (i < text.Length()) + { + + if (text[i] == 13 || text[i] == 10) + { + DrawParagraph(dc, paragraph,y); + paragraph = wxEmptyString ; + } + else + { + paragraph += text[i]; + } + ++i; + } + if (paragraph.Length() > 0) + DrawParagraph(dc, paragraph,y); +} + +void wxStaticText::OnPaint( wxPaintEvent & WXUNUSED(event) ) +{ + wxPaintDC dc(this); + OnDraw( dc ) ; +} + +wxSize wxStaticText::DoGetBestSize() const +{ + int widthTextMax = 0, widthLine, + heightTextTotal = 0, heightLineDefault = 0, heightLine = 0; + + wxString curLine; + for ( const wxChar *pc = m_label; ; pc++ ) + { + if ( *pc == wxT('\n') || *pc == wxT('\r') || *pc == wxT('\0') ) + { + if ( !curLine ) + { + // we can't use GetTextExtent - it will return 0 for both width + // and height and an empty line should count in height + // calculation + if ( !heightLineDefault ) + heightLineDefault = heightLine; + if ( !heightLineDefault ) + GetTextExtent(_T("W"), NULL, &heightLineDefault); + + heightTextTotal += heightLineDefault; + + heightTextTotal++; // FIXME: why is this necessary? + } + else + { + GetTextExtent(curLine, &widthLine, &heightLine); + if ( widthLine > widthTextMax ) + widthTextMax = widthLine; + heightTextTotal += heightLine; + + heightTextTotal++; // FIXME: why is this necessary? + } + + if ( *pc == wxT('\n') || *pc == wxT('\r')) { + curLine.Empty(); + } + else { + // the end of string + break; + } + } + else { + curLine += *pc; + } + } + + return wxSize(widthTextMax, heightTextTotal); +} + +void wxStaticText::SetLabel(const wxString& st ) +{ + SetTitle( st ) ; + m_label = st ; + if ( !(GetWindowStyle() & wxST_NO_AUTORESIZE) ) + { + // temporary fix until layout measurement and drawing are in synch again + Refresh() ; + SetSize( GetBestSize() ) ; + } + Refresh() ; + Update() ; +} + +bool wxStaticText::SetFont(const wxFont& font) +{ + bool ret = wxControl::SetFont(font); + + if ( ret ) + { + // adjust the size of the window to fit to the label unless autoresizing is + // disabled + if ( !(GetWindowStyle() & wxST_NO_AUTORESIZE) ) + { + // temporary fix until layout measurement and drawing are in synch again + Refresh() ; + SetSize( GetBestSize() ); + } + } + + return ret; +} diff --git a/src/mac/classic/tabctrl.cpp b/src/mac/classic/tabctrl.cpp new file mode 100644 index 0000000000..f879b78447 --- /dev/null +++ b/src/mac/classic/tabctrl.cpp @@ -0,0 +1,206 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: tabctrl.cpp +// Purpose: wxTabCtrl +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "tabctrl.h" +#endif + +#include "wx/defs.h" + +#include "wx/control.h" +#include "wx/tabctrl.h" +#include "wx/mac/uma.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxTabCtrl, wxControl) + +BEGIN_EVENT_TABLE(wxTabCtrl, wxControl) +END_EVENT_TABLE() +#endif + +wxTabCtrl::wxTabCtrl() +{ + m_imageList = NULL; +} + +bool wxTabCtrl::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, + long style, const wxString& name) +{ + if ( !wxControl::Create(parent, id, pos, size, + style, wxDefaultValidator, name) ) + return false; + + Rect bounds ; + Str255 title ; + + m_imageList = NULL; + + MacPreControlCreate( parent , id , wxEmptyString , pos , size ,style, wxDefaultValidator , name , &bounds , title ) ; + + m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()) , &bounds , title , false , 0 , 0 , 1, + kControlTabSmallProc , (long) this ) ; + + MacPostControlCreate() ; + return TRUE ; +} + +wxTabCtrl::~wxTabCtrl() +{ +} + +void wxTabCtrl::Command(wxCommandEvent& event) +{ +} + +// Delete all items +bool wxTabCtrl::DeleteAllItems() +{ + // TODO + return FALSE; +} + +// Delete an item +bool wxTabCtrl::DeleteItem(int item) +{ + // TODO + return FALSE; +} + +// Get the selection +int wxTabCtrl::GetSelection() const +{ + // TODO + return 0; +} + +// Get the tab with the current keyboard focus +int wxTabCtrl::GetCurFocus() const +{ + // TODO + return 0; +} + +// Get the associated image list +wxImageList* wxTabCtrl::GetImageList() const +{ + return m_imageList; +} + +// Get the number of items +int wxTabCtrl::GetItemCount() const +{ + // TODO + return 0; +} + +// Get the rect corresponding to the tab +bool wxTabCtrl::GetItemRect(int item, wxRect& wxrect) const +{ + // TODO + return FALSE; +} + +// Get the number of rows +int wxTabCtrl::GetRowCount() const +{ + // TODO + return 0; +} + +// Get the item text +wxString wxTabCtrl::GetItemText(int item) const +{ + // TODO + return wxEmptyString; +} + +// Get the item image +int wxTabCtrl::GetItemImage(int item) const +{ + // TODO + return 0; +} + +// Get the item data +void* wxTabCtrl::GetItemData(int item) const +{ + // TODO + return NULL; +} + +// Hit test +int wxTabCtrl::HitTest(const wxPoint& pt, long& flags) +{ + // TODO + return 0; +} + +// Insert an item +bool wxTabCtrl::InsertItem(int item, const wxString& text, int imageId, void* data) +{ + // TODO + return FALSE; +} + +// Set the selection +int wxTabCtrl::SetSelection(int item) +{ + // TODO + return 0; +} + +// Set the image list +void wxTabCtrl::SetImageList(wxImageList* imageList) +{ + // TODO +} + +// Set the text for an item +bool wxTabCtrl::SetItemText(int item, const wxString& text) +{ + // TODO + return FALSE; +} + +// Set the image for an item +bool wxTabCtrl::SetItemImage(int item, int image) +{ + // TODO + return FALSE; +} + +// Set the data for an item +bool wxTabCtrl::SetItemData(int item, void* data) +{ + // TODO + return FALSE; +} + +// Set the size for a fixed-width tab control +void wxTabCtrl::SetItemSize(const wxSize& size) +{ + // TODO +} + +// Set the padding between tabs +void wxTabCtrl::SetPadding(const wxSize& padding) +{ + // TODO +} + +// Tab event +IMPLEMENT_DYNAMIC_CLASS(wxTabEvent, wxCommandEvent) + +wxTabEvent::wxTabEvent(wxEventType commandType, int id): + wxCommandEvent(commandType, id) +{ +} + diff --git a/src/mac/classic/textctrl.cpp b/src/mac/classic/textctrl.cpp new file mode 100644 index 0000000000..2b03417c0f --- /dev/null +++ b/src/mac/classic/textctrl.cpp @@ -0,0 +1,1810 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: textctrl.cpp +// Purpose: wxTextCtrl +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "textctrl.h" +#endif + +#include "wx/defs.h" + +#if wxUSE_TEXTCTRL + +#ifdef __DARWIN__ + #include + #include +#else + #include +#endif + +#include "wx/msgdlg.h" + +#if wxUSE_STD_IOSTREAM + #if wxUSE_IOSTREAMH + #include + #else + #include + #endif +#endif + +#include "wx/app.h" +#include "wx/dc.h" +#include "wx/button.h" +#include "wx/toplevel.h" +#include "wx/textctrl.h" +#include "wx/notebook.h" +#include "wx/tabctrl.h" +#include "wx/settings.h" +#include "wx/filefn.h" +#include "wx/utils.h" + +#if defined(__BORLANDC__) && !defined(__WIN32__) + #include +#elif !defined(__MWERKS__) && !defined(__GNUWIN32) && !defined(__DARWIN__) + #include +#endif + +#ifndef __DARWIN__ +#include +#endif +#include +#include +#include +#include +#include "wx/mac/uma.h" + +#define TE_UNLIMITED_LENGTH 0xFFFFFFFFUL + +extern wxControl *wxFindControlFromMacControl(ControlHandle inControl ) ; + +// CS:TODO we still have a problem getting properly at the text events of a control because under Carbon +// the MLTE engine registers itself for the key events thus the normal flow never occurs, the only measure for the +// moment is to avoid setting the true focus on the control, the proper solution at the end would be to have +// an alternate path for carbon key events that routes automatically into the same wx flow of events + +/* part codes */ + +/* kmUPTextPart is the part code we return to indicate the user has clicked + in the text area of our control */ +#define kmUPTextPart 1 + +/* kmUPScrollPart is the part code we return to indicate the user has clicked + in the scroll bar part of the control. */ +#define kmUPScrollPart 2 + + +/* routines for using existing user pane controls. + These routines are useful for cases where you would like to use an + existing user pane control in, say, a dialog window as a scrolling + text edit field.*/ + +/* mUPOpenControl initializes a user pane control so it will be drawn + and will behave as a scrolling text edit field inside of a window. + This routine performs all of the initialization steps necessary, + except it does not create the user pane control itself. theControl + should refer to a user pane control that you have either created + yourself or extracted from a dialog's control heirarchy using + the GetDialogItemAsControl routine. */ +OSStatus mUPOpenControl(ControlHandle theControl, long wxStyle); + +/* Utility Routines */ + +enum { + kShiftKeyCode = 56 +}; + +/* kUserClickedToFocusPart is a part code we pass to the SetKeyboardFocus + routine. In our focus switching routine this part code is understood + as meaning 'the user has clicked in the control and we need to switch + the current focus to ourselves before we can continue'. */ +#define kUserClickedToFocusPart 100 + + +/* kmUPClickScrollDelayTicks is a time measurement in ticks used to + slow the speed of 'auto scrolling' inside of our clickloop routine. + This value prevents the text from wizzzzzing by while the mouse + is being held down inside of the text area. */ +#define kmUPClickScrollDelayTicks 3 + + +/* STPTextPaneVars is a structure used for storing the the mUP Control's + internal variables and state information. A handle to this record is + stored in the pane control's reference value field using the + SetControlReference routine. */ + +typedef struct { + /* OS records referenced */ + TXNObject fTXNRec; /* the txn record */ + TXNFrameID fTXNFrame; /* the txn frame ID */ + ControlHandle fUserPaneRec; /* handle to the user pane control */ + WindowPtr fOwner; /* window containing control */ + GrafPtr fDrawingEnvironment; /* grafport where control is drawn */ + /* flags */ + Boolean fInFocus; /* true while the focus rect is drawn around the control */ + Boolean fIsActive; /* true while the control is drawn in the active state */ + Boolean fTEActive; /* reflects the activation state of the text edit record */ + Boolean fInDialogWindow; /* true if displayed in a dialog window */ + /* calculated locations */ + Rect fRTextArea; /* area where the text is drawn */ + Rect fRFocusOutline; /* rectangle used to draw the focus box */ + Rect fRTextOutline; /* rectangle used to draw the border */ + RgnHandle fTextBackgroundRgn; /* background region for the text, erased before calling TEUpdate */ + /* our focus advance override routine */ + EventHandlerUPP handlerUPP; + EventHandlerRef handlerRef; + bool fMultiline ; +} STPTextPaneVars; + + + + +/* Univerals Procedure Pointer variables used by the + mUP Control. These variables are set up + the first time that mUPOpenControl is called. */ +ControlUserPaneDrawUPP gTPDrawProc = NULL; +ControlUserPaneHitTestUPP gTPHitProc = NULL; +ControlUserPaneTrackingUPP gTPTrackProc = NULL; +ControlUserPaneIdleUPP gTPIdleProc = NULL; +ControlUserPaneKeyDownUPP gTPKeyProc = NULL; +ControlUserPaneActivateUPP gTPActivateProc = NULL; +ControlUserPaneFocusUPP gTPFocusProc = NULL; + +/* TPActivatePaneText activates or deactivates the text edit record + according to the value of setActive. The primary purpose of this + routine is to ensure each call is only made once. */ +static void TPActivatePaneText(STPTextPaneVars **tpvars, Boolean setActive) { + STPTextPaneVars *varsp; + varsp = *tpvars; + if (varsp->fTEActive != setActive) { + + varsp->fTEActive = setActive; + + TXNActivate(varsp->fTXNRec, varsp->fTXNFrame, varsp->fTEActive); + + if (varsp->fInFocus) + TXNFocus( varsp->fTXNRec, varsp->fTEActive); + } +} + + +/* TPFocusPaneText set the focus state for the text record. */ +static void TPFocusPaneText(STPTextPaneVars **tpvars, Boolean setFocus) { + STPTextPaneVars *varsp; + varsp = *tpvars; + if (varsp->fInFocus != setFocus) { + varsp->fInFocus = setFocus; + TXNFocus( varsp->fTXNRec, varsp->fInFocus); + } +} + + +/* TPPaneDrawProc is called to redraw the control and for update events + referring to the control. This routine erases the text area's background, + and redraws the text. This routine assumes the scroll bar has been + redrawn by a call to DrawControls. */ +static pascal void TPPaneDrawProc(ControlRef theControl, ControlPartCode thePart) { + STPTextPaneVars **tpvars, *varsp; + char state; + Rect bounds; + /* set up our globals */ + + tpvars = (STPTextPaneVars **) GetControlReference(theControl); + if (tpvars != NULL) { + state = HGetState((Handle) tpvars); + HLock((Handle) tpvars); + varsp = *tpvars; + + /* save the drawing state */ + SetPort((**tpvars).fDrawingEnvironment); + /* verify our boundary */ + GetControlBounds(theControl, &bounds); + + wxMacWindowClipper clipper( wxFindControlFromMacControl(theControl ) ) ; + if ( ! EqualRect(&bounds, &varsp->fRFocusOutline) ) { + // scrollbar is on the border, we add one + Rect oldbounds = varsp->fRFocusOutline ; + InsetRect( &oldbounds , -1 , -1 ) ; + + if ( IsControlVisible( theControl ) ) + InvalWindowRect( GetControlOwner( theControl ) , &oldbounds ) ; + SetRect(&varsp->fRFocusOutline, bounds.left, bounds.top, bounds.right, bounds.bottom); + SetRect(&varsp->fRTextOutline, bounds.left, bounds.top, bounds.right, bounds.bottom); + SetRect(&varsp->fRTextArea, bounds.left + 2 , bounds.top + (varsp->fMultiline ? 0 : 2) , + bounds.right - (varsp->fMultiline ? 0 : 2), bounds.bottom - (varsp->fMultiline ? 0 : 2)); + RectRgn(varsp->fTextBackgroundRgn, &varsp->fRTextOutline); + if ( IsControlVisible( theControl ) ) + TXNSetFrameBounds( varsp->fTXNRec, varsp->fRTextArea.top, varsp->fRTextArea.left, + varsp->fRTextArea.bottom, varsp->fRTextArea.right, varsp->fTXNFrame); + else + TXNSetFrameBounds( varsp->fTXNRec, varsp->fRTextArea.top + 30000 , varsp->fRTextArea.left + 30000 , + varsp->fRTextArea.bottom + 30000 , varsp->fRTextArea.right + 30000 , varsp->fTXNFrame); + + } + + if ( IsControlVisible( theControl ) ) + { + /* update the text region */ + RGBColor white = { 65535 , 65535 , 65535 } ; + RGBBackColor( &white ) ; + EraseRgn(varsp->fTextBackgroundRgn); + TXNDraw(varsp->fTXNRec, NULL); + /* restore the drawing environment */ + /* draw the text frame and focus frame (if necessary) */ + DrawThemeEditTextFrame(&varsp->fRTextOutline, varsp->fIsActive ? kThemeStateActive: kThemeStateInactive); + if ((**tpvars).fIsActive && varsp->fInFocus) + DrawThemeFocusRect(&varsp->fRFocusOutline, true); + /* release our globals */ + HSetState((Handle) tpvars, state); + } + } +} + + +/* TPPaneHitTestProc is called when the control manager would + like to determine what part of the control the mouse resides over. + We also call this routine from our tracking proc to determine how + to handle mouse clicks. */ +static pascal ControlPartCode TPPaneHitTestProc(ControlHandle theControl, Point where) { + STPTextPaneVars **tpvars; + ControlPartCode result; + char state; + /* set up our locals and lock down our globals*/ + result = 0; + tpvars = (STPTextPaneVars **) GetControlReference(theControl); + if (tpvars != NULL && IsControlVisible( theControl) ) { + state = HGetState((Handle) tpvars); + HLock((Handle) tpvars); + /* find the region where we clicked */ + if (PtInRect(where, &(**tpvars).fRTextArea)) { + result = kmUPTextPart; + } else result = 0; + /* release oure globals */ + HSetState((Handle) tpvars, state); + } + return result; +} + + + + + +/* TPPaneTrackingProc is called when the mouse is being held down + over our control. This routine handles clicks in the text area + and in the scroll bar. */ +static pascal ControlPartCode TPPaneTrackingProc(ControlHandle theControl, Point startPt, ControlActionUPP actionProc) { + STPTextPaneVars **tpvars, *varsp; + char state; + ControlPartCode partCodeResult; + /* make sure we have some variables... */ + partCodeResult = 0; + tpvars = (STPTextPaneVars **) GetControlReference(theControl); + if (tpvars != NULL && IsControlVisible( theControl ) ) { + /* lock 'em down */ + state = HGetState((Handle) tpvars); + HLock((Handle) tpvars); + varsp = *tpvars; + /* we don't do any of these functions unless we're in focus */ + if ( ! varsp->fInFocus) { + WindowPtr owner; + owner = GetControlOwner(theControl); + ClearKeyboardFocus(owner); + SetKeyboardFocus(owner, theControl, kUserClickedToFocusPart); + } + /* find the location for the click */ + switch (TPPaneHitTestProc(theControl, startPt)) { + + /* handle clicks in the text part */ + case kmUPTextPart: + { SetPort((**tpvars).fDrawingEnvironment); + wxMacWindowClipper clipper( wxFindControlFromMacControl(theControl ) ) ; +#if !TARGET_CARBON + TXNClick( varsp->fTXNRec, (const EventRecord*) wxTheApp->MacGetCurrentEvent()); +#else + EventRecord rec ; + ConvertEventRefToEventRecord( (EventRef) wxTheApp->MacGetCurrentEvent() , &rec ) ; + TXNClick( varsp->fTXNRec, &rec ); +#endif + } + break; + + } + + HSetState((Handle) tpvars, state); + } + return partCodeResult; +} + + +/* TPPaneIdleProc is our user pane idle routine. When our text field + is active and in focus, we use this routine to set the cursor. */ +static pascal void TPPaneIdleProc(ControlHandle theControl) { + STPTextPaneVars **tpvars, *varsp; + /* set up locals */ + tpvars = (STPTextPaneVars **) GetControlReference(theControl); + if (tpvars != NULL && IsControlVisible( theControl ) ) { + /* if we're not active, then we have nothing to say about the cursor */ + if ((**tpvars).fIsActive) { + char state; + Rect bounds; + Point mousep; + /* lock down the globals */ + state = HGetState((Handle) tpvars); + HLock((Handle) tpvars); + varsp = *tpvars; + /* get the current mouse coordinates (in our window) */ + SetPortWindowPort(GetControlOwner(theControl)); + wxMacWindowClipper clipper( wxFindControlFromMacControl(theControl ) ) ; + GetMouse(&mousep); + /* there's a 'focus thing' and an 'unfocused thing' */ + if (varsp->fInFocus) { + /* flash the cursor */ + SetPort((**tpvars).fDrawingEnvironment); + TXNIdle(varsp->fTXNRec); + /* set the cursor */ + if (PtInRect(mousep, &varsp->fRTextArea)) { + RgnHandle theRgn; + RectRgn((theRgn = NewRgn()), &varsp->fRTextArea); + TXNAdjustCursor(varsp->fTXNRec, theRgn); + DisposeRgn(theRgn); + } + else + { + // SetThemeCursor(kThemeArrowCursor); + } + } else { + /* if it's in our bounds, set the cursor */ + GetControlBounds(theControl, &bounds); + if (PtInRect(mousep, &bounds)) + { + // SetThemeCursor(kThemeArrowCursor); + } + } + + HSetState((Handle) tpvars, state); + } + } +} + + +/* TPPaneKeyDownProc is called whenever a keydown event is directed + at our control. Here, we direct the keydown event to the text + edit record and redraw the scroll bar and text field as appropriate. */ +static pascal ControlPartCode TPPaneKeyDownProc(ControlHandle theControl, + SInt16 keyCode, SInt16 charCode, SInt16 modifiers) { + STPTextPaneVars **tpvars; + tpvars = (STPTextPaneVars **) GetControlReference(theControl); + if (tpvars != NULL) { + if ((**tpvars).fInFocus) { + /* turn autoscrolling on and send the key event to text edit */ + SetPort((**tpvars).fDrawingEnvironment); + wxMacWindowClipper clipper( wxFindControlFromMacControl(theControl ) ) ; + EventRecord ev ; + memset( &ev , 0 , sizeof( ev ) ) ; + ev.what = keyDown ; + ev.modifiers = modifiers ; + ev.message = (( keyCode << 8 ) & keyCodeMask ) + ( charCode & charCodeMask ) ; + TXNKeyDown( (**tpvars).fTXNRec, &ev); + } + } + return kControlEntireControl; +} + + +/* TPPaneActivateProc is called when the window containing + the user pane control receives activate events. Here, we redraw + the control and it's text as necessary for the activation state. */ +static pascal void TPPaneActivateProc(ControlHandle theControl, Boolean activating) { + Rect bounds; + STPTextPaneVars **tpvars, *varsp; + char state; + /* set up locals */ + tpvars = (STPTextPaneVars **) GetControlReference(theControl); + if (tpvars != NULL) { + state = HGetState((Handle) tpvars); + HLock((Handle) tpvars); + varsp = *tpvars; + /* de/activate the text edit record */ + SetPort((**tpvars).fDrawingEnvironment); + wxMacWindowClipper clipper( wxFindControlFromMacControl(theControl ) ) ; + GetControlBounds(theControl, &bounds); + varsp->fIsActive = activating; + TPActivatePaneText(tpvars, varsp->fIsActive && varsp->fInFocus); + /* redraw the frame */ + if ( IsControlVisible( theControl ) ) + { + DrawThemeEditTextFrame(&varsp->fRTextOutline, varsp->fIsActive ? kThemeStateActive: kThemeStateInactive); + if (varsp->fInFocus) + DrawThemeFocusRect(&varsp->fRFocusOutline, varsp->fIsActive); + } + HSetState((Handle) tpvars, state); + } +} + + +/* TPPaneFocusProc is called when every the focus changes to or + from our control. Herein, switch the focus appropriately + according to the parameters and redraw the control as + necessary. */ +static pascal ControlPartCode TPPaneFocusProc(ControlHandle theControl, ControlFocusPart action) { + ControlPartCode focusResult; + STPTextPaneVars **tpvars, *varsp; + char state; + /* set up locals */ + focusResult = kControlFocusNoPart; + tpvars = (STPTextPaneVars **) GetControlReference(theControl); + if (tpvars != NULL ) { + state = HGetState((Handle) tpvars); + HLock((Handle) tpvars); + varsp = *tpvars; + /* if kControlFocusPrevPart and kControlFocusNextPart are received when the user is + tabbing forwards (or shift tabbing backwards) through the items in the dialog, + and kControlFocusNextPart will be received. When the user clicks in our field + and it is not the current focus, then the constant kUserClickedToFocusPart will + be received. The constant kControlFocusNoPart will be received when our control + is the current focus and the user clicks in another control. In your focus routine, + you should respond to these codes as follows: + + kControlFocusNoPart - turn off focus and return kControlFocusNoPart. redraw + the control and the focus rectangle as necessary. + + kControlFocusPrevPart or kControlFocusNextPart - toggle focus on or off + depending on its current state. redraw the control and the focus rectangle + as appropriate for the new focus state. If the focus state is 'off', return the constant + kControlFocusNoPart, otherwise return a non-zero part code. + kUserClickedToFocusPart - is a constant defined for this example. You should + define your own value for handling click-to-focus type events. */ + /* calculate the next highlight state */ + switch (action) { + default: + case kControlFocusNoPart: + TPFocusPaneText(tpvars, false); + focusResult = kControlFocusNoPart; + break; + case kUserClickedToFocusPart: + TPFocusPaneText(tpvars, true); + focusResult = 1; + break; + case kControlFocusPrevPart: + case kControlFocusNextPart: + TPFocusPaneText(tpvars, ( ! varsp->fInFocus)); + focusResult = varsp->fInFocus ? 1 : kControlFocusNoPart; + break; + } + TPActivatePaneText(tpvars, varsp->fIsActive && varsp->fInFocus); + /* redraw the text fram and focus rectangle to indicate the + new focus state */ + if ( IsControlVisible( theControl ) ) + { + /* save the drawing state */ + SetPort((**tpvars).fDrawingEnvironment); + wxMacWindowClipper clipper( wxFindControlFromMacControl(theControl ) ) ; + DrawThemeEditTextFrame(&varsp->fRTextOutline, varsp->fIsActive ? kThemeStateActive: kThemeStateInactive); + DrawThemeFocusRect(&varsp->fRFocusOutline, varsp->fIsActive && varsp->fInFocus); + } + /* done */ + HSetState((Handle) tpvars, state); + } + return focusResult; +} + + +/* mUPOpenControl initializes a user pane control so it will be drawn + and will behave as a scrolling text edit field inside of a window. + This routine performs all of the initialization steps necessary, + except it does not create the user pane control itself. theControl + should refer to a user pane control that you have either created + yourself or extracted from a dialog's control heirarchy using + the GetDialogItemAsControl routine. */ +OSStatus mUPOpenControl(ControlHandle theControl, long wxStyle ) +{ + Rect bounds; + WindowRef theWindow; + STPTextPaneVars **tpvars, *varsp; + OSStatus err = noErr ; + RGBColor rgbWhite = {0xFFFF, 0xFFFF, 0xFFFF}; + TXNBackground tback; + + /* set up our globals */ + if (gTPDrawProc == NULL) gTPDrawProc = NewControlUserPaneDrawUPP(TPPaneDrawProc); + if (gTPHitProc == NULL) gTPHitProc = NewControlUserPaneHitTestUPP(TPPaneHitTestProc); + if (gTPTrackProc == NULL) gTPTrackProc = NewControlUserPaneTrackingUPP(TPPaneTrackingProc); + if (gTPIdleProc == NULL) gTPIdleProc = NewControlUserPaneIdleUPP(TPPaneIdleProc); + if (gTPKeyProc == NULL) gTPKeyProc = NewControlUserPaneKeyDownUPP(TPPaneKeyDownProc); + if (gTPActivateProc == NULL) gTPActivateProc = NewControlUserPaneActivateUPP(TPPaneActivateProc); + if (gTPFocusProc == NULL) gTPFocusProc = NewControlUserPaneFocusUPP(TPPaneFocusProc); + + /* allocate our private storage */ + tpvars = (STPTextPaneVars **) NewHandleClear(sizeof(STPTextPaneVars)); + SetControlReference(theControl, (long) tpvars); + HLock((Handle) tpvars); + varsp = *tpvars; + /* set the initial settings for our private data */ + varsp->fMultiline = wxStyle & wxTE_MULTILINE ; + varsp->fInFocus = false; + varsp->fIsActive = true; + varsp->fTEActive = true; // in order to get a deactivate + varsp->fUserPaneRec = theControl; + theWindow = varsp->fOwner = GetControlOwner(theControl); + + varsp->fDrawingEnvironment = (GrafPtr) GetWindowPort(theWindow); + + varsp->fInDialogWindow = ( GetWindowKind(varsp->fOwner) == kDialogWindowKind ); + /* set up the user pane procedures */ + SetControlData(theControl, kControlEntireControl, kControlUserPaneDrawProcTag, sizeof(gTPDrawProc), &gTPDrawProc); + SetControlData(theControl, kControlEntireControl, kControlUserPaneHitTestProcTag, sizeof(gTPHitProc), &gTPHitProc); + SetControlData(theControl, kControlEntireControl, kControlUserPaneTrackingProcTag, sizeof(gTPTrackProc), &gTPTrackProc); + SetControlData(theControl, kControlEntireControl, kControlUserPaneIdleProcTag, sizeof(gTPIdleProc), &gTPIdleProc); + SetControlData(theControl, kControlEntireControl, kControlUserPaneKeyDownProcTag, sizeof(gTPKeyProc), &gTPKeyProc); + SetControlData(theControl, kControlEntireControl, kControlUserPaneActivateProcTag, sizeof(gTPActivateProc), &gTPActivateProc); + SetControlData(theControl, kControlEntireControl, kControlUserPaneFocusProcTag, sizeof(gTPFocusProc), &gTPFocusProc); + /* calculate the rectangles used by the control */ + GetControlBounds(theControl, &bounds); + SetRect(&varsp->fRFocusOutline, bounds.left, bounds.top, bounds.right, bounds.bottom); + SetRect(&varsp->fRTextOutline, bounds.left, bounds.top, bounds.right, bounds.bottom); + SetRect(&varsp->fRTextArea, bounds.left + 2 , bounds.top + (varsp->fMultiline ? 0 : 2) , + bounds.right - (varsp->fMultiline ? 0 : 2), bounds.bottom - (varsp->fMultiline ? 0 : 2)); + /* calculate the background region for the text. In this case, it's kindof + and irregular region because we're setting the scroll bar a little ways inside + of the text area. */ + RectRgn((varsp->fTextBackgroundRgn = NewRgn()), &varsp->fRTextOutline); + + /* set up the drawing environment */ + SetPort(varsp->fDrawingEnvironment); + + /* create the new edit field */ + + TXNFrameOptions frameOptions = + kTXNDontDrawCaretWhenInactiveMask ; + if ( ! ( wxStyle & wxTE_NOHIDESEL ) ) + frameOptions |= kTXNDontDrawSelectionWhenInactiveMask ; + + if ( wxStyle & wxTE_MULTILINE ) + { + if ( ! ( wxStyle & wxTE_DONTWRAP ) ) + frameOptions |= kTXNAlwaysWrapAtViewEdgeMask ; + else + { + frameOptions |= kTXNAlwaysWrapAtViewEdgeMask ; + frameOptions |= kTXNWantHScrollBarMask ; + } + + if ( !(wxStyle & wxTE_NO_VSCROLL ) ) + frameOptions |= kTXNWantVScrollBarMask ; + } + else + frameOptions |= kTXNSingleLineOnlyMask ; + + if ( wxStyle & wxTE_READONLY ) + frameOptions |= kTXNReadOnlyMask ; + + TXNNewObject(NULL, varsp->fOwner, &varsp->fRTextArea, + frameOptions , + kTXNTextEditStyleFrameType, + kTXNTextensionFile, + kTXNSystemDefaultEncoding, + &varsp->fTXNRec, &varsp->fTXNFrame, (TXNObjectRefcon) tpvars); + + if ( !IsControlVisible( theControl ) ) + TXNSetFrameBounds( varsp->fTXNRec, varsp->fRTextArea.top + 30000 , varsp->fRTextArea.left + 30000 , + varsp->fRTextArea.bottom + 30000 , varsp->fRTextArea.right + 30000 , varsp->fTXNFrame); + + + if ( (wxStyle & wxTE_MULTILINE) && (wxStyle & wxTE_DONTWRAP) ) + { + TXNControlTag tag = kTXNWordWrapStateTag ; + TXNControlData dat ; + dat.uValue = kTXNNoAutoWrap ; + TXNSetTXNObjectControls( varsp->fTXNRec , false , 1 , &tag , &dat ) ; + } + Str255 fontName ; + SInt16 fontSize ; + Style fontStyle ; + + GetThemeFont(kThemeSmallSystemFont , GetApplicationScript() , fontName , &fontSize , &fontStyle ) ; + + TXNTypeAttributes typeAttr[] = + { + { kTXNQDFontNameAttribute , kTXNQDFontNameAttributeSize , { (void*) fontName } } , + { kTXNQDFontSizeAttribute , kTXNFontSizeAttributeSize , { (void*) (fontSize << 16) } } , + { kTXNQDFontStyleAttribute , kTXNQDFontStyleAttributeSize , { (void*) normal } } , + } ; + + err = TXNSetTypeAttributes (varsp->fTXNRec, sizeof( typeAttr ) / sizeof(TXNTypeAttributes) , typeAttr, + kTXNStartOffset, + kTXNEndOffset); + /* set the field's background */ + + tback.bgType = kTXNBackgroundTypeRGB; + tback.bg.color = rgbWhite; + TXNSetBackground( varsp->fTXNRec, &tback); + + /* unlock our storage */ + HUnlock((Handle) tpvars); + /* perform final activations and setup for our text field. Here, + we assume that the window is going to be the 'active' window. */ + TPActivatePaneText(tpvars, varsp->fIsActive && varsp->fInFocus); + /* all done */ + return err; +} + + + + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl) + +BEGIN_EVENT_TABLE(wxTextCtrl, wxControl) + EVT_DROP_FILES(wxTextCtrl::OnDropFiles) + EVT_CHAR(wxTextCtrl::OnChar) + EVT_MENU(wxID_CUT, wxTextCtrl::OnCut) + EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy) + EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste) + EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo) + EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo) + + EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut) + EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy) + EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste) + EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo) + EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo) +END_EVENT_TABLE() +#endif + +static void SetTXNData( TXNObject txn , const wxString& st , TXNOffset start , TXNOffset end ) +{ +#if wxUSE_UNICODE +#if SIZEOF_WCHAR_T == 2 + size_t len = st.Len() ; + TXNSetData( txn , kTXNUnicodeTextData, (void*)st.wc_str(), len * 2, + start, end); +#else + wxMBConvUTF16BE converter ; + ByteCount byteBufferLen = converter.WC2MB( NULL , st.wc_str() , 0 ) ; + UniChar *unibuf = (UniChar*) malloc(byteBufferLen) ; + converter.WC2MB( (char*) unibuf , st.wc_str() , byteBufferLen ) ; + TXNSetData( txn , kTXNUnicodeTextData, (void*)unibuf, byteBufferLen , + start, end); + free( unibuf ) ; +#endif +#else + wxCharBuffer text = st.mb_str(wxConvLocal) ; + TXNSetData( txn , kTXNTextData, (void*)text.data(), strlen( text ) , + start, end); +#endif +} + +// Text item +void wxTextCtrl::Init() +{ + m_macTE = NULL ; + m_macTXN = NULL ; + m_macTXNvars = NULL ; + m_macUsesTXN = false ; + + m_editable = true ; + m_dirty = false; + + m_maxLength = TE_UNLIMITED_LENGTH ; +} + +wxTextCtrl::~wxTextCtrl() +{ + if ( m_macUsesTXN ) + { + SetControlReference((ControlHandle)m_macControl, 0) ; + TXNDeleteObject((TXNObject)m_macTXN); + /* delete our private storage */ + DisposeHandle((Handle) m_macTXNvars); + /* zero the control reference */ + } +} + +const short kVerticalMargin = 2 ; +const short kHorizontalMargin = 2 ; + +bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id, + const wxString& str, + const wxPoint& pos, + const wxSize& size, long style, + const wxValidator& validator, + const wxString& name) +{ + m_macTE = NULL ; + m_macTXN = NULL ; + m_macTXNvars = NULL ; + m_macUsesTXN = false ; + m_editable = true ; + + m_macUsesTXN = ! (style & wxTE_PASSWORD ) ; + + m_macUsesTXN &= (TXNInitTextension != (void*) kUnresolvedCFragSymbolAddress) ; + + // base initialization + if ( !wxTextCtrlBase::Create(parent, id, pos, size, style & ~(wxHSCROLL|wxVSCROLL), validator, name) ) + return FALSE; + + wxSize mySize = size ; + if ( m_macUsesTXN ) + { + m_macHorizontalBorder = 5 ; // additional pixels around the real control + m_macVerticalBorder = 3 ; + } + else + { + m_macHorizontalBorder = 5 ; // additional pixels around the real control + m_macVerticalBorder = 5 ; + } + + + Rect bounds ; + Str255 title ; + /* + if ( mySize.y == -1 ) + { + mySize.y = 13 ; + if ( m_windowStyle & wxTE_MULTILINE ) + mySize.y *= 5 ; + + mySize.y += 2 * m_macVerticalBorder ; + } + */ + MacPreControlCreate( parent , id , wxEmptyString , pos , mySize ,style, validator , name , &bounds , title ) ; + + if ( m_windowStyle & wxTE_MULTILINE ) + { + wxASSERT_MSG( !(m_windowStyle & wxTE_PROCESS_ENTER), + wxT("wxTE_PROCESS_ENTER style is ignored for multiline text controls (they always process it)") ); + + m_windowStyle |= wxTE_PROCESS_ENTER; + } + + if ( m_windowStyle & wxTE_READONLY) + { + m_editable = FALSE ; + } + + wxString st = str ; + wxMacConvertNewlines13To10( &st ) ; + if ( !m_macUsesTXN ) + { + m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()) , &bounds , "\p" , false , 0 , 0 , 1, + (style & wxTE_PASSWORD) ? kControlEditTextPasswordProc : kControlEditTextProc , (long) this ) ; + long size ; + ::GetControlData((ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*)((TEHandle *)&m_macTE) , &size ) ; + + } + else + { + short featurSet; + + featurSet = kControlSupportsEmbedding | kControlSupportsFocus | kControlWantsIdle + | kControlWantsActivate | kControlHandlesTracking | kControlHasSpecialBackground + | kControlGetsFocusOnClick | kControlSupportsLiveFeedback; + /* create the control */ + m_macControl = NewControl(MAC_WXHWND(parent->MacGetRootWindow()), &bounds, "\p", false , featurSet, 0, featurSet, kControlUserPaneProc, 0); + /* set up the mUP specific features and data */ + mUPOpenControl((ControlHandle) m_macControl, m_windowStyle ); + } + MacPostControlCreate() ; + + if ( !m_macUsesTXN ) + { + wxCharBuffer text = st.mb_str(wxConvLocal) ; + ::SetControlData( (ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , strlen(text) , text ) ; + } + else + { + STPTextPaneVars **tpvars; + /* set up locals */ + tpvars = (STPTextPaneVars **) GetControlReference((ControlHandle) m_macControl); + /* set the text in the record */ + m_macTXN = (**tpvars).fTXNRec ; + SetTXNData( (TXNObject) m_macTXN , st , kTXNStartOffset, kTXNEndOffset ) ; + m_macTXNvars = tpvars ; + m_macUsesTXN = true ; + TXNSetSelection( (TXNObject) m_macTXN, 0, 0); + TXNShowSelection( (TXNObject) m_macTXN, kTXNShowStart); + } + + return TRUE; +} + +wxString wxTextCtrl::GetValue() const +{ + Size actualSize = 0; + wxString result ; + OSStatus err ; + if ( !m_macUsesTXN ) + { + err = ::GetControlDataSize((ControlHandle) m_macControl, 0, + ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag, &actualSize ) ; + + if ( err ) + return wxEmptyString ; + + if ( actualSize > 0 ) + { + wxCharBuffer buf(actualSize) ; + ::GetControlData( (ControlHandle) m_macControl, 0, + ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag, + actualSize , buf.data() , &actualSize ) ; + result = wxString( buf , wxConvLocal) ; + } + } + else + { +#if wxUSE_UNICODE + Handle theText ; + err = TXNGetDataEncoded( ((TXNObject) m_macTXN), kTXNStartOffset, kTXNEndOffset, &theText , kTXNUnicodeTextData ); + // all done + if ( err ) + { + actualSize = 0 ; + } + else + { + actualSize = GetHandleSize( theText ) / sizeof( UniChar) ; + if ( actualSize > 0 ) + { + wxChar *ptr = result.GetWriteBuf(actualSize*sizeof(wxChar)) ; +#if SIZEOF_WCHAR_T == 2 + wxStrncpy( ptr , (wxChar*) *theText , actualSize ) ; +#else + wxMBConvUTF16BE converter ; + HLock( theText ) ; + converter.MB2WC( ptr , (const char*)*theText , actualSize ) ; + HUnlock( theText ) ; +#endif + ptr[actualSize] = 0 ; + result.UngetWriteBuf( actualSize *sizeof(wxChar) ) ; + } + DisposeHandle( theText ) ; + } +#else + Handle theText ; + err = TXNGetDataEncoded( ((TXNObject) m_macTXN), kTXNStartOffset, kTXNEndOffset, &theText , kTXNTextData ); + // all done + if ( err ) + { + actualSize = 0 ; + } + else + { + actualSize = GetHandleSize( theText ) ; + if ( actualSize > 0 ) + { + HLock( theText ) ; + result = wxString( *theText , wxConvLocal , actualSize ) ; + HUnlock( theText ) ; + } + DisposeHandle( theText ) ; + } +#endif + } + wxMacConvertNewlines10To13( &result ) ; + return result ; +} + +void wxTextCtrl::GetSelection(long* from, long* to) const +{ + if ( !m_macUsesTXN ) + { + *from = (**((TEHandle) m_macTE)).selStart; + *to = (**((TEHandle) m_macTE)).selEnd; + } + else + { + TXNGetSelection( (TXNObject) m_macTXN , (TXNOffset*) from , (TXNOffset*) to ) ; + } +} + +void wxTextCtrl::SetValue(const wxString& str) +{ + wxString st = str ; + wxMacConvertNewlines13To10( &st ) ; + if ( !m_macUsesTXN ) + { + wxCharBuffer text = st.mb_str(wxConvLocal) ; + ::SetControlData( (ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , strlen(text) , text ) ; + } + else + { + bool formerEditable = m_editable ; + if ( !formerEditable ) + SetEditable(true) ; + SetTXNData( (TXNObject) m_macTXN , st , kTXNStartOffset, kTXNEndOffset ) ; + TXNSetSelection( (TXNObject) m_macTXN, 0, 0); + TXNShowSelection( (TXNObject) m_macTXN, kTXNShowStart); + if ( !formerEditable ) + SetEditable(formerEditable) ; + } + MacRedrawControl() ; +} + +void wxTextCtrl::SetMaxLength(unsigned long len) +{ + m_maxLength = len ; +} + +bool wxTextCtrl::SetStyle(long start, long end, const wxTextAttr& style) +{ + if ( m_macUsesTXN ) + { + bool formerEditable = m_editable ; + if ( !formerEditable ) + SetEditable(true) ; + TXNTypeAttributes typeAttr[4] ; + Str255 fontName = "\pMonaco" ; + SInt16 fontSize = 12 ; + Style fontStyle = normal ; + RGBColor color ; + int attrCounter = 0 ; + if ( style.HasFont() ) + { + const wxFont &font = style.GetFont() ; + wxMacStringToPascal( font.GetFaceName() , fontName ) ; + fontSize = font.GetPointSize() ; + if ( font.GetUnderlined() ) + fontStyle |= underline ; + if ( font.GetWeight() == wxBOLD ) + fontStyle |= bold ; + if ( font.GetStyle() == wxITALIC ) + fontStyle |= italic ; + + typeAttr[attrCounter].tag = kTXNQDFontNameAttribute ; + typeAttr[attrCounter].size = kTXNQDFontNameAttributeSize ; + typeAttr[attrCounter].data.dataPtr = (void*) fontName ; + typeAttr[attrCounter+1].tag = kTXNQDFontSizeAttribute ; + typeAttr[attrCounter+1].size = kTXNFontSizeAttributeSize ; + typeAttr[attrCounter+1].data.dataValue = (fontSize << 16) ; + typeAttr[attrCounter+2].tag = kTXNQDFontStyleAttribute ; + typeAttr[attrCounter+2].size = kTXNQDFontStyleAttributeSize ; + typeAttr[attrCounter+2].data.dataValue = fontStyle ; + attrCounter += 3 ; + + } + if ( style.HasTextColour() ) + { + typeAttr[attrCounter].tag = kTXNQDFontColorAttribute ; + typeAttr[attrCounter].size = kTXNQDFontColorAttributeSize ; + typeAttr[attrCounter].data.dataPtr = (void*) &color ; + color = MAC_WXCOLORREF(style.GetTextColour().GetPixel()) ; + attrCounter += 1 ; + } + + if ( attrCounter > 0 ) + { +#ifdef __WXDEBUG__ + OSStatus status = +#endif // __WXDEBUG__ + TXNSetTypeAttributes ((TXNObject)m_macTXN, attrCounter , typeAttr, start,end); + wxASSERT_MSG( status == noErr , wxT("Couldn't set text attributes") ) ; + } + if ( !formerEditable ) + SetEditable(formerEditable) ; + } + return TRUE ; +} + +bool wxTextCtrl::SetDefaultStyle(const wxTextAttr& style) +{ + wxTextCtrlBase::SetDefaultStyle( style ) ; + SetStyle( kTXNUseCurrentSelection , kTXNUseCurrentSelection , GetDefaultStyle() ) ; + return TRUE ; +} + +// Clipboard operations +void wxTextCtrl::Copy() +{ + if (CanCopy()) + { + if ( !m_macUsesTXN ) + { + TECopy( ((TEHandle) m_macTE) ) ; + ClearCurrentScrap(); + TEToScrap() ; + MacRedrawControl() ; + } + else + { + ClearCurrentScrap(); + TXNCopy((TXNObject)m_macTXN); + TXNConvertToPublicScrap(); + } + } +} + +void wxTextCtrl::Cut() +{ + if (CanCut()) + { + if ( !m_macUsesTXN ) + { + TECut( ((TEHandle) m_macTE) ) ; + ClearCurrentScrap(); + TEToScrap() ; + MacRedrawControl() ; + } + else + { + ClearCurrentScrap(); + TXNCut((TXNObject)m_macTXN); + TXNConvertToPublicScrap(); + } + wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_windowId); + event.SetString( GetValue() ) ; + event.SetEventObject( this ); + GetEventHandler()->ProcessEvent(event); + } +} + +void wxTextCtrl::Paste() +{ + if (CanPaste()) + { + if ( !m_macUsesTXN ) + { + TEFromScrap() ; + TEPaste( (TEHandle) m_macTE ) ; + MacRedrawControl() ; + } + else + { + TXNConvertFromPublicScrap(); + TXNPaste((TXNObject)m_macTXN); + SetStyle( kTXNUseCurrentSelection , kTXNUseCurrentSelection , GetDefaultStyle() ) ; + } + wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_windowId); + event.SetString( GetValue() ) ; + event.SetEventObject( this ); + GetEventHandler()->ProcessEvent(event); + } +} + +bool wxTextCtrl::CanCopy() const +{ + // Can copy if there's a selection + long from, to; + GetSelection(& from, & to); + return (from != to); +} + +bool wxTextCtrl::CanCut() const +{ + if ( !IsEditable() ) + { + return false ; + } + // Can cut if there's a selection + long from, to; + GetSelection(& from, & to); + return (from != to); +} + +bool wxTextCtrl::CanPaste() const +{ + if (!IsEditable()) + return FALSE; + +#if TARGET_CARBON + OSStatus err = noErr; + ScrapRef scrapRef; + + err = GetCurrentScrap( &scrapRef ); + if ( err != noTypeErr && err != memFullErr ) + { + ScrapFlavorFlags flavorFlags; + Size byteCount; + + if (( err = GetScrapFlavorFlags( scrapRef, 'TEXT', &flavorFlags )) == noErr) + { + if (( err = GetScrapFlavorSize( scrapRef, 'TEXT', &byteCount )) == noErr) + { + return TRUE ; + } + } + } + return FALSE; + +#else + long offset ; + if ( GetScrap( NULL , 'TEXT' , &offset ) > 0 ) + { + return TRUE ; + } +#endif + return FALSE ; +} + +void wxTextCtrl::SetEditable(bool editable) +{ + if ( editable != m_editable ) + { + m_editable = editable ; + if ( !m_macUsesTXN ) + { + if ( editable ) + UMAActivateControl( (ControlHandle) m_macControl ) ; + else + UMADeactivateControl((ControlHandle) m_macControl ) ; + } + else + { + TXNControlTag tag[] = { kTXNIOPrivilegesTag } ; + TXNControlData data[] = { { editable ? kTXNReadWrite : kTXNReadOnly } } ; + TXNSetTXNObjectControls( (TXNObject) m_macTXN , false , sizeof(tag) / sizeof (TXNControlTag) , tag , data ) ; + } + } +} + +void wxTextCtrl::SetInsertionPoint(long pos) +{ + SetSelection( pos , pos ) ; +} + +void wxTextCtrl::SetInsertionPointEnd() +{ + long pos = GetLastPosition(); + SetInsertionPoint(pos); +} + +long wxTextCtrl::GetInsertionPoint() const +{ + long begin,end ; + GetSelection( &begin , &end ) ; + return begin ; +} + +long wxTextCtrl::GetLastPosition() const +{ + if ( !m_macUsesTXN ) + { + return (**((TEHandle) m_macTE)).teLength ; + } + else + { + Handle theText ; + long actualsize ; + OSErr err = TXNGetDataEncoded( (TXNObject) m_macTXN, kTXNStartOffset, kTXNEndOffset, &theText , kTXNTextData ); + /* all done */ + if ( err ) + { + actualsize = 0 ; + } + else + { + actualsize = GetHandleSize( theText ) ; + DisposeHandle( theText ) ; + } + return actualsize ; + } +} + +void wxTextCtrl::Replace(long from, long to, const wxString& str) +{ + wxString value = str ; + wxMacConvertNewlines13To10( &value ) ; + if ( !m_macUsesTXN ) + { + ControlEditTextSelectionRec selection ; + + selection.selStart = from ; + selection.selEnd = to ; + ::SetControlData((ControlHandle) m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection ) ; + TESetSelect( from , to , ((TEHandle) m_macTE) ) ; + TEDelete( ((TEHandle) m_macTE) ) ; + TEInsert( value , value.Length() , ((TEHandle) m_macTE) ) ; + } + else + { + bool formerEditable = m_editable ; + if ( !formerEditable ) + SetEditable(true) ; + TXNSetSelection( ((TXNObject) m_macTXN) , from , to ) ; + TXNClear( ((TXNObject) m_macTXN) ) ; + SetTXNData( (TXNObject) m_macTXN , str , kTXNUseCurrentSelection, kTXNUseCurrentSelection ) ; + if ( !formerEditable ) + SetEditable( formerEditable ) ; + } + Refresh() ; +} + +void wxTextCtrl::Remove(long from, long to) +{ + if ( !m_macUsesTXN ) + { + ControlEditTextSelectionRec selection ; + + selection.selStart = from ; + selection.selEnd = to ; + ::SetControlData( (ControlHandle) m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection ) ; + TEDelete( ((TEHandle) m_macTE) ) ; + } + else + { + bool formerEditable = m_editable ; + if ( !formerEditable ) + SetEditable(true) ; + TXNSetSelection( ((TXNObject) m_macTXN) , from , to ) ; + TXNClear( ((TXNObject) m_macTXN) ) ; + if ( !formerEditable ) + SetEditable( formerEditable ) ; + } + Refresh() ; +} + +void wxTextCtrl::SetSelection(long from, long to) +{ + if ( !m_macUsesTXN ) + { + ControlEditTextSelectionRec selection ; + if ((from == -1) && (to == -1)) + { + selection.selStart = 0 ; + selection.selEnd = 32767 ; + } + else + { + selection.selStart = from ; + selection.selEnd = to ; + } + + TESetSelect( selection.selStart , selection.selEnd , ((TEHandle) m_macTE) ) ; + ::SetControlData((ControlHandle) m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection ) ; + } + else + { + STPTextPaneVars **tpvars; + /* set up our locals */ + tpvars = (STPTextPaneVars **) GetControlReference((ControlHandle) m_macControl); + /* and our drawing environment as the operation + may force a redraw in the text area. */ + SetPort((**tpvars).fDrawingEnvironment); + /* change the selection */ + if ((from == -1) && (to == -1)) + TXNSelectAll((TXNObject) m_macTXN); + else + TXNSetSelection( (**tpvars).fTXNRec, from, to); + TXNShowSelection( (TXNObject) m_macTXN, kTXNShowStart); + } +} + +bool wxTextCtrl::LoadFile(const wxString& file) +{ + if ( wxTextCtrlBase::LoadFile(file) ) + { + return TRUE; + } + + return FALSE; +} + +void wxTextCtrl::WriteText(const wxString& str) +{ + wxString st = str ; + wxMacConvertNewlines13To10( &st ) ; + if ( !m_macUsesTXN ) + { + wxCharBuffer text = st.mb_str(wxConvLocal) ; + TEInsert( text , strlen(text) , ((TEHandle) m_macTE) ) ; + } + else + { + bool formerEditable = m_editable ; + if ( !formerEditable ) + SetEditable(true) ; + long start , end , dummy ; + GetSelection( &start , &dummy ) ; + SetTXNData( (TXNObject) m_macTXN , st , kTXNUseCurrentSelection, kTXNUseCurrentSelection ) ; + GetSelection( &dummy , &end ) ; + SetStyle( start , end , GetDefaultStyle() ) ; + if ( !formerEditable ) + SetEditable( formerEditable ) ; + } + MacRedrawControl() ; +} + +void wxTextCtrl::AppendText(const wxString& text) +{ + SetInsertionPointEnd(); + WriteText(text); +} + +void wxTextCtrl::Clear() +{ + if ( !m_macUsesTXN ) + { + ::SetControlData((ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , 0 , (char*) ((const char*)NULL) ) ; + } + else + { + TXNSetSelection( (TXNObject)m_macTXN , kTXNStartOffset , kTXNEndOffset ) ; + TXNClear((TXNObject)m_macTXN); + } + Refresh() ; +} + +bool wxTextCtrl::IsModified() const +{ + return m_dirty; +} + +bool wxTextCtrl::IsEditable() const +{ + return IsEnabled() && m_editable ; +} + +bool wxTextCtrl::AcceptsFocus() const +{ + // we don't want focus if we can't be edited + return /*IsEditable() && */ wxControl::AcceptsFocus(); +} + +wxSize wxTextCtrl::DoGetBestSize() const +{ + int wText = 100 ; + + int hText; + if ( m_macUsesTXN ) + { + hText = 17 ; + } + else + { + hText = 13 ; + } +/* + int cx, cy; + wxGetCharSize(GetHWND(), &cx, &cy, &GetFont()); + + int wText = DEFAULT_ITEM_WIDTH; + + int hText = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy); + + return wxSize(wText, hText); +*/ + if ( m_windowStyle & wxTE_MULTILINE ) + { + hText *= 5 ; + } + hText += 2 * m_macVerticalBorder ; + wText += 2 * m_macHorizontalBorder ; + //else: for single line control everything is ok + return wxSize(wText, hText); +} + +// ---------------------------------------------------------------------------- +// Undo/redo +// ---------------------------------------------------------------------------- + +void wxTextCtrl::Undo() +{ + if (CanUndo()) + { + if ( m_macUsesTXN ) + { + TXNUndo((TXNObject)m_macTXN); + } + } +} + +void wxTextCtrl::Redo() +{ + if (CanRedo()) + { + if ( m_macUsesTXN ) + { + TXNRedo((TXNObject)m_macTXN); + } + } +} + +bool wxTextCtrl::CanUndo() const +{ + if ( !IsEditable() ) + { + return false ; + } + if ( m_macUsesTXN ) + { + return TXNCanUndo((TXNObject)m_macTXN,NULL); + } + return FALSE ; +} + +bool wxTextCtrl::CanRedo() const +{ + if ( !IsEditable() ) + { + return false ; + } + if ( m_macUsesTXN ) + { + return TXNCanRedo((TXNObject)m_macTXN,NULL); + } + return FALSE ; +} + +// Makes modifie or unmodified +void wxTextCtrl::MarkDirty() +{ + m_dirty = true; +} + +void wxTextCtrl::DiscardEdits() +{ + m_dirty = false; +} + +int wxTextCtrl::GetNumberOfLines() const +{ + if ( m_macUsesTXN ) + { + ItemCount lines ; + TXNGetLineCount((TXNObject)m_macTXN, &lines ) ; + return lines ; + } + else + { + wxString content = GetValue() ; + + int count = 1; + for (size_t i = 0; i < content.Length() ; i++) + { + if (content[i] == '\r') count++; + } + return count; + } +} + +long wxTextCtrl::XYToPosition(long x, long y) const +{ + // TODO + return 0; +} + +bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const +{ + return FALSE ; +} + +void wxTextCtrl::ShowPosition(long pos) +{ +#if TARGET_RT_MAC_MACHO && defined(AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER) + if ( m_macUsesTXN ) + { + Point current ; + Point desired ; + TXNOffset selstart , selend ; + TXNGetSelection( (TXNObject) m_macTXN , &selstart , &selend) ; + TXNOffsetToPoint( (TXNObject) m_macTXN, selstart , ¤t); + TXNOffsetToPoint( (TXNObject) m_macTXN, pos , &desired); + //TODO use HIPoints for 10.3 and above + if ( (UInt32) TXNScroll != (UInt32) kUnresolvedCFragSymbolAddress ) + { + OSErr theErr = noErr; + SInt32 dv = desired.v - current.v ; + SInt32 dh = desired.h - current.h ; + TXNShowSelection( (TXNObject) m_macTXN , true ) ; + theErr = TXNScroll( (TXNObject) m_macTXN, kTXNScrollUnitsInPixels , kTXNScrollUnitsInPixels , &dv , &dh ); + wxASSERT_MSG( theErr == noErr, _T("TXNScroll returned an error!") ); + } + } +#endif +} + +int wxTextCtrl::GetLineLength(long lineNo) const +{ + // TODO change this if possible to reflect real lines + wxString content = GetValue() ; + + // Find line first + int count = 0; + for (size_t i = 0; i < content.Length() ; i++) + { + if (count == lineNo) + { + // Count chars in line then + count = 0; + for (size_t j = i; j < content.Length(); j++) + { + count++; + if (content[j] == '\n') return count; + } + + return count; + } + if (content[i] == '\n') count++; + } + return 0; +} + +wxString wxTextCtrl::GetLineText(long lineNo) const +{ + // TODO change this if possible to reflect real lines + wxString content = GetValue() ; + + // Find line first + int count = 0; + for (size_t i = 0; i < content.Length() ; i++) + { + if (count == lineNo) + { + // Add chars in line then + wxString tmp; + + for (size_t j = i; j < content.Length(); j++) + { + if (content[j] == '\n') + return tmp; + + tmp += content[j]; + } + + return tmp; + } + if (content[i] == '\n') count++; + } + return wxEmptyString ; +} + +/* + * Text item + */ + +void wxTextCtrl::Command(wxCommandEvent & event) +{ + SetValue (event.GetString()); + ProcessCommand (event); +} + +void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event) +{ + // By default, load the first file into the text window. + if (event.GetNumberOfFiles() > 0) + { + LoadFile(event.GetFiles()[0]); + } +} + +void wxTextCtrl::OnChar(wxKeyEvent& event) +{ + int key = event.GetKeyCode() ; + bool eat_key = false ; + + if ( key == 'c' && event.MetaDown() ) + { + if ( CanCopy() ) + Copy() ; + return ; + } + + if ( !IsEditable() && key != WXK_LEFT && key != WXK_RIGHT && key != WXK_DOWN && key != WXK_UP && key != WXK_TAB && + !( key == WXK_RETURN && ( (m_windowStyle & wxPROCESS_ENTER) || (m_windowStyle & wxTE_MULTILINE) ) ) +/* && key != WXK_PRIOR && key != WXK_NEXT && key != WXK_HOME && key != WXK_END */ + ) + { + // eat it + return ; + } + + // assume that any key not processed yet is going to modify the control + m_dirty = true; + + if ( key == 'v' && event.MetaDown() ) + { + if ( CanPaste() ) + Paste() ; + return ; + } + if ( key == 'x' && event.MetaDown() ) + { + if ( CanCut() ) + Cut() ; + return ; + } + switch ( key ) + { + case WXK_RETURN: + if (m_windowStyle & wxPROCESS_ENTER) + { + wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId); + event.SetEventObject( this ); + event.SetString( GetValue() ); + if ( GetEventHandler()->ProcessEvent(event) ) + return; + } + if ( !(m_windowStyle & wxTE_MULTILINE) ) + { + wxWindow *parent = GetParent(); + while( parent && !parent->IsTopLevel() && parent->GetDefaultItem() == NULL ) { + parent = parent->GetParent() ; + } + if ( parent && parent->GetDefaultItem() ) + { + wxButton *def = wxDynamicCast(parent->GetDefaultItem(), + wxButton); + if ( def && def->IsEnabled() ) + { + wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() ); + event.SetEventObject(def); + def->Command(event); + return ; + } + } + + // this will make wxWindows eat the ENTER key so that + // we actually prevent line wrapping in a single line + // text control + eat_key = TRUE; + } + + break; + + case WXK_TAB: + // always produce navigation event - even if we process TAB + // ourselves the fact that we got here means that the user code + // decided to skip processing of this TAB - probably to let it + // do its default job. + { + wxNavigationKeyEvent eventNav; + eventNav.SetDirection(!event.ShiftDown()); + eventNav.SetWindowChange(event.ControlDown()); + eventNav.SetEventObject(this); + + if ( GetParent()->GetEventHandler()->ProcessEvent(eventNav) ) + return; + + event.Skip() ; + return; + } + break; + } + + if (!eat_key) + { + // perform keystroke handling +#if TARGET_CARBON + if ( m_macUsesTXN && wxTheApp->MacGetCurrentEvent() != NULL && wxTheApp->MacGetCurrentEventHandlerCallRef() != NULL ) + CallNextEventHandler((EventHandlerCallRef)wxTheApp->MacGetCurrentEventHandlerCallRef() , (EventRef) wxTheApp->MacGetCurrentEvent() ) ; + else + { + EventRecord rec ; + if ( wxMacConvertEventToRecord( (EventRef) wxTheApp->MacGetCurrentEvent() , &rec ) ) + { + EventRecord *ev = &rec ; + short keycode ; + short keychar ; + keychar = short(ev->message & charCodeMask); + keycode = short(ev->message & keyCodeMask) >> 8 ; + + ::HandleControlKey( (ControlHandle) m_macControl , keycode , keychar , ev->modifiers ) ; + } + } +#else + EventRecord *ev = (EventRecord*) wxTheApp->MacGetCurrentEvent() ; + short keycode ; + short keychar ; + keychar = short(ev->message & charCodeMask); + keycode = short(ev->message & keyCodeMask) >> 8 ; + + ::HandleControlKey( (ControlHandle) m_macControl , keycode , keychar , ev->modifiers ) ; +#endif + } + if ( ( key >= 0x20 && key < WXK_START ) || + key == WXK_RETURN || + key == WXK_DELETE || + key == WXK_BACK) + { + wxCommandEvent event1(wxEVT_COMMAND_TEXT_UPDATED, m_windowId); + event1.SetString( GetValue() ) ; + event1.SetEventObject( this ); + wxPostEvent(GetEventHandler(),event1); + } +} + +void wxTextCtrl::MacSuperShown( bool show ) +{ + bool former = m_macControlIsShown ; + wxControl::MacSuperShown( show ) ; + if ( (former != m_macControlIsShown) && m_macUsesTXN ) + { + if ( m_macControlIsShown ) + TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left, + (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom,(**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame); + else + TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left, + (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame); + } +} + +bool wxTextCtrl::Show(bool show) +{ + bool former = m_macControlIsShown ; + + bool retval = wxControl::Show( show ) ; + + if ( former != m_macControlIsShown && m_macUsesTXN ) + { + if ( m_macControlIsShown ) + TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left, + (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom,(**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame); + else + TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left, + (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame); + } + + return retval ; +} + +// ---------------------------------------------------------------------------- +// standard handlers for standard edit menu events +// ---------------------------------------------------------------------------- + +void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event)) +{ + Cut(); +} + +void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event)) +{ + Copy(); +} + +void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event)) +{ + Paste(); +} + +void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event)) +{ + Undo(); +} + +void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event)) +{ + Redo(); +} + +void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event) +{ + event.Enable( CanCut() ); +} + +void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event) +{ + event.Enable( CanCopy() ); +} + +void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event) +{ + event.Enable( CanPaste() ); +} + +void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event) +{ + event.Enable( CanUndo() ); +} + +void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event) +{ + event.Enable( CanRedo() ); +} + +bool wxTextCtrl::MacSetupCursor( const wxPoint& pt ) +{ + if ( m_macUsesTXN ) + return true ; + else + return wxWindow::MacSetupCursor( pt ) ; +} + +#endif + // wxUSE_TEXTCTRL diff --git a/src/mac/classic/tglbtn.cpp b/src/mac/classic/tglbtn.cpp new file mode 100644 index 0000000000..aa7ee2bb3e --- /dev/null +++ b/src/mac/classic/tglbtn.cpp @@ -0,0 +1,127 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: src/mac/tglbtn.cpp +// Purpose: Definition of the wxToggleButton class, which implements a +// toggle button under wxMac. +// Author: Stefan Csomor +// Modified by: +// Created: 08.02.01 +// RCS-ID: $Id$ +// Copyright: (c) 2000 Johnny C. Norris II +// License: Rocketeer license +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declatations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#ifdef __GNUG__ +#pragma implementation "button.h" +#endif + +#include "wx/defs.h" +#include "wx/tglbtn.h" + +#if wxUSE_TOGGLEBTN + +#include "wx/mac/uma.h" +// Button + +static const int kMacOSXHorizontalBorder = 2 ; +static const int kMacOSXVerticalBorder = 4 ; + +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxToggleButton, wxControl) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxToggleButton +// ---------------------------------------------------------------------------- + +// Single check box item +bool wxToggleButton::Create(wxWindow *parent, wxWindowID id, + const wxString& label, + const wxPoint& pos, + const wxSize& size, long style, + const wxValidator& validator, + const wxString& name) +{ + if ( !wxControl::Create(parent, id, pos, size, style, validator, name) ) + return false; + + Rect bounds ; + Str255 title ; + + if ( UMAHasAquaLayout() ) + { + m_macHorizontalBorder = kMacOSXHorizontalBorder; + m_macVerticalBorder = kMacOSXVerticalBorder; + } + + MacPreControlCreate( parent , id , label , pos , size ,style, validator , name , &bounds , title ) ; + + m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()) , &bounds , title , false , 0 , kControlBehaviorToggles , 1, + kControlBevelButtonNormalBevelProc , (long) this ) ; + wxASSERT_MSG( (ControlHandle) m_macControl != NULL , wxT("No valid mac control") ) ; + + MacPostControlCreate() ; + + return TRUE; +} + +wxSize wxToggleButton::DoGetBestSize() const +{ + int wBtn = 70 ; + int hBtn = 20 ; + + int lBtn = m_label.Length() * 8 + 12 ; + if (lBtn > wBtn) + wBtn = lBtn; + + if ( UMAHasAquaLayout() ) + { + wBtn += 2 * kMacOSXHorizontalBorder ; + hBtn += 2 * kMacOSXVerticalBorder ; + } + return wxSize ( wBtn , hBtn ) ; +} + +void wxToggleButton::SetValue(bool val) +{ + ::SetControl32BitValue( (ControlHandle) m_macControl , val ) ; +} + +bool wxToggleButton::GetValue() const +{ + return GetControl32BitValue( (ControlHandle) m_macControl ) ; +} + +void wxToggleButton::Command(wxCommandEvent & event) +{ + SetValue((event.GetInt() != 0)); + ProcessCommand(event); +} + +void wxToggleButton::MacHandleControlClick( WXWidget WXUNUSED(control) , wxInt16 controlpart , bool WXUNUSED(mouseStillDown) ) +{ + if ( controlpart != kControlNoPart ) + { + wxCommandEvent event(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, m_windowId); + event.SetInt(GetValue()); + event.SetEventObject(this); + ProcessCommand(event); + } +} + +#endif // wxUSE_TOGGLEBTN + diff --git a/src/mac/classic/thread.cpp b/src/mac/classic/thread.cpp new file mode 100644 index 0000000000..5e322a719d --- /dev/null +++ b/src/mac/classic/thread.cpp @@ -0,0 +1,921 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: thread.cpp +// Purpose: wxThread Implementation +// Author: Original from Wolfram Gloger/Guilhem Lavaux/Vadim Zeitlin +// Modified by: Stefan Csomor +// Created: 04/22/98 +// RCS-ID: $Id$ +// Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998), +// Vadim Zeitlin (1999) , Stefan Csomor (2000) +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ + #pragma implementation "thread.h" +#endif + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if defined(__BORLANDC__) + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/wx.h" +#endif + +#if wxUSE_THREADS + +#include "wx/module.h" +#include "wx/thread.h" + +#ifdef __WXMAC__ +#include +#include "wx/mac/uma.h" +#include "wx/mac/macnotfy.h" +#include +#endif + +#define INFINITE 0xFFFFFFFF + + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// the possible states of the thread ("=>" shows all possible transitions from +// this state) +enum wxThreadState +{ + STATE_NEW, // didn't start execution yet (=> RUNNING) + STATE_RUNNING, // thread is running (=> PAUSED, CANCELED) + STATE_PAUSED, // thread is temporarily suspended (=> RUNNING) + STATE_CANCELED, // thread should terminate a.s.a.p. (=> EXITED) + STATE_EXITED // thread is terminating +}; + +// ---------------------------------------------------------------------------- +// this module globals +// ---------------------------------------------------------------------------- + +static ThreadID gs_idMainThread = kNoThreadID ; +static bool gs_waitingForThread = FALSE ; +size_t g_numberOfThreads = 0; + +// ============================================================================ +// MacOS implementation of thread classes +// ============================================================================ + +class wxMacStCritical +{ +public : + wxMacStCritical() + { + if ( UMASystemIsInitialized() ) + ThreadBeginCritical() ; + } + ~wxMacStCritical() + { + if ( UMASystemIsInitialized() ) + ThreadEndCritical() ; + } +}; + +// ---------------------------------------------------------------------------- +// wxMutex implementation +// ---------------------------------------------------------------------------- + +class wxMutexInternal +{ +public: + wxMutexInternal(wxMutexType WXUNUSED(mutexType)) + { + m_owner = kNoThreadID ; + m_locked = 0; + } + + ~wxMutexInternal() + { + if ( m_locked > 0 ) + { + wxLogDebug(_T("Warning: freeing a locked mutex (%ld locks)."), m_locked); + } + } + + bool IsOk() const { return true; } + + wxMutexError Lock() ; + wxMutexError TryLock() ; + wxMutexError Unlock(); +public: + ThreadID m_owner ; + wxArrayLong m_waiters ; + long m_locked ; +}; + +wxMutexError wxMutexInternal::Lock() +{ + wxMacStCritical critical ; + if ( UMASystemIsInitialized() ) + { + OSErr err ; + ThreadID current = kNoThreadID; + err = ::MacGetCurrentThread(¤t); + // if we are not the owner, add this thread to the list of waiting threads, stop this thread + // and invoke the scheduler to continue executing the owner's thread + while ( m_owner != kNoThreadID && m_owner != current) + { + m_waiters.Add(current); + err = ::SetThreadStateEndCritical(kCurrentThreadID, kStoppedThreadState, m_owner); + err = ::ThreadBeginCritical(); + } + m_owner = current; + } + m_locked++; + + return wxMUTEX_NO_ERROR; +} + +wxMutexError wxMutexInternal::TryLock() +{ + wxMacStCritical critical ; + if ( UMASystemIsInitialized() ) + { + ThreadID current = kNoThreadID; + ::MacGetCurrentThread(¤t); + // if we are not the owner, give an error back + if ( m_owner != kNoThreadID && m_owner != current ) + return wxMUTEX_BUSY; + + m_owner = current; + } + m_locked++; + + return wxMUTEX_NO_ERROR; +} + +wxMutexError wxMutexInternal::Unlock() +{ + if ( UMASystemIsInitialized() ) + { + OSErr err; + err = ::ThreadBeginCritical(); + + if (m_locked > 0) + m_locked--; + + // this mutex is not owned by anybody anmore + m_owner = kNoThreadID; + + // now pass on to the first waiting thread + ThreadID firstWaiting = kNoThreadID; + bool found = false; + while (!m_waiters.IsEmpty() && !found) + { + firstWaiting = m_waiters[0]; + err = ::SetThreadState(firstWaiting, kReadyThreadState, kNoThreadID); + // in case this was not successful (dead thread), we just loop on and reset the id + found = (err != threadNotFoundErr); + if ( !found ) + firstWaiting = kNoThreadID ; + m_waiters.RemoveAt(0) ; + } + // now we have a valid firstWaiting thread, which has been scheduled to run next, just end the + // critical section and invoke the scheduler + err = ::SetThreadStateEndCritical(kCurrentThreadID, kReadyThreadState, firstWaiting); + } + else + { + if (m_locked > 0) + m_locked--; + } + return wxMUTEX_NO_ERROR; +} + +// -------------------------------------------------------------------------- +// wxSemaphore +// -------------------------------------------------------------------------- + +// TODO not yet implemented + +class wxSemaphoreInternal +{ +public: + wxSemaphoreInternal(int initialcount, int maxcount); + ~wxSemaphoreInternal(); + + bool IsOk() const { return true ; } + + wxSemaError Wait() { return WaitTimeout(INFINITE); } + wxSemaError TryWait() { return WaitTimeout(0); } + wxSemaError WaitTimeout(unsigned long milliseconds); + + wxSemaError Post(); + +private: +}; + +wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount) +{ + if ( maxcount == 0 ) + { + // make it practically infinite + maxcount = INT_MAX; + } +} + +wxSemaphoreInternal::~wxSemaphoreInternal() +{ +} + +wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds) +{ + return wxSEMA_MISC_ERROR; +} + +wxSemaError wxSemaphoreInternal::Post() +{ + return wxSEMA_MISC_ERROR; +} + +// ---------------------------------------------------------------------------- +// wxCondition implementation +// ---------------------------------------------------------------------------- + +// TODO this is not yet completed + +class wxConditionInternal +{ +public: + wxConditionInternal(wxMutex& mutex) : m_mutex(mutex) + { + m_excessSignals = 0 ; + } + ~wxConditionInternal() + { + } + + bool IsOk() const { return m_mutex.IsOk() ; } + + wxCondError Wait() + { + return WaitTimeout(0xFFFFFFFF ); + } + + wxCondError WaitTimeout(unsigned long msectimeout) + { + wxMacStCritical critical ; + if ( m_excessSignals > 0 ) + { + --m_excessSignals ; + return wxCOND_NO_ERROR ; + } + else if ( msectimeout == 0 ) + { + return wxCOND_MISC_ERROR ; + } + else + { + } + /* + waiters++; + + // FIXME this should be MsgWaitForMultipleObjects() as well probably + DWORD rc = ::WaitForSingleObject(event, timeout); + + waiters--; + + return rc != WAIT_TIMEOUT; + */ + return wxCOND_NO_ERROR ; + } + wxCondError Signal() + { + wxMacStCritical critical ; + return wxCOND_NO_ERROR; + } + + wxCondError Broadcast() + { + wxMacStCritical critical ; + return wxCOND_NO_ERROR; + } + + wxArrayLong m_waiters ; + wxInt32 m_excessSignals ; + wxMutex& m_mutex; +}; + +// ---------------------------------------------------------------------------- +// wxCriticalSection implementation +// ---------------------------------------------------------------------------- + +// it's implemented as a mutex on mac os, so it is defined in the headers + +// ---------------------------------------------------------------------------- +// wxThread implementation +// ---------------------------------------------------------------------------- + +// wxThreadInternal class +// ---------------------- + +class wxThreadInternal +{ +public: + wxThreadInternal() + { + m_tid = kNoThreadID ; + m_state = STATE_NEW; + m_priority = WXTHREAD_DEFAULT_PRIORITY; + } + + ~wxThreadInternal() + { + } + + void Free() + { + } + + // create a new (suspended) thread (for the given thread object) + bool Create(wxThread *thread, unsigned int stackSize); + + // suspend/resume/terminate + bool Suspend(); + bool Resume(); + void Cancel() { m_state = STATE_CANCELED; } + + // thread state + void SetState(wxThreadState state) { m_state = state; } + wxThreadState GetState() const { return m_state; } + + // thread priority + void SetPriority(unsigned int priority); + unsigned int GetPriority() const { return m_priority; } + + void SetResult( void *res ) { m_result = res ; } + void *GetResult() { return m_result ; } + + // thread handle and id + ThreadID GetId() const { return m_tid; } + + // thread function + static pascal void* MacThreadStart(wxThread* arg); + +private: + wxThreadState m_state; // state, see wxThreadState enum + unsigned int m_priority; // thread priority in "wx" units + ThreadID m_tid; // thread id + void* m_result; + static ThreadEntryUPP s_threadEntry ; +}; + +static wxArrayPtrVoid s_threads ; + +ThreadEntryUPP wxThreadInternal::s_threadEntry = NULL ; +pascal void* wxThreadInternal::MacThreadStart(wxThread *thread) +{ + // first of all, check whether we hadn't been cancelled already + if ( thread->m_internal->GetState() == STATE_EXITED ) + { + return (void*)-1; + } + + void* rc = thread->Entry(); + + // enter m_critsect before changing the thread state + thread->m_critsect.Enter(); + bool wasCancelled = thread->m_internal->GetState() == STATE_CANCELED; + thread->m_internal->SetState(STATE_EXITED); + thread->m_critsect.Leave(); + + thread->OnExit(); + + // if the thread was cancelled (from Delete()), then it the handle is still + // needed there + if ( thread->IsDetached() && !wasCancelled ) + { + // auto delete + delete thread; + } + //else: the joinable threads handle will be closed when Wait() is done + + return rc; +} +void wxThreadInternal::SetPriority(unsigned int priority) +{ + // Priorities don't exist on Mac +} + +bool wxThreadInternal::Create(wxThread *thread, unsigned int stackSize) +{ + if ( s_threadEntry == NULL ) + { + s_threadEntry = NewThreadEntryUPP( (ThreadEntryProcPtr) MacThreadStart ) ; + } + OSErr err = NewThread( kCooperativeThread, + s_threadEntry, + (void*) thread, + stackSize, + kNewSuspend, + &m_result, + &m_tid ); + + if ( err != noErr ) + { + wxLogSysError(_("Can't create thread")); + return FALSE; + } + + if ( m_priority != WXTHREAD_DEFAULT_PRIORITY ) + { + SetPriority(m_priority); + } + + m_state = STATE_NEW; + + return TRUE; +} + +bool wxThreadInternal::Suspend() +{ + OSErr err ; + + ::ThreadBeginCritical(); + + if ( m_state != STATE_RUNNING ) + { + ::ThreadEndCritical() ; + wxLogSysError(_("Can not suspend thread %x"), m_tid); + return FALSE; + } + + m_state = STATE_PAUSED; + + err = ::SetThreadStateEndCritical(m_tid, kStoppedThreadState, kNoThreadID); + + return TRUE; +} + +bool wxThreadInternal::Resume() +{ + ThreadID current ; + OSErr err ; + err = MacGetCurrentThread( ¤t ) ; + + wxASSERT( err == noErr ) ; + wxASSERT( current != m_tid ) ; + + ::ThreadBeginCritical(); + if ( m_state != STATE_PAUSED && m_state != STATE_NEW ) + { + ::ThreadEndCritical() ; + wxLogSysError(_("Can not resume thread %x"), m_tid); + return FALSE; + + } + err = ::SetThreadStateEndCritical(m_tid, kReadyThreadState, kNoThreadID); + wxASSERT( err == noErr ) ; + + m_state = STATE_RUNNING; + ::ThreadEndCritical() ; + ::YieldToAnyThread() ; + return TRUE; +} + +// static functions +// ---------------- +wxThread *wxThread::This() +{ + wxMacStCritical critical ; + + ThreadID current ; + OSErr err ; + + err = MacGetCurrentThread( ¤t ) ; + + for ( size_t i = 0 ; i < s_threads.Count() ; ++i ) + { + if ( ( (wxThread*) s_threads[i] )->GetId() == current ) + return (wxThread*) s_threads[i] ; + } + + wxLogSysError(_("Couldn't get the current thread pointer")); + return NULL; +} + +bool wxThread::IsMain() +{ + ThreadID current ; + OSErr err ; + + err = MacGetCurrentThread( ¤t ) ; + return current == gs_idMainThread; +} + +#ifdef Yield +#undef Yield +#endif + +void wxThread::Yield() +{ + ::YieldToAnyThread() ; +} + +void wxThread::Sleep(unsigned long milliseconds) +{ + UnsignedWide start, now; + + Microseconds(&start); + + double mssleep = milliseconds * 1000 ; + double msstart, msnow ; + msstart = (start.hi * 4294967296.0 + start.lo) ; + + do + { + YieldToAnyThread(); + Microseconds(&now); + msnow = (now.hi * 4294967296.0 + now.lo) ; + } while( msnow - msstart < mssleep ); +} + +int wxThread::GetCPUCount() +{ + // we will use whatever MP API will be used for the new MP Macs + return 1; +} + +unsigned long wxThread::GetCurrentId() +{ + ThreadID current ; + MacGetCurrentThread( ¤t ) ; + return (unsigned long)current; +} + +bool wxThread::SetConcurrency(size_t level) +{ + wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") ); + + // ok only for the default one + if ( level == 0 ) + return 0; + + // how many CPUs have we got? + if ( GetCPUCount() == 1 ) + { + // don't bother with all this complicated stuff - on a single + // processor system it doesn't make much sense anyhow + return level == 1; + } + + return TRUE ; +} + +// ctor and dtor +// ------------- + +wxThread::wxThread(wxThreadKind kind) +{ + g_numberOfThreads++; + m_internal = new wxThreadInternal(); + + m_isDetached = kind == wxTHREAD_DETACHED; + s_threads.Add( (void*) this ) ; +} + +wxThread::~wxThread() +{ + if (g_numberOfThreads>0) + { + g_numberOfThreads--; + } +#ifdef __WXDEBUG__ + else + { + wxFAIL_MSG(wxT("More threads deleted than created.")); + } +#endif + + s_threads.Remove( (void*) this ) ; + if (m_internal != NULL) { + delete m_internal; + m_internal = NULL; + } +} + +// create/start thread +// ------------------- + +wxThreadError wxThread::Create(unsigned int stackSize) +{ + wxCriticalSectionLocker lock(m_critsect); + + if ( !m_internal->Create(this, stackSize) ) + return wxTHREAD_NO_RESOURCE; + + return wxTHREAD_NO_ERROR; +} + +wxThreadError wxThread::Run() +{ + wxCriticalSectionLocker lock(m_critsect); + + if ( m_internal->GetState() != STATE_NEW ) + { + // actually, it may be almost any state at all, not only STATE_RUNNING + return wxTHREAD_RUNNING; + } + + // the thread has just been created and is still suspended - let it run + return Resume(); +} + +// suspend/resume thread +// --------------------- + +wxThreadError wxThread::Pause() +{ + wxCriticalSectionLocker lock(m_critsect); + + return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR; +} + +wxThreadError wxThread::Resume() +{ + wxCriticalSectionLocker lock(m_critsect); + + return m_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR; +} + +// stopping thread +// --------------- + +wxThread::ExitCode wxThread::Wait() +{ + // although under MacOS we can wait for any thread, it's an error to + // wait for a detached one in wxWin API + wxCHECK_MSG( !IsDetached(), (ExitCode)-1, + _T("can't wait for detached thread") ); + + ExitCode rc = (ExitCode)-1; + + (void)Delete(&rc); + + m_internal->Free(); + + return rc; +} + +wxThreadError wxThread::Delete(ExitCode *pRc) +{ + ExitCode rc = 0; + + // Delete() is always safe to call, so consider all possible states + + // has the thread started to run? + bool shouldResume = FALSE; + + { + wxCriticalSectionLocker lock(m_critsect); + + if ( m_internal->GetState() == STATE_NEW ) + { + // WinThreadStart() will see it and terminate immediately + m_internal->SetState(STATE_EXITED); + + shouldResume = TRUE; + } + } + + // is the thread paused? + if ( shouldResume || IsPaused() ) + Resume(); + + // does is still run? + if ( IsRunning() ) + { + if ( IsMain() ) + { + // set flag for wxIsWaitingForThread() + gs_waitingForThread = TRUE; + +#if wxUSE_GUI + wxBeginBusyCursor(); +#endif // wxUSE_GUI + } + + // ask the thread to terminate + { + wxCriticalSectionLocker lock(m_critsect); + + m_internal->Cancel(); + } + +#if wxUSE_GUI + // simply wait for the thread to terminate + while( TestDestroy() ) + { + ::YieldToAnyThread() ; + } +#else // !wxUSE_GUI + // simply wait for the thread to terminate + while( TestDestroy() ) + { + ::YieldToAnyThread() ; + } +#endif // wxUSE_GUI/!wxUSE_GUI + + if ( IsMain() ) + { + gs_waitingForThread = FALSE; + +#if wxUSE_GUI + wxEndBusyCursor(); +#endif // wxUSE_GUI + } + } + + if ( IsDetached() ) + { + // if the thread exits normally, this is done in WinThreadStart, but in + // this case it would have been too early because + // MsgWaitForMultipleObject() would fail if the therad handle was + // closed while we were waiting on it, so we must do it here + delete this; + } + + if ( pRc ) + *pRc = rc; + + return rc == (ExitCode)-1 ? wxTHREAD_MISC_ERROR : wxTHREAD_NO_ERROR; +} + +wxThreadError wxThread::Kill() +{ + if ( !IsRunning() ) + return wxTHREAD_NOT_RUNNING; + +// if ( !::TerminateThread(m_internal->GetHandle(), (DWORD)-1) ) + { + wxLogSysError(_("Couldn't terminate thread")); + + return wxTHREAD_MISC_ERROR; + } + + m_internal->Free(); + + if ( IsDetached() ) + { + delete this; + } + + return wxTHREAD_NO_ERROR; +} + +void wxThread::Exit(ExitCode status) +{ + m_internal->Free(); + + if ( IsDetached() ) + { + delete this; + } + + m_internal->SetResult( status ) ; + +/* +#if defined(__VISUALC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500)) + _endthreadex((unsigned)status); +#else // !VC++ + ::ExitThread((DWORD)status); +#endif // VC++/!VC++ +*/ + wxFAIL_MSG(wxT("Couldn't return from ExitThread()!")); +} + +// priority setting +// ---------------- + +// since all these calls are execute cooperatively we don't have to use the critical section + +void wxThread::SetPriority(unsigned int prio) +{ + m_internal->SetPriority(prio); +} + +unsigned int wxThread::GetPriority() const +{ + return m_internal->GetPriority(); +} + +unsigned long wxThread::GetId() const +{ + return (unsigned long)m_internal->GetId(); +} + +bool wxThread::IsRunning() const +{ + return m_internal->GetState() == STATE_RUNNING; +} + +bool wxThread::IsAlive() const +{ + return (m_internal->GetState() == STATE_RUNNING) || + (m_internal->GetState() == STATE_PAUSED); +} + +bool wxThread::IsPaused() const +{ + return m_internal->GetState() == STATE_PAUSED; +} + +bool wxThread::TestDestroy() +{ + return m_internal->GetState() == STATE_CANCELED; +} + +// ---------------------------------------------------------------------------- +// Automatic initialization for thread module +// ---------------------------------------------------------------------------- + +class wxThreadModule : public wxModule +{ +public: + virtual bool OnInit(); + virtual void OnExit(); + +private: + DECLARE_DYNAMIC_CLASS(wxThreadModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule) + +bool wxThreadModule::OnInit() +{ + long response; + bool hasThreadManager ; + hasThreadManager = Gestalt( gestaltThreadMgrAttr, &response) == noErr && response & 1; +#if !TARGET_CARBON +#if GENERATINGCFM + // verify presence of shared library + hasThreadManager = hasThreadManager && ((Ptr)NewThread != (Ptr)kUnresolvedCFragSymbolAddress); +#endif +#endif + if ( !hasThreadManager ) + { + wxLogSysError( wxT("Thread Support is not available on this System") ); + return FALSE ; + } + + // no error return for GetCurrentThreadId() + MacGetCurrentThread( &gs_idMainThread ) ; + + return TRUE; +} + +void wxThreadModule::OnExit() +{ +} + +// ---------------------------------------------------------------------------- +// under MacOS we don't have currently preemptive threads, so any thread may access +// the GUI at any time +// ---------------------------------------------------------------------------- + +void WXDLLEXPORT wxMutexGuiEnter() +{ +} + +void WXDLLEXPORT wxMutexGuiLeave() +{ +} + +void WXDLLEXPORT wxMutexGuiLeaveOrEnter() +{ +} + +bool WXDLLEXPORT wxGuiOwnedByMainThread() +{ + return false ; +} + +// wake up the main thread +void WXDLLEXPORT wxWakeUpMainThread() +{ + wxMacWakeUp() ; +} + +bool WXDLLEXPORT wxIsWaitingForThread() +{ + return false ; +} + +#include "wx/thrimpl.cpp" + +#endif // wxUSE_THREADS diff --git a/src/mac/classic/timer.cpp b/src/mac/classic/timer.cpp new file mode 100644 index 0000000000..a639e2c464 --- /dev/null +++ b/src/mac/classic/timer.cpp @@ -0,0 +1,143 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: timer.cpp +// Purpose: wxTimer implementation +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "timer.h" +#endif + +#include "wx/timer.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_ABSTRACT_CLASS(wxTimer, wxObject) +#endif + +#ifdef __WXMAC__ +#include "wx/mac/private.h" +#endif +#ifndef __DARWIN__ +#include +#endif + +#include "wx/dynarray.h" + +typedef struct MacTimerInfo +{ + TMTask m_task; + wxMacNotifierTableRef m_table ; + wxTimer* m_timer ; +} ; + +static void wxProcessTimer( unsigned long event , void *data ) ; + +static pascal void MacTimerProc( TMTask * t ) +{ + MacTimerInfo * tm = (MacTimerInfo*) t ; + wxMacAddEvent( tm->m_table , wxProcessTimer, 0 , (void*) tm->m_timer , TRUE ) ; +} + +// we need this array to track timers that are being deleted within the Notify procedure +// adding the timer before the Notify call and checking after whether it still is in there +// as the destructor would have removed it from the array + +wxArrayPtrVoid gTimersInProcess ; + +static void wxProcessTimer( unsigned long event , void *data ) +{ + if ( !data ) + return ; + + wxTimer* timer = (wxTimer*) data ; + + if ( timer->IsOneShot() ) + timer->Stop() ; + + gTimersInProcess.Add( timer ) ; + + timer->Notify(); + + int index = gTimersInProcess.Index( timer ) ; + + if ( index != wxNOT_FOUND ) + { + gTimersInProcess.RemoveAt( index ) ; + + if ( !timer->IsOneShot() && timer->m_info->m_task.tmAddr ) + { + PrimeTime( (QElemPtr) &timer->m_info->m_task , timer->GetInterval() ) ; + } + + } +} + +void wxTimer::Init() +{ + m_info = new MacTimerInfo() ; + m_info->m_task.tmAddr = NULL ; + m_info->m_task.tmWakeUp = 0 ; + m_info->m_task.tmReserved = 0 ; + m_info->m_task.qType = 0 ; + m_info->m_table = wxMacGetNotifierTable() ; + m_info->m_timer = this ; +} + +bool wxTimer::IsRunning() const +{ + // as the qType may already indicate it is elapsed, but it + // was not handled internally yet + return ( m_info->m_task.tmAddr != NULL ) ; +} + +wxTimer::~wxTimer() +{ + Stop(); + if (m_info != NULL) { + delete m_info ; + m_info = NULL ; + } + int index = gTimersInProcess.Index( this ) ; + if ( index != wxNOT_FOUND ) + gTimersInProcess.RemoveAt( index ) ; +} + +bool wxTimer::Start(int milliseconds,bool mode) +{ + (void)wxTimerBase::Start(milliseconds, mode); + + wxCHECK_MSG( m_milli > 0, FALSE, wxT("invalid value for timer timeout") ); + wxCHECK_MSG( m_info->m_task.tmAddr == NULL , FALSE, wxT("attempting to restart a timer") ); + +#if defined(UNIVERSAL_INTERFACES_VERSION) && (UNIVERSAL_INTERFACES_VERSION >= 0x0340) + m_info->m_task.tmAddr = NewTimerUPP( MacTimerProc ) ; +#else + m_info->m_task.tmAddr = NewTimerProc( MacTimerProc ) ; +#endif + m_info->m_task.tmWakeUp = 0 ; + m_info->m_task.tmReserved = 0 ; + m_info->m_task.qType = 0 ; + m_info->m_timer = this ; + InsXTime((QElemPtr) &m_info->m_task ) ; + PrimeTime( (QElemPtr) &m_info->m_task , m_milli ) ; + return TRUE; +} + +void wxTimer::Stop() +{ + if ( m_info->m_task.tmAddr ) + { + RmvTime( (QElemPtr) &m_info->m_task ) ; + DisposeTimerUPP(m_info->m_task.tmAddr) ; + m_info->m_task.tmAddr = NULL ; + } + wxMacRemoveAllNotifiersForData( wxMacGetNotifierTable() , this ) ; +} + + + diff --git a/src/mac/classic/toolbar.cpp b/src/mac/classic/toolbar.cpp new file mode 100644 index 0000000000..d8bdac1326 --- /dev/null +++ b/src/mac/classic/toolbar.cpp @@ -0,0 +1,620 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: toolbar.cpp +// Purpose: wxToolBar +// Author: Stefan Csomor +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: The wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "toolbar.h" +#endif + +#include "wx/wx.h" + +#if wxUSE_TOOLBAR + +#include "wx/toolbar.h" +#include "wx/notebook.h" +#include "wx/tabctrl.h" +#include "wx/bitmap.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxToolBar, wxControl) + +BEGIN_EVENT_TABLE(wxToolBar, wxToolBarBase) + EVT_MOUSE_EVENTS( wxToolBar::OnMouse ) + EVT_PAINT( wxToolBar::OnPaint ) +END_EVENT_TABLE() +#endif + +#include "wx/mac/uma.h" +#include "wx/geometry.h" +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +class wxToolBarTool : public wxToolBarToolBase +{ +public: + wxToolBarTool(wxToolBar *tbar, + int id, + const wxString& label, + const wxBitmap& bmpNormal, + const wxBitmap& bmpDisabled, + wxItemKind kind, + wxObject *clientData, + const wxString& shortHelp, + const wxString& longHelp) ; + + wxToolBarTool(wxToolBar *tbar, wxControl *control) + : wxToolBarToolBase(tbar, control) + { + Init() ; + } + + ~wxToolBarTool() + { + if ( m_controlHandle ) + DisposeControl( m_controlHandle ) ; + } + + ControlHandle GetControlHandle() { return m_controlHandle ; } + void SetControlHandle( ControlHandle handle ) { m_controlHandle = handle ; } + + void SetSize(const wxSize& size) ; + void SetPosition( const wxPoint& position ) ; + wxSize GetSize() const + { + if ( IsControl() ) + { + return GetControl()->GetSize() ; + } + else if ( IsButton() ) + { + return GetToolBar()->GetToolSize() ; + } + else + { + wxSize sz = GetToolBar()->GetToolSize() ; + sz.x /= 4 ; + sz.y /= 4 ; + return sz ; + } + } + wxPoint GetPosition() const + { + return wxPoint(m_x, m_y); + } +private : + void Init() + { + m_controlHandle = NULL ; + } + ControlHandle m_controlHandle ; + + wxCoord m_x; + wxCoord m_y; +}; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxToolBarTool +// ---------------------------------------------------------------------------- + +void wxToolBarTool::SetSize(const wxSize& size) +{ + if ( IsControl() ) + { + GetControl()->SetSize( size ) ; + } +} + +void wxToolBarTool::SetPosition(const wxPoint& position) +{ + m_x = position.x; + m_y = position.y; + + if ( IsButton() ) + { + int x , y ; + x = y = 0 ; + WindowRef rootwindow = (WindowRef) GetToolBar()->MacGetRootWindow() ; + GetToolBar()->MacWindowToRootWindow( &x , &y ) ; + int mac_x = x + position.x ; + int mac_y = y + position.y ; + + + Rect contrlRect ; + GetControlBounds( m_controlHandle , &contrlRect ) ; + int former_mac_x = contrlRect.left ; + int former_mac_y = contrlRect.top ; + wxSize sz = GetToolBar()->GetToolSize() ; + + if ( mac_x != former_mac_x || mac_y != former_mac_y ) + { + { + Rect inval = { former_mac_y , former_mac_x , former_mac_y + sz.y , former_mac_x + sz.x } ; + InvalWindowRect( rootwindow , &inval ) ; + } + UMAMoveControl( m_controlHandle , mac_x , mac_y ) ; + { + Rect inval = { mac_y , mac_x , mac_y + sz.y , mac_x + sz.x } ; + InvalWindowRect( rootwindow , &inval ) ; + } + } + } + else if ( IsControl() ) + { + GetControl()->Move( position ) ; + } +} + +const short kwxMacToolBarToolDefaultWidth = 24 ; +const short kwxMacToolBarToolDefaultHeight = 22 ; +const short kwxMacToolBarTopMargin = 2 ; +const short kwxMacToolBarLeftMargin = 2 ; + +wxToolBarTool::wxToolBarTool(wxToolBar *tbar, + int id, + const wxString& label, + const wxBitmap& bmpNormal, + const wxBitmap& bmpDisabled, + wxItemKind kind, + wxObject *clientData, + const wxString& shortHelp, + const wxString& longHelp) + : wxToolBarToolBase(tbar, id, label, bmpNormal, bmpDisabled, kind, + clientData, shortHelp, longHelp) +{ + Init(); + + if (id == wxID_SEPARATOR) return; + + WindowRef window = (WindowRef) tbar->MacGetRootWindow() ; + wxSize toolSize = tbar->GetToolSize() ; + Rect toolrect = { 0, 0 , toolSize.y , toolSize.x } ; + + ControlButtonContentInfo info ; + wxMacCreateBitmapButton( &info , GetNormalBitmap() ) ; + + SInt16 behaviour = kControlBehaviorOffsetContents ; + if ( CanBeToggled() ) + behaviour += kControlBehaviorToggles ; + + if ( info.contentType != kControlNoContent ) + { + m_controlHandle = ::NewControl( window , &toolrect , "\p" , false , 0 , + behaviour + info.contentType , 0 , kControlBevelButtonNormalBevelProc , (long) this ) ; + + ::SetControlData( m_controlHandle , kControlButtonPart , kControlBevelButtonContentTag , sizeof(info) , (char*) &info ) ; + } + else + { + m_controlHandle = ::NewControl( window , &toolrect , "\p" , false , 0 , + behaviour , 0 , kControlBevelButtonNormalBevelProc , (long) this ) ; + } + UMAShowControl( m_controlHandle ) ; + if ( !IsEnabled() ) + { + UMADeactivateControl( m_controlHandle ) ; + } + if ( CanBeToggled() && IsToggled() ) + { + ::SetControl32BitValue( m_controlHandle , 1 ) ; + } + else + { + ::SetControl32BitValue( m_controlHandle , 0 ) ; + } + + ControlHandle container = (ControlHandle) tbar->MacGetContainerForEmbedding() ; + wxASSERT_MSG( container != NULL , wxT("No valid mac container control") ) ; + ::EmbedControl( m_controlHandle , container ) ; +} + + +wxToolBarToolBase *wxToolBar::CreateTool(int id, + const wxString& label, + const wxBitmap& bmpNormal, + const wxBitmap& bmpDisabled, + wxItemKind kind, + wxObject *clientData, + const wxString& shortHelp, + const wxString& longHelp) +{ + return new wxToolBarTool(this, id, label, bmpNormal, bmpDisabled, kind, + clientData, shortHelp, longHelp); +} + +wxToolBarToolBase *wxToolBar::CreateTool(wxControl *control) +{ + return new wxToolBarTool(this, control); +} + +void wxToolBar::Init() +{ + m_maxWidth = -1; + m_maxHeight = -1; + m_defaultWidth = kwxMacToolBarToolDefaultWidth; + m_defaultHeight = kwxMacToolBarToolDefaultHeight; +} + +bool wxToolBar::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, + long style, const wxString& name) +{ + int x = pos.x; + int y = pos.y; + int width = size.x; + int height = size.y; + + if (width <= 0) + width = 100; + if (height <= 0) + height = 30; + if (x < 0) + x = 0; + if (y < 0) + y = 0; + + SetName(name); + + m_windowStyle = style; + parent->AddChild(this); + + m_backgroundColour = parent->GetBackgroundColour() ; + m_foregroundColour = parent->GetForegroundColour() ; + + if (id == -1) + m_windowId = NewControlId(); + else + m_windowId = id; + + { + m_width = size.x ; + m_height = size.y ; + int x = pos.x ; + int y = pos.y ; + AdjustForParentClientOrigin(x, y, wxSIZE_USE_EXISTING); + m_x = x ; + m_y = y ; + } + + return TRUE; +} + +wxToolBar::~wxToolBar() +{ + // we must refresh the frame size when the toolbar is deleted but the frame + // is not - otherwise toolbar leaves a hole in the place it used to occupy +} + +bool wxToolBar::Realize() +{ + if (m_tools.GetCount() == 0) + return FALSE; + + int x = m_xMargin + kwxMacToolBarLeftMargin ; + int y = m_yMargin + kwxMacToolBarTopMargin ; + + int tw, th; + GetSize(& tw, & th); + + int maxWidth = 0 ; + int maxHeight = 0 ; + + int maxToolWidth = 0; + int maxToolHeight = 0; + + // Find the maximum tool width and height + wxToolBarToolsList::Node *node = m_tools.GetFirst(); + while ( node ) + { + wxToolBarTool *tool = (wxToolBarTool *)node->GetData(); + wxSize sz = tool->GetSize() ; + + if ( sz.x > maxToolWidth ) + maxToolWidth = sz.x ; + if (sz.y> maxToolHeight) + maxToolHeight = sz.y; + + node = node->GetNext(); + } + + node = m_tools.GetFirst(); + while (node) + { + wxToolBarTool *tool = (wxToolBarTool *)node->GetData(); + wxSize cursize = tool->GetSize() ; + + // for the moment we just do a single row/column alignement + if ( x + cursize.x > maxWidth ) + maxWidth = x + cursize.x ; + if ( y + cursize.y > maxHeight ) + maxHeight = y + cursize.y ; + + tool->SetPosition( wxPoint( x , y ) ) ; + + if ( GetWindowStyleFlag() & wxTB_VERTICAL ) + { + y += cursize.y ; + } + else + { + x += cursize.x ; + } + + node = node->GetNext(); + } + + if ( GetWindowStyleFlag() & wxTB_HORIZONTAL ) + { + if ( m_maxRows == 0 ) + { + // if not set yet, only one row + SetRows(1); + } + maxWidth = tw ; + maxHeight += m_yMargin + kwxMacToolBarTopMargin; + m_maxHeight = maxHeight ; + } + else + { + if ( GetToolsCount() > 0 && m_maxRows == 0 ) + { + // if not set yet, have one column + SetRows(GetToolsCount()); + } + maxHeight = th ; + maxWidth += m_xMargin + kwxMacToolBarLeftMargin; + m_maxWidth = maxWidth ; + } + + SetSize(maxWidth, maxHeight); + + return TRUE; +} + +void wxToolBar::SetToolBitmapSize(const wxSize& size) +{ + m_defaultWidth = size.x+4; m_defaultHeight = size.y+4; +} + +// The button size is bigger than the bitmap size +wxSize wxToolBar::GetToolSize() const +{ + return wxSize(m_defaultWidth + 4, m_defaultHeight + 4); +} + +void wxToolBar::MacHandleControlClick( WXWidget control , wxInt16 controlpart , bool WXUNUSED( mouseStillDown ) ) +{ + wxToolBarToolsList::Node *node; + for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) + { + wxToolBarTool* tool = (wxToolBarTool*) node->GetData() ; + if ( tool->IsButton() ) + { + if( tool->GetControlHandle() == control ) + { + if ( tool->CanBeToggled() ) + { + tool->Toggle( GetControl32BitValue( (ControlHandle) control ) ) ; + } + OnLeftClick( tool->GetId() , tool -> IsToggled() ) ; + break ; + } + } + } +} + +void wxToolBar::SetRows(int nRows) +{ + if ( nRows == m_maxRows ) + { + // avoid resizing the frame uselessly + return; + } + + m_maxRows = nRows; +} + +void wxToolBar::MacSuperChangedPosition() +{ + wxWindow::MacSuperChangedPosition() ; + Realize() ; +} + +wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord x, wxCoord y) const +{ + wxToolBarToolsList::Node *node = m_tools.GetFirst(); + while (node) + { + wxToolBarTool *tool = (wxToolBarTool *)node->GetData() ; + wxRect2DInt r( tool->GetPosition() , tool->GetSize() ) ; + if ( r.Contains( wxPoint( x , y ) ) ) + { + return tool; + } + + node = node->GetNext(); + } + + return (wxToolBarToolBase *)NULL; +} + +wxString wxToolBar::MacGetToolTipString( wxPoint &pt ) +{ + wxToolBarToolBase* tool = FindToolForPosition( pt.x , pt.y ) ; + if ( tool ) + { + return tool->GetShortHelp() ; + } + return wxEmptyString ; +} + +void wxToolBar::DoEnableTool(wxToolBarToolBase *t, bool enable) +{ + if (!IsShown()) + return ; + + wxToolBarTool *tool = (wxToolBarTool *)t; + if ( tool->IsControl() ) + { + tool->GetControl()->Enable( enable ) ; + } + else if ( tool->IsButton() ) + { + if ( enable ) + UMAActivateControl( tool->GetControlHandle() ) ; + else + UMADeactivateControl( tool->GetControlHandle() ) ; + } +} + +void wxToolBar::DoToggleTool(wxToolBarToolBase *t, bool toggle) +{ + if (!IsShown()) + return ; + + wxToolBarTool *tool = (wxToolBarTool *)t; + if ( tool->IsButton() ) + { + ::SetControl32BitValue( tool->GetControlHandle() , toggle ) ; + } +} + +bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), + wxToolBarToolBase *tool) +{ + // nothing special to do here - we relayout in Realize() later + tool->Attach(this); + + return TRUE; +} + +void wxToolBar::DoSetToggle(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle)) +{ + wxFAIL_MSG( _T("not implemented") ); +} + +bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos), wxToolBarToolBase *tool) +{ + wxToolBarToolsList::Node *node; + for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) + { + wxToolBarToolBase *tool2 = node->GetData(); + if ( tool2 == tool ) + { + // let node point to the next node in the list + node = node->GetNext(); + + break; + } + } + + wxSize sz = ((wxToolBarTool*)tool)->GetSize() ; + + tool->Detach(); + + // and finally reposition all the controls after this one + + for ( /* node -> first after deleted */ ; node; node = node->GetNext() ) + { + wxToolBarTool *tool2 = (wxToolBarTool*) node->GetData(); + wxPoint pt = tool2->GetPosition() ; + + if ( GetWindowStyleFlag() & wxTB_VERTICAL ) + { + pt.y -= sz.y ; + } + else + { + pt.x -= sz.x ; + } + tool2->SetPosition( pt ) ; + } + + return TRUE ; +} + +void wxToolBar::OnPaint(wxPaintEvent& event) +{ + wxPaintDC dc(this) ; + wxMacPortSetter helper(&dc) ; + + Rect toolbarrect = { dc.YLOG2DEVMAC(0) , dc.XLOG2DEVMAC(0) , + dc.YLOG2DEVMAC(m_height) , dc.XLOG2DEVMAC(m_width) } ; + UMADrawThemePlacard( &toolbarrect , IsEnabled() ? kThemeStateActive : kThemeStateInactive) ; + { + wxToolBarToolsList::Node *node; + for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) + { + wxToolBarTool* tool = (wxToolBarTool*) node->GetData() ; + if ( tool->IsButton() ) + { + UMADrawControl( tool->GetControlHandle() ) ; + } + } + } +} + +void wxToolBar::OnMouse( wxMouseEvent &event ) +{ + if (event.GetEventType() == wxEVT_LEFT_DOWN || event.GetEventType() == wxEVT_LEFT_DCLICK ) + { + + int x = event.m_x ; + int y = event.m_y ; + + MacClientToRootWindow( &x , &y ) ; + + ControlHandle control ; + Point localwhere ; + SInt16 controlpart ; + WindowRef window = (WindowRef) MacGetRootWindow() ; + + localwhere.h = x ; + localwhere.v = y ; + + short modifiers = 0; + + if ( !event.m_leftDown && !event.m_rightDown ) + modifiers |= btnState ; + + if ( event.m_shiftDown ) + modifiers |= shiftKey ; + + if ( event.m_controlDown ) + modifiers |= controlKey ; + + if ( event.m_altDown ) + modifiers |= optionKey ; + + if ( event.m_metaDown ) + modifiers |= cmdKey ; + + controlpart = ::FindControl( localwhere , window , &control ) ; + { + if ( control && ::IsControlActive( control ) ) + { + { + controlpart = ::HandleControlClick( control , localwhere , modifiers , (ControlActionUPP) -1 ) ; + wxTheApp->s_lastMouseDown = 0 ; + if ( control && controlpart != kControlNoPart ) // otherwise we will get the event twice + { + MacHandleControlClick( control , controlpart , false /* not down anymore */ ) ; + } + } + } + } + } +} + +#endif // wxUSE_TOOLBAR + diff --git a/src/mac/classic/tooltip.cpp b/src/mac/classic/tooltip.cpp new file mode 100644 index 0000000000..f269196711 --- /dev/null +++ b/src/mac/classic/tooltip.cpp @@ -0,0 +1,408 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: tooltip.cpp +// Purpose: wxToolTip implementation +// Author: Robert Roebling +// Id: $Id$ +// Copyright: (c) 1998 Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ + #pragma implementation "tooltip.h" +#endif + +#include "wx/defs.h" + +#if wxUSE_TOOLTIPS + +#include "wx/app.h" +#include "wx/dc.h" +#include "wx/window.h" +#include "wx/tooltip.h" +#include "wx/timer.h" +#include "wx/geometry.h" +#include "wx/mac/uma.h" + +//----------------------------------------------------------------------------- +// global data +//----------------------------------------------------------------------------- + +class wxMacToolTipTimer ; + +class wxMacToolTip +{ + public : + wxMacToolTip( ) ; + ~wxMacToolTip() ; + + void Setup( WindowRef window , const wxString& text , wxPoint localPosition ) ; + long GetMark() { return m_mark ; } + void Draw() ; + void Clear() ; + bool IsShown() { return m_shown ; } + private : + + wxString m_label ; + wxPoint m_position ; + Rect m_rect ; + WindowRef m_window ; + PicHandle m_backpict ; + bool m_shown ; + long m_mark ; + wxMacToolTipTimer* m_timer ; +#if TARGET_CARBON + wxMacCFStringHolder m_helpTextRef ; +#endif +} ; + +class wxMacToolTipTimer : public wxTimer +{ +public: + wxMacToolTipTimer() {} ; + wxMacToolTipTimer(wxMacToolTip* tip, int iMilliseconds) ; + virtual ~wxMacToolTipTimer() {} ; + void Notify() + { + if ( m_mark == m_tip->GetMark() ) + m_tip->Draw() ; + } +protected: + wxMacToolTip* m_tip; + long m_mark ; +}; + +//----------------------------------------------------------------------------- +// wxToolTip +//----------------------------------------------------------------------------- +static long s_ToolTipDelay = 500 ; +static bool s_ShowToolTips = true ; +static wxMacToolTip s_ToolTip ; +static wxWindow* s_LastWindowEntered = NULL ; +static wxRect2DInt s_ToolTipArea ; +static WindowRef s_ToolTipWindowRef = NULL ; + +IMPLEMENT_ABSTRACT_CLASS(wxToolTip, wxObject) + +wxToolTip::wxToolTip( const wxString &tip ) +{ + m_text = tip; + m_window = (wxWindow*) NULL; +} + +wxToolTip::~wxToolTip() +{ +} + +void wxToolTip::SetTip( const wxString &tip ) +{ + m_text = tip; + + if ( m_window ) + { + /* + // update it immediately + wxToolInfo ti(GetHwndOf(m_window)); + ti.lpszText = (wxChar *)m_text.c_str(); + + (void)SendTooltipMessage(GetToolTipCtrl(), TTM_UPDATETIPTEXT, 0, &ti); + */ + } +} + +void wxToolTip::SetWindow( wxWindow *win ) +{ + m_window = win ; +} + +void wxToolTip::Enable( bool flag ) +{ + if ( s_ShowToolTips != flag ) + { + s_ShowToolTips = flag ; + if ( s_ShowToolTips ) + { + } + else + { + s_ToolTip.Clear() ; + } + } +} + +void wxToolTip::SetDelay( long msecs ) +{ + s_ToolTipDelay = msecs ; +} + +void wxToolTip::RelayEvent( wxWindow *win , wxMouseEvent &event ) +{ + if ( s_ShowToolTips ) + { + if ( event.GetEventType() == wxEVT_LEAVE_WINDOW ) + { + s_ToolTip.Clear() ; + } + else if (event.GetEventType() == wxEVT_ENTER_WINDOW || event.GetEventType() == wxEVT_MOTION ) + { + wxPoint2DInt where( event.m_x , event.m_y ) ; + if ( s_LastWindowEntered == win && s_ToolTipArea.Contains( where ) ) + { + } + else + { + s_ToolTip.Clear() ; + s_ToolTipArea = wxRect2DInt( event.m_x - 2 , event.m_y - 2 , 4 , 4 ) ; + s_LastWindowEntered = win ; + + WindowRef window = MAC_WXHWND( win->MacGetRootWindow() ) ; + int x = event.m_x ; + int y = event.m_y ; + wxPoint local( x , y ) ; + win->MacClientToRootWindow( &x, &y ) ; + wxPoint windowlocal( x , y ) ; + s_ToolTip.Setup( window , win->MacGetToolTipString( local ) , windowlocal ) ; + } + } + } +} + +void wxToolTip::RemoveToolTips() +{ + s_ToolTip.Clear() ; +} +// --- mac specific + +wxMacToolTipTimer::wxMacToolTipTimer( wxMacToolTip *tip , int msec ) +{ + m_tip = tip; + m_mark = tip->GetMark() ; + Start(msec, true); +} + +wxMacToolTip::wxMacToolTip() +{ + m_window = NULL ; + m_backpict = NULL ; + m_mark = 0 ; + m_shown = false ; + m_timer = NULL ; +} + +void wxMacToolTip::Setup( WindowRef win , const wxString& text , wxPoint localPosition ) +{ + m_mark++ ; + Clear() ; + m_position = localPosition ; + m_label = text ; + m_window =win; + s_ToolTipWindowRef = m_window ; + m_backpict = NULL ; + if ( m_timer ) + delete m_timer ; + m_timer = new wxMacToolTipTimer( this , s_ToolTipDelay ) ; +} + +wxMacToolTip::~wxMacToolTip() +{ + if ( m_timer ) { + delete m_timer ; + m_timer = NULL; + } + if ( m_backpict ) + Clear() ; +} + +const short kTipBorder = 2 ; +const short kTipOffset = 5 ; + +void wxMacToolTip::Draw() +{ + if ( m_label.Length() == 0 ) + return ; + + if ( m_window == s_ToolTipWindowRef ) + { + m_shown = true ; +#if TARGET_CARBON + HMHelpContentRec tag ; + tag.version = kMacHelpVersion; + SetRect( &tag.absHotRect , m_position.x - 2 , m_position.y - 2 , m_position.x + 2 , m_position.y + 2 ) ; + GrafPtr port ; + GetPort( &port ) ; + SetPortWindowPort(m_window) ; + LocalToGlobal( (Point *) &tag.absHotRect.top ); + LocalToGlobal( (Point *) &tag.absHotRect.bottom ); + SetPort( port ); + m_helpTextRef.Assign( m_label , wxFONTENCODING_DEFAULT ) ; + tag.content[kHMMinimumContentIndex].contentType = kHMCFStringContent ; + tag.content[kHMMinimumContentIndex].u.tagCFString = m_helpTextRef ; + tag.content[kHMMaximumContentIndex].contentType = kHMCFStringContent ; + tag.content[kHMMaximumContentIndex].u.tagCFString = m_helpTextRef ; + tag.tagSide = kHMDefaultSide; + HMDisplayTag( &tag ); +#else + wxMacPortStateHelper help( (GrafPtr) GetWindowPort( m_window ) ); + FontFamilyID fontId ; + Str255 fontName ; + SInt16 fontSize ; + Style fontStyle ; + GetThemeFont(kThemeSmallSystemFont , GetApplicationScript() , fontName , &fontSize , &fontStyle ) ; + GetFNum( fontName, &fontId ); + + TextFont( fontId ) ; + TextSize( fontSize ) ; + TextFace( fontStyle ) ; + FontInfo fontInfo; + ::GetFontInfo(&fontInfo); + short lineh = fontInfo.ascent + fontInfo.descent + fontInfo.leading; + short height = 0 ; + + int i = 0 ; + int length = m_label.Length() ; + int width = 0 ; + int thiswidth = 0 ; + int laststop = 0 ; + wxCharBuffer text = m_label.mb_str( wxConvLocal) ; + + while( i < length ) + { + if( text[i] == 13 || text[i] == 10) + { + thiswidth = ::TextWidth( text , laststop , i - laststop ) ; + if ( thiswidth > width ) + width = thiswidth ; + + height += lineh ; + laststop = i+1 ; + } + i++ ; + } + if ( i - laststop > 0 ) + { + thiswidth = ::TextWidth( text , laststop , i - laststop ) ; + if ( thiswidth > width ) + width = thiswidth ; + height += lineh ; + } + + m_rect.left = m_position.x + kTipOffset; + m_rect.top = m_position.y + kTipOffset; + m_rect.right = m_rect.left + width + 2 * kTipBorder; + + m_rect.bottom = m_rect.top + height + 2 * kTipBorder; + Rect r ; + GetPortBounds( GetWindowPort( m_window ) , &r ) ; + if ( m_rect.top < 0 ) + { + m_rect.bottom += -m_rect.top ; + m_rect.top = 0 ; + } + if ( m_rect.left < 0 ) + { + m_rect.right += -m_rect.left ; + m_rect.left = 0 ; + } + if ( m_rect.right > r.right ) + { + m_rect.left -= (m_rect.right - r.right ) ; + m_rect.right = r.right ; + } + if ( m_rect.bottom > r.bottom ) + { + m_rect.top -= (m_rect.bottom - r.bottom) ; + m_rect.bottom = r.bottom ; + } + ClipRect( &m_rect ) ; + BackColor( whiteColor ) ; + ForeColor(blackColor ) ; + GWorldPtr port ; + NewGWorld( &port , wxDisplayDepth() , &m_rect , NULL , NULL , 0 ) ; + CGrafPtr origPort ; + GDHandle origDevice ; + + GetGWorld( &origPort , &origDevice ) ; + SetGWorld( port , NULL ) ; + + m_backpict = OpenPicture(&m_rect); + + CopyBits(GetPortBitMapForCopyBits(GetWindowPort(m_window)), + GetPortBitMapForCopyBits(port), + &m_rect, + &m_rect, + srcCopy, + NULL); + ClosePicture(); + SetGWorld( origPort , origDevice ) ; + DisposeGWorld( port ) ; + PenNormal() ; + + RGBColor tooltipbackground = { 0xFFFF , 0xFFFF , 0xC000 } ; + BackColor( whiteColor ) ; + RGBForeColor( &tooltipbackground ) ; + + PaintRect( &m_rect ) ; + ForeColor(blackColor ) ; + FrameRect( &m_rect ) ; + SetThemeTextColor(kThemeTextColorNotification,wxDisplayDepth(),true) ; + ::MoveTo( m_rect.left + kTipBorder , m_rect.top + fontInfo.ascent + kTipBorder); + + i = 0 ; + laststop = 0 ; + height = 0 ; + + while( i < length ) + { + if( text[i] == 13 || text[i] == 10) + { + ::DrawText( text , laststop , i - laststop ) ; + height += lineh ; + ::MoveTo( m_rect.left + kTipBorder , m_rect.top + fontInfo.ascent + kTipBorder + height ); + laststop = i+1 ; + } + i++ ; + } + ::DrawText( text , laststop , i - laststop ) ; + ::TextMode( srcOr ) ; +#endif + } +} + +void wxToolTip::NotifyWindowDelete( WXHWND win ) +{ + if ( win == s_ToolTipWindowRef ) + { + s_ToolTipWindowRef = NULL ; + } +} + +void wxMacToolTip::Clear() +{ + m_mark++ ; + if ( m_timer ) + { + delete m_timer ; + m_timer = NULL ; + } + if ( !m_shown ) + return ; +#if TARGET_CARBON + HMHideTag() ; + m_helpTextRef.Release() ; +#else + if ( m_window == s_ToolTipWindowRef && m_backpict ) + { + wxMacPortStateHelper help( (GrafPtr) GetWindowPort(m_window) ) ; + + m_shown = false ; + + BackColor( whiteColor ) ; + ForeColor(blackColor ) ; + DrawPicture(m_backpict, &m_rect); + KillPicture(m_backpict); + m_backpict = NULL ; + } +#endif +} + +#endif + diff --git a/src/mac/classic/toplevel.cpp b/src/mac/classic/toplevel.cpp new file mode 100644 index 0000000000..878c27f2a9 --- /dev/null +++ b/src/mac/classic/toplevel.cpp @@ -0,0 +1,1463 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: mac/toplevel.cpp +// Purpose: implements wxTopLevelWindow for Mac +// Author: Stefan Csomor +// Modified by: +// Created: 24.09.01 +// RCS-ID: $Id$ +// Copyright: (c) 2001-2004 Stefan Csomor +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#ifdef __GNUG__ + #pragma implementation "toplevel.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/toplevel.h" + #include "wx/frame.h" + #include "wx/string.h" + #include "wx/log.h" + #include "wx/intl.h" +#endif //WX_PRECOMP + +#include "wx/mac/uma.h" +#include "wx/mac/aga.h" +#include "wx/app.h" +#include "wx/tooltip.h" +#include "wx/dnd.h" +#if wxUSE_SYSTEM_OPTIONS + #include "wx/sysopt.h" +#endif + +#include + + +#define wxMAC_DEBUG_REDRAW 0 +#ifndef wxMAC_DEBUG_REDRAW +#define wxMAC_DEBUG_REDRAW 0 +#endif + +// ---------------------------------------------------------------------------- +// globals +// ---------------------------------------------------------------------------- + +// list of all frames and modeless dialogs +wxWindowList wxModelessWindows; + +// double click testing +static Point gs_lastWhere; +static long gs_lastWhen = 0; + + +#if TARGET_CARBON +static pascal long wxShapedMacWindowDef(short varCode, WindowRef window, SInt16 message, SInt32 param); +#endif + +// ============================================================================ +// wxTopLevelWindowMac implementation +// ============================================================================ + +// --------------------------------------------------------------------------- +// Carbon Events +// --------------------------------------------------------------------------- + +#if TARGET_CARBON + +extern long wxMacTranslateKey(unsigned char key, unsigned char code) ; + +static const EventTypeSpec eventList[] = +{ + { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent } , + + { kEventClassKeyboard, kEventRawKeyDown } , + { kEventClassKeyboard, kEventRawKeyRepeat } , + { kEventClassKeyboard, kEventRawKeyUp } , + { kEventClassKeyboard, kEventRawKeyModifiersChanged } , + + { kEventClassWindow , kEventWindowShown } , + { kEventClassWindow , kEventWindowUpdate } , + { kEventClassWindow , kEventWindowActivated } , + { kEventClassWindow , kEventWindowDeactivated } , + { kEventClassWindow , kEventWindowBoundsChanging } , + { kEventClassWindow , kEventWindowBoundsChanged } , + { kEventClassWindow , kEventWindowClose } , + + { kEventClassMouse , kEventMouseDown } , + { kEventClassMouse , kEventMouseUp } , + { kEventClassMouse , kEventMouseWheelMoved } , + { kEventClassMouse , kEventMouseMoved } , + { kEventClassMouse , kEventMouseDragged } , + +} ; + +static pascal OSStatus TextInputEventHandler( EventHandlerCallRef handler , EventRef event , void *data ) +{ + OSStatus result = eventNotHandledErr ; + + wxWindow* focus = wxWindow::FindFocus() ; + char charCode ; + UInt32 keyCode ; + UInt32 modifiers ; + Point point ; + + EventRef rawEvent ; + + GetEventParameter( event , kEventParamTextInputSendKeyboardEvent ,typeEventRef,NULL,sizeof(rawEvent),NULL,&rawEvent ) ; + + GetEventParameter( rawEvent, kEventParamKeyMacCharCodes, typeChar, NULL,sizeof(char), NULL,&charCode ); + GetEventParameter( rawEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode ); + GetEventParameter( rawEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); + GetEventParameter( rawEvent, kEventParamMouseLocation, typeQDPoint, NULL, + sizeof( Point ), NULL, &point ); + + switch ( GetEventKind( event ) ) + { + case kEventTextInputUnicodeForKeyEvent : + // this is only called when no default handler has jumped in, eg a wxControl on a floater window does not + // get its own kEventTextInputUnicodeForKeyEvent, so we route back the + wxControl* control = wxDynamicCast( focus , wxControl ) ; + if ( control ) + { + ControlHandle macControl = (ControlHandle) control->GetMacControl() ; + if ( macControl ) + { + ::HandleControlKey( macControl , keyCode , charCode , modifiers ) ; + result = noErr ; + } + } + /* + // this may lead to double events sent to a window in case all handlers have skipped the key down event + UInt32 when = EventTimeToTicks( GetEventTime( event ) ) ; + UInt32 message = (keyCode << 8) + charCode; + + if ( (focus != NULL) && wxTheApp->MacSendKeyDownEvent( + focus , message , modifiers , when , point.h , point.v ) ) + { + result = noErr ; + } + */ + break ; + } + + return result ; +} + +static pascal OSStatus KeyboardEventHandler( EventHandlerCallRef handler , EventRef event , void *data ) +{ + OSStatus result = eventNotHandledErr ; + + wxWindow* focus = wxWindow::FindFocus() ; + char charCode ; + UInt32 keyCode ; + UInt32 modifiers ; + Point point ; + UInt32 when = EventTimeToTicks( GetEventTime( event ) ) ; + + GetEventParameter( event, kEventParamKeyMacCharCodes, typeChar, NULL,sizeof(char), NULL,&charCode ); + GetEventParameter( event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode ); + GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); + GetEventParameter( event, kEventParamMouseLocation, typeQDPoint, NULL, + sizeof( Point ), NULL, &point ); + + UInt32 message = (keyCode << 8) + charCode; + switch( GetEventKind( event ) ) + { + case kEventRawKeyRepeat : + case kEventRawKeyDown : + { + WXEVENTREF formerEvent = wxTheApp->MacGetCurrentEvent() ; + WXEVENTHANDLERCALLREF formerHandler = wxTheApp->MacGetCurrentEventHandlerCallRef() ; + wxTheApp->MacSetCurrentEvent( event , handler ) ; + if ( (focus != NULL) && wxTheApp->MacSendKeyDownEvent( + focus , message , modifiers , when , point.h , point.v ) ) + { + result = noErr ; + } + wxTheApp->MacSetCurrentEvent( formerEvent , formerHandler ) ; + } + break ; + case kEventRawKeyUp : + if ( (focus != NULL) && wxTheApp->MacSendKeyUpEvent( + focus , message , modifiers , when , point.h , point.v ) ) + { + result = noErr ; + } + break ; + case kEventRawKeyModifiersChanged : + { + wxKeyEvent event(wxEVT_KEY_DOWN); + + event.m_shiftDown = modifiers & shiftKey; + event.m_controlDown = modifiers & controlKey; + event.m_altDown = modifiers & optionKey; + event.m_metaDown = modifiers & cmdKey; + + event.m_x = point.h; + event.m_y = point.v; + event.m_timeStamp = when; + wxWindow* focus = wxWindow::FindFocus() ; + event.SetEventObject(focus); + + if ( focus && (modifiers ^ wxTheApp->s_lastModifiers ) & controlKey ) + { + event.m_keyCode = WXK_CONTROL ; + event.SetEventType( ( modifiers & controlKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ; + focus->GetEventHandler()->ProcessEvent( event ) ; + } + if ( focus && (modifiers ^ wxTheApp->s_lastModifiers ) & shiftKey ) + { + event.m_keyCode = WXK_SHIFT ; + event.SetEventType( ( modifiers & shiftKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ; + focus->GetEventHandler()->ProcessEvent( event ) ; + } + if ( focus && (modifiers ^ wxTheApp->s_lastModifiers ) & optionKey ) + { + event.m_keyCode = WXK_ALT ; + event.SetEventType( ( modifiers & optionKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ; + focus->GetEventHandler()->ProcessEvent( event ) ; + } + if ( focus && (modifiers ^ wxTheApp->s_lastModifiers ) & cmdKey ) + { + event.m_keyCode = WXK_COMMAND ; + event.SetEventType( ( modifiers & cmdKey ) ? wxEVT_KEY_DOWN : wxEVT_KEY_UP ) ; + focus->GetEventHandler()->ProcessEvent( event ) ; + } + wxTheApp->s_lastModifiers = modifiers ; + } + break ; + } + + return result ; +} + +pascal OSStatus MouseEventHandler( EventHandlerCallRef handler , EventRef event , void *data ) +{ + OSStatus result = eventNotHandledErr ; + + wxTopLevelWindowMac* toplevelWindow = (wxTopLevelWindowMac*) data ; + Point point ; + UInt32 modifiers = 0; + EventMouseButton button = 0 ; + UInt32 click = 0 ; + + GetEventParameter( event, kEventParamMouseLocation, typeQDPoint, NULL, + sizeof( Point ), NULL, &point ); + GetEventParameter( event, kEventParamKeyModifiers, typeUInt32, NULL, + sizeof( UInt32 ), NULL, &modifiers ); + GetEventParameter( event, kEventParamMouseButton, typeMouseButton, NULL, + sizeof( EventMouseButton ), NULL, &button ); + GetEventParameter( event, kEventParamClickCount, typeUInt32, NULL, + sizeof( UInt32 ), NULL, &click ); + + if ( button == 0 || GetEventKind( event ) == kEventMouseUp ) + modifiers += btnState ; + + // temporary hack to support true two button mouse + if ( button == kEventMouseButtonSecondary ) + { + modifiers |= controlKey ; + } + WindowRef window ; + short windowPart = ::FindWindow(point, &window); + + // either we really are active or we are capturing mouse events + + if ( (IsWindowActive(window) && windowPart == inContent) || + (wxTheApp->s_captureWindow && wxTheApp->s_captureWindow->MacGetTopLevelWindow() == toplevelWindow) ) + { + switch ( GetEventKind( event ) ) + { + case kEventMouseDown : + toplevelWindow->MacFireMouseEvent( mouseDown , point.h , point.v , modifiers , EventTimeToTicks( GetEventTime( event ) ) ) ; + result = noErr ; + break ; + case kEventMouseUp : + toplevelWindow->MacFireMouseEvent( mouseUp , point.h , point.v , modifiers , EventTimeToTicks( GetEventTime( event ) ) ) ; + result = noErr ; + break ; + case kEventMouseMoved : + wxTheApp->MacHandleMouseMovedEvent( point.h , point.v , modifiers , EventTimeToTicks( GetEventTime( event ) ) ) ; + result = noErr ; + break ; + case kEventMouseDragged : + toplevelWindow->MacFireMouseEvent( nullEvent , point.h , point.v , modifiers , EventTimeToTicks( GetEventTime( event ) ) ) ; + result = noErr ; + break ; + case kEventMouseWheelMoved : + { + //bClearTooltip = false; + EventMouseWheelAxis axis = kEventMouseWheelAxisY; + SInt32 delta = 0; + Point mouseLoc = {0, 0}; + if (::GetEventParameter(event, kEventParamMouseWheelAxis, typeMouseWheelAxis, + NULL, sizeof(EventMouseWheelAxis), NULL, &axis) == noErr && + ::GetEventParameter(event, kEventParamMouseWheelDelta, typeLongInteger, + NULL, sizeof(SInt32), NULL, &delta) == noErr && + ::GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, + NULL, sizeof(Point), NULL, &mouseLoc) == noErr) + { + wxMouseEvent wheelEvent(wxEVT_MOUSEWHEEL); + + wheelEvent.m_x = mouseLoc.h; + wheelEvent.m_y = mouseLoc.v; + + wheelEvent.m_wheelRotation = delta; + wheelEvent.m_wheelDelta = 1; + wheelEvent.m_linesPerAction = 1; + + wxWindow* currentMouseWindow = NULL; + wxWindow::MacGetWindowFromPoint(wxPoint(mouseLoc.h, mouseLoc.v), ¤tMouseWindow); + + if (currentMouseWindow) + { + currentMouseWindow->GetEventHandler()->ProcessEvent(wheelEvent); + result = noErr; + } + } + } + break ; + default : + break ; + } + } + + return result ; + + +} +static pascal OSStatus WindowEventHandler( EventHandlerCallRef handler , EventRef event , void *data ) +{ + OSStatus result = eventNotHandledErr ; + OSStatus err = noErr ; + + UInt32 attributes; + WindowRef windowRef ; + wxTopLevelWindowMac* toplevelWindow = (wxTopLevelWindowMac*) data ; + + GetEventParameter( event, kEventParamDirectObject, typeWindowRef, NULL, + sizeof( WindowRef ), NULL, &windowRef ); + + switch( GetEventKind( event ) ) + { + case kEventWindowUpdate : + if ( !wxPendingDelete.Member(toplevelWindow) ) + toplevelWindow->MacUpdate( EventTimeToTicks( GetEventTime( event ) ) ) ; + result = noErr ; + break ; + case kEventWindowActivated : + toplevelWindow->MacActivate( EventTimeToTicks( GetEventTime( event ) ) , true) ; + result = noErr ; + break ; + case kEventWindowDeactivated : + toplevelWindow->MacActivate( EventTimeToTicks( GetEventTime( event ) ) , false) ; + result = noErr ; + break ; + case kEventWindowShown : + toplevelWindow->Refresh() ; + result = noErr ; + break ; + case kEventWindowClose : + toplevelWindow->Close() ; + result = noErr ; + break ; + case kEventWindowBoundsChanged : + err = GetEventParameter( event, kEventParamAttributes, typeUInt32, + NULL, sizeof( UInt32 ), NULL, &attributes ); + if ( err == noErr ) + { + Rect newContentRect ; + + GetEventParameter( event, kEventParamCurrentBounds, typeQDRectangle, NULL, + sizeof( newContentRect ), NULL, &newContentRect ); + + toplevelWindow->SetSize( newContentRect.left , newContentRect.top , + newContentRect.right - newContentRect.left , + newContentRect.bottom - newContentRect.top, wxSIZE_USE_EXISTING); + + result = noErr; + } + break ; + case kEventWindowBoundsChanging : + err = GetEventParameter( event, kEventParamAttributes, typeUInt32, + NULL, sizeof( UInt32 ), NULL, &attributes ); + if ( err == noErr ) + { + Rect newContentRect ; + + GetEventParameter( event, kEventParamCurrentBounds, typeQDRectangle, NULL, + sizeof( newContentRect ), NULL, &newContentRect ); + + wxSize formerSize = toplevelWindow->GetSize() ; + + if ( (attributes & kWindowBoundsChangeSizeChanged ) || + ( attributes & kWindowBoundsChangeOriginChanged ) ) + toplevelWindow->SetSize( newContentRect.left , newContentRect.top , + newContentRect.right - newContentRect.left , + newContentRect.bottom - newContentRect.top, wxSIZE_USE_EXISTING); + + int x , y , w , h ; + toplevelWindow->GetPosition( &x , &y ) ; + toplevelWindow->GetSize( &w , &h ) ; + Rect adjustedRect = { y , x , y + h , x + w } ; + + if ( !EqualRect( &newContentRect , &adjustedRect ) ) + { + SetEventParameter( event , kEventParamCurrentBounds , typeQDRectangle, sizeof( adjustedRect ) , &adjustedRect ) ; + } + + if ( toplevelWindow->GetSize() != formerSize ) + toplevelWindow->Update() ; + + result = noErr ; + } + break ; + default : + break ; + } + return result ; +} + +pascal OSStatus wxMacWindowEventHandler( EventHandlerCallRef handler , EventRef event , void *data ) +{ + OSStatus result = eventNotHandledErr ; + + switch ( GetEventClass( event ) ) + { + case kEventClassKeyboard : + result = KeyboardEventHandler( handler, event , data ) ; + break ; + case kEventClassTextInput : + result = TextInputEventHandler( handler, event , data ) ; + break ; + case kEventClassWindow : + result = WindowEventHandler( handler, event , data ) ; + break ; + case kEventClassMouse : + result = MouseEventHandler( handler, event , data ) ; + break ; + default : + break ; + } + return result ; +} + +DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacWindowEventHandler ) + +#endif + +// --------------------------------------------------------------------------- +// wxWindowMac utility functions +// --------------------------------------------------------------------------- + +// Find an item given the Macintosh Window Reference + +wxList *wxWinMacWindowList = NULL; +wxTopLevelWindowMac *wxFindWinFromMacWindow(WXWindow inWindowRef) +{ + if ( wxWinMacWindowList == NULL ) + return NULL ; + wxNode *node = wxWinMacWindowList->Find((long)inWindowRef); + if (!node) + return NULL; + return (wxTopLevelWindowMac *)node->GetData(); +} + +void wxAssociateWinWithMacWindow(WXWindow inWindowRef, wxTopLevelWindowMac *win) +{ + // adding NULL WindowRef is (first) surely a result of an error and + // (secondly) breaks menu command processing + wxCHECK_RET( inWindowRef != (WindowRef) NULL, wxT("attempt to add a NULL WindowRef to window list") ); + + if ( !wxWinMacWindowList->Find((long)inWindowRef) ) + wxWinMacWindowList->Append((long)inWindowRef, win); +} + +void wxRemoveMacWindowAssociation(wxTopLevelWindowMac *win) +{ + wxWinMacWindowList->DeleteObject(win); +} + + +// ---------------------------------------------------------------------------- +// wxTopLevelWindowMac creation +// ---------------------------------------------------------------------------- + +WXHWND wxTopLevelWindowMac::s_macWindowInUpdate = NULL; +wxTopLevelWindowMac *wxTopLevelWindowMac::s_macDeactivateWindow = NULL; +bool wxTopLevelWindowMac::s_macWindowCompositing = FALSE; + +void wxTopLevelWindowMac::Init() +{ + m_iconized = + m_maximizeOnShow = FALSE; + m_macNoEraseUpdateRgn = NewRgn() ; + m_macNeedsErasing = false ; + m_macWindow = NULL ; + m_macUsesCompositing = FALSE ; +#if TARGET_CARBON + m_macEventHandler = NULL ; + #endif +} + +class wxMacDeferredWindowDeleter : public wxObject +{ +public : + wxMacDeferredWindowDeleter( WindowRef windowRef ) + { + m_macWindow = windowRef ; + } + virtual ~wxMacDeferredWindowDeleter() + { + UMADisposeWindow( (WindowRef) m_macWindow ) ; + } + protected : + WindowRef m_macWindow ; +} ; + +bool wxTopLevelWindowMac::Create(wxWindow *parent, + wxWindowID id, + const wxString& title, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + // init our fields + Init(); + + m_windowStyle = style; + + SetName(name); + + m_windowId = id == -1 ? NewControlId() : id; + + wxTopLevelWindows.Append(this); + + if ( parent ) + parent->AddChild(this); + + return TRUE; +} + +wxTopLevelWindowMac::~wxTopLevelWindowMac() +{ + if ( m_macWindow ) + { + wxToolTip::NotifyWindowDelete(m_macWindow) ; + wxPendingDelete.Append( new wxMacDeferredWindowDeleter( (WindowRef) m_macWindow ) ) ; + } + +#if TARGET_CARBON + if ( m_macEventHandler ) + { + ::RemoveEventHandler((EventHandlerRef) m_macEventHandler); + m_macEventHandler = NULL ; + } +#endif + + wxRemoveMacWindowAssociation( this ) ; + + if ( wxModelessWindows.Find(this) ) + wxModelessWindows.DeleteObject(this); + + DisposeRgn( (RgnHandle) m_macNoEraseUpdateRgn ) ; +} + + +// ---------------------------------------------------------------------------- +// wxTopLevelWindowMac maximize/minimize +// ---------------------------------------------------------------------------- + +void wxTopLevelWindowMac::Maximize(bool maximize) +{ + wxMacPortStateHelper help( (GrafPtr) GetWindowPort( (WindowRef) m_macWindow) ) ; + wxMacWindowClipper clip (this); + ZoomWindow( (WindowRef)m_macWindow , maximize ? inZoomOut : inZoomIn , false ) ; + + Rect tempRect ; + GrafPtr port ; + GetPort( &port ) ; + Point pt = { 0, 0 } ; + SetPortWindowPort((WindowRef)m_macWindow) ; + LocalToGlobal( &pt ) ; + SetPort( port ) ; + + GetWindowPortBounds((WindowRef)m_macWindow, &tempRect ) ; + SetSize( pt.h , pt.v , tempRect.right-tempRect.left , + tempRect.bottom-tempRect.top, wxSIZE_USE_EXISTING); +} + +bool wxTopLevelWindowMac::IsMaximized() const +{ + return IsWindowInStandardState( (WindowRef)m_macWindow , NULL , NULL ) ; +} + +void wxTopLevelWindowMac::Iconize(bool iconize) +{ + if ( IsWindowCollapsable((WindowRef)m_macWindow) ) + CollapseWindow((WindowRef)m_macWindow , iconize ) ; +} + +bool wxTopLevelWindowMac::IsIconized() const +{ + return IsWindowCollapsed((WindowRef)m_macWindow ) ; +} + +void wxTopLevelWindowMac::Restore() +{ + // not available on mac +} + +// ---------------------------------------------------------------------------- +// wxTopLevelWindowMac misc +// ---------------------------------------------------------------------------- + +void wxTopLevelWindowMac::SetIcon(const wxIcon& icon) +{ + // this sets m_icon + wxTopLevelWindowBase::SetIcon(icon); +} + +void wxTopLevelWindowMac::MacCreateRealWindow( const wxString& title, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name ) +{ + OSStatus err = noErr ; + SetName(name); + m_windowStyle = style; + m_isShown = FALSE; + + // create frame. + + Rect theBoundsRect; + + m_x = (int)pos.x; + m_y = (int)pos.y; + if ( m_y < 50 ) + m_y = 50 ; + if ( m_x < 20 ) + m_x = 20 ; + + m_width = WidthDefault(size.x); + m_height = HeightDefault(size.y); + + ::SetRect(&theBoundsRect, m_x, m_y , m_x + m_width, m_y + m_height); + + // translate the window attributes in the appropriate window class and attributes + + WindowClass wclass = 0; + WindowAttributes attr = kWindowNoAttributes ; + + if ( HasFlag( wxFRAME_TOOL_WINDOW) ) + { + if ( + HasFlag( wxMINIMIZE_BOX ) || HasFlag( wxMAXIMIZE_BOX ) || + HasFlag( wxSYSTEM_MENU ) || HasFlag( wxCAPTION ) || + HasFlag(wxTINY_CAPTION_HORIZ) || HasFlag(wxTINY_CAPTION_VERT) + ) + { + wclass = kFloatingWindowClass ; + if ( HasFlag(wxTINY_CAPTION_VERT) ) + { + attr |= kWindowSideTitlebarAttribute ; + } + } + else + { +#if TARGET_CARBON + wclass = kPlainWindowClass ; +#else + wclass = kFloatingWindowClass ; +#endif + } + } + else if ( HasFlag( wxCAPTION ) ) + { + wclass = kDocumentWindowClass ; + } + else + { + if ( HasFlag( wxMINIMIZE_BOX ) || HasFlag( wxMAXIMIZE_BOX ) || + HasFlag( wxCLOSE_BOX ) || HasFlag( wxSYSTEM_MENU ) ) + { + wclass = kDocumentWindowClass ; + } + else + { +#if TARGET_CARBON + wclass = kPlainWindowClass ; +#else + wclass = kModalWindowClass ; +#endif + } + } + + if ( HasFlag( wxMINIMIZE_BOX ) ) + { + attr |= kWindowCollapseBoxAttribute ; + } + if ( HasFlag( wxMAXIMIZE_BOX ) ) + { + attr |= kWindowFullZoomAttribute ; + } + if ( HasFlag( wxRESIZE_BORDER ) ) + { + attr |= kWindowResizableAttribute ; + } + if ( HasFlag( wxCLOSE_BOX) ) + { + attr |= kWindowCloseBoxAttribute ; + } + + if (UMAGetSystemVersion() >= 0x1000) + { + //turn on live resizing (OS X only) + attr |= kWindowLiveResizeAttribute; + } + +#if TARGET_CARBON +#if 0 // having problems right now with that + if (HasFlag(wxSTAY_ON_TOP)) + wclass = kUtilityWindowClass; +#endif +#endif + + //this setup lets us have compositing and non-compositing + //windows in the same application. + +#if UNIVERSAL_INTERFACES_VERSION >= 0x0400 + if ( wxTopLevelWindowMac::s_macWindowCompositing ) + { + attr |= kWindowCompositingAttribute; + m_macUsesCompositing = TRUE; + } + else +#endif + { + m_macUsesCompositing = FALSE; + } + +#if TARGET_CARBON + if ( HasFlag(wxFRAME_SHAPED) ) + { + WindowDefSpec customWindowDefSpec; + customWindowDefSpec.defType = kWindowDefProcPtr; + customWindowDefSpec.u.defProc = NewWindowDefUPP(wxShapedMacWindowDef); + + err = ::CreateCustomWindow( &customWindowDefSpec, wclass, + attr, &theBoundsRect, + (WindowRef*) &m_macWindow); + } + else +#endif + { + err = ::CreateNewWindow( wclass , attr , &theBoundsRect , (WindowRef*)&m_macWindow ) ; + } + + wxCHECK_RET( err == noErr, wxT("Mac OS error when trying to create new window") ); + wxAssociateWinWithMacWindow( m_macWindow , this ) ; + UMASetWTitle( (WindowRef)m_macWindow , title , m_font.GetEncoding() ) ; + if ( wxTopLevelWindowMac::s_macWindowCompositing ) + { + ::GetRootControl( (WindowRef)m_macWindow, (ControlHandle*)&m_macRootControl ) ; + } + else + { + ::CreateRootControl( (WindowRef)m_macWindow , (ControlHandle*)&m_macRootControl ) ; + } +#if TARGET_CARBON + InstallStandardEventHandler( GetWindowEventTarget(MAC_WXHWND(m_macWindow)) ) ; + InstallWindowEventHandler(MAC_WXHWND(m_macWindow), GetwxMacWindowEventHandlerUPP(), + GetEventTypeCount(eventList), eventList, this, (EventHandlerRef *)&m_macEventHandler); +#endif + m_macFocus = NULL ; + + +#if TARGET_CARBON + if ( HasFlag(wxFRAME_SHAPED) ) + { + // default shape matches the window size + wxRegion rgn(0, 0, m_width, m_height); + SetShape(rgn); + } +#endif + + wxWindowCreateEvent event(this); + GetEventHandler()->ProcessEvent(event); +} + +bool wxTopLevelWindowMac::MacEnableCompositing( bool useCompositing ) +{ + bool oldval = s_macWindowCompositing; + s_macWindowCompositing = useCompositing; + return oldval; +} + +void wxTopLevelWindowMac::MacGetPortParams(WXPOINTPTR localOrigin, WXRECTPTR clipRect, WXHWND *window , wxWindowMac** rootwin) +{ + ((Point*)localOrigin)->h = 0; + ((Point*)localOrigin)->v = 0; + ((Rect*)clipRect)->left = 0; + ((Rect*)clipRect)->top = 0; + ((Rect*)clipRect)->right = m_width; + ((Rect*)clipRect)->bottom = m_height; + *window = m_macWindow ; + *rootwin = this ; +} + +void wxTopLevelWindowMac::ClearBackground() +{ + wxWindow::ClearBackground() ; +} + +WXWidget wxTopLevelWindowMac::MacGetContainerForEmbedding() +{ + return m_macRootControl ; +} + + +void wxTopLevelWindowMac::MacUpdate( long timestamp) +{ + wxMacPortStateHelper help( (GrafPtr) GetWindowPort( (WindowRef) m_macWindow) ) ; + + RgnHandle visRgn = NewRgn() ; + GetPortVisibleRegion( GetWindowPort( (WindowRef)m_macWindow ), visRgn ); + BeginUpdate( (WindowRef)m_macWindow ) ; + + RgnHandle updateRgn = NewRgn(); + RgnHandle diffRgn = NewRgn() ; + + if ( updateRgn && diffRgn ) + { +#if 1 + // macos internal control redraws clean up areas we'd like to redraw ourselves + // therefore we pick the boundary rect and make sure we can redraw it + // this has to be intersected by the visRgn in order to avoid drawing over its own + // boundaries + RgnHandle trueUpdateRgn = NewRgn() ; + Rect trueUpdateRgnBoundary ; + GetPortVisibleRegion( GetWindowPort( (WindowRef)m_macWindow ), trueUpdateRgn ); + GetRegionBounds( trueUpdateRgn , &trueUpdateRgnBoundary ) ; + RectRgn( updateRgn , &trueUpdateRgnBoundary ) ; + SectRgn( updateRgn , visRgn , updateRgn ) ; + if ( trueUpdateRgn ) + DisposeRgn( trueUpdateRgn ) ; + SetPortVisibleRegion( GetWindowPort( (WindowRef)m_macWindow ), updateRgn ) ; +#else + GetPortVisibleRegion( GetWindowPort( (WindowRef)m_macWindow ), updateRgn ); +#endif + DiffRgn( updateRgn , (RgnHandle) m_macNoEraseUpdateRgn , diffRgn ) ; + if ( !EmptyRgn( updateRgn ) ) + { + MacRedraw( updateRgn , timestamp , m_macNeedsErasing || !EmptyRgn( diffRgn ) ) ; + } + } + if ( updateRgn ) + DisposeRgn( updateRgn ); + if ( diffRgn ) + DisposeRgn( diffRgn ); + if ( visRgn ) + DisposeRgn( visRgn ) ; + + EndUpdate( (WindowRef)m_macWindow ) ; + SetEmptyRgn( (RgnHandle) m_macNoEraseUpdateRgn ) ; + m_macNeedsErasing = false ; +} + + +// Raise the window to the top of the Z order +void wxTopLevelWindowMac::Raise() +{ + ::SelectWindow( (WindowRef)m_macWindow ) ; +} + +// Lower the window to the bottom of the Z order +void wxTopLevelWindowMac::Lower() +{ + ::SendBehind( (WindowRef)m_macWindow , NULL ) ; +} + +void wxTopLevelWindowMac::MacFireMouseEvent( + wxUint16 kind , wxInt32 x , wxInt32 y ,wxUint32 modifiers , long timestamp ) +{ + wxMouseEvent event(wxEVT_LEFT_DOWN); + bool isDown = !(modifiers & btnState) ; // 1 is for up + bool controlDown = modifiers & controlKey ; // for simulating right mouse + + event.m_leftDown = isDown && !controlDown; + + event.m_middleDown = FALSE; + event.m_rightDown = isDown && controlDown; + + if ( kind == mouseDown ) + { + if ( controlDown ) + event.SetEventType(wxEVT_RIGHT_DOWN ) ; + else + event.SetEventType(wxEVT_LEFT_DOWN ) ; + } + else if ( kind == mouseUp ) + { + if ( controlDown ) + event.SetEventType(wxEVT_RIGHT_UP ) ; + else + event.SetEventType(wxEVT_LEFT_UP ) ; + } + else + { + event.SetEventType(wxEVT_MOTION ) ; + } + + event.m_shiftDown = modifiers & shiftKey; + event.m_controlDown = modifiers & controlKey; + event.m_altDown = modifiers & optionKey; + event.m_metaDown = modifiers & cmdKey; + + Point localwhere ; + localwhere.h = x ; + localwhere.v = y ; + + GrafPtr port ; + ::GetPort( &port ) ; + ::SetPort( UMAGetWindowPort( (WindowRef)m_macWindow ) ) ; + ::GlobalToLocal( &localwhere ) ; + ::SetPort( port ) ; + + if ( kind == mouseDown ) + { + if ( timestamp - gs_lastWhen <= (long) GetDblTime() ) + { + if ( abs( localwhere.h - gs_lastWhere.h ) < 3 && abs( localwhere.v - gs_lastWhere.v ) < 3 ) + { + // This is not right if the second mouse down + // event occured in a differen window. We + // correct this in MacDispatchMouseEvent. + if ( controlDown ) + event.SetEventType(wxEVT_RIGHT_DCLICK ) ; + else + event.SetEventType(wxEVT_LEFT_DCLICK ) ; + } + gs_lastWhen = 0 ; + } + else + { + gs_lastWhen = timestamp ; + } + gs_lastWhere = localwhere ; + } + + event.m_x = localwhere.h; + event.m_y = localwhere.v; + event.m_x += m_x; + event.m_y += m_y; + + event.m_timeStamp = timestamp; + event.SetEventObject(this); + if ( wxTheApp->s_captureWindow ) + { + int x = event.m_x ; + int y = event.m_y ; + wxTheApp->s_captureWindow->ScreenToClient( &x , &y ) ; + event.m_x = x ; + event.m_y = y ; + event.SetEventObject( wxTheApp->s_captureWindow ) ; + wxTheApp->s_captureWindow->GetEventHandler()->ProcessEvent( event ) ; + + if ( kind == mouseUp ) + { + wxTheApp->s_captureWindow = NULL ; + if ( !wxIsBusy() ) + { + m_cursor.MacInstall() ; + } + } + } + else + { + MacDispatchMouseEvent( event ) ; + } +} + +#if !TARGET_CARBON + +void wxTopLevelWindowMac::MacMouseDown( WXEVENTREF ev , short part) +{ + MacFireMouseEvent( mouseDown , ((EventRecord*)ev)->where.h , ((EventRecord*)ev)->where.v , + ((EventRecord*)ev)->modifiers , ((EventRecord*)ev)->when ) ; +} + +void wxTopLevelWindowMac::MacMouseUp( WXEVENTREF ev , short part) +{ + switch (part) + { + case inContent: + { + MacFireMouseEvent( mouseUp , ((EventRecord*)ev)->where.h , ((EventRecord*)ev)->where.v , + ((EventRecord*)ev)->modifiers , ((EventRecord*)ev)->when ) ; + } + break ; + } +} + +void wxTopLevelWindowMac::MacMouseMoved( WXEVENTREF ev , short part) +{ + switch (part) + { + case inContent: + { + MacFireMouseEvent( nullEvent /*moved*/ , ((EventRecord*)ev)->where.h , ((EventRecord*)ev)->where.v , + ((EventRecord*)ev)->modifiers , ((EventRecord*)ev)->when ) ; + } + break ; + } +} + +#endif + +void wxTopLevelWindowMac::MacDelayedDeactivation(long timestamp) +{ + if(s_macDeactivateWindow) + { + wxLogDebug(wxT("Doing delayed deactivation of %p"),s_macDeactivateWindow); + s_macDeactivateWindow->MacActivate(timestamp, false); + } +} + +void wxTopLevelWindowMac::MacActivate( long timestamp , bool inIsActivating ) +{ + // wxLogDebug(wxT("TopLevel=%p::MacActivate"),this); + + if(s_macDeactivateWindow==this) + s_macDeactivateWindow=NULL; + MacDelayedDeactivation(timestamp); + wxActivateEvent event(wxEVT_ACTIVATE, inIsActivating , m_windowId); + event.m_timeStamp = timestamp ; + event.SetEventObject(this); + + GetEventHandler()->ProcessEvent(event); + + UMAHighlightAndActivateWindow( (WindowRef)m_macWindow , inIsActivating ) ; + + // Early versions of MacOS X don't refresh backgrounds properly, + // so refresh the whole window on activation and deactivation. + long osVersion = UMAGetSystemVersion(); + if (osVersion >= 0x1000 && osVersion < 0x1020 ) + { + Refresh(TRUE); + } + else + { + // for the moment we have to resolve some redrawing issues like this + // the OS is stealing some redrawing areas as soon as it draws a control + Refresh(TRUE); + } +} + +#if !TARGET_CARBON + +void wxTopLevelWindowMac::MacKeyDown( WXEVENTREF ev ) +{ +} + +#endif + +void wxTopLevelWindowMac::SetTitle(const wxString& title) +{ + wxWindow::SetTitle( title ) ; + UMASetWTitle( (WindowRef)m_macWindow , title , m_font.GetEncoding() ) ; +} + +bool wxTopLevelWindowMac::Show(bool show) +{ + if ( !wxWindow::Show(show) ) + return FALSE; + + if (show) + { + #if wxUSE_SYSTEM_OPTIONS //code contributed by Ryan Wilcox December 18, 2003 + if ( (wxSystemOptions::HasOption(wxMAC_WINDOW_PLAIN_TRANSITION) ) && ( wxSystemOptions::GetOptionInt( wxMAC_WINDOW_PLAIN_TRANSITION ) == 1) ) + { + ::ShowWindow( (WindowRef)m_macWindow ); + } + else + #endif + { + ::TransitionWindow((WindowRef)m_macWindow,kWindowZoomTransitionEffect,kWindowShowTransitionAction,nil); + } + ::SelectWindow( (WindowRef)m_macWindow ) ; + // no need to generate events here, they will get them triggered by macos + // actually they should be , but apparently they are not + wxSize size(m_width, m_height); + wxSizeEvent event(size, m_windowId); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); + } + else + { + #if wxUSE_SYSTEM_OPTIONS + if ( (wxSystemOptions::HasOption(wxMAC_WINDOW_PLAIN_TRANSITION) ) && ( wxSystemOptions::GetOptionInt( wxMAC_WINDOW_PLAIN_TRANSITION ) == 1) ) + { + ::HideWindow((WindowRef) m_macWindow ); + } + else + #endif + { + ::TransitionWindow((WindowRef)m_macWindow,kWindowZoomTransitionEffect,kWindowHideTransitionAction,nil); + } + } + + if ( !show ) + { + } + else + { + Refresh() ; + } + + return TRUE; +} + +void wxTopLevelWindowMac::DoMoveWindow(int x, int y, int width, int height) +{ + wxMacPortStateHelper help( (GrafPtr) GetWindowPort( (WindowRef) m_macWindow) ) ; + wxMacWindowClipper clip (this); + + int former_x = m_x ; + int former_y = m_y ; + int former_w = m_width ; + int former_h = m_height ; + + int actualWidth = width; + int actualHeight = height; + int actualX = x; + int actualY = y; + + if ((m_minWidth != -1) && (actualWidth < m_minWidth)) + actualWidth = m_minWidth; + if ((m_minHeight != -1) && (actualHeight < m_minHeight)) + actualHeight = m_minHeight; + if ((m_maxWidth != -1) && (actualWidth > m_maxWidth)) + actualWidth = m_maxWidth; + if ((m_maxHeight != -1) && (actualHeight > m_maxHeight)) + actualHeight = m_maxHeight; + + bool doMove = false ; + bool doResize = false ; + + if ( actualX != former_x || actualY != former_y ) + { + doMove = true ; + } + if ( actualWidth != former_w || actualHeight != former_h ) + { + doResize = true ; + } + + if ( doMove || doResize ) + { + m_x = actualX ; + m_y = actualY ; + + if ( doMove ) + ::MoveWindow((WindowRef)m_macWindow, m_x, m_y , false); // don't make frontmost + + m_width = actualWidth ; + m_height = actualHeight ; + + if ( doResize ) + ::SizeWindow((WindowRef)m_macWindow, m_width, m_height , true); + + // the OS takes care of invalidating and erasing the new area so we only have to + // take care of refreshing for full repaints + + if ( doResize && HasFlag(wxFULL_REPAINT_ON_RESIZE) ) + Refresh() ; + + + if ( IsKindOf( CLASSINFO( wxFrame ) ) ) + { + wxFrame* frame = (wxFrame*) this ; +#if wxUSE_STATUSBAR + frame->PositionStatusBar(); +#endif +#if wxUSE_TOOLBAR + frame->PositionToolBar(); +#endif + } + if ( doMove ) + wxWindowMac::MacTopLevelWindowChangedPosition() ; // like this only children will be notified + + MacRepositionScrollBars() ; + if ( doMove ) + { + wxPoint point(m_x, m_y); + wxMoveEvent event(point, m_windowId); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event) ; + } + if ( doResize ) + { + MacRepositionScrollBars() ; + wxSize size(m_width, m_height); + wxSizeEvent event(size, m_windowId); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); + } + } + +} + +/* + * Invalidation Mechanism + * + * The update mechanism reflects exactely the windows mechanism + * the rect gets added to the window invalidate region, if the eraseBackground flag + * has been true for any part of the update rgn the background is erased in the entire region + * not just in the specified rect. + * + * In order to achive this, we also have an internal m_macNoEraseUpdateRgn, all rects that have + * the eraseBackground flag set to false are also added to this rgn. upon receiving an update event + * the update rgn is compared to the m_macNoEraseUpdateRgn and in case they differ, every window + * will get the eraseBackground event first + */ + +void wxTopLevelWindowMac::MacInvalidate( const WXRECTPTR rect, bool eraseBackground ) +{ + GrafPtr formerPort ; + GetPort( &formerPort ) ; + SetPortWindowPort( (WindowRef)m_macWindow ) ; + + m_macNeedsErasing |= eraseBackground ; + + // if we already know that we will have to erase, there's no need to track the rest + if ( !m_macNeedsErasing) + { + // we end only here if eraseBackground is false + // if we already have a difference between m_macNoEraseUpdateRgn and UpdateRgn + // we will have to erase anyway + + RgnHandle updateRgn = NewRgn(); + RgnHandle diffRgn = NewRgn() ; + if ( updateRgn && diffRgn ) + { + GetWindowUpdateRgn( (WindowRef)m_macWindow , updateRgn ); + Point pt = {0,0} ; + LocalToGlobal( &pt ) ; + OffsetRgn( updateRgn , -pt.h , -pt.v ) ; + DiffRgn( updateRgn , (RgnHandle) m_macNoEraseUpdateRgn , diffRgn ) ; + if ( !EmptyRgn( diffRgn ) ) + { + m_macNeedsErasing = true ; + } + } + if ( updateRgn ) + DisposeRgn( updateRgn ); + if ( diffRgn ) + DisposeRgn( diffRgn ); + + if ( !m_macNeedsErasing ) + { + RgnHandle rectRgn = NewRgn() ; + SetRectRgn( rectRgn , ((Rect*)rect)->left , ((Rect*)rect)->top , ((Rect*)rect)->right , ((Rect*)rect)->bottom ) ; + UnionRgn( (RgnHandle) m_macNoEraseUpdateRgn , rectRgn , (RgnHandle) m_macNoEraseUpdateRgn ) ; + DisposeRgn( rectRgn ) ; + } + } + InvalWindowRect( (WindowRef)m_macWindow , (Rect*)rect ) ; + // turn this on to debug the refreshing cycle +#if wxMAC_DEBUG_REDRAW + PaintRect( rect ) ; +#endif + SetPort( formerPort ) ; +} + + +bool wxTopLevelWindowMac::SetShape(const wxRegion& region) +{ + wxCHECK_MSG( HasFlag(wxFRAME_SHAPED), FALSE, + _T("Shaped windows must be created with the wxFRAME_SHAPED style.")); + +#if TARGET_CARBON + // The empty region signifies that the shape should be removed from the + // window. + if ( region.IsEmpty() ) + { + wxSize sz = GetClientSize(); + wxRegion rgn(0, 0, sz.x, sz.y); + return SetShape(rgn); + } + + // Make a copy of the region + RgnHandle shapeRegion = NewRgn(); + CopyRgn( (RgnHandle)region.GetWXHRGN(), shapeRegion ); + + // Dispose of any shape region we may already have + RgnHandle oldRgn = (RgnHandle)GetWRefCon( (WindowRef)MacGetWindowRef() ); + if ( oldRgn ) + DisposeRgn(oldRgn); + + // Save the region so we can use it later + SetWRefCon((WindowRef)MacGetWindowRef(), (SInt32)shapeRegion); + + // Tell the window manager that the window has changed shape + ReshapeCustomWindow((WindowRef)MacGetWindowRef()); + return TRUE; +#else + return FALSE; +#endif +} + +// --------------------------------------------------------------------------- +// Support functions for shaped windows, based on Apple's CustomWindow sample at +// http://developer.apple.com/samplecode/Sample_Code/Human_Interface_Toolbox/Mac_OS_High_Level_Toolbox/CustomWindow.htm +// --------------------------------------------------------------------------- + +#if TARGET_CARBON + +static void wxShapedMacWindowGetPos(WindowRef window, Rect* inRect) +{ + GetWindowPortBounds(window, inRect); + Point pt = {inRect->left, inRect->top}; + SetPort((GrafPtr) GetWindowPort(window)); + LocalToGlobal(&pt); + inRect->top = pt.v; + inRect->left = pt.h; + inRect->bottom += pt.v; + inRect->right += pt.h; +} + + +static SInt32 wxShapedMacWindowGetFeatures(WindowRef window, SInt32 param) +{ + /*------------------------------------------------------ + Define which options your custom window supports. + --------------------------------------------------------*/ + //just enable everything for our demo + *(OptionBits*)param=//kWindowCanGrow| + //kWindowCanZoom| + //kWindowCanCollapse| + //kWindowCanGetWindowRegion| + //kWindowHasTitleBar| + //kWindowSupportsDragHilite| + kWindowCanDrawInCurrentPort| + //kWindowCanMeasureTitle| + kWindowWantsDisposeAtProcessDeath| + kWindowSupportsSetGrowImageRegion| + kWindowDefSupportsColorGrafPort; + return 1; +} + +// The content region is left as a rectangle matching the window size, this is +// so the origin in the paint event, and etc. still matches what the +// programmer expects. +static void wxShapedMacWindowContentRegion(WindowRef window, RgnHandle rgn) +{ + SetEmptyRgn(rgn); + wxTopLevelWindowMac* win = wxFindWinFromMacWindow(window); + if (win) + { + wxRect r = win->GetRect(); + SetRectRgn(rgn, r.GetLeft(), r.GetTop(), r.GetRight(), r.GetBottom()); + } +} + +// The structure region is set to the shape given to the SetShape method. +static void wxShapedMacWindowStructureRegion(WindowRef window, RgnHandle rgn) +{ + RgnHandle cachedRegion = (RgnHandle) GetWRefCon(window); + + SetEmptyRgn(rgn); + if (cachedRegion) + { + Rect windowRect; + wxShapedMacWindowGetPos(window, &windowRect); //how big is the window + CopyRgn(cachedRegion, rgn); //make a copy of our cached region + OffsetRgn(rgn, windowRect.left, windowRect.top); // position it over window + //MapRgn(rgn, &mMaskSize, &windowRect); //scale it to our actual window size + } +} + + + +static SInt32 wxShapedMacWindowGetRegion(WindowRef window, SInt32 param) +{ + GetWindowRegionPtr rgnRec=(GetWindowRegionPtr)param; + + switch(rgnRec->regionCode) + { + case kWindowStructureRgn: + wxShapedMacWindowStructureRegion(window, rgnRec->winRgn); + break; + case kWindowContentRgn: + wxShapedMacWindowContentRegion(window, rgnRec->winRgn); + break; + default: + SetEmptyRgn(rgnRec->winRgn); + } //switch + + return noErr; +} + + +static SInt32 wxShapedMacWindowHitTest(WindowRef window,SInt32 param) +{ + /*------------------------------------------------------ + Determine the region of the window which was hit + --------------------------------------------------------*/ + Point hitPoint; + static RgnHandle tempRgn=nil; + + if(!tempRgn) + tempRgn=NewRgn(); + + SetPt(&hitPoint,LoWord(param),HiWord(param));//get the point clicked + + //Mac OS 8.5 or later + wxShapedMacWindowStructureRegion(window, tempRgn); + if (PtInRgn(hitPoint, tempRgn)) //in window content region? + return wInContent; + + return wNoHit;//no significant area was hit. +} + + +static pascal long wxShapedMacWindowDef(short varCode, WindowRef window, SInt16 message, SInt32 param) +{ + switch(message) + { + case kWindowMsgHitTest: + return wxShapedMacWindowHitTest(window,param); + + case kWindowMsgGetFeatures: + return wxShapedMacWindowGetFeatures(window,param); + + // kWindowMsgGetRegion is sent during CreateCustomWindow and ReshapeCustomWindow + case kWindowMsgGetRegion: + return wxShapedMacWindowGetRegion(window,param); + } + + return 0; +} + +#endif +// --------------------------------------------------------------------------- + diff --git a/src/mac/classic/treectrl.cpp b/src/mac/classic/treectrl.cpp new file mode 100644 index 0000000000..7a548a7436 --- /dev/null +++ b/src/mac/classic/treectrl.cpp @@ -0,0 +1,419 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: treectrl.cpp +// Purpose: wxTreeCtrl. See also Robert's generic wxTreeCtrl. +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "treectrl.h" +#endif + +#include "wx/stubs/textctrl.h" +#include "wx/treebase.h" +#include "wx/stubs/treectrl.h" + +#if !USE_SHARED_LIBRARY +IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxControl) +IMPLEMENT_DYNAMIC_CLASS(wxTreeItem, wxObject) + +#endif + +wxTreeCtrl::wxTreeCtrl() +{ + m_imageListNormal = NULL; + m_imageListState = NULL; + m_textCtrl = NULL; +} + +bool wxTreeCtrl::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, + long style, const wxValidator& validator, const wxString& name) +{ + SetName(name); + SetValidator(validator); + + m_imageListNormal = NULL; + m_imageListState = NULL; + m_textCtrl = NULL; + + m_windowStyle = style; + + SetParent(parent); + + m_windowId = (id == -1) ? NewControlId() : id; + + if (parent) parent->AddChild(this); + + // TODO create tree control + + return FALSE; +} + +wxTreeCtrl::~wxTreeCtrl() +{ + if (m_textCtrl) + { + delete m_textCtrl; + } +} + +// Attributes +int wxTreeCtrl::GetCount() const +{ + // TODO + return 0; +} + +int wxTreeCtrl::GetIndent() const +{ + // TODO + return 0; +} + +void wxTreeCtrl::SetIndent(int indent) +{ + // TODO +} + +wxImageList *wxTreeCtrl::GetImageList(int which) const +{ + if ( which == wxIMAGE_LIST_NORMAL ) + { + return m_imageListNormal; + } + else if ( which == wxIMAGE_LIST_STATE ) + { + return m_imageListState; + } + return NULL; +} + +void wxTreeCtrl::SetImageList(wxImageList *imageList, int which) +{ + if ( which == wxIMAGE_LIST_NORMAL ) + { + m_imageListNormal = imageList; + } + else if ( which == wxIMAGE_LIST_STATE ) + { + m_imageListState = imageList; + } + // TODO +} + +long wxTreeCtrl::GetNextItem(long item, int code) const +{ + // TODO + return 0; +} + +bool wxTreeCtrl::ItemHasChildren(long item) const +{ + // TODO + return FALSE; +} + +long wxTreeCtrl::GetChild(long item) const +{ + // TODO + return 0; +} + +long wxTreeCtrl::GetItemParent(long item) const +{ + // TODO + return 0; +} + +long wxTreeCtrl::GetFirstVisibleItem() const +{ + // TODO + return 0; +} + +long wxTreeCtrl::GetNextVisibleItem(long item) const +{ + // TODO + return 0; +} + +long wxTreeCtrl::GetSelection() const +{ + // TODO + return 0; +} + +long wxTreeCtrl::GetRootItem() const +{ + // TODO + return 0; +} + +bool wxTreeCtrl::GetItem(wxTreeItem& info) const +{ + // TODO + return FALSE; +} + +bool wxTreeCtrl::SetItem(wxTreeItem& info) +{ + // TODO + return FALSE; +} + +int wxTreeCtrl::GetItemState(long item, long stateMask) const +{ + wxTreeItem info; + + info.m_mask = wxTREE_MASK_STATE ; + info.m_stateMask = stateMask; + info.m_itemId = item; + + if (!GetItem(info)) + return 0; + + return info.m_state; +} + +bool wxTreeCtrl::SetItemState(long item, long state, long stateMask) +{ + wxTreeItem info; + + info.m_mask = wxTREE_MASK_STATE ; + info.m_state = state; + info.m_stateMask = stateMask; + info.m_itemId = item; + + return SetItem(info); +} + +bool wxTreeCtrl::SetItemImage(long item, int image, int selImage) +{ + wxTreeItem info; + + info.m_mask = wxTREE_MASK_IMAGE ; + info.m_image = image; + if ( selImage > -1) + { + info.m_selectedImage = selImage; + info.m_mask |= wxTREE_MASK_SELECTED_IMAGE; + } + info.m_itemId = item; + + return SetItem(info); +} + +wxString wxTreeCtrl::GetItemText(long item) const +{ + wxTreeItem info; + + info.m_mask = wxTREE_MASK_TEXT ; + info.m_itemId = item; + + if (!GetItem(info)) + return wxString(""); + return info.m_text; +} + +void wxTreeCtrl::SetItemText(long item, const wxString& str) +{ + wxTreeItem info; + + info.m_mask = wxTREE_MASK_TEXT ; + info.m_itemId = item; + info.m_text = str; + + SetItem(info); +} + +long wxTreeCtrl::GetItemData(long item) const +{ + wxTreeItem info; + + info.m_mask = wxTREE_MASK_DATA ; + info.m_itemId = item; + + if (!GetItem(info)) + return 0; + return info.m_data; +} + +bool wxTreeCtrl::SetItemData(long item, long data) +{ + wxTreeItem info; + + info.m_mask = wxTREE_MASK_DATA ; + info.m_itemId = item; + info.m_data = data; + + return SetItem(info); +} + +bool wxTreeCtrl::GetItemRect(long item, wxRect& rect, bool textOnly) const +{ + // TODO + return FALSE; +} + +wxTextCtrl* wxTreeCtrl::GetEditControl() const +{ + return m_textCtrl; +} + +// Operations +bool wxTreeCtrl::DeleteItem(long item) +{ + // TODO + return FALSE; +} + +bool wxTreeCtrl::ExpandItem(long item, int action) +{ + // TODO + switch ( action ) + { + case wxTREE_EXPAND_EXPAND: + break; + + case wxTREE_EXPAND_COLLAPSE: + break; + + case wxTREE_EXPAND_COLLAPSE_RESET: + break; + + case wxTREE_EXPAND_TOGGLE: + break; + + default: + wxFAIL_MSG("unknown action in wxTreeCtrl::ExpandItem"); + } + + bool bOk = FALSE; // TODO expand item + + // May not send messages, so emulate them + if ( bOk ) { + wxTreeEvent event(wxEVT_NULL, m_windowId); + event.m_item.m_itemId = item; + event.m_item.m_mask = + event.m_item.m_stateMask = 0xffff; // get all + GetItem(event.m_item); + + bool bIsExpanded = (event.m_item.m_state & wxTREE_STATE_EXPANDED) != 0; + + event.m_code = action; + event.SetEventObject(this); + + // @@@ return values of {EXPAND|COLLAPS}ING event handler is discarded + event.SetEventType(bIsExpanded ? wxEVT_COMMAND_TREE_ITEM_EXPANDING + : wxEVT_COMMAND_TREE_ITEM_COLLAPSING); + GetEventHandler()->ProcessEvent(event); + + event.SetEventType(bIsExpanded ? wxEVT_COMMAND_TREE_ITEM_EXPANDED + : wxEVT_COMMAND_TREE_ITEM_COLLAPSED); + GetEventHandler()->ProcessEvent(event); + } + + return bOk; +} + +long wxTreeCtrl::InsertItem(long parent, wxTreeItem& info, long insertAfter) +{ + // TODO + return 0; +} + +long wxTreeCtrl::InsertItem(long parent, const wxString& label, int image, int selImage, + long insertAfter) +{ + wxTreeItem info; + info.m_text = label; + info.m_mask = wxTREE_MASK_TEXT; + if ( image > -1 ) + { + info.m_mask |= wxTREE_MASK_IMAGE | wxTREE_MASK_SELECTED_IMAGE; + info.m_image = image; + if ( selImage == -1 ) + info.m_selectedImage = image; + else + info.m_selectedImage = selImage; + } + + return InsertItem(parent, info, insertAfter); +} + +bool wxTreeCtrl::SelectItem(long item) +{ + // TODO + return FALSE; +} + +bool wxTreeCtrl::ScrollTo(long item) +{ + // TODO + return FALSE; +} + +bool wxTreeCtrl::DeleteAllItems() +{ + // TODO + return FALSE; +} + +wxTextCtrl* wxTreeCtrl::EditLabel(long item, wxClassInfo* textControlClass) +{ + // TODO + return NULL; +} + +// End label editing, optionally cancelling the edit +bool wxTreeCtrl::EndEditLabel(bool cancel) +{ + // TODO + return FALSE; +} + +long wxTreeCtrl::HitTest(const wxPoint& point, int& flags) +{ + // TODO + return 0; +} + +bool wxTreeCtrl::SortChildren(long item) +{ + // TODO + return FALSE; +} + +bool wxTreeCtrl::EnsureVisible(long item) +{ + // TODO + return FALSE; +} + +// Tree item structure +wxTreeItem::wxTreeItem() +{ + m_mask = 0; + m_itemId = 0; + m_state = 0; + m_stateMask = 0; + m_image = -1; + m_selectedImage = -1; + m_children = 0; + m_data = 0; +} + +// Tree event +IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxCommandEvent) + +wxTreeEvent::wxTreeEvent(wxEventType commandType, int id): + wxCommandEvent(commandType, id) +{ + m_code = 0; + m_oldItem = 0; +} + diff --git a/src/mac/classic/uma.cpp b/src/mac/classic/uma.cpp new file mode 100644 index 0000000000..48a7599f04 --- /dev/null +++ b/src/mac/classic/uma.cpp @@ -0,0 +1,815 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: uma.cpp +// Purpose: UMA support +// Author: Stefan Csomor +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: The wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/defs.h" + +#if wxUSE_GUI + +#include "wx/dc.h" +#include + +#ifndef __DARWIN__ +# include +# if defined(TARGET_CARBON) +# if PM_USE_SESSION_APIS +# include +# endif +# include +# else +# include +# endif +#endif + +#ifndef __DARWIN__ +#include +#endif +#include "wx/mac/uma.h" + + +// since we have decided that we only support 8.6 upwards we are +// checking for these minimum requirements in the startup code of +// the application so all wxWindows code can safely assume that appearance 1.1 +// windows manager, control manager, navigation services etc. are +// present + +static bool sUMAHasAppearance = false ; +static long sUMAAppearanceVersion = 0 ; +static long sUMASystemVersion = 0 ; +static bool sUMAHasAquaLayout = false ; + +static bool sUMAHasInittedAppearance = false; + +extern int gAGABackgroundColor ; +bool UMAHasAppearance() { return sUMAHasAppearance ; } +long UMAGetAppearanceVersion() { return sUMAAppearanceVersion ; } +long UMAGetSystemVersion() { return sUMASystemVersion ; } + +static bool sUMAHasWindowManager = false ; +static long sUMAWindowManagerAttr = 0 ; + +bool UMAHasWindowManager() { return sUMAHasWindowManager ; } +long UMAGetWindowManagerAttr() { return sUMAWindowManagerAttr ; } +bool UMAHasAquaLayout() { return sUMAHasAquaLayout ; } + + +void UMACleanupToolbox() +{ + if (sUMAHasInittedAppearance) + { + UnregisterAppearanceClient() ; + } + if ( NavServicesAvailable() ) + { + NavUnload() ; + } + if ( TXNTerminateTextension != (void*) kUnresolvedCFragSymbolAddress ) + TXNTerminateTextension( ) ; +} +void UMAInitToolbox( UInt16 inMoreMastersCalls, bool isEmbedded ) +{ +#if !TARGET_CARBON + ::MaxApplZone(); + for (long i = 1; i <= inMoreMastersCalls; i++) + ::MoreMasters(); + + if (!isEmbedded) + { + ::InitGraf(&qd.thePort); + ::InitFonts(); + ::InitMenus(); + ::TEInit(); + ::InitDialogs(0L); + ::FlushEvents(everyEvent, 0); + } + + long total,contig; + PurgeSpace(&total, &contig); +#endif + + ::InitCursor(); + + if ( Gestalt(gestaltSystemVersion, &sUMASystemVersion) != noErr) + sUMASystemVersion = 0x0000 ; + + long theAppearance ; + if ( Gestalt( gestaltAppearanceAttr, &theAppearance ) == noErr ) + { + sUMAHasAppearance = true ; + OSStatus status = RegisterAppearanceClient(); + // If status equals appearanceProcessRegisteredErr it means the + // appearance client already was registered (For example if we run + // embedded, the host might have registered it). In such a case + // we don't unregister it later on. + if (status != appearanceProcessRegisteredErr) + { + // Appearance client wasn't registered yet. + sUMAHasInittedAppearance = true; + } + + if ( Gestalt( gestaltAppearanceVersion, &theAppearance ) == noErr ) + { + sUMAAppearanceVersion = theAppearance ; + } + else + { + sUMAAppearanceVersion = 0x0100 ; + } + } + if ( Gestalt( gestaltWindowMgrAttr, &sUMAWindowManagerAttr ) == noErr ) + { + sUMAHasWindowManager = sUMAWindowManagerAttr & gestaltWindowMgrPresent ; + } + +#if TARGET_CARBON +// Call currently implicitely done : InitFloatingWindows() ; +#else + if (!isEmbedded) + { + if ( sUMAHasWindowManager ) + InitFloatingWindows() ; + else + InitWindows(); + } +#endif + + if ( NavServicesAvailable() ) + { + NavLoad() ; + } + + long menuMgrAttr ; + Gestalt( gestaltMenuMgrAttr , &menuMgrAttr ) ; + if ( menuMgrAttr & gestaltMenuMgrAquaLayoutMask ) + sUMAHasAquaLayout = true ; + + if ( TXNInitTextension != (void*) kUnresolvedCFragSymbolAddress ) + { + FontFamilyID fontId ; + Str255 fontName ; + SInt16 fontSize ; + Style fontStyle ; + GetThemeFont(kThemeSmallSystemFont , GetApplicationScript() , fontName , &fontSize , &fontStyle ) ; + GetFNum( fontName, &fontId ); + + TXNMacOSPreferredFontDescription fontDescriptions[] = + { + { fontId , (fontSize << 16) ,kTXNDefaultFontStyle, kTXNSystemDefaultEncoding } + } ; + int noOfFontDescriptions = sizeof( fontDescriptions ) / sizeof(TXNMacOSPreferredFontDescription) ; + + // kTXNAlwaysUseQuickDrawTextMask might be desirable because of speed increases but it crashes the app under OS X upon key stroke +#if 0 + // leads to unexpected content for clients, TODO configurable + OptionBits options = kTXNWantMoviesMask | kTXNWantSoundMask | kTXNWantGraphicsMask ; +#else + OptionBits options = 0 ; +#endif + +#if TARGET_CARBON + if ( !UMAHasAquaLayout() ) +#endif + { + options |= kTXNAlwaysUseQuickDrawTextMask ; + } + TXNInitTextension(fontDescriptions, noOfFontDescriptions, options ); + } + + + UMASetSystemIsInitialized(true); + +} + +/* +Boolean CanUseATSUI() + { + long result; + OSErr err = Gestalt(gestaltATSUVersion, &result); + return (err == noErr); + } +*/ +// process manager +long UMAGetProcessMode() +{ + OSErr err ; + ProcessInfoRec processinfo; + ProcessSerialNumber procno ; + + procno.highLongOfPSN = NULL ; + procno.lowLongOfPSN = kCurrentProcess ; + processinfo.processInfoLength = sizeof(ProcessInfoRec); + processinfo.processName = NULL; + processinfo.processAppSpec = NULL; + + err = ::GetProcessInformation( &procno , &processinfo ) ; + wxASSERT( err == noErr ) ; + return processinfo.processMode ; +} + +bool UMAGetProcessModeDoesActivateOnFGSwitch() +{ + return UMAGetProcessMode() & modeDoesActivateOnFGSwitch ; +} + +// menu manager + +MenuRef UMANewMenu( SInt16 id , const wxString& title , wxFontEncoding encoding ) +{ + wxString str = wxStripMenuCodes( title ) ; + MenuRef menu ; +#if TARGET_CARBON + CreateNewMenu( id , 0 , &menu ) ; + SetMenuTitleWithCFString( menu , wxMacCFStringHolder(str , encoding ) ) ; +#else + Str255 ptitle ; + wxMacStringToPascal( str , ptitle ) ; + menu = ::NewMenu( id , ptitle ) ; +#endif + return menu ; +} + +void UMASetMenuTitle( MenuRef menu , const wxString& title , wxFontEncoding encoding) +{ + wxString str = wxStripMenuCodes( title ) ; +#if TARGET_CARBON + SetMenuTitleWithCFString( menu , wxMacCFStringHolder(str , encoding) ) ; +#else + Str255 ptitle ; + wxMacStringToPascal( str , ptitle ) ; + SetMenuTitle( menu , ptitle ) ; +#endif +} + +void UMASetMenuItemText( MenuRef menu, MenuItemIndex item, const wxString& title , wxFontEncoding encoding) +{ + wxString str = wxStripMenuCodes( title ) ; +#if TARGET_CARBON + SetMenuItemTextWithCFString( menu , item , wxMacCFStringHolder(str , encoding) ) ; +#else + Str255 ptitle ; + wxMacStringToPascal( str , ptitle ) ; + SetMenuItemText( menu , item , ptitle ) ; +#endif +} + + +UInt32 UMAMenuEvent( EventRecord *inEvent ) +{ + return MenuEvent( inEvent ) ; +} + +void UMAEnableMenuItem( MenuRef inMenu , MenuItemIndex inItem , bool enable) +{ + if ( enable ) + EnableMenuItem( inMenu , inItem ) ; + else + DisableMenuItem( inMenu , inItem ) ; +} + +void UMAAppendSubMenuItem( MenuRef menu , const wxString& title, wxFontEncoding encoding , SInt16 id ) +{ + MacAppendMenu(menu, "\pA"); + UMASetMenuItemText(menu, (SInt16) ::CountMenuItems(menu), title , encoding ); + SetMenuItemHierarchicalID( menu , CountMenuItems( menu ) , id ) ; +} + +void UMAInsertSubMenuItem( MenuRef menu , const wxString& title, wxFontEncoding encoding , MenuItemIndex item , SInt16 id ) +{ + MacInsertMenuItem(menu, "\pA" , item); + UMASetMenuItemText(menu, item , title , encoding); + SetMenuItemHierarchicalID( menu , item , id ) ; +} + +void UMASetMenuItemShortcut( MenuRef menu , MenuItemIndex item , wxAcceleratorEntry *entry ) +{ + if ( !entry ) + return ; + + UInt8 modifiers = 0 ; + SInt16 key = entry->GetKeyCode() ; + if ( key ) + { + bool explicitCommandKey = false ; + + if ( entry->GetFlags() & wxACCEL_CTRL ) + { + explicitCommandKey = true ; + } + + if (entry->GetFlags() & wxACCEL_ALT ) + { + modifiers |= kMenuOptionModifier ; + } + + if (entry->GetFlags() & wxACCEL_SHIFT) + { + modifiers |= kMenuShiftModifier ; + } + + SInt16 glyph = 0 ; + SInt16 macKey = key ; + if ( key >= WXK_F1 && key <= WXK_F15 ) + { + // for some reasons this must be 0 right now + // everything else leads to just the first function key item + // to be selected. Thanks to Ryan Wilcox for finding out. + macKey = 0 ; + glyph = kMenuF1Glyph + ( key - WXK_F1 ) ; + if ( key >= WXK_F13 ) + glyph += 13 ; + if ( !explicitCommandKey ) + modifiers |= kMenuNoCommandModifier ; + } + else + { + switch( key ) + { + case WXK_BACK : + macKey = kBackspaceCharCode ; + glyph = kMenuDeleteLeftGlyph ; + break ; + case WXK_TAB : + macKey = kTabCharCode ; + glyph = kMenuTabRightGlyph ; + break ; + case kEnterCharCode : + macKey = kEnterCharCode ; + glyph = kMenuEnterGlyph ; + break ; + case WXK_RETURN : + macKey = kReturnCharCode ; + glyph = kMenuReturnGlyph ; + break ; + case WXK_ESCAPE : + macKey = kEscapeCharCode ; + glyph = kMenuEscapeGlyph ; + break ; + case WXK_SPACE : + macKey = ' ' ; + glyph = kMenuSpaceGlyph ; + break ; + case WXK_DELETE : + macKey = kDeleteCharCode ; + glyph = kMenuDeleteRightGlyph ; + break ; + case WXK_CLEAR : + macKey = kClearCharCode ; + glyph = kMenuClearGlyph ; + break ; + case WXK_PRIOR : // PAGE UP + macKey = kPageUpCharCode ; + glyph = kMenuPageUpGlyph ; + break ; + case WXK_NEXT : + macKey = kPageDownCharCode ; + glyph = kMenuPageDownGlyph ; + break ; + case WXK_LEFT : + macKey = kLeftArrowCharCode ; + glyph = kMenuLeftArrowGlyph ; + break ; + case WXK_UP : + macKey = kUpArrowCharCode ; + glyph = kMenuUpArrowGlyph ; + break ; + case WXK_RIGHT : + macKey = kRightArrowCharCode ; + glyph = kMenuRightArrowGlyph ; + break ; + case WXK_DOWN : + macKey = kDownArrowCharCode ; + glyph = kMenuDownArrowGlyph ; + break ; + } + } + + SetItemCmd( menu, item , macKey ); + SetMenuItemModifiers(menu, item , modifiers ) ; + + if ( glyph ) + SetMenuItemKeyGlyph(menu, item , glyph ) ; + } +} + +void UMAAppendMenuItem( MenuRef menu , const wxString& title, wxFontEncoding encoding , wxAcceleratorEntry *entry ) +{ + MacAppendMenu(menu, "\pA"); + UMASetMenuItemText(menu, (SInt16) ::CountMenuItems(menu), title , encoding ); + UMASetMenuItemShortcut( menu , (SInt16) ::CountMenuItems(menu), entry ) ; +} + +void UMAInsertMenuItem( MenuRef menu , const wxString& title, wxFontEncoding encoding , MenuItemIndex item , wxAcceleratorEntry *entry ) +{ + MacInsertMenuItem( menu , "\pA" , item) ; + UMASetMenuItemText(menu, item+1 , title , encoding ); + UMASetMenuItemShortcut( menu , item+1 , entry ) ; +} + +// quickdraw + +#if !TARGET_CARBON + +int gPrOpenCounter = 0 ; + +OSStatus UMAPrOpen() +{ + OSErr err = noErr ; + ++gPrOpenCounter ; + if ( gPrOpenCounter == 1 ) + { + PrOpen() ; + err = PrError() ; + wxASSERT( err == noErr ) ; + } + return err ; +} + +OSStatus UMAPrClose() +{ + OSErr err = noErr ; + wxASSERT( gPrOpenCounter >= 1 ) ; + if ( gPrOpenCounter == 1 ) + { + PrClose() ; + err = PrError() ; + wxASSERT( err == noErr ) ; + } + --gPrOpenCounter ; + return err ; +} + +pascal QDGlobalsPtr GetQDGlobalsPtr (void) ; +pascal QDGlobalsPtr GetQDGlobalsPtr (void) +{ + return QDGlobalsPtr (* (Ptr*) LMGetCurrentA5 ( ) - 0xCA); +} + +#endif + +void UMAShowWatchCursor() +{ + OSErr err = noErr; + + CursHandle watchFob = GetCursor (watchCursor); + + if (!watchFob) + err = nilHandleErr; + else + { + #if TARGET_CARBON +// Cursor preservedArrow; +// GetQDGlobalsArrow (&preservedArrow); +// SetQDGlobalsArrow (*watchFob); +// InitCursor ( ); +// SetQDGlobalsArrow (&preservedArrow); + SetCursor (*watchFob); + #else + SetCursor (*watchFob); + #endif + } +} + +void UMAShowArrowCursor() +{ +#if TARGET_CARBON + Cursor arrow; + SetCursor (GetQDGlobalsArrow (&arrow)); +#else + SetCursor (&(qd.arrow)); +#endif +} + +// window manager + +GrafPtr UMAGetWindowPort( WindowRef inWindowRef ) +{ + wxASSERT( inWindowRef != NULL ) ; +#if TARGET_CARBON + return (GrafPtr) GetWindowPort( inWindowRef ) ; +#else + return (GrafPtr) inWindowRef ; +#endif +} + +void UMADisposeWindow( WindowRef inWindowRef ) +{ + wxASSERT( inWindowRef != NULL ) ; + DisposeWindow( inWindowRef ) ; +} + +void UMASetWTitle( WindowRef inWindowRef , const wxString& title , wxFontEncoding encoding) +{ +#if TARGET_CARBON + SetWindowTitleWithCFString( inWindowRef , wxMacCFStringHolder(title , encoding) ) ; +#else + Str255 ptitle ; + wxMacStringToPascal( title , ptitle ) ; + SetWTitle( inWindowRef , ptitle ) ; +#endif +} + +// appearance additions + +void UMASetControlTitle( ControlHandle inControl , const wxString& title , wxFontEncoding encoding) +{ +#if TARGET_CARBON + SetControlTitleWithCFString( inControl , wxMacCFStringHolder(title , encoding) ) ; +#else + Str255 ptitle ; + wxMacStringToPascal( title , ptitle ) ; + SetControlTitle( inControl , ptitle ) ; +#endif +} + +void UMAActivateControl( ControlHandle inControl ) +{ + // we have to add the control after again to the update rgn + // otherwise updates get lost + if ( !IsControlActive( inControl ) ) + { + bool visible = IsControlVisible( inControl ) ; + if ( visible ) + SetControlVisibility( inControl , false , false ) ; + ::ActivateControl( inControl ) ; + if ( visible ) { + SetControlVisibility( inControl , true , false ) ; + Rect ctrlBounds ; + InvalWindowRect(GetControlOwner(inControl),GetControlBounds(inControl,&ctrlBounds) ) ; + } + } +} + +void UMADrawControl( ControlHandle inControl ) +{ + WindowRef theWindow = GetControlOwner(inControl) ; + wxMacPortStateHelper help( (GrafPtr) GetWindowPort(theWindow) ) ; + RgnHandle updateRgn = NewRgn() ; + GetWindowUpdateRgn( theWindow , updateRgn ) ; + Point zero = { 0 , 0 } ; + LocalToGlobal( &zero ) ; + OffsetRgn( updateRgn , -zero.h , -zero.v ) ; + ::DrawControlInCurrentPort( inControl ) ; + InvalWindowRgn( theWindow, updateRgn) ; + DisposeRgn( updateRgn ) ; +} + +void UMAMoveControl( ControlHandle inControl , short x , short y ) +{ + bool visible = IsControlVisible( inControl ) ; + if ( visible ) { + SetControlVisibility( inControl , false , false ) ; + Rect ctrlBounds ; + InvalWindowRect(GetControlOwner(inControl),GetControlBounds(inControl,&ctrlBounds) ) ; + } + ::MoveControl( inControl , x , y ) ; + if ( visible ) { + SetControlVisibility( inControl , true , false ) ; + Rect ctrlBounds ; + InvalWindowRect(GetControlOwner(inControl),GetControlBounds(inControl,&ctrlBounds) ) ; + } +} + +void UMASizeControl( ControlHandle inControl , short x , short y ) +{ + bool visible = IsControlVisible( inControl ) ; + if ( visible ) { + SetControlVisibility( inControl , false , false ) ; + Rect ctrlBounds ; + InvalWindowRect(GetControlOwner(inControl),GetControlBounds(inControl,&ctrlBounds) ) ; + } + ::SizeControl( inControl , x , y ) ; + if ( visible ) { + SetControlVisibility( inControl , true , false ) ; + Rect ctrlBounds ; + InvalWindowRect(GetControlOwner(inControl),GetControlBounds(inControl,&ctrlBounds) ) ; + } +} + +void UMADeactivateControl( ControlHandle inControl ) +{ + // we have to add the control after again to the update rgn + // otherwise updates get lost + bool visible = IsControlVisible( inControl ) ; + if ( visible ) + SetControlVisibility( inControl , false , false ) ; + ::DeactivateControl( inControl ) ; + if ( visible ) { + SetControlVisibility( inControl , true , false ) ; + Rect ctrlBounds ; + InvalWindowRect(GetControlOwner(inControl),GetControlBounds(inControl,&ctrlBounds) ) ; + } +} +// shows the control and adds the region to the update region +void UMAShowControl (ControlHandle inControl) +{ + SetControlVisibility( inControl , true , false ) ; + Rect ctrlBounds ; + InvalWindowRect(GetControlOwner(inControl),GetControlBounds(inControl,&ctrlBounds) ) ; +} + +// shows the control and adds the region to the update region +void UMAHideControl (ControlHandle inControl) +{ + SetControlVisibility( inControl , false , false ) ; + Rect ctrlBounds ; + InvalWindowRect(GetControlOwner(inControl),GetControlBounds(inControl,&ctrlBounds) ) ; +} +// keyboard focus +OSErr UMASetKeyboardFocus (WindowPtr inWindow, + ControlHandle inControl, + ControlFocusPart inPart) +{ + OSErr err = noErr; + GrafPtr port ; + GetPort( &port ) ; + + SetPortWindowPort( inWindow ) ; + + err = SetKeyboardFocus( inWindow , inControl , inPart ) ; + SetPort( port ) ; + return err ; +} + + +// events +void UMAUpdateControls( WindowPtr inWindow , RgnHandle inRgn ) +{ + wxMacPortStateHelper help( (GrafPtr) GetWindowPort( (WindowRef) inWindow) ) ; + RgnHandle updateRgn = NewRgn() ; + GetWindowUpdateRgn( inWindow , updateRgn ) ; + + Point zero = { 0 , 0 } ; + LocalToGlobal( &zero ) ; + OffsetRgn( updateRgn , -zero.h , -zero.v ) ; + + UpdateControls( inWindow , inRgn ) ; + InvalWindowRgn( inWindow, updateRgn) ; + DisposeRgn( updateRgn ) ; +} + +bool UMAIsWindowFloating( WindowRef inWindow ) +{ + WindowClass cl ; + + GetWindowClass( inWindow , &cl ) ; + return cl == kFloatingWindowClass ; +} + +bool UMAIsWindowModal( WindowRef inWindow ) +{ + WindowClass cl ; + + GetWindowClass( inWindow , &cl ) ; + return cl < kFloatingWindowClass ; +} + +// others + +void UMAHighlightAndActivateWindow( WindowRef inWindowRef , bool inActivate ) +{ + if ( inWindowRef ) + { +// bool isHighlighted = IsWindowHighlited( inWindowRef ) ; +// if ( inActivate != isHightlited ) + GrafPtr port ; + GetPort( &port ) ; + SetPortWindowPort( inWindowRef ) ; + HiliteWindow( inWindowRef , inActivate ) ; + ControlHandle control = NULL ; + ::GetRootControl( inWindowRef , & control ) ; + if ( control ) + { + if ( inActivate ) + UMAActivateControl( control ) ; + else + UMADeactivateControl( control ) ; + } + SetPort( port ) ; + } +} + +OSStatus UMADrawThemePlacard( const Rect *inRect , ThemeDrawState inState ) +{ + return ::DrawThemePlacard( inRect , inState ) ; +} + +#if !TARGET_CARBON +static OSStatus helpMenuStatus = noErr ; +static MenuItemIndex firstCustomItemIndex = 0 ; +#endif + +OSStatus UMAGetHelpMenu( + MenuRef * outHelpMenu, + MenuItemIndex * outFirstCustomItemIndex) +{ +#if TARGET_CARBON + return HMGetHelpMenu( outHelpMenu , outFirstCustomItemIndex ) ; +#else + MenuRef helpMenuHandle ; + helpMenuStatus = HMGetHelpMenuHandle( &helpMenuHandle ) ; + if ( firstCustomItemIndex == 0 && helpMenuStatus == noErr ) + { + firstCustomItemIndex = CountMenuItems( helpMenuHandle ) + 1 ; + } + if ( outFirstCustomItemIndex ) + { + *outFirstCustomItemIndex = firstCustomItemIndex ; + } + *outHelpMenu = helpMenuHandle ; + return helpMenuStatus ; +#endif +} + +wxMacPortStateHelper::wxMacPortStateHelper( GrafPtr newport) +{ + m_clip = NULL ; + Setup( newport ) ; +} + +wxMacPortStateHelper::wxMacPortStateHelper() +{ + m_clip = NULL ; +} + +void wxMacPortStateHelper::Setup( GrafPtr newport ) +{ + GetPort( &m_oldPort ) ; + SetPort( newport ) ; + SetOrigin(0,0); + wxASSERT_MSG( m_clip == NULL , wxT("Cannot call setup twice") ) ; + m_clip = NewRgn() ; + GetClip( m_clip ); + m_textFont = GetPortTextFont( (CGrafPtr) newport); + m_textSize = GetPortTextSize( (CGrafPtr) newport); + m_textStyle = GetPortTextFace( (CGrafPtr) newport); + m_textMode = GetPortTextMode( (CGrafPtr) newport); + GetThemeDrawingState( &m_drawingState ) ; + m_currentPort = newport ; +} +void wxMacPortStateHelper::Clear() +{ + if ( m_clip ) + { + DisposeRgn( m_clip ) ; + DisposeThemeDrawingState( m_drawingState ) ; + m_clip = NULL ; + } +} + +wxMacPortStateHelper::~wxMacPortStateHelper() +{ + if ( m_clip ) + { + SetPort( m_currentPort ) ; + SetClip( m_clip ) ; + DisposeRgn( m_clip ) ; + TextFont( m_textFont ); + TextSize( m_textSize ); + TextFace( m_textStyle ); + TextMode( m_textMode ); + SetThemeDrawingState( m_drawingState , true ) ; + SetPort( m_oldPort ) ; + } +} + +OSStatus UMAPutScrap( Size size , OSType type , void *data ) +{ + OSStatus err = noErr ; +#if !TARGET_CARBON + err = PutScrap( size , type , data ) ; +#else + ScrapRef scrap; + err = GetCurrentScrap (&scrap); + if ( !err ) + { + err = PutScrapFlavor (scrap, type , 0, size, data); + } +#endif + return err ; +} + +#endif // wxUSE_GUI + +#if wxUSE_BASE + +static bool sUMASystemInitialized = false ; + +bool UMASystemIsInitialized() +{ + return sUMASystemInitialized ; +} + +void UMASetSystemIsInitialized(bool val) +{ + sUMASystemInitialized = val; +} + + +#endif // wxUSE_BASE diff --git a/src/mac/classic/utils.cpp b/src/mac/classic/utils.cpp new file mode 100644 index 0000000000..b64f77fae0 --- /dev/null +++ b/src/mac/classic/utils.cpp @@ -0,0 +1,1395 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: utils.cpp +// Purpose: Various utilities +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +// Note: this is done in utilscmn.cpp now. +// #pragma implementation "utils.h" +#endif + +#include "wx/setup.h" +#include "wx/utils.h" +#include "wx/app.h" +#include "wx/apptrait.h" + +#if wxUSE_GUI + #include "wx/mac/uma.h" + #include "wx/font.h" +#else + #include "wx/intl.h" +#endif + +#include + +#include +#include +#include +#include + +#ifdef __DARWIN__ +# include "MoreFilesX.h" +#else +# include "MoreFiles.h" +# include "MoreFilesExtras.h" +#endif + +#ifndef __DARWIN__ +#include +#include +#endif + +#include +#include +#include + +#include "wx/mac/private.h" // includes mac headers + +#if defined(__MWERKS__) && wxUSE_UNICODE + #include +#endif + +// --------------------------------------------------------------------------- +// code used in both base and GUI compilation +// --------------------------------------------------------------------------- + +// our OS version is the same in non GUI and GUI cases +static int DoGetOSVersion(int *majorVsn, int *minorVsn) +{ + long theSystem ; + + // are there x-platform conventions ? + + Gestalt(gestaltSystemVersion, &theSystem) ; + if (minorVsn != NULL) { + *minorVsn = (theSystem & 0xFF ) ; + } + if (majorVsn != NULL) { + *majorVsn = (theSystem >> 8 ) ; + } +#ifdef __DARWIN__ + return wxMAC_DARWIN; +#else + return wxMAC; +#endif +} + +#if wxUSE_BASE + +#ifndef __DARWIN__ +// defined in unix/utilsunx.cpp for Mac OS X + +// get full hostname (with domain name if possible) +bool wxGetFullHostName(wxChar *buf, int maxSize) +{ + return wxGetHostName(buf, maxSize); +} + +// Get hostname only (without domain name) +bool wxGetHostName(wxChar *buf, int maxSize) +{ + // Gets Chooser name of user by examining a System resource. + + const short kComputerNameID = -16413; + + short oldResFile = CurResFile() ; + UseResFile(0); + StringHandle chooserName = (StringHandle)::GetString(kComputerNameID); + UseResFile(oldResFile); + + if (chooserName && *chooserName) + { + HLock( (Handle) chooserName ) ; + wxString name = wxMacMakeStringFromPascal( *chooserName ) ; + HUnlock( (Handle) chooserName ) ; + ReleaseResource( (Handle) chooserName ) ; + wxStrncpy( buf , name , maxSize - 1 ) ; + } + else + buf[0] = 0 ; + + return TRUE; +} + +// Get user ID e.g. jacs +bool wxGetUserId(wxChar *buf, int maxSize) +{ + return wxGetUserName( buf , maxSize ) ; +} + +const wxChar* wxGetHomeDir(wxString *pstr) +{ + *pstr = wxMacFindFolder( (short) kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder ) ; + return pstr->c_str() ; +} + +// Get user name e.g. Stefan Csomor +bool wxGetUserName(wxChar *buf, int maxSize) +{ + // Gets Chooser name of user by examining a System resource. + + const short kChooserNameID = -16096; + + short oldResFile = CurResFile() ; + UseResFile(0); + StringHandle chooserName = (StringHandle)::GetString(kChooserNameID); + UseResFile(oldResFile); + + if (chooserName && *chooserName) + { + HLock( (Handle) chooserName ) ; + wxString name = wxMacMakeStringFromPascal( *chooserName ) ; + HUnlock( (Handle) chooserName ) ; + ReleaseResource( (Handle) chooserName ) ; + wxStrncpy( buf , name , maxSize - 1 ) ; + } + else + buf[0] = 0 ; + + return TRUE; +} + +int wxKill(long pid, wxSignal sig , wxKillError *rc ) +{ + // TODO + return 0; +} + +WXDLLEXPORT bool wxGetEnv(const wxString& var, wxString *value) +{ + // TODO : under classic there is no environement support, under X yes + return false ; +} + +// set the env var name to the given value, return TRUE on success +WXDLLEXPORT bool wxSetEnv(const wxString& var, const wxChar *value) +{ + // TODO : under classic there is no environement support, under X yes + return false ; +} + +// +// Execute a program in an Interactive Shell +// +bool wxShell(const wxString& command) +{ + // TODO + return FALSE; +} + +// Shutdown or reboot the PC +bool wxShutdown(wxShutdownFlags wFlags) +{ + // TODO + return FALSE; +} + +// Get free memory in bytes, or -1 if cannot determine amount (e.g. on UNIX) +long wxGetFreeMemory() +{ + return FreeMem() ; +} + +void wxUsleep(unsigned long milliseconds) +{ + clock_t start = clock() ; + do + { + YieldToAnyThread() ; + } while( clock() - start < milliseconds / 1000.0 * CLOCKS_PER_SEC ) ; +} + +void wxSleep(int nSecs) +{ + wxUsleep(1000*nSecs); +} + +// Consume all events until no more left +void wxFlushEvents() +{ +} + +#endif // !__DARWIN__ + +// Emit a beeeeeep +void wxBell() +{ + SysBeep(30); +} + +wxToolkitInfo& wxConsoleAppTraits::GetToolkitInfo() +{ + static wxToolkitInfo info; + info.os = DoGetOSVersion(&info.versionMajor, &info.versionMinor); + info.name = _T("wxBase"); + return info; +} + +#endif // wxUSE_BASE + +#if wxUSE_GUI + +wxToolkitInfo& wxGUIAppTraits::GetToolkitInfo() +{ + static wxToolkitInfo info; + info.os = DoGetOSVersion(&info.versionMajor, &info.versionMinor); + info.shortName = _T("mac"); + info.name = _T("wxMac"); +#ifdef __WXUNIVERSAL__ + info.shortName << _T("univ"); + info.name << _T("/wxUniversal"); +#endif + return info; +} + +// Reading and writing resources (eg WIN.INI, .Xdefaults) +#if wxUSE_RESOURCES +bool wxWriteResource(const wxString& section, const wxString& entry, const wxString& value, const wxString& file) +{ + // TODO + return FALSE; +} + +bool wxWriteResource(const wxString& section, const wxString& entry, float value, const wxString& file) +{ + wxString buf; + buf.Printf(wxT("%.4f"), value); + + return wxWriteResource(section, entry, buf, file); +} + +bool wxWriteResource(const wxString& section, const wxString& entry, long value, const wxString& file) +{ + wxString buf; + buf.Printf(wxT("%ld"), value); + + return wxWriteResource(section, entry, buf, file); +} + +bool wxWriteResource(const wxString& section, const wxString& entry, int value, const wxString& file) +{ + wxString buf; + buf.Printf(wxT("%d"), value); + + return wxWriteResource(section, entry, buf, file); +} + +bool wxGetResource(const wxString& section, const wxString& entry, char **value, const wxString& file) +{ + // TODO + return FALSE; +} + +bool wxGetResource(const wxString& section, const wxString& entry, float *value, const wxString& file) +{ + char *s = NULL; + bool succ = wxGetResource(section, entry, (char **)&s, file); + if (succ) + { + *value = (float)strtod(s, NULL); + delete[] s; + return TRUE; + } + else return FALSE; +} + +bool wxGetResource(const wxString& section, const wxString& entry, long *value, const wxString& file) +{ + char *s = NULL; + bool succ = wxGetResource(section, entry, (char **)&s, file); + if (succ) + { + *value = strtol(s, NULL, 10); + delete[] s; + return TRUE; + } + else return FALSE; +} + +bool wxGetResource(const wxString& section, const wxString& entry, int *value, const wxString& file) +{ + char *s = NULL; + bool succ = wxGetResource(section, entry, (char **)&s, file); + if (succ) + { + *value = (int)strtol(s, NULL, 10); + delete[] s; + return TRUE; + } + else return FALSE; +} +#endif // wxUSE_RESOURCES + +int gs_wxBusyCursorCount = 0; +extern wxCursor gMacCurrentCursor ; +wxCursor gMacStoredActiveCursor ; + +// Set the cursor to the busy cursor for all windows +void wxBeginBusyCursor(wxCursor *cursor) +{ + if (gs_wxBusyCursorCount++ == 0) + { + gMacStoredActiveCursor = gMacCurrentCursor ; + cursor->MacInstall() ; + } + //else: nothing to do, already set +} + +// Restore cursor to normal +void wxEndBusyCursor() +{ + wxCHECK_RET( gs_wxBusyCursorCount > 0, + wxT("no matching wxBeginBusyCursor() for wxEndBusyCursor()") ); + + if (--gs_wxBusyCursorCount == 0) + { + gMacStoredActiveCursor.MacInstall() ; + gMacStoredActiveCursor = wxNullCursor ; + } +} + +// TRUE if we're between the above two calls +bool wxIsBusy() +{ + return (gs_wxBusyCursorCount > 0); +} + +#endif // wxUSE_GUI + +#if wxUSE_BASE + +wxString wxMacFindFolder( short vol, + OSType folderType, + Boolean createFolder) +{ + short vRefNum ; + long dirID ; + wxString strDir ; + + if ( FindFolder( vol, folderType, createFolder, &vRefNum, &dirID) == noErr) + { + FSSpec file ; + if ( FSMakeFSSpec( vRefNum , dirID , "\p" , &file ) == noErr ) + { + strDir = wxMacFSSpec2MacFilename( &file ) + wxFILE_SEP_PATH ; + } + } + return strDir ; +} + +#endif // wxUSE_BASE + +#if wxUSE_GUI + +// Check whether this window wants to process messages, e.g. Stop button +// in long calculations. +bool wxCheckForInterrupt(wxWindow *wnd) +{ + // TODO + return FALSE; +} + +void wxGetMousePosition( int* x, int* y ) +{ + Point pt ; + + GetMouse( &pt ) ; + LocalToGlobal( &pt ) ; + *x = pt.h ; + *y = pt.v ; +}; + +// Return TRUE if we have a colour display +bool wxColourDisplay() +{ + return TRUE; +} + +// Returns depth of screen +int wxDisplayDepth() +{ + Rect globRect ; + SetRect(&globRect, -32760, -32760, 32760, 32760); + GDHandle theMaxDevice; + + int theDepth = 8; + theMaxDevice = GetMaxDevice(&globRect); + if (theMaxDevice != nil) + theDepth = (**(**theMaxDevice).gdPMap).pixelSize; + + return theDepth ; +} + +// Get size of display +void wxDisplaySize(int *width, int *height) +{ + BitMap screenBits; + GetQDGlobalsScreenBits( &screenBits ); + + if (width != NULL) { + *width = screenBits.bounds.right - screenBits.bounds.left ; + } + if (height != NULL) { + *height = screenBits.bounds.bottom - screenBits.bounds.top ; + } +} + +void wxDisplaySizeMM(int *width, int *height) +{ + wxDisplaySize(width, height); + // on mac 72 is fixed (at least now ;-) + float cvPt2Mm = 25.4 / 72; + + if (width != NULL) { + *width = int( *width * cvPt2Mm ); + } + if (height != NULL) { + *height = int( *height * cvPt2Mm ); + } +} + +void wxClientDisplayRect(int *x, int *y, int *width, int *height) +{ +#if TARGET_CARBON + Rect r ; + GetAvailableWindowPositioningBounds( GetMainDevice() , &r ) ; + if ( x ) + *x = r.left ; + if ( y ) + *y = r.top ; + if ( width ) + *width = r.right - r.left ; + if ( height ) + *height = r.bottom - r.top ; +#else + BitMap screenBits; + GetQDGlobalsScreenBits( &screenBits ); + + if (x) *x = 0; + if (y) *y = 0; + + if (width != NULL) { + *width = screenBits.bounds.right - screenBits.bounds.left ; + } + if (height != NULL) { + *height = screenBits.bounds.bottom - screenBits.bounds.top ; + } + + SInt16 mheight ; +#if TARGET_CARBON + GetThemeMenuBarHeight( &mheight ) ; +#else + mheight = LMGetMBarHeight() ; +#endif + if (height != NULL) { + *height -= mheight ; + } + if (y) + *y = mheight ; +#endif +} + +wxWindow* wxFindWindowAtPoint(const wxPoint& pt) +{ + return wxGenericFindWindowAtPoint(pt); +} + +#endif // wxUSE_GUI + +#if wxUSE_BASE + +wxString wxGetOsDescription() +{ +#ifdef WXWIN_OS_DESCRIPTION + // use configure generated description if available + return wxString(wxT("MacOS (")) + wxT(WXWIN_OS_DESCRIPTION) + wxString(wxT(")")); +#else + return wxT("MacOS") ; //TODO:define further +#endif +} + +#ifndef __DARWIN__ +wxChar *wxGetUserHome (const wxString& user) +{ + // TODO + return NULL; +} + +bool wxGetDiskSpace(const wxString& path, wxLongLong *pTotal, wxLongLong *pFree) +{ + if ( path.empty() ) + return FALSE; + + wxString p = path ; + if (p[0u] == ':' ) { + p = wxGetCwd() + p ; + } + + int pos = p.Find(':') ; + if ( pos != wxNOT_FOUND ) { + p = p.Mid(1,pos) ; + } + + p = p + wxT(":") ; + + Str255 volumeName ; + XVolumeParam pb ; + + wxMacStringToPascal( p , volumeName ) ; + OSErr err = XGetVolumeInfoNoName( volumeName , 0 , &pb ) ; + if ( err == noErr ) { + if ( pTotal ) { + (*pTotal) = wxLongLong( pb.ioVTotalBytes ) ; + } + if ( pFree ) { + (*pFree) = wxLongLong( pb.ioVFreeBytes ) ; + } + } + + return err == noErr ; +} +#endif // !__DARWIN__ + +//--------------------------------------------------------------------------- +// wxMac Specific utility functions +//--------------------------------------------------------------------------- + +void wxMacStringToPascal( const wxString&from , StringPtr to ) +{ + wxCharBuffer buf = from.mb_str( wxConvLocal ) ; + int len = strlen(buf) ; + + if ( len > 255 ) + len = 255 ; + to[0] = len ; + memcpy( (char*) &to[1] , buf , len ) ; +} + +wxString wxMacMakeStringFromPascal( ConstStringPtr from ) +{ + return wxString( (char*) &from[1] , wxConvLocal , from[0] ) ; +} + + +wxUint32 wxMacGetSystemEncFromFontEnc(wxFontEncoding encoding) +{ + TextEncodingBase enc = 0 ; + if ( encoding == wxFONTENCODING_DEFAULT ) + { +#if wxUSE_GUI + encoding = wxFont::GetDefaultEncoding() ; +#else + encoding = wxLocale::GetSystemEncoding() ; +#endif + } + + switch( encoding) + { + case wxFONTENCODING_ISO8859_1 : + enc = kTextEncodingISOLatin1 ; + break ; + case wxFONTENCODING_ISO8859_2 : + enc = kTextEncodingISOLatin2; + break ; + case wxFONTENCODING_ISO8859_3 : + enc = kTextEncodingISOLatin3 ; + break ; + case wxFONTENCODING_ISO8859_4 : + enc = kTextEncodingISOLatin4; + break ; + case wxFONTENCODING_ISO8859_5 : + enc = kTextEncodingISOLatinCyrillic; + break ; + case wxFONTENCODING_ISO8859_6 : + enc = kTextEncodingISOLatinArabic; + break ; + case wxFONTENCODING_ISO8859_7 : + enc = kTextEncodingISOLatinGreek; + break ; + case wxFONTENCODING_ISO8859_8 : + enc = kTextEncodingISOLatinHebrew; + break ; + case wxFONTENCODING_ISO8859_9 : + enc = kTextEncodingISOLatin5; + break ; + case wxFONTENCODING_ISO8859_10 : + enc = kTextEncodingISOLatin6; + break ; + case wxFONTENCODING_ISO8859_13 : + enc = kTextEncodingISOLatin7; + break ; + case wxFONTENCODING_ISO8859_14 : + enc = kTextEncodingISOLatin8; + break ; + case wxFONTENCODING_ISO8859_15 : + enc = kTextEncodingISOLatin9; + break ; + + case wxFONTENCODING_KOI8 : + enc = kTextEncodingKOI8_R; + break ; + case wxFONTENCODING_ALTERNATIVE : // MS-DOS CP866 + enc = kTextEncodingDOSRussian; + break ; +/* + case wxFONTENCODING_BULGARIAN : + enc = ; + break ; +*/ + case wxFONTENCODING_CP437 : + enc =kTextEncodingDOSLatinUS ; + break ; + case wxFONTENCODING_CP850 : + enc = kTextEncodingDOSLatin1; + break ; + case wxFONTENCODING_CP852 : + enc = kTextEncodingDOSLatin2; + break ; + case wxFONTENCODING_CP855 : + enc = kTextEncodingDOSCyrillic; + break ; + case wxFONTENCODING_CP866 : + enc =kTextEncodingDOSRussian ; + break ; + case wxFONTENCODING_CP874 : + enc = kTextEncodingDOSThai; + break ; + case wxFONTENCODING_CP932 : + enc = kTextEncodingDOSJapanese; + break ; + case wxFONTENCODING_CP936 : + enc =kTextEncodingDOSChineseSimplif ; + break ; + case wxFONTENCODING_CP949 : + enc = kTextEncodingDOSKorean; + break ; + case wxFONTENCODING_CP950 : + enc = kTextEncodingDOSChineseTrad; + break ; + + case wxFONTENCODING_CP1250 : + enc = kTextEncodingWindowsLatin2; + break ; + case wxFONTENCODING_CP1251 : + enc =kTextEncodingWindowsCyrillic ; + break ; + case wxFONTENCODING_CP1252 : + enc =kTextEncodingWindowsLatin1 ; + break ; + case wxFONTENCODING_CP1253 : + enc = kTextEncodingWindowsGreek; + break ; + case wxFONTENCODING_CP1254 : + enc = kTextEncodingWindowsLatin5; + break ; + case wxFONTENCODING_CP1255 : + enc =kTextEncodingWindowsHebrew ; + break ; + case wxFONTENCODING_CP1256 : + enc =kTextEncodingWindowsArabic ; + break ; + case wxFONTENCODING_CP1257 : + enc = kTextEncodingWindowsBalticRim; + break ; + + case wxFONTENCODING_UTF7 : + enc = CreateTextEncoding(kTextEncodingUnicodeDefault,0,kUnicodeUTF7Format) ; + break ; + case wxFONTENCODING_UTF8 : + enc = CreateTextEncoding(kTextEncodingUnicodeDefault,0,kUnicodeUTF8Format) ; + break ; + case wxFONTENCODING_EUC_JP : + enc = kTextEncodingEUC_JP; + break ; + case wxFONTENCODING_UTF16BE : + enc = CreateTextEncoding(kTextEncodingUnicodeDefault,0,kUnicode16BitFormat) ; + break ; + case wxFONTENCODING_UTF16LE : + enc = CreateTextEncoding(kTextEncodingUnicodeDefault,0,kUnicode16BitFormat) ; + break ; + case wxFONTENCODING_UTF32BE : + enc = CreateTextEncoding(kTextEncodingUnicodeDefault,0,kUnicode32BitFormat) ; + break ; + case wxFONTENCODING_UTF32LE : + enc = CreateTextEncoding(kTextEncodingUnicodeDefault,0,kUnicode32BitFormat) ; + break ; + + case wxFONTENCODING_MACROMAN : + enc = kTextEncodingMacRoman ; + break ; + case wxFONTENCODING_MACJAPANESE : + enc = kTextEncodingMacJapanese ; + break ; + case wxFONTENCODING_MACCHINESETRAD : + enc = kTextEncodingMacChineseTrad ; + break ; + case wxFONTENCODING_MACKOREAN : + enc = kTextEncodingMacKorean ; + break ; + case wxFONTENCODING_MACARABIC : + enc = kTextEncodingMacArabic ; + break ; + case wxFONTENCODING_MACHEBREW : + enc = kTextEncodingMacHebrew ; + break ; + case wxFONTENCODING_MACGREEK : + enc = kTextEncodingMacGreek ; + break ; + case wxFONTENCODING_MACCYRILLIC : + enc = kTextEncodingMacCyrillic ; + break ; + case wxFONTENCODING_MACDEVANAGARI : + enc = kTextEncodingMacDevanagari ; + break ; + case wxFONTENCODING_MACGURMUKHI : + enc = kTextEncodingMacGurmukhi ; + break ; + case wxFONTENCODING_MACGUJARATI : + enc = kTextEncodingMacGujarati ; + break ; + case wxFONTENCODING_MACORIYA : + enc = kTextEncodingMacOriya ; + break ; + case wxFONTENCODING_MACBENGALI : + enc = kTextEncodingMacBengali ; + break ; + case wxFONTENCODING_MACTAMIL : + enc = kTextEncodingMacTamil ; + break ; + case wxFONTENCODING_MACTELUGU : + enc = kTextEncodingMacTelugu ; + break ; + case wxFONTENCODING_MACKANNADA : + enc = kTextEncodingMacKannada ; + break ; + case wxFONTENCODING_MACMALAJALAM : + enc = kTextEncodingMacMalayalam ; + break ; + case wxFONTENCODING_MACSINHALESE : + enc = kTextEncodingMacSinhalese ; + break ; + case wxFONTENCODING_MACBURMESE : + enc = kTextEncodingMacBurmese ; + break ; + case wxFONTENCODING_MACKHMER : + enc = kTextEncodingMacKhmer ; + break ; + case wxFONTENCODING_MACTHAI : + enc = kTextEncodingMacThai ; + break ; + case wxFONTENCODING_MACLAOTIAN : + enc = kTextEncodingMacLaotian ; + break ; + case wxFONTENCODING_MACGEORGIAN : + enc = kTextEncodingMacGeorgian ; + break ; + case wxFONTENCODING_MACARMENIAN : + enc = kTextEncodingMacArmenian ; + break ; + case wxFONTENCODING_MACCHINESESIMP : + enc = kTextEncodingMacChineseSimp ; + break ; + case wxFONTENCODING_MACTIBETAN : + enc = kTextEncodingMacTibetan ; + break ; + case wxFONTENCODING_MACMONGOLIAN : + enc = kTextEncodingMacMongolian ; + break ; + case wxFONTENCODING_MACETHIOPIC : + enc = kTextEncodingMacEthiopic ; + break ; + case wxFONTENCODING_MACCENTRALEUR : + enc = kTextEncodingMacCentralEurRoman ; + break ; + case wxFONTENCODING_MACVIATNAMESE : + enc = kTextEncodingMacVietnamese ; + break ; + case wxFONTENCODING_MACARABICEXT : + enc = kTextEncodingMacExtArabic ; + break ; + case wxFONTENCODING_MACSYMBOL : + enc = kTextEncodingMacSymbol ; + break ; + case wxFONTENCODING_MACDINGBATS : + enc = kTextEncodingMacDingbats ; + break ; + case wxFONTENCODING_MACTURKISH : + enc = kTextEncodingMacTurkish ; + break ; + case wxFONTENCODING_MACCROATIAN : + enc = kTextEncodingMacCroatian ; + break ; + case wxFONTENCODING_MACICELANDIC : + enc = kTextEncodingMacIcelandic ; + break ; + case wxFONTENCODING_MACROMANIAN : + enc = kTextEncodingMacRomanian ; + break ; + case wxFONTENCODING_MACCELTIC : + enc = kTextEncodingMacCeltic ; + break ; + case wxFONTENCODING_MACGAELIC : + enc = kTextEncodingMacGaelic ; + break ; + case wxFONTENCODING_MACKEYBOARD : + enc = kTextEncodingMacKeyboardGlyphs ; + break ; + default : + // to make gcc happy + break ; + } ; + return enc ; +} + +wxFontEncoding wxMacGetFontEncFromSystemEnc(wxUint32 encoding) +{ + wxFontEncoding enc = wxFONTENCODING_DEFAULT ; + + switch( encoding) + { + case kTextEncodingISOLatin1 : + enc = wxFONTENCODING_ISO8859_1 ; + break ; + case kTextEncodingISOLatin2 : + enc = wxFONTENCODING_ISO8859_2; + break ; + case kTextEncodingISOLatin3 : + enc = wxFONTENCODING_ISO8859_3 ; + break ; + case kTextEncodingISOLatin4 : + enc = wxFONTENCODING_ISO8859_4; + break ; + case kTextEncodingISOLatinCyrillic : + enc = wxFONTENCODING_ISO8859_5; + break ; + case kTextEncodingISOLatinArabic : + enc = wxFONTENCODING_ISO8859_6; + break ; + case kTextEncodingISOLatinGreek : + enc = wxFONTENCODING_ISO8859_7; + break ; + case kTextEncodingISOLatinHebrew : + enc = wxFONTENCODING_ISO8859_8; + break ; + case kTextEncodingISOLatin5 : + enc = wxFONTENCODING_ISO8859_9; + break ; + case kTextEncodingISOLatin6 : + enc = wxFONTENCODING_ISO8859_10; + break ; + case kTextEncodingISOLatin7 : + enc = wxFONTENCODING_ISO8859_13; + break ; + case kTextEncodingISOLatin8 : + enc = wxFONTENCODING_ISO8859_14; + break ; + case kTextEncodingISOLatin9 : + enc =wxFONTENCODING_ISO8859_15 ; + break ; + + case kTextEncodingKOI8_R : + enc = wxFONTENCODING_KOI8; + break ; +/* + case : + enc = wxFONTENCODING_BULGARIAN; + break ; +*/ + case kTextEncodingDOSLatinUS : + enc = wxFONTENCODING_CP437; + break ; + case kTextEncodingDOSLatin1 : + enc = wxFONTENCODING_CP850; + break ; + case kTextEncodingDOSLatin2 : + enc =wxFONTENCODING_CP852 ; + break ; + case kTextEncodingDOSCyrillic : + enc = wxFONTENCODING_CP855; + break ; + case kTextEncodingDOSRussian : + enc = wxFONTENCODING_CP866; + break ; + case kTextEncodingDOSThai : + enc =wxFONTENCODING_CP874 ; + break ; + case kTextEncodingDOSJapanese : + enc = wxFONTENCODING_CP932; + break ; + case kTextEncodingDOSChineseSimplif : + enc = wxFONTENCODING_CP936; + break ; + case kTextEncodingDOSKorean : + enc = wxFONTENCODING_CP949; + break ; + case kTextEncodingDOSChineseTrad : + enc = wxFONTENCODING_CP950; + break ; + + case kTextEncodingWindowsLatin2 : + enc = wxFONTENCODING_CP1250; + break ; + case kTextEncodingWindowsCyrillic : + enc = wxFONTENCODING_CP1251; + break ; + case kTextEncodingWindowsLatin1 : + enc = wxFONTENCODING_CP1252; + break ; + case kTextEncodingWindowsGreek : + enc = wxFONTENCODING_CP1253; + break ; + case kTextEncodingWindowsLatin5 : + enc = wxFONTENCODING_CP1254; + break ; + case kTextEncodingWindowsHebrew : + enc = wxFONTENCODING_CP1255; + break ; + case kTextEncodingWindowsArabic : + enc = wxFONTENCODING_CP1256; + break ; + case kTextEncodingWindowsBalticRim : + enc =wxFONTENCODING_CP1257 ; + break ; + case kTextEncodingEUC_JP : + enc = wxFONTENCODING_EUC_JP; + break ; + /* + case wxFONTENCODING_UTF7 : + enc = CreateTextEncoding(kTextEncodingUnicodeDefault,0,kUnicodeUTF7Format) ; + break ; + case wxFONTENCODING_UTF8 : + enc = CreateTextEncoding(kTextEncodingUnicodeDefault,0,kUnicodeUTF8Format) ; + break ; + case wxFONTENCODING_UTF16BE : + enc = CreateTextEncoding(kTextEncodingUnicodeDefault,0,kUnicode16BitFormat) ; + break ; + case wxFONTENCODING_UTF16LE : + enc = CreateTextEncoding(kTextEncodingUnicodeDefault,0,kUnicode16BitFormat) ; + break ; + case wxFONTENCODING_UTF32BE : + enc = CreateTextEncoding(kTextEncodingUnicodeDefault,0,kUnicode32BitFormat) ; + break ; + case wxFONTENCODING_UTF32LE : + enc = CreateTextEncoding(kTextEncodingUnicodeDefault,0,kUnicode32BitFormat) ; + break ; + */ + case kTextEncodingMacRoman : + enc = wxFONTENCODING_MACROMAN ; + break ; + case kTextEncodingMacJapanese : + enc = wxFONTENCODING_MACJAPANESE ; + break ; + case kTextEncodingMacChineseTrad : + enc = wxFONTENCODING_MACCHINESETRAD ; + break ; + case kTextEncodingMacKorean : + enc = wxFONTENCODING_MACKOREAN ; + break ; + case kTextEncodingMacArabic : + enc =wxFONTENCODING_MACARABIC ; + break ; + case kTextEncodingMacHebrew : + enc = wxFONTENCODING_MACHEBREW ; + break ; + case kTextEncodingMacGreek : + enc = wxFONTENCODING_MACGREEK ; + break ; + case kTextEncodingMacCyrillic : + enc = wxFONTENCODING_MACCYRILLIC ; + break ; + case kTextEncodingMacDevanagari : + enc = wxFONTENCODING_MACDEVANAGARI ; + break ; + case kTextEncodingMacGurmukhi : + enc = wxFONTENCODING_MACGURMUKHI ; + break ; + case kTextEncodingMacGujarati : + enc = wxFONTENCODING_MACGUJARATI ; + break ; + case kTextEncodingMacOriya : + enc =wxFONTENCODING_MACORIYA ; + break ; + case kTextEncodingMacBengali : + enc =wxFONTENCODING_MACBENGALI ; + break ; + case kTextEncodingMacTamil : + enc = wxFONTENCODING_MACTAMIL ; + break ; + case kTextEncodingMacTelugu : + enc = wxFONTENCODING_MACTELUGU ; + break ; + case kTextEncodingMacKannada : + enc = wxFONTENCODING_MACKANNADA ; + break ; + case kTextEncodingMacMalayalam : + enc = wxFONTENCODING_MACMALAJALAM ; + break ; + case kTextEncodingMacSinhalese : + enc = wxFONTENCODING_MACSINHALESE ; + break ; + case kTextEncodingMacBurmese : + enc = wxFONTENCODING_MACBURMESE ; + break ; + case kTextEncodingMacKhmer : + enc = wxFONTENCODING_MACKHMER ; + break ; + case kTextEncodingMacThai : + enc = wxFONTENCODING_MACTHAI ; + break ; + case kTextEncodingMacLaotian : + enc = wxFONTENCODING_MACLAOTIAN ; + break ; + case kTextEncodingMacGeorgian : + enc = wxFONTENCODING_MACGEORGIAN ; + break ; + case kTextEncodingMacArmenian : + enc = wxFONTENCODING_MACARMENIAN ; + break ; + case kTextEncodingMacChineseSimp : + enc = wxFONTENCODING_MACCHINESESIMP ; + break ; + case kTextEncodingMacTibetan : + enc = wxFONTENCODING_MACTIBETAN ; + break ; + case kTextEncodingMacMongolian : + enc = wxFONTENCODING_MACMONGOLIAN ; + break ; + case kTextEncodingMacEthiopic : + enc = wxFONTENCODING_MACETHIOPIC ; + break ; + case kTextEncodingMacCentralEurRoman: + enc = wxFONTENCODING_MACCENTRALEUR ; + break ; + case kTextEncodingMacVietnamese: + enc = wxFONTENCODING_MACVIATNAMESE ; + break ; + case kTextEncodingMacExtArabic : + enc = wxFONTENCODING_MACARABICEXT ; + break ; + case kTextEncodingMacSymbol : + enc = wxFONTENCODING_MACSYMBOL ; + break ; + case kTextEncodingMacDingbats : + enc = wxFONTENCODING_MACDINGBATS ; + break ; + case kTextEncodingMacTurkish : + enc = wxFONTENCODING_MACTURKISH ; + break ; + case kTextEncodingMacCroatian : + enc = wxFONTENCODING_MACCROATIAN ; + break ; + case kTextEncodingMacIcelandic : + enc = wxFONTENCODING_MACICELANDIC ; + break ; + case kTextEncodingMacRomanian : + enc = wxFONTENCODING_MACROMANIAN ; + break ; + case kTextEncodingMacCeltic : + enc = wxFONTENCODING_MACCELTIC ; + break ; + case kTextEncodingMacGaelic : + enc = wxFONTENCODING_MACGAELIC ; + break ; + case kTextEncodingMacKeyboardGlyphs : + enc = wxFONTENCODING_MACKEYBOARD ; + break ; + } ; + return enc ; +} + +#endif // wxUSE_BASE + +#if wxUSE_GUI + + +// +// CFStringRefs (Carbon only) +// + +#if TARGET_CARBON + +// converts this string into a carbon foundation string with optional pc 2 mac encoding +void wxMacCFStringHolder::Assign( const wxString &st , wxFontEncoding encoding ) +{ + Release() ; + + wxString str = st ; + wxMacConvertNewlines13To10( &str ) ; +#if wxUSE_UNICODE +#if SIZEOF_WCHAR_T == 2 + m_cfs = CFStringCreateWithCharacters( kCFAllocatorDefault, + (UniChar*)str.wc_str() , str.Len() ); +#else + wxMBConvUTF16BE converter ; + size_t unicharlen = converter.WC2MB( NULL , str.wc_str() , 0 ) ; + UniChar *unibuf = new UniChar[ unicharlen / sizeof(UniChar) + 1 ] ; + converter.WC2MB( (char*)unibuf , str.wc_str() , unicharlen ) ; + m_cfs = CFStringCreateWithCharacters( kCFAllocatorDefault , + unibuf , unicharlen / sizeof(UniChar) ) ; + delete[] unibuf ; +#endif +#else // not wxUSE_UNICODE + m_cfs = CFStringCreateWithCString( kCFAllocatorSystemDefault , str.c_str() , + wxMacGetSystemEncFromFontEnc( encoding ) ) ; +#endif + m_release = true ; +} + +wxString wxMacCFStringHolder::AsString(wxFontEncoding encoding) +{ + Size cflen = CFStringGetLength( m_cfs ) ; + size_t noChars ; + wxChar* buf = NULL ; + +#if wxUSE_UNICODE +#if SIZEOF_WCHAR_T == 2 + buf = new wxChar[ cflen + 1 ] ; + CFStringGetCharacters( m_cfs , CFRangeMake( 0 , cflen ) , (UniChar*) buf ) ; + noChars = cflen ; +#else + UniChar* unibuf = new UniChar[ cflen + 1 ] ; + CFStringGetCharacters( m_cfs , CFRangeMake( 0 , cflen ) , (UniChar*) unibuf ) ; + unibuf[cflen] = 0 ; + wxMBConvUTF16BE converter ; + noChars = converter.MB2WC( NULL , (const char*)unibuf , 0 ) ; + buf = new wxChar[ noChars + 1 ] ; + converter.MB2WC( buf , (const char*)unibuf , noChars ) ; + delete[] unibuf ; +#endif +#else + CFIndex cStrLen ; + CFStringGetBytes( m_cfs , CFRangeMake(0, cflen) , wxMacGetSystemEncFromFontEnc( encoding ) , + '?' , false , NULL , 0 , &cStrLen ) ; + buf = new wxChar[ cStrLen + 1 ] ; + CFStringGetBytes( m_cfs , CFRangeMake(0, cflen) , wxMacGetSystemEncFromFontEnc( encoding ) , + '?' , false , (unsigned char*) buf , cStrLen , &cStrLen) ; + noChars = cStrLen ; +#endif + + buf[noChars] = 0 ; + wxMacConvertNewlines10To13( buf ) ; + wxString result(buf) ; + delete[] buf ; + return result ; +} + +#endif //TARGET_CARBON + +void wxMacConvertNewlines13To10( char * data ) +{ + char * buf = data ; + while( (buf=strchr(buf,0x0d)) != NULL ) + { + *buf = 0x0a ; + buf++ ; + } +} + +void wxMacConvertNewlines10To13( char * data ) +{ + char * buf = data ; + while( (buf=strchr(buf,0x0a)) != NULL ) + { + *buf = 0x0d ; + buf++ ; + } +} + +void wxMacConvertNewlines13To10( wxString * data ) +{ + size_t len = data->Length() ; + + if ( len == 0 || wxStrchr(data->c_str(),0x0d)==NULL) + return ; + + wxString temp(*data) ; + wxStringBuffer buf(*data,len ) ; + memcpy( buf , temp.c_str() , (len+1)*sizeof(wxChar) ) ; + + wxMacConvertNewlines13To10( buf ) ; +} + +void wxMacConvertNewlines10To13( wxString * data ) +{ + size_t len = data->Length() ; + + if ( data->Length() == 0 || wxStrchr(data->c_str(),0x0a)==NULL) + return ; + + wxString temp(*data) ; + wxStringBuffer buf(*data,len ) ; + memcpy( buf , temp.c_str() , (len+1)*sizeof(wxChar) ) ; + wxMacConvertNewlines10To13( buf ) ; +} + + +#if wxUSE_UNICODE +void wxMacConvertNewlines13To10( wxChar * data ) +{ + wxChar * buf = data ; + while( (buf=wxStrchr(buf,0x0d)) != NULL ) + { + *buf = 0x0a ; + buf++ ; + } +} + +void wxMacConvertNewlines10To13( wxChar * data ) +{ + wxChar * buf = data ; + while( (buf=wxStrchr(buf,0x0a)) != NULL ) + { + *buf = 0x0d ; + buf++ ; + } +} +#endif + +// ---------------------------------------------------------------------------- +// debugging support +// ---------------------------------------------------------------------------- + +#if defined(__WXMAC__) && !defined(__DARWIN__) && defined(__MWERKS__) && (__MWERKS__ >= 0x2400) + +// MetroNub stuff doesn't seem to work in CodeWarrior 5.3 Carbon builds... + +#ifndef __MetroNubUtils__ +#include "MetroNubUtils.h" +#endif + +#ifndef __GESTALT__ +#include +#endif + +#if TARGET_API_MAC_CARBON + + #include + + extern "C" long CallUniversalProc(UniversalProcPtr theProcPtr, ProcInfoType procInfo, ...); + + ProcPtr gCallUniversalProc_Proc = NULL; + +#endif + +static MetroNubUserEntryBlock* gMetroNubEntry = NULL; + +static long fRunOnce = false; + +/* --------------------------------------------------------------------------- + IsMetroNubInstalled + --------------------------------------------------------------------------- */ + +Boolean IsMetroNubInstalled() +{ + if (!fRunOnce) + { + long result, value; + + fRunOnce = true; + gMetroNubEntry = NULL; + + if (Gestalt(gestaltSystemVersion, &value) == noErr && value < 0x1000) + { + /* look for MetroNub's Gestalt selector */ + if (Gestalt(kMetroNubUserSignature, &result) == noErr) + { + + #if TARGET_API_MAC_CARBON + if (gCallUniversalProc_Proc == NULL) + { + CFragConnectionID connectionID; + Ptr mainAddress; + Str255 errorString; + ProcPtr symbolAddress; + OSErr err; + CFragSymbolClass symbolClass; + + symbolAddress = NULL; + err = GetSharedLibrary("\pInterfaceLib", kPowerPCCFragArch, kFindCFrag, + &connectionID, &mainAddress, errorString); + + if (err != noErr) + { + gCallUniversalProc_Proc = NULL; + goto end; + } + + err = FindSymbol(connectionID, "\pCallUniversalProc", + (Ptr *) &gCallUniversalProc_Proc, &symbolClass); + + if (err != noErr) + { + gCallUniversalProc_Proc = NULL; + goto end; + } + } + #endif + + { + MetroNubUserEntryBlock* block = (MetroNubUserEntryBlock *)result; + + /* make sure the version of the API is compatible */ + if (block->apiLowVersion <= kMetroNubUserAPIVersion && + kMetroNubUserAPIVersion <= block->apiHiVersion) + gMetroNubEntry = block; /* success! */ + } + + } + } + } + +end: + +#if TARGET_API_MAC_CARBON + return (gMetroNubEntry != NULL && gCallUniversalProc_Proc != NULL); +#else + return (gMetroNubEntry != NULL); +#endif +} + +/* --------------------------------------------------------------------------- + IsMWDebuggerRunning [v1 API] + --------------------------------------------------------------------------- */ + +Boolean IsMWDebuggerRunning() +{ + if (IsMetroNubInstalled()) + return CallIsDebuggerRunningProc(gMetroNubEntry->isDebuggerRunning); + else + return false; +} + +/* --------------------------------------------------------------------------- + AmIBeingMWDebugged [v1 API] + --------------------------------------------------------------------------- */ + +Boolean AmIBeingMWDebugged() +{ + if (IsMetroNubInstalled()) + return CallAmIBeingDebuggedProc(gMetroNubEntry->amIBeingDebugged); + else + return false; +} + +extern bool WXDLLEXPORT wxIsDebuggerRunning() +{ + return IsMWDebuggerRunning() && AmIBeingMWDebugged(); +} + +#else + +extern bool WXDLLEXPORT wxIsDebuggerRunning() +{ + return false; +} + +#endif // defined(__WXMAC__) && !defined(__DARWIN__) && (__MWERKS__ >= 0x2400) + +#endif // wxUSE_GUI + diff --git a/src/mac/classic/utilsexc.cpp b/src/mac/classic/utilsexc.cpp new file mode 100644 index 0000000000..f270694d38 --- /dev/null +++ b/src/mac/classic/utilsexc.cpp @@ -0,0 +1,223 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: utilsexec.cpp +// Purpose: Execution-related utilities +// Author: Stefan Csomor +// Modified by: David Elliott +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +//#pragma implementation +#endif + +#include "wx/log.h" +#include "wx/utils.h" +#ifdef __DARWIN__ +#include "wx/unix/execute.h" +#include +#include +extern "C" { +#include +} +#include +#endif + +#include +#include +#include + +#ifndef __DARWIN__ +#define wxEXECUTE_WIN_MESSAGE 10000 + +#include "wx/mac/private.h" + +/* +Below FinderLaunch function comes from: +http://developer.apple.com/technotes/tn/tn1002.html#fndrask +*/ + /* FinderLaunch converts a list of nTargets FSSpec records + pointed to by the targetList parameter and converts the + list to an Apple Event. It then sends that event to the + Finder. The array of FSSpec records pointed to by the + targetList parameter may contain references to files, + folders, or applications. The net effect of this command + is equivalent to the user selecting an icon in one of the + Finder's windows and then choosing the open command from + the Finder's file menu. */ +static OSErr FinderLaunch(long nTargets, FSSpec *targetList) { + OSErr err; + AppleEvent theAEvent, theReply; + AEAddressDesc fndrAddress; + AEDescList targetListDesc; + OSType fndrCreator; + Boolean wasChanged; + AliasHandle targetAlias; + long index; + + /* set up locals */ + AECreateDesc(typeNull, NULL, 0, &theAEvent); + AECreateDesc(typeNull, NULL, 0, &fndrAddress); + AECreateDesc(typeNull, NULL, 0, &theReply); + AECreateDesc(typeNull, NULL, 0, &targetListDesc); + targetAlias = NULL; + fndrCreator = 'MACS'; + + /* verify parameters */ + if ((nTargets == 0) || (targetList == NULL)) { + err = paramErr; + goto bail; + } + + /* create an open documents event targeting the + finder */ + err = AECreateDesc(typeApplSignature, (Ptr) &fndrCreator, + sizeof(fndrCreator), &fndrAddress); + if (err != noErr) goto bail; + err = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments, + &fndrAddress, kAutoGenerateReturnID, + kAnyTransactionID, &theAEvent); + if (err != noErr) goto bail; + + /* create the list of files to open */ + err = AECreateList(NULL, 0, false, &targetListDesc); + if (err != noErr) goto bail; + for ( index=0; index < nTargets; index++) { + if (targetAlias == NULL) + err = NewAlias(NULL, (targetList + index), + &targetAlias); + else err = UpdateAlias(NULL, (targetList + index), + targetAlias, &wasChanged); + if (err != noErr) goto bail; + HLock((Handle) targetAlias); + err = AEPutPtr(&targetListDesc, (index + 1), + typeAlias, *targetAlias, + GetHandleSize((Handle) targetAlias)); + HUnlock((Handle) targetAlias); + if (err != noErr) goto bail; + } + + /* add the file list to the Apple Event */ + err = AEPutParamDesc(&theAEvent, keyDirectObject, + &targetListDesc); + if (err != noErr) goto bail; + + /* send the event to the Finder */ + err = AESend(&theAEvent, &theReply, kAENoReply, + kAENormalPriority, kAEDefaultTimeout, NULL, NULL); + + /* clean up and leave */ +bail: + if (targetAlias != NULL) DisposeHandle((Handle) targetAlias); + AEDisposeDesc(&targetListDesc); + AEDisposeDesc(&theAEvent); + AEDisposeDesc(&fndrAddress); + AEDisposeDesc(&theReply); + return err; +} + +long wxExecute(const wxString& command, int flags, wxProcess *WXUNUSED(handler)) +{ + wxASSERT_MSG( flags == wxEXEC_ASYNC, + wxT("wxExecute: Only wxEXEC_ASYNC is supported") ); + + FSSpec fsSpec; + wxMacFilename2FSSpec(command, &fsSpec); + + // 0 means execution failed. Returning non-zero is a PID, but not + // on Mac where PIDs are 64 bits and won't fit in a long, so we + // return a dummy value for now. + return ( FinderLaunch(1 /*one file*/, &fsSpec) == noErr ) ? -1 : 0; +} + +#endif + +#ifdef __DARWIN__ +void wxMAC_MachPortEndProcessDetect(CFMachPortRef port, void *data) +{ + wxEndProcessData *proc_data = (wxEndProcessData*)data; + wxLogDebug(wxT("Wow.. this actually worked!")); + int status = 0; + int rc = waitpid(abs(proc_data->pid), &status, WNOHANG); + if(!rc) + { + wxLogDebug(wxT("Mach port was invalidated, but process hasn't terminated!")); + return; + } + if((rc != -1) && WIFEXITED(status)) + proc_data->exitcode = WEXITSTATUS(status); + else + proc_data->exitcode = -1; + wxHandleProcessTermination(proc_data); +} + +int wxAddProcessCallbackForPid(wxEndProcessData *proc_data, int pid) +{ + if(pid < 1) + return -1; + kern_return_t kernResult; + mach_port_t taskOfOurProcess; + mach_port_t machPortForProcess; + taskOfOurProcess = mach_task_self(); + if(taskOfOurProcess == MACH_PORT_NULL) + { + wxLogDebug(wxT("No mach_task_self()")); + return -1; + } + wxLogDebug(wxT("pid=%d"),pid); + kernResult = task_for_pid(taskOfOurProcess,pid, &machPortForProcess); + if(kernResult != KERN_SUCCESS) + { + wxLogDebug(wxT("no task_for_pid()")); + // try seeing if it is already dead or something + // FIXME: a better method would be to call the callback function + // from idle time until the process terminates. Of course, how + // likely is it that it will take more than 0.1 seconds for the + // mach terminate event to make its way to the BSD subsystem? + usleep(100); // sleep for 0.1 seconds + wxMAC_MachPortEndProcessDetect(NULL, (void*)proc_data); + return -1; + } + CFMachPortContext termcb_contextinfo; + termcb_contextinfo.version = NULL; + termcb_contextinfo.info = (void*)proc_data; + termcb_contextinfo.retain = NULL; + termcb_contextinfo.release = NULL; + termcb_contextinfo.copyDescription = NULL; + CFMachPortRef CFMachPortForProcess; + Boolean ShouldFreePort; + CFMachPortForProcess = CFMachPortCreateWithPort(NULL, machPortForProcess, NULL, &termcb_contextinfo, &ShouldFreePort); + if(!CFMachPortForProcess) + { + wxLogDebug(wxT("No CFMachPortForProcess")); + mach_port_deallocate(taskOfOurProcess, machPortForProcess); + return -1; + } + if(ShouldFreePort) + { + kernResult = mach_port_deallocate(taskOfOurProcess, machPortForProcess); + if(kernResult!=KERN_SUCCESS) + { + wxLogDebug(wxT("Couldn't deallocate mach port")); + return -1; + } + } + CFMachPortSetInvalidationCallBack(CFMachPortForProcess, &wxMAC_MachPortEndProcessDetect); + CFRunLoopSourceRef runloopsource; + runloopsource = CFMachPortCreateRunLoopSource(NULL,CFMachPortForProcess, (CFIndex)0); + if(!runloopsource) + { + wxLogDebug(wxT("Couldn't create runloopsource")); + return -1; + } + + CFRelease(CFMachPortForProcess); + + CFRunLoopAddSource(CFRunLoopGetCurrent(),runloopsource,kCFRunLoopDefaultMode); + CFRelease(runloopsource); + wxLogDebug(wxT("Successfully added notification to the runloop")); + return 0; +} +#endif diff --git a/src/mac/classic/window.cpp b/src/mac/classic/window.cpp new file mode 100644 index 0000000000..a5c56e4202 --- /dev/null +++ b/src/mac/classic/window.cpp @@ -0,0 +1,2096 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: windows.cpp +// Purpose: wxWindowMac +// Author: Stefan Csomor +// Modified by: +// Created: 1998-01-01 +// RCS-ID: $Id$ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "window.h" +#endif + +#include "wx/setup.h" +#include "wx/menu.h" +#include "wx/window.h" +#include "wx/dc.h" +#include "wx/dcclient.h" +#include "wx/utils.h" +#include "wx/app.h" +#include "wx/panel.h" +#include "wx/layout.h" +#include "wx/dialog.h" +#include "wx/listbox.h" +#include "wx/scrolbar.h" +#include "wx/statbox.h" +#include "wx/button.h" +#include "wx/settings.h" +#include "wx/msgdlg.h" +#include "wx/frame.h" +#include "wx/notebook.h" +#include "wx/tabctrl.h" +#include "wx/tooltip.h" +#include "wx/statusbr.h" +#include "wx/menuitem.h" +#include "wx/spinctrl.h" +#include "wx/log.h" +#include "wx/geometry.h" + +#if wxUSE_CARET + #include "wx/caret.h" +#endif // wxUSE_CARET + +#define wxWINDOW_HSCROLL 5998 +#define wxWINDOW_VSCROLL 5997 +#define MAC_SCROLLBAR_SIZE 16 + +#include "wx/mac/uma.h" +#ifndef __DARWIN__ +#include +#include +#endif + +#if wxUSE_DRAG_AND_DROP +#include "wx/dnd.h" +#endif + +#include + +extern wxList wxPendingDelete; +wxWindowMac* gFocusWindow = NULL ; + +#ifdef __WXUNIVERSAL__ + IMPLEMENT_ABSTRACT_CLASS(wxWindowMac, wxWindowBase) +#else // __WXMAC__ + IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase) +#endif // __WXUNIVERSAL__/__WXMAC__ + +#if !USE_SHARED_LIBRARY + +BEGIN_EVENT_TABLE(wxWindowMac, wxWindowBase) + EVT_NC_PAINT(wxWindowMac::OnNcPaint) + EVT_ERASE_BACKGROUND(wxWindowMac::OnEraseBackground) + EVT_SYS_COLOUR_CHANGED(wxWindowMac::OnSysColourChanged) + EVT_INIT_DIALOG(wxWindowMac::OnInitDialog) + EVT_SET_FOCUS(wxWindowMac::OnSetFocus) + EVT_MOUSE_EVENTS(wxWindowMac::OnMouseEvent) +END_EVENT_TABLE() + +#endif + +#define wxMAC_DEBUG_REDRAW 0 +#ifndef wxMAC_DEBUG_REDRAW +#define wxMAC_DEBUG_REDRAW 0 +#endif + +#define wxMAC_USE_THEME_BORDER 0 + + +// =========================================================================== +// implementation +// =========================================================================== + + +// ---------------------------------------------------------------------------- +// constructors and such +// ---------------------------------------------------------------------------- + +void wxWindowMac::Init() +{ + m_backgroundTransparent = FALSE; + + // as all windows are created with WS_VISIBLE style... + m_isShown = TRUE; + + m_x = 0; + m_y = 0 ; + m_width = 0 ; + m_height = 0 ; + + m_hScrollBar = NULL ; + m_vScrollBar = NULL ; +} + +// Destructor +wxWindowMac::~wxWindowMac() +{ + SendDestroyEvent(); + + // deleting a window while it is shown invalidates the region + if ( IsShown() ) { + wxWindowMac* iter = this ; + while( iter ) { + if ( iter->IsTopLevel() ) + { + Refresh() ; + break ; + } + iter = iter->GetParent() ; + + } + } + + m_isBeingDeleted = TRUE; + +#ifndef __WXUNIVERSAL__ + // VS: make sure there's no wxFrame with last focus set to us: + for ( wxWindow *win = GetParent(); win; win = win->GetParent() ) + { + wxFrame *frame = wxDynamicCast(win, wxFrame); + if ( frame ) + { + if ( frame->GetLastFocus() == this ) + { + frame->SetLastFocus((wxWindow*)NULL); + } + break; + } + } +#endif // __WXUNIVERSAL__ + + if ( s_lastMouseWindow == this ) + { + s_lastMouseWindow = NULL ; + } + + wxFrame* frame = wxDynamicCast( wxGetTopLevelParent( this ) , wxFrame ) ; + if ( frame ) + { + if ( frame->GetLastFocus() == this ) + frame->SetLastFocus( NULL ) ; + } + + if ( gFocusWindow == this ) + { + gFocusWindow = NULL ; + } + + DestroyChildren(); + + // delete our drop target if we've got one +#if wxUSE_DRAG_AND_DROP + if ( m_dropTarget != NULL ) + { + delete m_dropTarget; + m_dropTarget = NULL; + } +#endif // wxUSE_DRAG_AND_DROP +} + +// Constructor +bool wxWindowMac::Create(wxWindowMac *parent, wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + wxCHECK_MSG( parent, FALSE, wxT("can't create wxWindowMac without parent") ); + +#if wxUSE_STATBOX + // wxGTK doesn't allow to create controls with static box as the parent so + // this will result in a crash when the program is ported to wxGTK - warn + // about it + // + // the correct solution is to create the controls as siblings of the + // static box + wxASSERT_MSG( !wxDynamicCast(parent, wxStaticBox), + _T("wxStaticBox can't be used as a window parent!") ); +#endif // wxUSE_STATBOX + + if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) ) + return FALSE; + + parent->AddChild(this); + + m_x = (int)pos.x; + m_y = (int)pos.y; + AdjustForParentClientOrigin(m_x, m_y, wxSIZE_USE_EXISTING); + m_width = WidthDefault( size.x ); + m_height = HeightDefault( size.y ) ; +#ifndef __WXUNIVERSAL__ + // Don't give scrollbars to wxControls unless they ask for them + if ( (! IsKindOf(CLASSINFO(wxControl)) && ! IsKindOf(CLASSINFO(wxStatusBar))) || + (IsKindOf(CLASSINFO(wxControl)) && ( style & wxHSCROLL || style & wxVSCROLL))) + { + MacCreateScrollBars( style ) ; + } +#endif + + wxWindowCreateEvent event(this); + GetEventHandler()->AddPendingEvent(event); + + return TRUE; +} + +void wxWindowMac::SetFocus() +{ + if ( gFocusWindow == this ) + return ; + + if ( AcceptsFocus() ) + { + if (gFocusWindow ) + { +#if wxUSE_CARET + // Deal with caret + if ( gFocusWindow->m_caret ) + { + gFocusWindow->m_caret->OnKillFocus(); + } +#endif // wxUSE_CARET +#ifndef __WXUNIVERSAL__ + wxControl* control = wxDynamicCast( gFocusWindow , wxControl ) ; + if ( control && control->GetMacControl() ) + { + UMASetKeyboardFocus( (WindowRef) gFocusWindow->MacGetRootWindow() , (ControlHandle) control->GetMacControl() , kControlFocusNoPart ) ; + control->MacRedrawControl() ; + } +#endif + // Without testing the window id, for some reason + // a kill focus event can still be sent to + // the control just being focussed. + int thisId = this->m_windowId; + int gFocusWindowId = gFocusWindow->m_windowId; + if (gFocusWindowId != thisId) + { + wxFocusEvent event(wxEVT_KILL_FOCUS, gFocusWindow->m_windowId); + event.SetEventObject(gFocusWindow); + gFocusWindow->GetEventHandler()->ProcessEvent(event) ; + } + } + gFocusWindow = this ; + { + #if wxUSE_CARET + // Deal with caret + if ( m_caret ) + { + m_caret->OnSetFocus(); + } + #endif // wxUSE_CARET + // panel wants to track the window which was the last to have focus in it + wxChildFocusEvent eventFocus(this); + GetEventHandler()->ProcessEvent(eventFocus); + + #ifndef __WXUNIVERSAL__ + wxControl* control = wxDynamicCast( gFocusWindow , wxControl ) ; + if ( control && control->GetMacControl() ) + { + UMASetKeyboardFocus( (WindowRef) gFocusWindow->MacGetRootWindow() , (ControlHandle) control->GetMacControl() , kControlFocusNextPart ) ; + } + #endif + wxFocusEvent event(wxEVT_SET_FOCUS, m_windowId); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event) ; + } + } +} + +bool wxWindowMac::Enable(bool enable) +{ + if ( !wxWindowBase::Enable(enable) ) + return FALSE; + + MacSuperEnabled( enable ) ; + + return TRUE; +} + +void wxWindowMac::DoCaptureMouse() +{ + wxTheApp->s_captureWindow = this ; +} + +wxWindow* wxWindowBase::GetCapture() +{ + return wxTheApp->s_captureWindow ; +} + +void wxWindowMac::DoReleaseMouse() +{ + wxTheApp->s_captureWindow = NULL ; +} + +#if wxUSE_DRAG_AND_DROP + +void wxWindowMac::SetDropTarget(wxDropTarget *pDropTarget) +{ + if ( m_dropTarget != 0 ) { + delete m_dropTarget; + } + + m_dropTarget = pDropTarget; + if ( m_dropTarget != 0 ) + { + // TODO + } +} + +#endif + +// Old style file-manager drag&drop +void wxWindowMac::DragAcceptFiles(bool accept) +{ + // TODO +} + +// Get total size +void wxWindowMac::DoGetSize(int *x, int *y) const +{ + if(x) *x = m_width ; + if(y) *y = m_height ; +} + +void wxWindowMac::DoGetPosition(int *x, int *y) const +{ + int xx,yy; + + xx = m_x ; + yy = m_y ; + if ( !IsTopLevel() && GetParent()) + { + wxPoint pt(GetParent()->GetClientAreaOrigin()); + xx -= pt.x; + yy -= pt.y; + } + if(x) *x = xx; + if(y) *y = yy; +} + +#if wxUSE_MENUS +bool wxWindowMac::DoPopupMenu(wxMenu *menu, int x, int y) +{ + menu->SetInvokingWindow(this); + menu->UpdateUI(); + ClientToScreen( &x , &y ) ; + + menu->MacBeforeDisplay( true ) ; + long menuResult = ::PopUpMenuSelect((MenuHandle) menu->GetHMenu() ,y,x, 0) ; + if ( HiWord(menuResult) != 0 ) + { + MenuCommand id ; + GetMenuItemCommandID( GetMenuHandle(HiWord(menuResult)) , LoWord(menuResult) , &id ) ; + wxMenuItem* item = NULL ; + wxMenu* realmenu ; + item = menu->FindItem(id, &realmenu) ; + if (item->IsCheckable()) + { + item->Check( !item->IsChecked() ) ; + } + menu->SendEvent( id , item->IsCheckable() ? item->IsChecked() : -1 ) ; + } + menu->MacAfterDisplay( true ) ; + + menu->SetInvokingWindow(NULL); + + return TRUE; +} +#endif + +void wxWindowMac::DoScreenToClient(int *x, int *y) const +{ + WindowRef window = (WindowRef) MacGetRootWindow() ; + + Point localwhere = {0,0} ; + + if(x) localwhere.h = * x ; + if(y) localwhere.v = * y ; + + GrafPtr port ; + ::GetPort( &port ) ; + ::SetPort( UMAGetWindowPort( window ) ) ; + ::GlobalToLocal( &localwhere ) ; + ::SetPort( port ) ; + + if(x) *x = localwhere.h ; + if(y) *y = localwhere.v ; + + MacRootWindowToWindow( x , y ) ; + if ( x ) + *x -= MacGetLeftBorderSize() ; + if ( y ) + *y -= MacGetTopBorderSize() ; +} + +void wxWindowMac::DoClientToScreen(int *x, int *y) const +{ + WindowRef window = (WindowRef) MacGetRootWindow() ; + + if ( x ) + *x += MacGetLeftBorderSize() ; + if ( y ) + *y += MacGetTopBorderSize() ; + + MacWindowToRootWindow( x , y ) ; + + Point localwhere = { 0,0 }; + if(x) localwhere.h = * x ; + if(y) localwhere.v = * y ; + + GrafPtr port ; + ::GetPort( &port ) ; + ::SetPort( UMAGetWindowPort( window ) ) ; + + ::LocalToGlobal( &localwhere ) ; + ::SetPort( port ) ; + if(x) *x = localwhere.h ; + if(y) *y = localwhere.v ; +} + +void wxWindowMac::MacClientToRootWindow( int *x , int *y ) const +{ + wxPoint origin = GetClientAreaOrigin() ; + if(x) *x += origin.x ; + if(y) *y += origin.y ; + + MacWindowToRootWindow( x , y ) ; +} + +void wxWindowMac::MacRootWindowToClient( int *x , int *y ) const +{ + wxPoint origin = GetClientAreaOrigin() ; + MacRootWindowToWindow( x , y ) ; + if(x) *x -= origin.x ; + if(y) *y -= origin.y ; +} + +void wxWindowMac::MacWindowToRootWindow( int *x , int *y ) const +{ + if ( !IsTopLevel() ) + { + if(x) *x += m_x ; + if(y) *y += m_y ; + GetParent()->MacWindowToRootWindow( x , y ) ; + } +} + +void wxWindowMac::MacRootWindowToWindow( int *x , int *y ) const +{ + if ( !IsTopLevel() ) + { + if(x) *x -= m_x ; + if(y) *y -= m_y ; + GetParent()->MacRootWindowToWindow( x , y ) ; + } +} + +bool wxWindowMac::SetCursor(const wxCursor& cursor) +{ + if (m_cursor == cursor) + return FALSE; + + if (wxNullCursor == cursor) + { + if ( ! wxWindowBase::SetCursor( *wxSTANDARD_CURSOR ) ) + return FALSE ; + } + else + { + if ( ! wxWindowBase::SetCursor( cursor ) ) + return FALSE ; + } + + wxASSERT_MSG( m_cursor.Ok(), + wxT("cursor must be valid after call to the base version")); + + Point pt ; + wxWindowMac *mouseWin ; + GetMouse( &pt ) ; + + // Change the cursor NOW if we're within the correct window + + if ( MacGetWindowFromPoint( wxPoint( pt.h , pt.v ) , &mouseWin ) ) + { + if ( mouseWin == this && !wxIsBusy() ) + { + m_cursor.MacInstall() ; + } + } + + return TRUE ; +} + + +// Get size *available for subwindows* i.e. excluding menu bar etc. +void wxWindowMac::DoGetClientSize(int *x, int *y) const +{ + int ww, hh; + ww = m_width ; + hh = m_height ; + + ww -= MacGetLeftBorderSize( ) + MacGetRightBorderSize( ) ; + hh -= MacGetTopBorderSize( ) + MacGetBottomBorderSize( ); + + if ( (m_vScrollBar && m_vScrollBar->IsShown()) || (m_hScrollBar && m_hScrollBar->IsShown()) ) + { + int x1 = 0 ; + int y1 = 0 ; + int w = m_width ; + int h = m_height ; + + MacClientToRootWindow( &x1 , &y1 ) ; + MacClientToRootWindow( &w , &h ) ; + + wxWindowMac *iter = (wxWindowMac*)this ; + + int totW = 10000 , totH = 10000; + while( iter ) + { + if ( iter->IsTopLevel() ) + { + totW = iter->m_width ; + totH = iter->m_height ; + break ; + } + + iter = iter->GetParent() ; + } + + if (m_hScrollBar && m_hScrollBar->IsShown() ) + { + hh -= MAC_SCROLLBAR_SIZE; + if ( h-y1 >= totH ) + { + hh += 1 ; + } + } + if (m_vScrollBar && m_vScrollBar->IsShown() ) + { + ww -= MAC_SCROLLBAR_SIZE; + if ( w-x1 >= totW ) + { + ww += 1 ; + } + } + } + if(x) *x = ww; + if(y) *y = hh; +} + + +// ---------------------------------------------------------------------------- +// tooltips +// ---------------------------------------------------------------------------- + +#if wxUSE_TOOLTIPS + +void wxWindowMac::DoSetToolTip(wxToolTip *tooltip) +{ + wxWindowBase::DoSetToolTip(tooltip); + + if ( m_tooltip ) + m_tooltip->SetWindow(this); +} + +#endif // wxUSE_TOOLTIPS + +void wxWindowMac::DoMoveWindow(int x, int y, int width, int height) +{ + int former_x = m_x ; + int former_y = m_y ; + int former_w = m_width ; + int former_h = m_height ; + + int actualWidth = width; + int actualHeight = height; + int actualX = x; + int actualY = y; + + if ((m_minWidth != -1) && (actualWidth < m_minWidth)) + actualWidth = m_minWidth; + if ((m_minHeight != -1) && (actualHeight < m_minHeight)) + actualHeight = m_minHeight; + if ((m_maxWidth != -1) && (actualWidth > m_maxWidth)) + actualWidth = m_maxWidth; + if ((m_maxHeight != -1) && (actualHeight > m_maxHeight)) + actualHeight = m_maxHeight; + + bool doMove = false ; + bool doResize = false ; + + if ( actualX != former_x || actualY != former_y ) + { + doMove = true ; + } + if ( actualWidth != former_w || actualHeight != former_h ) + { + doResize = true ; + } + + if ( doMove || doResize ) + { + // erase former position + + bool partialRepaint = false ; + + if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) ) + { + wxPoint oldPos( m_x , m_y ) ; + wxPoint newPos( actualX , actualY ) ; + MacWindowToRootWindow( &oldPos.x , &oldPos.y ) ; + MacWindowToRootWindow( &newPos.x , &newPos.y ) ; + if ( oldPos == newPos ) + { + partialRepaint = true ; + RgnHandle oldRgn,newRgn,diffRgn ; + oldRgn = NewRgn() ; + newRgn = NewRgn() ; + diffRgn = NewRgn() ; + + // invalidate the differences between the old and the new area + + SetRectRgn(oldRgn , oldPos.x , oldPos.y , oldPos.x + m_width , oldPos.y + m_height ) ; + SetRectRgn(newRgn , newPos.x , newPos.y , newPos.x + actualWidth , newPos.y + actualHeight ) ; + DiffRgn( newRgn , oldRgn , diffRgn ) ; + InvalWindowRgn( (WindowRef) MacGetRootWindow() , diffRgn ) ; + DiffRgn( oldRgn , newRgn , diffRgn ) ; + InvalWindowRgn( (WindowRef) MacGetRootWindow() , diffRgn ) ; + + // we also must invalidate the border areas, someone might optimize this one day to invalidate only the really + // changing pixels... + + if ( MacGetLeftBorderSize() != 0 || MacGetRightBorderSize() != 0 || + MacGetTopBorderSize() != 0 || MacGetBottomBorderSize() != 0 ) + { + RgnHandle innerOldRgn, innerNewRgn ; + innerOldRgn = NewRgn() ; + innerNewRgn = NewRgn() ; + + SetRectRgn(innerOldRgn , oldPos.x + MacGetLeftBorderSize() , oldPos.y + MacGetTopBorderSize() , + oldPos.x + m_width - MacGetRightBorderSize() , oldPos.y + m_height - MacGetBottomBorderSize() ) ; + DiffRgn( oldRgn , innerOldRgn , diffRgn ) ; + InvalWindowRgn( (WindowRef) MacGetRootWindow() , diffRgn ) ; + + SetRectRgn(innerNewRgn , newPos.x + MacGetLeftBorderSize() , newPos.y + MacGetTopBorderSize() , + newPos.x + actualWidth - MacGetRightBorderSize() , newPos.y + actualHeight - MacGetBottomBorderSize() ) ; + DiffRgn( newRgn , innerNewRgn , diffRgn ) ; + InvalWindowRgn( (WindowRef) MacGetRootWindow() , diffRgn ) ; + + DisposeRgn( innerOldRgn ) ; + DisposeRgn( innerNewRgn ) ; + } + + DisposeRgn(oldRgn) ; + DisposeRgn(newRgn) ; + DisposeRgn(diffRgn) ; + } + } + + if ( !partialRepaint ) + Refresh() ; + + m_x = actualX ; + m_y = actualY ; + m_width = actualWidth ; + m_height = actualHeight ; + + // update any low-level frame-relative positions + + MacUpdateDimensions() ; + // erase new position + + if ( !partialRepaint ) + Refresh() ; + if ( doMove ) + wxWindowMac::MacSuperChangedPosition() ; // like this only children will be notified + + MacRepositionScrollBars() ; + if ( doMove ) + { + wxPoint point(m_x, m_y); + wxMoveEvent event(point, m_windowId); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event) ; + } + if ( doResize ) + { + MacRepositionScrollBars() ; + wxSize size(m_width, m_height); + wxSizeEvent event(size, m_windowId); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); + } + } + +} + +// set the size of the window: if the dimensions are positive, just use them, +// but if any of them is equal to -1, it means that we must find the value for +// it ourselves (unless sizeFlags contains wxSIZE_ALLOW_MINUS_ONE flag, in +// which case -1 is a valid value for x and y) +// +// If sizeFlags contains wxSIZE_AUTO_WIDTH/HEIGHT flags (default), we calculate +// the width/height to best suit our contents, otherwise we reuse the current +// width/height +void wxWindowMac::DoSetSize(int x, int y, int width, int height, int sizeFlags) +{ + // get the current size and position... + int currentX, currentY; + GetPosition(¤tX, ¤tY); + + int currentW,currentH; + GetSize(¤tW, ¤tH); + + // ... and don't do anything (avoiding flicker) if it's already ok + if ( x == currentX && y == currentY && + width == currentW && height == currentH ) + { + MacRepositionScrollBars() ; // we might have a real position shift + return; + } + + if ( x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) + x = currentX; + if ( y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) ) + y = currentY; + + AdjustForParentClientOrigin(x, y, sizeFlags); + + wxSize size(-1, -1); + if ( width == -1 ) + { + if ( sizeFlags & wxSIZE_AUTO_WIDTH ) + { + size = DoGetBestSize(); + width = size.x; + } + else + { + // just take the current one + width = currentW; + } + } + + if ( height == -1 ) + { + if ( sizeFlags & wxSIZE_AUTO_HEIGHT ) + { + if ( size.x == -1 ) + { + size = DoGetBestSize(); + } + //else: already called DoGetBestSize() above + + height = size.y; + } + else + { + // just take the current one + height = currentH; + } + } + + DoMoveWindow(x, y, width, height); + +} +// For implementation purposes - sometimes decorations make the client area +// smaller + +wxPoint wxWindowMac::GetClientAreaOrigin() const +{ + return wxPoint(MacGetLeftBorderSize( ) , MacGetTopBorderSize( ) ); +} + +void wxWindowMac::SetTitle(const wxString& title) +{ + m_label = title ; +} + +wxString wxWindowMac::GetTitle() const +{ + return m_label ; +} + +bool wxWindowMac::Show(bool show) +{ + if ( !wxWindowBase::Show(show) ) + return FALSE; + + MacSuperShown( show ) ; + Refresh() ; + + return TRUE; +} + +void wxWindowMac::MacSuperShown( bool show ) +{ + wxWindowListNode *node = GetChildren().GetFirst(); + while ( node ) + { + wxWindowMac *child = node->GetData(); + if ( child->m_isShown ) + child->MacSuperShown( show ) ; + node = node->GetNext(); + } +} + +void wxWindowMac::MacSuperEnabled( bool enabled ) +{ + if ( !IsTopLevel() ) + { + // to be absolutely correct we'd have to invalidate (with eraseBkground + // because unter MacOSX the frames are drawn with an addXXX mode) + // the borders area + } + wxWindowListNode *node = GetChildren().GetFirst(); + while ( node ) + { + wxWindowMac *child = (wxWindowMac *)node->GetData(); + if ( child->m_isShown ) + child->MacSuperEnabled( enabled ) ; + node = node->GetNext(); + } +} + +bool wxWindowMac::MacIsReallyShown() const +{ + if ( m_isShown && (m_parent != NULL && !IsTopLevel() ) ) { + return m_parent->MacIsReallyShown(); + } + return m_isShown; +/* + bool status = m_isShown ; + wxWindowMac * win = this ; + while ( status && win->m_parent != NULL ) + { + win = win->m_parent ; + status = win->m_isShown ; + } + return status ; +*/ +} + +int wxWindowMac::GetCharHeight() const +{ + wxClientDC dc ( (wxWindowMac*)this ) ; + return dc.GetCharHeight() ; +} + +int wxWindowMac::GetCharWidth() const +{ + wxClientDC dc ( (wxWindowMac*)this ) ; + return dc.GetCharWidth() ; +} + +void wxWindowMac::GetTextExtent(const wxString& string, int *x, int *y, + int *descent, int *externalLeading, const wxFont *theFont ) const +{ + const wxFont *fontToUse = theFont; + if ( !fontToUse ) + fontToUse = &m_font; + + wxClientDC dc( (wxWindowMac*) this ) ; + long lx,ly,ld,le ; + dc.GetTextExtent( string , &lx , &ly , &ld, &le, (wxFont *)fontToUse ) ; + if ( externalLeading ) + *externalLeading = le ; + if ( descent ) + *descent = ld ; + if ( x ) + *x = lx ; + if ( y ) + *y = ly ; +} + +/* + * Rect is given in client coordinates, for further reading, read wxTopLevelWindowMac::InvalidateRect + * we always intersect with the entire window, not only with the client area + */ + +void wxWindowMac::Refresh(bool eraseBack, const wxRect *rect) +{ + if ( MacGetTopLevelWindow() == NULL ) + return ; + + if ( !MacIsReallyShown() ) + return ; + + wxPoint client = GetClientAreaOrigin(); + int x1 = -client.x; + int y1 = -client.y; + int x2 = m_width - client.x; + int y2 = m_height - client.y; + + if (IsKindOf( CLASSINFO(wxButton))) + { + // buttons have an "aura" + y1 -= 5; + x1 -= 5; + y2 += 5; + x2 += 5; + } + + Rect clientrect = { y1, x1, y2, x2 }; + + if ( rect ) + { + Rect r = { rect->y , rect->x , rect->y + rect->height , rect->x + rect->width } ; + SectRect( &clientrect , &r , &clientrect ) ; + } + + if ( !EmptyRect( &clientrect ) ) + { + int top = 0 , left = 0 ; + + MacClientToRootWindow( &left , &top ) ; + OffsetRect( &clientrect , left , top ) ; + + MacGetTopLevelWindow()->MacInvalidate( &clientrect , eraseBack ) ; + } +} + +wxWindowMac *wxGetActiveWindow() +{ + // actually this is a windows-only concept + return NULL; +} + +// Coordinates relative to the window +void wxWindowMac::WarpPointer (int x_pos, int y_pos) +{ + // We really don't move the mouse programmatically under Mac. +} + +const wxBrush& wxWindowMac::MacGetBackgroundBrush() +{ + if ( m_backgroundColour == wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE) ) + { + m_macBackgroundBrush.SetMacTheme( kThemeBrushDocumentWindowBackground ) ; + } + else if ( m_backgroundColour == wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE ) ) + { + // on mac we have the difficult situation, that 3dface gray can be different colours, depending whether + // it is on a notebook panel or not, in order to take care of that we walk up the hierarchy until we have + // either a non gray background color or a non control window + + WindowRef window = (WindowRef) MacGetRootWindow() ; + + wxWindowMac* parent = GetParent() ; + while( parent ) + { + if ( parent->MacGetRootWindow() != window ) + { + // we are in a different window on the mac system + parent = NULL ; + break ; + } + + { + if ( parent->m_backgroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE ) + && parent->m_backgroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE) ) + { + // if we have any other colours in the hierarchy + m_macBackgroundBrush.SetColour( parent->m_backgroundColour ) ; + break ; + } + // if we have the normal colours in the hierarchy but another control etc. -> use it's background + if ( parent->IsKindOf( CLASSINFO( wxNotebook ) ) || parent->IsKindOf( CLASSINFO( wxTabCtrl ) )) + { + Rect extent = { 0 , 0 , 0 , 0 } ; + int x , y ; + x = y = 0 ; + wxSize size = parent->GetSize() ; + parent->MacClientToRootWindow( &x , &y ) ; + extent.left = x ; + extent.top = y ; + extent.top-- ; + extent.right = x + size.x ; + extent.bottom = y + size.y ; + m_macBackgroundBrush.SetMacThemeBackground( kThemeBackgroundTabPane , (WXRECTPTR) &extent ) ; // todo eventually change for inactive + break ; + } + } + parent = parent->GetParent() ; + } + if ( !parent ) + { + m_macBackgroundBrush.SetMacTheme( kThemeBrushDialogBackgroundActive ) ; // todo eventually change for inactive + } + } + else + { + m_macBackgroundBrush.SetColour( m_backgroundColour ) ; + } + + return m_macBackgroundBrush ; +} + +void wxWindowMac::OnEraseBackground(wxEraseEvent& event) +{ + event.GetDC()->Clear() ; +} + +void wxWindowMac::OnNcPaint( wxNcPaintEvent& event ) +{ + wxWindowDC dc(this) ; + wxMacPortSetter helper(&dc) ; + + MacPaintBorders( dc.m_macLocalOrigin.x , dc.m_macLocalOrigin.y) ; +} + +int wxWindowMac::GetScrollPos(int orient) const +{ + if ( orient == wxHORIZONTAL ) + { + if ( m_hScrollBar ) + return m_hScrollBar->GetThumbPosition() ; + } + else + { + if ( m_vScrollBar ) + return m_vScrollBar->GetThumbPosition() ; + } + return 0; +} + +// This now returns the whole range, not just the number +// of positions that we can scroll. +int wxWindowMac::GetScrollRange(int orient) const +{ + if ( orient == wxHORIZONTAL ) + { + if ( m_hScrollBar ) + return m_hScrollBar->GetRange() ; + } + else + { + if ( m_vScrollBar ) + return m_vScrollBar->GetRange() ; + } + return 0; +} + +int wxWindowMac::GetScrollThumb(int orient) const +{ + if ( orient == wxHORIZONTAL ) + { + if ( m_hScrollBar ) + return m_hScrollBar->GetThumbSize() ; + } + else + { + if ( m_vScrollBar ) + return m_vScrollBar->GetThumbSize() ; + } + return 0; +} + +void wxWindowMac::SetScrollPos(int orient, int pos, bool refresh) +{ + if ( orient == wxHORIZONTAL ) + { + if ( m_hScrollBar ) + m_hScrollBar->SetThumbPosition( pos ) ; + } + else + { + if ( m_vScrollBar ) + m_vScrollBar->SetThumbPosition( pos ) ; + } +} + +void wxWindowMac::MacPaintBorders( int left , int top ) +{ + if( IsTopLevel() ) + return ; + + int major,minor; + wxGetOsVersion( &major, &minor ); + + RGBColor white = { 0xFFFF, 0xFFFF , 0xFFFF } ; + RGBColor face = { 0xDDDD, 0xDDDD , 0xDDDD } ; + + RGBColor darkShadow = { 0x0000, 0x0000 , 0x0000 } ; + RGBColor lightShadow = { 0x4444, 0x4444 , 0x4444 } ; + // OS X has lighter border edges than classic: + if (major >= 10) + { + darkShadow.red = 0x8E8E; + darkShadow.green = 0x8E8E; + darkShadow.blue = 0x8E8E; + lightShadow.red = 0xBDBD; + lightShadow.green = 0xBDBD; + lightShadow.blue = 0xBDBD; + } + + PenNormal() ; + + if (HasFlag(wxRAISED_BORDER) || HasFlag( wxSUNKEN_BORDER) || HasFlag(wxDOUBLE_BORDER) ) + { +#if wxMAC_USE_THEME_BORDER + Rect rect = { top , left , m_height + top , m_width + left } ; + SInt32 border = 0 ; + /* + GetThemeMetric( kThemeMetricListBoxFrameOutset , &border ) ; + InsetRect( &rect , border , border ); + DrawThemeListBoxFrame(&rect,IsEnabled() ? kThemeStateActive : kThemeStateInactive) ; + */ + + DrawThemePrimaryGroup(&rect ,IsEnabled() ? kThemeStateActive : kThemeStateInactive) ; +#else + bool sunken = HasFlag( wxSUNKEN_BORDER ) ; + RGBForeColor( &face ); + MoveTo( left + 0 , top + m_height - 2 ); + LineTo( left + 0 , top + 0 ); + LineTo( left + m_width - 2 , top + 0 ); + + MoveTo( left + 2 , top + m_height - 3 ); + LineTo( left + m_width - 3 , top + m_height - 3 ); + LineTo( left + m_width - 3 , top + 2 ); + + RGBForeColor( sunken ? &face : &darkShadow ); + MoveTo( left + 0 , top + m_height - 1 ); + LineTo( left + m_width - 1 , top + m_height - 1 ); + LineTo( left + m_width - 1 , top + 0 ); + + RGBForeColor( sunken ? &lightShadow : &white ); + MoveTo( left + 1 , top + m_height - 3 ); + LineTo( left + 1, top + 1 ); + LineTo( left + m_width - 3 , top + 1 ); + + RGBForeColor( sunken ? &white : &lightShadow ); + MoveTo( left + 1 , top + m_height - 2 ); + LineTo( left + m_width - 2 , top + m_height - 2 ); + LineTo( left + m_width - 2 , top + 1 ); + + RGBForeColor( sunken ? &darkShadow : &face ); + MoveTo( left + 2 , top + m_height - 4 ); + LineTo( left + 2 , top + 2 ); + LineTo( left + m_width - 4 , top + 2 ); +#endif + } + else if (HasFlag(wxSIMPLE_BORDER)) + { + Rect rect = { top , left , m_height + top , m_width + left } ; + RGBForeColor( &darkShadow ) ; + FrameRect( &rect ) ; + } +} + +void wxWindowMac::RemoveChild( wxWindowBase *child ) +{ + if ( child == m_hScrollBar ) + m_hScrollBar = NULL ; + if ( child == m_vScrollBar ) + m_vScrollBar = NULL ; + + wxWindowBase::RemoveChild( child ) ; +} + +// New function that will replace some of the above. +void wxWindowMac::SetScrollbar(int orient, int pos, int thumbVisible, + int range, bool refresh) +{ + if ( orient == wxHORIZONTAL ) + { + if ( m_hScrollBar ) + { + if ( range == 0 || thumbVisible >= range ) + { + if ( m_hScrollBar->IsShown() ) + m_hScrollBar->Show(false) ; + } + else + { + if ( !m_hScrollBar->IsShown() ) + m_hScrollBar->Show(true) ; + m_hScrollBar->SetScrollbar( pos , thumbVisible , range , thumbVisible , refresh ) ; + } + } + } + else + { + if ( m_vScrollBar ) + { + if ( range == 0 || thumbVisible >= range ) + { + if ( m_vScrollBar->IsShown() ) + m_vScrollBar->Show(false) ; + } + else + { + if ( !m_vScrollBar->IsShown() ) + m_vScrollBar->Show(true) ; + m_vScrollBar->SetScrollbar( pos , thumbVisible , range , thumbVisible , refresh ) ; + } + } + } + MacRepositionScrollBars() ; +} + +// Does a physical scroll +void wxWindowMac::ScrollWindow(int dx, int dy, const wxRect *rect) +{ + if( dx == 0 && dy ==0 ) + return ; + + + { + wxClientDC dc(this) ; + wxMacPortSetter helper(&dc) ; + + int width , height ; + GetClientSize( &width , &height ) ; + + Rect scrollrect = { dc.YLOG2DEVMAC(0) , dc.XLOG2DEVMAC(0) , dc.YLOG2DEVMAC(height) , dc.XLOG2DEVMAC(width) } ; + RgnHandle updateRgn = NewRgn() ; + ClipRect( &scrollrect ) ; + if ( rect ) + { + Rect r = { dc.YLOG2DEVMAC(rect->y) , dc.XLOG2DEVMAC(rect->x) , dc.YLOG2DEVMAC(rect->y + rect->height) , + dc.XLOG2DEVMAC(rect->x + rect->width) } ; + SectRect( &scrollrect , &r , &scrollrect ) ; + } + ScrollRect( &scrollrect , dx , dy , updateRgn ) ; + // we also have to scroll the update rgn in this rectangle + // in order not to loose updates + WindowRef rootWindow = (WindowRef) MacGetRootWindow() ; + RgnHandle formerUpdateRgn = NewRgn() ; + RgnHandle scrollRgn = NewRgn() ; + RectRgn( scrollRgn , &scrollrect ) ; + GetWindowUpdateRgn( rootWindow , formerUpdateRgn ) ; + Point pt = {0,0} ; + LocalToGlobal( &pt ) ; + OffsetRgn( formerUpdateRgn , -pt.h , -pt.v ) ; + SectRgn( formerUpdateRgn , scrollRgn , formerUpdateRgn ) ; + if ( !EmptyRgn( formerUpdateRgn ) ) + { + MacOffsetRgn( formerUpdateRgn , dx , dy ) ; + SectRgn( formerUpdateRgn , scrollRgn , formerUpdateRgn ) ; + InvalWindowRgn(rootWindow , formerUpdateRgn ) ; + } + InvalWindowRgn(rootWindow , updateRgn ) ; + DisposeRgn( updateRgn ) ; + DisposeRgn( formerUpdateRgn ) ; + DisposeRgn( scrollRgn ) ; + } + + for (wxWindowListNode *node = GetChildren().GetFirst(); node; node = node->GetNext()) + { + wxWindowMac *child = node->GetData(); + if (child == m_vScrollBar) continue; + if (child == m_hScrollBar) continue; + if (child->IsTopLevel()) continue; + + int x,y; + child->GetPosition( &x, &y ); + int w,h; + child->GetSize( &w, &h ); + if (rect) + { + wxRect rc(x,y,w,h); + if (rect->Intersects(rc)) + child->SetSize( x+dx, y+dy, w, h ); + } + else + { + child->SetSize( x+dx, y+dy, w, h ); + } + } + + Update() ; + +} + +void wxWindowMac::MacOnScroll(wxScrollEvent &event ) +{ + if ( event.m_eventObject == m_vScrollBar || event.m_eventObject == m_hScrollBar ) + { + wxScrollWinEvent wevent; + wevent.SetPosition(event.GetPosition()); + wevent.SetOrientation(event.GetOrientation()); + wevent.m_eventObject = this; + + if (event.m_eventType == wxEVT_SCROLL_TOP) + wevent.m_eventType = wxEVT_SCROLLWIN_TOP; + else if (event.m_eventType == wxEVT_SCROLL_BOTTOM) + wevent.m_eventType = wxEVT_SCROLLWIN_BOTTOM; + else if (event.m_eventType == wxEVT_SCROLL_LINEUP) + wevent.m_eventType = wxEVT_SCROLLWIN_LINEUP; + else if (event.m_eventType == wxEVT_SCROLL_LINEDOWN) + wevent.m_eventType = wxEVT_SCROLLWIN_LINEDOWN; + else if (event.m_eventType == wxEVT_SCROLL_PAGEUP) + wevent.m_eventType = wxEVT_SCROLLWIN_PAGEUP; + else if (event.m_eventType == wxEVT_SCROLL_PAGEDOWN) + wevent.m_eventType = wxEVT_SCROLLWIN_PAGEDOWN; + else if (event.m_eventType == wxEVT_SCROLL_THUMBTRACK) + wevent.m_eventType = wxEVT_SCROLLWIN_THUMBTRACK; + else if (event.m_eventType == wxEVT_SCROLL_THUMBRELEASE) + wevent.m_eventType = wxEVT_SCROLLWIN_THUMBRELEASE; + + GetEventHandler()->ProcessEvent(wevent); + } +} + +// Get the window with the focus +wxWindowMac *wxWindowBase::FindFocus() +{ + return gFocusWindow ; +} + +void wxWindowMac::OnSetFocus(wxFocusEvent& event) +{ + // panel wants to track the window which was the last to have focus in it, + // so we want to set ourselves as the window which last had focus + // + // notice that it's also important to do it upwards the tree becaus + // otherwise when the top level panel gets focus, it won't set it back to + // us, but to some other sibling + + // CS:don't know if this is still needed: + //wxChildFocusEvent eventFocus(this); + //(void)GetEventHandler()->ProcessEvent(eventFocus); + + event.Skip(); +} + +// Setup background and foreground colours correctly +void wxWindowMac::SetupColours() +{ + if ( GetParent() ) + SetBackgroundColour(GetParent()->GetBackgroundColour()); +} + +void wxWindowMac::OnInternalIdle() +{ + // This calls the UI-update mechanism (querying windows for + // menu/toolbar/control state information) + if (wxUpdateUIEvent::CanUpdate(this)) + UpdateWindowUI(wxUPDATE_UI_FROMIDLE); +} + +// Raise the window to the top of the Z order +void wxWindowMac::Raise() +{ +} + +// Lower the window to the bottom of the Z order +void wxWindowMac::Lower() +{ +} + +void wxWindowMac::DoSetClientSize(int width, int height) +{ + if ( width != -1 || height != -1 ) + { + + if ( width != -1 && m_vScrollBar ) + width += MAC_SCROLLBAR_SIZE ; + if ( height != -1 && m_vScrollBar ) + height += MAC_SCROLLBAR_SIZE ; + + width += MacGetLeftBorderSize( ) + MacGetRightBorderSize( ) ; + height += MacGetTopBorderSize( ) + MacGetBottomBorderSize( ) ; + + DoSetSize( -1 , -1 , width , height ) ; + } +} + + +wxWindowMac* wxWindowMac::s_lastMouseWindow = NULL ; + +bool wxWindowMac::MacGetWindowFromPointSub( const wxPoint &point , wxWindowMac** outWin ) +{ + if ( IsTopLevel() ) + { + if ((point.x < 0) || (point.y < 0) || + (point.x > (m_width)) || (point.y > (m_height))) + return FALSE; + } + else + { + if ((point.x < m_x) || (point.y < m_y) || + (point.x > (m_x + m_width)) || (point.y > (m_y + m_height))) + return FALSE; + } + + WindowRef window = (WindowRef) MacGetRootWindow() ; + + wxPoint newPoint( point ) ; + + if ( !IsTopLevel() ) + { + newPoint.x -= m_x; + newPoint.y -= m_y; + } + + for (wxWindowListNode *node = GetChildren().GetFirst(); node; node = node->GetNext()) + { + wxWindowMac *child = node->GetData(); + // added the m_isShown test --dmazzoni + if ( child->MacGetRootWindow() == window && child->m_isShown ) + { + if (child->MacGetWindowFromPointSub(newPoint , outWin )) + return TRUE; + } + } + + *outWin = this ; + return TRUE; +} + +bool wxWindowMac::MacGetWindowFromPoint( const wxPoint &screenpoint , wxWindowMac** outWin ) +{ + WindowRef window ; + + Point pt = { screenpoint.y , screenpoint.x } ; + if ( ::FindWindow( pt , &window ) == 3 ) + { + + wxWindowMac* win = wxFindWinFromMacWindow( window ) ; + if ( win ) + { + // No, this yields the CLIENT are, we need the whole frame. RR. + // point = win->ScreenToClient( point ) ; + + GrafPtr port; + ::GetPort( &port ) ; + ::SetPort( UMAGetWindowPort( window ) ) ; + ::GlobalToLocal( &pt ) ; + ::SetPort( port ) ; + + wxPoint point( pt.h, pt.v ) ; + + return win->MacGetWindowFromPointSub( point , outWin ) ; + } + } + return FALSE ; +} + +static wxWindow *gs_lastWhich = NULL; + +bool wxWindowMac::MacSetupCursor( const wxPoint& pt) +{ + // first trigger a set cursor event + + wxPoint clientorigin = GetClientAreaOrigin() ; + wxSize clientsize = GetClientSize() ; + wxCursor cursor ; + if ( wxRect2DInt( clientorigin.x , clientorigin.y , clientsize.x , clientsize.y ).Contains( wxPoint2DInt( pt ) ) ) + { + wxSetCursorEvent event( pt.x , pt.y ); + + bool processedEvtSetCursor = GetEventHandler()->ProcessEvent(event); + if ( processedEvtSetCursor && event.HasCursor() ) + { + cursor = event.GetCursor() ; + } + else + { + + // the test for processedEvtSetCursor is here to prevent using m_cursor + // if the user code caught EVT_SET_CURSOR() and returned nothing from + // it - this is a way to say that our cursor shouldn't be used for this + // point + if ( !processedEvtSetCursor && m_cursor.Ok() ) + { + cursor = m_cursor ; + } + if ( wxIsBusy() ) + { + } + else + { + if ( !GetParent() ) + cursor = *wxSTANDARD_CURSOR ; + } + } + if ( cursor.Ok() ) + cursor.MacInstall() ; + } + return cursor.Ok() ; +} + +bool wxWindowMac::MacDispatchMouseEvent(wxMouseEvent& event) +{ + if ((event.m_x < m_x) || (event.m_y < m_y) || + (event.m_x > (m_x + m_width)) || (event.m_y > (m_y + m_height))) + return FALSE; + + + if ( IsKindOf( CLASSINFO ( wxStaticBox ) ) /* || IsKindOf( CLASSINFO( wxSpinCtrl ) ) */) + return FALSE ; + + WindowRef window = (WindowRef) MacGetRootWindow() ; + + event.m_x -= m_x; + event.m_y -= m_y; + + int x = event.m_x ; + int y = event.m_y ; + + for (wxWindowListNode *node = GetChildren().GetFirst(); node; node = node->GetNext()) + { + wxWindowMac *child = node->GetData(); + if ( child->MacGetRootWindow() == window && child->IsShown() && child->IsEnabled() ) + { + if (child->MacDispatchMouseEvent(event)) + return TRUE; + } + } + + wxWindow* cursorTarget = this ; + wxPoint cursorPoint( x , y ) ; + + while( cursorTarget && !cursorTarget->MacSetupCursor( cursorPoint ) ) + { + cursorTarget = cursorTarget->GetParent() ; + if ( cursorTarget ) + cursorPoint += cursorTarget->GetPosition() ; + } + event.m_x = x ; + event.m_y = y ; + event.SetEventObject( this ) ; + + if ( event.GetEventType() == wxEVT_LEFT_DOWN ) + { + // set focus to this window + if (AcceptsFocus() && FindFocus()!=this) + SetFocus(); + } + +#if wxUSE_TOOLTIPS + if ( event.GetEventType() == wxEVT_MOTION + || event.GetEventType() == wxEVT_ENTER_WINDOW + || event.GetEventType() == wxEVT_LEAVE_WINDOW ) + wxToolTip::RelayEvent( this , event); +#endif // wxUSE_TOOLTIPS + + if (gs_lastWhich != this) + { + gs_lastWhich = this; + + // Double clicks must always occur on the same window + if (event.GetEventType() == wxEVT_LEFT_DCLICK) + event.SetEventType( wxEVT_LEFT_DOWN ); + if (event.GetEventType() == wxEVT_RIGHT_DCLICK) + event.SetEventType( wxEVT_RIGHT_DOWN ); + + // Same for mouse up events + if (event.GetEventType() == wxEVT_LEFT_UP) + return TRUE; + if (event.GetEventType() == wxEVT_RIGHT_UP) + return TRUE; + } + + GetEventHandler()->ProcessEvent( event ) ; + + return TRUE; +} + +wxString wxWindowMac::MacGetToolTipString( wxPoint &pt ) +{ + if ( m_tooltip ) + { + return m_tooltip->GetTip() ; + } + return wxEmptyString ; +} + +void wxWindowMac::Update() +{ + wxRegion visRgn = MacGetVisibleRegion( false ) ; + int top = 0 , left = 0 ; + MacWindowToRootWindow( &left , &top ) ; + WindowRef rootWindow = (WindowRef) MacGetRootWindow() ; + RgnHandle updateRgn = NewRgn() ; + // getting the update region in macos local coordinates + GetWindowUpdateRgn( rootWindow , updateRgn ) ; + GrafPtr port ; + ::GetPort( &port ) ; + ::SetPort( UMAGetWindowPort( rootWindow ) ) ; + Point pt = {0,0} ; + LocalToGlobal( &pt ) ; + ::SetPort( port ) ; + OffsetRgn( updateRgn , -pt.h , -pt.v ) ; + // translate to window local coordinates + OffsetRgn( updateRgn , -left , -top ) ; + SectRgn( updateRgn , (RgnHandle) visRgn.GetWXHRGN() , updateRgn ) ; + MacRedraw( updateRgn , 0 , true ) ; + // for flushing and validating we need macos-local coordinates again + OffsetRgn( updateRgn , left , top ) ; +#if TARGET_API_MAC_CARBON + if ( QDIsPortBuffered( GetWindowPort( rootWindow ) ) ) + { + QDFlushPortBuffer( GetWindowPort( rootWindow ) , updateRgn ) ; + } +#endif + ValidWindowRgn( rootWindow , updateRgn ) ; + DisposeRgn( updateRgn ) ; +} + +wxTopLevelWindowMac* wxWindowMac::MacGetTopLevelWindow() const +{ + wxTopLevelWindowMac* win = NULL ; + WindowRef window = (WindowRef) MacGetRootWindow() ; + if ( window ) + { + win = wxFindWinFromMacWindow( window ) ; + } + return win ; +} + +const wxRegion& wxWindowMac::MacGetVisibleRegion( bool respectChildrenAndSiblings ) +{ + RgnHandle visRgn = NewRgn() ; + RgnHandle tempRgn = NewRgn() ; + RgnHandle tempStaticBoxRgn = NewRgn() ; + + if ( MacIsReallyShown() ) + { + SetRectRgn( visRgn , 0 , 0 , m_width , m_height ) ; + + //TODO : as soon as the new scheme has proven to work correctly, move this to wxStaticBox + if ( IsKindOf( CLASSINFO( wxStaticBox ) ) ) + { + int borderTop = 14 ; + int borderOther = 4 ; + if ( UMAGetSystemVersion() >= 0x1030 ) + borderTop += 2 ; + + SetRectRgn( tempStaticBoxRgn , borderOther , borderTop , m_width - borderOther , m_height - borderOther ) ; + DiffRgn( visRgn , tempStaticBoxRgn , visRgn ) ; + } + + if ( !IsTopLevel() ) + { + wxWindow* parent = GetParent() ; + while( parent ) + { + wxSize size = parent->GetSize() ; + int x , y ; + x = y = 0 ; + parent->MacWindowToRootWindow( &x, &y ) ; + MacRootWindowToWindow( &x , &y ) ; + + SetRectRgn( tempRgn , + x + parent->MacGetLeftBorderSize() , y + parent->MacGetTopBorderSize() , + x + size.x - parent->MacGetRightBorderSize(), + y + size.y - parent->MacGetBottomBorderSize()) ; + + SectRgn( visRgn , tempRgn , visRgn ) ; + if ( parent->IsTopLevel() ) + break ; + parent = parent->GetParent() ; + } + } + if ( respectChildrenAndSiblings ) + { + if ( GetWindowStyle() & wxCLIP_CHILDREN ) + { + for (wxWindowListNode *node = GetChildren().GetFirst(); node; node = node->GetNext()) + { + wxWindowMac *child = node->GetData(); + + if ( !child->IsTopLevel() && child->IsShown() ) + { + SetRectRgn( tempRgn , child->m_x , child->m_y , child->m_x + child->m_width , child->m_y + child->m_height ) ; + if ( child->IsKindOf( CLASSINFO( wxStaticBox ) ) ) + { + int borderTop = 14 ; + int borderOther = 4 ; + if ( UMAGetSystemVersion() >= 0x1030 ) + borderTop += 2 ; + + SetRectRgn( tempStaticBoxRgn , child->m_x + borderOther , child->m_y + borderTop , child->m_x + child->m_width - borderOther , child->m_y + child->m_height - borderOther ) ; + DiffRgn( tempRgn , tempStaticBoxRgn , tempRgn ) ; + } + DiffRgn( visRgn , tempRgn , visRgn ) ; + } + } + } + + if ( (GetWindowStyle() & wxCLIP_SIBLINGS) && GetParent() ) + { + bool thisWindowThrough = false ; + for (wxWindowListNode *node = GetParent()->GetChildren().GetFirst(); node; node = node->GetNext()) + { + wxWindowMac *sibling = node->GetData(); + if ( sibling == this ) + { + thisWindowThrough = true ; + continue ; + } + if( !thisWindowThrough ) + { + continue ; + } + + if ( !sibling->IsTopLevel() && sibling->IsShown() ) + { + SetRectRgn( tempRgn , sibling->m_x - m_x , sibling->m_y - m_y , sibling->m_x + sibling->m_width - m_x , sibling->m_y + sibling->m_height - m_y ) ; + if ( sibling->IsKindOf( CLASSINFO( wxStaticBox ) ) ) + { + int borderTop = 14 ; + int borderOther = 4 ; + if ( UMAGetSystemVersion() >= 0x1030 ) + borderTop += 2 ; + + SetRectRgn( tempStaticBoxRgn , sibling->m_x - m_x + borderOther , sibling->m_y - m_y + borderTop , sibling->m_x + sibling->m_width - m_x - borderOther , sibling->m_y + sibling->m_height - m_y - borderOther ) ; + DiffRgn( tempRgn , tempStaticBoxRgn , tempRgn ) ; + } + DiffRgn( visRgn , tempRgn , visRgn ) ; + } + } + } + } + } + m_macVisibleRegion = visRgn ; + DisposeRgn( visRgn ) ; + DisposeRgn( tempRgn ) ; + DisposeRgn( tempStaticBoxRgn ) ; + return m_macVisibleRegion ; +} + +void wxWindowMac::MacRedraw( WXHRGN updatergnr , long time, bool erase) +{ + RgnHandle updatergn = (RgnHandle) updatergnr ; + // updatergn is always already clipped to our boundaries + // it is in window coordinates, not in client coordinates + + WindowRef window = (WindowRef) MacGetRootWindow() ; + + { + // ownUpdateRgn is the area that this window has to repaint, it is in window coordinates + RgnHandle ownUpdateRgn = NewRgn() ; + CopyRgn( updatergn , ownUpdateRgn ) ; + + SectRgn( ownUpdateRgn , (RgnHandle) MacGetVisibleRegion().GetWXHRGN() , ownUpdateRgn ) ; + + // newupdate is the update region in client coordinates + RgnHandle newupdate = NewRgn() ; + wxSize point = GetClientSize() ; + wxPoint origin = GetClientAreaOrigin() ; + SetRectRgn( newupdate , origin.x , origin.y , origin.x + point.x , origin.y+point.y ) ; + SectRgn( newupdate , ownUpdateRgn , newupdate ) ; + OffsetRgn( newupdate , -origin.x , -origin.y ) ; + m_updateRegion = newupdate ; + DisposeRgn( newupdate ) ; // it's been cloned to m_updateRegion + + if ( erase && !EmptyRgn(ownUpdateRgn) ) + { + wxWindowDC dc(this); + if (!EmptyRgn(ownUpdateRgn)) + dc.SetClippingRegion(wxRegion(ownUpdateRgn)); + wxEraseEvent eevent( GetId(), &dc ); + eevent.SetEventObject( this ); + GetEventHandler()->ProcessEvent( eevent ); + + wxNcPaintEvent eventNc( GetId() ); + eventNc.SetEventObject( this ); + GetEventHandler()->ProcessEvent( eventNc ); + } + DisposeRgn( ownUpdateRgn ) ; + if ( !m_updateRegion.Empty() ) + { + wxWindowList hiddenWindows ; + for (wxWindowListNode *node = GetChildren().GetFirst(); node; node = node->GetNext()) + { + wxControl *child = wxDynamicCast( ( wxWindow*)node->GetData() , wxControl ) ; + + if ( child && child->MacGetRootWindow() == window && child->IsShown() && child->GetMacControl() ) + { + SetControlVisibility( (ControlHandle) child->GetMacControl() , false , false ) ; + hiddenWindows.Append( child ) ; + } + } + + wxPaintEvent event; + event.m_timeStamp = time ; + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); + + for (wxWindowListNode *node = hiddenWindows.GetFirst(); node; node = node->GetNext()) + { + wxControl *child = wxDynamicCast( ( wxWindow*)node->GetData() , wxControl ) ; + + if ( child && child->GetMacControl() ) + { + SetControlVisibility( (ControlHandle) child->GetMacControl() , true , false ) ; + } + } + } + } + + // now intersect for each of the children their rect with the updateRgn and call MacRedraw recursively + + RgnHandle childupdate = NewRgn() ; + for (wxWindowListNode *node = GetChildren().GetFirst(); node; node = node->GetNext()) + { + // calculate the update region for the child windows by intersecting the window rectangle with our own + // passed in update region and then offset it to be client-wise window coordinates again + wxWindowMac *child = node->GetData(); + SetRectRgn( childupdate , child->m_x , child->m_y , child->m_x + child->m_width , child->m_y + child->m_height ) ; + SectRgn( childupdate , updatergn , childupdate ) ; + OffsetRgn( childupdate , -child->m_x , -child->m_y ) ; + if ( child->MacGetRootWindow() == window && child->IsShown() && !EmptyRgn( childupdate ) ) + { + // because dialogs may also be children + child->MacRedraw( childupdate , time , erase ) ; + } + } + DisposeRgn( childupdate ) ; + // eventually a draw grow box here + +} + +WXHWND wxWindowMac::MacGetRootWindow() const +{ + wxWindowMac *iter = (wxWindowMac*)this ; + + while( iter ) + { + if ( iter->IsTopLevel() ) + return ((wxTopLevelWindow*)iter)->MacGetWindowRef() ; + + iter = iter->GetParent() ; + } + wxASSERT_MSG( 1 , wxT("No valid mac root window") ) ; + return NULL ; +} + +void wxWindowMac::MacCreateScrollBars( long style ) +{ + wxASSERT_MSG( m_vScrollBar == NULL && m_hScrollBar == NULL , wxT("attempt to create window twice") ) ; + + bool hasBoth = ( style & wxVSCROLL ) && ( style & wxHSCROLL ) ; + int adjust = hasBoth ? MAC_SCROLLBAR_SIZE - 1: 0 ; + int width, height ; + GetClientSize( &width , &height ) ; + + wxPoint vPoint(width-MAC_SCROLLBAR_SIZE, 0) ; + wxSize vSize(MAC_SCROLLBAR_SIZE, height - adjust) ; + wxPoint hPoint(0 , height-MAC_SCROLLBAR_SIZE ) ; + wxSize hSize( width - adjust, MAC_SCROLLBAR_SIZE) ; + + m_vScrollBar = new wxScrollBar(this, wxWINDOW_VSCROLL, vPoint, + vSize , wxVERTICAL); + + if ( style & wxVSCROLL ) + { + + } + else + { + m_vScrollBar->Show(false) ; + } + m_hScrollBar = new wxScrollBar(this, wxWINDOW_HSCROLL, hPoint, + hSize , wxHORIZONTAL); + if ( style & wxHSCROLL ) + { + } + else + { + m_hScrollBar->Show(false) ; + } + + // because the create does not take into account the client area origin + MacRepositionScrollBars() ; // we might have a real position shift +} + +void wxWindowMac::MacRepositionScrollBars() +{ + bool hasBoth = ( m_hScrollBar && m_hScrollBar->IsShown()) && ( m_vScrollBar && m_vScrollBar->IsShown()) ; + int adjust = hasBoth ? MAC_SCROLLBAR_SIZE - 1 : 0 ; + + // get real client area + + int width = m_width ; + int height = m_height ; + + width -= MacGetLeftBorderSize() + MacGetRightBorderSize(); + height -= MacGetTopBorderSize() + MacGetBottomBorderSize(); + + wxPoint vPoint(width-MAC_SCROLLBAR_SIZE, 0) ; + wxSize vSize(MAC_SCROLLBAR_SIZE, height - adjust) ; + wxPoint hPoint(0 , height-MAC_SCROLLBAR_SIZE ) ; + wxSize hSize( width - adjust, MAC_SCROLLBAR_SIZE) ; + + int x = 0 ; + int y = 0 ; + int w = m_width ; + int h = m_height ; + + MacClientToRootWindow( &x , &y ) ; + MacClientToRootWindow( &w , &h ) ; + + wxWindowMac *iter = (wxWindowMac*)this ; + + int totW = 10000 , totH = 10000; + while( iter ) + { + if ( iter->IsTopLevel() ) + { + totW = iter->m_width ; + totH = iter->m_height ; + break ; + } + + iter = iter->GetParent() ; + } + + if ( x == 0 ) + { + hPoint.x = -1 ; + hSize.x += 1 ; + } + if ( y == 0 ) + { + vPoint.y = -1 ; + vSize.y += 1 ; + } + + if ( w-x >= totW ) + { + hSize.x += 1 ; + vPoint.x += 1 ; + } + + if ( h-y >= totH ) + { + vSize.y += 1 ; + hPoint.y += 1 ; + } + + if ( m_vScrollBar ) + { + m_vScrollBar->SetSize( vPoint.x , vPoint.y, vSize.x, vSize.y , wxSIZE_ALLOW_MINUS_ONE); + } + if ( m_hScrollBar ) + { + m_hScrollBar->SetSize( hPoint.x , hPoint.y, hSize.x, hSize.y, wxSIZE_ALLOW_MINUS_ONE); + } +} + +bool wxWindowMac::AcceptsFocus() const +{ + return MacCanFocus() && wxWindowBase::AcceptsFocus(); +} + +WXWidget wxWindowMac::MacGetContainerForEmbedding() +{ + return GetParent()->MacGetContainerForEmbedding() ; +} + +void wxWindowMac::MacSuperChangedPosition() +{ + // only window-absolute structures have to be moved i.e. controls + + wxWindowListNode *node = GetChildren().GetFirst(); + while ( node ) + { + wxWindowMac *child = node->GetData(); + child->MacSuperChangedPosition() ; + node = node->GetNext(); + } +} + +void wxWindowMac::MacTopLevelWindowChangedPosition() +{ + // only screen-absolute structures have to be moved i.e. glcanvas + + wxWindowListNode *node = GetChildren().GetFirst(); + while ( node ) + { + wxWindowMac *child = node->GetData(); + child->MacTopLevelWindowChangedPosition() ; + node = node->GetNext(); + } +} +long wxWindowMac::MacGetLeftBorderSize( ) const +{ + if( IsTopLevel() ) + return 0 ; + + if (m_windowStyle & wxRAISED_BORDER || m_windowStyle & wxSUNKEN_BORDER ) + { + SInt32 border = 3 ; +#if wxMAC_USE_THEME_BORDER +#if TARGET_CARBON + GetThemeMetric( kThemeMetricListBoxFrameOutset , &border ) ; +#endif +#endif + return border ; + } + else if ( m_windowStyle &wxDOUBLE_BORDER) + { + SInt32 border = 3 ; +#if wxMAC_USE_THEME_BORDER +#if TARGET_CARBON + GetThemeMetric( kThemeMetricListBoxFrameOutset , &border ) ; +#endif +#endif + return border ; + } + else if (m_windowStyle &wxSIMPLE_BORDER) + { + return 1 ; + } + return 0 ; +} + +long wxWindowMac::MacGetRightBorderSize( ) const +{ + // they are all symmetric in mac themes + return MacGetLeftBorderSize() ; +} + +long wxWindowMac::MacGetTopBorderSize( ) const +{ + // they are all symmetric in mac themes + return MacGetLeftBorderSize() ; +} + +long wxWindowMac::MacGetBottomBorderSize( ) const +{ + // they are all symmetric in mac themes + return MacGetLeftBorderSize() ; +} + +long wxWindowMac::MacRemoveBordersFromStyle( long style ) +{ + return style & ~( wxDOUBLE_BORDER | wxSUNKEN_BORDER | wxRAISED_BORDER | wxBORDER | wxSTATIC_BORDER ) ; +} + +// Find the wxWindowMac at the current mouse position, returning the mouse +// position. +wxWindowMac* wxFindWindowAtPointer(wxPoint& pt) +{ + pt = wxGetMousePosition(); + wxWindowMac* found = wxFindWindowAtPoint(pt); + return found; +} + +// Get the current mouse position. +wxPoint wxGetMousePosition() +{ + int x, y; + wxGetMousePosition(& x, & y); + return wxPoint(x, y); +} + +void wxWindowMac::OnMouseEvent( wxMouseEvent &event ) +{ + if ( event.GetEventType() == wxEVT_RIGHT_DOWN ) + { + // copied from wxGTK : CS + // generate a "context menu" event: this is similar to wxEVT_RIGHT_DOWN + // except that: + // + // (a) it's a command event and so is propagated to the parent + // (b) under MSW it can be generated from kbd too + // (c) it uses screen coords (because of (a)) + wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, + this->GetId(), + this->ClientToScreen(event.GetPosition())); + if ( ! GetEventHandler()->ProcessEvent(evtCtx) ) + event.Skip() ; + } + else + { + event.Skip() ; + } +} + diff --git a/src/mac/classic/wxmac.icns b/src/mac/classic/wxmac.icns new file mode 100644 index 0000000000000000000000000000000000000000..2c4e6f097d2f4315aaabf16668dbab4f4db6ebd0 GIT binary patch literal 36901 zcmeHP4|r46**`Z)n>3`5u*sgW@O(w8TWlLmVY0Lp($q1met_8!9{gZ)VK$|r+bZo? zwcMNju^@Hm#BQG-6CYZg@>Oh0DB$W+bha`?Y!#5w0G4^>a~Suy5(XRhd*5^KP17`m z^bd2-yt%o5&UxSW_x{fBoZQ@=6DV}wUrflR>u$?iFoO_AM=tl8`zay$TM1eGV?wMi z6Y}jtgxvi@Lay)Jbj@3=E-mecDcAI}E!y~I*ecPXvp)=?vS03x#usRqtJcdEJ9S5*WvOIqqa_5 zw{G3q`v<}&9xvbvo*F18KU7^(^6)@;qG9dox(NT|hYIRS$|LOlr%LKRIRG!QF8M$y zzs7_wKOwJmb$`;aq_D)uw41TK@Ab^vA1Wy=^qWnL8O!^!uUk^bulAeTP3=&AUA;4_ zFAz9lG@B*=YcpGJBFP5E)QU@{85uKQCdo!) ziirXLu6=neXn&=>t7jVK%S&^1oh0E`@_~2Fcfk1ioL(>vzD0=Ua~TJpOOqQq-*!P<<44JvtS`*cTkok{&_YF5kfQ_f9uILv>i>^eFc(uo8w#fQvVhhvJPre>W4ESRH^rhA%)+MvOG}%#Lx&QLK1sGEBqV8dInJur$VcmiB-iHcI z8Zcbs1kJ^efKhrH#h)r$TDFvPGp^H^$WQD0`%d^sr>5+@`yp9u*9gfRm#J$->w zd?Qr7N@FOwV1F-rO5J;^?{}P_YUV?jN1*I9G!GYG_#I$sI1{Xt^L!i%oaj5%+t=H| z2@`(*Vq2SUPum{fo~Cz@1P@;-xc4+YA&@|IFL^@{J`t$g%l@+}pL_@8E~;;K7Zl#> zDJY<&J^Sx*7kFT!rQKck6nIwMTjZgo*8TSu-CI=PxtEr9b=|WH;_m**Jym{``%6Ww z``u`F9pOI~w*WM2a?2vuT`t$6*}D(A?_E{karFkzczM;I0wABNDR&EJ*Wc#z1F(CQ z>qM}UXE4arlz+^A%beM>A9$dkXjKtfI9~IoK3Y~LfUie_H26=Xt?XGi&8EO%Fe;fo(YDR4u>!m zFA=1v=Gf=hr=jpYl%SaDZ9u}XbP)cPhNh;*9ZfqLcRUNitD0<1AUFroWr6TVt2dFy z!@~dgk*Z3v281tu`{<6Qoy|L&nrP|h>E_0!R@i9i{g1%5tJ$}cmX4in_BH#OTAO9t zE{J=!_`6llkTW2B@v+m5Xy0hJJ6%p!zBAw6a2-1d*p0h3{xtY~uTw=Mr#3m?y)GlelKtwQ);+uTg6*^K zJLfs)&zUDiI=fhl<|bRVEt@M%EH3`^`%b5ebuxCUi}PJeMtX)NJ^epGmnMvy53w{- z-{kC?o?*3E(rq?QQ2QWKPKl=UG~6uEa}%11X~tXgC9X7Mh9$#t4a7D6kk7A>)6My# zB|QTJr(-wd&C8#6NB$l2<}Y{`n`p5C(F}{lYNOpyOEzIQ-1n{3MPI1L5BS8(ubAH~ zvJuXow>?ZHl1R8R;)2>E%F&nqY&+(QEp`wl+o^IS-<{z}Nl83>*VgqU zsWIaNl459iwaK_ucYn(doJ3Q%dQ(D5@`H!SCPKE~l$x^DaQM(#J0VEqyVN~BIjPjdfrf8UQ%ANHd=xA z3RK`pcNN z%P=E##)qX(mEK=^kKY8DjX0}B$Oi^zi}R%y?>^gm_IG{;&?k#H?;2VlAoT`tX(#Om zOzlRIPqQKO_H3s!3+j6efMYg^e7X&{WM;NBFF=3e0VB>ziF^#H(1KZTmn3fyQ+qqi zPKo^eGn<{a%&?-r-v~f-mWq&W!wi^sYR-rHcMJ@8%l?L0&6!Th=PmSx1Qh3k$A?8v8`qAph~46DFF8&m{v>DDS{{p z46i`LL3t`tJP+?FTDZ=|Tg2%(oPz9p@k;&;TL?}@()mC*zIi2oZW~z$GlLzS^$1^o z@Jjv{I+z;{c5Fj@Jj9;Ri~s>X=KvnTaf&n!J`7B@igX|-4*bM(2u;~{bjF^bjo`y> z6Y-Hur}rW6Qt#3g53LZ7vDQx-wj`zjJhT-yJ_zvEx2-BdXDiViCebd0c`U~{Pn`HPH*e`*0NPXfomM6hu&J*;NfU{0*3L9%VUTwl z31Mro&t3$4m=DDXUu31fD~!*X`?a}_+$k`(3p2~Kf02})=~q#BoW|9EJ%Udb(NRjd zH66$WU!Cm-tuTKFQ_gh88PY_w*Gxj@X<0D&T61wdyf1KN7q|_XK;JOhMh-!puIEz@c$OkUV`{p zkN}Qhe5@Tod@jMNACBNNA0AV8cwhUsK0gZ#w+>md9opeIf=1OAlU2z<~-bcb_< zKFb}Hk3%Fhz+cr5G%x@=Y!Lr`EtLl-O$+n4S*_@-#$yJAMDU-II1y*&K_HY>(kJ9y z?k)3P@GjxJ7nX7yH_%_pfi+5>n}vNK^AF26_gCi5`;p^Exho$V;-FM0 z3Jjw_p$C^0bhG8zjbFmzLh=S!T-YK^av3)*)DhV9L=Q(=l_u=g=?MHyO?O&#ov>Yp zcBs@7W7ta!!%E4E20|Q$N?s61}lqI{Sqc<8L2d!tT1x?v!JRkJ(lUAgKAWE-?2J4O8Lg*1e6~w@=lm$aU znEem%ylZ;!H6Ls9qKEA-fi{BeXZ5;sbl7&}u;)q}Hiw4 zg!HVKK0)MPiSbhEU_|OrfXV}jp?x$p&kFjWAZ@5XVi_L_Q3`6v0~n0I_|Y=bP%Ws+ zcn}VNc{ZSe_$>k{dvq^ZArH!DE z^&AdQGt};PQ!ICps{;n#z&ij+JW@32wqjt4G$DnnBN(iKg%=nH8uvHt_FT?xvZa=X z0K(%b0*0=RP%v1{s{$CTcIWykE9{8ir~Ci}9S{M`Uv=k)+FWWe*FTAoAxh-kyWmRl7PM zRF5BWx?vM^?)<$SQjIHs0v8!$K9l@nEmVL2Goig+4;|$YJA+ z{}WvH2&^nYZ)n^Wo9$-KX0oLIAp{t$tv=we@kU>$jCB$h=Ty7w2%&c0+*szdm}~%a zlJW#Ba0`}IJ5@BvG`BO&l$IKk!SWaqv$7T(Oqxcqd1}-L7xVy2OWA`9XCYP=kTgEbCO0k#&6vev^IFK% z3PB4PG?CY-w!7q3HPTik&|DHmsLbn3#Fjfn8ELE3z!{n^k$IALNxgwB@?jFONjAVR z`fh|zffI6wJEG{^_P|z3hP43HbUL;dY;ZB|MjYD~dxeDnyb83VV|!}k*!Iw6L1p@6 zn5QbGnkpdQ3+3~bWRd;kv*JHk0a+LMJlHz4B>TlY4|N~3COaf1>_5a3yF&4obPDE?Hdan>gcH{>F^XNEW^6^a7GC{XAw#s$CmqFKYL9r}}MM@Hpcn+y(@CfztV zY|=@(U0MfQx%iSC00)-E$z_(slRJ+4(fRnA5_<073+S@ofwkrB?f&HM-xb^kKZjTC zyY0PNhVdJ^QxCzSqEWLi+i!sSAi z5&HaMoL3*1)(kDgdGmoK>k$4u^U>F3e`@0=F57%hyis<0TR z#h53X1mH{;nF3rcYpZ7$rFHc zEYQ>2b5an3+$ZEOy9D5H_&KhDyaSKrzSfnjhin55zSjy03ku~cPk9^ro&hk*e=sla z_XP!ozxp%Fo8N=-hMd{16{}Z24O0*wz60g;Ia%4i7KGP7VR-|!!>=-*6oh?eS^i64 z|JglRIXPfIdi2QABgcUY*GW!O4#!{P_K{x5yyyLwceb?b#Vh#V&N8|U{;AsV zW!W$ObC}J@E(+bN@ty;pQ$iAm>f{86%bziMnd2KeO&BQZK11sv4(~CZuv7S=EjBhSE%NYHd*E9VFrrkf`+S^kMW&<%83>Y-z1$mHL z=MY1TigR$sSX?ar`vNqdhkqN<*||9E3IEmt*8Udh7)HKFzzSKJ4wj$9dxYafdXIpA zWPtaGOjxnPdx8qqVZd&m;&5caJ>y*Z^|~~M5V#>|wFCF3aFSsz3LnIKz*iqdvou~t zeEL6uC2aCDgf(^zb5*Nn$p+XNyas{hr1cBY{g($cra1g_#l9(!fpDGAPEZoB^ zq#UEQQC<~DPC|$zHF~2=bD-&wxbazOc3>4Nax^v?gIy3yzX777b%+#ed-V<+MPk(BgQsp-6{ch~_Ay>~sy||C~dompGSomtB7w}b^&n|o>pZyMe z)yBN4^{_=7U}roY(do(+tcQWSQuN=dzgikV>C9n@pVyN z6-Z7(kV%c+C^uQADmGoly}T8(4vGU-a^zTT;Vy{QPX->FL!^@1Irys0hni>=2N?!6 zl;s+DHZp9)R`@zip-E9Dp#qE>} z--788kBJrz8fSe_q6+cE)C7^EVGGjYuUUpRa_mMsf z4ET@ffufRK|4b#j1|BG4Ue&g;z74Q5t*xTdl`Gg*{6_i63sG?CgM%0@mBdu>`&2|mYjq<8MauPx$snHu{ngdOb#Es8NvjeMGk)yHE80>;r`V9~rtwW?(+vmaq zMJ3c=_YZ53We|zY^}>&fV29tTu=pDjmka(Ww+pV=NU*CK1J4^%DQ$QF`3T2D6&XVA}Pm}C`5Q6&+@fg)@2FA}~vO4ChJ_YI*L zmm}@7EtTQMZ-BWeEydBb;68!*1H+M81RnTjj z)FD^TL%p~UJd%y{>M`L#y7cE5)w1+3 zt2;`yqJW}+qJW}+qJW}+qJW}+qJW}+qJW}+qQKY`7{Q;nV@otlw30t=1%^>@Y}IjR zALf4$9b5Jh{Z@6Xsba<}?T=f5nEH*iGVbik_#3O#G2<2e<5nQ1eq*hSJG(Oe$0~Kq zct!uX6^N