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
This commit is contained in:
Vadim Zeitlin 1999-10-18 00:08:40 +00:00
parent 23d277e683
commit d59ceba572
9 changed files with 820 additions and 333 deletions

View File

@ -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

View File

@ -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();

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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 <ole2.h>
#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
}
//-----------------------------------------------------------------------------

View File

@ -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;
}
}

View File

@ -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

View File

@ -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