1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 #ifndef _DTRANS_X11_SELECTION_HXX_ 25 #define _DTRANS_X11_SELECTION_HXX_ 26 27 #include <cppuhelper/compbase3.hxx> 28 #include <cppuhelper/compbase4.hxx> 29 #include <com/sun/star/datatransfer/XTransferable.hpp> 30 #include <com/sun/star/datatransfer/dnd/XDropTarget.hpp> 31 #include <com/sun/star/datatransfer/dnd/XDragSource.hpp> 32 #include <com/sun/star/awt/XDisplayConnection.hpp> 33 #include <com/sun/star/lang/XInitialization.hpp> 34 #include <com/sun/star/lang/XServiceInfo.hpp> 35 #include <com/sun/star/script/XInvocation.hpp> 36 #include <com/sun/star/frame/XDesktop.hpp> 37 #include <osl/thread.h> 38 39 #ifndef _OSL_CONDITION_HXX_ 40 #include <osl/conditn.hxx> 41 #endif 42 43 #include <hash_map> 44 #include <list> 45 46 #include "tools/prex.h" 47 #include <X11/Xlib.h> 48 #include "tools/postx.h" 49 50 #define XDND_IMPLEMENTATION_NAME "com.sun.star.datatransfer.dnd.XdndSupport" 51 #define XDND_DROPTARGET_IMPLEMENTATION_NAME "com.sun.star.datatransfer.dnd.XdndDropTarget" 52 53 using namespace ::com::sun::star::uno; 54 55 namespace x11 { 56 57 class PixmapHolder; // in bmp.hxx 58 59 // ------------------------------------------------------------------------ 60 rtl_TextEncoding getTextPlainEncoding( const ::rtl::OUString& rMimeType ); 61 62 class SelectionAdaptor 63 { 64 public: 65 virtual com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > getTransferable() = 0; 66 virtual void clearTransferable() = 0; 67 virtual void fireContentsChanged() = 0; 68 virtual com::sun::star::uno::Reference< XInterface > getReference() = 0; 69 // returns a reference that will keep the SelectionAdaptor alive until the 70 // reference is released 71 }; 72 73 class DropTarget : 74 public ::cppu::WeakComponentImplHelper3< 75 ::com::sun::star::datatransfer::dnd::XDropTarget, 76 ::com::sun::star::lang::XInitialization, 77 ::com::sun::star::lang::XServiceInfo 78 > 79 { 80 public: 81 ::osl::Mutex m_aMutex; 82 bool m_bActive; 83 sal_Int8 m_nDefaultActions; 84 XLIB_Window m_aTargetWindow; 85 class SelectionManager* m_pSelectionManager; 86 com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSource > 87 m_xSelectionManager; 88 ::std::list< com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetListener > > 89 m_aListeners; 90 91 DropTarget(); 92 virtual ~DropTarget(); 93 94 // convenience functions that loop over listeners 95 void dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& dtde ) throw(); 96 void dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& dte ) throw(); 97 void dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& dtde ) throw(); 98 void drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& dtde ) throw(); 99 100 // XInitialization 101 virtual void SAL_CALL initialize( const Sequence< Any >& args ) throw ( ::com::sun::star::uno::Exception ); 102 103 // XDropTarget 104 virtual void SAL_CALL addDropTargetListener( const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetListener >& ) throw(); 105 virtual void SAL_CALL removeDropTargetListener( const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDropTargetListener >& ) throw(); 106 virtual sal_Bool SAL_CALL isActive() throw(); 107 virtual void SAL_CALL setActive( sal_Bool active ) throw(); 108 virtual sal_Int8 SAL_CALL getDefaultActions() throw(); 109 virtual void SAL_CALL setDefaultActions( sal_Int8 actions ) throw(); 110 111 // XServiceInfo 112 virtual ::rtl::OUString SAL_CALL getImplementationName() throw(); 113 virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw(); 114 virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > 115 SAL_CALL getSupportedServiceNames() throw(); 116 }; 117 118 class SelectionManagerHolder : 119 public ::cppu::WeakComponentImplHelper3< 120 ::com::sun::star::datatransfer::dnd::XDragSource, 121 ::com::sun::star::lang::XInitialization, 122 ::com::sun::star::lang::XServiceInfo 123 > 124 { 125 ::osl::Mutex m_aMutex; 126 com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSource > 127 m_xRealDragSource; 128 public: 129 SelectionManagerHolder(); 130 virtual ~SelectionManagerHolder(); 131 132 // XServiceInfo 133 virtual ::rtl::OUString SAL_CALL getImplementationName() throw(); 134 virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw(); 135 virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > 136 SAL_CALL getSupportedServiceNames() throw(); 137 138 // XInitialization 139 virtual void SAL_CALL initialize( const Sequence< Any >& arguments ) throw( ::com::sun::star::uno::Exception ); 140 141 // XDragSource 142 virtual sal_Bool SAL_CALL isDragImageSupported() throw(); 143 virtual sal_Int32 SAL_CALL getDefaultCursor( sal_Int8 dragAction ) throw(); 144 virtual void SAL_CALL startDrag( 145 const ::com::sun::star::datatransfer::dnd::DragGestureEvent& trigger, 146 sal_Int8 sourceActions, sal_Int32 cursor, sal_Int32 image, 147 const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& transferable, 148 const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener >& listener 149 ) throw(); 150 151 }; 152 153 154 class SelectionManager : 155 public ::cppu::WeakImplHelper4< 156 ::com::sun::star::datatransfer::dnd::XDragSource, 157 ::com::sun::star::lang::XInitialization, 158 ::com::sun::star::awt::XEventHandler, 159 ::com::sun::star::frame::XTerminateListener 160 >, 161 public SelectionAdaptor 162 { 163 static ::std::hash_map< ::rtl::OUString, SelectionManager*, ::rtl::OUStringHash >& getInstances(); 164 165 // for INCR type selection transfer 166 // INCR protocol is used if the data cannot 167 // be transported at once but in parts 168 // IncrementalTransfer holds the bytes to be transmitted 169 // as well a the current position 170 // INCR triggers the delivery of the next part by deleting the 171 // property used to transfer the data 172 struct IncrementalTransfer 173 { 174 Sequence< sal_Int8 > m_aData; 175 int m_nBufferPos; 176 XLIB_Window m_aRequestor; 177 Atom m_aProperty; 178 Atom m_aTarget; 179 int m_nFormat; 180 int m_nTransferStartTime; 181 }; 182 int m_nIncrementalThreshold; 183 184 // a struct to hold the data associated with a selection 185 struct Selection 186 { 187 enum State 188 { 189 Inactive, WaitingForResponse, WaitingForData, IncrementalTransfer 190 }; 191 192 State m_eState; 193 SelectionAdaptor* m_pAdaptor; 194 Atom m_aAtom; 195 ::osl::Condition m_aDataArrived; 196 Sequence< sal_Int8 > m_aData; 197 Sequence< ::com::sun::star::datatransfer::DataFlavor > 198 m_aTypes; 199 std::vector< Atom > m_aNativeTypes; 200 // this is used for caching 201 // m_aTypes is invalid after 2 seconds 202 // m_aNativeTypes contains the corresponding original atom 203 Atom m_aRequestedType; 204 // m_aRequestedType is only valid while WaitingForResponse and WaitingFotData 205 int m_nLastTimestamp; 206 bool m_bHaveUTF16; 207 Atom m_aUTF8Type; 208 bool m_bHaveCompound; 209 bool m_bOwner; 210 XLIB_Window m_aLastOwner; 211 PixmapHolder* m_pPixmap; 212 // m_nOrigXLIB_Timestamp contains the XLIB_Timestamp at which the seclection 213 // was acquired; needed for XLIB_TimeSTAMP target 214 XLIB_Time m_nOrigTimestamp; 215 Selectionx11::SelectionManager::Selection216 Selection() : m_eState( Inactive ), 217 m_pAdaptor( NULL ), 218 m_aAtom( None ), 219 m_aRequestedType( None ), 220 m_nLastTimestamp( 0 ), 221 m_bHaveUTF16( false ), 222 m_aUTF8Type( None ), 223 m_bHaveCompound( false ), 224 m_bOwner( false ), 225 m_aLastOwner( None ), 226 m_pPixmap( NULL ), 227 m_nOrigTimestamp( CurrentTime ) 228 {} 229 }; 230 231 // a struct to hold data associated with a XDropTarget 232 struct DropTargetEntry 233 { 234 DropTarget* m_pTarget; 235 XLIB_Window m_aRootWindow; 236 DropTargetEntryx11::SelectionManager::DropTargetEntry237 DropTargetEntry() : m_pTarget( NULL ), m_aRootWindow( None ) {} DropTargetEntryx11::SelectionManager::DropTargetEntry238 DropTargetEntry( DropTarget* pTarget ) : 239 m_pTarget( pTarget ), 240 m_aRootWindow( None ) 241 {} DropTargetEntryx11::SelectionManager::DropTargetEntry242 DropTargetEntry( const DropTargetEntry& rEntry ) : 243 m_pTarget( rEntry.m_pTarget ), 244 m_aRootWindow( rEntry.m_aRootWindow ) 245 {} ~DropTargetEntryx11::SelectionManager::DropTargetEntry246 ~DropTargetEntry() {} 247 operator ->x11::SelectionManager::DropTargetEntry248 DropTarget* operator->() const { return m_pTarget; } operator =x11::SelectionManager::DropTargetEntry249 DropTargetEntry& operator=(const DropTargetEntry& rEntry) 250 { m_pTarget = rEntry.m_pTarget; m_aRootWindow = rEntry.m_aRootWindow; return *this; } 251 }; 252 253 // internal data 254 Display* m_pDisplay; 255 oslThread m_aThread; 256 oslThread m_aDragExecuteThread; 257 ::osl::Condition m_aDragRunning; 258 XLIB_Window m_aWindow; 259 com::sun::star::uno::Reference< ::com::sun::star::awt::XDisplayConnection > 260 m_xDisplayConnection; 261 com::sun::star::uno::Reference< com::sun::star::script::XInvocation > 262 m_xBitmapConverter; 263 sal_Int32 m_nSelectionTimeout; 264 XLIB_Time m_nSelectionTimestamp; 265 266 267 // members used for Xdnd 268 269 // drop only 270 271 // contains the XdndEnterEvent of a drop action running 272 // with one of our targets. The data.l[0] member 273 // (conatining the drag source XLIB_Window) is set 274 // to None while that is not the case 275 XClientMessageEvent m_aDropEnterEvent; 276 // set to false on XdndEnter 277 // set to true on first XdndPosition or XdndLeave 278 bool m_bDropEnterSent; 279 XLIB_Window m_aCurrentDropWindow; 280 // XLIB_Time code of XdndDrop 281 XLIB_Time m_nDropTime; 282 sal_Int8 m_nLastDropAction; 283 // XTransferable for Xdnd with foreign drag source 284 com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > 285 m_xDropTransferable; 286 int m_nLastX, m_nLastY; 287 XLIB_Time m_nDropTimestamp; 288 // set to true when calling drop() 289 // if another XdndEnter is received this shows that 290 // someone forgot to call dropComplete - we should reset 291 // and react to the new drop 292 bool m_bDropWaitingForCompletion; 293 294 // drag only 295 296 // None if no Dnd action is running with us as source 297 XLIB_Window m_aDropWindow; 298 // either m_aDropXLIB_Window or its XdndProxy 299 XLIB_Window m_aDropProxy; 300 XLIB_Window m_aDragSourceWindow; 301 // XTransferable for Xdnd when we are drag source 302 com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > 303 m_xDragSourceTransferable; 304 com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener > 305 m_xDragSourceListener; 306 // root coordinates 307 int m_nLastDragX, m_nLastDragY; 308 Sequence< ::com::sun::star::datatransfer::DataFlavor > 309 m_aDragFlavors; 310 // the rectangle the pointer must leave until a new XdndPosition should 311 // be sent. empty unless the drop target told to fill 312 int m_nNoPosX, m_nNoPosY, m_nNoPosWidth, m_nNoPosHeight; 313 unsigned int m_nDragButton; 314 sal_Int8 m_nUserDragAction; 315 sal_Int8 m_nTargetAcceptAction; 316 sal_Int8 m_nSourceActions; 317 bool m_bLastDropAccepted; 318 bool m_bDropSuccess; 319 bool m_bDropSent; 320 time_t m_nDropTimeout; 321 bool m_bWaitingForPrimaryConversion; 322 XLIB_Time m_nDragTimestamp; 323 324 // drag cursors 325 XLIB_Cursor m_aMoveCursor; 326 XLIB_Cursor m_aCopyCursor; 327 XLIB_Cursor m_aLinkCursor; 328 XLIB_Cursor m_aNoneCursor; 329 XLIB_Cursor m_aCurrentCursor; 330 331 332 // drag and drop 333 334 int m_nCurrentProtocolVersion; 335 ::std::hash_map< XLIB_Window, DropTargetEntry > 336 m_aDropTargets; 337 338 339 // some special atoms that are needed often 340 Atom m_nCLIPBOARDAtom; 341 Atom m_nTARGETSAtom; 342 Atom m_nTIMESTAMPAtom; 343 Atom m_nTEXTAtom; 344 Atom m_nINCRAtom; 345 Atom m_nCOMPOUNDAtom; 346 Atom m_nMULTIPLEAtom; 347 Atom m_nUTF16Atom; 348 Atom m_nImageBmpAtom; 349 Atom m_nXdndAware; 350 Atom m_nXdndEnter; 351 Atom m_nXdndLeave; 352 Atom m_nXdndPosition; 353 Atom m_nXdndStatus; 354 Atom m_nXdndDrop; 355 Atom m_nXdndFinished; 356 Atom m_nXdndSelection; 357 Atom m_nXdndTypeList; 358 Atom m_nXdndProxy; 359 Atom m_nXdndActionCopy; 360 Atom m_nXdndActionMove; 361 Atom m_nXdndActionLink; 362 Atom m_nXdndActionAsk; 363 Atom m_nXdndActionPrivate; 364 365 // caching for atoms 366 ::std::hash_map< Atom, ::rtl::OUString > 367 m_aAtomToString; 368 ::std::hash_map< ::rtl::OUString, Atom, ::rtl::OUStringHash > 369 m_aStringToAtom; 370 371 // the registered selections 372 ::std::hash_map< Atom, Selection* > 373 m_aSelections; 374 // IncrementalTransfers in progress 375 std::hash_map< XLIB_Window, std::hash_map< Atom, IncrementalTransfer > > 376 m_aIncrementals; 377 378 // do not use X11 multithreading capabilities 379 // since this leads to deadlocks in different Xlib implentations 380 // (XFree as well as Xsun) use an own mutex instead 381 ::osl::Mutex m_aMutex; 382 bool m_bShutDown; 383 384 SelectionManager(); 385 ~SelectionManager(); 386 387 SelectionAdaptor* getAdaptor( Atom selection ); 388 PixmapHolder* getPixmapHolder( Atom selection ); 389 390 // handle various events 391 bool handleSelectionRequest( XSelectionRequestEvent& rRequest ); 392 bool handleSendPropertyNotify( XPropertyEvent& rNotify ); 393 bool handleReceivePropertyNotify( XPropertyEvent& rNotify ); 394 bool handleSelectionNotify( XSelectionEvent& rNotify ); 395 bool handleDragEvent( XEvent& rMessage ); 396 bool handleDropEvent( XClientMessageEvent& rMessage ); 397 398 // dnd helpers 399 void sendDragStatus( Atom nDropAction ); 400 void sendDropPosition( bool bForce, XLIB_Time eventXLIB_Time ); 401 bool updateDragAction( int modifierState ); 402 int getXdndVersion( XLIB_Window aXLIB_Window, XLIB_Window& rProxy ); 403 XLIB_Cursor createCursor( const char* pPointerData, const char* pMaskData, int width, int height, int hotX, int hotY ); 404 // coordinates on root XLIB_Window 405 void updateDragWindow( int nX, int nY, XLIB_Window aRoot ); 406 407 bool getPasteData( Atom selection, Atom type, Sequence< sal_Int8 >& rData ); 408 // returns true if conversion was successful 409 bool convertData( const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& xTransferable, 410 Atom nType, 411 Atom nSelection, 412 int & rFormat, 413 Sequence< sal_Int8 >& rData ); 414 bool sendData( SelectionAdaptor* pAdaptor, XLIB_Window requestor, Atom target, Atom property, Atom selection ); 415 416 // thread dispatch loop 417 public: 418 // public for extern "C" stub 419 static void run( void* ); 420 private: 421 void dispatchEvent( int millisec ); 422 // drag thread dispatch 423 public: 424 // public for extern "C" stub 425 static void runDragExecute( void* ); 426 private: 427 void dragDoDispatch(); 428 bool handleXEvent( XEvent& rEvent ); 429 430 // compound text conversion 431 ::rtl::OString convertToCompound( const ::rtl::OUString& rText ); 432 ::rtl::OUString convertFromCompound( const char* pText, int nLen = -1 ); 433 434 sal_Int8 getUserDragAction() const; 435 sal_Int32 getSelectionTimeout(); 436 public: 437 static SelectionManager& get( const ::rtl::OUString& rDisplayName = ::rtl::OUString() ); 438 getDisplay()439 Display * getDisplay() { return m_pDisplay; }; getWindow()440 XLIB_Window getWindow() { return m_aWindow; }; 441 442 443 void registerHandler( Atom selection, SelectionAdaptor& rAdaptor ); 444 void deregisterHandler( Atom selection ); 445 bool requestOwnership( Atom selection ); 446 447 // allow for synchronization over one mutex for XClipboard getMutex()448 osl::Mutex& getMutex() { return m_aMutex; } 449 450 451 Atom getAtom( const ::rtl::OUString& rString ); 452 const ::rtl::OUString& getString( Atom nAtom ); 453 454 // type conversion 455 // note: convertTypeToNative does NOT clear the list, so you can append 456 // multiple types to the same list 457 void convertTypeToNative( const ::rtl::OUString& rType, Atom selection, int& rFormat, ::std::list< Atom >& rConversions, bool bPushFront = false ); 458 ::rtl::OUString convertTypeFromNative( Atom nType, Atom selection, int& rFormat ); 459 void getNativeTypeList( const Sequence< com::sun::star::datatransfer::DataFlavor >& rTypes, std::list< Atom >& rOutTypeList, Atom targetselection ); 460 461 // methods for transferable 462 bool getPasteDataTypes( Atom selection, Sequence< ::com::sun::star::datatransfer::DataFlavor >& rTypes ); 463 bool getPasteData( Atom selection, const ::rtl::OUString& rType, Sequence< sal_Int8 >& rData ); 464 465 // for XDropTarget to register/deregister itself 466 void registerDropTarget( XLIB_Window aXLIB_Window, DropTarget* pTarget ); 467 void deregisterDropTarget( XLIB_Window aXLIB_Window ); 468 469 // for XDropTarget{Drag|Drop}Context 470 void accept( sal_Int8 dragOperation, XLIB_Window aDropXLIB_Window, XLIB_Time aXLIB_Timestamp ); 471 void reject( XLIB_Window aDropXLIB_Window, XLIB_Time aXLIB_Timestamp ); 472 void dropComplete( sal_Bool success, XLIB_Window aDropXLIB_Window, XLIB_Time aXLIB_Timestamp ); 473 474 // for XDragSourceContext 475 sal_Int32 getCurrentCursor(); 476 void setCursor( sal_Int32 cursor, XLIB_Window aDropXLIB_Window, XLIB_Time aXLIB_Timestamp ); 477 void setImage( sal_Int32 image, XLIB_Window aDropXLIB_Window, XLIB_Time aXLIB_Timestamp ); 478 void transferablesFlavorsChanged(); 479 480 void shutdown() throw(); 481 482 // XInitialization 483 virtual void SAL_CALL initialize( const Sequence< Any >& arguments ) throw( ::com::sun::star::uno::Exception ); 484 485 // XEventHandler 486 virtual sal_Bool SAL_CALL handleEvent( const Any& event ) throw(); 487 488 // XDragSource 489 virtual sal_Bool SAL_CALL isDragImageSupported() throw(); 490 virtual sal_Int32 SAL_CALL getDefaultCursor( sal_Int8 dragAction ) throw(); 491 virtual void SAL_CALL startDrag( 492 const ::com::sun::star::datatransfer::dnd::DragGestureEvent& trigger, 493 sal_Int8 sourceActions, sal_Int32 cursor, sal_Int32 image, 494 const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& transferable, 495 const com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener >& listener 496 ) throw(); 497 498 // SelectionAdaptor for XdndSelection Drag (we are drag source) 499 virtual com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > getTransferable() throw(); 500 virtual void clearTransferable() throw(); 501 virtual void fireContentsChanged() throw(); 502 virtual com::sun::star::uno::Reference< XInterface > getReference() throw(); 503 504 // XEventListener 505 virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw( ::com::sun::star::uno::RuntimeException ); 506 507 // XTerminateListener 508 virtual void SAL_CALL queryTermination( const ::com::sun::star::lang::EventObject& aEvent ) 509 throw( ::com::sun::star::frame::TerminationVetoException, ::com::sun::star::uno::RuntimeException ); 510 virtual void SAL_CALL notifyTermination( const ::com::sun::star::lang::EventObject& aEvent ) 511 throw( ::com::sun::star::uno::RuntimeException ); 512 }; 513 514 // ------------------------------------------------------------------------ 515 516 ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL Xdnd_getSupportedServiceNames(); 517 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL Xdnd_createInstance( 518 const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & xMultiServiceFactory); 519 520 ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL Xdnd_dropTarget_getSupportedServiceNames(); 521 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL Xdnd_dropTarget_createInstance( 522 const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & xMultiServiceFactory); 523 524 // ------------------------------------------------------------------------ 525 526 } 527 528 #endif 529