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