// 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
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);
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();
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
// ----------------------------------------------------------------------------
// 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
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)
// 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);
{ 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; }
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
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;
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:
}
// 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
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;
m_hasBitmap = FALSE;
}
+ // accessors
+ DnDShape *GetShape() const { return m_shape; }
+
// implement base class pure virtuals
// ----------------------------------
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
}
else
{
- wxASSERT_MSG( format == wxDF_BITMAP, "unsupported format" );
-
if ( !m_hasBitmap )
CreateBitmap();
}
}
- 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
{
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;
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()
};
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
};
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)
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()
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...");
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");
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
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);
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 );
-}
-
-void DnDFrame::OnClipboardHasText(wxCommandEvent& WXUNUSED(event))
-{
- if ( !wxTheClipboard->Open() )
- {
- wxLogError( _T("Can't open clipboard.") );
-
- return;
- }
-
- if ( !wxTheClipboard->IsSupported( wxDF_TEXT ) )
+ if ( m_bitmap.Ok() )
{
- wxLogMessage( _T("No text on the clipboard") );
+ // 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);
}
- else
- {
- wxLogMessage( _T("There is text on the clipboard") );
- }
-
- wxTheClipboard->Close();
}
-void DnDFrame::OnClipboardHasBitmap(wxCommandEvent& WXUNUSED(event))
+void DnDFrame::OnUpdateUIPasteText(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") );
- }
+ event.Enable( wxTheClipboard->IsSupported(wxDF_TEXT) );
+}
- wxTheClipboard->Close();
+void DnDFrame::OnUpdateUIPasteBitmap(wxUpdateUIEvent& event)
+{
+ event.Enable( wxTheClipboard->IsSupported(wxDF_BITMAP) );
}
void DnDFrame::OnNewFrame(wxCommandEvent& WXUNUSED(event))
// DnDShapeFrame
// ----------------------------------------------------------------------------
+DnDShapeFrame *DnDShapeFrame::ms_lastDropTarget = NULL;
+
DnDShapeFrame::DnDShapeFrame(wxFrame *parent)
: wxFrame(parent, -1, "Shape Frame",
wxDefaultPosition, wxSize(250, 150))
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));
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:
//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 )
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 )
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);
}
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);
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;
}
// ----------------------------------------------------------------------------
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);
#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 <ole2.h>
+#endif // wxUSE_OLE_CLIPBOARD
+
#ifdef __WIN16__
#define memcpy hmemcpy
#endif
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)
// 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;
}
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 )
{
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();
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 )
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 )
{
return FALSE;
}
-#else
+#else // !wxUSE_DATAOBJ
return FALSE;
-#endif
+#endif // wxUSE_DATAOBJ/!wxUSE_DATAOBJ
}
//-----------------------------------------------------------------------------
// 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)
-{
- m_hDC = (WXHDC) ::CreateCompatibleDC((HDC) NULL);
- m_ok = (m_hDC != 0);
- m_bOwnsDC = TRUE;
+// ----------------------------------------------------------------------------
+// wxMemoryDC
+// ----------------------------------------------------------------------------
- SetBrush(*wxWHITE_BRUSH);
- SetPen(*wxBLACK_PEN);
+wxMemoryDC::wxMemoryDC()
+{
+ m_hDC = (WXHDC) ::CreateCompatibleDC((HDC) NULL);
+ m_ok = (m_hDC != 0);
+ m_bOwnsDC = TRUE;
- // 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;
+ }
+ }
+
+ // 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)") );
+
+ m_selectedBitmap = bitmap;
+ WXHBITMAP hBmp = m_selectedBitmap.GetHBITMAP();
+ if ( !hBmp )
+ return;
+
+ m_selectedBitmap.SetSelectedInto(this);
+ hBmp = (WXHBITMAP)::SelectObject(GetHdc(), (HBITMAP)hBmp);
+
+ if ( !hBmp )
+ {
+ wxLogLastError("SelectObject(memDC, bitmap)");
+
+ wxFAIL_MSG(wxT("Couldn't select a bitmap into wxMemoryDC"));
+ }
+ else if ( !m_oldBitmap )
+ {
+ m_oldBitmap = hBmp;
}
- }
-
- // 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 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;
-// }
-
- if (!m_selectedBitmap.Ok())
- return;
-
- m_selectedBitmap.SetSelectedInto(this);
- HBITMAP bm = (HBITMAP) ::SelectObject((HDC) m_hDC, (HBITMAP) m_selectedBitmap.GetHBITMAP());
-
- 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;
}
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;
+ }
}
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
*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
*x += pt1.x;
*y += pt1.y;
- wxWindow::ClientToScreen(x, y);
+ wxWindow::DoClientToScreen(x, y);
}
#if wxUSE_TOOLBAR
// ----------------------------------------------------------------------------
#ifdef __WXDEBUG__
- static const char *GetTymedName(DWORD tymed);
+ static const wxChar *GetTymedName(DWORD tymed);
#endif // Debug
// ----------------------------------------------------------------------------
{
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;
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;
};
// ============================================================================
{
m_cRef = 0;
m_pDataObject = pDataObject;
+ m_mustDelete = FALSE;
+}
+
+wxIDataObject::~wxIDataObject()
+{
+ if ( m_mustDelete )
+ {
+ delete m_pDataObject;
+ }
}
// get data functions
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:
}
wxDataFormat format = (wxDataFormatId)pformatetc->cfFormat;
- m_pDataObject->GetDataHere(format, pBuf);
+ if ( !m_pDataObject->GetDataHere(format, pBuf) )
+ return E_UNEXPECTED;
GlobalUnlock(pmedium->hGlobal);
}
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,
{
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
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);
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
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;
}
}
// ----------------------------------------------------------------------------
-// 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
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;
}
// ----------------------------------------------------------------------------
#ifdef __WXDEBUG__
-static const char *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 const wxChar *GetTymedName(DWORD tymed)
+{
+ 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