Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/modules/gui/skins2/x11/   (VLC Media Plyer ©)  Datei vom 23.9.2026 mit Größe 12 kB image not shown  

Quelle  x11_graphics.cpp   Sprache: C

 

/*****************************************************************************
 * x11_graphics.cpp
 *****************************************************************************
 * Copyright (C) 2003 the VideoLAN team
 *
 * Authors: Cyril Deguet     <asmax@via.ecp.fr>
 *          Olivier Teulière <ipkiss@via.ecp.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/


#ifdef X11_SKINS

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/shape.h>

#include "x11_display.hpp"
#include "x11_graphics.hpp"
#include "x11_window.hpp"
#include "../src/generic_bitmap.hpp"
#include "../utils/position.hpp"


X11Graphics::X11Graphics( intf_thread_t *pIntf, X11Display &rDisplay,
                          int width, int height ):
    OSGraphics( pIntf ), m_rDisplay( rDisplay ), m_width( width ),
    m_height( height )
{
    // Get the display parameters
    int screen = DefaultScreen( XDISPLAY );
    int depth = DefaultDepth( XDISPLAY, screen );

    // X11 doesn't accept that !
    if( width == 0 || height == 0 )
    {
        // Avoid a X11 Bad Value error
        width = height = 1;
        msg_Err( getIntf(), "invalid image size (null width or height)" );
    }

    // Create a pixmap
    m_pixmap = XCreatePixmap( XDISPLAY, DefaultRootWindow( XDISPLAY ),
                              width, height, depth);

    // Create the transparency mask (everything is transparent initially)
    m_mask = XCreateRegion();

    // Create a Graphics Context that does not generate GraphicsExpose events
    XGCValues xgcvalues;
    xgcvalues.graphics_exposures = False;
    m_gc = XCreateGC( XDISPLAY, m_pixmap, GCGraphicsExposures, &xgcvalues );
}


X11Graphics::~X11Graphics()
{
    XFreeGC( XDISPLAY, m_gc );
    XDestroyRegion( m_mask );
    XFreePixmap( XDISPLAY, m_pixmap );
}


void X11Graphics::clear( int xDest, int yDest, int width, int height )
{
    if( width <= 0 || height <= 0 )
    {
        // Clear the transparency mask completely
        XDestroyRegion( m_mask );
        m_mask = XCreateRegion();
    }
    else
    {
        // remove this area from the mask
        XRectangle rect;
        rect.x = xDest;
        rect.y = yDest;
        rect.width = width;
        rect.height = height;
        Region regMask = XCreateRegion();
        XUnionRectWithRegion( &rect, regMask, regMask );
        XSubtractRegion( m_mask, regMask, m_mask );
        XDestroyRegion( regMask );
    }
}


void X11Graphics::drawGraphics( const OSGraphics &rGraphics, int xSrc,
                                int ySrc, int xDest, int yDest, int width,
                                int height )
{
    const X11Graphics& rGraph = (X11Graphics&)rGraphics;

    // check and adapt to source if needed
    if( !checkBoundaries( 0, 0, rGraph.getWidth(), rGraph.getHeight(),
                          xSrc, ySrc, width, height ) )
    {
        msg_Err( getIntf(), "nothing to draw from graphics source" );
        return;
    }

    // check destination
    if( !checkBoundaries( 0, 0, m_width, m_height,
                          xDest, yDest, width, height ) )
    {
        msg_Err( getIntf(), "out of reach destination! pls, debug your skin" );
        return;
    }

    // Source drawable
    Drawable src = rGraph.getDrawable();

    // Create the mask for transparency
    Region voidMask = XCreateRegion();
    XRectangle rect;
    rect.x = xSrc;
    rect.y = ySrc;
    rect.width = width;
    rect.height = height;
    Region clipMask = XCreateRegion();
    XUnionRectWithRegion( &rect, voidMask, clipMask );
    Region mask = XCreateRegion();
    XIntersectRegion( rGraph.getMask(), clipMask, mask );
    XDestroyRegion( clipMask );
    XDestroyRegion( voidMask );
    XOffsetRegion( mask, xDest - xSrc, yDest - ySrc );

    // Copy the pixmap
    XSetRegion( XDISPLAY, m_gc, mask );
    XCopyArea( XDISPLAY, src, m_pixmap, m_gc, xSrc, ySrc, width, height,
               xDest, yDest );

    // Add the source mask to the mask of the graphics
    Region newMask = XCreateRegion();
    XUnionRegion( m_mask, mask, newMask );
    XDestroyRegion( mask );
    XDestroyRegion( m_mask );
    m_mask = newMask;
}


void X11Graphics::drawBitmap( const GenericBitmap &rBitmap, int xSrc,
                              int ySrc, int xDest, int yDest, int width,
                              int height, bool blend )
{
    // check and adapt to source if needed
    if( !checkBoundaries( 0, 0, rBitmap.getWidth(), rBitmap.getHeight(),
                          xSrc, ySrc, width, height ) )
    {
        msg_Err( getIntf(), "empty source! pls, debug your skin" );
        return;
    }

    // check destination
    if( !checkBoundaries( 0, 0, m_width, m_height,
                          xDest, yDest, width, height ) )
    {
        msg_Err( getIntf(), "out of reach destination! pls, debug your skin" );
        return;
    }

    // Get a buffer on the image data
    uint8_t *pBmpData = rBitmap.getData();
    if( pBmpData == NULL )
    {
        // Nothing to draw
        return;
    }

    // Force pending XCopyArea to be sent to the X Server
    // before issuing an XGetImage.
    XSync( XDISPLAY, False );

    // Get the image from the pixmap
    XImage *pImage = XGetImage( XDISPLAY, m_pixmap, xDest, yDest, width,
                                height, AllPlanes, ZPixmap );
    if( pImage == NULL )
    {
        msg_Dbg( getIntf(), "XGetImage returned NULL" );
        return;
    }
    char *pData = pImage->data;

    // Get the padding of this image
    int pad = pImage->bitmap_pad >> 3;
    int shift = ( pad - ( (width * XPIXELSIZE) % pad ) ) % pad;

    // Mask for transparency
    Region mask = XCreateRegion();

    // Get a pointer on the right X11Display::makePixel method
    X11Display::MakePixelFunc_t makePixelFunc = ( blend ?
        m_rDisplay.getBlendPixel() : m_rDisplay.getPutPixel() );

    // Skip the first lines of the image
    pBmpData += 4 * ySrc * rBitmap.getWidth();

    // Copy the bitmap on the image and compute the mask
    for( int y = 0; y < height; y++ )
    {
        // Skip uninteresting bytes at the beginning of the line
        pBmpData += 4 * xSrc;
        // Flag to say whether the previous pixel on the line was visible
        bool wasVisible = false;
        // Beginning of the current visible segment on the line
        int visibleSegmentStart = 0;
        for( int x = 0; x < width; x++ )
        {
            uint8_t b = *(pBmpData++);
            uint8_t g = *(pBmpData++);
            uint8_t r = *(pBmpData++);
            uint8_t a = *(pBmpData++);
            // Draw the pixel
            (m_rDisplay.*makePixelFunc)( (uint8_t*)pData, r, g, b, a );
            pData += XPIXELSIZE;
            if( a > 0 )
            {
                // Pixel is visible
                if( ! wasVisible )
                {
                    // Beginning of a visible segment
                    visibleSegmentStart = x;
                }
                wasVisible = true;
            }
            else
            {
                // Pixel is transparent
                if( wasVisible )
                {
                    // End of a visible segment: add it to the mask
                    addHSegmentInRegion( mask, visibleSegmentStart, x, y );
                }
                wasVisible = false;
            }
        }
        if( wasVisible )
        {
            // End of a visible segment: add it to the mask
            addHSegmentInRegion( mask, visibleSegmentStart, width, y );
        }
        pData += shift;
        // Skip uninteresting bytes at the end of the line
        pBmpData += 4 * (rBitmap.getWidth() - width - xSrc);
    }

    // Apply the mask to the graphics context
    XOffsetRegion( mask, xDest, yDest );
    XSetRegion( XDISPLAY, m_gc, mask );
    // Copy the image on the pixmap
    XPutImage( XDISPLAY, m_pixmap, m_gc, pImage, 0, 0, xDest, yDest, width,
               height);
    XDestroyImage( pImage );

    // Add the bitmap mask to the global graphics mask
    Region newMask = XCreateRegion();
    XUnionRegion( mask, m_mask, newMask );
    XDestroyRegion( m_mask );
    m_mask = newMask;

    XDestroyRegion( mask );
}


void X11Graphics::fillRect( int left, int top, int width, int height,
                            uint32_t color )
{
    // Update the mask with the rectangle area
    Region newMask = XCreateRegion();
    XRectangle rect;
    rect.x = left;
    rect.y = top;
    rect.width = width;
    rect.height = height;
    XUnionRectWithRegion( &rect, m_mask, newMask );
    XDestroyRegion( m_mask );
    m_mask = newMask;

    // Draw the rectangle
    XGCValues gcVal;
    gcVal.foreground = m_rDisplay.getPixelValue( color >> 16, color >> 8, color );
    XChangeGC( XDISPLAY, m_gc, GCForeground,  &gcVal );
    XSetRegion( XDISPLAY, m_gc, m_mask );
    XFillRectangle( XDISPLAY, m_pixmap, m_gc, left, top, width, height );
}


void X11Graphics::drawRect( int left, int top, int width, int height,
                            uint32_t color )
{
    // Update the mask with the rectangle
    addHSegmentInRegion( m_mask, left, left + width, top );
    addHSegmentInRegion( m_mask, left, left + width, top + height );
    addVSegmentInRegion( m_mask, top, top + height, left );
    addVSegmentInRegion( m_mask, top, top + height, left + width );

    // Draw the rectangle
    XGCValues gcVal;
    gcVal.foreground = m_rDisplay.getPixelValue( color >> 16, color >> 8, color );
    XChangeGC( XDISPLAY, m_gc, GCForeground,  &gcVal );
    XSetRegion( XDISPLAY, m_gc, m_mask );
    XDrawRectangle( XDISPLAY, m_pixmap, m_gc, left, top, width - 1, height - 1 );
}


void X11Graphics::applyMaskToWindow( OSWindow &rWindow )
{
    // Get the target window
    Window win = ((X11Window&)rWindow).getDrawable();

    // ensure the window size is right
    XResizeWindow( XDISPLAY, win, m_width, m_height );

    // Change the shape of the window
    XShapeCombineRegion( XDISPLAY, win, ShapeBounding, 0, 0, m_mask,
                         ShapeSet );
}


void X11Graphics::copyToWindow( OSWindow &rWindow, int xSrc,  int ySrc,
                                int width, int height, int xDest, int yDest )
{
    // Destination window
    Drawable dest = ((X11Window&)rWindow).getDrawable();

    XCopyArea( XDISPLAY, m_pixmap, dest, XGC, xSrc, ySrc, width, height,
               xDest, yDest );
}


bool X11Graphics::hit( int x, int y ) const
{
    return XPointInRegion( m_mask, x, y );
}


inline void X11Graphics::addHSegmentInRegion( Region &rMask, int xStart,
                                              int xEnd, int y )
{
    XRectangle rect;
    rect.x = xStart;
    rect.y = y;
    rect.width = xEnd - xStart;
    rect.height = 1;
    Region newMask = XCreateRegion();
    XUnionRectWithRegion( &rect, rMask, newMask );
    XDestroyRegion( rMask );
    rMask = newMask;
}


inline void X11Graphics::addVSegmentInRegion( Region &rMask, int yStart,
                                              int yEnd, int x )
{
    XRectangle rect;
    rect.x = x;
    rect.y = yStart;
    rect.width = 1;
    rect.height = yEnd - yStart;
    Region newMask = XCreateRegion();
    XUnionRectWithRegion( &rect, rMask, newMask );
    XDestroyRegion( rMask );
    rMask = newMask;
}

bool X11Graphics::checkBoundaries( int x_src, int y_src,
                                   int w_src, int h_src,
                                   int& x_target, int& y_target,
                                   int& w_target, int& h_target )
{
    // set valid width and height
    w_target = (w_target > 0) ? w_target : w_src;
    h_target = (h_target > 0) ? h_target : h_src;

    // clip source if needed
    rect srcRegion( x_src, y_src, w_src, h_src );
    rect targetRegion( x_target, y_target, w_target, h_target );
    rect inter;
    if( rect::intersect( srcRegion, targetRegion, &inter ) )
    {
        x_target = inter.x;
        y_target = inter.y;
        w_target = inter.width;
        h_target = inter.height;
        return true;
    }
    return false;
}

#endif

Messung
CHZG
89999694

¤ Dauer der Verarbeitung: 0.6 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.