1. wxPostEvent added and documented

2. Made it possible to have wxDataObjects which support multiple formats
   painlessly
3. Extensively modified dnd sample to show a "real life" wxDataObject


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@4028 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
1999-10-17 01:18:49 +00:00
parent 6d693bb4fc
commit 8e193f384f
24 changed files with 1359 additions and 637 deletions

View File

@@ -9,6 +9,14 @@
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#ifdef __GNUG__
#pragma implementation "event.h"
#endif
@@ -38,6 +46,10 @@
#include "wx/validate.h"
#endif // wxUSE_GUI
// ----------------------------------------------------------------------------
// wxWin macros
// ----------------------------------------------------------------------------
#if !USE_SHARED_LIBRARY
IMPLEMENT_DYNAMIC_CLASS(wxEvtHandler, wxObject)
IMPLEMENT_ABSTRACT_CLASS(wxEvent, wxObject)
@@ -84,12 +96,26 @@
#endif // !USE_SHARED_LIBRARY
// ----------------------------------------------------------------------------
// global variables
// ----------------------------------------------------------------------------
// To put pending event handlers
wxList *wxPendingEvents = (wxList *)NULL;
#if wxUSE_THREADS
/* To put pending event handlers */
extern wxList *wxPendingEvents;
extern wxCriticalSection *wxPendingEventsLocker;
// protects wxPendingEvents list
wxCriticalSection *wxPendingEventsLocker = (wxCriticalSection *)NULL;
#endif
// ============================================================================
// implementation
// ============================================================================
// ----------------------------------------------------------------------------
// wxEvent
// ----------------------------------------------------------------------------
/*
* General wxWindows events, covering
* all interesting things that might happen (button clicking, resizing,
@@ -514,10 +540,10 @@ wxEvtHandler::wxEvtHandler()
m_enabled = TRUE;
m_dynamicEvents = (wxList *) NULL;
m_isWindow = FALSE;
#if wxUSE_THREADS
m_eventsLocker = new wxCriticalSection();
#endif
m_pendingEvents = (wxList *) NULL;
#if wxUSE_THREADS
m_eventsLocker = new wxCriticalSection;
#endif
}
wxEvtHandler::~wxEvtHandler()
@@ -542,63 +568,76 @@ wxEvtHandler::~wxEvtHandler()
delete m_dynamicEvents;
};
#if wxUSE_THREADS
if (m_pendingEvents)
delete m_pendingEvents;
delete m_pendingEvents;
#if wxUSE_THREADS
delete m_eventsLocker;
#endif
}
#if wxUSE_THREADS
#ifdef __WXGTK__
extern bool g_isIdle;
extern void wxapp_install_idle_handler();
#endif
bool wxEvtHandler::ProcessThreadEvent(wxEvent& event)
{
wxEvent *event_main;
wxCriticalSectionLocker locker(*m_eventsLocker);
// check that we are really in a child thread
wxASSERT( !wxThread::IsMain() );
wxASSERT_MSG( !wxThread::IsMain(),
wxT("use ProcessEvent() in main thread") );
if (m_pendingEvents == NULL)
m_pendingEvents = new wxList();
AddPendingEvent(event);
event_main = (wxEvent *)event.Clone();
return TRUE;
}
m_pendingEvents->Append(event_main);
#endif // wxUSE_THREADS
void wxEvtHandler::AddPendingEvent(wxEvent& event)
{
if ( !m_pendingEvents )
m_pendingEvents = new wxList;
wxEvent *event2 = (wxEvent *)event.Clone();
m_pendingEvents->Append(event2);
wxPendingEventsLocker->Enter();
if ( !wxPendingEvents )
wxPendingEvents = new wxList;
wxPendingEvents->Append(this);
wxPendingEventsLocker->Leave();
// TODO: Wake up idle handler for the other platforms.
#ifdef __WXGTK__
if (g_isIdle)
extern bool g_isIdle;
extern void wxapp_install_idle_handler();
if ( g_isIdle )
wxapp_install_idle_handler();
#endif
return TRUE;
#else // this works for wxMSW, but may be for others too?
// might also send a dummy message to the top level window, this would
// probably be cleaner?
wxIdleEvent eventIdle;
wxTheApp->OnIdle(eventIdle);
#endif // platform
}
void wxEvtHandler::ProcessPendingEvents()
{
#if wxUSE_THREADS
wxCriticalSectionLocker locker(*m_eventsLocker);
#endif
wxNode *node = m_pendingEvents->First();
wxEvent *event;
while (node != NULL) {
event = (wxEvent *)node->Data();
ProcessEvent(*event);
delete node;
node = m_pendingEvents->First();
while ( node )
{
event = (wxEvent *)node->Data();
ProcessEvent(*event);
delete node;
node = m_pendingEvents->First();
}
}
#endif
/*
* Event table stuff
@@ -607,25 +646,24 @@ void wxEvtHandler::ProcessPendingEvents()
bool wxEvtHandler::ProcessEvent(wxEvent& event)
{
#if wxUSE_GUI
/* check that our flag corresponds to reality */
// check that our flag corresponds to reality
wxASSERT( m_isWindow == IsKindOf(CLASSINFO(wxWindow)) );
#endif // wxUSE_GUI
/* An event handler can be enabled or disabled */
// An event handler can be enabled or disabled
if ( GetEvtHandlerEnabled() )
{
#if wxUSE_THREADS
/* Check whether we are in a child thread. */
if (!wxThread::IsMain())
// Check whether we are in a child thread.
if ( !wxThread::IsMain() )
return ProcessThreadEvent(event);
#endif
/* Handle per-instance dynamic event tables first */
#endif // wxUSE_THREADS
// Handle per-instance dynamic event tables first
if ( m_dynamicEvents && SearchDynamicEventTable(event) )
return TRUE;
/* Then static per-class event tables */
// Then static per-class event tables
const wxEventTable *table = GetEventTable();
#if wxUSE_GUI && wxUSE_VALIDATORS

View File

@@ -48,10 +48,6 @@
wxApp *wxTheApp = (wxApp *) NULL;
wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL;
#if wxUSE_THREADS
extern wxList *wxPendingEvents;
extern wxCriticalSection *wxPendingEventsLocker;
#endif
extern wxResourceCache *wxTheResourceCache;
extern bool g_isIdle;
@@ -127,7 +123,7 @@ unsigned char g_palette[64*3] =
// local functions
//-----------------------------------------------------------------------------
extern void wxFlushResources(void);
extern void wxFlushResources();
//-----------------------------------------------------------------------------
// global functions
@@ -265,6 +261,7 @@ static gint wxapp_wakeup_timerout_callback( gpointer WXUNUSED(data) )
return TRUE;
}
#endif // wxUSE_THREADS
//-----------------------------------------------------------------------------
@@ -427,11 +424,9 @@ void wxApp::OnIdle( wxIdleEvent &event )
s_inOnIdle = TRUE;
#if wxUSE_THREADS
/* Resend in the main thread events which have been prepared in other
threads */
ProcessPendingEvents();
#endif
/* 'Garbage' collection of windows deleted with Close(). */
DeletePendingObjects();
@@ -520,12 +515,16 @@ void wxApp::Dispatch()
gtk_main_iteration();
}
#if wxUSE_THREADS
void wxApp::ProcessPendingEvents()
{
wxNode *node = wxPendingEvents->First();
#if wxUSE_THREADS
wxCriticalSectionLocker locker(*wxPendingEventsLocker);
#endif // wxUSE_THREADS
if ( !wxPendingEvents )
return;
wxNode *node = wxPendingEvents->First();
while (node)
{
wxEvtHandler *handler = (wxEvtHandler *)node->Data();
@@ -537,7 +536,6 @@ void wxApp::ProcessPendingEvents()
node = wxPendingEvents->First();
}
}
#endif // wxUSE_THREADS
void wxApp::DeletePendingObjects()
{

View File

@@ -39,12 +39,6 @@ wxWindowList wxTopLevelWindows;
/* List of windows pending deletion */
wxList wxPendingDelete;
#if wxUSE_THREADS
/* List of events pending processing */
wxList *wxPendingEvents = NULL;
wxCriticalSection *wxPendingEventsLocker = NULL;
#endif
/* Current cursor, in order to hang on to
* cursor handle when setting the cursor globally */
wxCursor g_globalCursor;

View File

@@ -651,7 +651,7 @@ source_drag_data_get (GtkWidget *WXUNUSED(widget),
/* disable GUI threads */
wxapp_uninstall_thread_wakeup();
#endif
gtk_selection_data_set( selection_data,
selection_data->target,
8, // 8-bit
@@ -745,7 +745,8 @@ wxDropSource::wxDropSource( wxWindow *win, const wxIcon &go, const wxIcon &stop
if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
}
wxDropSource::wxDropSource( wxDataObject *data, wxWindow *win, const wxIcon &go, const wxIcon &stop )
wxDropSource::wxDropSource( wxDataObject& data, wxWindow *win,
const wxIcon &go, const wxIcon &stop )
{
m_waiting = TRUE;
@@ -754,15 +755,8 @@ wxDropSource::wxDropSource( wxDataObject *data, wxWindow *win, const wxIcon &go,
if (win->m_wxwindow) m_widget = win->m_wxwindow;
m_retValue = wxDragCancel;
if (data)
{
m_data = new wxDataBroker();
m_data->Add( data );
}
else
{
m_data = (wxDataBroker*) NULL;
}
m_data = new wxDataBroker;
m_data->Add(&data);
m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
m_goaheadCursor = wxCursor( wxCURSOR_HAND );
@@ -786,6 +780,15 @@ wxDropSource::wxDropSource( wxDataBroker *data, wxWindow *win )
m_goaheadCursor = wxCursor( wxCURSOR_HAND );
}
void wxDropSource::SetData( wxDataObject& data )
{
if ( m_data )
delete m_data;
m_data = new wxDataBroker;
m_data->Add(&data);
}
void wxDropSource::SetData( wxDataObject *data )
{
if (m_data) delete m_data;
@@ -808,7 +811,7 @@ void wxDropSource::SetData( wxDataBroker *data )
m_data = data;
}
wxDropSource::~wxDropSource(void)
wxDropSource::~wxDropSource()
{
if (m_data) delete m_data;
@@ -854,7 +857,7 @@ wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
/* disable GUI threads */
wxapp_uninstall_thread_wakeup();
#endif
/* don't start dragging if no button is down */
if (button_number)
{
@@ -883,7 +886,7 @@ wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
/* re-enable GUI threads */
wxapp_install_thread_wakeup();
#endif
g_blockEventsOnDrag = FALSE;
UnregisterWindow();

View File

@@ -48,10 +48,6 @@
wxApp *wxTheApp = (wxApp *) NULL;
wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL;
#if wxUSE_THREADS
extern wxList *wxPendingEvents;
extern wxCriticalSection *wxPendingEventsLocker;
#endif
extern wxResourceCache *wxTheResourceCache;
extern bool g_isIdle;
@@ -127,7 +123,7 @@ unsigned char g_palette[64*3] =
// local functions
//-----------------------------------------------------------------------------
extern void wxFlushResources(void);
extern void wxFlushResources();
//-----------------------------------------------------------------------------
// global functions
@@ -265,6 +261,7 @@ static gint wxapp_wakeup_timerout_callback( gpointer WXUNUSED(data) )
return TRUE;
}
#endif // wxUSE_THREADS
//-----------------------------------------------------------------------------
@@ -427,11 +424,9 @@ void wxApp::OnIdle( wxIdleEvent &event )
s_inOnIdle = TRUE;
#if wxUSE_THREADS
/* Resend in the main thread events which have been prepared in other
threads */
ProcessPendingEvents();
#endif
/* 'Garbage' collection of windows deleted with Close(). */
DeletePendingObjects();
@@ -520,12 +515,16 @@ void wxApp::Dispatch()
gtk_main_iteration();
}
#if wxUSE_THREADS
void wxApp::ProcessPendingEvents()
{
wxNode *node = wxPendingEvents->First();
#if wxUSE_THREADS
wxCriticalSectionLocker locker(*wxPendingEventsLocker);
#endif // wxUSE_THREADS
if ( !wxPendingEvents )
return;
wxNode *node = wxPendingEvents->First();
while (node)
{
wxEvtHandler *handler = (wxEvtHandler *)node->Data();
@@ -537,7 +536,6 @@ void wxApp::ProcessPendingEvents()
node = wxPendingEvents->First();
}
}
#endif // wxUSE_THREADS
void wxApp::DeletePendingObjects()
{

View File

@@ -39,12 +39,6 @@ wxWindowList wxTopLevelWindows;
/* List of windows pending deletion */
wxList wxPendingDelete;
#if wxUSE_THREADS
/* List of events pending processing */
wxList *wxPendingEvents = NULL;
wxCriticalSection *wxPendingEventsLocker = NULL;
#endif
/* Current cursor, in order to hang on to
* cursor handle when setting the cursor globally */
wxCursor g_globalCursor;

View File

@@ -651,7 +651,7 @@ source_drag_data_get (GtkWidget *WXUNUSED(widget),
/* disable GUI threads */
wxapp_uninstall_thread_wakeup();
#endif
gtk_selection_data_set( selection_data,
selection_data->target,
8, // 8-bit
@@ -745,7 +745,8 @@ wxDropSource::wxDropSource( wxWindow *win, const wxIcon &go, const wxIcon &stop
if (wxNullIcon == stop) m_stopIcon = wxIcon( gv_xpm );
}
wxDropSource::wxDropSource( wxDataObject *data, wxWindow *win, const wxIcon &go, const wxIcon &stop )
wxDropSource::wxDropSource( wxDataObject& data, wxWindow *win,
const wxIcon &go, const wxIcon &stop )
{
m_waiting = TRUE;
@@ -754,15 +755,8 @@ wxDropSource::wxDropSource( wxDataObject *data, wxWindow *win, const wxIcon &go,
if (win->m_wxwindow) m_widget = win->m_wxwindow;
m_retValue = wxDragCancel;
if (data)
{
m_data = new wxDataBroker();
m_data->Add( data );
}
else
{
m_data = (wxDataBroker*) NULL;
}
m_data = new wxDataBroker;
m_data->Add(&data);
m_defaultCursor = wxCursor( wxCURSOR_NO_ENTRY );
m_goaheadCursor = wxCursor( wxCURSOR_HAND );
@@ -786,6 +780,15 @@ wxDropSource::wxDropSource( wxDataBroker *data, wxWindow *win )
m_goaheadCursor = wxCursor( wxCURSOR_HAND );
}
void wxDropSource::SetData( wxDataObject& data )
{
if ( m_data )
delete m_data;
m_data = new wxDataBroker;
m_data->Add(&data);
}
void wxDropSource::SetData( wxDataObject *data )
{
if (m_data) delete m_data;
@@ -808,7 +811,7 @@ void wxDropSource::SetData( wxDataBroker *data )
m_data = data;
}
wxDropSource::~wxDropSource(void)
wxDropSource::~wxDropSource()
{
if (m_data) delete m_data;
@@ -854,7 +857,7 @@ wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
/* disable GUI threads */
wxapp_uninstall_thread_wakeup();
#endif
/* don't start dragging if no button is down */
if (button_number)
{
@@ -883,7 +886,7 @@ wxDragResult wxDropSource::DoDragDrop( bool WXUNUSED(bAllowMove) )
/* re-enable GUI threads */
wxapp_install_thread_wakeup();
#endif
g_blockEventsOnDrag = FALSE;
UnregisterWindow();

View File

@@ -98,10 +98,6 @@ extern wxChar *wxBuffer;
extern wxChar *wxOsVersion;
extern wxList *wxWinHandleList;
extern wxList WXDLLEXPORT wxPendingDelete;
#if wxUSE_THREADS
extern wxList *wxPendingEvents;
extern wxCriticalSection *wxPendingEventsLocker;
#endif
extern void wxSetKeyboardHook(bool doIt);
extern wxCursor *g_globalCursor;
@@ -179,11 +175,8 @@ bool wxApp::Initialize()
wxGetResource(wxT("wxWindows"), wxT("OsVersion"), &wxOsVersion);
#endif
// I'm annoyed ... I don't know where to put this and I don't want to
// create a module for that as it's part of the core.
#if wxUSE_THREADS
wxPendingEvents = new wxList();
wxPendingEventsLocker = new wxCriticalSection();
wxPendingEventsLocker = new wxCriticalSection;
#endif
wxTheColourDatabase = new wxColourDatabase(wxKEY_STRING);
@@ -565,8 +558,8 @@ void wxApp::CleanUp()
// GL: I'm annoyed ... I don't know where to put this and I don't want to
// create a module for that as it's part of the core.
#if wxUSE_THREADS
delete wxPendingEvents;
#if wxUSE_THREADS
delete wxPendingEventsLocker;
// If we don't do the following, we get an apparent memory leak.
((wxEvtHandler&) wxDefaultValidator).ClearEventLocker();
@@ -931,12 +924,17 @@ bool wxApp::ProcessIdle()
return event.MoreRequested();
}
#if wxUSE_THREADS
void wxApp::ProcessPendingEvents()
{
wxNode *node = wxPendingEvents->First();
#if wxUSE_THREADS
// ensure that we're the only thread to modify the pending events list
wxCriticalSectionLocker locker(*wxPendingEventsLocker);
#endif
if ( !wxPendingEvents )
return;
wxNode *node = wxPendingEvents->First();
while (node)
{
wxEvtHandler *handler = (wxEvtHandler *)node->Data();
@@ -947,8 +945,6 @@ void wxApp::ProcessPendingEvents()
node = wxPendingEvents->First();
}
}
#endif
void wxApp::ExitMainLoop()
{
@@ -1032,10 +1028,11 @@ void wxApp::OnIdle(wxIdleEvent& event)
event.RequestMore(TRUE);
}
// If they are pending events, we must process them.
#if wxUSE_THREADS
// If they are pending events, we must process them: pending events are
// either events to the threads other than main or events posted with
// wxPostEvent() functions
ProcessPendingEvents();
#endif
s_inOnIdle = FALSE;
}
@@ -1168,22 +1165,19 @@ void wxExit()
// Yield to incoming messages
bool wxYield()
{
// we don't want to process WM_QUIT from here - it should be processed in
// the main event loop in order to stop it
MSG msg;
// We want to go back to the main message loop
// if we see a WM_QUIT. (?)
#ifdef __WXWINE__
while (PeekMessage(&msg, (HWND)NULL, 0, 0, PM_NOREMOVE) && msg.message != WM_QUIT)
#else
while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) && msg.message != WM_QUIT)
#endif
while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
msg.message != WM_QUIT )
{
if ( !wxTheApp->DoMessage() )
break;
}
// If they are pending events, we must process them.
#if wxUSE_THREADS
wxTheApp->ProcessPendingEvents();
#endif
return TRUE;
}

View File

@@ -142,7 +142,8 @@ bool wxIsClipboardFormatAvailable(wxDataFormat dataFormat)
#if wxUSE_DRAG_AND_DROP
static bool wxSetClipboardData(wxDataObject *data)
{
size_t size = data->GetDataSize();
wxDataFormat format = data->GetPreferredFormat();
size_t size = data->GetDataSize(format);
HANDLE hGlobal = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size);
if ( !hGlobal )
{
@@ -154,11 +155,10 @@ static bool wxSetClipboardData(wxDataObject *data)
LPVOID lpGlobalMemory = ::GlobalLock(hGlobal);
data->GetDataHere(lpGlobalMemory);
data->GetDataHere(format, lpGlobalMemory);
GlobalUnlock(hGlobal);
wxDataFormat format = data->GetPreferredFormat();
if ( !::SetClipboardData(format, hGlobal) )
{
wxLogSysError(_("Failed to set clipboard data in format %s"),

View File

@@ -37,12 +37,6 @@ wxWindowList wxTopLevelWindows;
// List of windows pending deletion
wxList WXDLLEXPORT wxPendingDelete;
// List of events pending processing
#if wxUSE_THREADS
wxList *wxPendingEvents = NULL;
wxCriticalSection *wxPendingEventsLocker = NULL;
#endif
// Current cursor, in order to hang on to
// cursor handle when setting the cursor globally
wxCursor *g_globalCursor = NULL;

View File

@@ -54,52 +54,58 @@
// functions
// ----------------------------------------------------------------------------
static const char *GetTymedName(DWORD tymed);
#ifdef __WXDEBUG__
static const char *GetTymedName(DWORD tymed);
#endif // Debug
// ----------------------------------------------------------------------------
// wxIEnumFORMATETC interface implementation
// ----------------------------------------------------------------------------
class wxIEnumFORMATETC : public IEnumFORMATETC
{
public:
wxIEnumFORMATETC(CLIPFORMAT cf);
wxIEnumFORMATETC(const wxDataFormat* formats, ULONG nCount);
~wxIEnumFORMATETC() { delete [] m_formats; }
DECLARE_IUNKNOWN_METHODS;
DECLARE_IUNKNOWN_METHODS;
// IEnumFORMATETC
STDMETHODIMP Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched);
STDMETHODIMP Skip(ULONG celt);
STDMETHODIMP Reset();
STDMETHODIMP Clone(IEnumFORMATETC **ppenum);
// IEnumFORMATETC
STDMETHODIMP Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched);
STDMETHODIMP Skip(ULONG celt);
STDMETHODIMP Reset();
STDMETHODIMP Clone(IEnumFORMATETC **ppenum);
private:
FORMATETC m_format; // (unique @@@) format we can provide data in
ULONG m_nCurrent; // current enum position (currently either 0 or 1)
CLIPFORMAT *m_formats; // formats we can provide data in
ULONG m_nCount, // number of formats we support
m_nCurrent; // current enum position
};
// ----------------------------------------------------------------------------
// wxIDataObject implementation of IDataObject interface
// ----------------------------------------------------------------------------
class wxIDataObject : public IDataObject
{
public:
wxIDataObject(wxDataObject *pDataObject);
wxIDataObject(wxDataObject *pDataObject);
DECLARE_IUNKNOWN_METHODS;
DECLARE_IUNKNOWN_METHODS;
// IDataObject
STDMETHODIMP GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium);
STDMETHODIMP GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium);
STDMETHODIMP QueryGetData(FORMATETC *pformatetc);
STDMETHODIMP GetCanonicalFormatEtc(FORMATETC *In, FORMATETC *pOut);
STDMETHODIMP SetData(FORMATETC *pfetc, STGMEDIUM *pmedium, BOOL fRelease);
STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFEtc);
STDMETHODIMP DAdvise(FORMATETC *pfetc, DWORD ad, IAdviseSink *p, DWORD *pdw);
STDMETHODIMP DUnadvise(DWORD dwConnection);
STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise);
// IDataObject
STDMETHODIMP GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium);
STDMETHODIMP GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium);
STDMETHODIMP QueryGetData(FORMATETC *pformatetc);
STDMETHODIMP GetCanonicalFormatEtc(FORMATETC *In, FORMATETC *pOut);
STDMETHODIMP SetData(FORMATETC *pfetc, STGMEDIUM *pmedium, BOOL fRelease);
STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFEtc);
STDMETHODIMP DAdvise(FORMATETC *pfetc, DWORD ad, IAdviseSink *p, DWORD *pdw);
STDMETHODIMP DUnadvise(DWORD dwConnection);
STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise);
private:
wxDataObject *m_pDataObject; // pointer to C++ class we belong to
wxDataObject *m_pDataObject; // pointer to C++ class we belong to
};
// ============================================================================
@@ -144,70 +150,90 @@ wxString wxDataFormat::GetId() const
// ----------------------------------------------------------------------------
BEGIN_IID_TABLE(wxIEnumFORMATETC)
ADD_IID(Unknown)
ADD_IID(EnumFORMATETC)
ADD_IID(Unknown)
ADD_IID(EnumFORMATETC)
END_IID_TABLE;
IMPLEMENT_IUNKNOWN_METHODS(wxIEnumFORMATETC)
wxIEnumFORMATETC::wxIEnumFORMATETC(CLIPFORMAT cf)
wxIEnumFORMATETC::wxIEnumFORMATETC(const wxDataFormat *formats, ULONG nCount)
{
m_format.cfFormat = cf;
m_format.ptd = NULL;
m_format.dwAspect = DVASPECT_CONTENT;
m_format.lindex = -1;
m_format.tymed = TYMED_HGLOBAL;
m_cRef = 0;
m_nCurrent = 0;
m_cRef = 0;
m_nCurrent = 0;
m_nCount = nCount;
m_formats = new CLIPFORMAT[nCount];
for ( ULONG n = 0; n < nCount; n++ ) {
m_formats[n] = formats[n].GetFormatId();
}
}
STDMETHODIMP wxIEnumFORMATETC::Next(ULONG celt,
FORMATETC *rgelt,
ULONG *pceltFetched)
{
wxLogTrace(wxT("wxIEnumFORMATETC::Next"));
wxLogTrace(wxTRACE_OleCalls, wxT("wxIEnumFORMATETC::Next"));
if ( celt > 1 )
return S_FALSE;
if ( celt > 1 ) {
// we only return 1 element at a time - mainly because I'm too lazy to
// implement something which you're never asked for anyhow
return S_FALSE;
}
if ( m_nCurrent == 0 ) {
*rgelt = m_format;
m_nCurrent++;
if ( m_nCurrent < m_nCount ) {
FORMATETC format;
format.cfFormat = m_formats[m_nCurrent++];
format.ptd = NULL;
format.dwAspect = DVASPECT_CONTENT;
format.lindex = -1;
format.tymed = TYMED_HGLOBAL;
*rgelt = format;
return S_OK;
}
else
return S_FALSE;
return S_OK;
}
else {
// bad index
return S_FALSE;
}
}
STDMETHODIMP wxIEnumFORMATETC::Skip(ULONG celt)
{
wxLogTrace(wxT("wxIEnumFORMATETC::Skip"));
wxLogTrace(wxTRACE_OleCalls, wxT("wxIEnumFORMATETC::Skip"));
if ( m_nCurrent == 0 )
m_nCurrent++;
m_nCurrent += celt;
if ( m_nCurrent < m_nCount )
return S_OK;
return S_FALSE;
// no, can't skip this many elements
m_nCurrent -= celt;
return S_FALSE;
}
STDMETHODIMP wxIEnumFORMATETC::Reset()
{
wxLogTrace(wxT("wxIEnumFORMATETC::Reset"));
wxLogTrace(wxTRACE_OleCalls, wxT("wxIEnumFORMATETC::Reset"));
m_nCurrent = 0;
m_nCurrent = 0;
return S_OK;
return S_OK;
}
STDMETHODIMP wxIEnumFORMATETC::Clone(IEnumFORMATETC **ppenum)
{
wxLogTrace(wxT("wxIEnumFORMATETC::Clone"));
wxLogTrace(wxTRACE_OleCalls, wxT("wxIEnumFORMATETC::Clone"));
wxIEnumFORMATETC *pNew = new wxIEnumFORMATETC(m_format.cfFormat);
pNew->AddRef();
*ppenum = pNew;
// unfortunately, we can't reuse the code in ctor - types are different
wxIEnumFORMATETC *pNew = new wxIEnumFORMATETC(NULL, 0);
pNew->m_nCount = m_nCount;
pNew->m_formats = new CLIPFORMAT[m_nCount];
for ( ULONG n = 0; n < m_nCount; n++ ) {
pNew->m_formats[n] = m_formats[n];
}
pNew->AddRef();
*ppenum = pNew;
return S_OK;
return S_OK;
}
// ----------------------------------------------------------------------------
@@ -215,71 +241,118 @@ STDMETHODIMP wxIEnumFORMATETC::Clone(IEnumFORMATETC **ppenum)
// ----------------------------------------------------------------------------
BEGIN_IID_TABLE(wxIDataObject)
ADD_IID(Unknown)
ADD_IID(DataObject)
ADD_IID(Unknown)
ADD_IID(DataObject)
END_IID_TABLE;
IMPLEMENT_IUNKNOWN_METHODS(wxIDataObject)
wxIDataObject::wxIDataObject(wxDataObject *pDataObject)
{
m_cRef = 0;
m_pDataObject = pDataObject;
m_cRef = 0;
m_pDataObject = pDataObject;
}
// get data functions
STDMETHODIMP wxIDataObject::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
{
wxLogTrace(wxT("wxIDataObject::GetData"));
wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::GetData"));
// is data is in our format?
HRESULT hr = QueryGetData(pformatetcIn);
if ( FAILED(hr) )
return hr;
// is data is in our format?
HRESULT hr = QueryGetData(pformatetcIn);
if ( FAILED(hr) )
return hr;
// alloc memory
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
m_pDataObject->GetDataSize());
if ( hGlobal == NULL ) {
wxLogLastError("GlobalAlloc");
return E_OUTOFMEMORY;
}
// for the bitmaps and metafiles we use the handles instead of global memory
// to pass the data
wxDataFormat format = (wxDataFormatId)pformatetcIn->cfFormat;
// copy data
pmedium->tymed = TYMED_HGLOBAL;
pmedium->hGlobal = hGlobal;
pmedium->pUnkForRelease = NULL;
switch ( format )
{
case wxDF_BITMAP:
pmedium->tymed = TYMED_GDI;
break;
hr = GetDataHere(pformatetcIn, pmedium);
if ( FAILED(hr) ) {
GlobalFree(hGlobal);
return hr;
}
case wxDF_METAFILE:
pmedium->tymed = TYMED_MFPICT;
break;
return S_OK;
default:
// alloc memory
size_t size = m_pDataObject->GetDataSize(format);
if ( !size ) {
// it probably means that the method is just not implemented
wxLogDebug(wxT("Invalid data size - can't be 0"));
return DV_E_FORMATETC;
}
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, size);
if ( hGlobal == NULL ) {
wxLogLastError("GlobalAlloc");
return E_OUTOFMEMORY;
}
// copy data
pmedium->tymed = TYMED_HGLOBAL;
pmedium->hGlobal = hGlobal;
}
pmedium->pUnkForRelease = NULL;
// do copy the data
hr = GetDataHere(pformatetcIn, pmedium);
if ( FAILED(hr) ) {
// free resources we allocated
if ( pmedium->tymed == TYMED_HGLOBAL ) {
GlobalFree(pmedium->hGlobal);
}
return hr;
}
return S_OK;
}
STDMETHODIMP wxIDataObject::GetDataHere(FORMATETC *pformatetc,
STGMEDIUM *pmedium)
{
wxLogTrace(wxT("wxIDataObject::GetDataHere"));
wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::GetDataHere"));
// put data in caller provided medium
if ( pmedium->tymed != TYMED_HGLOBAL )
return DV_E_TYMED;
// put data in caller provided medium
switch ( pmedium->tymed )
{
case TYMED_GDI:
m_pDataObject->GetDataHere(wxDF_BITMAP, &pmedium->hBitmap);
break;
// copy data
void *pBuf = GlobalLock(pmedium->hGlobal);
if ( pBuf == NULL ) {
wxLogLastError(wxT("GlobalLock"));
return E_OUTOFMEMORY;
}
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;
m_pDataObject->GetDataHere(pBuf);
case TYMED_HGLOBAL:
{
// copy data
void *pBuf = GlobalLock(pmedium->hGlobal);
if ( pBuf == NULL ) {
wxLogLastError(wxT("GlobalLock"));
return E_OUTOFMEMORY;
}
GlobalUnlock(pmedium->hGlobal);
wxDataFormat format = (wxDataFormatId)pformatetc->cfFormat;
m_pDataObject->GetDataHere(format, pBuf);
return S_OK;
GlobalUnlock(pmedium->hGlobal);
}
break;
default:
return DV_E_TYMED;
}
return S_OK;
}
// set data functions (not implemented)
@@ -287,7 +360,8 @@ STDMETHODIMP wxIDataObject::SetData(FORMATETC *pformatetc,
STGMEDIUM *pmedium,
BOOL fRelease)
{
wxLogTrace(wxT("wxIDataObject::SetData"));
wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::SetData"));
return E_NOTIMPL;
}
@@ -296,39 +370,53 @@ STDMETHODIMP wxIDataObject::QueryGetData(FORMATETC *pformatetc)
{
// do we accept data in this format?
if ( pformatetc == NULL ) {
wxLogTrace(wxT("wxIDataObject::QueryGetData: invalid ptr."));
wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::QueryGetData: invalid ptr."));
return E_INVALIDARG;
}
// the only one allowed by current COM implementation
if ( pformatetc->lindex != -1 ) {
wxLogTrace(wxT("wxIDataObject::QueryGetData: bad lindex %d"),
wxLogTrace(wxTRACE_OleCalls,
wxT("wxIDataObject::QueryGetData: bad lindex %d"),
pformatetc->lindex);
return DV_E_LINDEX;
}
// we don't support anything other (THUMBNAIL, ICON, DOCPRINT...)
if ( pformatetc->dwAspect != DVASPECT_CONTENT ) {
wxLogTrace(wxT("wxIDataObject::QueryGetData: bad dwAspect %d"),
wxLogTrace(wxTRACE_OleCalls,
wxT("wxIDataObject::QueryGetData: bad dwAspect %d"),
pformatetc->dwAspect);
return DV_E_DVASPECT;
}
// @@ we only transfer data by global memory (bad for large amounts of it!)
if ( !(pformatetc->tymed & TYMED_HGLOBAL) ) {
wxLogTrace(wxT("wxIDataObject::QueryGetData: %s != TYMED_HGLOBAL."),
GetTymedName(pformatetc->tymed));
// 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
#ifdef __WXDEBUG__
wxLogTrace(wxTRACE_OleCalls,
wxT("wxIDataObject::QueryGetData: %s & %s == 0."),
GetTymedName(tymed),
GetTymedName(format == wxDF_BITMAP ? TYMED_GDI : TYMED_HGLOBAL));
#endif // Debug
return DV_E_TYMED;
}
// and now check the type of data requested
if ( m_pDataObject->IsSupportedFormat((wxDataFormatId)pformatetc->cfFormat) ) {
wxLogTrace(wxT("wxIDataObject::QueryGetData: %s ok"),
wxDataObject::GetFormatName((wxDataFormatId)pformatetc->cfFormat));
if ( m_pDataObject->IsSupportedFormat(format) ) {
#ifdef __WXDEBUG__
wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::QueryGetData: %s ok"),
wxDataObject::GetFormatName(format));
#endif // Debug
return S_OK;
}
else {
wxLogTrace(wxT("wxIDataObject::QueryGetData: %s unsupported"),
wxLogTrace(wxTRACE_OleCalls,
wxT("wxIDataObject::QueryGetData: %s unsupported"),
wxDataObject::GetFormatName((wxDataFormatId)pformatetc->cfFormat));
return DV_E_FORMATETC;
}
@@ -337,30 +425,47 @@ STDMETHODIMP wxIDataObject::QueryGetData(FORMATETC *pformatetc)
STDMETHODIMP wxIDataObject::GetCanonicalFormatEtc(FORMATETC *pFormatetcIn,
FORMATETC *pFormatetcOut)
{
wxLogTrace(wxT("wxIDataObject::GetCanonicalFormatEtc"));
wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::GetCanonicalFormatEtc"));
// @@ implementation is trivial, we might want something better here
if ( pFormatetcOut != NULL )
pFormatetcOut->ptd = NULL;
return DATA_S_SAMEFORMATETC;
// TODO we might want something better than this trivial implementation here
if ( pFormatetcOut != NULL )
pFormatetcOut->ptd = NULL;
return DATA_S_SAMEFORMATETC;
}
STDMETHODIMP wxIDataObject::EnumFormatEtc(DWORD dwDirection,
IEnumFORMATETC **ppenumFormatEtc)
{
wxLogTrace(wxT("wxIDataObject::EnumFormatEtc"));
wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::EnumFormatEtc"));
if ( dwDirection == DATADIR_SET ) {
// we don't allow setting of data anyhow
return E_NOTIMPL;
}
if ( dwDirection == DATADIR_SET ) {
// we don't allow setting of data anyhow
return E_NOTIMPL;
}
wxIEnumFORMATETC *pEnum =
new wxIEnumFORMATETC(m_pDataObject->GetPreferredFormat());
pEnum->AddRef();
*ppenumFormatEtc = pEnum;
size_t nFormatCount = m_pDataObject->GetFormatCount();
wxDataFormat format, *formats;
if ( nFormatCount == 1 ) {
// this is the most common case, this is why we consider it separately
formats = &format;
format = m_pDataObject->GetPreferredFormat();
}
else {
// bad luck, build the array with all formats
formats = new wxDataFormat[nFormatCount];
m_pDataObject->GetAllFormats(formats);
}
return S_OK;
wxIEnumFORMATETC *pEnum = new wxIEnumFORMATETC(formats, nFormatCount);
pEnum->AddRef();
*ppenumFormatEtc = pEnum;
if ( formats != &format ) {
delete [] formats;
}
return S_OK;
}
// advise sink functions (not implemented)
@@ -397,9 +502,32 @@ wxDataObject::~wxDataObject()
m_pIDataObject->Release();
}
bool wxDataObject::IsSupportedFormat(const wxDataFormat& format) const
{
size_t nFormatCount = GetFormatCount();
if ( nFormatCount == 1 ) {
return format == GetPreferredFormat();
}
else {
wxDataFormat *formats = new wxDataFormat[nFormatCount];
GetAllFormats(formats);
size_t n;
for ( n = 0; n < nFormatCount; n++ ) {
if ( formats[n] == format )
break;
}
delete [] formats;
// found?
return n < nFormatCount;
}
}
#ifdef __WXDEBUG__
const char *wxDataObject::GetFormatName(wxDataFormat format)
{
#ifdef __WXDEBUG__
// case 'xxx' is not a valid value for switch of enum 'wxDataFormat'
#ifdef __VISUALC__
#pragma warning(disable:4063)
@@ -431,11 +559,8 @@ const char *wxDataObject::GetFormatName(wxDataFormat format)
#ifdef __VISUALC__
#pragma warning(default:4063)
#endif // VC++
#else // !Debug
return "";
#endif // Debug
}
#endif // Debug
// ----------------------------------------------------------------------------
// wxPrivateDataObject
@@ -478,9 +603,34 @@ void wxPrivateDataObject::WriteData( const void *data, void *dest ) const
memcpy( dest, data, GetSize() );
}
// ----------------------------------------------------------------------------
// wxBitmapDataObject
// ----------------------------------------------------------------------------
// 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
// don't make much sense to them.
size_t wxBitmapDataObject::GetDataSize(const wxDataFormat& format) const
{
// no data to copy anyhow
return 0;
}
void wxBitmapDataObject::GetDataHere(const wxDataFormat& format,
void *pBuf) const
{
// we put a bitmap handle into pBuf
*(WXHBITMAP *)pBuf = m_bitmap.GetHBITMAP();
}
// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------
#ifdef __WXDEBUG__
static const char *GetTymedName(DWORD tymed)
{
static char s_szBuf[128];
@@ -498,7 +648,7 @@ static const char *GetTymedName(DWORD tymed)
}
}
// TODO: OLE parts of wxBitmap/File/MetafileDataObject
#endif // Debug
#endif

View File

@@ -160,13 +160,18 @@ void wxDropSource::Init()
m_pIDropSource->AddRef();
}
wxDropSource::wxDropSource(wxWindow* WXUNUSED(win))
wxDropSource::wxDropSource(wxWindow* WXUNUSED(win),
const wxIcon & WXUNUSED(go),
const wxIcon & WXUNUSED(stop))
{
Init();
m_pData = NULL;
}
wxDropSource::wxDropSource(wxDataObject& data, wxWindow* WXUNUSED(win))
wxDropSource::wxDropSource(wxDataObject& data,
wxWindow* WXUNUSED(win),
const wxIcon & WXUNUSED(go),
const wxIcon & WXUNUSED(stop))
{
Init();
SetData(data);