]> git.saurik.com Git - wxWidgets.git/commitdiff
1. more drag and drop and clipboard changes:
authorVadim Zeitlin <vadim@wxwidgets.org>
Mon, 18 Oct 1999 00:08:40 +0000 (00:08 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Mon, 18 Oct 1999 00:08:40 +0000 (00:08 +0000)
 a) OLE clipboard works fine
 b) wxBitmapDataObject now accepts DIBs (but doesn't give them back :-( )
 c) bugs in sample corrected
2. wxFatalExit() replaced with wxFAIL_MSG() in bitmap.cpp and dcmemory.cpp
3. wxFrame::ClientToScreen and ScreenToClient() replaced with DoXXX() - like
   this, they don't hide the base class versions

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@4039 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/msw/clipbrd.h
include/wx/msw/frame.h
include/wx/msw/ole/dataobj.h
samples/dnd/dnd.cpp
src/msw/bitmap.cpp
src/msw/clipbrd.cpp
src/msw/dcmemory.cpp
src/msw/frame.cpp
src/msw/ole/dataobj.cpp

index c1afb26016c9958d961f38213bef5fb2e84fc307..a7d010e60d14643fdef172b1002720789d5907bb 100644 (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
index 722f4bf695e51dfa7ab20bb4058f98bc95bfb9d6..e2854723527d49bf469a482df4e759a571a8b354 100644 (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();
index ea49caaa041b1fcd489efe1100ceaa1e0b12eb8d..ab800e3e074e541fbaeaa4422011a64e5d3cb159 100644 (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;
index 5bfcff4ecceca7de5a16512e3e1d552792eae635..6bd041c9243219db753754a6f8c843bb11e4df9d 100644 (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 );
-}
-
-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))
@@ -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);
 
index 101db25b5879c278c432c52fd56fe2091d34ebe6..9498c65e43f4877c6138649e9472cc060aec96d0 100644 (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);
index cd94dce908685bbdf0357e581de4515b5fd63f0c..f31924940b5b95ea3d235c00f7876976c4dc9e70 100644 (file)
 #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
 }
 
 //-----------------------------------------------------------------------------
index c8ce5662de76cc7875129eae3699c270808d2275..78fa04fea3fe3d71496dac17795c84ccaeacb517 100644 (file)
 // 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;
+    }
 }
 
index ffa5812de36377f270cca3439f6c149ae6c2837a..aded67d34f85bf74e7239b622d4fedfd4004a485 100644 (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
index f1eab4707cf21e5b143d7f6fe89afa2dabbdbbab..a4209d8a43334f3c41f32fdc12b6983f85222d70 100644 (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 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