Commit 8efd4540 authored by Alexandre Julliard's avatar Alexandre Julliard

Removed CALL_LARGE_STACK support.

parent 16a9a2d7
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#include "wine/winbase16.h" #include "wine/winbase16.h"
#include "winreg.h" #include "winreg.h"
#include "callback.h"
#include "debugtools.h" #include "debugtools.h"
#include "gdi.h" #include "gdi.h"
#include "options.h" #include "options.h"
...@@ -257,11 +256,6 @@ static void create_desktop( const char *geometry ) ...@@ -257,11 +256,6 @@ static void create_desktop( const char *geometry )
TSXMapWindow( display, root_window ); TSXMapWindow( display, root_window );
} }
/* Created so that XOpenIM can be called using the 'large stack' */
static void XOpenIM_large_stack(void)
{
TSXOpenIM(display,NULL,NULL,NULL);
}
/*********************************************************************** /***********************************************************************
* X11DRV process initialisation routine * X11DRV process initialisation routine
...@@ -315,7 +309,7 @@ static void process_attach(void) ...@@ -315,7 +309,7 @@ static void process_attach(void)
* them to work in Wine, even whith a libX11 including the dead key * them to work in Wine, even whith a libX11 including the dead key
* patches from Th.Quinot (http://Web.FdN.FR/~tquinot/dead-keys.en.html) * patches from Th.Quinot (http://Web.FdN.FR/~tquinot/dead-keys.en.html)
*/ */
CALL_LARGE_STACK( XOpenIM_large_stack, NULL ); TSXOpenIM( display, NULL, NULL, NULL);
if (Options.synchronous) XSetErrorHandler( error_handler ); if (Options.synchronous) XSetErrorHandler( error_handler );
......
...@@ -13,8 +13,10 @@ ...@@ -13,8 +13,10 @@
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "bitmap.h" #include "bitmap.h"
#include "callback.h"
#include "color.h" #include "color.h"
#include "gdi.h" #include "gdi.h"
#include "metafile.h" #include "metafile.h"
...@@ -1421,34 +1423,6 @@ static BOOL BITBLT_InternalStretchBlt( DC *dcDst, INT xDst, INT yDst, ...@@ -1421,34 +1423,6 @@ static BOOL BITBLT_InternalStretchBlt( DC *dcDst, INT xDst, INT yDst,
return TRUE; return TRUE;
} }
struct StretchBlt_params
{
DC *dcDst;
INT xDst;
INT yDst;
INT widthDst;
INT heightDst;
DC *dcSrc;
INT xSrc;
INT ySrc;
INT widthSrc;
INT heightSrc;
DWORD rop;
};
/***********************************************************************
* BITBLT_DoStretchBlt
*
* Wrapper function for BITBLT_InternalStretchBlt
* to use with CALL_LARGE_STACK.
*/
static int BITBLT_DoStretchBlt( const struct StretchBlt_params *p )
{
return (int)BITBLT_InternalStretchBlt( p->dcDst, p->xDst, p->yDst,
p->widthDst, p->heightDst,
p->dcSrc, p->xSrc, p->ySrc,
p->widthSrc, p->heightSrc, p->rop );
}
/*********************************************************************** /***********************************************************************
* X11DRV_PatBlt * X11DRV_PatBlt
...@@ -1456,25 +1430,12 @@ static int BITBLT_DoStretchBlt( const struct StretchBlt_params *p ) ...@@ -1456,25 +1430,12 @@ static int BITBLT_DoStretchBlt( const struct StretchBlt_params *p )
BOOL X11DRV_PatBlt( DC *dc, INT left, INT top, BOOL X11DRV_PatBlt( DC *dc, INT left, INT top,
INT width, INT height, DWORD rop ) INT width, INT height, DWORD rop )
{ {
struct StretchBlt_params params;
BOOL result; BOOL result;
params.dcDst = dc;
params.xDst = left;
params.yDst = top;
params.widthDst = width;
params.heightDst = height;
params.dcSrc = NULL;
params.xSrc = 0;
params.ySrc = 0;
params.widthSrc = 0;
params.heightSrc = 0;
params.rop = rop;
X11DRV_LockDIBSection( dc, DIB_Status_GdiMod, FALSE ); X11DRV_LockDIBSection( dc, DIB_Status_GdiMod, FALSE );
EnterCriticalSection( &X11DRV_CritSection ); wine_tsx11_lock();
result = (BOOL)CALL_LARGE_STACK( BITBLT_DoStretchBlt, &params ); result = BITBLT_InternalStretchBlt( dc, left, top, width, height, NULL, 0, 0, 0, 0, rop );
LeaveCriticalSection( &X11DRV_CritSection ); wine_tsx11_unlock();
X11DRV_UnlockDIBSection( dc, TRUE ); X11DRV_UnlockDIBSection( dc, TRUE );
return result; return result;
} }
...@@ -1487,7 +1448,6 @@ BOOL X11DRV_BitBlt( DC *dcDst, INT xDst, INT yDst, ...@@ -1487,7 +1448,6 @@ BOOL X11DRV_BitBlt( DC *dcDst, INT xDst, INT yDst,
INT width, INT height, DC *dcSrc, INT width, INT height, DC *dcSrc,
INT xSrc, INT ySrc, DWORD rop ) INT xSrc, INT ySrc, DWORD rop )
{ {
struct StretchBlt_params params;
BOOL result = FALSE; BOOL result = FALSE;
INT sSrc, sDst; INT sSrc, sDst;
RECT visRectDst, visRectSrc; RECT visRectDst, visRectSrc;
...@@ -1515,7 +1475,7 @@ BOOL X11DRV_BitBlt( DC *dcDst, INT xDst, INT yDst, ...@@ -1515,7 +1475,7 @@ BOOL X11DRV_BitBlt( DC *dcDst, INT xDst, INT yDst,
dcSrc, xSrc, ySrc, width, height, dcSrc, xSrc, ySrc, width, height,
&visRectSrc, &visRectDst )) &visRectSrc, &visRectDst ))
goto END; goto END;
xSrc = visRectSrc.left; xSrc = visRectSrc.left;
ySrc = visRectSrc.top; ySrc = visRectSrc.top;
xDst = visRectDst.left; xDst = visRectDst.left;
...@@ -1533,24 +1493,13 @@ BOOL X11DRV_BitBlt( DC *dcDst, INT xDst, INT yDst, ...@@ -1533,24 +1493,13 @@ BOOL X11DRV_BitBlt( DC *dcDst, INT xDst, INT yDst,
goto END; goto END;
} }
params.dcDst = dcDst;
params.xDst = xDst;
params.yDst = yDst;
params.widthDst = width;
params.heightDst = height;
params.dcSrc = dcSrc;
params.xSrc = xSrc;
params.ySrc = ySrc;
params.widthSrc = width;
params.heightSrc = height;
params.rop = rop;
X11DRV_CoerceDIBSection( dcDst, DIB_Status_GdiMod, FALSE ); X11DRV_CoerceDIBSection( dcDst, DIB_Status_GdiMod, FALSE );
X11DRV_CoerceDIBSection( dcSrc, DIB_Status_GdiMod, FALSE ); X11DRV_CoerceDIBSection( dcSrc, DIB_Status_GdiMod, FALSE );
EnterCriticalSection( &X11DRV_CritSection ); wine_tsx11_lock();
result = (BOOL)CALL_LARGE_STACK( BITBLT_DoStretchBlt, &params ); result = BITBLT_InternalStretchBlt( dcDst, xDst, yDst, width, height,
LeaveCriticalSection( &X11DRV_CritSection ); dcSrc, xSrc, ySrc, width, height, rop );
wine_tsx11_unlock();
END: END:
X11DRV_UnlockDIBSection( dcSrc, FALSE ); X11DRV_UnlockDIBSection( dcSrc, FALSE );
...@@ -1568,27 +1517,15 @@ BOOL X11DRV_StretchBlt( DC *dcDst, INT xDst, INT yDst, ...@@ -1568,27 +1517,15 @@ BOOL X11DRV_StretchBlt( DC *dcDst, INT xDst, INT yDst,
DC *dcSrc, INT xSrc, INT ySrc, DC *dcSrc, INT xSrc, INT ySrc,
INT widthSrc, INT heightSrc, DWORD rop ) INT widthSrc, INT heightSrc, DWORD rop )
{ {
struct StretchBlt_params params;
BOOL result; BOOL result;
params.dcDst = dcDst;
params.xDst = xDst;
params.yDst = yDst;
params.widthDst = widthDst;
params.heightDst = heightDst;
params.dcSrc = dcSrc;
params.xSrc = xSrc;
params.ySrc = ySrc;
params.widthSrc = widthSrc;
params.heightSrc = heightSrc;
params.rop = rop;
X11DRV_LockDIBSection( dcDst, DIB_Status_GdiMod, FALSE ); X11DRV_LockDIBSection( dcDst, DIB_Status_GdiMod, FALSE );
X11DRV_LockDIBSection( dcSrc, DIB_Status_GdiMod, FALSE ); X11DRV_LockDIBSection( dcSrc, DIB_Status_GdiMod, FALSE );
EnterCriticalSection( &X11DRV_CritSection ); wine_tsx11_lock();
result = (BOOL)CALL_LARGE_STACK( BITBLT_DoStretchBlt, &params ); result = BITBLT_InternalStretchBlt( dcDst, xDst, yDst, widthDst, heightDst,
LeaveCriticalSection( &X11DRV_CritSection ); dcSrc, xSrc, ySrc, widthSrc, heightSrc, rop );
wine_tsx11_unlock();
X11DRV_UnlockDIBSection( dcSrc, FALSE ); X11DRV_UnlockDIBSection( dcSrc, FALSE );
X11DRV_UnlockDIBSection( dcDst, TRUE ); X11DRV_UnlockDIBSection( dcDst, TRUE );
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "gdi.h" #include "gdi.h"
#include "callback.h"
#include "bitmap.h" #include "bitmap.h"
#include "heap.h" #include "heap.h"
#include "debugtools.h" #include "debugtools.h"
...@@ -110,27 +109,6 @@ HBITMAP X11DRV_BITMAP_SelectObject( DC * dc, HBITMAP hbitmap, ...@@ -110,27 +109,6 @@ HBITMAP X11DRV_BITMAP_SelectObject( DC * dc, HBITMAP hbitmap,
} }
/***********************************************************************
* XPutImage_wrapper
*
* Wrapper to call XPutImage with CALL_LARGE_STACK.
*/
struct XPutImage_descr
{
BITMAPOBJ *bmp;
XImage *image;
INT width;
INT height;
};
static int XPutImage_wrapper( const struct XPutImage_descr *descr )
{
return XPutImage( display, (Pixmap)descr->bmp->physBitmap, BITMAP_GC(descr->bmp),
descr->image, 0, 0, 0, 0, descr->width, descr->height );
}
/**************************************************************************** /****************************************************************************
* *
* X11DRV_CreateBitmap * X11DRV_CreateBitmap
...@@ -190,19 +168,6 @@ BOOL X11DRV_CreateBitmap( HBITMAP hbitmap ) ...@@ -190,19 +168,6 @@ BOOL X11DRV_CreateBitmap( HBITMAP hbitmap )
/*********************************************************************** /***********************************************************************
* X11DRV_BITMAP_GetXImage
*
* Get an X image for a bitmap. For use with CALL_LARGE_STACK.
*/
XImage *X11DRV_BITMAP_GetXImage( const BITMAPOBJ *bmp )
{
return XGetImage( display, (Pixmap)bmp->physBitmap,
0, 0, bmp->bitmap.bmWidth, bmp->bitmap.bmHeight,
AllPlanes, ZPixmap );
}
/***********************************************************************
* X11DRV_GetBitmapBits * X11DRV_GetBitmapBits
* *
* RETURNS * RETURNS
...@@ -218,7 +183,7 @@ static LONG X11DRV_GetBitmapBits(BITMAPOBJ *bmp, void *buffer, LONG count) ...@@ -218,7 +183,7 @@ static LONG X11DRV_GetBitmapBits(BITMAPOBJ *bmp, void *buffer, LONG count)
TRACE("(bmp=%p, buffer=%p, count=0x%lx)\n", bmp, buffer, count); TRACE("(bmp=%p, buffer=%p, count=0x%lx)\n", bmp, buffer, count);
EnterCriticalSection( &X11DRV_CritSection ); wine_tsx11_lock();
/* Hack: change the bitmap height temporarily to avoid */ /* Hack: change the bitmap height temporarily to avoid */
/* getting unnecessary bitmap rows. */ /* getting unnecessary bitmap rows. */
...@@ -226,8 +191,9 @@ static LONG X11DRV_GetBitmapBits(BITMAPOBJ *bmp, void *buffer, LONG count) ...@@ -226,8 +191,9 @@ static LONG X11DRV_GetBitmapBits(BITMAPOBJ *bmp, void *buffer, LONG count)
old_height = bmp->bitmap.bmHeight; old_height = bmp->bitmap.bmHeight;
height = bmp->bitmap.bmHeight = count / bmp->bitmap.bmWidthBytes; height = bmp->bitmap.bmHeight = count / bmp->bitmap.bmWidthBytes;
image = (XImage *)CALL_LARGE_STACK( X11DRV_BITMAP_GetXImage, bmp ); image = XGetImage( display, (Pixmap)bmp->physBitmap,
0, 0, bmp->bitmap.bmWidth, bmp->bitmap.bmHeight,
AllPlanes, ZPixmap );
bmp->bitmap.bmHeight = old_height; bmp->bitmap.bmHeight = old_height;
/* copy XImage to 16 bit padded image buffer with real bitsperpixel */ /* copy XImage to 16 bit padded image buffer with real bitsperpixel */
...@@ -322,8 +288,7 @@ static LONG X11DRV_GetBitmapBits(BITMAPOBJ *bmp, void *buffer, LONG count) ...@@ -322,8 +288,7 @@ static LONG X11DRV_GetBitmapBits(BITMAPOBJ *bmp, void *buffer, LONG count)
FIXME("Unhandled bits:%d\n", bmp->bitmap.bmBitsPixel); FIXME("Unhandled bits:%d\n", bmp->bitmap.bmBitsPixel);
} }
XDestroyImage( image ); XDestroyImage( image );
LeaveCriticalSection( &X11DRV_CritSection ); wine_tsx11_unlock();
return count; return count;
} }
...@@ -338,7 +303,6 @@ static LONG X11DRV_GetBitmapBits(BITMAPOBJ *bmp, void *buffer, LONG count) ...@@ -338,7 +303,6 @@ static LONG X11DRV_GetBitmapBits(BITMAPOBJ *bmp, void *buffer, LONG count)
*/ */
static LONG X11DRV_SetBitmapBits(BITMAPOBJ *bmp, void *bits, LONG count) static LONG X11DRV_SetBitmapBits(BITMAPOBJ *bmp, void *bits, LONG count)
{ {
struct XPutImage_descr descr;
LONG height; LONG height;
XImage *image; XImage *image;
LPBYTE sbuf, startline; LPBYTE sbuf, startline;
...@@ -348,14 +312,14 @@ static LONG X11DRV_SetBitmapBits(BITMAPOBJ *bmp, void *bits, LONG count) ...@@ -348,14 +312,14 @@ static LONG X11DRV_SetBitmapBits(BITMAPOBJ *bmp, void *bits, LONG count)
height = count / bmp->bitmap.bmWidthBytes; height = count / bmp->bitmap.bmWidthBytes;
EnterCriticalSection( &X11DRV_CritSection ); wine_tsx11_lock();
image = XCreateImage( display, X11DRV_GetVisual(), bmp->bitmap.bmBitsPixel, ZPixmap, 0, NULL, image = XCreateImage( display, X11DRV_GetVisual(), bmp->bitmap.bmBitsPixel, ZPixmap, 0, NULL,
bmp->bitmap.bmWidth, height, 32, 0 ); bmp->bitmap.bmWidth, height, 32, 0 );
if (!(image->data = (LPBYTE)malloc(image->bytes_per_line * height))) if (!(image->data = (LPBYTE)malloc(image->bytes_per_line * height)))
{ {
WARN("No memory to create image data.\n"); WARN("No memory to create image data.\n");
XDestroyImage( image ); XDestroyImage( image );
LeaveCriticalSection( &X11DRV_CritSection ); wine_tsx11_unlock();
return 0; return 0;
} }
...@@ -440,16 +404,10 @@ static LONG X11DRV_SetBitmapBits(BITMAPOBJ *bmp, void *bits, LONG count) ...@@ -440,16 +404,10 @@ static LONG X11DRV_SetBitmapBits(BITMAPOBJ *bmp, void *bits, LONG count)
FIXME("Unhandled bits:%d\n", bmp->bitmap.bmBitsPixel); FIXME("Unhandled bits:%d\n", bmp->bitmap.bmBitsPixel);
} }
XPutImage( display, (Pixmap)bmp->physBitmap, BITMAP_GC(bmp),
descr.bmp = bmp; image, 0, 0, 0, 0, bmp->bitmap.bmWidth, height );
descr.image = image;
descr.width = bmp->bitmap.bmWidth;
descr.height = height;
CALL_LARGE_STACK( XPutImage_wrapper, &descr );
XDestroyImage( image ); /* frees image->data too */ XDestroyImage( image ); /* frees image->data too */
LeaveCriticalSection( &X11DRV_CritSection ); wine_tsx11_unlock();
return count; return count;
} }
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#include "debugtools.h" #include "debugtools.h"
#include "gdi.h" #include "gdi.h"
#include "color.h" #include "color.h"
#include "callback.h"
#include "selectors.h" #include "selectors.h"
#include "global.h" #include "global.h"
...@@ -37,6 +36,35 @@ static int ximageDepthTable[] = { 0, 0, 0, 0, 0, 0, 0 }; ...@@ -37,6 +36,35 @@ static int ximageDepthTable[] = { 0, 0, 0, 0, 0, 0, 0 };
static int XShmErrorFlag = 0; static int XShmErrorFlag = 0;
/* This structure holds the arguments for DIB_SetImageBits() */
typedef struct
{
struct tagDC *dc;
LPCVOID bits;
XImage *image;
PALETTEENTRY *palentry;
int lines;
DWORD infoWidth;
WORD depth;
WORD infoBpp;
WORD compression;
RGBQUAD *colorMap;
int nColorMap;
Drawable drawable;
GC gc;
int xSrc;
int ySrc;
int xDest;
int yDest;
int width;
int height;
DWORD rMask;
DWORD gMask;
DWORD bMask;
BOOL useShm;
int dibpitch;
} X11DRV_DIB_IMAGEBITS_DESCR;
/*********************************************************************** /***********************************************************************
* X11DRV_DIB_Init * X11DRV_DIB_Init
*/ */
...@@ -2608,13 +2636,13 @@ static void X11DRV_DIB_GetImageBits_32( int lines, BYTE *dstbits, ...@@ -2608,13 +2636,13 @@ static void X11DRV_DIB_GetImageBits_32( int lines, BYTE *dstbits,
* *
* Transfer the bits to an X image. * Transfer the bits to an X image.
* Helper function for SetDIBits() and SetDIBitsToDevice(). * Helper function for SetDIBits() and SetDIBitsToDevice().
* The Xlib critical section must be entered before calling this function.
*/ */
int X11DRV_DIB_SetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr ) static int X11DRV_DIB_SetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr )
{ {
int lines = descr->lines >= 0 ? descr->lines : -descr->lines; int lines = descr->lines >= 0 ? descr->lines : -descr->lines;
XImage *bmpImage; XImage *bmpImage;
wine_tsx11_lock();
if (descr->image) if (descr->image)
bmpImage = descr->image; bmpImage = descr->image;
else { else {
...@@ -2624,6 +2652,7 @@ int X11DRV_DIB_SetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr ) ...@@ -2624,6 +2652,7 @@ int X11DRV_DIB_SetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr )
if(bmpImage->data == NULL) { if(bmpImage->data == NULL) {
ERR("Out of memory!\n"); ERR("Out of memory!\n");
XDestroyImage( bmpImage ); XDestroyImage( bmpImage );
wine_tsx11_unlock();
return lines; return lines;
} }
} }
...@@ -2709,6 +2738,7 @@ int X11DRV_DIB_SetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr ) ...@@ -2709,6 +2738,7 @@ int X11DRV_DIB_SetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr )
descr->width, descr->height ); descr->width, descr->height );
if (!descr->image) XDestroyImage( bmpImage ); if (!descr->image) XDestroyImage( bmpImage );
wine_tsx11_unlock();
return lines; return lines;
} }
...@@ -2716,14 +2746,14 @@ int X11DRV_DIB_SetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr ) ...@@ -2716,14 +2746,14 @@ int X11DRV_DIB_SetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr )
* X11DRV_DIB_GetImageBits * X11DRV_DIB_GetImageBits
* *
* Transfer the bits from an X image. * Transfer the bits from an X image.
* The Xlib critical section must be entered before calling this function.
*/ */
int X11DRV_DIB_GetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr ) static int X11DRV_DIB_GetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr )
{ {
int lines = descr->lines >= 0 ? descr->lines : -descr->lines; int lines = descr->lines >= 0 ? descr->lines : -descr->lines;
XImage *bmpImage; XImage *bmpImage;
if (descr->image) wine_tsx11_lock();
if (descr->image)
bmpImage = descr->image; bmpImage = descr->image;
else { else {
bmpImage = XCreateImage( display, X11DRV_GetVisual(), descr->depth, ZPixmap, 0, NULL, bmpImage = XCreateImage( display, X11DRV_GetVisual(), descr->depth, ZPixmap, 0, NULL,
...@@ -2732,8 +2762,10 @@ int X11DRV_DIB_GetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr ) ...@@ -2732,8 +2762,10 @@ int X11DRV_DIB_GetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr )
if(bmpImage->data == NULL) { if(bmpImage->data == NULL) {
ERR("Out of memory!\n"); ERR("Out of memory!\n");
XDestroyImage( bmpImage ); XDestroyImage( bmpImage );
wine_tsx11_unlock();
return lines; return lines;
} } }
}
TRACE("XGetSubImage(%p,%ld,%d,%d,%d,%d,%ld,%d,%p,%d,%d)\n", TRACE("XGetSubImage(%p,%ld,%d,%d,%d,%d,%ld,%d,%p,%d,%d)\n",
display, descr->drawable, descr->xSrc, descr->ySrc, descr->width, display, descr->drawable, descr->xSrc, descr->ySrc, descr->width,
...@@ -2798,6 +2830,7 @@ int X11DRV_DIB_GetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr ) ...@@ -2798,6 +2830,7 @@ int X11DRV_DIB_GetImageBits( const X11DRV_DIB_IMAGEBITS_DESCR *descr )
} }
if (!descr->image) XDestroyImage( bmpImage ); if (!descr->image) XDestroyImage( bmpImage );
wine_tsx11_unlock();
return lines; return lines;
} }
...@@ -2886,9 +2919,7 @@ INT X11DRV_SetDIBitsToDevice( DC *dc, INT xDest, INT yDest, DWORD cx, ...@@ -2886,9 +2919,7 @@ INT X11DRV_SetDIBitsToDevice( DC *dc, INT xDest, INT yDest, DWORD cx,
descr.useShm = FALSE; descr.useShm = FALSE;
descr.dibpitch = ((width * descr.infoBpp + 31) &~31) / 8; descr.dibpitch = ((width * descr.infoBpp + 31) &~31) / 8;
EnterCriticalSection( &X11DRV_CritSection ); result = X11DRV_DIB_SetImageBits( &descr );
result = CALL_LARGE_STACK( X11DRV_DIB_SetImageBits, &descr );
LeaveCriticalSection( &X11DRV_CritSection );
if (descr.infoBpp <= 8) if (descr.infoBpp <= 8)
HeapFree(GetProcessHeap(), 0, descr.colorMap); HeapFree(GetProcessHeap(), 0, descr.colorMap);
...@@ -2974,11 +3005,8 @@ INT X11DRV_DIB_SetDIBits( ...@@ -2974,11 +3005,8 @@ INT X11DRV_DIB_SetDIBits(
descr.height = lines; descr.height = lines;
descr.useShm = FALSE; descr.useShm = FALSE;
descr.dibpitch = ((descr.infoWidth * descr.infoBpp + 31) &~31) / 8; descr.dibpitch = ((descr.infoWidth * descr.infoBpp + 31) &~31) / 8;
result = X11DRV_DIB_SetImageBits( &descr );
EnterCriticalSection( &X11DRV_CritSection );
result = CALL_LARGE_STACK( X11DRV_DIB_SetImageBits, &descr );
LeaveCriticalSection( &X11DRV_CritSection );
if (descr.colorMap) HeapFree(GetProcessHeap(), 0, descr.colorMap); if (descr.colorMap) HeapFree(GetProcessHeap(), 0, descr.colorMap);
return result; return result;
...@@ -3089,12 +3117,8 @@ INT X11DRV_DIB_GetDIBits( ...@@ -3089,12 +3117,8 @@ INT X11DRV_DIB_GetDIBits(
descr.dibpitch = dib ? (dib->dibSection.dsBm.bmWidthBytes) descr.dibpitch = dib ? (dib->dibSection.dsBm.bmWidthBytes)
: (((descr.infoWidth * descr.infoBpp + 31) &~31) / 8); : (((descr.infoWidth * descr.infoBpp + 31) &~31) / 8);
EnterCriticalSection( &X11DRV_CritSection ); X11DRV_DIB_GetImageBits( &descr );
CALL_LARGE_STACK( X11DRV_DIB_GetImageBits, &descr );
LeaveCriticalSection( &X11DRV_CritSection );
if(info->bmiHeader.biSizeImage == 0) /* Fill in biSizeImage */ if(info->bmiHeader.biSizeImage == 0) /* Fill in biSizeImage */
info->bmiHeader.biSizeImage = DIB_GetDIBImageBytes( info->bmiHeader.biSizeImage = DIB_GetDIBImageBytes(
info->bmiHeader.biWidth, info->bmiHeader.biWidth,
...@@ -3201,16 +3225,12 @@ static void X11DRV_DIB_DoCopyDIBSection(BITMAPOBJ *bmp, BOOL toDIB, ...@@ -3201,16 +3225,12 @@ static void X11DRV_DIB_DoCopyDIBSection(BITMAPOBJ *bmp, BOOL toDIB,
if (toDIB) if (toDIB)
{ {
TRACE("Copying from Pixmap to DIB bits\n"); TRACE("Copying from Pixmap to DIB bits\n");
EnterCriticalSection( &X11DRV_CritSection ); X11DRV_DIB_GetImageBits( &descr );
CALL_LARGE_STACK( X11DRV_DIB_GetImageBits, &descr );
LeaveCriticalSection( &X11DRV_CritSection );
} }
else else
{ {
TRACE("Copying from DIB bits to Pixmap\n"); TRACE("Copying from DIB bits to Pixmap\n");
EnterCriticalSection( &X11DRV_CritSection ); X11DRV_DIB_SetImageBits( &descr );
CALL_LARGE_STACK( X11DRV_DIB_SetImageBits, &descr );
LeaveCriticalSection( &X11DRV_CritSection );
} }
} }
...@@ -3699,7 +3719,7 @@ extern BOOL X11DRV_XShmCreateImage(XImage** image, int width, int height, int bp ...@@ -3699,7 +3719,7 @@ extern BOOL X11DRV_XShmCreateImage(XImage** image, int width, int height, int bp
*image = TSXShmCreateImage(display, X11DRV_GetVisual(), bpp, ZPixmap, NULL, shminfo, width, height); *image = TSXShmCreateImage(display, X11DRV_GetVisual(), bpp, ZPixmap, NULL, shminfo, width, height);
if( *image != NULL ) if( *image != NULL )
{ {
EnterCriticalSection( &X11DRV_CritSection ); wine_tsx11_lock();
shminfo->shmid = shmget(IPC_PRIVATE, (*image)->bytes_per_line * height, shminfo->shmid = shmget(IPC_PRIVATE, (*image)->bytes_per_line * height,
IPC_CREAT|0700); IPC_CREAT|0700);
if( shminfo->shmid != -1 ) if( shminfo->shmid != -1 )
...@@ -3720,8 +3740,7 @@ extern BOOL X11DRV_XShmCreateImage(XImage** image, int width, int height, int bp ...@@ -3720,8 +3740,7 @@ extern BOOL X11DRV_XShmCreateImage(XImage** image, int width, int height, int bp
shmctl(shminfo->shmid, IPC_RMID, 0); shmctl(shminfo->shmid, IPC_RMID, 0);
XSetErrorHandler(WineXHandler); XSetErrorHandler(WineXHandler);
LeaveCriticalSection( &X11DRV_CritSection ); wine_tsx11_unlock();
return TRUE; /* Success! */ return TRUE; /* Success! */
} }
/* An error occured */ /* An error occured */
...@@ -3734,7 +3753,7 @@ extern BOOL X11DRV_XShmCreateImage(XImage** image, int width, int height, int bp ...@@ -3734,7 +3753,7 @@ extern BOOL X11DRV_XShmCreateImage(XImage** image, int width, int height, int bp
} }
XFlush(display); XFlush(display);
XDestroyImage(*image); XDestroyImage(*image);
LeaveCriticalSection( &X11DRV_CritSection ); wine_tsx11_unlock();
} }
return FALSE; return FALSE;
} }
......
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#include "x11font.h" #include "x11font.h"
#include "bitmap.h" #include "bitmap.h"
#include "gdi.h" #include "gdi.h"
#include "callback.h"
#include "metafile.h" #include "metafile.h"
#include "palette.h" #include "palette.h"
#include "color.h" #include "color.h"
...@@ -124,7 +123,7 @@ BOOL X11DRV_SetupGCForPatBlt( DC * dc, GC gc, BOOL fMapColors ) ...@@ -124,7 +123,7 @@ BOOL X11DRV_SetupGCForPatBlt( DC * dc, GC gc, BOOL fMapColors )
{ {
register int x, y; register int x, y;
XImage *image; XImage *image;
EnterCriticalSection( &X11DRV_CritSection ); wine_tsx11_lock();
pixmap = XCreatePixmap( display, X11DRV_GetXRootWindow(), pixmap = XCreatePixmap( display, X11DRV_GetXRootWindow(),
8, 8, X11DRV_GetDepth() ); 8, 8, X11DRV_GetDepth() );
image = XGetImage( display, physDev->brush.pixmap, 0, 0, 8, 8, image = XGetImage( display, physDev->brush.pixmap, 0, 0, 8, 8,
...@@ -135,7 +134,7 @@ BOOL X11DRV_SetupGCForPatBlt( DC * dc, GC gc, BOOL fMapColors ) ...@@ -135,7 +134,7 @@ BOOL X11DRV_SetupGCForPatBlt( DC * dc, GC gc, BOOL fMapColors )
X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y)] ); X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y)] );
XPutImage( display, pixmap, gc, image, 0, 0, 0, 0, 8, 8 ); XPutImage( display, pixmap, gc, image, 0, 0, 0, 0, 8, 8 );
XDestroyImage( image ); XDestroyImage( image );
LeaveCriticalSection( &X11DRV_CritSection ); wine_tsx11_unlock();
val.tile = pixmap; val.tile = pixmap;
} }
else val.tile = physDev->brush.pixmap; else val.tile = physDev->brush.pixmap;
...@@ -880,7 +879,7 @@ X11DRV_GetPixel( DC *dc, INT x, INT y ) ...@@ -880,7 +879,7 @@ X11DRV_GetPixel( DC *dc, INT x, INT y )
x = dc->DCOrgX + XLPTODP( dc, x ); x = dc->DCOrgX + XLPTODP( dc, x );
y = dc->DCOrgY + YLPTODP( dc, y ); y = dc->DCOrgY + YLPTODP( dc, y );
EnterCriticalSection( &X11DRV_CritSection ); wine_tsx11_lock();
if (dc->flags & DC_MEMORY) if (dc->flags & DC_MEMORY)
{ {
image = XGetImage( display, physDev->drawable, x, y, 1, 1, image = XGetImage( display, physDev->drawable, x, y, 1, 1,
...@@ -898,8 +897,7 @@ X11DRV_GetPixel( DC *dc, INT x, INT y ) ...@@ -898,8 +897,7 @@ X11DRV_GetPixel( DC *dc, INT x, INT y )
} }
pixel = XGetPixel( image, 0, 0 ); pixel = XGetPixel( image, 0, 0 );
XDestroyImage( image ); XDestroyImage( image );
LeaveCriticalSection( &X11DRV_CritSection ); wine_tsx11_unlock();
return X11DRV_PALETTE_ToLogical(pixel); return X11DRV_PALETTE_ToLogical(pixel);
} }
...@@ -1212,88 +1210,51 @@ static void X11DRV_InternalFloodFill(XImage *image, DC *dc, ...@@ -1212,88 +1210,51 @@ static void X11DRV_InternalFloodFill(XImage *image, DC *dc,
/********************************************************************** /**********************************************************************
* X11DRV_DoFloodFill * X11DRV_ExtFloodFill
*
* Main flood-fill routine.
*
* The Xlib critical section must be entered before calling this function.
*/ */
BOOL
struct FloodFill_params X11DRV_ExtFloodFill( DC *dc, INT x, INT y, COLORREF color,
{ UINT fillType )
DC *dc;
INT x;
INT y;
COLORREF color;
UINT fillType;
};
static BOOL X11DRV_DoFloodFill( const struct FloodFill_params *params )
{ {
XImage *image; XImage *image;
RECT rect; RECT rect;
DC *dc = params->dc;
X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev; X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
TRACE("X11DRV_ExtFloodFill %d,%d %06lx %d\n", x, y, color, fillType );
if (!PtVisible( dc->hSelf, x, y )) return FALSE;
if (GetRgnBox( dc->hGCClipRgn, &rect ) == ERROR) return FALSE; if (GetRgnBox( dc->hGCClipRgn, &rect ) == ERROR) return FALSE;
if (!(image = XGetImage( display, physDev->drawable, if (!(image = TSXGetImage( display, physDev->drawable,
rect.left, rect.left,
rect.top, rect.top,
rect.right - rect.left, rect.right - rect.left,
rect.bottom - rect.top, rect.bottom - rect.top,
AllPlanes, ZPixmap ))) return FALSE; AllPlanes, ZPixmap ))) return FALSE;
wine_tsx11_lock();
if (X11DRV_SetupGCForBrush( dc )) if (X11DRV_SetupGCForBrush( dc ))
{ {
/* Update the pixmap from the DIB section */ /* Update the pixmap from the DIB section */
X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE); X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
/* ROP mode is always GXcopy for flood-fill */ /* ROP mode is always GXcopy for flood-fill */
XSetFunction( display, physDev->gc, GXcopy ); XSetFunction( display, physDev->gc, GXcopy );
X11DRV_InternalFloodFill(image, dc, X11DRV_InternalFloodFill(image, dc,
XLPTODP(dc,params->x) + dc->DCOrgX - rect.left, XLPTODP(dc,x) + dc->DCOrgX - rect.left,
YLPTODP(dc,params->y) + dc->DCOrgY - rect.top, YLPTODP(dc,y) + dc->DCOrgY - rect.top,
rect.left, rect.left, rect.top,
rect.top, X11DRV_PALETTE_ToPhysical( dc, color ),
X11DRV_PALETTE_ToPhysical( dc, params->color ), fillType );
params->fillType ); /* Update the DIBSection of the dc's bitmap */
X11DRV_UnlockDIBSection(dc, TRUE);
/* Update the DIBSection of the dc's bitmap */
X11DRV_UnlockDIBSection(dc, TRUE);
} }
XDestroyImage( image ); XDestroyImage( image );
wine_tsx11_unlock();
return TRUE; return TRUE;
} }
/**********************************************************************
* X11DRV_ExtFloodFill
*/
BOOL
X11DRV_ExtFloodFill( DC *dc, INT x, INT y, COLORREF color,
UINT fillType )
{
BOOL result;
struct FloodFill_params params;
TRACE("X11DRV_ExtFloodFill %d,%d %06lx %d\n",
x, y, color, fillType );
params.dc = dc;
params.x = x;
params.y = y;
params.color = color;
params.fillType = fillType;
if (!PtVisible( dc->hSelf, x, y )) return FALSE;
EnterCriticalSection( &X11DRV_CritSection );
result = CALL_LARGE_STACK( X11DRV_DoFloodFill, &params );
LeaveCriticalSection( &X11DRV_CritSection );
return result;
}
/********************************************************************** /**********************************************************************
* X11DRV_SetBkColor * X11DRV_SetBkColor
*/ */
......
...@@ -19,8 +19,12 @@ typedef unsigned long Pixel; ...@@ -19,8 +19,12 @@ typedef unsigned long Pixel;
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "wine/winuser16.h"
#include "bitmap.h" #include "bitmap.h"
#include "callback.h"
#include "color.h" #include "color.h"
#include "cursoricon.h" #include "cursoricon.h"
#include "debugtools.h" #include "debugtools.h"
...@@ -352,30 +356,6 @@ static HBITMAP16 OBM_MakeBitmap( WORD width, WORD height, ...@@ -352,30 +356,6 @@ static HBITMAP16 OBM_MakeBitmap( WORD width, WORD height,
} }
#endif /* defined(HAVE_LIBXXPM) */ #endif /* defined(HAVE_LIBXXPM) */
/***********************************************************************
* OBM_CreatePixmaps
*
* Create the 2 pixmaps from XPM data.
*
* The Xlib critical section must be entered before calling this function.
*/
#ifdef HAVE_LIBXXPM
typedef struct
{
char **data;
XpmAttributes *attrs;
Pixmap pixmap;
Pixmap pixmask;
} OBM_PIXMAP_DESCR;
static int OBM_CreatePixmaps( OBM_PIXMAP_DESCR *descr )
{
return XpmCreatePixmapFromData( display, X11DRV_GetXRootWindow(), descr->data,
&descr->pixmap, &descr->pixmask, descr->attrs );
}
#endif /* defined(HAVE_LIBXXPM) */
/*********************************************************************** /***********************************************************************
* OBM_CreateBitmaps * OBM_CreateBitmaps
...@@ -386,50 +366,44 @@ static BOOL OBM_CreateBitmaps( char **data, BOOL color, ...@@ -386,50 +366,44 @@ static BOOL OBM_CreateBitmaps( char **data, BOOL color,
HBITMAP16 *bitmap, HBITMAP16 *mask, POINT *hotspot ) HBITMAP16 *bitmap, HBITMAP16 *mask, POINT *hotspot )
{ {
#ifdef HAVE_LIBXXPM #ifdef HAVE_LIBXXPM
OBM_PIXMAP_DESCR descr; XpmAttributes *attrs;
Pixmap pixmap, pixmask;
int err; int err;
descr.attrs = (XpmAttributes *)HeapAlloc( GetProcessHeap(), 0, attrs = (XpmAttributes *)HeapAlloc( GetProcessHeap(), 0, XpmAttributesSize() );
XpmAttributesSize() ); if (attrs == NULL) return FALSE;
if (descr.attrs == NULL) return FALSE; attrs->valuemask = XpmColormap | XpmDepth | XpmColorSymbols | XpmHotspot;
descr.attrs->valuemask = XpmColormap | XpmDepth | XpmColorSymbols | XpmHotspot; attrs->colormap = X11DRV_PALETTE_PaletteXColormap;
descr.attrs->colormap = X11DRV_PALETTE_PaletteXColormap; attrs->depth = color ? X11DRV_GetDepth() : 1;
descr.attrs->depth = color ? X11DRV_GetDepth() : 1; attrs->colorsymbols = (attrs->depth > 1) ? OBM_Colors : OBM_BlackAndWhite;
descr.attrs->colorsymbols = (descr.attrs->depth > 1) ? OBM_Colors : OBM_BlackAndWhite; attrs->numsymbols = (attrs->depth > 1) ? NB_COLOR_SYMBOLS : 2;
descr.attrs->numsymbols = (descr.attrs->depth > 1) ? NB_COLOR_SYMBOLS : 2;
descr.data = data;
EnterCriticalSection( &X11DRV_CritSection );
err = CALL_LARGE_STACK( OBM_CreatePixmaps, &descr );
LeaveCriticalSection( &X11DRV_CritSection );
err = TSXpmCreatePixmapFromData( display, X11DRV_GetXRootWindow(), data,
&pixmap, &pixmask, attrs );
if (err != XpmSuccess) if (err != XpmSuccess)
{ {
HeapFree( GetProcessHeap(), 0, descr.attrs ); HeapFree( GetProcessHeap(), 0, attrs );
return FALSE; return FALSE;
} }
if (hotspot) if (hotspot)
{ {
hotspot->x = descr.attrs->x_hotspot; hotspot->x = attrs->x_hotspot;
hotspot->y = descr.attrs->y_hotspot; hotspot->y = attrs->y_hotspot;
} }
if (bitmap) if (bitmap)
*bitmap = OBM_MakeBitmap( descr.attrs->width, descr.attrs->height, *bitmap = OBM_MakeBitmap( attrs->width, attrs->height,
descr.attrs->depth, descr.pixmap ); attrs->depth, pixmap );
if (mask) if (mask)
*mask = OBM_MakeBitmap( descr.attrs->width, descr.attrs->height, *mask = OBM_MakeBitmap( attrs->width, attrs->height,
1, descr.pixmask ); 1, pixmask );
HeapFree( GetProcessHeap(), 0, descr.attrs ); HeapFree( GetProcessHeap(), 0, attrs );
if (descr.pixmap && (!bitmap || !*bitmap)) if (pixmap && (!bitmap || !*bitmap)) TSXFreePixmap( display, pixmap );
TSXFreePixmap( display, descr.pixmap ); if (pixmask && (!mask || !*mask)) TSXFreePixmap( display, pixmask );
if (descr.pixmask && (!mask || !*mask))
TSXFreePixmap( display, descr.pixmask );
if (bitmap && !*bitmap) if (bitmap && !*bitmap)
{ {
......
...@@ -13,10 +13,6 @@ ...@@ -13,10 +13,6 @@
#include "wine/winuser16.h" #include "wine/winuser16.h"
extern void SYSDEPS_SwitchToThreadStack( void (*func)(void) ) WINE_NORETURN; extern void SYSDEPS_SwitchToThreadStack( void (*func)(void) ) WINE_NORETURN;
extern int SYSDEPS_CallOnLargeStack( int (*func)(void *), void *arg );
#define CALL_LARGE_STACK( func, arg ) \
SYSDEPS_CallOnLargeStack( (int (*)(void *))(func), (void *)(arg) )
typedef void (*RELAY)(); typedef void (*RELAY)();
extern FARPROC THUNK_Alloc( FARPROC16 func, RELAY relay ); extern FARPROC THUNK_Alloc( FARPROC16 func, RELAY relay );
......
...@@ -240,36 +240,6 @@ typedef struct ...@@ -240,36 +240,6 @@ typedef struct
} X11DRV_DIBSECTION; } X11DRV_DIBSECTION;
/* This structure holds the arguments for DIB_SetImageBits() */
typedef struct
{
struct tagDC *dc;
LPCVOID bits;
XImage *image;
PALETTEENTRY *palentry;
int lines;
DWORD infoWidth;
WORD depth;
WORD infoBpp;
WORD compression;
RGBQUAD *colorMap;
int nColorMap;
Drawable drawable;
GC gc;
int xSrc;
int ySrc;
int xDest;
int yDest;
int width;
int height;
DWORD rMask;
DWORD gMask;
DWORD bMask;
BOOL useShm;
int dibpitch;
} X11DRV_DIB_IMAGEBITS_DESCR;
extern int *X11DRV_DIB_BuildColorMap( struct tagDC *dc, WORD coloruse, extern int *X11DRV_DIB_BuildColorMap( struct tagDC *dc, WORD coloruse,
WORD depth, const BITMAPINFO *info, WORD depth, const BITMAPINFO *info,
int *nColors ); int *nColors );
......
...@@ -274,10 +274,6 @@ int SYSDEPS_CallOnStack( LPVOID stackTop, LPVOID stackLow, ...@@ -274,10 +274,6 @@ int SYSDEPS_CallOnStack( LPVOID stackTop, LPVOID stackLow,
/*********************************************************************** /***********************************************************************
* SYSDEPS_SwitchToThreadStack * SYSDEPS_SwitchToThreadStack
*/ */
static LPVOID SYSDEPS_LargeStackTop = NULL;
static LPVOID SYSDEPS_LargeStackLow = NULL;
void SYSDEPS_SwitchToThreadStack( void (*func)(void) ) void SYSDEPS_SwitchToThreadStack( void (*func)(void) )
{ {
DWORD page_size = getpagesize(); DWORD page_size = getpagesize();
...@@ -298,34 +294,10 @@ void SYSDEPS_SwitchToThreadStack( void (*func)(void) ) ...@@ -298,34 +294,10 @@ void SYSDEPS_SwitchToThreadStack( void (*func)(void) )
teb->stack_top = (LPVOID) cur_stack; teb->stack_top = (LPVOID) cur_stack;
teb->stack_low = (LPVOID)(cur_stack - rl.rlim_cur); teb->stack_low = (LPVOID)(cur_stack - rl.rlim_cur);
#if 0
SYSDEPS_LargeStackTop = (LPVOID)(cur_stack - 2*page_size);
SYSDEPS_LargeStackLow = (LPVOID)(cur_stack - rl.rlim_cur);
#endif
SYSDEPS_CallOnStack( stackTop, stackLow, SYSDEPS_CallOnStack( stackTop, stackLow,
(int (*)(void *))func, NULL ); (int (*)(void *))func, NULL );
} }
/***********************************************************************
* SYSDEPS_CallOnLargeStack
*/
int SYSDEPS_CallOnLargeStack( int (*func)(LPVOID), LPVOID arg )
{
static int recurse = 0;
int retv;
if ( recurse++ == 0 && SYSDEPS_LargeStackTop )
retv = SYSDEPS_CallOnStack( SYSDEPS_LargeStackTop,
SYSDEPS_LargeStackLow, func, arg );
else
retv = func( arg );
recurse--;
return retv;
}
/********************************************************************** /**********************************************************************
* NtCurrentTeb (NTDLL.89) * NtCurrentTeb (NTDLL.89)
* *
......
...@@ -8,11 +8,12 @@ ...@@ -8,11 +8,12 @@
#include "ts_xlib.h" #include "ts_xlib.h"
#include "callback.h" #include "windef.h"
#include "wine/winuser16.h"
#include "debugtools.h" #include "debugtools.h"
#include "mouse.h" #include "mouse.h"
#include "win.h" #include "win.h"
#include "windef.h"
#include "x11drv.h" #include "x11drv.h"
DEFAULT_DEBUG_CHANNEL(cursor); DEFAULT_DEBUG_CHANNEL(cursor);
...@@ -167,9 +168,9 @@ void X11DRV_SetCursor( CURSORICONINFO *lpCursor ) ...@@ -167,9 +168,9 @@ void X11DRV_SetCursor( CURSORICONINFO *lpCursor )
{ {
BOOL success; BOOL success;
EnterCriticalSection( &X11DRV_CritSection ); wine_tsx11_lock();
success = CALL_LARGE_STACK( X11DRV_MOUSE_DoSetCursor, lpCursor ); success = X11DRV_MOUSE_DoSetCursor( lpCursor );
LeaveCriticalSection( &X11DRV_CritSection ); wine_tsx11_unlock();
if ( !success ) return; if ( !success ) return;
if (X11DRV_GetXRootWindow() != DefaultRootWindow(display)) if (X11DRV_GetXRootWindow() != DefaultRootWindow(display))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment