1 /****************************************************************************
2 ** $Id$
3 **
4 ** Implementation of some internal classes
5 **
6 ** Created : 010427
7 **
8 ** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9 **
10 ** This file is part of the kernel module of the TQt 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.TQPL 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 COPYING included in the
19 ** packaging of this file.
20 **
21 ** Licensees holding valid TQt Enterprise Edition or TQt Professional Edition
22 ** licenses may use this file in accordance with the TQt 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 TQt Commercial License Agreements.
30 ** See http://www.trolltech.com/qpl/ for TQPL 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 ** SPDX-License-Identifier: GPL-2.0 OR QPL-1.0
37 **
38 **********************************************************************/
39
40 #include "secqinternal_p.h"
41 #include "ntqwidget.h"
42 #include "ntqpixmap.h"
43 #include "ntqpainter.h"
44 #include "ntqcleanuphandler.h"
45
46 static TQPixmap* qdb_shared_pixmap = 0;
47 static TQPixmap *qdb_force_pixmap = 0;
48 static SecTQSharedDoubleBuffer* qdb_owner = 0;
49
50 static TQCleanupHandler<TQPixmap> qdb_pixmap_cleanup;
51
52 #ifdef Q_WS_MACX
53 bool SecTQSharedDoubleBuffer::dblbufr = FALSE;
54 #else
55 bool SecTQSharedDoubleBuffer::dblbufr = TRUE;
56 #endif
57
58
59 /*
60 hardLimitWidth/Height: if >= 0, the maximum number of pixels that
61 get double buffered.
62
63 sharedLimitWidth/Height: if >= 0, the maximum number of pixels the
64 shared double buffer can keep.
65
66 For x with sharedLimitSize < x <= hardLimitSize, temporary buffers
67 are constructed.
68 */
69 static const int hardLimitWidth = -1;
70 static const int hardLimitHeight = -1;
71 #if defined( Q_WS_QWS ) || defined( Q_WS_MAC9 )
72 // Small in TQt/Embedded / Mac9 - 5K on 32bpp
73 static const int sharedLimitWidth = 64;
74 static const int sharedLimitHeight = 20;
75 #else
76 // 240K on 32bpp
77 static const int sharedLimitWidth = 640;
78 static const int sharedLimitHeight = 100;
79 #endif
80
81 // *******************************************************************
82 // SecTQSharedDoubleBufferCleaner declaration and implementation
83 // *******************************************************************
84
85 /* \internal
86 This class is responsible for cleaning up the pixmaps created by the
87 SecTQSharedDoubleBuffer class. When SecTQSharedDoubleBuffer creates a
88 pixmap larger than the shared limits, this class deletes it after a
89 specified amount of time.
90
91 When the large pixmap is created/used, you must call start(). If the
92 large pixmap is ever deleted, you must call stop(). The start()
93 method always restarts the timer, so if the large pixmap is
94 constantly in use, the timer will never fire, and the pixmap will
95 not be constantly created and destroyed.
96 */
97
98 static const int shared_double_buffer_cleanup_timeout = 30000; // 30 seconds
99
100 // declaration
101
102 class SecTQSharedDoubleBufferCleaner : public TQObject
103 {
104 public:
105 SecTQSharedDoubleBufferCleaner( void );
106
107 void start( void );
108 void stop( void );
109
110 void doCleanup( void );
111
112 bool event( TQEvent *e );
113
114 private:
115 int timer_id;
116 };
117
118 // implementation
119
120 /* \internal
121 Creates a SecTQSharedDoubleBufferCleaner object. The timer is not
122 started when creating the object.
123 */
SecTQSharedDoubleBufferCleaner(void)124 SecTQSharedDoubleBufferCleaner::SecTQSharedDoubleBufferCleaner( void )
125 : TQObject( 0, "internal shared double buffer cleanup object" ),
126 timer_id( -1 )
127 {
128 }
129
130 /* \internal
131 Starts the cleanup timer. Any previously running timer is stopped.
132 */
start(void)133 void SecTQSharedDoubleBufferCleaner::start( void )
134 {
135 stop();
136 timer_id = startTimer( shared_double_buffer_cleanup_timeout );
137 }
138
139 /* \internal
140 Stops the cleanup timer, if it is running.
141 */
stop(void)142 void SecTQSharedDoubleBufferCleaner::stop( void )
143 {
144 if ( timer_id != -1 )
145 killTimer( timer_id );
146 timer_id = -1;
147 }
148
149 /* \internal
150 */
doCleanup(void)151 void SecTQSharedDoubleBufferCleaner::doCleanup( void )
152 {
153 qdb_pixmap_cleanup.remove( &qdb_force_pixmap );
154 delete qdb_force_pixmap;
155 qdb_force_pixmap = 0;
156 }
157
158 /* \internal
159 Event handler reimplementation. Calls doCleanup() when the timer
160 fires.
161 */
event(TQEvent * e)162 bool SecTQSharedDoubleBufferCleaner::event( TQEvent *e )
163 {
164 if ( e->type() != TQEvent::Timer )
165 return FALSE;
166
167 TQTimerEvent *event = (TQTimerEvent *) e;
168 if ( event->timerId() == timer_id ) {
169 doCleanup();
170 stop();
171 }
172 #ifdef QT_CHECK_STATE
173 else {
174 tqWarning( "SecTQSharedDoubleBufferCleaner::event: invalid timer event received." );
175 return FALSE;
176 }
177 #endif // QT_CHECK_STATE
178
179 return TRUE;
180 }
181
182 // static instance
183 static SecTQSharedDoubleBufferCleaner *static_cleaner = 0;
184 TQSingleCleanupHandler<SecTQSharedDoubleBufferCleaner> cleanup_static_cleaner;
185
staticCleaner()186 inline static SecTQSharedDoubleBufferCleaner *staticCleaner()
187 {
188 if ( ! static_cleaner ) {
189 static_cleaner = new SecTQSharedDoubleBufferCleaner();
190 cleanup_static_cleaner.set( &static_cleaner );
191 }
192 return static_cleaner;
193 }
194
195
196 // *******************************************************************
197 // SecTQSharedDoubleBuffer implementation
198 // *******************************************************************
199
200 /* \internal
201 \enum DoubleBufferFlags
202
203 \value InitBG initialize the background of the double buffer.
204
205 \value Force disable shared buffer size limits.
206
207 \value Default InitBG and Force are used by default.
208 */
209
210 /* \internal
211 \enum DoubleBufferState
212
213 \value Active indicates that the buffer may be used.
214
215 \value BufferActive indicates that painting with painter() will be
216 double buffered.
217
218 \value ExternalPainter indicates that painter() will return a
219 painter that was not created by SecTQSharedDoubleBuffer.
220 */
221
222 /* \internal
223 \class SecTQSharedDoubleBuffer
224
225 This class provides a single, reusable double buffer. This class
226 is used internally by TQt widgets that need double buffering, which
227 prevents each individual widget form creating a double buffering
228 pixmap.
229
230 Using a single pixmap double buffer and sharing it across all
231 widgets is nicer on window system resources.
232 */
233
234 /* \internal
235 Creates a SecTQSharedDoubleBuffer with flags \f.
236
237 \sa DoubleBufferFlags
238 */
SecTQSharedDoubleBuffer(DBFlags f)239 SecTQSharedDoubleBuffer::SecTQSharedDoubleBuffer( DBFlags f )
240 : wid( 0 ), rx( 0 ), ry( 0 ), rw( 0 ), rh( 0 ), flags( f ), state( 0 ),
241 p( 0 ), external_p( 0 ), pix( 0 )
242 {
243 }
244
245 /* \internal
246 Creates a SecTQSharedDoubleBuffer with flags \f. The \a widget, \a x,
247 \a y, \a w and \a h arguments are passed to begin().
248
249 \sa DoubleBufferFlags begin()
250 */
SecTQSharedDoubleBuffer(TQWidget * widget,int x,int y,int w,int h,DBFlags f)251 SecTQSharedDoubleBuffer::SecTQSharedDoubleBuffer( TQWidget* widget,
252 int x, int y, int w, int h,
253 DBFlags f )
254 : wid( 0 ), rx( 0 ), ry( 0 ), rw( 0 ), rh( 0 ), flags( f ), state( 0 ),
255 p( 0 ), external_p( 0 ), pix( 0 )
256 {
257 begin( widget, x, y, w, h );
258 }
259
260 /* \internal
261 Creates a SecTQSharedDoubleBuffer with flags \f. The \a painter, \a x,
262 \a y, \a w and \a h arguments are passed to begin().
263
264 \sa DoubleBufferFlags begin()
265 */
SecTQSharedDoubleBuffer(TQPainter * painter,int x,int y,int w,int h,DBFlags f)266 SecTQSharedDoubleBuffer::SecTQSharedDoubleBuffer( TQPainter* painter,
267 int x, int y, int w, int h,
268 DBFlags f)
269 : wid( 0 ), rx( 0 ), ry( 0 ), rw( 0 ), rh( 0 ), flags( f ), state( 0 ),
270 p( 0 ), external_p( 0 ), pix( 0 )
271 {
272 begin( painter, x, y, w, h );
273 }
274
275 /* \internal
276 Creates a SecTQSharedDoubleBuffer with flags \f. The \a widget and
277 \a r arguments are passed to begin().
278
279 \sa DoubleBufferFlags begin()
280 */
SecTQSharedDoubleBuffer(TQWidget * widget,const TQRect & r,DBFlags f)281 SecTQSharedDoubleBuffer::SecTQSharedDoubleBuffer( TQWidget *widget, const TQRect &r, DBFlags f )
282 : wid( 0 ), rx( 0 ), ry( 0 ), rw( 0 ), rh( 0 ), flags( f ), state( 0 ),
283 p( 0 ), external_p( 0 ), pix( 0 )
284 {
285 begin( widget, r );
286 }
287
288 /* \internal
289 Creates a SecTQSharedDoubleBuffer with flags \f. The \a painter and
290 \a r arguments are passed to begin().
291
292 \sa DoubleBufferFlags begin()
293 */
SecTQSharedDoubleBuffer(TQPainter * painter,const TQRect & r,DBFlags f)294 SecTQSharedDoubleBuffer::SecTQSharedDoubleBuffer( TQPainter *painter, const TQRect &r, DBFlags f )
295 : wid( 0 ), rx( 0 ), ry( 0 ), rw( 0 ), rh( 0 ), flags( f ), state( 0 ),
296 p( 0 ), external_p( 0 ), pix( 0 )
297 {
298 begin( painter, r );
299 }
300
301 /* \internal
302 Destructs the SecTQSharedDoubleBuffer and calls end() if the buffer is
303 active.
304
305 \sa isActive() end()
306 */
~SecTQSharedDoubleBuffer()307 SecTQSharedDoubleBuffer::~SecTQSharedDoubleBuffer()
308 {
309 if ( isActive() )
310 end();
311 }
312
313 /* \internal
314 Starts double buffered painting in the area specified by \a x,
315 \a y, \a w and \a h on \a painter. Painting should be done using the
316 TQPainter returned by SecTQSharedDoubleBuffer::painter().
317
318 The double buffered area will be updated when calling end().
319
320 \sa painter() isActive() end()
321 */
begin(TQPainter * painter,int x,int y,int w,int h)322 bool SecTQSharedDoubleBuffer::begin( TQPainter* painter, int x, int y, int w, int h )
323 {
324 if ( isActive() ) {
325 #if defined(QT_CHECK_STATE)
326 tqWarning( "SecTQSharedDoubleBuffer::begin: Buffer is already active."
327 "\n\tYou must end() the buffer before a second begin()" );
328 #endif // QT_CHECK_STATE
329 return FALSE;
330 }
331
332 external_p = painter;
333
334 if ( painter->device()->devType() == TQInternal::Widget )
335 return begin( (TQWidget *) painter->device(), x, y, w, h );
336
337 state = Active;
338
339 rx = x;
340 ry = y;
341 rw = w;
342 rh = h;
343
344 if ( ( pix = getPixmap() ) ) {
345 #ifdef Q_WS_X11
346 if ( painter->device()->x11Screen() != pix->x11Screen() )
347 pix->x11SetScreen( painter->device()->x11Screen() );
348 TQPixmap::x11SetDefaultScreen( pix->x11Screen() );
349 #endif // Q_WS_X11
350
351 state |= BufferActive;
352 p = new TQPainter( pix );
353 if ( p->isActive() ) {
354 p->setPen( external_p->pen() );
355 p->setBackgroundColor( external_p->backgroundColor() );
356 p->setFont( external_p->font() );
357 }
358 } else {
359 state |= ExternalPainter;
360 p = external_p;
361 }
362
363 return TRUE;
364 }
365
366 /* \internal
367
368
369 Starts double buffered painting in the area specified by \a x,
370 \a y, \a w and \a h on \a widget. Painting should be done using the
371 TQPainter returned by SecTQSharedDoubleBuffer::painter().
372
373 The double buffered area will be updated when calling end().
374
375 \sa painter() isActive() end()
376 */
begin(TQWidget * widget,int x,int y,int w,int h)377 bool SecTQSharedDoubleBuffer::begin( TQWidget* widget, int x, int y, int w, int h )
378 {
379 if ( isActive() ) {
380 #if defined(QT_CHECK_STATE)
381 tqWarning( "SecTQSharedDoubleBuffer::begin: Buffer is already active."
382 "\n\tYou must end() the buffer before a second begin()" );
383 #endif // QT_CHECK_STATE
384 return FALSE;
385 }
386
387 state = Active;
388
389 wid = widget;
390 rx = x;
391 ry = y;
392 rw = w <= 0 ? wid->width() : w;
393 rh = h <= 0 ? wid->height() : h;
394
395 if ( ( pix = getPixmap() ) ) {
396 #ifdef Q_WS_X11
397 if ( wid->x11Screen() != pix->x11Screen() )
398 pix->x11SetScreen( wid->x11Screen() );
399 TQPixmap::x11SetDefaultScreen( pix->x11Screen() );
400 #endif // Q_WS_X11
401
402 state |= BufferActive;
403 if ( flags & InitBG ) {
404 pix->fill( wid, rx, ry );
405 }
406 p = new TQPainter( pix, wid );
407 // newly created painters should be translated to the origin
408 // of the widget, so that paint methods can draw onto the double
409 // buffered painter in widget coordinates.
410 p->setBrushOrigin( -rx, -ry );
411 p->translate( -rx, -ry );
412 } else {
413 if ( external_p ) {
414 state |= ExternalPainter;
415 p = external_p;
416 } else {
417 p = new TQPainter( wid );
418 }
419
420 if ( flags & InitBG ) {
421 wid->erase( rx, ry, rw, rh );
422 }
423 }
424 return TRUE;
425 }
426
427 /* \internal
428 Ends double buffered painting. The contents of the shared double
429 buffer pixmap are drawn onto the destination by calling flush(),
430 and ownership of the shared double buffer pixmap is released.
431
432 \sa begin() flush()
433 */
end()434 bool SecTQSharedDoubleBuffer::end()
435 {
436 if ( ! isActive() ) {
437 #if defined(QT_CHECK_STATE)
438 tqWarning( "SecTQSharedDoubleBuffer::end: Buffer is not active."
439 "\n\tYou must call begin() before calling end()." );
440 #endif // QT_CHECK_STATE
441 return FALSE;
442 }
443
444 if ( ! ( state & ExternalPainter ) ) {
445 p->end();
446 delete p;
447 }
448
449 flush();
450
451 if ( pix ) {
452 releasePixmap();
453 }
454
455 wid = 0;
456 rx = ry = rw = rh = 0;
457 // do not reset flags!
458 state = 0;
459
460 p = external_p = 0;
461 pix = 0;
462
463 return TRUE;
464 }
465
466 /* \internal
467 Paints the contents of the shared double buffer pixmap onto the
468 destination. The destination is determined from the arguments
469 based to begin().
470
471 Note: You should not need to call this function, since it is called
472 from end().
473
474 \sa begin() end()
475 */
flush()476 void SecTQSharedDoubleBuffer::flush()
477 {
478 if ( ! isActive() || ! ( state & BufferActive ) )
479 return;
480
481 if ( external_p )
482 external_p->drawPixmap( rx, ry, *pix, 0, 0, rw, rh );
483 else if ( wid && wid->isVisible() )
484 bitBlt( wid, rx, ry, pix, 0, 0, rw, rh );
485 }
486
487 /* \internal
488 Atquire ownership of the shared double buffer pixmap, subject to the
489 following conditions:
490
491 \list 1
492 \i double buffering is enabled globally.
493 \i the shared double buffer pixmap is not in use.
494 \i the size specified in begin() is valid, and within limits.
495 \endlist
496
497 If all of these conditions are met, then this SecTQSharedDoubleBuffer
498 object becomes the owner of the shared double buffer pixmap. The
499 shared double buffer pixmap is resize if necessary, and this
500 function returns a pointer to the pixmap. Ownership must later be
501 relinquished by calling releasePixmap().
502
503 If none of the above conditions are met, this function returns
504 zero.
505
506 \sa releasePixmap()
507 */
getPixmap()508 TQPixmap *SecTQSharedDoubleBuffer::getPixmap()
509 {
510 if ( isDisabled() ) {
511 // double buffering disabled globally
512 return 0;
513 }
514
515 if ( qdb_owner ) {
516 // shared pixmap already in use
517 return 0;
518 }
519
520 if ( rw <= 0 || rh <= 0 ||
521 ( hardLimitWidth > 0 && rw >= hardLimitWidth ) ||
522 ( hardLimitHeight > 0 && rh >= hardLimitHeight ) ) {
523 // invalid size, or hard limit reached
524 return 0;
525 }
526
527 if ( rw >= sharedLimitWidth || rh >= sharedLimitHeight ) {
528 if ( flags & Force ) {
529 rw = TQMIN(rw, 8000);
530 rh = TQMIN(rh, 8000);
531 // need to create a big pixmap and start the cleaner
532 if ( ! qdb_force_pixmap ) {
533 qdb_force_pixmap = new TQPixmap( rw, rh );
534 qdb_pixmap_cleanup.add( &qdb_force_pixmap );
535 } else if ( qdb_force_pixmap->width () < rw ||
536 qdb_force_pixmap->height() < rh ) {
537 qdb_force_pixmap->resize( rw, rh );
538 }
539 qdb_owner = this;
540 staticCleaner()->start();
541 return qdb_force_pixmap;
542 }
543
544 // size is outside shared limit
545 return 0;
546 }
547
548 if ( ! qdb_shared_pixmap ) {
549 qdb_shared_pixmap = new TQPixmap( rw, rh );
550 qdb_pixmap_cleanup.add( &qdb_shared_pixmap );
551 } else if ( qdb_shared_pixmap->width() < rw ||
552 qdb_shared_pixmap->height() < rh ) {
553 qdb_shared_pixmap->resize( rw, rh );
554 }
555 qdb_owner = this;
556 return qdb_shared_pixmap;
557 }
558
559 /* \internal
560 Releases ownership of the shared double buffer pixmap.
561
562 \sa getPixmap()
563 */
releasePixmap()564 void SecTQSharedDoubleBuffer::releasePixmap()
565 {
566 if ( qdb_owner != this ) {
567 // sanity check
568
569 #ifdef QT_CHECK_STATE
570 tqWarning( "SecTQSharedDoubleBuffer::releasePixmap: internal error."
571 "\n\t%p does not own shared pixmap, %p does.",
572 (void*)this, (void*)qdb_owner );
573 #endif // QT_CHECK_STATE
574
575 return;
576 }
577
578 qdb_owner = 0;
579 }
580
581 /* \internal
582 \fn bool SecTQSharedDoubleBuffer::isDisabled()
583
584 Returns TRUE is double buffering is disabled globally, FALSE otherwise.
585 */
586
587 /* \internal
588 \fn void SecTQSharedDoubleBuffer::setDisabled( bool off )
589
590 Disables global double buffering \a off is TRUE, otherwise global
591 double buffering is enabled.
592 */
593
594 /* \internal
595 Deletes the shared double buffer pixmap. You should not need to
596 call this function, since it is called from the TQApplication
597 destructor.
598 */
cleanup()599 void SecTQSharedDoubleBuffer::cleanup()
600 {
601 qdb_pixmap_cleanup.remove( &qdb_shared_pixmap );
602 qdb_pixmap_cleanup.remove( &qdb_force_pixmap );
603 delete qdb_shared_pixmap;
604 delete qdb_force_pixmap;
605 qdb_shared_pixmap = 0;
606 qdb_force_pixmap = 0;
607 qdb_owner = 0;
608 }
609
610 /* \internal
611 \fn bool SecTQSharedDoubleBuffer::begin( TQWidget *widget, const TQRect &r )
612 \overload
613 */
614
615 /* \internal
616 \fn bool SecTQSharedDoubleBuffer::begin( TQPainter *painter, const TQRect &r )
617 \overload
618 */
619
620 /* \internal
621 \fn TQPainter *SecTQSharedDoubleBuffer::painter() const
622
623 Returns the active painter on the double buffered area,
624 or zero if double buffered painting is not active.
625 */
626
627 /* \internal
628 \fn bool SecTQSharedDoubleBuffer::isActive() const
629
630 Returns TRUE if double buffered painting is active, FALSE otherwise.
631 */
632
633 /* \internal
634 \fn bool SecTQSharedDoubleBuffer::isBuffered() const
635
636 Returns TRUE if painting is double buffered, FALSE otherwise.
637 */
638