1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2003 the VideoLAN team
7 * Authors: Cyril Deguet <asmax@via.ecp.fr>
8 * Olivier Teulière <ipkiss@via.ecp.fr>
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.
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.
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 *****************************************************************************/
29 #include <X11/Xutil.h>
30 #include <X11/extensions/shape.h>
32 #include "x11_display.hpp"
33 #include "x11_graphics.hpp"
34 #include "x11_window.hpp"
35 #include "../src/generic_bitmap.hpp"
38 X11Graphics::X11Graphics( intf_thread_t *pIntf, X11Display &rDisplay,
39 int width, int height ):
40 OSGraphics( pIntf ), m_rDisplay( rDisplay ), m_width( width ),
43 // Get the display paramaters
44 int screen = DefaultScreen( XDISPLAY );
45 int depth = DefaultDepth( XDISPLAY, screen );
47 // X11 doesn't accept that !
48 if( width == 0 || height == 0 )
50 // Avoid a X11 Bad Value error
52 msg_Err( getIntf(), "invalid image size (null width or height)" );
56 m_pixmap = XCreatePixmap( XDISPLAY, DefaultRootWindow( XDISPLAY ),
57 width, height, depth);
59 // Create the transparency mask (everything is transparent initially)
60 m_mask = XCreateRegion();
62 // Create a Graphics Context that does not generate GraphicsExpose events
64 xgcvalues.graphics_exposures = False;
65 m_gc = XCreateGC( XDISPLAY, m_pixmap, GCGraphicsExposures, &xgcvalues );
69 X11Graphics::~X11Graphics()
71 XFreeGC( XDISPLAY, m_gc );
72 XDestroyRegion( m_mask );
73 XFreePixmap( XDISPLAY, m_pixmap );
77 void X11Graphics::clear()
79 // Clear the transparency mask
80 XDestroyRegion( m_mask );
81 m_mask = XCreateRegion();
85 void X11Graphics::drawGraphics( const OSGraphics &rGraphics, int xSrc,
86 int ySrc, int xDest, int yDest, int width,
91 width = rGraphics.getWidth();
95 height = rGraphics.getHeight();
99 Drawable src = ((X11Graphics&)rGraphics).getDrawable();
101 // Create the mask for transparency
102 Region voidMask = XCreateRegion();
107 rect.height = height;
108 Region clipMask = XCreateRegion();
109 XUnionRectWithRegion( &rect, voidMask, clipMask );
110 Region mask = XCreateRegion();
111 XIntersectRegion( ((X11Graphics&)rGraphics).getMask(), clipMask, mask );
112 XDestroyRegion( clipMask );
113 XDestroyRegion( voidMask );
114 XOffsetRegion( mask, xDest - xSrc, yDest - ySrc );
117 XSetRegion( XDISPLAY, m_gc, mask );
118 XCopyArea( XDISPLAY, src, m_pixmap, m_gc, xSrc, ySrc, width, height,
121 // Add the source mask to the mask of the graphics
122 Region newMask = XCreateRegion();
123 XUnionRegion( m_mask, mask, newMask );
124 XDestroyRegion( mask );
125 XDestroyRegion( m_mask );
130 void X11Graphics::drawBitmap( const GenericBitmap &rBitmap, int xSrc,
131 int ySrc, int xDest, int yDest, int width,
132 int height, bool blend )
134 // Get the bitmap size if necessary
137 width = rBitmap.getWidth();
139 else if( width > rBitmap.getWidth() )
141 msg_Dbg( getIntf(), "bitmap width too small (%i)", rBitmap.getWidth() );
142 width = rBitmap.getWidth();
146 height = rBitmap.getHeight();
148 else if( height > rBitmap.getHeight() )
150 msg_Dbg( getIntf(), "bitmap height too small (%i)", rBitmap.getHeight()
152 height = rBitmap.getHeight();
155 // Nothing to draw if width or height is null
156 if( width == 0 || height == 0 )
161 // Safety check for debugging purpose
162 if( xDest + width > m_width || yDest + height > m_height )
164 msg_Dbg( getIntf(), "bitmap too large" );
168 // Get a buffer on the image data
169 uint8_t *pBmpData = rBitmap.getData();
170 if( pBmpData == NULL )
176 // Get the image from the pixmap
177 XImage *pImage = XGetImage( XDISPLAY, m_pixmap, xDest, yDest, width,
178 height, AllPlanes, ZPixmap );
181 msg_Dbg( getIntf(), "XGetImage returned NULL" );
184 char *pData = pImage->data;
186 // Get the padding of this image
187 int pad = pImage->bitmap_pad >> 3;
188 int shift = ( pad - ( (width * XPIXELSIZE) % pad ) ) % pad;
190 // Mask for transparency
191 Region mask = XCreateRegion();
193 // Get a pointer on the right X11Display::makePixel method
194 X11Display::MakePixelFunc_t makePixelFunc = ( blend ?
195 m_rDisplay.getBlendPixel() : m_rDisplay.getPutPixel() );
197 // Skip the first lines of the image
198 pBmpData += 4 * ySrc * rBitmap.getWidth();
200 // Copy the bitmap on the image and compute the mask
201 for( int y = 0; y < height; y++ )
203 // Skip uninteresting bytes at the beginning of the line
204 pBmpData += 4 * xSrc;
205 // Flag to say whether the previous pixel on the line was visible
206 bool wasVisible = false;
207 // Beginning of the current visible segment on the line
208 int visibleSegmentStart = 0;
209 for( int x = 0; x < width; x++ )
211 uint8_t b = *(pBmpData++);
212 uint8_t g = *(pBmpData++);
213 uint8_t r = *(pBmpData++);
214 uint8_t a = *(pBmpData++);
216 (m_rDisplay.*makePixelFunc)( (uint8_t*)pData, r, g, b, a );
223 // Beginning of a visible segment
224 visibleSegmentStart = x;
230 // Pixel is transparent
233 // End of a visible segment: add it to the mask
234 addHSegmentInRegion( mask, visibleSegmentStart, x, y );
241 // End of a visible segment: add it to the mask
242 addHSegmentInRegion( mask, visibleSegmentStart, width, y );
245 // Skip uninteresting bytes at the end of the line
246 pBmpData += 4 * (rBitmap.getWidth() - width - xSrc);
249 // Apply the mask to the graphics context
250 XOffsetRegion( mask, xDest, yDest );
251 XSetRegion( XDISPLAY, m_gc, mask );
252 // Copy the image on the pixmap
253 XPutImage( XDISPLAY, m_pixmap, m_gc, pImage, 0, 0, xDest, yDest, width,
255 XDestroyImage( pImage );
257 // Add the bitmap mask to the global graphics mask
258 Region newMask = XCreateRegion();
259 XUnionRegion( mask, m_mask, newMask );
260 XDestroyRegion( m_mask );
263 XDestroyRegion( mask );
267 void X11Graphics::fillRect( int left, int top, int width, int height,
270 // Update the mask with the rectangle area
271 Region newMask = XCreateRegion();
276 rect.height = height;
277 XUnionRectWithRegion( &rect, m_mask, newMask );
278 XDestroyRegion( m_mask );
281 // Draw the rectangle
283 gcVal.foreground = m_rDisplay.getPixelValue( color >> 16, color >> 8, color );
284 XChangeGC( XDISPLAY, m_gc, GCForeground, &gcVal );
285 XSetRegion( XDISPLAY, m_gc, m_mask );
286 XFillRectangle( XDISPLAY, m_pixmap, m_gc, left, top, width, height );
290 void X11Graphics::drawRect( int left, int top, int width, int height,
293 // Update the mask with the rectangle
294 addHSegmentInRegion( m_mask, left, left + width, top );
295 addHSegmentInRegion( m_mask, left, left + width, top + height );
296 addVSegmentInRegion( m_mask, top, top + height, left );
297 addVSegmentInRegion( m_mask, top, top + height, left + width );
299 // Draw the rectangle
301 gcVal.foreground = m_rDisplay.getPixelValue( color >> 16, color >> 8, color );
302 XChangeGC( XDISPLAY, m_gc, GCForeground, &gcVal );
303 XSetRegion( XDISPLAY, m_gc, m_mask );
304 XDrawRectangle( XDISPLAY, m_pixmap, m_gc, left, top, width - 1, height - 1 );
308 void X11Graphics::applyMaskToWindow( OSWindow &rWindow )
310 // Get the target window
311 Window win = ((X11Window&)rWindow).getDrawable();
313 // Change the shape of the window
314 XShapeCombineRegion( XDISPLAY, win, ShapeBounding, 0, 0, m_mask,
319 void X11Graphics::copyToWindow( OSWindow &rWindow, int xSrc, int ySrc,
320 int width, int height, int xDest, int yDest )
322 // Destination window
323 Drawable dest = ((X11Window&)rWindow).getDrawable();
325 XCopyArea( XDISPLAY, m_pixmap, dest, XGC, xSrc, ySrc, width, height,
330 bool X11Graphics::hit( int x, int y ) const
332 return XPointInRegion( m_mask, x, y );
336 inline void X11Graphics::addHSegmentInRegion( Region &rMask, int xStart,
342 rect.width = xEnd - xStart;
344 Region newMask = XCreateRegion();
345 XUnionRectWithRegion( &rect, rMask, newMask );
346 XDestroyRegion( rMask );
351 inline void X11Graphics::addVSegmentInRegion( Region &rMask, int yStart,
358 rect.height = yEnd - yStart;
359 Region newMask = XCreateRegion();
360 XUnionRectWithRegion( &rect, rMask, newMask );
361 XDestroyRegion( rMask );