Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

x11_graphics.cpp

00001 /*****************************************************************************
00002  * x11_graphics.cpp
00003  *****************************************************************************
00004  * Copyright (C) 2003 the VideoLAN team
00005  * $Id: x11_graphics.cpp 11664 2005-07-09 06:17:09Z courmisch $
00006  *
00007  * Authors: Cyril Deguet     <[email protected]>
00008  *          Olivier Teulière <[email protected]>
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00023  *****************************************************************************/
00024 
00025 #ifdef X11_SKINS
00026 
00027 #include <stdlib.h>
00028 #include <X11/Xlib.h>
00029 #include <X11/Xutil.h>
00030 #include <X11/extensions/shape.h>
00031 
00032 #include "x11_display.hpp"
00033 #include "x11_graphics.hpp"
00034 #include "x11_window.hpp"
00035 #include "../src/generic_bitmap.hpp"
00036 
00037 
00038 X11Graphics::X11Graphics( intf_thread_t *pIntf, X11Display &rDisplay,
00039                           int width, int height ):
00040     OSGraphics( pIntf ), m_rDisplay( rDisplay ), m_width( width ),
00041     m_height( height )
00042 {
00043     // Get the display paramaters
00044     int screen = DefaultScreen( XDISPLAY );
00045     int depth = DefaultDepth( XDISPLAY, screen );
00046 
00047     // X11 doesn't accept that !
00048     if( width == 0 || height == 0 )
00049     {
00050         // Avoid a X11 Bad Value error
00051         width = height = 1;
00052         msg_Err( getIntf(), "Invalid image size (null width or height)" );
00053     }
00054 
00055     // Create a pixmap
00056     m_pixmap = XCreatePixmap( XDISPLAY, DefaultRootWindow( XDISPLAY ),
00057                               width, height, depth);
00058 
00059     // Create the transparency mask (everything is transparent initially)
00060     m_mask = XCreateRegion();
00061 
00062     // Create a Graphics Context that does not generate GraphicsExpose events
00063     XGCValues xgcvalues;
00064     xgcvalues.graphics_exposures = False;
00065     m_gc = XCreateGC( XDISPLAY, m_pixmap, GCGraphicsExposures, &xgcvalues );
00066 }
00067 
00068 
00069 X11Graphics::~X11Graphics()
00070 {
00071     XFreeGC( XDISPLAY, m_gc );
00072     XDestroyRegion( m_mask );
00073     XFreePixmap( XDISPLAY, m_pixmap );
00074 }
00075 
00076 
00077 void X11Graphics::clear()
00078 {
00079     // Clear the transparency mask
00080     XDestroyRegion( m_mask );
00081     m_mask = XCreateRegion();
00082 }
00083 
00084 
00085 void X11Graphics::drawGraphics( const OSGraphics &rGraphics, int xSrc,
00086                                 int ySrc, int xDest, int yDest, int width,
00087                                 int height )
00088 {
00089     if( width == -1 )
00090     {
00091         width = rGraphics.getWidth();
00092     }
00093     if( height == -1 )
00094     {
00095         height = rGraphics.getHeight();
00096     }
00097 
00098     // Source drawable
00099     Drawable src = ((X11Graphics&)rGraphics).getDrawable();
00100 
00101     // Create the mask for transparency
00102     Region voidMask = XCreateRegion();
00103     XRectangle rect;
00104     rect.x = xSrc;
00105     rect.y = ySrc;
00106     rect.width = width;
00107     rect.height = height;
00108     Region clipMask = XCreateRegion();
00109     XUnionRectWithRegion( &rect, voidMask, clipMask );
00110     Region mask = XCreateRegion();
00111     XIntersectRegion( ((X11Graphics&)rGraphics).getMask(), clipMask, mask );
00112     XDestroyRegion( clipMask );
00113     XDestroyRegion( voidMask );
00114     XOffsetRegion( mask, xDest - xSrc, yDest - ySrc );
00115 
00116     // Copy the pixmap
00117     XSetRegion( XDISPLAY, m_gc, mask );
00118     XCopyArea( XDISPLAY, src, m_pixmap, m_gc, xSrc, ySrc, width, height,
00119                xDest, yDest );
00120 
00121     // Add the source mask to the mask of the graphics
00122     Region newMask = XCreateRegion();
00123     XUnionRegion( m_mask, mask, newMask );
00124     XDestroyRegion( mask );
00125     XDestroyRegion( m_mask );
00126     m_mask = newMask;
00127 }
00128 
00129 
00130 void X11Graphics::drawBitmap( const GenericBitmap &rBitmap, int xSrc,
00131                               int ySrc, int xDest, int yDest, int width,
00132                               int height, bool blend )
00133 {
00134     // Get the bitmap size if necessary
00135     if( width == -1 )
00136     {
00137         width = rBitmap.getWidth();
00138     }
00139     else if( width > rBitmap.getWidth() )
00140     {
00141         msg_Dbg( getIntf(), "Bitmap width too small!" );
00142         width = rBitmap.getWidth();
00143     }
00144     if( height == -1 )
00145     {
00146         height = rBitmap.getHeight();
00147     }
00148     else if( height > rBitmap.getHeight() )
00149     {
00150         msg_Dbg( getIntf(), "Bitmap height too small!" );
00151         height = rBitmap.getHeight();
00152     }
00153 
00154     // Nothing to draw if width or height is null
00155     if( width == 0 || height == 0 )
00156     {
00157         return;
00158     }
00159 
00160     // Safety check for debugging purpose
00161     if( xDest + width > m_width || yDest + height > m_height )
00162     {
00163         msg_Dbg( getIntf(), "Bitmap too large !" );
00164         return;
00165     }
00166 
00167     // Get a buffer on the image data
00168     uint8_t *pBmpData = rBitmap.getData();
00169     if( pBmpData == NULL )
00170     {
00171         // Nothing to draw
00172         return;
00173     }
00174 
00175     // Get the image from the pixmap
00176     XImage *pImage = XGetImage( XDISPLAY, m_pixmap, xDest, yDest, width,
00177                                 height, AllPlanes, ZPixmap );
00178     if( pImage == NULL )
00179     {
00180         msg_Dbg( getIntf(), "XGetImage returned NULL" );
00181         return;
00182     }
00183     char *pData = pImage->data;
00184 
00185     // Get the padding of this image
00186     int pad = pImage->bitmap_pad >> 3;
00187     int shift = ( pad - ( (width * XPIXELSIZE) % pad ) ) % pad;
00188 
00189     // Mask for transparency
00190     Region mask = XCreateRegion();
00191 
00192     // Get a pointer on the right X11Display::makePixel method
00193     X11Display::MakePixelFunc_t makePixelFunc = ( blend ?
00194         m_rDisplay.getBlendPixel() : m_rDisplay.getPutPixel() );
00195 
00196     // Skip the first lines of the image
00197     pBmpData += 4 * ySrc * rBitmap.getWidth();
00198 
00199     // Copy the bitmap on the image and compute the mask
00200     for( int y = 0; y < height; y++ )
00201     {
00202         // Skip uninteresting bytes at the beginning of the line
00203         pBmpData += 4 * xSrc;
00204         // Flag to say whether the previous pixel on the line was visible
00205         bool wasVisible = false;
00206         // Beginning of the current visible segment on the line
00207         int visibleSegmentStart = 0;
00208         for( int x = 0; x < width; x++ )
00209         {
00210             uint8_t b = *(pBmpData++);
00211             uint8_t g = *(pBmpData++);
00212             uint8_t r = *(pBmpData++);
00213             uint8_t a = *(pBmpData++);
00214             // Draw the pixel
00215             (m_rDisplay.*makePixelFunc)( (uint8_t*)pData, r, g, b, a );
00216             pData += XPIXELSIZE;
00217             if( a > 0 )
00218             {
00219                 // Pixel is visible
00220                 if( ! wasVisible )
00221                 {
00222                     // Beginning of a visible segment
00223                     visibleSegmentStart = x;
00224                 }
00225                 wasVisible = true;
00226             }
00227             else
00228             {
00229                 // Pixel is transparent
00230                 if( wasVisible )
00231                 {
00232                     // End of a visible segment: add it to the mask
00233                     addHSegmentInRegion( mask, visibleSegmentStart, x, y );
00234                 }
00235                 wasVisible = false;
00236             }
00237         }
00238         if( wasVisible )
00239         {
00240             // End of a visible segment: add it to the mask
00241             addHSegmentInRegion( mask, visibleSegmentStart, width, y );
00242         }
00243         pData += shift;
00244         // Skip uninteresting bytes at the end of the line
00245         pBmpData += 4 * (rBitmap.getWidth() - width - xSrc);
00246     }
00247 
00248     // Apply the mask to the graphics context
00249     XOffsetRegion( mask, xDest, yDest );
00250     XSetRegion( XDISPLAY, m_gc, mask );
00251     // Copy the image on the pixmap
00252     XPutImage( XDISPLAY, m_pixmap, m_gc, pImage, 0, 0, xDest, yDest, width,
00253                height);
00254     XDestroyImage( pImage );
00255 
00256     // Add the bitmap mask to the global graphics mask
00257     Region newMask = XCreateRegion();
00258     XUnionRegion( mask, m_mask, newMask );
00259     XDestroyRegion( m_mask );
00260     m_mask = newMask;
00261 
00262     XDestroyRegion( mask );
00263 }
00264 
00265 
00266 void X11Graphics::fillRect( int left, int top, int width, int height,
00267                             uint32_t color )
00268 {
00269     // Update the mask with the rectangle area
00270     Region newMask = XCreateRegion();
00271     XRectangle rect;
00272     rect.x = left;
00273     rect.y = top;
00274     rect.width = width;
00275     rect.height = height;
00276     XUnionRectWithRegion( &rect, m_mask, newMask );
00277     XDestroyRegion( m_mask );
00278     m_mask = newMask;
00279 
00280     // Draw the rectangle
00281     XGCValues gcVal;
00282     gcVal.foreground = m_rDisplay.getPixelValue( color >> 16, color >> 8, color );
00283     XChangeGC( XDISPLAY, m_gc, GCForeground,  &gcVal );
00284     XSetRegion( XDISPLAY, m_gc, m_mask );
00285     XFillRectangle( XDISPLAY, m_pixmap, m_gc, left, top, width, height );
00286 }
00287 
00288 
00289 void X11Graphics::drawRect( int left, int top, int width, int height,
00290                             uint32_t color )
00291 {
00292     // Update the mask with the rectangle
00293     addHSegmentInRegion( m_mask, left, left + width, top );
00294     addHSegmentInRegion( m_mask, left, left + width, top + height );
00295     addVSegmentInRegion( m_mask, top, top + height, left );
00296     addVSegmentInRegion( m_mask, top, top + height, left + width );
00297 
00298     // Draw the rectangle
00299     XGCValues gcVal;
00300     gcVal.foreground = m_rDisplay.getPixelValue( color >> 16, color >> 8, color );
00301     XChangeGC( XDISPLAY, m_gc, GCForeground,  &gcVal );
00302     XSetRegion( XDISPLAY, m_gc, m_mask );
00303     XDrawRectangle( XDISPLAY, m_pixmap, m_gc, left, top, width - 1, height - 1 );
00304 }
00305 
00306 
00307 void X11Graphics::applyMaskToWindow( OSWindow &rWindow )
00308 {
00309     // Get the target window
00310     Window win = ((X11Window&)rWindow).getDrawable();
00311 
00312     // Change the shape of the window
00313     XShapeCombineRegion( XDISPLAY, win, ShapeBounding, 0, 0, m_mask,
00314                          ShapeSet );
00315 }
00316 
00317 
00318 void X11Graphics::copyToWindow( OSWindow &rWindow, int xSrc,  int ySrc,
00319                                 int width, int height, int xDest, int yDest )
00320 {
00321     // Destination window
00322     Drawable dest = ((X11Window&)rWindow).getDrawable();
00323 
00324     XCopyArea( XDISPLAY, m_pixmap, dest, XGC, xSrc, ySrc, width, height,
00325                xDest, yDest );
00326 }
00327 
00328 
00329 bool X11Graphics::hit( int x, int y ) const
00330 {
00331     return XPointInRegion( m_mask, x, y );
00332 }
00333 
00334 
00335 inline void X11Graphics::addHSegmentInRegion( Region &rMask, int xStart,
00336                                               int xEnd, int y )
00337 {
00338     XRectangle rect;
00339     rect.x = xStart;
00340     rect.y = y;
00341     rect.width = xEnd - xStart;
00342     rect.height = 1;
00343     Region newMask = XCreateRegion();
00344     XUnionRectWithRegion( &rect, rMask, newMask );
00345     XDestroyRegion( rMask );
00346     rMask = newMask;
00347 }
00348 
00349 
00350 inline void X11Graphics::addVSegmentInRegion( Region &rMask, int yStart,
00351                                               int yEnd, int x )
00352 {
00353     XRectangle rect;
00354     rect.x = x;
00355     rect.y = yStart;
00356     rect.width = 1;
00357     rect.height = yEnd - yStart;
00358     Region newMask = XCreateRegion();
00359     XUnionRectWithRegion( &rect, rMask, newMask );
00360     XDestroyRegion( rMask );
00361     rMask = newMask;
00362 }
00363 
00364 #endif

Generated on Tue Dec 20 10:14:44 2005 for vlc-0.8.4a by  doxygen 1.4.2