From d59ceba5720b79347a1d63efe4497a768a819979 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 18 Oct 1999 00:08:40 +0000 Subject: [PATCH] 1. more drag and drop and clipboard changes: a) OLE clipboard works fine b) wxBitmapDataObject now accepts DIBs (but doesn't give them back :-( ) c) bugs in sample corrected 2. wxFatalExit() replaced with wxFAIL_MSG() in bitmap.cpp and dcmemory.cpp 3. wxFrame::ClientToScreen and ScreenToClient() replaced with DoXXX() - like this, they don't hide the base class versions git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@4039 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/msw/clipbrd.h | 13 +- include/wx/msw/frame.h | 6 +- include/wx/msw/ole/dataobj.h | 57 +++--- samples/dnd/dnd.cpp | 250 ++++++++++++++++-------- src/msw/bitmap.cpp | 29 +-- src/msw/clipbrd.cpp | 266 ++++++++++++++++++++----- src/msw/dcmemory.cpp | 161 ++++++++-------- src/msw/frame.cpp | 8 +- src/msw/ole/dataobj.cpp | 363 +++++++++++++++++++++++++++-------- 9 files changed, 820 insertions(+), 333 deletions(-) diff --git a/include/wx/msw/clipbrd.h b/include/wx/msw/clipbrd.h index c1afb26016..a7d010e60d 100644 --- a/include/wx/msw/clipbrd.h +++ b/include/wx/msw/clipbrd.h @@ -83,10 +83,17 @@ public: // clears wxTheClipboard and the system's clipboard if possible virtual void Clear(); - - /// X11 has two clipboards which get selected by this call. Empty on MSW. + + // flushes the clipboard: this means that the data which is currently on + // clipboard will stay available even after the application exits (possibly + // eating memory), otherwise the clipboard will be emptied on exit + virtual bool Flush(); + + // X11 has two clipboards which get selected by this call. Empty on MSW. void UsePrimarySelection( bool WXUNUSED(primary) = FALSE ) { } - + +private: + bool m_clearOnExit; }; // The global clipboard object diff --git a/include/wx/msw/frame.h b/include/wx/msw/frame.h index 722f4bf695..e285472352 100644 --- a/include/wx/msw/frame.h +++ b/include/wx/msw/frame.h @@ -57,9 +57,6 @@ public: virtual bool Destroy(); - virtual void ClientToScreen(int *x, int *y) const; - virtual void ScreenToClient(int *x, int *y) const; - void OnSize(wxSizeEvent& event); void OnMenuHighlight(wxMenuEvent& event); void OnActivate(wxActivateEvent& event); @@ -179,6 +176,9 @@ protected: virtual void DoSetClientSize(int width, int height); + virtual void DoClientToScreen(int *x, int *y) const; + virtual void DoScreenToClient(int *x, int *y) const; + // a plug in for MDI frame classes which need to do something special when // the menubar is set virtual void InternalSetMenuBar(); diff --git a/include/wx/msw/ole/dataobj.h b/include/wx/msw/ole/dataobj.h index ea49caaa04..ab800e3e07 100644 --- a/include/wx/msw/ole/dataobj.h +++ b/include/wx/msw/ole/dataobj.h @@ -23,8 +23,12 @@ public: typedef unsigned int NativeFormat; wxDataFormat(NativeFormat format = wxDF_INVALID) { m_format = format; } + wxDataFormat(const wxChar *format) { SetId(format); } + wxDataFormat& operator=(NativeFormat format) { m_format = format; return *this; } + wxDataFormat& operator=(const wxDataFormat& format) + { m_format = format.m_format; return *this; } // defautl copy ctor/assignment operators ok @@ -62,14 +66,11 @@ private: // ---------------------------------------------------------------------------- // forward declarations // ---------------------------------------------------------------------------- + struct IDataObject; // ---------------------------------------------------------------------------- // wxDataObject is a "smart" and polymorphic piece of data. -// -// TODO it's currently "read-only" from COM point of view, i.e. we don't -// support SetData. We don't support all advise functions neither (but -// it's easy to do if we really want them) // ---------------------------------------------------------------------------- class WXDLLEXPORT wxDataObject @@ -80,18 +81,26 @@ public: virtual ~wxDataObject(); // pure virtuals to override - // get the best suited format for our data + // get the best suited format for rendering our data virtual wxDataFormat GetPreferredFormat() const = 0; - // get the number of formats we support - virtual size_t GetFormatCount() const + // get the number of formats we support: it is understood that if we + // can accept data in some format, then we can render data in this + // format as well, but the contrary is not necessarily true. For the + // default value of the argument, all formats we support should be + // returned, but if outputOnlyToo == FALSE, then we should only return + // the formats which our SetData() understands + virtual size_t GetFormatCount(bool outputOnlyToo = TRUE) const { return 1; } // return all formats in the provided array (of size GetFormatCount()) - virtual void GetAllFormats(wxDataFormat *formats) const + virtual void GetAllFormats(wxDataFormat *formats, + bool outputOnlyToo = TRUE) const { formats[0] = GetPreferredFormat(); } // get the (total) size of data for the given format virtual size_t GetDataSize(const wxDataFormat& format) const = 0; // copy raw data (in the specified format) to provided pointer - virtual void GetDataHere(const wxDataFormat& format, void *pBuf) const = 0; + virtual bool GetDataHere(const wxDataFormat& format, void *buf) const = 0; + // get data from the buffer (in the given format) + virtual bool SetData(const wxDataFormat& format, const void *buf) = 0; // accessors // retrieve IDataObject interface (for other OLE related classes) @@ -105,6 +114,13 @@ public: // format) -- now uses GetAllFormats() virtual bool IsSupportedFormat(const wxDataFormat& format) const; + // implementation only from now on + // ------------------------------- + + // tell the object that it should be now owned by IDataObject - i.e. when + // it is deleted, it should delete us as well + void SetAutoDelete(); + #ifdef __WXDEBUG__ // function to return symbolic name of clipboard format (for debug messages) static const char *GetFormatName(wxDataFormat format); @@ -133,8 +149,10 @@ public: { return format == wxDF_TEXT || format == wxDF_LOCALE; } virtual size_t GetDataSize(const wxDataFormat& format) const { return m_strText.Len() + 1; } // +1 for trailing '\0'of course - virtual void GetDataHere(const wxDataFormat& format, void *pBuf) const - { memcpy(pBuf, m_strText.c_str(), GetDataSize(format)); } + virtual bool GetDataHere(const wxDataFormat& format, void *buf) const + { memcpy(buf, m_strText.c_str(), GetDataSize(format)); return TRUE; } + virtual bool SetData(const wxDataFormat& format, const void *buf) + { m_strText = (const wxChar *)buf; return TRUE; } // additional helpers void SetText(const wxString& strText) { m_strText = strText; } @@ -144,16 +162,10 @@ private: wxString m_strText; }; -// ---------------------------------------------------------------------------- -// TODO: wx{Bitmap|Metafile|...}DataObject -// ---------------------------------------------------------------------------- - // ---------------------------------------------------------------------------- // wxBitmapDataObject is a specialization of wxDataObject for bitmap data // ---------------------------------------------------------------------------- -// TODO: implement OLE side of things. At present, it's just for clipboard -// use. #include "wx/bitmap.h" class WXDLLEXPORT wxBitmapDataObject : public wxDataObject @@ -168,12 +180,13 @@ public: const wxBitmap GetBitmap() const { return m_bitmap; } // implement base class pure virtuals - virtual wxDataFormat GetPreferredFormat() const - { return wxDF_BITMAP; } - virtual bool IsSupportedFormat(const wxDataFormat& format) const - { return format == wxDF_BITMAP; } + virtual wxDataFormat GetPreferredFormat() const { return wxDF_BITMAP; } + virtual size_t GetFormatCount(bool outputOnlyToo = TRUE) const; + virtual void GetAllFormats(wxDataFormat *formats, + bool outputOnlyToo = TRUE) const; virtual size_t GetDataSize(const wxDataFormat& format) const; - virtual void GetDataHere(const wxDataFormat& format, void *pBuf) const; + virtual bool GetDataHere(const wxDataFormat& format, void *buf) const; + virtual bool SetData(const wxDataFormat& format, const void *buf); private: wxBitmap m_bitmap; diff --git a/samples/dnd/dnd.cpp b/samples/dnd/dnd.cpp index 5bfcff4ecc..6bd041c924 100644 --- a/samples/dnd/dnd.cpp +++ b/samples/dnd/dnd.cpp @@ -102,12 +102,13 @@ public: void OnPaste(wxCommandEvent& event); void OnCopyBitmap(wxCommandEvent& event); void OnPasteBitmap(wxCommandEvent& event); - void OnClipboardHasText(wxCommandEvent& event); - void OnClipboardHasBitmap(wxCommandEvent& event); void OnLeftDown(wxMouseEvent& event); void OnRightDown(wxMouseEvent& event); + void OnUpdateUIPasteText(wxUpdateUIEvent& event); + void OnUpdateUIPasteBitmap(wxUpdateUIEvent& event); + DECLARE_EVENT_TABLE() private: @@ -146,11 +147,7 @@ public: } // the functions used for drag-and-drop: they dump and restore a shape into - // some bitwise-copiable data - // - // NB: here we profit from the fact that wxPoint, wxSize and wxColour are - // POD (plain old data) and so can be copied directly - but it wouldn't - // work for other types! + // some bitwise-copiable data (might use streams too...) // ------------------------------------------------------------------------ // restore from buffer @@ -179,6 +176,8 @@ public: const wxColour& GetColour() const { return m_col; } const wxSize& GetSize() const { return m_size; } + void Move(const wxPoint& pos) { m_pos = pos; } + // to implement in derived classes virtual Kind GetKind() const = 0; @@ -307,6 +306,9 @@ public: m_hasBitmap = FALSE; } + // accessors + DnDShape *GetShape() const { return m_shape; } + // implement base class pure virtuals // ---------------------------------- @@ -315,16 +317,26 @@ public: return m_formatShape; } - virtual size_t GetFormatCount() const + virtual size_t GetFormatCount(bool outputOnlyToo) const { - // +1 for our custom format - return m_dataobj.GetFormatCount() + 1; + // our custom format is supported by both GetData() and SetData() + size_t nFormats = 1; + if ( outputOnlyToo ) + { + // but the bitmap format(s) are only supported for output + nFormats += m_dataobj.GetFormatCount(); + } + + return nFormats; } - virtual void GetAllFormats(wxDataFormat *formats) const + virtual void GetAllFormats(wxDataFormat *formats, bool outputOnlyToo) const { formats[0] = m_formatShape; - m_dataobj.GetAllFormats(&formats[1]); + if ( outputOnlyToo ) + { + m_dataobj.GetAllFormats(&formats[1]); + } } virtual size_t GetDataSize(const wxDataFormat& format) const @@ -335,8 +347,6 @@ public: } else { - wxASSERT_MSG( format == wxDF_BITMAP, "unsupported format" ); - if ( !m_hasBitmap ) CreateBitmap(); @@ -344,11 +354,13 @@ public: } } - virtual void GetDataHere(const wxDataFormat& format, void *pBuf) const + virtual bool GetDataHere(const wxDataFormat& format, void *pBuf) const { if ( format == m_formatShape ) { m_shape->GetDataHere(pBuf); + + return TRUE; } else { @@ -357,10 +369,23 @@ public: if ( !m_hasBitmap ) CreateBitmap(); - m_dataobj.GetDataHere(format, pBuf); + return m_dataobj.GetDataHere(format, pBuf); } } + virtual bool SetData(const wxDataFormat& format, const void *buf) + { + wxCHECK_MSG( format == m_formatShape, FALSE, "unsupported format" ); + + delete m_shape; + m_shape = DnDShape::New(buf); + + // the shape has changed + m_hasBitmap = FALSE; + + return TRUE; + } + private: // creates a bitmap and assigns it to m_dataobj (also sets m_hasBitmap) void CreateBitmap() const; @@ -422,14 +447,25 @@ public: void SetShape(DnDShape *shape); // callbacks + void OnNewShape(wxCommandEvent& event); + void OnEditShape(wxCommandEvent& event); + void OnClearShape(wxCommandEvent& event); + + void OnCopyShape(wxCommandEvent& event); + void OnPasteShape(wxCommandEvent& event); + + void OnUpdateUICopy(wxUpdateUIEvent& event); + void OnUpdateUIPaste(wxUpdateUIEvent& event); + void OnDrag(wxMouseEvent& event); - void OnEdit(wxMouseEvent& event); void OnPaint(wxPaintEvent& event); void OnDrop(long x, long y, DnDShape *shape); private: DnDShape *m_shape; + static DnDShapeFrame *ms_lastDropTarget; + DECLARE_EVENT_TABLE() }; @@ -486,10 +522,13 @@ enum Menu_Paste, Menu_CopyBitmap, Menu_PasteBitmap, - Menu_HasText, - Menu_HasBitmap, Menu_ToBeGreyed, /* for testing */ Menu_ToBeDeleted, /* for testing */ + Menu_Shape_New = 500, + Menu_Shape_Edit, + Menu_Shape_Clear, + Menu_ShapeClipboard_Copy, + Menu_ShapeClipboard_Paste, Button_Colour = 1001 }; @@ -504,8 +543,9 @@ BEGIN_EVENT_TABLE(DnDFrame, wxFrame) EVT_MENU(Menu_Paste, DnDFrame::OnPaste) EVT_MENU(Menu_CopyBitmap, DnDFrame::OnCopyBitmap) EVT_MENU(Menu_PasteBitmap,DnDFrame::OnPasteBitmap) - EVT_MENU(Menu_HasText, DnDFrame::OnClipboardHasText) - EVT_MENU(Menu_HasBitmap, DnDFrame::OnClipboardHasBitmap) + + EVT_UPDATE_UI(Menu_Paste, DnDFrame::OnUpdateUIPasteText) + EVT_UPDATE_UI(Menu_PasteBitmap, DnDFrame::OnUpdateUIPasteBitmap) EVT_LEFT_DOWN( DnDFrame::OnLeftDown) EVT_RIGHT_DOWN( DnDFrame::OnRightDown) @@ -513,8 +553,18 @@ BEGIN_EVENT_TABLE(DnDFrame, wxFrame) END_EVENT_TABLE() BEGIN_EVENT_TABLE(DnDShapeFrame, wxFrame) - EVT_RIGHT_DOWN(DnDShapeFrame::OnDrag) - EVT_LEFT_DCLICK(DnDShapeFrame::OnEdit) + EVT_MENU(Menu_Shape_New, DnDShapeFrame::OnNewShape) + EVT_MENU(Menu_Shape_Edit, DnDShapeFrame::OnEditShape) + EVT_MENU(Menu_Shape_Clear, DnDShapeFrame::OnClearShape) + + EVT_MENU(Menu_ShapeClipboard_Copy, DnDShapeFrame::OnCopyShape) + EVT_MENU(Menu_ShapeClipboard_Paste, DnDShapeFrame::OnPasteShape) + + EVT_UPDATE_UI(Menu_ShapeClipboard_Copy, DnDShapeFrame::OnUpdateUICopy) + EVT_UPDATE_UI(Menu_ShapeClipboard_Paste, DnDShapeFrame::OnUpdateUIPaste) + + EVT_LEFT_DOWN(DnDShapeFrame::OnDrag) + EVT_PAINT(DnDShapeFrame::OnPaint) END_EVENT_TABLE() @@ -567,7 +617,7 @@ DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h) file_menu->Append(Menu_Quit, "E&xit"); wxMenu *log_menu = new wxMenu; - log_menu->Append(Menu_Clear, "Clear"); + log_menu->Append(Menu_Clear, "Clear\tDel"); wxMenu *help_menu = new wxMenu; help_menu->Append(Menu_Help, "&Help..."); @@ -578,11 +628,8 @@ DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h) clip_menu->Append(Menu_Copy, "&Copy text\tCtrl+C"); clip_menu->Append(Menu_Paste, "&Paste text\tCtrl+V"); clip_menu->AppendSeparator(); - clip_menu->Append(Menu_CopyBitmap, "&Copy bitmap"); - clip_menu->Append(Menu_PasteBitmap, "&Paste bitmap"); - clip_menu->AppendSeparator(); - clip_menu->Append(Menu_HasText, "Clipboard has &text\tCtrl+T"); - clip_menu->Append(Menu_HasBitmap, "Clipboard has a &bitmap\tCtrl+B"); + clip_menu->Append(Menu_CopyBitmap, "&Copy bitmap\tAlt+C"); + clip_menu->Append(Menu_PasteBitmap, "&Paste bitmap\tAlt+V"); wxMenuBar *menu_bar = new wxMenuBar; menu_bar->Append(file_menu, "&File"); @@ -598,12 +645,14 @@ DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h) wxString strFile("Drop files here!"), strText("Drop text on me"); - m_ctrlFile = new wxListBox(this, -1, pos, size, 1, &strFile, wxLB_HSCROLL | wxLB_ALWAYS_SB ); - m_ctrlText = new wxListBox(this, -1, pos, size, 1, &strText, wxLB_HSCROLL | wxLB_ALWAYS_SB ); + m_ctrlFile = new wxListBox(this, -1, pos, size, 1, &strFile, + wxLB_HSCROLL | wxLB_ALWAYS_SB ); + m_ctrlText = new wxListBox(this, -1, pos, size, 1, &strText, + wxLB_HSCROLL | wxLB_ALWAYS_SB ); m_ctrlLog = new wxTextCtrl(this, -1, "", pos, size, - wxTE_MULTILINE | wxTE_READONLY | - wxSUNKEN_BORDER ); + wxTE_MULTILINE | wxTE_READONLY | + wxSUNKEN_BORDER ); // redirect log messages to the text window and switch on OLE messages // logging @@ -637,7 +686,7 @@ DnDFrame::DnDFrame(wxFrame *frame, char *title, int x, int y, int w, int h) c = new wxLayoutConstraints; c->left.SameAs (this, wxLeft); c->right.SameAs (this, wxRight); - c->height.PercentOf(this, wxHeight, 30); + c->height.PercentOf(this, wxHeight, 50); c->top.SameAs(m_ctrlText, wxBottom); m_ctrlLog->SetConstraints(c); @@ -659,50 +708,23 @@ void DnDFrame::OnPaint(wxPaintEvent& WXUNUSED(event)) dc.SetFont( wxFont( 24, wxDECORATIVE, wxNORMAL, wxNORMAL, FALSE, "charter" ) ); dc.DrawText( "Drag text from here!", 20, h-50 ); - if (m_bitmap.Ok()) - dc.DrawBitmap( m_bitmap, 280, h-120, TRUE ); + if ( m_bitmap.Ok() ) + { + // 4/5 is 80% taken by other windows, 20 is arbitrary margin + dc.DrawBitmap(m_bitmap, + w - m_bitmap.GetWidth() - 20, + (4*h)/5 + 20); + } } -void DnDFrame::OnClipboardHasText(wxCommandEvent& WXUNUSED(event)) +void DnDFrame::OnUpdateUIPasteText(wxUpdateUIEvent& event) { - if ( !wxTheClipboard->Open() ) - { - wxLogError( _T("Can't open clipboard.") ); - - return; - } - - if ( !wxTheClipboard->IsSupported( wxDF_TEXT ) ) - { - wxLogMessage( _T("No text on the clipboard") ); - } - else - { - wxLogMessage( _T("There is text on the clipboard") ); - } - - wxTheClipboard->Close(); + event.Enable( wxTheClipboard->IsSupported(wxDF_TEXT) ); } -void DnDFrame::OnClipboardHasBitmap(wxCommandEvent& WXUNUSED(event)) +void DnDFrame::OnUpdateUIPasteBitmap(wxUpdateUIEvent& event) { - if ( !wxTheClipboard->Open() ) - { - wxLogError( _T("Can't open clipboard.") ); - - return; - } - - if ( !wxTheClipboard->IsSupported( wxDF_BITMAP ) ) - { - wxLogMessage( _T("No bitmap on the clipboard") ); - } - else - { - wxLogMessage( _T("There is a bitmap on the clipboard") ); - } - - wxTheClipboard->Close(); + event.Enable( wxTheClipboard->IsSupported(wxDF_BITMAP) ); } void DnDFrame::OnNewFrame(wxCommandEvent& WXUNUSED(event)) @@ -1097,6 +1119,8 @@ void DnDShapeDialog::OnColour(wxCommandEvent& WXUNUSED(event)) // DnDShapeFrame // ---------------------------------------------------------------------------- +DnDShapeFrame *DnDShapeFrame::ms_lastDropTarget = NULL; + DnDShapeFrame::DnDShapeFrame(wxFrame *parent) : wxFrame(parent, -1, "Shape Frame", wxDefaultPosition, wxSize(250, 150)) @@ -1105,7 +1129,23 @@ DnDShapeFrame::DnDShapeFrame(wxFrame *parent) CreateStatusBar(); - SetStatusText("Double click the frame to create a shape"); + wxMenu *menuShape = new wxMenu; + menuShape->Append(Menu_Shape_New, "&New default shape\tCtrl-S"); + menuShape->Append(Menu_Shape_Edit, "&Edit shape\tCtrl-E"); + menuShape->AppendSeparator(); + menuShape->Append(Menu_Shape_Clear, "&Clear shape\tDel"); + + wxMenu *menuClipboard = new wxMenu; + menuClipboard->Append(Menu_ShapeClipboard_Copy, "&Copy\tCtrl-C"); + menuClipboard->Append(Menu_ShapeClipboard_Paste, "&Paste\tCtrl-V"); + + wxMenuBar *menubar = new wxMenuBar; + menubar->Append(menuShape, "&Shape"); + menubar->Append(menuClipboard, "&Clipboard"); + + SetMenuBar(menubar); + + SetStatusText("Press Ctrl-S to create a new shape"); SetDropTarget(new DnDShapeDropTarget(this)); @@ -1156,7 +1196,11 @@ void DnDShapeFrame::OnDrag(wxMouseEvent& event) case wxDragMove: pc = "moved"; - SetShape(NULL); + if ( ms_lastDropTarget != this ) + { + // don't delete the shape if we dropped it on ourselves! + SetShape(NULL); + } break; case wxDragCancel: @@ -1171,7 +1215,7 @@ void DnDShapeFrame::OnDrag(wxMouseEvent& event) //else: status text already set } -void DnDShapeFrame::OnEdit(wxMouseEvent& event) +void DnDShapeFrame::OnEditShape(wxCommandEvent& event) { DnDShapeDialog dlg(this, m_shape); if ( dlg.ShowModal() == wxID_OK ) @@ -1180,11 +1224,52 @@ void DnDShapeFrame::OnEdit(wxMouseEvent& event) if ( m_shape ) { - SetStatusText("Right click now drag the shape to another frame"); + SetStatusText("You can now drag the shape to another frame"); } } } +void DnDShapeFrame::OnNewShape(wxCommandEvent& event) +{ + SetShape(new DnDEllipticShape(wxPoint(10, 10), wxSize(80, 60), *wxRED)); + + SetStatusText("You can now drag the shape to another frame"); +} + +void DnDShapeFrame::OnClearShape(wxCommandEvent& event) +{ + SetShape(NULL); +} + +void DnDShapeFrame::OnCopyShape(wxCommandEvent& event) +{ + if ( m_shape ) + wxTheClipboard->AddData(new DnDShapeDataObject(m_shape)); +} + +void DnDShapeFrame::OnPasteShape(wxCommandEvent& event) +{ + DnDShapeDataObject shapeDataObject(NULL); + if ( wxTheClipboard->GetData(&shapeDataObject) ) + { + SetShape(shapeDataObject.GetShape()); + } + else + { + wxLogStatus("No shape on the clipboard"); + } +} + +void DnDShapeFrame::OnUpdateUICopy(wxUpdateUIEvent& event) +{ + event.Enable( m_shape != NULL ); +} + +void DnDShapeFrame::OnUpdateUIPaste(wxUpdateUIEvent& event) +{ + event.Enable( wxTheClipboard->IsSupported(wxDataFormat(shapeFormatId)) ); +} + void DnDShapeFrame::OnPaint(wxPaintEvent& event) { if ( m_shape ) @@ -1195,10 +1280,13 @@ void DnDShapeFrame::OnPaint(wxPaintEvent& event) void DnDShapeFrame::OnDrop(long x, long y, DnDShape *shape) { + ms_lastDropTarget = this; + wxString s; - s.Printf("Drop occured at (%ld, %ld)", x, y); + s.Printf("Shape dropped at (%ld, %ld)", x, y); SetStatusText(s); + shape->Move(ScreenToClient(wxPoint(x, y))); SetShape(shape); } @@ -1238,9 +1326,15 @@ DnDShape *DnDShape::New(const void *buf) void DnDShapeDataObject::CreateBitmap() const { - wxBitmap bitmap; + wxPoint pos = m_shape->GetPosition(); + wxSize size = m_shape->GetSize(); + int x = pos.x + size.x, + y = pos.y + size.y; + wxBitmap bitmap(x, y); wxMemoryDC dc; dc.SelectObject(bitmap); + dc.SetBrush(wxBrush("white", wxSOLID)); + dc.Clear(); m_shape->Draw(dc); dc.SelectObject(wxNullBitmap); diff --git a/src/msw/bitmap.cpp b/src/msw/bitmap.cpp index 101db25b58..9498c65e43 100644 --- a/src/msw/bitmap.cpp +++ b/src/msw/bitmap.cpp @@ -77,22 +77,14 @@ wxBitmapRefData::wxBitmapRefData() wxBitmapRefData::~wxBitmapRefData() { - if (m_selectedInto) - { - wxChar buf[200]; - wxSprintf(buf, wxT("Bitmap was deleted without selecting out of wxMemoryDC %lX."), (unsigned long) m_selectedInto); - wxFatalError(buf); - } - if (m_hBitmap) - { - DeleteObject((HBITMAP) m_hBitmap); - } - m_hBitmap = 0 ; + wxASSERT_MSG( !m_selectedInto, + wxT("deleting bitmap still selected into wxMemoryDC") ); - if (m_bitmapMask) - delete m_bitmapMask; - m_bitmapMask = NULL; + if ( m_hBitmap) + DeleteObject((HBITMAP) m_hBitmap); + if ( m_bitmapMask ) + delete m_bitmapMask; } // ---------------------------------------------------------------------------- @@ -143,12 +135,9 @@ bool wxBitmap::FreeResource(bool WXUNUSED(force)) if ( !M_BITMAPDATA ) return FALSE; - if (M_BITMAPDATA->m_selectedInto) - { - wxChar buf[200]; - wxSprintf(buf, wxT("Bitmap %lX was deleted without selecting out of wxMemoryDC %lX."), (unsigned long) this, (unsigned long) M_BITMAPDATA->m_selectedInto); - wxFatalError(buf); - } + wxASSERT_MSG( !M_BITMAPDATA->m_selectedInto, + wxT("freeing bitmap still selected into wxMemoryDC") ); + if (M_BITMAPDATA->m_hBitmap) { DeleteObject((HBITMAP) M_BITMAPDATA->m_hBitmap); diff --git a/src/msw/clipbrd.cpp b/src/msw/clipbrd.cpp index cd94dce908..f31924940b 100644 --- a/src/msw/clipbrd.cpp +++ b/src/msw/clipbrd.cpp @@ -57,14 +57,24 @@ #include "wx/msw/private.h" #include "wx/msw/dib.h" -// wxDataObject is tied to OLE/drag and drop implementation, -// therefore so is wxClipboard :-( -#if wxUSE_DRAG_AND_DROP +// wxDataObject is tied to OLE/drag and drop implementation, therefore so are +// the functions using wxDataObject in wxClipboard +#define wxUSE_DATAOBJ wxUSE_DRAG_AND_DROP + +#if wxUSE_DATAOBJ #include "wx/dataobj.h" - static bool wxSetClipboardData(wxDataObject *data); + // use OLE clipboard + #define wxUSE_OLE_CLIPBOARD 1 +#else // !wxUSE_DATAOBJ + // use Win clipboard API + #define wxUSE_OLE_CLIPBOARD 0 #endif +#if wxUSE_OLE_CLIPBOARD + #include +#endif // wxUSE_OLE_CLIPBOARD + #ifdef __WIN16__ #define memcpy hmemcpy #endif @@ -136,41 +146,12 @@ bool wxIsClipboardOpened() bool wxIsClipboardFormatAvailable(wxDataFormat dataFormat) { - return ::IsClipboardFormatAvailable(dataFormat) != 0; + // for bitmaps, DIBs will also do + return (::IsClipboardFormatAvailable(dataFormat) != 0) || + (dataFormat.GetFormatId() == CF_BITMAP && + ::IsClipboardFormatAvailable(CF_DIB)); } -#if wxUSE_DRAG_AND_DROP -static bool wxSetClipboardData(wxDataObject *data) -{ - wxDataFormat format = data->GetPreferredFormat(); - size_t size = data->GetDataSize(format); - HANDLE hGlobal = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size); - if ( !hGlobal ) - { - wxLogSysError(_("Failed to allocate %dKb of memory for clipboard " - "transfer."), size / 1024); - - return FALSE; - } - - LPVOID lpGlobalMemory = ::GlobalLock(hGlobal); - - data->GetDataHere(format, lpGlobalMemory); - - GlobalUnlock(hGlobal); - - if ( !::SetClipboardData(format, hGlobal) ) - { - wxLogSysError(_("Failed to set clipboard data in format %s"), - wxDataObject::GetFormatName(format)); - - return FALSE; - } - - return TRUE; -} -#endif // wxUSE_DRAG_AND_DROP - bool wxSetClipboardData(wxDataFormat dataFormat, const void *data, int width, int height) @@ -223,7 +204,7 @@ bool wxSetClipboardData(wxDataFormat dataFormat, // NULL palette means to use the system one HANDLE hDIB = wxBitmapToDIB(hBitmap, (HPALETTE)NULL); handle = SetClipboardData(CF_DIB, hDIB); -#endif +#endif // wxUSE_IMAGE_LOADING_IN_MSW break; } @@ -442,20 +423,51 @@ wxClipboard* wxTheClipboard = (wxClipboard *)NULL; wxClipboard::wxClipboard() { + m_clearOnExit = FALSE; } wxClipboard::~wxClipboard() { - Clear(); + if ( m_clearOnExit ) + { + Clear(); + } } void wxClipboard::Clear() { +#if wxUSE_OLE_CLIPBOARD + if ( FAILED(OleSetClipboard(NULL)) ) + { + wxLogLastError("OleSetClipboard(NULL)"); + } +#endif +} + +bool wxClipboard::Flush() +{ + if ( FAILED(OleFlushClipboard()) ) + { + wxLogLastError("OleFlushClipboard"); + + return FALSE; + } + else + { + m_clearOnExit = FALSE; + + return TRUE; + } } bool wxClipboard::Open() { + // OLE opens clipboard for us +#if wxUSE_OLE_CLIPBOARD + return TRUE; +#else return wxOpenClipboard(); +#endif } bool wxClipboard::SetData( wxDataObject *data ) @@ -472,7 +484,32 @@ bool wxClipboard::AddData( wxDataObject *data ) { wxCHECK_MSG( data, FALSE, wxT("data is invalid") ); -#if wxUSE_DRAG_AND_DROP +#if wxUSE_OLE_CLIPBOARD + HRESULT hr = OleSetClipboard(data->GetInterface()); + if ( FAILED(hr) ) + { + wxLogSysError(hr, _("Failed to put data on the clipboard")); + + // don't free anything in this case + + return FALSE; + } + + // we have a problem here because we should delete wxDataObject, but we + // can't do it because IDataObject which we just gave to the clipboard + // would try to use it when it will need the data. IDataObject is ref + // counted and so doesn't suffer from such problem, so we release it now + // and tell it to delete wxDataObject when it is deleted itself. + data->SetAutoDelete(); + + // we have to call either OleSetClipboard(NULL) or OleFlushClipboard() when + // using OLE clipboard when the app terminates - by default, we call + // OleSetClipboard(NULL) which won't waste RAM, but the app can call + // wxClipboard::Flush() to chaneg this + m_clearOnExit = TRUE; + + return TRUE; +#elif wxUSE_DATAOBJ wxCHECK_MSG( wxIsClipboardOpened(), FALSE, wxT("clipboard not open") ); wxDataFormat format = data->GetFormat(); @@ -510,14 +547,17 @@ bool wxClipboard::AddData( wxDataObject *data ) default: return wxSetClipboardData(data); } -#else // !wxUSE_DRAG_AND_DROP +#else // !wxUSE_DATAOBJ return FALSE; -#endif // wxUSE_DRAG_AND_DROP/!wxUSE_DRAG_AND_DROP +#endif // wxUSE_DATAOBJ/!wxUSE_DATAOBJ } void wxClipboard::Close() { + // OLE closes clipboard for us +#if !wxUSE_OLE_CLIPBOARD wxCloseClipboard(); +#endif } bool wxClipboard::IsSupported( wxDataFormat format ) @@ -527,9 +567,145 @@ bool wxClipboard::IsSupported( wxDataFormat format ) bool wxClipboard::GetData( wxDataObject *data ) { + wxCHECK_MSG( data, FALSE, wxT("invalid data object") ); + +#if wxUSE_OLE_CLIPBOARD + IDataObject *pDataObject = NULL; + HRESULT hr = OleGetClipboard(&pDataObject); + if ( FAILED(hr) || !pDataObject ) + { + wxLogSysError(hr, _("Failed to get data from the clipboard")); + + return FALSE; + } + + // build the list of supported formats + size_t nFormats = data->GetFormatCount(FALSE /* for SetData() */); + wxDataFormat format, *formats; + if ( nFormats == 1 ) + { + // the most common case + formats = &format; + } + else + { + // bad luck, need to alloc mem + formats = new wxDataFormat[nFormats]; + } + + data->GetAllFormats(formats, FALSE); + + // get the format enumerator + bool result = FALSE; + wxArrayInt supportedFormats; + IEnumFORMATETC *pEnumFormatEtc = NULL; + hr = pDataObject->EnumFormatEtc(DATADIR_GET, &pEnumFormatEtc); + if ( FAILED(hr) || !pEnumFormatEtc ) + { + wxLogSysError(hr, + _("Failed to retrieve the supported clipboard formats")); + } + else + { + // ask for the supported formats and see if there are any we support + FORMATETC formatEtc; + for ( ;; ) + { + ULONG nCount; + hr = pEnumFormatEtc->Next(1, &formatEtc, &nCount); + + // don't use FAILED() because S_FALSE would pass it + if ( hr != S_OK ) + { + // no more formats + break; + } + + CLIPFORMAT cf = formatEtc.cfFormat; + +#ifdef __WXDEBUG__ + wxLogTrace(wxTRACE_OleCalls, + wxT("Object on the clipboard supports format %s."), + wxDataObject::GetFormatName(cf)); +#endif // Debug + + // is supported? + for ( size_t n = 0; n < nFormats; n++ ) + { + if ( formats[n].GetFormatId() == cf ) + { + if ( supportedFormats.Index(cf) == wxNOT_FOUND ) + { + supportedFormats.Add(cf); + } + } + } + } + + pEnumFormatEtc->Release(); + } + + if ( formats != &format ) + { + delete [] formats; + } + //else: we didn't allocate any memory + + if ( !supportedFormats.IsEmpty() ) + { + FORMATETC formatEtc; + formatEtc.ptd = NULL; + formatEtc.dwAspect = DVASPECT_CONTENT; + formatEtc.lindex = -1; + formatEtc.tymed = TYMED_HGLOBAL; + + size_t nSupportedFormats = supportedFormats.GetCount(); + for ( size_t n = 0; !result && (n < nSupportedFormats); n++ ) + { + STGMEDIUM medium; + formatEtc.cfFormat = supportedFormats[n]; + + // try to get data + hr = pDataObject->GetData(&formatEtc, &medium); + if ( FAILED(hr) ) + { + // try other tymed for GDI objects + if ( formatEtc.cfFormat == CF_BITMAP ) + { + formatEtc.tymed = TYMED_HGLOBAL; + hr = pDataObject->GetData(&formatEtc, &medium); + } + } + + if ( SUCCEEDED(hr) ) + { + // pass the data to the data object + hr = data->GetInterface()->SetData(&formatEtc, &medium, TRUE); + if ( FAILED(hr) ) + { + wxLogDebug(wxT("Failed to set data in wxIDataObject")); + + // IDataObject only takes the ownership of data if it + // successfully got it - which is not the case here + ReleaseStgMedium(&medium); + } + else + { + result = TRUE; + } + } + //else: unsupported tymed? + } + } + //else: unsupported format + + // clean up and return + pDataObject->Release(); + + return result; +#elif wxUSE_DATAOBJ wxCHECK_MSG( wxIsClipboardOpened(), FALSE, wxT("clipboard not open") ); -#if wxUSE_DRAG_AND_DROP wxDataFormat format = data->GetFormat(); switch ( format ) { @@ -593,9 +769,9 @@ bool wxClipboard::GetData( wxDataObject *data ) return FALSE; } -#else +#else // !wxUSE_DATAOBJ return FALSE; -#endif +#endif // wxUSE_DATAOBJ/!wxUSE_DATAOBJ } //----------------------------------------------------------------------------- diff --git a/src/msw/dcmemory.cpp b/src/msw/dcmemory.cpp index c8ce5662de..78fa04fea3 100644 --- a/src/msw/dcmemory.cpp +++ b/src/msw/dcmemory.cpp @@ -6,136 +6,137 @@ // Created: 01/02/97 // RCS-ID: $Id$ // Copyright: (c) Julian Smart and Markus Holzem -// Licence: wxWindows licence +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + #ifdef __GNUG__ -#pragma implementation "dcmemory.h" + #pragma implementation "dcmemory.h" #endif // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ -#pragma hdrstop + #pragma hdrstop #endif #ifndef WX_PRECOMP -#include "wx/utils.h" + #include "wx/utils.h" #endif #include "wx/msw/private.h" #include "wx/dcmemory.h" +// ---------------------------------------------------------------------------- +// wxWin macros +// ---------------------------------------------------------------------------- + #if !USE_SHARED_LIBRARY -IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC, wxDC) + IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC, wxDC) #endif -/* - * Memory DC - * - */ +// ============================================================================ +// implementation +// ============================================================================ -wxMemoryDC::wxMemoryDC(void) +// ---------------------------------------------------------------------------- +// wxMemoryDC +// ---------------------------------------------------------------------------- + +wxMemoryDC::wxMemoryDC() { - m_hDC = (WXHDC) ::CreateCompatibleDC((HDC) NULL); - m_ok = (m_hDC != 0); - m_bOwnsDC = TRUE; + m_hDC = (WXHDC) ::CreateCompatibleDC((HDC) NULL); + m_ok = (m_hDC != 0); + m_bOwnsDC = TRUE; - SetBrush(*wxWHITE_BRUSH); - SetPen(*wxBLACK_PEN); - - // the background mode is only used for text background - // and is set in DrawText() to OPAQUE as required, other- - // wise always TRANSPARENT, RR - ::SetBkMode( GetHdc(), TRANSPARENT ); + SetBrush(*wxWHITE_BRUSH); + SetPen(*wxBLACK_PEN); + // the background mode is only used for text background and is set in + // DrawText() to OPAQUE as required, otherwise always TRANSPARENT + ::SetBkMode( GetHdc(), TRANSPARENT ); } wxMemoryDC::wxMemoryDC(wxDC *old_dc) { - old_dc->BeginDrawing(); + old_dc->BeginDrawing(); - m_hDC = (WXHDC) ::CreateCompatibleDC((HDC) old_dc->GetHDC()); - m_ok = (m_hDC != 0); + m_hDC = (WXHDC) ::CreateCompatibleDC(GetHdcOf(*old_dc)); + m_ok = (m_hDC != 0); - old_dc->EndDrawing(); + old_dc->EndDrawing(); - SetBrush(*wxWHITE_BRUSH); - SetPen(*wxBLACK_PEN); - - // the background mode is only used for text background - // and is set in DrawText() to OPAQUE as required, other- - // wise always TRANSPARENT, RR - ::SetBkMode( GetHdc(), TRANSPARENT ); + SetBrush(*wxWHITE_BRUSH); + SetPen(*wxBLACK_PEN); + // the background mode is only used for text background and is set in + // DrawText() to OPAQUE as required, otherwise always TRANSPARENT + ::SetBkMode( GetHdc(), TRANSPARENT ); } -wxMemoryDC::~wxMemoryDC(void) +wxMemoryDC::~wxMemoryDC() { } void wxMemoryDC::SelectObject(const wxBitmap& bitmap) { - // Select old bitmap out of the device context - if (m_oldBitmap) - { - ::SelectObject((HDC) m_hDC, (HBITMAP) m_oldBitmap); - if (m_selectedBitmap.Ok()) + // select old bitmap out of the device context + if ( m_oldBitmap ) { - m_selectedBitmap.SetSelectedInto(NULL); - m_selectedBitmap = wxNullBitmap; + ::SelectObject(GetHdc(), (HBITMAP) m_oldBitmap); + if ( m_selectedBitmap.Ok() ) + { + m_selectedBitmap.SetSelectedInto(NULL); + m_selectedBitmap = wxNullBitmap; + } } - } - // Do own check for whether the bitmap is already selected into - // a device context - if (bitmap.GetSelectedInto() && (bitmap.GetSelectedInto() != this)) - { - wxFatalError(wxT("Error in wxMemoryDC::SelectObject\nBitmap is selected in another wxMemoryDC.\nDelete the first wxMemoryDC or use SelectObject(NULL)")); - return; - } + // check for whether the bitmap is already selected into a device context + wxCHECK_RET( !bitmap.GetSelectedInto() || + (bitmap.GetSelectedInto() == this), + wxT("Bitmap is selected in another wxMemoryDC, delete the " + "first wxMemoryDC or use SelectObject(NULL)") ); - // Check if the bitmap has the correct depth for this device context -// if (bitmap.Ok() && (bitmap.GetDepth() != GetDepth())) - // JACS 11/12/98: disabling this since the Forty Thieves sample - // shows this not working properly. In fact, if loading from a resource, - // the depth should become the screen depth, so why was it being called? -// if (0) -// { -// // Make a new bitmap that has the correct depth. -// wxBitmap newBitmap = bitmap.GetBitmapForDC(* this); -// -// m_selectedBitmap = newBitmap ; -// } -// else -// { - m_selectedBitmap = bitmap; -// } + m_selectedBitmap = bitmap; + WXHBITMAP hBmp = m_selectedBitmap.GetHBITMAP(); + if ( !hBmp ) + return; - if (!m_selectedBitmap.Ok()) - return; + m_selectedBitmap.SetSelectedInto(this); + hBmp = (WXHBITMAP)::SelectObject(GetHdc(), (HBITMAP)hBmp); - m_selectedBitmap.SetSelectedInto(this); - HBITMAP bm = (HBITMAP) ::SelectObject((HDC) m_hDC, (HBITMAP) m_selectedBitmap.GetHBITMAP()); + if ( !hBmp ) + { + wxLogLastError("SelectObject(memDC, bitmap)"); - if (bm == ERROR) - { - wxFatalError(wxT("Error in wxMemoryDC::SelectObject\nBitmap may not be loaded, or may be selected in another wxMemoryDC.\nDelete the first wxMemoryDC to deselect bitmap.")); - } - else if (!m_oldBitmap) - m_oldBitmap = (WXHBITMAP) bm; + wxFAIL_MSG(wxT("Couldn't select a bitmap into wxMemoryDC")); + } + else if ( !m_oldBitmap ) + { + m_oldBitmap = hBmp; + } } void wxMemoryDC::DoGetSize(int *width, int *height) const { - if (!m_selectedBitmap.Ok()) - { - *width = 0; *height = 0; - return; - } - *width = m_selectedBitmap.GetWidth(); - *height = m_selectedBitmap.GetHeight(); + if ( m_selectedBitmap.Ok() ) + { + *width = m_selectedBitmap.GetWidth(); + *height = m_selectedBitmap.GetHeight(); + } + else + { + *width = 0; + *height = 0; + } } diff --git a/src/msw/frame.cpp b/src/msw/frame.cpp index ffa5812de3..aded67d34f 100644 --- a/src/msw/frame.cpp +++ b/src/msw/frame.cpp @@ -705,9 +705,9 @@ wxPoint wxFrame::GetClientAreaOrigin() const return pt; } -void wxFrame::ScreenToClient(int *x, int *y) const +void wxFrame::DoScreenToClient(int *x, int *y) const { - wxWindow::ScreenToClient(x, y); + wxWindow::DoScreenToClient(x, y); // We may be faking the client origin. // So a window that's really at (0, 30) may appear @@ -717,7 +717,7 @@ void wxFrame::ScreenToClient(int *x, int *y) const *y -= pt.y; } -void wxFrame::ClientToScreen(int *x, int *y) const +void wxFrame::DoClientToScreen(int *x, int *y) const { // We may be faking the client origin. // So a window that's really at (0, 30) may appear @@ -726,7 +726,7 @@ void wxFrame::ClientToScreen(int *x, int *y) const *x += pt1.x; *y += pt1.y; - wxWindow::ClientToScreen(x, y); + wxWindow::DoClientToScreen(x, y); } #if wxUSE_TOOLBAR diff --git a/src/msw/ole/dataobj.cpp b/src/msw/ole/dataobj.cpp index f1eab4707c..a4209d8a43 100644 --- a/src/msw/ole/dataobj.cpp +++ b/src/msw/ole/dataobj.cpp @@ -55,7 +55,7 @@ // ---------------------------------------------------------------------------- #ifdef __WXDEBUG__ - static const char *GetTymedName(DWORD tymed); + static const wxChar *GetTymedName(DWORD tymed); #endif // Debug // ---------------------------------------------------------------------------- @@ -90,6 +90,12 @@ class wxIDataObject : public IDataObject { public: wxIDataObject(wxDataObject *pDataObject); + ~wxIDataObject(); + + // normally, wxDataObject controls our lifetime (i.e. we're deleted when it + // is), but in some cases, the situation is inversed, that is we delete it + // when this object is deleted - setting this flag enables such logic + void SetDeleteFlag() { m_mustDelete = TRUE; } DECLARE_IUNKNOWN_METHODS; @@ -106,6 +112,24 @@ public: private: wxDataObject *m_pDataObject; // pointer to C++ class we belong to + + bool m_mustDelete; +}; + +// ---------------------------------------------------------------------------- +// small helper class for getting screen DC (we're working with bitmaps and +// DIBs here) +// ---------------------------------------------------------------------------- + +class ScreenHDC +{ +public: + ScreenHDC() { m_hdc = GetDC(NULL); } + ~ScreenHDC() { ReleaseDC(NULL, m_hdc); } + operator HDC() const { return m_hdc; } + +private: + HDC m_hdc; }; // ============================================================================ @@ -251,6 +275,15 @@ wxIDataObject::wxIDataObject(wxDataObject *pDataObject) { m_cRef = 0; m_pDataObject = pDataObject; + m_mustDelete = FALSE; +} + +wxIDataObject::~wxIDataObject() +{ + if ( m_mustDelete ) + { + delete m_pDataObject; + } } // get data functions @@ -323,7 +356,8 @@ STDMETHODIMP wxIDataObject::GetDataHere(FORMATETC *pformatetc, switch ( pmedium->tymed ) { case TYMED_GDI: - m_pDataObject->GetDataHere(wxDF_BITMAP, &pmedium->hBitmap); + if ( !m_pDataObject->GetDataHere(wxDF_BITMAP, &pmedium->hBitmap) ) + return E_UNEXPECTED; break; case TYMED_MFPICT: @@ -342,7 +376,8 @@ STDMETHODIMP wxIDataObject::GetDataHere(FORMATETC *pformatetc, } wxDataFormat format = (wxDataFormatId)pformatetc->cfFormat; - m_pDataObject->GetDataHere(format, pBuf); + if ( !m_pDataObject->GetDataHere(format, pBuf) ) + return E_UNEXPECTED; GlobalUnlock(pmedium->hGlobal); } @@ -360,66 +395,117 @@ STDMETHODIMP wxIDataObject::SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease) { - wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::SetData")); + wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::SetData")); - return E_NOTIMPL; + switch ( pmedium->tymed ) + { + case TYMED_GDI: + m_pDataObject->SetData(wxDF_BITMAP, &pmedium->hBitmap); + break; + + case TYMED_MFPICT: + // this should be copied on bitmaps - but I don't have time for + // this now + wxFAIL_MSG(wxT("TODO - no support for metafiles in wxDataObject")); + break; + + case TYMED_HGLOBAL: + { + // copy data + void *pBuf = GlobalLock(pmedium->hGlobal); + if ( pBuf == NULL ) { + wxLogLastError("GlobalLock"); + + return E_OUTOFMEMORY; + } + + wxDataFormat format = (wxDataFormatId)pformatetc->cfFormat; + m_pDataObject->SetData(format, pBuf); + + GlobalUnlock(pmedium->hGlobal); + } + break; + + default: + return DV_E_TYMED; + } + + if ( fRelease ) { + // we own the medium, so we must release it - but do *not* free the + // bitmap handle fi we have it because we have copied it elsewhere + if ( pmedium->tymed == TYMED_GDI ) + { + pmedium->hBitmap = 0; + } + + ReleaseStgMedium(pmedium); + } + + return S_OK; } // information functions STDMETHODIMP wxIDataObject::QueryGetData(FORMATETC *pformatetc) { - // do we accept data in this format? - if ( pformatetc == NULL ) { - wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::QueryGetData: invalid ptr.")); + // do we accept data in this format? + if ( pformatetc == NULL ) { + wxLogTrace(wxTRACE_OleCalls, + wxT("wxIDataObject::QueryGetData: invalid ptr.")); - return E_INVALIDARG; - } + return E_INVALIDARG; + } - // the only one allowed by current COM implementation - if ( pformatetc->lindex != -1 ) { - wxLogTrace(wxTRACE_OleCalls, - wxT("wxIDataObject::QueryGetData: bad lindex %d"), - pformatetc->lindex); - return DV_E_LINDEX; - } + // the only one allowed by current COM implementation + if ( pformatetc->lindex != -1 ) { + wxLogTrace(wxTRACE_OleCalls, + wxT("wxIDataObject::QueryGetData: bad lindex %d"), + pformatetc->lindex); - // we don't support anything other (THUMBNAIL, ICON, DOCPRINT...) - if ( pformatetc->dwAspect != DVASPECT_CONTENT ) { - wxLogTrace(wxTRACE_OleCalls, - wxT("wxIDataObject::QueryGetData: bad dwAspect %d"), - pformatetc->dwAspect); - return DV_E_DVASPECT; - } + return DV_E_LINDEX; + } - // we only transfer data by global memory, except for some particular cases - wxDataFormat format = (wxDataFormatId)pformatetc->cfFormat; - DWORD tymed = pformatetc->tymed; - if ( (format == wxDF_BITMAP && !(tymed & TYMED_GDI)) || - !(tymed & TYMED_HGLOBAL) ) { - // it's not what we're waiting for + // we don't support anything other (THUMBNAIL, ICON, DOCPRINT...) + if ( pformatetc->dwAspect != DVASPECT_CONTENT ) { + wxLogTrace(wxTRACE_OleCalls, + wxT("wxIDataObject::QueryGetData: bad dwAspect %d"), + pformatetc->dwAspect); + + return DV_E_DVASPECT; + } + + // and now check the type of data requested + wxDataFormat format = (wxDataFormatId)pformatetc->cfFormat; + if ( m_pDataObject->IsSupportedFormat(format) ) { #ifdef __WXDEBUG__ - wxLogTrace(wxTRACE_OleCalls, - wxT("wxIDataObject::QueryGetData: %s & %s == 0."), - GetTymedName(tymed), - GetTymedName(format == wxDF_BITMAP ? TYMED_GDI : TYMED_HGLOBAL)); + wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::QueryGetData: %s ok"), + wxDataObject::GetFormatName(format)); #endif // Debug - return DV_E_TYMED; - } + } + else { + wxLogTrace(wxTRACE_OleCalls, + wxT("wxIDataObject::QueryGetData: %s unsupported"), + wxDataObject::GetFormatName(format)); - // and now check the type of data requested - if ( m_pDataObject->IsSupportedFormat(format) ) { + return DV_E_FORMATETC; + } + + // we only transfer data by global memory, except for some particular cases + DWORD tymed = pformatetc->tymed; + if ( (format == wxDF_BITMAP && !(tymed & TYMED_GDI)) && + !(tymed & TYMED_HGLOBAL) ) { + // it's not what we're waiting for #ifdef __WXDEBUG__ - wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::QueryGetData: %s ok"), - wxDataObject::GetFormatName(format)); + wxLogTrace(wxTRACE_OleCalls, + wxT("wxIDataObject::QueryGetData: %s != %s"), + GetTymedName(tymed), + GetTymedName(format == wxDF_BITMAP ? TYMED_GDI + : TYMED_HGLOBAL)); #endif // Debug + + return DV_E_TYMED; + } + return S_OK; - } - else { - wxLogTrace(wxTRACE_OleCalls, - wxT("wxIDataObject::QueryGetData: %s unsupported"), - wxDataObject::GetFormatName((wxDataFormatId)pformatetc->cfFormat)); - return DV_E_FORMATETC; - } } STDMETHODIMP wxIDataObject::GetCanonicalFormatEtc(FORMATETC *pFormatetcIn, @@ -439,12 +525,9 @@ STDMETHODIMP wxIDataObject::EnumFormatEtc(DWORD dwDirection, { wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::EnumFormatEtc")); - if ( dwDirection == DATADIR_SET ) { - // we don't allow setting of data anyhow - return E_NOTIMPL; - } + bool allowOutputOnly = dwDirection == DATADIR_GET; - size_t nFormatCount = m_pDataObject->GetFormatCount(); + size_t nFormatCount = m_pDataObject->GetFormatCount(allowOutputOnly); wxDataFormat format, *formats; if ( nFormatCount == 1 ) { // this is the most common case, this is why we consider it separately @@ -454,7 +537,7 @@ STDMETHODIMP wxIDataObject::EnumFormatEtc(DWORD dwDirection, else { // bad luck, build the array with all formats formats = new wxDataFormat[nFormatCount]; - m_pDataObject->GetAllFormats(formats); + m_pDataObject->GetAllFormats(formats, allowOutputOnly); } wxIEnumFORMATETC *pEnum = new wxIEnumFORMATETC(formats, nFormatCount); @@ -493,13 +576,22 @@ STDMETHODIMP wxIDataObject::EnumDAdvise(IEnumSTATDATA **ppenumAdvise) wxDataObject::wxDataObject() { - m_pIDataObject = new wxIDataObject(this); - m_pIDataObject->AddRef(); + m_pIDataObject = new wxIDataObject(this); + m_pIDataObject->AddRef(); } wxDataObject::~wxDataObject() { - m_pIDataObject->Release(); + ReleaseInterface(m_pIDataObject); +} + +void wxDataObject::SetAutoDelete() +{ + ((wxIDataObject *)m_pIDataObject)->SetDeleteFlag(); + m_pIDataObject->Release(); + + // so that the dtor doesnt' crash + m_pIDataObject = NULL; } bool wxDataObject::IsSupportedFormat(const wxDataFormat& format) const @@ -552,7 +644,7 @@ const char *wxDataObject::GetFormatName(wxDataFormat format) case CF_HDROP: return "CF_HDROP"; case CF_LOCALE: return "CF_LOCALE"; default: - sprintf(s_szBuf, "clipboard format %d (unknown)", format); + sprintf(s_szBuf, "clipboard format 0x%x (unknown)", format); return s_szBuf; } @@ -604,9 +696,21 @@ void wxPrivateDataObject::WriteData( const void *data, void *dest ) const } // ---------------------------------------------------------------------------- -// wxBitmapDataObject +// wxBitmapDataObject: it supports standard CF_BITMAP and CF_DIB formats // ---------------------------------------------------------------------------- +size_t wxBitmapDataObject::GetFormatCount(bool outputOnlyToo) const +{ + return 2; +} + +void wxBitmapDataObject::GetAllFormats(wxDataFormat *formats, + bool outputOnlyToo) const +{ + formats[0] = CF_BITMAP; + formats[1] = CF_DIB; +} + // the bitmaps aren't passed by value as other types of data (i.e. by copyign // the data into a global memory chunk and passing it to the clipboard or // another application or whatever), but by handle, so these generic functions @@ -614,15 +718,118 @@ void wxPrivateDataObject::WriteData( const void *data, void *dest ) const size_t wxBitmapDataObject::GetDataSize(const wxDataFormat& format) const { - // no data to copy anyhow - return 0; + if ( format.GetFormatId() == CF_DIB ) + { + // create the DIB + ScreenHDC hdc; + + // shouldn't be selected into a DC or GetDIBits() would fail + wxASSERT_MSG( !m_bitmap.GetSelectedInto(), + wxT("can't copy bitmap selected into wxMemoryDC") ); + + // first get the info + BITMAPINFO bi; + if ( !GetDIBits(hdc, (HBITMAP)m_bitmap.GetHBITMAP(), 0, 0, + NULL, &bi, DIB_RGB_COLORS) ) + { + wxLogLastError("GetDIBits(NULL)"); + + return 0; + } + + return sizeof(BITMAPINFO) + bi.bmiHeader.biSizeImage; + } + else // CF_BITMAP + { + // no data to copy - we don't pass HBITMAP via global memory + return 0; + } } -void wxBitmapDataObject::GetDataHere(const wxDataFormat& format, +bool wxBitmapDataObject::GetDataHere(const wxDataFormat& format, void *pBuf) const { - // we put a bitmap handle into pBuf - *(WXHBITMAP *)pBuf = m_bitmap.GetHBITMAP(); + wxASSERT_MSG( m_bitmap.Ok(), wxT("copying invalid bitmap") ); + + HBITMAP hbmp = (HBITMAP)m_bitmap.GetHBITMAP(); + if ( format.GetFormatId() == CF_DIB ) + { + // create the DIB + ScreenHDC hdc; + + // shouldn't be selected into a DC or GetDIBits() would fail + wxASSERT_MSG( !m_bitmap.GetSelectedInto(), + wxT("can't copy bitmap selected into wxMemoryDC") ); + + // first get the info + BITMAPINFO *pbi = (BITMAPINFO *)pBuf; + if ( !GetDIBits(hdc, hbmp, 0, 0, NULL, pbi, DIB_RGB_COLORS) ) + { + wxLogLastError("GetDIBits(NULL)"); + + return 0; + } + + // and now copy the bits + if ( !GetDIBits(hdc, hbmp, 0, pbi->bmiHeader.biHeight, pbi + 1, + pbi, DIB_RGB_COLORS) ) + { + wxLogLastError("GetDIBits"); + + return FALSE; + } + } + else // CF_BITMAP + { + // we put a bitmap handle into pBuf + *(HBITMAP *)pBuf = hbmp; + } + + return TRUE; +} + +bool wxBitmapDataObject::SetData(const wxDataFormat& format, const void *pBuf) +{ + HBITMAP hbmp; + if ( format.GetFormatId() == CF_DIB ) + { + // here we get BITMAPINFO struct followed by the actual bitmap bits and + // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info + ScreenHDC hdc; + + BITMAPINFO *pbmi = (BITMAPINFO *)pBuf; + BITMAPINFOHEADER *pbmih = &pbmi->bmiHeader; + hbmp = CreateDIBitmap(hdc, pbmih, CBM_INIT, + pbmi + 1, pbmi, DIB_RGB_COLORS); + if ( !hbmp ) + { + wxLogLastError("CreateDIBitmap"); + } + + m_bitmap.SetWidth(pbmih->biWidth); + m_bitmap.SetHeight(pbmih->biHeight); + } + else // CF_BITMAP + { + // it's easy with bitmaps: we pass them by handle + hbmp = *(HBITMAP *)pBuf; + + BITMAP bmp; + if ( !GetObject(hbmp, sizeof(BITMAP), &bmp) ) + { + wxLogLastError("GetObject(HBITMAP)"); + } + + m_bitmap.SetWidth(bmp.bmWidth); + m_bitmap.SetHeight(bmp.bmHeight); + m_bitmap.SetDepth(bmp.bmPlanes); + } + + m_bitmap.SetHBITMAP((WXHBITMAP)hbmp); + + wxASSERT_MSG( m_bitmap.Ok(), wxT("pasting invalid bitmap") ); + + return TRUE; } // ---------------------------------------------------------------------------- @@ -631,24 +838,24 @@ void wxBitmapDataObject::GetDataHere(const wxDataFormat& format, #ifdef __WXDEBUG__ -static const char *GetTymedName(DWORD tymed) +static const wxChar *GetTymedName(DWORD tymed) { - static char s_szBuf[128]; - switch ( tymed ) { - case TYMED_HGLOBAL: return "TYMED_HGLOBAL"; - case TYMED_FILE: return "TYMED_FILE"; - case TYMED_ISTREAM: return "TYMED_ISTREAM"; - case TYMED_ISTORAGE: return "TYMED_ISTORAGE"; - case TYMED_GDI: return "TYMED_GDI"; - case TYMED_MFPICT: return "TYMED_MFPICT"; - case TYMED_ENHMF: return "TYMED_ENHMF"; - default: - sprintf(s_szBuf, "type of media format %d (unknown)", tymed); - return s_szBuf; - } + static wxChar s_szBuf[128]; + switch ( tymed ) { + case TYMED_HGLOBAL: return wxT("TYMED_HGLOBAL"); + case TYMED_FILE: return wxT("TYMED_FILE"); + case TYMED_ISTREAM: return wxT("TYMED_ISTREAM"); + case TYMED_ISTORAGE: return wxT("TYMED_ISTORAGE"); + case TYMED_GDI: return wxT("TYMED_GDI"); + case TYMED_MFPICT: return wxT("TYMED_MFPICT"); + case TYMED_ENHMF: return wxT("TYMED_ENHMF"); + default: + wxSprintf(s_szBuf, wxT("type of media format %d (unknown)"), tymed); + return s_szBuf; + } } #endif // Debug -#endif +#endif // not using OLE at all