source: trunk/src/kernel/qclipboard_pm.cpp@ 20

Last change on this file since 20 was 20, checked in by dmik, 20 years ago

Fixed a bunch of compiler warnings

  • Property svn:keywords set to Id
File size: 17.5 KB
Line 
1/****************************************************************************
2** $Id: qclipboard_pm.cpp 20 2005-11-17 18:00:27Z dmik $
3**
4** Implementation of QClipboard class for OS/2
5**
6** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
7** Copyright (C) 2004 Norman ASA. Initial OS/2 Port.
8** Copyright (C) 2005 netlabs.org. Further OS/2 Development.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qclipboard.h"
39
40#ifndef QT_NO_CLIPBOARD
41
42#include "qapplication.h"
43#include "qapplication_p.h"
44#include "qeventloop.h"
45#include "qpixmap.h"
46#include "qdatetime.h"
47#include "qimage.h"
48#include "qmime.h"
49#include "qt_os2.h"
50
51
52/*****************************************************************************
53 Internal QClipboard functions for OS/2.
54 *****************************************************************************/
55
56static HWND prevClipboardViewer = 0;
57static QWidget *qt_cb_owner = 0;
58
59static QWidget *clipboardOwner()
60{
61 if ( !qt_cb_owner )
62 qt_cb_owner = new QWidget( 0, "internal clipboard owner" );
63 return qt_cb_owner;
64}
65
66
67/*****************************************************************************
68 QClipboard member functions for OS/2.
69 *****************************************************************************/
70
71bool QClipboard::supportsSelection() const
72{
73 return FALSE;
74}
75
76
77bool QClipboard::ownsSelection() const
78{
79 return FALSE;
80}
81
82
83bool QClipboard::ownsClipboard() const
84{
85 return qt_cb_owner && WinQueryClipbrdOwner( 0 ) == qt_cb_owner->winId();
86}
87
88
89void QClipboard::setSelectionMode(bool)
90{
91}
92
93
94bool QClipboard::selectionModeEnabled() const
95{
96 return FALSE;
97}
98
99
100void QClipboard::ownerDestroyed()
101{
102 QWidget *owner = (QWidget *)sender();
103 if ( owner == qt_cb_owner ) {
104 if ( owner->winId() == WinQueryClipbrdViewer( 0 ) )
105 WinSetClipbrdViewer( 0, prevClipboardViewer );
106 prevClipboardViewer = 0;
107 }
108}
109
110
111void QClipboard::connectNotify( const char *signal )
112{
113 if ( qstrcmp( signal, SIGNAL( dataChanged() ) ) == 0 ) {
114 QWidget *owner = clipboardOwner();
115 HWND clipboardViewer = WinQueryClipbrdViewer( 0 );
116 if ( owner->winId() != clipboardViewer ) {
117 prevClipboardViewer = clipboardViewer;
118 BOOL ok = WinSetClipbrdViewer( 0, owner->winId() );
119 Q_UNUSED( ok );
120#ifndef QT_NO_DEBUG
121 if ( !ok )
122 qSystemWarning( "QClipboard: Failed to set clipboard viewer" );
123#endif
124 connect( owner, SIGNAL( destroyed() ), SLOT( ownerDestroyed() ) );
125 }
126 }
127}
128
129class QClipboardWatcher : public QMimeSource {
130public:
131 QClipboardWatcher()
132 {
133 }
134
135 bool provides( const char* mime ) const
136 {
137 bool r = FALSE;
138 if ( WinOpenClipbrd( 0 ) ) {
139 ulong cf = 0;
140 while (!r && (cf = WinEnumClipbrdFmts( 0, cf ))) {
141 if ( QPMMime::convertor( mime, cf ) )
142 r = TRUE;
143 }
144#ifndef QT_NO_DEBUG
145 if ( !WinCloseClipbrd( 0 ) )
146 qSystemWarning( "QClipboard: Failed to close clipboard" );
147#else
148 WinCloseClipbrd( 0 );
149#endif
150 }
151#ifndef QT_NO_DEBUG
152 else
153 qSystemWarning( "QClipboardWatcher: Failed to open clipboard" );
154#endif
155 return r;
156 }
157
158 // Not efficient to iterate over this (so we provide provides() above).
159
160 // In order to be able to use UniCode characters, we have to give
161 // it a higher priority than single-byte characters. To do this, we
162 // treat CF_TEXT as a special case and postpone its processing until
163 // we're sure we do not have CF_TextUnicode ("text/unicode" atom)
164 const char* format( int n ) const
165 {
166 const char* mime = 0;
167 bool sawText = false;
168
169 if ( n >= 0 ) {
170 if ( WinOpenClipbrd( 0 ) ) {
171 ulong cf = 0;
172 while ( (cf = WinEnumClipbrdFmts( 0, cf )) ) {
173 if ( cf == CF_TEXT ) {
174 sawText = true;
175 } else {
176 mime = QPMMime::cfToMime( cf );
177 if ( mime ) {
178 if ( !n )
179 break; // COME FROM HERE
180 n--;
181 mime = 0;
182 }
183 }
184 }
185 // COME FROM BREAK
186
187 // If we did not find a suitable mime type, yet skipped
188 // CF_TEXT due to the priorities above, give it a shot
189 if ( !mime && sawText && !n ) {
190 mime = QPMMime::cfToMime( CF_TEXT );
191 }
192 WinCloseClipbrd( 0 );
193 }
194 }
195 if ( !n )
196 return mime;
197 return 0;
198 }
199
200 QByteArray encodedData( const char* mime ) const
201 {
202 QByteArray r;
203 if ( WinOpenClipbrd( 0 ) ) {
204 QPtrList<QPMMime> all = QPMMime::all();
205 for ( QPMMime* c = all.first(); c; c = all.next() ) {
206 ulong cf = c->cfFor( mime );
207 if ( cf ) {
208 ULONG fl = 0;
209 BOOL ok = WinQueryClipbrdFmtInfo( 0, cf, &fl );
210 if ( ok && (fl & QPMMime::CFI_Storage) ==
211 (c->flFor( cf ) & QPMMime::CFI_Storage) ) {
212 ULONG data = WinQueryClipbrdData ( 0, cf );
213 if ( (ok = (data != 0)) ) {
214 char *dataPtr = 0;
215 uint dataSize = 0;
216 if ( fl & CFI_POINTER ) {
217 ULONG sz = ~0, flags = 0;
218 // get data size rounded to the page boundary (4K)
219 APIRET rc = DosQueryMem( (PVOID) data, &sz, &flags );
220 if ( rc ) {
221#ifndef QT_NO_DEBUG
222 qSystemWarning( "QClipboard: Failed to query memory info", rc );
223#endif
224 continue;
225 }
226 // look at the last dword of the last page
227 dataSize = *(((ULONG *)(data + sz)) - 1);
228 // If this dword seems to contain the exact data size,
229 // use it. Otherwise use the rounded size hoping
230 // that a data reader will correctly determine
231 // the exact size according to the mime type and
232 // data header
233 if ( !dataSize || dataSize > (sz - sizeof( ULONG )) )
234 dataSize = sz;
235 dataPtr = (char *) data;
236 }
237 else if ( fl & CFI_HANDLE ) {
238 // represent the handle as first 4 bytes of
239 // the data array
240 dataSize = sizeof( ULONG );
241 dataPtr = (char *) &data;
242 }
243 else {
244#ifdef QT_CHECK_RANGE
245 qWarning( "QClipboard: wrong format flags: %08lX", fl );
246#endif
247 continue;
248 }
249 r.setRawData( dataPtr, dataSize );
250 QByteArray tr = c->convertToMime( r, mime, cf );
251 tr.detach();
252 r.resetRawData( dataPtr, dataSize );
253 r = tr;
254 break;
255 }
256 }
257#ifndef QT_NO_DEBUG
258 if ( !ok )
259 qSystemWarning( "QClipboard: Failed to read clipboard data" );
260#endif
261 }
262 }
263 WinCloseClipbrd( 0 );
264 }
265#ifndef QT_NO_DEBUG
266 else
267 qSystemWarning( "QClipboard: Failed to open Clipboard" );
268#endif
269 return r;
270 }
271};
272
273
274
275class QClipboardData
276{
277public:
278 QClipboardData();
279 ~QClipboardData();
280
281 void setSource(QMimeSource* s)
282 {
283 delete src;
284 src = s;
285 if ( src )
286 src->clearCache();
287 }
288 QMimeSource* source()
289 {
290 if ( src )
291 src->clearCache();
292 return src;
293 }
294 QMimeSource* provider()
295 {
296 if (!prov)
297 prov = new QClipboardWatcher();
298 prov->clearCache();
299 return prov;
300 }
301
302private:
303 QMimeSource* src;
304 QMimeSource* prov;
305};
306
307QClipboardData::QClipboardData()
308{
309 src = 0;
310 prov = 0;
311}
312
313QClipboardData::~QClipboardData()
314{
315 delete src;
316 delete prov;
317}
318
319static QClipboardData *internalCbData = 0;
320
321static void cleanupClipboardData()
322{
323 delete internalCbData;
324 internalCbData = 0;
325}
326
327static QClipboardData *clipboardData()
328{
329 if ( internalCbData == 0 ) {
330 internalCbData = new QClipboardData;
331 Q_CHECK_PTR( internalCbData );
332 qAddPostRoutine( cleanupClipboardData );
333 }
334 return internalCbData;
335}
336
337
338//#define QT_DEBUG_CB
339
340static void setClipboardData( ulong cf, const char *mime, QPMMime *c, QMimeSource *s )
341{
342 QByteArray md = s->encodedData( mime );
343#if defined(QT_DEBUG_CB)
344 qDebug( "source is %d bytes of %s", md.size(), mime );
345#endif
346
347 md = c->convertFromMime( md, mime, cf );
348 ulong fl = c->flFor( cf );
349 int len = md.size();
350#if defined(QT_DEBUG_CB)
351 qDebug( "rendered %d bytes of CF 0x%08lX (0x%08lX) by %s",
352 len, cf, fl, c->convertorName());
353#endif
354
355 ULONG data = 0;
356 if ( fl & CFI_POINTER ) {
357 // allocate memory for the array + dword for its size
358 APIRET rc = DosAllocSharedMem( (PVOID *) &data, NULL, len + 4,
359 PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE );
360 if ( rc ) {
361#ifndef QT_NO_DEBUG
362 qSystemWarning( "QClipboard: Failed to allocate shared memory", rc );
363#endif
364 return;
365 }
366 // get the size rounded to the page boundary (4K)
367 ULONG sz = ~0, flags = 0;
368 rc = DosQueryMem( (PVOID) (data + len - 1), &sz, &flags );
369 if ( !rc ) {
370 sz += (len - 1);
371 // store the exact size to the last dword of the last page
372 *(((ULONG *)(data + sz)) - 1) = len;
373 }
374#ifndef QT_NO_DEBUG
375 else
376 qSystemWarning( "QClipboard: Failed to query memory info", rc );
377#endif
378 memcpy( (void *) data, md.data(), len );
379 }
380 else if ( fl & CFI_HANDLE ) {
381 if ( len == sizeof(ULONG) ) {
382 // treat first 4 bytes of the array as a handle
383 data = *(ULONG *) md.data();
384 } else {
385#ifdef QT_CHECK_RANGE
386 qWarning( "QClipboard: wrong CFI_HANDLE data len: %d", len );
387#endif
388 return;
389 }
390 }
391 else {
392#ifdef QT_CHECK_RANGE
393 qWarning( "QClipboard: wrong format flags: %08lX", fl );
394#endif
395 return;
396 }
397 BOOL ok = WinSetClipbrdData( 0, data, cf, fl );
398#ifndef QT_NO_DEBUG
399 if ( !ok )
400 qSystemWarning( "QClipboard: Failed to write data" );
401#else
402 Q_UNUSED( ok );
403#endif
404}
405
406static void renderFormat( ulong cf )
407{
408#if defined(QT_DEBUG_CB)
409 qDebug( "renderFormat(0x%08lX)", cf );
410#endif
411 // sanity checks
412 if ( !internalCbData )
413 return;
414 QMimeSource *s = internalCbData->source();
415 if ( !s )
416 return;
417
418 const char* mime;
419 for ( int i = 0; (mime = s->format( i )); i++ ) {
420 QPMMime* c = QPMMime::convertor( mime, cf );
421 if ( c ) {
422 setClipboardData( cf, mime, c, s );
423 return;
424 }
425 }
426}
427
428static bool ignore_WM_DESTROYCLIPBOARD = FALSE;
429
430static void renderAllFormats()
431{
432#if defined(QT_DEBUG_CB)
433 qDebug( "renderAllFormats" );
434#endif
435 // sanity checks
436 if ( !internalCbData )
437 return;
438 QMimeSource *s = internalCbData->source();
439 if ( !s )
440 return;
441 if ( !qt_cb_owner )
442 return;
443
444 if ( !WinOpenClipbrd( 0 ) ) {
445#if defined(QT_CHECK_STATE)
446 qSystemWarning( "renderAllFormats: couldn't open clipboard" );
447#endif
448 return;
449 }
450
451 ignore_WM_DESTROYCLIPBOARD = TRUE;
452 WinEmptyClipbrd( 0 );
453 ignore_WM_DESTROYCLIPBOARD = FALSE;
454
455 const char* mime;
456 QPtrList<QPMMime> all = QPMMime::all();
457 for ( int i = 0; (mime = s->format( i )); i++ ) {
458 for ( QPMMime* c = all.first(); c; c = all.next() ) {
459 if ( c->cfFor( mime ) ) {
460 for ( int j = 0; j < c->countCf(); j++ ) {
461 ulong cf = c->cf(j);
462 if ( c->canConvert( mime, cf ) ) {
463 ulong fl = 0;
464 if ( WinQueryClipbrdFmtInfo( 0, cf, &fl ) ) {
465 // the format is already rendered by some other
466 // convertor, skip it
467 continue;
468 }
469 setClipboardData( cf, mime, c, s );
470 }
471 }
472 }
473 }
474 }
475
476 WinCloseClipbrd( 0 );
477}
478
479QClipboard::~QClipboard()
480{
481 renderAllFormats();
482 delete qt_cb_owner;
483 qt_cb_owner = 0;
484}
485
486bool QClipboard::event( QEvent *e )
487{
488 if ( e->type() != QEvent::Clipboard )
489 return QObject::event( e );
490
491 QMSG *msg = (QMSG *)((QCustomEvent*)e)->data();
492 if ( !msg ) {
493 renderAllFormats();
494 return TRUE;
495 }
496
497#if defined(QT_DEBUG_CB)
498 qDebug( "QClipboard::event: msg=%08lX mp1=%p mp2=%p",
499 msg->msg, msg->mp1, msg->mp2 );
500#endif
501
502 switch ( msg->msg ) {
503
504 case WM_DRAWCLIPBOARD:
505 emit dataChanged();
506 // PM doesn't inform the previous clipboard viewer when another
507 // app changes it (nor does it support viewer chains in some other
508 // way). The best we can do is to propagate the message to the
509 // previous clipboard viewer ourselves (though there is no guarantee
510 // that all non-Qt apps will do the same).
511 if ( prevClipboardViewer ) {
512 // propagate the message to the previous clipboard viewer
513 BOOL ok = WinPostMsg ( prevClipboardViewer,
514 msg->msg, msg->mp1, msg->mp2 );
515 if ( !ok )
516 prevClipboardViewer = 0;
517 }
518 break;
519
520 case WM_DESTROYCLIPBOARD:
521 if ( !ignore_WM_DESTROYCLIPBOARD )
522 cleanupClipboardData();
523 break;
524
525 case WM_RENDERFMT:
526 renderFormat( (ULONG) msg->mp1 );
527 break;
528 case WM_RENDERALLFMTS:
529 renderAllFormats();
530 break;
531 }
532
533 return TRUE;
534}
535
536
537void QClipboard::clear( Mode mode )
538{
539 if ( mode != Clipboard ) return;
540
541 if ( WinOpenClipbrd( 0 ) ) {
542 WinEmptyClipbrd( 0 );
543 WinCloseClipbrd( 0 );
544 }
545}
546
547
548QMimeSource* QClipboard::data( Mode mode ) const
549{
550 if ( mode != Clipboard ) return 0;
551
552 QClipboardData *d = clipboardData();
553 return d->provider();
554}
555
556
557void QClipboard::setData( QMimeSource* src, Mode mode )
558{
559 if ( mode != Clipboard ) return;
560
561 if ( !WinOpenClipbrd( 0 ) ) {
562#ifndef QT_NO_DEBUG
563 qSystemWarning( "QClipboard: Failed to open clipboard" );
564#endif
565 return;
566 }
567
568 QClipboardData *d = clipboardData();
569 d->setSource( src );
570
571 ignore_WM_DESTROYCLIPBOARD = TRUE;
572 BOOL ok = WinEmptyClipbrd( 0 );
573 ignore_WM_DESTROYCLIPBOARD = FALSE;
574#ifndef QT_NO_DEBUG
575 if ( !ok )
576 qSystemWarning( "QClipboard: Failed to empty clipboard" );
577#else
578 Q_UNUSED( ok );
579#endif
580
581 // Register all the formats of src that we can render.
582 const char* mime;
583 QPtrList<QPMMime> all = QPMMime::all();
584 for ( int i = 0; (mime = src->format( i )); i++ ) {
585#if defined(QT_DEBUG_CB)
586 qDebug( "setData: src mime[%i] = %s", i, mime );
587#endif
588 for ( QPMMime* c = all.first(); c; c = all.next() ) {
589#if defined(QT_DEBUG_CB)
590 qDebug( "setData: trying convertor %s", c->convertorName() );
591#endif
592 if ( c->cfFor( mime ) ) {
593 for ( int j = 0; j < c->countCf(); j++ ) {
594 ulong cf = c->cf( j );
595 if ( c->canConvert( mime, cf ) ) {
596 ulong fl = 0;
597 if ( WinQueryClipbrdFmtInfo( 0, cf, &fl ) ) {
598 // the format is already rendered by some other
599 // convertor, skip it
600 continue;
601 }
602
603 fl = c->flFor( cf );
604#if defined(QT_DEBUG_CB)
605 qDebug( "setData: converting to CF 0x%08lX (0x%08lX)",
606 cf, fl );
607#endif
608 if ( qApp && qApp->eventLoop()->loopLevel() ) {
609 // setup delayed rendering of clipboard data
610 WinSetClipbrdOwner( 0, clipboardOwner()->winId() );
611 WinSetClipbrdData( 0, 0, cf, fl );
612 }
613 else {
614 // write now if we can't process data requests
615 setClipboardData( cf, mime, c, src );
616 }
617 }
618 }
619 }
620 }
621 }
622
623 WinCloseClipbrd( 0 );
624}
625
626#endif // QT_NO_CLIPBOARD
Note: See TracBrowser for help on using the repository browser.