00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
00044 int screen = DefaultScreen( XDISPLAY );
00045 int depth = DefaultDepth( XDISPLAY, screen );
00046
00047
00048 if( width == 0 || height == 0 )
00049 {
00050
00051 width = height = 1;
00052 msg_Err( getIntf(), "Invalid image size (null width or height)" );
00053 }
00054
00055
00056 m_pixmap = XCreatePixmap( XDISPLAY, DefaultRootWindow( XDISPLAY ),
00057 width, height, depth);
00058
00059
00060 m_mask = XCreateRegion();
00061
00062
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
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
00099 Drawable src = ((X11Graphics&)rGraphics).getDrawable();
00100
00101
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
00117 XSetRegion( XDISPLAY, m_gc, mask );
00118 XCopyArea( XDISPLAY, src, m_pixmap, m_gc, xSrc, ySrc, width, height,
00119 xDest, yDest );
00120
00121
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
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
00155 if( width == 0 || height == 0 )
00156 {
00157 return;
00158 }
00159
00160
00161 if( xDest + width > m_width || yDest + height > m_height )
00162 {
00163 msg_Dbg( getIntf(), "Bitmap too large !" );
00164 return;
00165 }
00166
00167
00168 uint8_t *pBmpData = rBitmap.getData();
00169 if( pBmpData == NULL )
00170 {
00171
00172 return;
00173 }
00174
00175
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
00186 int pad = pImage->bitmap_pad >> 3;
00187 int shift = ( pad - ( (width * XPIXELSIZE) % pad ) ) % pad;
00188
00189
00190 Region mask = XCreateRegion();
00191
00192
00193 X11Display::MakePixelFunc_t makePixelFunc = ( blend ?
00194 m_rDisplay.getBlendPixel() : m_rDisplay.getPutPixel() );
00195
00196
00197 pBmpData += 4 * ySrc * rBitmap.getWidth();
00198
00199
00200 for( int y = 0; y < height; y++ )
00201 {
00202
00203 pBmpData += 4 * xSrc;
00204
00205 bool wasVisible = false;
00206
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
00215 (m_rDisplay.*makePixelFunc)( (uint8_t*)pData, r, g, b, a );
00216 pData += XPIXELSIZE;
00217 if( a > 0 )
00218 {
00219
00220 if( ! wasVisible )
00221 {
00222
00223 visibleSegmentStart = x;
00224 }
00225 wasVisible = true;
00226 }
00227 else
00228 {
00229
00230 if( wasVisible )
00231 {
00232
00233 addHSegmentInRegion( mask, visibleSegmentStart, x, y );
00234 }
00235 wasVisible = false;
00236 }
00237 }
00238 if( wasVisible )
00239 {
00240
00241 addHSegmentInRegion( mask, visibleSegmentStart, width, y );
00242 }
00243 pData += shift;
00244
00245 pBmpData += 4 * (rBitmap.getWidth() - width - xSrc);
00246 }
00247
00248
00249 XOffsetRegion( mask, xDest, yDest );
00250 XSetRegion( XDISPLAY, m_gc, mask );
00251
00252 XPutImage( XDISPLAY, m_pixmap, m_gc, pImage, 0, 0, xDest, yDest, width,
00253 height);
00254 XDestroyImage( pImage );
00255
00256
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
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
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
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
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
00310 Window win = ((X11Window&)rWindow).getDrawable();
00311
00312
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
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