00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifdef HAVE_CONFIG_H
00021 #include <config.h>
00022 #endif
00023
00024 #include <iostream>
00025 using std::cerr;
00026 using std::endl;
00027
00028 #include "displayer.h"
00029 #include <gdk/gdkx.h>
00030
00031 AspectRatioCalculator::AspectRatioCalculator( int widgetWidth, int widgetHeight,
00032 int imageWidth, int imageHeight,
00033 int maxImageWidth, int maxImageHeight )
00034 {
00035 double ratioWidth = ( double ) widgetWidth / ( double ) imageWidth;
00036 double ratioHeight = ( double ) widgetHeight / ( double ) imageHeight;
00037 double ratioConstant = ratioHeight < ratioWidth ?
00038 ratioHeight : ratioWidth;
00039 width = ( int ) ( imageWidth * ratioConstant + 0.5 );
00040 height = ( int ) ( imageHeight * ratioConstant + 0.5 );
00041 if ( width > maxImageWidth )
00042 width = maxImageWidth;
00043 if ( height > maxImageHeight )
00044 height = maxImageHeight;
00045 x = ( widgetWidth - width ) / 2;
00046 y = ( widgetHeight - height ) / 2;
00047 }
00048
00049 AspectRatioCalculator::AspectRatioCalculator( int widgetWidth, int widgetHeight,
00050 int imageWidth, int imageHeight, bool isPAL, bool isWidescreen )
00051 {
00052
00053 static Preferences & prefs = Preferences::getInstance();
00054
00055 if ( prefs.displayMode == 0 && imageWidth == 360 )
00056 {
00057 imageWidth *= 2;
00058 imageHeight *= 2;
00059 }
00060
00061
00062
00063 if ( isWidescreen )
00064 {
00065 if ( isPAL )
00066 {
00067
00068 imageWidth = imageWidth * 1024 / 720;
00069 imageHeight = imageHeight * imageHeight / 576;
00070 }
00071 else
00072 {
00073
00074 imageWidth = imageWidth * 854 / 720;
00075 imageHeight = imageHeight * imageHeight / 480;
00076 }
00077 }
00078 else
00079 {
00080 if ( isPAL )
00081 {
00082
00083 imageWidth = imageWidth * 768 / 720;
00084 imageHeight = imageHeight * imageHeight / 576;
00085 }
00086 else
00087 {
00088
00089 imageWidth = imageWidth * imageWidth / 720;
00090 imageHeight = imageHeight * 540 / 480;
00091 }
00092 }
00093
00094
00095
00096 double ratioWidth = ( double ) widgetWidth / ( double ) imageWidth;
00097 double ratioHeight = ( double ) widgetHeight / ( double ) imageHeight;
00098
00099 if ( ratioHeight < ratioWidth )
00100 {
00101 width = ( int ) ( imageWidth * ratioHeight + 0.5 );
00102 height = ( int ) ( imageHeight * ratioHeight + 0.5 );
00103 }
00104 else
00105 {
00106 width = ( int ) ( imageWidth * ratioWidth + 0.5 );
00107 height = ( int ) ( imageHeight * ratioWidth + 0.5 );
00108 }
00109
00110
00111
00112
00113 x = ( widgetWidth - width ) / 2;
00114 y = ( widgetHeight - height ) / 2;
00115 }
00116
00121 bool Displayer::usable()
00122 {
00123 return false;
00124 }
00125
00129 DisplayerInput Displayer::format()
00130 {
00131 return DISPLAY_NONE;
00132 }
00133
00137 int Displayer::preferredWidth()
00138 {
00139 return img_width;
00140 }
00141
00145 int Displayer::preferredHeight()
00146 {
00147 return img_height;
00148 }
00149
00158 void Displayer::put( void *image, int width, int height )
00159 {
00160 if ( width == preferredWidth() && height == preferredHeight() )
00161 {
00162 put( image );
00163 }
00164 else
00165 {
00166 reformat( format(), format(), image, width, height );
00167 put( pixels );
00168 }
00169 }
00170
00181 void Displayer::put( DisplayerInput inFormat, void *image,
00182 int width, int height )
00183 {
00184 if ( format() == inFormat &&
00185 width == preferredWidth() && height == preferredHeight() )
00186 {
00187 put( image );
00188 }
00189 else
00190 {
00191 reformat( inFormat, format(), image, width, height );
00192 put( pixels );
00193 }
00194 }
00195
00196 void Displayer::Reformat424( unsigned char *image, int inWidth, int inHeight, int outWidth, int outHeight )
00197 {
00198
00199 int rounding = 1 << 15;
00200
00201 unsigned int xfactor = ( inWidth << 16 ) / outWidth;
00202 unsigned int yfactor = ( inHeight << 16 ) / outHeight;
00203
00204 unsigned int ymax = yfactor * outHeight;
00205 unsigned int xmax = xfactor * outWidth;
00206
00207 unsigned int y = 0;
00208
00209 unsigned int i = 0;
00210
00211 unsigned int o = 0;
00212
00213 for ( unsigned int yft = 0; yft < ymax; yft += yfactor )
00214 {
00215 y = ( ( yft + rounding ) >> 16 ) * inWidth * 4;
00216 for ( unsigned int xft = 0; xft < xmax; xft += xfactor )
00217 {
00218 i = y + ( ( xft + rounding ) >> 16 ) * 4;
00219 pixels[ o ++ ] = image[ i ++ ];
00220 pixels[ o ++ ] = image[ i ++ ];
00221 pixels[ o ++ ] = image[ i ++ ];
00222 pixels[ o ++ ] = image[ i ];
00223 }
00224 }
00225 }
00226
00227 void Displayer::Reformat222( unsigned char *image, int inWidth, int inHeight, int outWidth, int outHeight )
00228 {
00229
00230 int rounding = 1 << 15;
00231
00232 unsigned int xfactor = ( inWidth << 16 ) / outWidth;
00233 unsigned int yfactor = ( inHeight << 16 ) / outHeight;
00234
00235 unsigned int ymax = yfactor * outHeight;
00236 unsigned int xmax = xfactor * outWidth;
00237
00238 unsigned int y = 0;
00239
00240 unsigned int i = 0;
00241
00242 unsigned int o = 0;
00243
00244 for ( unsigned int yft = 0; yft < ymax; yft += yfactor )
00245 {
00246 y = ( ( yft + rounding ) >> 16 ) * inWidth * 2;
00247 for ( unsigned int xft = 0; xft < xmax; xft += xfactor )
00248 {
00249 i = y + ( ( xft + rounding ) >> 16 ) * 2;
00250 pixels[ o ++ ] = image[ i ++ ];
00251 pixels[ o ++ ] = image[ i ];
00252 }
00253 }
00254 }
00255
00256 void Displayer::Reformat323( unsigned char *image, int inWidth, int inHeight, int outWidth, int outHeight )
00257 {
00258
00259 int rounding = 1 << 15;
00260
00261 unsigned int xfactor = ( inWidth << 16 ) / outWidth;
00262 unsigned int yfactor = ( inHeight << 16 ) / outHeight;
00263
00264 unsigned int ymax = yfactor * outHeight;
00265 unsigned int xmax = xfactor * outWidth;
00266
00267 unsigned int y = 0;
00268
00269 unsigned int i = 0;
00270
00271 unsigned int o = 0;
00272
00273 for ( unsigned int yft = 0; yft < ymax; yft += yfactor )
00274 {
00275 y = ( ( yft + rounding ) >> 16 ) * inWidth * 3;
00276 for ( unsigned int xft = 0; xft < xmax; xft += xfactor )
00277 {
00278 i = y + ( ( xft + rounding ) >> 16 ) * 3;
00279 pixels[ o ++ ] = image[ i ++ ];
00280 pixels[ o ++ ] = image[ i ++ ];
00281 pixels[ o ++ ] = image[ i ];
00282 }
00283 }
00284 }
00285
00286 void Displayer::Reformat323R( unsigned char *image, int inWidth, int inHeight, int outWidth, int outHeight )
00287 {
00288
00289 int rounding = 1 << 15;
00290
00291 unsigned int xfactor = ( inWidth << 16 ) / outWidth;
00292 unsigned int yfactor = ( inHeight << 16 ) / outHeight;
00293
00294 unsigned int ymax = yfactor * outHeight;
00295 unsigned int xmax = xfactor * outWidth;
00296
00297 unsigned int y = 0;
00298
00299 unsigned int i = 0;
00300
00301 unsigned int o = 0;
00302
00303 for ( unsigned int yft = 0; yft < ymax; yft += yfactor )
00304 {
00305 y = ( ( yft + rounding ) >> 16 ) * inWidth * 3;
00306 for ( unsigned int xft = 0; xft < xmax; xft += xfactor )
00307 {
00308 i = y + ( ( xft + rounding ) >> 16 ) * 3 + 2;
00309 pixels[ o ++ ] = image[ i ];
00310 pixels[ o ++ ] = image[ -- i ];
00311 pixels[ o ++ ] = image[ -- i ];
00312 }
00313 }
00314 }
00315
00316 void Displayer::Reformat324( unsigned char *image, int inWidth, int inHeight, int outWidth, int outHeight )
00317 {
00318
00319 int rounding = 1 << 15;
00320
00321 unsigned int xfactor = ( inWidth << 16 ) / outWidth;
00322 unsigned int yfactor = ( inHeight << 16 ) / outHeight;
00323
00324 unsigned int ymax = yfactor * outHeight;
00325 unsigned int xmax = xfactor * outWidth;
00326
00327 unsigned int y = 0;
00328
00329 unsigned int i = 0;
00330
00331 unsigned int o = 0;
00332
00333 for ( unsigned int yft = 0; yft < ymax; yft += yfactor )
00334 {
00335 y = ( ( yft + rounding ) >> 16 ) * inWidth * 3;
00336 for ( unsigned int xft = 0; xft < xmax; xft += xfactor )
00337 {
00338 i = y + ( ( xft + rounding ) >> 16 ) * 3;
00339 pixels[ o ++ ] = image[ i ++ ];
00340 pixels[ o ++ ] = image[ i ++ ];
00341 pixels[ o ++ ] = image[ i ];
00342 pixels[ o ++ ] = 0;
00343 }
00344 }
00345 }
00346
00356 void Displayer::reformat( DisplayerInput inFormat, int outFormat, void *image,
00357 int width, int height )
00358 {
00359
00360
00361
00362
00363 unsigned char * img = ( unsigned char * ) image;
00364 if ( inFormat == DISPLAY_YUV && outFormat == DISPLAY_YUV )
00365 Reformat424( img, width, height, this->preferredWidth(), this->preferredHeight() );
00366 else if ( inFormat == DISPLAY_RGB16 && outFormat == DISPLAY_RGB16 )
00367 Reformat222( img, width, height, this->preferredWidth(), this->preferredHeight() );
00368 else if ( inFormat == DISPLAY_BGR && outFormat == DISPLAY_RGB )
00369 Reformat323( img, width, height, this->preferredWidth(), this->preferredHeight() );
00370 else if ( inFormat == DISPLAY_BGR && outFormat == DISPLAY_BGR0 )
00371 Reformat324( img, width, height, this->preferredWidth(), this->preferredHeight() );
00372
00373 else if ( inFormat == outFormat )
00374 Reformat323( img, width, height, this->preferredWidth(), this->preferredHeight() );
00375
00376
00377
00378
00379 }
00380
00384 XDisplayer::XDisplayer( GtkWidget *drawingarea ) : xImage( NULL )
00385 {
00386 this->drawingarea = drawingarea;
00387 this->canuse = true;
00388
00389 cerr << ">> Trying X Displayer" << endl;
00390 #if 0
00391
00392 memset( &shmInfo, 0, sizeof( XShmSegmentInfo ) );
00393 GdkWindowPrivate *priv = ( GdkWindowPrivate* ) drawingarea->window;
00394 window = priv->xwindow;
00395 display = priv->xdisplay;
00396
00397 gc = XCreateGC( display, window, 0, &values );
00398
00399 Visual *v = ( ( GdkVisualPrivate * ) gdk_visual_get_system() ) ->xvisual;
00400 depth = DefaultDepth( display, DefaultScreen( display ) );
00401
00402 xImage = ( XImage * ) XShmCreateImage( display, v, depth, ZPixmap,
00403 ( char * ) NULL, &shmInfo,
00404 this->preferredWidth(),
00405 this->preferredHeight() );
00406
00407 shmInfo.shmid = shmget( IPC_PRIVATE,
00408 this->preferredWidth() * this->preferredHeight() * 4,
00409 IPC_CREAT | 0777 );
00410
00411 shmInfo.shmaddr = ( char * ) shmat( shmInfo.shmid, 0, 0 );
00412 xImage->data = shmInfo.shmaddr;
00413 shmInfo.readOnly = 0;
00414 if ( !XShmAttach( display, &shmInfo ) )
00415 {
00416 this->canuse = false;
00417 fprintf( stderr, "Cannot attach shared memory\n" );
00418 xImage = NULL;
00419 return ;
00420 }
00421 #endif
00422 }
00423
00424 XDisplayer::~XDisplayer()
00425 {
00426 #if 0
00427 if ( shmInfo.shmaddr != NULL )
00428 {
00429 XShmDetach( display, &shmInfo );
00430 shmdt( shmInfo.shmaddr );
00431 }
00432 if ( xImage != NULL )
00433 {
00434 XDestroyImage( xImage );
00435 }
00436 #endif
00437 }
00438
00439 bool XDisplayer::usable()
00440 {
00441 return canuse;
00442 }
00443
00444 DisplayerInput XDisplayer::format()
00445 {
00446 return DISPLAY_RGB;
00447 }
00448
00449 void XDisplayer::put( void *data )
00450 {
00451 unsigned char * image = ( unsigned char * ) data;
00452 memcpy( xImage->data, image,
00453 this->preferredWidth() * this->preferredHeight() * 4 );
00454 XShmPutImage( display, window, gc, xImage, 0, 0, 0, 0,
00455 this->preferredWidth(), this->preferredHeight(), false );
00456 }
00457
00461 XvDisplayer::XvDisplayer( GtkWidget *drawingarea, int width, int height, bool isPAL, bool isWidescreen ) :
00462 xvImage( NULL )
00463 {
00464
00465 cerr << ">> Trying XVideo at " << width << "x" << height << endl;
00466
00467 this->drawingarea = drawingarea;
00468 img_width = width;
00469 img_height = height;
00470 this->isPAL = isPAL;
00471 this->isWidescreen = isWidescreen;
00472
00473 shmInfo.shmaddr = NULL;
00474 gotPort = false;
00475
00476 window = GDK_WINDOW_XID( drawingarea->window );
00477 display = GDK_WINDOW_XDISPLAY( drawingarea->window );
00478
00479 unsigned int count;
00480 XvAdaptorInfo *adaptorInfo;
00481
00482 if ( XvQueryAdaptors( display, window, &count, &adaptorInfo ) == Success )
00483 {
00484
00485 cerr << ">>> XvQueryAdaptors count: " << count << endl;
00486 for ( unsigned int n = 0; gotPort == false && n < count; ++n )
00487 {
00488
00489 cerr << ">>> Xv: " << adaptorInfo[ n ].name
00490 << ": ports " << adaptorInfo[ n ].base_id
00491 << " - " << adaptorInfo[ n ].base_id +
00492 adaptorInfo[ n ].num_ports - 1
00493 << endl;
00494
00495 for ( port = adaptorInfo[ n ].base_id;
00496 port < adaptorInfo[ n ].base_id + adaptorInfo[ n ].num_ports;
00497 port ++ )
00498 {
00499 if ( XvGrabPort( display, port, CurrentTime ) == 0 )
00500 {
00501
00502 int formats;
00503 XvImageFormatValues *list;
00504
00505 list = XvListImageFormats( display, port, &formats );
00506
00507 cerr << ">>> formats supported: " << formats << endl;
00508
00509 for ( int i = 0; i < formats; i ++ )
00510 {
00511 fprintf( stderr, ">>> 0x%x (%c%c%c%c) %s\n",
00512 list[ i ].id,
00513 ( list[ i ].id ) & 0xff,
00514 ( list[ i ].id >> 8 ) & 0xff,
00515 ( list[ i ].id >> 16 ) & 0xff,
00516 ( list[ i ].id >> 24 ) & 0xff,
00517 ( list[ i ].format == XvPacked ) ? "packed" : "planar" );
00518 if ( list[ i ].id == 0x32595559 && !gotPort )
00519 gotPort = true;
00520 }
00521
00522 if ( !gotPort )
00523 {
00524 XvUngrabPort( display, port, CurrentTime );
00525 }
00526 else
00527 {
00528 grabbedPort = port;
00529 break;
00530 }
00531 }
00532 }
00533 }
00534
00535 if ( gotPort )
00536 {
00537 int num;
00538 unsigned int unum;
00539 XvEncodingInfo *enc;
00540
00541 XvQueryEncodings( display, grabbedPort, &unum, &enc );
00542 for ( unsigned int index = 0; index < unum; index ++ )
00543 {
00544 fprintf( stderr, ">>> %d: %s, %ldx%ld rate = %d/%d\n", index, enc->name,
00545 enc->width, enc->height, enc->rate.numerator,
00546 enc->rate.denominator );
00547 }
00548
00549 XvAttribute *xvattr = XvQueryPortAttributes( display, port, &num );
00550 for ( int k = 0; k < num; k++ )
00551 {
00552 if ( xvattr[k].flags & XvSettable )
00553 {
00554 if ( strcmp( xvattr[k].name, "XV_AUTOPAINT_COLORKEY") == 0 )
00555 {
00556 Atom val_atom = XInternAtom( display, xvattr[k].name, False );
00557 if ( XvSetPortAttribute( display, port, val_atom, 1 ) != Success )
00558 fprintf(stderr, "Couldn't set Xv attribute %s\n", xvattr[k].name);
00559 }
00560 else if ( strcmp( xvattr[k].name, "XV_COLORKEY") == 0 )
00561 {
00562 Atom val_atom = XInternAtom( display, xvattr[k].name, False );
00563 if ( XvSetPortAttribute( display, port, val_atom, 0x010102 ) != Success )
00564 fprintf(stderr, "Couldn't set Xv attribute %s\n", xvattr[k].name);
00565 }
00566 }
00567 }
00568 }
00569
00570 if ( gotPort )
00571 {
00572 gc = XCreateGC( display, window, 0, &values );
00573
00574 xvImage = ( XvImage * ) XvShmCreateImage( display, port, 0x32595559, 0, width, height, &shmInfo );
00575
00576 shmInfo.shmid = shmget( IPC_PRIVATE, xvImage->data_size, IPC_CREAT | 0777 );
00577 if (shmInfo.shmid < 0) {
00578 perror("shmget");
00579 gotPort = false;
00580 } else {
00581 shmInfo.shmaddr = ( char * ) shmat( shmInfo.shmid, 0, 0 );
00582 xvImage->data = shmInfo.shmaddr;
00583 shmInfo.readOnly = 0;
00584 if ( !XShmAttach( gdk_display, &shmInfo ) )
00585 {
00586 gotPort = false;
00587 }
00588 XSync( display, false );
00589 shmctl( shmInfo.shmid, IPC_RMID, 0 );
00590 #if 0
00591 xvImage = ( XvImage * ) XvCreateImage( display, port, 0x32595559, pix, width , height );
00592 #endif
00593 }
00594 }
00595 }
00596 else
00597 {
00598 gotPort = false;
00599 }
00600 }
00601
00602 XvDisplayer::~XvDisplayer()
00603 {
00604 cerr << ">> Destroying XV Displayer" << endl;
00605
00606 if ( gotPort )
00607 {
00608 XvUngrabPort( display, grabbedPort, CurrentTime );
00609 }
00610
00611 if ( xvImage != NULL )
00612 XvStopVideo( display, port, window );
00613
00614 if ( shmInfo.shmaddr != NULL )
00615 {
00616 XShmDetach( display, &shmInfo );
00617 shmctl( shmInfo.shmid, IPC_RMID, 0 );
00618 shmdt( shmInfo.shmaddr );
00619 }
00620 if ( xvImage != NULL )
00621 XFree( xvImage );
00622 }
00623
00624 bool XvDisplayer::usable()
00625 {
00626 return gotPort;
00627 }
00628
00629 DisplayerInput XvDisplayer::format()
00630 {
00631 return DISPLAY_YUV;
00632 }
00633
00634 void XvDisplayer::put( void *image )
00635 {
00636 AspectRatioCalculator calc( ( ( GtkWidget * ) drawingarea ) ->allocation.width,
00637 ( ( GtkWidget * ) drawingarea ) ->allocation.height,
00638 this->preferredWidth(), this->preferredHeight(),
00639 isPAL, isWidescreen );
00640
00641 memcpy( xvImage->data, image, xvImage->data_size );
00642
00643 XvShmPutImage( display, port, window, gc, xvImage,
00644 0, 0, this->preferredWidth(), this->preferredHeight(),
00645 calc.x, calc.y, calc.width, calc.height, false );
00646 #if 0
00647
00648 XvPutImage( display, port, window, gc, xvImage,
00649 0, 0, this->preferredWidth(), this->preferredHeight(),
00650 calc.x, calc.y, calc.width, calc.height );
00651 #endif
00652 }
00653
00654 GdkDisplayer::GdkDisplayer( GtkWidget *drawingarea, int width, int height, bool is_wide )
00655 {
00656 this->drawingarea = drawingarea;
00657 img_width = width;
00658 img_height = height;
00659 m_is_wide = is_wide;
00660 }
00661
00662 GdkDisplayer::~GdkDisplayer()
00663 {}
00664
00665 bool GdkDisplayer::usable()
00666 {
00667 return true;
00668 }
00669
00670 DisplayerInput GdkDisplayer::format()
00671 {
00672 return DISPLAY_RGB;
00673 }
00674
00675 void GdkDisplayer::put( void *data )
00676 {
00677 unsigned char * image = ( unsigned char * ) data;
00678
00679 AspectRatioCalculator calc( ( ( GtkWidget * ) drawingarea ) ->allocation.width,
00680 ( ( GtkWidget * ) drawingarea ) ->allocation.height,
00681 this->preferredWidth(), this->preferredHeight(),
00682 img_height == 576, m_is_wide );
00683
00684 GdkGC *gc = gdk_gc_new( drawingarea->window );
00685 GdkPixbuf *pix = gdk_pixbuf_new_from_data( image, GDK_COLORSPACE_RGB, FALSE, 8, preferredWidth(), preferredHeight(), preferredWidth() * 3, NULL, NULL );
00686 GdkPixbuf *im = gdk_pixbuf_scale_simple( pix, calc.width, calc.height, GDK_INTERP_NEAREST );
00687 gdk_draw_pixbuf( drawingarea->window, gc, im, 0, 0, 0, 0, -1, -1, GDK_RGB_DITHER_NORMAL, 0, 0 );
00688 g_object_unref( im );
00689 g_object_unref( pix );
00690 g_object_unref( gc );
00691 }
00692
00693 Displayer *FindDisplayer::getDisplayer( GtkWidget *drawingarea, Frame &frame )
00694 {
00695 Displayer * display = NULL;
00696 Preferences &prefs = Preferences::getInstance();
00697
00698 switch ( prefs.displayMode )
00699 {
00700 case DISPLAY_XV:
00701 display = new XvDisplayer( drawingarea, frame.GetWidth(), frame.GetHeight(),
00702 frame.IsPAL(), frame.IsWide() );
00703 if ( !display->usable() )
00704 {
00705 delete display;
00706 display = NULL;
00707 }
00708
00709 case DISPLAY_XX:
00710 if ( display == NULL )
00711 {
00712 display = new XvDisplayer( drawingarea, frame.GetWidth() / 2, frame.GetHeight() / 2,
00713 frame.IsPAL(), frame.IsWide() );
00714 if ( !display->usable() )
00715 {
00716 delete display;
00717 display = NULL;
00718 }
00719 }
00720
00721 default:
00722 if ( display == NULL )
00723 {
00724 display = new GdkDisplayer( drawingarea, frame.GetWidth(), frame.GetHeight(), frame.IsWide( ) );
00725 }
00726 }
00727
00728 return display;
00729 }
00730
00731 Displayer *FindDisplayer::getDisplayer( GtkWidget *drawingarea, int width, int height )
00732 {
00733 Displayer * display = NULL;
00734 Preferences &prefs = Preferences::getInstance();
00735
00736 switch ( prefs.displayMode )
00737 {
00738 case DISPLAY_XV:
00739 display = new XvDisplayer( drawingarea, width, height, (height > 480), false );
00740 if ( !display->usable() )
00741 {
00742 delete display;
00743 display = NULL;
00744 }
00745
00746 case DISPLAY_XX:
00747 if ( display == NULL )
00748 {
00749 display = new XvDisplayer( drawingarea, width / 2, height / 2, (height > 480), false );
00750 if ( !display->usable() )
00751 {
00752 delete display;
00753 display = NULL;
00754 }
00755 }
00756
00757 default:
00758 if ( display == NULL )
00759 {
00760 display = new GdkDisplayer( drawingarea, width, height, false );
00761 }
00762 }
00763
00764 return display;
00765 }