x11_graphics.cpp
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:11k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * x11_graphics.cpp
  3.  *****************************************************************************
  4.  * Copyright (C) 2003 the VideoLAN team
  5.  * $Id: e1b59cf793e885a541246243d2c58107f205fff9 $
  6.  *
  7.  * Authors: Cyril Deguet     <asmax@via.ecp.fr>
  8.  *          Olivier Teulière <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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  23.  *****************************************************************************/
  24. #ifdef X11_SKINS
  25. #include <X11/Xlib.h>
  26. #include <X11/Xutil.h>
  27. #include <X11/extensions/shape.h>
  28. #include "x11_display.hpp"
  29. #include "x11_graphics.hpp"
  30. #include "x11_window.hpp"
  31. #include "../src/generic_bitmap.hpp"
  32. X11Graphics::X11Graphics( intf_thread_t *pIntf, X11Display &rDisplay,
  33.                           int width, int height ):
  34.     OSGraphics( pIntf ), m_rDisplay( rDisplay ), m_width( width ),
  35.     m_height( height )
  36. {
  37.     // Get the display paramaters
  38.     int screen = DefaultScreen( XDISPLAY );
  39.     int depth = DefaultDepth( XDISPLAY, screen );
  40.     // X11 doesn't accept that !
  41.     if( width == 0 || height == 0 )
  42.     {
  43.         // Avoid a X11 Bad Value error
  44.         width = height = 1;
  45.         msg_Err( getIntf(), "invalid image size (null width or height)" );
  46.     }
  47.     // Create a pixmap
  48.     m_pixmap = XCreatePixmap( XDISPLAY, DefaultRootWindow( XDISPLAY ),
  49.                               width, height, depth);
  50.     // Create the transparency mask (everything is transparent initially)
  51.     m_mask = XCreateRegion();
  52.     // Create a Graphics Context that does not generate GraphicsExpose events
  53.     XGCValues xgcvalues;
  54.     xgcvalues.graphics_exposures = False;
  55.     m_gc = XCreateGC( XDISPLAY, m_pixmap, GCGraphicsExposures, &xgcvalues );
  56. }
  57. X11Graphics::~X11Graphics()
  58. {
  59.     XFreeGC( XDISPLAY, m_gc );
  60.     XDestroyRegion( m_mask );
  61.     XFreePixmap( XDISPLAY, m_pixmap );
  62. }
  63. void X11Graphics::clear()
  64. {
  65.     // Clear the transparency mask
  66.     XDestroyRegion( m_mask );
  67.     m_mask = XCreateRegion();
  68. }
  69. void X11Graphics::drawGraphics( const OSGraphics &rGraphics, int xSrc,
  70.                                 int ySrc, int xDest, int yDest, int width,
  71.                                 int height )
  72. {
  73.     if( width == -1 )
  74.     {
  75.         width = rGraphics.getWidth();
  76.     }
  77.     if( height == -1 )
  78.     {
  79.         height = rGraphics.getHeight();
  80.     }
  81.     // Source drawable
  82.     Drawable src = ((X11Graphics&)rGraphics).getDrawable();
  83.     // Create the mask for transparency
  84.     Region voidMask = XCreateRegion();
  85.     XRectangle rect;
  86.     rect.x = xSrc;
  87.     rect.y = ySrc;
  88.     rect.width = width;
  89.     rect.height = height;
  90.     Region clipMask = XCreateRegion();
  91.     XUnionRectWithRegion( &rect, voidMask, clipMask );
  92.     Region mask = XCreateRegion();
  93.     XIntersectRegion( ((X11Graphics&)rGraphics).getMask(), clipMask, mask );
  94.     XDestroyRegion( clipMask );
  95.     XDestroyRegion( voidMask );
  96.     XOffsetRegion( mask, xDest - xSrc, yDest - ySrc );
  97.     // Copy the pixmap
  98.     XSetRegion( XDISPLAY, m_gc, mask );
  99.     XCopyArea( XDISPLAY, src, m_pixmap, m_gc, xSrc, ySrc, width, height,
  100.                xDest, yDest );
  101.     // Add the source mask to the mask of the graphics
  102.     Region newMask = XCreateRegion();
  103.     XUnionRegion( m_mask, mask, newMask );
  104.     XDestroyRegion( mask );
  105.     XDestroyRegion( m_mask );
  106.     m_mask = newMask;
  107. }
  108. void X11Graphics::drawBitmap( const GenericBitmap &rBitmap, int xSrc,
  109.                               int ySrc, int xDest, int yDest, int width,
  110.                               int height, bool blend )
  111. {
  112.     // Get the bitmap size if necessary
  113.     if( width == -1 )
  114.     {
  115.         width = rBitmap.getWidth();
  116.     }
  117.     else if( width > rBitmap.getWidth() )
  118.     {
  119.         msg_Dbg( getIntf(), "bitmap width too small (%i)", rBitmap.getWidth() );
  120.         width = rBitmap.getWidth();
  121.     }
  122.     if( height == -1 )
  123.     {
  124.         height = rBitmap.getHeight();
  125.     }
  126.     else if( height > rBitmap.getHeight() )
  127.     {
  128.         msg_Dbg( getIntf(), "bitmap height too small (%i)", rBitmap.getHeight()
  129.                                  );
  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 = ( blend ?
  166.         m_rDisplay.getBlendPixel() : m_rDisplay.getPutPixel() );
  167.     // Skip the first lines of the image
  168.     pBmpData += 4 * ySrc * rBitmap.getWidth();
  169.     // Copy the bitmap on the image and compute the mask
  170.     for( int y = 0; y < height; y++ )
  171.     {
  172.         // Skip uninteresting bytes at the beginning of the line
  173.         pBmpData += 4 * xSrc;
  174.         // Flag to say whether the previous pixel on the line was visible
  175.         bool wasVisible = false;
  176.         // Beginning of the current visible segment on the line
  177.         int visibleSegmentStart = 0;
  178.         for( int x = 0; x < width; x++ )
  179.         {
  180.             uint8_t b = *(pBmpData++);
  181.             uint8_t g = *(pBmpData++);
  182.             uint8_t r = *(pBmpData++);
  183.             uint8_t a = *(pBmpData++);
  184.             // Draw the pixel
  185.             (m_rDisplay.*makePixelFunc)( (uint8_t*)pData, r, g, b, a );
  186.             pData += XPIXELSIZE;
  187.             if( a > 0 )
  188.             {
  189.                 // Pixel is visible
  190.                 if( ! wasVisible )
  191.                 {
  192.                     // Beginning of a visible segment
  193.                     visibleSegmentStart = x;
  194.                 }
  195.                 wasVisible = true;
  196.             }
  197.             else
  198.             {
  199.                 // Pixel is transparent
  200.                 if( wasVisible )
  201.                 {
  202.                     // End of a visible segment: add it to the mask
  203.                     addHSegmentInRegion( mask, visibleSegmentStart, x, y );
  204.                 }
  205.                 wasVisible = false;
  206.             }
  207.         }
  208.         if( wasVisible )
  209.         {
  210.             // End of a visible segment: add it to the mask
  211.             addHSegmentInRegion( mask, visibleSegmentStart, width, y );
  212.         }
  213.         pData += shift;
  214.         // Skip uninteresting bytes at the end of the line
  215.         pBmpData += 4 * (rBitmap.getWidth() - width - xSrc);
  216.     }
  217.     // Apply the mask to the graphics context
  218.     XOffsetRegion( mask, xDest, yDest );
  219.     XSetRegion( XDISPLAY, m_gc, mask );
  220.     // Copy the image on the pixmap
  221.     XPutImage( XDISPLAY, m_pixmap, m_gc, pImage, 0, 0, xDest, yDest, width,
  222.                height);
  223.     XDestroyImage( pImage );
  224.     // Add the bitmap mask to the global graphics mask
  225.     Region newMask = XCreateRegion();
  226.     XUnionRegion( mask, m_mask, newMask );
  227.     XDestroyRegion( m_mask );
  228.     m_mask = newMask;
  229.     XDestroyRegion( mask );
  230. }
  231. void X11Graphics::fillRect( int left, int top, int width, int height,
  232.                             uint32_t color )
  233. {
  234.     // Update the mask with the rectangle area
  235.     Region newMask = XCreateRegion();
  236.     XRectangle rect;
  237.     rect.x = left;
  238.     rect.y = top;
  239.     rect.width = width;
  240.     rect.height = height;
  241.     XUnionRectWithRegion( &rect, m_mask, newMask );
  242.     XDestroyRegion( m_mask );
  243.     m_mask = newMask;
  244.     // Draw the rectangle
  245.     XGCValues gcVal;
  246.     gcVal.foreground = m_rDisplay.getPixelValue( color >> 16, color >> 8, color );
  247.     XChangeGC( XDISPLAY, m_gc, GCForeground,  &gcVal );
  248.     XSetRegion( XDISPLAY, m_gc, m_mask );
  249.     XFillRectangle( XDISPLAY, m_pixmap, m_gc, left, top, width, height );
  250. }
  251. void X11Graphics::drawRect( int left, int top, int width, int height,
  252.                             uint32_t color )
  253. {
  254.     // Update the mask with the rectangle
  255.     addHSegmentInRegion( m_mask, left, left + width, top );
  256.     addHSegmentInRegion( m_mask, left, left + width, top + height );
  257.     addVSegmentInRegion( m_mask, top, top + height, left );
  258.     addVSegmentInRegion( m_mask, top, top + height, left + width );
  259.     // Draw the rectangle
  260.     XGCValues gcVal;
  261.     gcVal.foreground = m_rDisplay.getPixelValue( color >> 16, color >> 8, color );
  262.     XChangeGC( XDISPLAY, m_gc, GCForeground,  &gcVal );
  263.     XSetRegion( XDISPLAY, m_gc, m_mask );
  264.     XDrawRectangle( XDISPLAY, m_pixmap, m_gc, left, top, width - 1, height - 1 );
  265. }
  266. void X11Graphics::applyMaskToWindow( OSWindow &rWindow )
  267. {
  268.     // Get the target window
  269.     Window win = ((X11Window&)rWindow).getDrawable();
  270.     // Change the shape of the window
  271.     XShapeCombineRegion( XDISPLAY, win, ShapeBounding, 0, 0, m_mask,
  272.                          ShapeSet );
  273. }
  274. void X11Graphics::copyToWindow( OSWindow &rWindow, int xSrc,  int ySrc,
  275.                                 int width, int height, int xDest, int yDest )
  276. {
  277.     // Destination window
  278.     Drawable dest = ((X11Window&)rWindow).getDrawable();
  279.     XCopyArea( XDISPLAY, m_pixmap, dest, XGC, xSrc, ySrc, width, height,
  280.                xDest, yDest );
  281. }
  282. bool X11Graphics::hit( int x, int y ) const
  283. {
  284.     return XPointInRegion( m_mask, x, y );
  285. }
  286. inline void X11Graphics::addHSegmentInRegion( Region &rMask, int xStart,
  287.                                               int xEnd, int y )
  288. {
  289.     XRectangle rect;
  290.     rect.x = xStart;
  291.     rect.y = y;
  292.     rect.width = xEnd - xStart;
  293.     rect.height = 1;
  294.     Region newMask = XCreateRegion();
  295.     XUnionRectWithRegion( &rect, rMask, newMask );
  296.     XDestroyRegion( rMask );
  297.     rMask = newMask;
  298. }
  299. inline void X11Graphics::addVSegmentInRegion( Region &rMask, int yStart,
  300.                                               int yEnd, int x )
  301. {
  302.     XRectangle rect;
  303.     rect.x = x;
  304.     rect.y = yStart;
  305.     rect.width = 1;
  306.     rect.height = yEnd - yStart;
  307.     Region newMask = XCreateRegion();
  308.     XUnionRectWithRegion( &rect, rMask, newMask );
  309.     XDestroyRegion( rMask );
  310.     rMask = newMask;
  311. }
  312. #endif