x11_graphics.cpp
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:11k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * x11_graphics.cpp
  3.  *****************************************************************************
  4.  * Copyright (C) 2003 VideoLAN
  5.  * $Id: x11_graphics.cpp 7292 2004-04-06 20:38:10Z asmax $
  6.  *
  7.  * Authors: Cyril Deguet     <asmax@via.ecp.fr>
  8.  *          Olivier Teuli鑢e <ipkiss@via.ecp.fr>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  23.  *****************************************************************************/
  24. #ifdef X11_SKINS
  25. #include <stdlib.h>
  26. #include <X11/Xlib.h>
  27. #include <X11/Xutil.h>
  28. #include <X11/extensions/shape.h>
  29. #include "x11_display.hpp"
  30. #include "x11_graphics.hpp"
  31. #include "x11_window.hpp"
  32. #include "../src/generic_bitmap.hpp"
  33. X11Graphics::X11Graphics( intf_thread_t *pIntf, X11Display &rDisplay,
  34.                           int width, int height ):
  35.     OSGraphics( pIntf ), m_rDisplay( rDisplay ), m_width( width ),
  36.     m_height( height )
  37. {
  38.     // Get the display paramaters
  39.     int screen = DefaultScreen( XDISPLAY );
  40.     int depth = DefaultDepth( XDISPLAY, screen );
  41.     // X11 doesn't accept that !
  42.     if( width == 0 || height == 0 )
  43.     {
  44.         // Avoid a X11 Bad Value error
  45.         width = height = 1;
  46.         msg_Err( getIntf(), "Invalid image size (null width or height)" );
  47.     }
  48.     // Create a pixmap
  49.     m_pixmap = XCreatePixmap( XDISPLAY, DefaultRootWindow( XDISPLAY ),
  50.                               width, height, depth);
  51.     // Create the transparency mask (everything is transparent initially)
  52.     m_mask = XCreateRegion();
  53.     // Create a Graphics Context that does not generate GraphicsExpose events
  54.     XGCValues xgcvalues;
  55.     xgcvalues.graphics_exposures = False;
  56.     m_gc = XCreateGC( XDISPLAY, m_pixmap, GCGraphicsExposures, &xgcvalues );
  57. }
  58. X11Graphics::~X11Graphics()
  59. {
  60.     XFreeGC( XDISPLAY, m_gc );
  61.     XDestroyRegion( m_mask );
  62.     XFreePixmap( XDISPLAY, m_pixmap );
  63. }
  64. void X11Graphics::clear()
  65. {
  66.     // Clear the transparency mask
  67.     XDestroyRegion( m_mask );
  68.     m_mask = XCreateRegion();
  69. }
  70. void X11Graphics::drawGraphics( const OSGraphics &rGraphics, int xSrc,
  71.                                 int ySrc, int xDest, int yDest, int width,
  72.                                 int height )
  73. {
  74.     if( width == -1 )
  75.     {
  76.         width = rGraphics.getWidth();
  77.     }
  78.     if( height == -1 )
  79.     {
  80.         height = rGraphics.getHeight();
  81.     }
  82.     // Source drawable
  83.     Drawable src = ((X11Graphics&)rGraphics).getDrawable();
  84.     // Create the mask for transparency
  85.     Region voidMask = XCreateRegion();
  86.     XRectangle rect;
  87.     rect.x = xSrc;
  88.     rect.y = ySrc;
  89.     rect.width = width;
  90.     rect.height = height;
  91.     Region clipMask = XCreateRegion();
  92.     XUnionRectWithRegion( &rect, voidMask, clipMask );
  93.     Region mask = XCreateRegion();
  94.     XIntersectRegion( ((X11Graphics&)rGraphics).getMask(), clipMask, mask );
  95.     XDestroyRegion( clipMask );
  96.     XDestroyRegion( voidMask );
  97.     XOffsetRegion( mask, xDest - xSrc, yDest - ySrc );
  98.     // Copy the pixmap
  99.     XSetRegion( XDISPLAY, m_gc, mask );
  100.     XCopyArea( XDISPLAY, src, m_pixmap, m_gc, xSrc, ySrc, width, height,
  101.                xDest, yDest );
  102.     // Add the source mask to the mask of the graphics
  103.     Region newMask = XCreateRegion();
  104.     XUnionRegion( m_mask, mask, newMask );
  105.     XDestroyRegion( mask );
  106.     XDestroyRegion( m_mask );
  107.     m_mask = newMask;
  108. }
  109. void X11Graphics::drawBitmap( const GenericBitmap &rBitmap, int xSrc,
  110.                               int ySrc, int xDest, int yDest, int width,
  111.                               int height )
  112. {
  113.     // Get the bitmap size if necessary
  114.     if( width == -1 )
  115.     {
  116.         width = rBitmap.getWidth();
  117.     }
  118.     else if( width > rBitmap.getWidth() )
  119.     {
  120.         msg_Dbg( getIntf(), "Bitmap width too small!" );
  121.         width = rBitmap.getWidth();
  122.     }
  123.     if( height == -1 )
  124.     {
  125.         height = rBitmap.getHeight();
  126.     }
  127.     else if( height > rBitmap.getHeight() )
  128.     {
  129.         msg_Dbg( getIntf(), "Bitmap height too small!" );
  130.         height = rBitmap.getHeight();
  131.     }
  132.     // Nothing to draw if width or height is null
  133.     if( width == 0 || height == 0 )
  134.     {
  135.         return;
  136.     }
  137.     // Safety check for debugging purpose
  138.     if( xDest + width > m_width || yDest + height > m_height )
  139.     {
  140.         msg_Dbg( getIntf(), "Bitmap too large !" );
  141.         return;
  142.     }
  143.     // Get a buffer on the image data
  144.     uint8_t *pBmpData = rBitmap.getData();
  145.     if( pBmpData == NULL )
  146.     {
  147.         // Nothing to draw
  148.         return;
  149.     }
  150.     // Get the image from the pixmap
  151.     XImage *pImage = XGetImage( XDISPLAY, m_pixmap, xDest, yDest, width,
  152.                                 height, AllPlanes, ZPixmap );
  153.     if( pImage == NULL )
  154.     {
  155.         msg_Dbg( getIntf(), "XGetImage returned NULL" );
  156.         return;
  157.     }
  158.     char *pData = pImage->data;
  159.     // Get the padding of this image
  160.     int pad = pImage->bitmap_pad >> 3;
  161.     int shift = ( pad - ( (width * XPIXELSIZE) % pad ) ) % pad;
  162.     // Mask for transparency
  163.     Region mask = XCreateRegion();
  164.     // Get a pointer on the right X11Display::makePixel method
  165.     X11Display::MakePixelFunc_t makePixelFunc = m_rDisplay.getMakePixel();
  166.     // Skip the first lines of the image
  167.     pBmpData += 4 * ySrc * rBitmap.getWidth();
  168.     // Copy the bitmap on the image and compute the mask
  169.     for( int y = 0; y < height; y++ )
  170.     {
  171.         // Skip uninteresting bytes at the beginning of the line
  172.         pBmpData += 4 * xSrc;
  173.         // Flag to say whether the previous pixel on the line was visible
  174.         bool wasVisible = false;
  175.         // Beginning of the current visible segment on the line
  176.         int visibleSegmentStart = 0;
  177.         for( int x = 0; x < width; x++ )
  178.         {
  179.             uint8_t b = *(pBmpData++);
  180.             uint8_t g = *(pBmpData++);
  181.             uint8_t r = *(pBmpData++);
  182.             uint8_t a = *(pBmpData++);
  183.             // Draw the pixel
  184.             (m_rDisplay.*makePixelFunc)( (uint8_t*)pData, r, g, b, a );
  185.             pData += XPIXELSIZE;
  186.             if( a > 0 )
  187.             {
  188.                 // Pixel is visible
  189.                 if( ! wasVisible )
  190.                 {
  191.                     // Beginning of a visible segment
  192.                     visibleSegmentStart = x;
  193.                 }
  194.                 wasVisible = true;
  195.             }
  196.             else
  197.             {
  198.                 // Pixel is transparent
  199.                 if( wasVisible )
  200.                 {
  201.                     // End of a visible segment: add it to the mask
  202.                     addHSegmentInRegion( mask, visibleSegmentStart, x, y );
  203.                 }
  204.                 wasVisible = false;
  205.             }
  206.         }
  207.         if( wasVisible )
  208.         {
  209.             // End of a visible segment: add it to the mask
  210.             addHSegmentInRegion( mask, visibleSegmentStart, width, y );
  211.         }
  212.         pData += shift;
  213.         // Skip uninteresting bytes at the end of the line
  214.         pBmpData += 4 * (rBitmap.getWidth() - width - xSrc);
  215.     }
  216.     // Apply the mask to the graphics context
  217.     XOffsetRegion( mask, xDest, yDest );
  218.     XSetRegion( XDISPLAY, m_gc, mask );
  219.     // Copy the image on the pixmap
  220.     XPutImage( XDISPLAY, m_pixmap, m_gc, pImage, 0, 0, xDest, yDest, width,
  221.                height);
  222.     XDestroyImage( pImage );
  223.     // Add the bitmap mask to the global graphics mask
  224.     Region newMask = XCreateRegion();
  225.     XUnionRegion( mask, m_mask, newMask );
  226.     XDestroyRegion( m_mask );
  227.     m_mask = newMask;
  228.     XDestroyRegion( mask );
  229. }
  230. void X11Graphics::fillRect( int left, int top, int width, int height,
  231.                             uint32_t color )
  232. {
  233.     // Update the mask with the rectangle area
  234.     Region newMask = XCreateRegion();
  235.     XRectangle rect;
  236.     rect.x = left;
  237.     rect.y = top;
  238.     rect.width = width;
  239.     rect.height = height;
  240.     XUnionRectWithRegion( &rect, m_mask, newMask );
  241.     XDestroyRegion( m_mask );
  242.     m_mask = newMask;
  243.     // Draw the rectangle
  244.     XGCValues gcVal;
  245.     gcVal.foreground = m_rDisplay.getPixelValue( color >> 16, color >> 8, color );
  246.     XChangeGC( XDISPLAY, m_gc, GCForeground,  &gcVal );
  247.     XSetRegion( XDISPLAY, m_gc, m_mask );
  248.     XFillRectangle( XDISPLAY, m_pixmap, m_gc, left, top, width, height );
  249. }
  250. void X11Graphics::drawRect( int left, int top, int width, int height,
  251.                             uint32_t color )
  252. {
  253.     // Update the mask with the rectangle
  254.     addHSegmentInRegion( m_mask, left, left + width, top );
  255.     addHSegmentInRegion( m_mask, left, left + width, top + height );
  256.     addVSegmentInRegion( m_mask, top, top + height, left );
  257.     addVSegmentInRegion( m_mask, top, top + height, left + width );
  258.     // Draw the rectangle
  259.     XGCValues gcVal;
  260.     gcVal.foreground = m_rDisplay.getPixelValue( color >> 16, color >> 8, color );
  261.     XChangeGC( XDISPLAY, m_gc, GCForeground,  &gcVal );
  262.     XSetRegion( XDISPLAY, m_gc, m_mask );
  263.     XDrawRectangle( XDISPLAY, m_pixmap, m_gc, left, top, width - 1, height - 1 );
  264. }
  265. void X11Graphics::applyMaskToWindow( OSWindow &rWindow )
  266. {
  267.     // Get the target window
  268.     Window win = ((X11Window&)rWindow).getDrawable();
  269.     // Change the shape of the window
  270.     XShapeCombineRegion( XDISPLAY, win, ShapeBounding, 0, 0, m_mask,
  271.                          ShapeSet );
  272. }
  273. void X11Graphics::copyToWindow( OSWindow &rWindow, int xSrc,  int ySrc,
  274.                                 int width, int height, int xDest, int yDest )
  275. {
  276.     // Destination window
  277.     Drawable dest = ((X11Window&)rWindow).getDrawable();
  278.     XCopyArea( XDISPLAY, m_pixmap, dest, XGC, xSrc, ySrc, width, height,
  279.                xDest, yDest );
  280. }
  281. bool X11Graphics::hit( int x, int y ) const
  282. {
  283.     return XPointInRegion( m_mask, x, y );
  284. }
  285. inline void X11Graphics::addHSegmentInRegion( Region &rMask, int xStart,
  286.                                               int xEnd, int y )
  287. {
  288.     XRectangle rect;
  289.     rect.x = xStart;
  290.     rect.y = y;
  291.     rect.width = xEnd - xStart;
  292.     rect.height = 1;
  293.     Region newMask = XCreateRegion();
  294.     XUnionRectWithRegion( &rect, rMask, newMask );
  295.     XDestroyRegion( rMask );
  296.     rMask = newMask;
  297. }
  298. inline void X11Graphics::addVSegmentInRegion( Region &rMask, int yStart,
  299.                                               int yEnd, int x )
  300. {
  301.     XRectangle rect;
  302.     rect.x = x;
  303.     rect.y = yStart;
  304.     rect.width = 1;
  305.     rect.height = yEnd - yStart;
  306.     Region newMask = XCreateRegion();
  307.     XUnionRectWithRegion( &rect, rMask, newMask );
  308.     XDestroyRegion( rMask );
  309.     rMask = newMask;
  310. }
  311. #endif