1/////////////////////////////////////////////////////////////////////////////// 2// Name: src/gtk1/dataobj.cpp 3// Purpose: wxDataObject class 4// Author: Robert Roebling 5// Id: $Id: dataobj.cpp 39957 2006-07-03 19:02:54Z ABX $ 6// Copyright: (c) 1998 Robert Roebling 7// Licence: wxWindows licence 8/////////////////////////////////////////////////////////////////////////////// 9 10// For compilers that support precompilation, includes "wx.h". 11#include "wx/wxprec.h" 12 13#if wxUSE_DATAOBJ 14 15#include "wx/dataobj.h" 16 17#ifndef WX_PRECOMP 18 #include "wx/log.h" 19 #include "wx/app.h" 20 #include "wx/image.h" 21#endif 22 23#include "wx/mstream.h" 24#include "wx/uri.h" 25 26#include <gdk/gdk.h> 27 28//------------------------------------------------------------------------- 29// global data 30//------------------------------------------------------------------------- 31 32GdkAtom g_textAtom = 0; 33GdkAtom g_altTextAtom = 0; 34GdkAtom g_pngAtom = 0; 35GdkAtom g_fileAtom = 0; 36 37//------------------------------------------------------------------------- 38// wxDataFormat 39//------------------------------------------------------------------------- 40 41wxDataFormat::wxDataFormat() 42{ 43 // do *not* call PrepareFormats() from here for 2 reasons: 44 // 45 // 1. we will have time to do it later because some other Set function 46 // must be called before we really need them 47 // 48 // 2. doing so prevents us from declaring global wxDataFormats because 49 // calling PrepareFormats (and thus gdk_atom_intern) before GDK is 50 // initialised will result in a crash 51 m_type = wxDF_INVALID; 52 m_format = (GdkAtom) 0; 53} 54 55wxDataFormat::wxDataFormat( wxDataFormatId type ) 56{ 57 PrepareFormats(); 58 SetType( type ); 59} 60 61wxDataFormat::wxDataFormat( const wxChar *id ) 62{ 63 PrepareFormats(); 64 SetId( id ); 65} 66 67wxDataFormat::wxDataFormat( const wxString &id ) 68{ 69 PrepareFormats(); 70 SetId( id ); 71} 72 73wxDataFormat::wxDataFormat( NativeFormat format ) 74{ 75 PrepareFormats(); 76 SetId( format ); 77} 78 79void wxDataFormat::SetType( wxDataFormatId type ) 80{ 81 PrepareFormats(); 82 83 m_type = type; 84 85#if wxUSE_UNICODE 86 if (m_type == wxDF_UNICODETEXT) 87 m_format = g_textAtom; 88 else if (m_type == wxDF_TEXT) 89 m_format = g_altTextAtom; 90#else 91 if (m_type == wxDF_TEXT || m_type == wxDF_UNICODETEXT) 92 m_format = g_textAtom; 93#endif 94 else 95 if (m_type == wxDF_BITMAP) 96 m_format = g_pngAtom; 97 else 98 if (m_type == wxDF_FILENAME) 99 m_format = g_fileAtom; 100 else 101 { 102 wxFAIL_MSG( wxT("invalid dataformat") ); 103 } 104} 105 106wxDataFormatId wxDataFormat::GetType() const 107{ 108 return m_type; 109} 110 111wxString wxDataFormat::GetId() const 112{ 113 gchar* atom_name = gdk_atom_name( m_format ); 114 wxString ret = wxString::FromAscii( atom_name ); 115 g_free(atom_name); 116 return ret; 117} 118 119void wxDataFormat::SetId( NativeFormat format ) 120{ 121 PrepareFormats(); 122 m_format = format; 123 124 if (m_format == g_textAtom) 125#if wxUSE_UNICODE 126 m_type = wxDF_UNICODETEXT; 127#else 128 m_type = wxDF_TEXT; 129#endif 130 else 131 if (m_format == g_altTextAtom) 132 m_type = wxDF_TEXT; 133 else 134 if (m_format == g_pngAtom) 135 m_type = wxDF_BITMAP; 136 else 137 if (m_format == g_fileAtom) 138 m_type = wxDF_FILENAME; 139 else 140 m_type = wxDF_PRIVATE; 141} 142 143void wxDataFormat::SetId( const wxChar *id ) 144{ 145 PrepareFormats(); 146 m_type = wxDF_PRIVATE; 147 wxString tmp( id ); 148 m_format = gdk_atom_intern( (const char*) tmp.ToAscii(), FALSE ); 149} 150 151void wxDataFormat::PrepareFormats() 152{ 153 // VZ: GNOME included in RedHat 6.1 uses the MIME types below and not the 154 // atoms STRING and file:ALL as the old code was, but normal X apps 155 // use STRING for text selection when transfering the data via 156 // clipboard, for example, so do use STRING for now (GNOME apps will 157 // probably support STRING as well for compatibility anyhow), but use 158 // text/uri-list for file dnd because compatibility is not important 159 // here (with whom?) 160 if (!g_textAtom) 161#if wxUSE_UNICODE 162 g_textAtom = gdk_atom_intern( "UTF8_STRING", FALSE ); 163 g_altTextAtom = gdk_atom_intern( "STRING", FALSE ); 164#else 165 g_textAtom = gdk_atom_intern( "STRING" /* "text/plain" */, FALSE ); 166#endif 167 if (!g_pngAtom) 168 g_pngAtom = gdk_atom_intern( "image/png", FALSE ); 169 if (!g_fileAtom) 170 g_fileAtom = gdk_atom_intern( "text/uri-list", FALSE ); 171} 172 173//------------------------------------------------------------------------- 174// wxDataObject 175//------------------------------------------------------------------------- 176 177wxDataObject::wxDataObject() 178{ 179} 180 181wxDataObject::~wxDataObject() 182{ 183 // dtor is empty but needed for Darwin and AIX -- otherwise it doesn't link 184} 185 186bool wxDataObject::IsSupportedFormat(const wxDataFormat& format, Direction dir) const 187{ 188 size_t nFormatCount = GetFormatCount(dir); 189 if ( nFormatCount == 1 ) 190 { 191 return format == GetPreferredFormat(); 192 } 193 else 194 { 195 wxDataFormat *formats = new wxDataFormat[nFormatCount]; 196 GetAllFormats(formats,dir); 197 198 size_t n; 199 for ( n = 0; n < nFormatCount; n++ ) 200 { 201 if ( formats[n] == format ) 202 break; 203 } 204 205 delete [] formats; 206 207 // found? 208 return n < nFormatCount; 209 } 210} 211 212// ---------------------------------------------------------------------------- 213// wxFileDataObject 214// ---------------------------------------------------------------------------- 215 216bool wxFileDataObject::GetDataHere(void *buf) const 217{ 218 wxString filenames; 219 220 for (size_t i = 0; i < m_filenames.GetCount(); i++) 221 { 222 filenames += wxT("file:"); 223 filenames += m_filenames[i]; 224 filenames += wxT("\r\n"); 225 } 226 227 memcpy( buf, filenames.mbc_str(), filenames.length() + 1 ); 228 229 return true; 230} 231 232size_t wxFileDataObject::GetDataSize() const 233{ 234 size_t res = 0; 235 236 for (size_t i = 0; i < m_filenames.GetCount(); i++) 237 { 238 // This is junk in UTF-8 239 res += m_filenames[i].length(); 240 res += 5 + 2; // "file:" (5) + "\r\n" (2) 241 } 242 243 return res + 1; 244} 245 246bool wxFileDataObject::SetData(size_t WXUNUSED(size), const void *buf) 247{ 248 m_filenames.Empty(); 249 250 // we get data in the text/uri-list format, i.e. as a sequence of URIs 251 // (filenames prefixed by "file:") delimited by "\r\n" 252 wxString filename; 253 for ( const char *p = (const char *)buf; ; p++ ) 254 { 255 // some broken programs (testdnd GTK+ sample!) omit the trailing 256 // "\r\n", so check for '\0' explicitly here instead of doing it in 257 // the loop statement to account for it 258 if ( (*p == '\r' && *(p+1) == '\n') || !*p ) 259 { 260 size_t lenPrefix = 5; // strlen("file:") 261 if ( filename.Left(lenPrefix).MakeLower() == _T("file:") ) 262 { 263 // sometimes the syntax is "file:filename", sometimes it's 264 // URL-like: "file://filename" - deal with both 265 if ( filename[lenPrefix] == _T('/') && 266 filename[lenPrefix + 1] == _T('/') ) 267 { 268 // skip the slashes 269 lenPrefix += 2; 270 } 271 272 AddFile(wxURI::Unescape(filename.c_str() + lenPrefix)); 273 filename.Empty(); 274 } 275 else 276 { 277 wxLogDebug(_T("Unsupported URI '%s' in wxFileDataObject"), 278 filename.c_str()); 279 } 280 281 if ( !*p ) 282 break; 283 284 // skip '\r' 285 p++; 286 } 287 else 288 { 289 filename += *p; 290 } 291 } 292 293 return true; 294} 295 296void wxFileDataObject::AddFile( const wxString &filename ) 297{ 298 m_filenames.Add( filename ); 299} 300 301// ---------------------------------------------------------------------------- 302// wxBitmapDataObject 303// ---------------------------------------------------------------------------- 304 305wxBitmapDataObject::wxBitmapDataObject() 306{ 307 Init(); 308} 309 310wxBitmapDataObject::wxBitmapDataObject( const wxBitmap& bitmap ) 311 : wxBitmapDataObjectBase(bitmap) 312{ 313 Init(); 314 315 DoConvertToPng(); 316} 317 318wxBitmapDataObject::~wxBitmapDataObject() 319{ 320 Clear(); 321} 322 323void wxBitmapDataObject::SetBitmap( const wxBitmap &bitmap ) 324{ 325 ClearAll(); 326 327 wxBitmapDataObjectBase::SetBitmap(bitmap); 328 329 DoConvertToPng(); 330} 331 332bool wxBitmapDataObject::GetDataHere(void *buf) const 333{ 334 if ( !m_pngSize ) 335 { 336 wxFAIL_MSG( wxT("attempt to copy empty bitmap failed") ); 337 338 return false; 339 } 340 341 memcpy(buf, m_pngData, m_pngSize); 342 343 return true; 344} 345 346bool wxBitmapDataObject::SetData(size_t size, const void *buf) 347{ 348 Clear(); 349 350 wxCHECK_MSG( wxImage::FindHandler(wxBITMAP_TYPE_PNG) != NULL, 351 false, wxT("You must call wxImage::AddHandler(new wxPNGHandler); to be able to use clipboard with bitmaps!") ); 352 353 m_pngSize = size; 354 m_pngData = malloc(m_pngSize); 355 356 memcpy(m_pngData, buf, m_pngSize); 357 358 wxMemoryInputStream mstream((char*) m_pngData, m_pngSize); 359 wxImage image; 360 if ( !image.LoadFile( mstream, wxBITMAP_TYPE_PNG ) ) 361 { 362 return false; 363 } 364 365 m_bitmap = wxBitmap(image); 366 367 return m_bitmap.Ok(); 368} 369 370void wxBitmapDataObject::DoConvertToPng() 371{ 372 if ( !m_bitmap.Ok() ) 373 return; 374 375 wxCHECK_RET( wxImage::FindHandler(wxBITMAP_TYPE_PNG) != NULL, 376 wxT("You must call wxImage::AddHandler(new wxPNGHandler); to be able to use clipboard with bitmaps!") ); 377 378 wxImage image = m_bitmap.ConvertToImage(); 379 380 wxCountingOutputStream count; 381 image.SaveFile(count, wxBITMAP_TYPE_PNG); 382 383 m_pngSize = count.GetSize() + 100; // sometimes the size seems to vary ??? 384 m_pngData = malloc(m_pngSize); 385 386 wxMemoryOutputStream mstream((char*) m_pngData, m_pngSize); 387 image.SaveFile(mstream, wxBITMAP_TYPE_PNG); 388} 389 390#endif // wxUSE_DATAOBJ 391