Commit 715d0e84 authored by Ulrich Czekalla's avatar Ulrich Czekalla Committed by Alexandre Julliard

winex11.drv: Correctly position and clip opengl child windows.

parent 0ab55904
...@@ -266,6 +266,21 @@ sub GenerateThunk($$$$$) ...@@ -266,6 +266,21 @@ sub GenerateThunk($$$$$)
if ( $func_ref->[0] eq "glGetIntegerv" ) { if ( $func_ref->[0] eq "glGetIntegerv" ) {
$wine_func_ref_name = "internal_glGetIntegerv"; $wine_func_ref_name = "internal_glGetIntegerv";
} }
if ( $func_ref->[0] eq "glEnable" ) {
$wine_func_ref_name = "internal_glEnable";
}
if ( $func_ref->[0] eq "glIsEnabled" ) {
$wine_func_ref_name = "internal_glIsEnabled";
}
if ( $func_ref->[0] eq "glDisable" ) {
$wine_func_ref_name = "internal_glDisable";
}
if ( $func_ref->[0] eq "glScissor" ) {
$wine_func_ref_name = "internal_glScissor";
}
if ( $func_ref->[0] eq "glViewport" ) {
$wine_func_ref_name = "internal_glViewport";
}
$ret = "$ret$prefix$wine_func_ref_name( $call_arg);\n"; $ret = "$ret$prefix$wine_func_ref_name( $call_arg);\n";
if ($thread_safe) { if ($thread_safe) {
$ret = "$ret LEAVE_GL();\n"; $ret = "$ret LEAVE_GL();\n";
......
...@@ -64,5 +64,10 @@ extern const int extension_registry_size; ...@@ -64,5 +64,10 @@ extern const int extension_registry_size;
const GLubyte* internal_glGetString(GLenum name); const GLubyte* internal_glGetString(GLenum name);
void internal_glGetIntegerv(GLenum pname, GLint* params); void internal_glGetIntegerv(GLenum pname, GLint* params);
void internal_glDisable(GLenum cap);
void internal_glEnable(GLenum cap);
GLboolean internal_glIsEnabled(GLenum cap);
void internal_glScissor(GLint x, GLint y, GLsizei width, GLsizei height);
void internal_glViewport(GLint x, GLint y, GLsizei width, GLsizei height);
#endif /* __DLLS_OPENGL32_OPENGL_EXT_H */ #endif /* __DLLS_OPENGL32_OPENGL_EXT_H */
...@@ -815,7 +815,7 @@ void WINAPI wine_glDepthRange( GLclampd nearParam, GLclampd farParam ) { ...@@ -815,7 +815,7 @@ void WINAPI wine_glDepthRange( GLclampd nearParam, GLclampd farParam ) {
void WINAPI wine_glDisable( GLenum cap ) { void WINAPI wine_glDisable( GLenum cap ) {
TRACE("(%d)\n", cap ); TRACE("(%d)\n", cap );
ENTER_GL(); ENTER_GL();
glDisable( cap ); internal_glDisable( cap );
LEAVE_GL(); LEAVE_GL();
} }
...@@ -915,7 +915,7 @@ void WINAPI wine_glEdgeFlagv( GLboolean* flag ) { ...@@ -915,7 +915,7 @@ void WINAPI wine_glEdgeFlagv( GLboolean* flag ) {
void WINAPI wine_glEnable( GLenum cap ) { void WINAPI wine_glEnable( GLenum cap ) {
TRACE("(%d)\n", cap ); TRACE("(%d)\n", cap );
ENTER_GL(); ENTER_GL();
glEnable( cap ); internal_glEnable( cap );
LEAVE_GL(); LEAVE_GL();
} }
...@@ -1772,7 +1772,7 @@ GLboolean WINAPI wine_glIsEnabled( GLenum cap ) { ...@@ -1772,7 +1772,7 @@ GLboolean WINAPI wine_glIsEnabled( GLenum cap ) {
GLboolean ret_value; GLboolean ret_value;
TRACE("(%d)\n", cap ); TRACE("(%d)\n", cap );
ENTER_GL(); ENTER_GL();
ret_value = glIsEnabled( cap ); ret_value = internal_glIsEnabled( cap );
LEAVE_GL(); LEAVE_GL();
return ret_value; return ret_value;
} }
...@@ -2889,7 +2889,7 @@ void WINAPI wine_glScalef( GLfloat x, GLfloat y, GLfloat z ) { ...@@ -2889,7 +2889,7 @@ void WINAPI wine_glScalef( GLfloat x, GLfloat y, GLfloat z ) {
void WINAPI wine_glScissor( GLint x, GLint y, GLsizei width, GLsizei height ) { void WINAPI wine_glScissor( GLint x, GLint y, GLsizei width, GLsizei height ) {
TRACE("(%d, %d, %d, %d)\n", x, y, width, height ); TRACE("(%d, %d, %d, %d)\n", x, y, width, height );
ENTER_GL(); ENTER_GL();
glScissor( x, y, width, height ); internal_glScissor( x, y, width, height );
LEAVE_GL(); LEAVE_GL();
} }
...@@ -3759,6 +3759,6 @@ void WINAPI wine_glVertexPointer( GLint size, GLenum type, GLsizei stride, GLvoi ...@@ -3759,6 +3759,6 @@ void WINAPI wine_glVertexPointer( GLint size, GLenum type, GLsizei stride, GLvoi
void WINAPI wine_glViewport( GLint x, GLint y, GLsizei width, GLsizei height ) { void WINAPI wine_glViewport( GLint x, GLint y, GLsizei width, GLsizei height ) {
TRACE("(%d, %d, %d, %d)\n", x, y, width, height ); TRACE("(%d, %d, %d, %d)\n", x, y, width, height );
ENTER_GL(); ENTER_GL();
glViewport( x, y, width, height ); internal_glViewport( x, y, width, height );
LEAVE_GL(); LEAVE_GL();
} }
...@@ -49,7 +49,12 @@ WINE_DECLARE_DEBUG_CHANNEL(opengl); ...@@ -49,7 +49,12 @@ WINE_DECLARE_DEBUG_CHANNEL(opengl);
typedef struct wine_wgl_s { typedef struct wine_wgl_s {
PROC WINAPI (*p_wglGetProcAddress)(LPCSTR lpszProc); PROC WINAPI (*p_wglGetProcAddress)(LPCSTR lpszProc);
void WINAPI (*p_wglDisable)(GLenum cap);
void WINAPI (*p_wglEnable)(GLenum cap);
void WINAPI (*p_wglGetIntegerv)(GLenum pname, GLint* params); void WINAPI (*p_wglGetIntegerv)(GLenum pname, GLint* params);
GLboolean WINAPI (*p_wglIsEnabled)(GLenum cap);
void WINAPI (*p_wglScissor)(GLint x, GLint y, GLsizei width, GLsizei height);
void WINAPI (*p_wglViewport)(GLint x, GLint y, GLsizei width, GLsizei height);
} wine_wgl_t; } wine_wgl_t;
/** global wgl object */ /** global wgl object */
...@@ -86,8 +91,7 @@ typedef struct wine_glcontext { ...@@ -86,8 +91,7 @@ typedef struct wine_glcontext {
GLXFBConfig fb_conf; GLXFBConfig fb_conf;
GLXContext ctx; GLXContext ctx;
BOOL do_escape; BOOL do_escape;
struct wine_glcontext *next; /* ... more stuff here */
struct wine_glcontext *prev;
} Wine_GLContext; } Wine_GLContext;
void enter_gl(void) void enter_gl(void)
...@@ -557,6 +561,31 @@ BOOL WINAPI wglUseFontOutlinesW(HDC hdc, ...@@ -557,6 +561,31 @@ BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE); return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
} }
void internal_glEnable(GLenum cap)
{
wine_wgl.p_wglEnable(cap);
}
GLboolean internal_glIsEnabled(GLenum cap)
{
return wine_wgl.p_wglIsEnabled(cap);
}
void internal_glDisable(GLenum cap)
{
wine_wgl.p_wglDisable(cap);
}
void internal_glScissor( GLint x, GLint y, GLsizei width, GLsizei height )
{
wine_wgl.p_wglScissor(x, y, width, height);
}
void internal_glViewport( GLint x, GLint y, GLsizei width, GLsizei height )
{
wine_wgl.p_wglViewport(x, y, width, height);
}
const GLubyte * internal_glGetString(GLenum name) { const GLubyte * internal_glGetString(GLenum name) {
const char* GL_Extensions = NULL; const char* GL_Extensions = NULL;
...@@ -641,7 +670,12 @@ static BOOL process_attach(void) ...@@ -641,7 +670,12 @@ static BOOL process_attach(void)
wine_wgl.p_wglGetProcAddress = (void *)GetProcAddress(mod_gdi32, "wglGetProcAddress"); wine_wgl.p_wglGetProcAddress = (void *)GetProcAddress(mod_gdi32, "wglGetProcAddress");
/* Interal WGL function */ /* Interal WGL function */
wine_wgl.p_wglDisable = (void *)wine_wgl.p_wglGetProcAddress("wglDisable");
wine_wgl.p_wglEnable = (void *)wine_wgl.p_wglGetProcAddress("wglEnable");
wine_wgl.p_wglGetIntegerv = (void *)wine_wgl.p_wglGetProcAddress("wglGetIntegerv"); wine_wgl.p_wglGetIntegerv = (void *)wine_wgl.p_wglGetProcAddress("wglGetIntegerv");
wine_wgl.p_wglIsEnabled = (void *)wine_wgl.p_wglGetProcAddress("wglIsEnabled");
wine_wgl.p_wglScissor = (void *)wine_wgl.p_wglGetProcAddress("wglScissor");
wine_wgl.p_wglViewport = (void *)wine_wgl.p_wglGetProcAddress("wglViewport");
internal_gl_disabled_extensions[0] = 0; internal_gl_disabled_extensions[0] = 0;
if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\OpenGL", &hkey)) { if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\OpenGL", &hkey)) {
......
...@@ -74,6 +74,10 @@ typedef struct wine_glcontext { ...@@ -74,6 +74,10 @@ typedef struct wine_glcontext {
GLXFBConfig fb_conf; GLXFBConfig fb_conf;
GLXContext ctx; GLXContext ctx;
BOOL do_escape; BOOL do_escape;
X11DRV_PDEVICE *physDev;
RECT viewport;
RECT scissor;
BOOL scissor_enabled;
struct wine_glcontext *next; struct wine_glcontext *next;
struct wine_glcontext *prev; struct wine_glcontext *prev;
} Wine_GLContext; } Wine_GLContext;
...@@ -253,13 +257,18 @@ MAKE_FUNCPTR(glBindTexture) ...@@ -253,13 +257,18 @@ MAKE_FUNCPTR(glBindTexture)
MAKE_FUNCPTR(glBitmap) MAKE_FUNCPTR(glBitmap)
MAKE_FUNCPTR(glCopyTexSubImage1D) MAKE_FUNCPTR(glCopyTexSubImage1D)
MAKE_FUNCPTR(glCopyTexSubImage2D) MAKE_FUNCPTR(glCopyTexSubImage2D)
MAKE_FUNCPTR(glDisable)
MAKE_FUNCPTR(glDrawBuffer) MAKE_FUNCPTR(glDrawBuffer)
MAKE_FUNCPTR(glEnable)
MAKE_FUNCPTR(glEndList) MAKE_FUNCPTR(glEndList)
MAKE_FUNCPTR(glGetError) MAKE_FUNCPTR(glGetError)
MAKE_FUNCPTR(glGetIntegerv) MAKE_FUNCPTR(glGetIntegerv)
MAKE_FUNCPTR(glGetString) MAKE_FUNCPTR(glGetString)
MAKE_FUNCPTR(glIsEnabled)
MAKE_FUNCPTR(glNewList) MAKE_FUNCPTR(glNewList)
MAKE_FUNCPTR(glPixelStorei) MAKE_FUNCPTR(glPixelStorei)
MAKE_FUNCPTR(glScissor)
MAKE_FUNCPTR(glViewport)
#undef MAKE_FUNCPTR #undef MAKE_FUNCPTR
static BOOL X11DRV_WineGL_InitOpenglInfo(void) static BOOL X11DRV_WineGL_InitOpenglInfo(void)
...@@ -377,15 +386,20 @@ LOAD_FUNCPTR(glXGetFBConfigs) ...@@ -377,15 +386,20 @@ LOAD_FUNCPTR(glXGetFBConfigs)
/* Standard OpenGL calls */ /* Standard OpenGL calls */
LOAD_FUNCPTR(glBindTexture) LOAD_FUNCPTR(glBindTexture)
LOAD_FUNCPTR(glBitmap) LOAD_FUNCPTR(glBitmap)
LOAD_FUNCPTR(glEndList)
LOAD_FUNCPTR(glCopyTexSubImage1D) LOAD_FUNCPTR(glCopyTexSubImage1D)
LOAD_FUNCPTR(glCopyTexSubImage2D) LOAD_FUNCPTR(glCopyTexSubImage2D)
LOAD_FUNCPTR(glDisable)
LOAD_FUNCPTR(glDrawBuffer) LOAD_FUNCPTR(glDrawBuffer)
LOAD_FUNCPTR(glEnable)
LOAD_FUNCPTR(glEndList)
LOAD_FUNCPTR(glGetError) LOAD_FUNCPTR(glGetError)
LOAD_FUNCPTR(glGetIntegerv) LOAD_FUNCPTR(glGetIntegerv)
LOAD_FUNCPTR(glGetString) LOAD_FUNCPTR(glGetString)
LOAD_FUNCPTR(glIsEnabled)
LOAD_FUNCPTR(glNewList) LOAD_FUNCPTR(glNewList)
LOAD_FUNCPTR(glPixelStorei) LOAD_FUNCPTR(glPixelStorei)
LOAD_FUNCPTR(glScissor)
LOAD_FUNCPTR(glViewport)
#undef LOAD_FUNCPTR #undef LOAD_FUNCPTR
/* It doesn't matter if these fail. They'll only be used if the driver reports /* It doesn't matter if these fail. They'll only be used if the driver reports
...@@ -539,7 +553,7 @@ inline static HDC get_hdc_from_Drawable(GLXDrawable d) ...@@ -539,7 +553,7 @@ inline static HDC get_hdc_from_Drawable(GLXDrawable d)
{ {
Wine_GLContext *ret; Wine_GLContext *ret;
for (ret = context_list; ret; ret = ret->next) { for (ret = context_list; ret; ret = ret->next) {
if (d == get_drawable( ret->hdc )) { if (d == ret->physDev->drawable) {
return ret->hdc; return ret->hdc;
} }
} }
...@@ -1318,6 +1332,7 @@ HGLRC X11DRV_wglCreateContext(X11DRV_PDEVICE *physDev) ...@@ -1318,6 +1332,7 @@ HGLRC X11DRV_wglCreateContext(X11DRV_PDEVICE *physDev)
ret = alloc_context(); ret = alloc_context();
wine_tsx11_unlock(); wine_tsx11_unlock();
ret->hdc = hdc; ret->hdc = hdc;
ret->physDev = physDev;
ret->display = gdi_display; ret->display = gdi_display;
ret->fb_conf = cur_cfg; ret->fb_conf = cur_cfg;
/*ret->vis = vis;*/ /*ret->vis = vis;*/
...@@ -1424,6 +1439,47 @@ PROC X11DRV_wglGetProcAddress(LPCSTR lpszProc) ...@@ -1424,6 +1439,47 @@ PROC X11DRV_wglGetProcAddress(LPCSTR lpszProc)
return NULL; return NULL;
} }
/***********************************************************************
* sync_current_drawable
*
* Adjust the current viewport and scissor in order to position
* and size the current drawable correctly on the parent window.
*/
static void sync_current_drawable(void)
{
int dy;
int width;
int height;
RECT rc;
Wine_GLContext *ctx = (Wine_GLContext *) NtCurrentTeb()->glContext;
TRACE("\n");
if (ctx && ctx->physDev)
{
GetClipBox(ctx->physDev->hdc, &rc); /* Make sure physDev is up to date */
dy = ctx->physDev->drawable_rect.bottom - ctx->physDev->dc_rect.bottom;
width = ctx->physDev->dc_rect.right - ctx->physDev->dc_rect.left;
height = ctx->physDev->dc_rect.bottom - ctx->physDev->dc_rect.top;
pglViewport(ctx->physDev->dc_rect.left + ctx->viewport.left,
dy + ctx->viewport.top,
ctx->viewport.right ? (ctx->viewport.right - ctx->viewport.left) : width,
ctx->viewport.bottom ? (ctx->viewport.bottom - ctx->viewport.top) : height);
pglEnable(GL_SCISSOR_TEST);
if (ctx->scissor_enabled)
pglScissor(ctx->physDev->dc_rect.left + min(width, max(0, ctx->scissor.left)),
dy + min(height, max(0, ctx->scissor.top)),
min(width, max(0, ctx->scissor.right - ctx->scissor.left)),
min(height, max(0, ctx->scissor.bottom - ctx->scissor.top)));
else
pglScissor(ctx->physDev->dc_rect.left, dy, width, height);
}
}
/** /**
* X11DRV_wglMakeCurrent * X11DRV_wglMakeCurrent
...@@ -1466,11 +1522,20 @@ BOOL X11DRV_wglMakeCurrent(X11DRV_PDEVICE *physDev, HGLRC hglrc) { ...@@ -1466,11 +1522,20 @@ BOOL X11DRV_wglMakeCurrent(X11DRV_PDEVICE *physDev, HGLRC hglrc) {
TRACE(" make current for dis %p, drawable %p, ctx %p\n", ctx->display, (void*) drawable, ctx->ctx); TRACE(" make current for dis %p, drawable %p, ctx %p\n", ctx->display, (void*) drawable, ctx->ctx);
ret = pglXMakeCurrent(ctx->display, drawable, ctx->ctx); ret = pglXMakeCurrent(ctx->display, drawable, ctx->ctx);
NtCurrentTeb()->glContext = ctx; NtCurrentTeb()->glContext = ctx;
if(ret && type == OBJ_MEMDC) if(ret)
{
ctx->physDev = physDev;
if (type == OBJ_MEMDC)
{ {
ctx->do_escape = TRUE; ctx->do_escape = TRUE;
pglDrawBuffer(GL_FRONT_LEFT); pglDrawBuffer(GL_FRONT_LEFT);
} }
else
{
sync_current_drawable();
}
}
} }
wine_tsx11_unlock(); wine_tsx11_unlock();
TRACE(" returning %s\n", (ret ? "True" : "False")); TRACE(" returning %s\n", (ret ? "True" : "False"));
...@@ -1541,7 +1606,7 @@ BOOL X11DRV_wglShareLists(HGLRC hglrc1, HGLRC hglrc2) { ...@@ -1541,7 +1606,7 @@ BOOL X11DRV_wglShareLists(HGLRC hglrc1, HGLRC hglrc2) {
if (org->ctx == NULL) { if (org->ctx == NULL) {
wine_tsx11_lock(); wine_tsx11_lock();
describeContext(org); describeContext(org);
org->ctx = pglXCreateContext(org->display, org->vis, NULL, GetObjectType(org->hdc) == OBJ_MEMDC ? False : True); org->ctx = pglXCreateContext(org->display, org->vis, NULL, GetObjectType(org->physDev->hdc) == OBJ_MEMDC ? False : True);
wine_tsx11_unlock(); wine_tsx11_unlock();
TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org); TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
} }
...@@ -1549,7 +1614,7 @@ BOOL X11DRV_wglShareLists(HGLRC hglrc1, HGLRC hglrc2) { ...@@ -1549,7 +1614,7 @@ BOOL X11DRV_wglShareLists(HGLRC hglrc1, HGLRC hglrc2) {
wine_tsx11_lock(); wine_tsx11_lock();
describeContext(dest); describeContext(dest);
/* Create the destination context with display lists shared */ /* Create the destination context with display lists shared */
dest->ctx = pglXCreateContext(org->display, dest->vis, org->ctx, GetObjectType(org->hdc) == OBJ_MEMDC ? False : True); dest->ctx = pglXCreateContext(org->display, dest->vis, org->ctx, GetObjectType(org->physDev->hdc) == OBJ_MEMDC ? False : True);
wine_tsx11_unlock(); wine_tsx11_unlock();
TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx); TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
return TRUE; return TRUE;
...@@ -1722,6 +1787,32 @@ BOOL X11DRV_wglUseFontBitmapsW(X11DRV_PDEVICE *physDev, DWORD first, DWORD count ...@@ -1722,6 +1787,32 @@ BOOL X11DRV_wglUseFontBitmapsW(X11DRV_PDEVICE *physDev, DWORD first, DWORD count
return TRUE; return TRUE;
} }
static void WINAPI X11DRV_wglDisable(GLenum cap)
{
if (cap == GL_SCISSOR_TEST)
{
Wine_GLContext *ctx = (Wine_GLContext *) NtCurrentTeb()->glContext;
ctx->scissor_enabled = FALSE;
}
else
{
pglDisable(cap);
}
}
static void WINAPI X11DRV_wglEnable(GLenum cap)
{
if (cap == GL_SCISSOR_TEST)
{
Wine_GLContext *ctx = (Wine_GLContext *) NtCurrentTeb()->glContext;
ctx->scissor_enabled = TRUE;
}
else
{
pglEnable(cap);
}
}
/* WGL helper function which handles differences in glGetIntegerv from WGL and GLX */ /* WGL helper function which handles differences in glGetIntegerv from WGL and GLX */
static void WINAPI X11DRV_wglGetIntegerv(GLenum pname, GLint* params) { static void WINAPI X11DRV_wglGetIntegerv(GLenum pname, GLint* params) {
TRACE("pname: 0x%x, params: %p\n", pname, params); TRACE("pname: 0x%x, params: %p\n", pname, params);
...@@ -1749,6 +1840,47 @@ static void WINAPI X11DRV_wglGetIntegerv(GLenum pname, GLint* params) { ...@@ -1749,6 +1840,47 @@ static void WINAPI X11DRV_wglGetIntegerv(GLenum pname, GLint* params) {
} }
} }
static GLboolean WINAPI X11DRV_wglIsEnabled(GLenum cap)
{
GLboolean enabled;
if (cap == GL_SCISSOR_TEST)
{
Wine_GLContext *ctx = (Wine_GLContext *) NtCurrentTeb()->glContext;
enabled = ctx->scissor_enabled;
}
else
{
enabled = pglIsEnabled(cap);
}
return enabled;
}
static void WINAPI X11DRV_wglScissor(GLint x, GLint y, GLsizei width, GLsizei height)
{
Wine_GLContext *ctx = (Wine_GLContext *) NtCurrentTeb()->glContext;
ctx->scissor.left = x;
ctx->scissor.top = y;
ctx->scissor.right = x + width;
ctx->scissor.bottom = y + height;
sync_current_drawable();
}
static void WINAPI X11DRV_wglViewport(GLint x, GLint y, GLsizei width, GLsizei height)
{
Wine_GLContext *ctx = (Wine_GLContext *) NtCurrentTeb()->glContext;
ctx->viewport.left = x;
ctx->viewport.top = y;
ctx->viewport.right = x + width;
ctx->viewport.bottom = y + height;
sync_current_drawable();
}
/** /**
* X11DRV_wglGetExtensionsStringARB * X11DRV_wglGetExtensionsStringARB
* *
...@@ -2673,7 +2805,12 @@ static const WineGLExtension WGL_internal_functions = ...@@ -2673,7 +2805,12 @@ static const WineGLExtension WGL_internal_functions =
{ {
"", "",
{ {
{ "wglDisable", X11DRV_wglDisable },
{ "wglEnable", X11DRV_wglEnable },
{ "wglGetIntegerv", X11DRV_wglGetIntegerv }, { "wglGetIntegerv", X11DRV_wglGetIntegerv },
{ "wglIsEnabled", X11DRV_wglIsEnabled },
{ "wglScissor", X11DRV_wglScissor },
{ "wglViewport", X11DRV_wglViewport },
} }
}; };
......
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