Commit d174cb22 authored by Jacek Caban's avatar Jacek Caban Committed by Alexandre Julliard

win32u: Move GetWindowLong implementation from user32.

parent d312083e
...@@ -2326,131 +2326,6 @@ UINT WINAPI GetDpiForWindow( HWND hwnd ) ...@@ -2326,131 +2326,6 @@ UINT WINAPI GetDpiForWindow( HWND hwnd )
/********************************************************************** /**********************************************************************
* WIN_GetWindowLong
*
* Helper function for GetWindowLong().
*/
static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
{
LONG_PTR retvalue = 0;
WND *wndPtr;
if (offset == GWLP_HWNDPARENT)
{
HWND parent = GetAncestor( hwnd, GA_PARENT );
if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
return (ULONG_PTR)parent;
}
if (!(wndPtr = WIN_GetPtr( hwnd )))
{
SetLastError( ERROR_INVALID_WINDOW_HANDLE );
return 0;
}
if (wndPtr == WND_DESKTOP)
{
switch (offset)
{
case GWL_STYLE:
retvalue = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; /* message parent is not visible */
if (WIN_GetFullHandle( hwnd ) == GetDesktopWindow())
retvalue |= WS_VISIBLE;
return retvalue;
case GWL_EXSTYLE:
case GWLP_USERDATA:
case GWLP_ID:
case GWLP_HINSTANCE:
return 0;
case GWLP_WNDPROC:
SetLastError( ERROR_ACCESS_DENIED );
return 0;
}
SetLastError( ERROR_INVALID_INDEX );
return 0;
}
if (wndPtr == WND_OTHER_PROCESS)
{
if (offset == GWLP_WNDPROC)
{
SetLastError( ERROR_ACCESS_DENIED );
return 0;
}
SERVER_START_REQ( set_window_info )
{
req->handle = wine_server_user_handle( hwnd );
req->flags = 0; /* don't set anything, just retrieve */
req->extra_offset = (offset >= 0) ? offset : -1;
req->extra_size = (offset >= 0) ? size : 0;
if (!wine_server_call_err( req ))
{
switch(offset)
{
case GWL_STYLE: retvalue = reply->old_style; break;
case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
case GWLP_ID: retvalue = reply->old_id; break;
case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
case GWLP_USERDATA: retvalue = reply->old_user_data; break;
default:
if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
else SetLastError( ERROR_INVALID_INDEX );
break;
}
}
}
SERVER_END_REQ;
return retvalue;
}
/* now we have a valid wndPtr */
if (offset >= 0)
{
if (offset > (int)(wndPtr->cbWndExtra - size))
{
WARN("Invalid offset %d\n", offset );
WIN_ReleasePtr( wndPtr );
SetLastError( ERROR_INVALID_INDEX );
return 0;
}
retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
/* Special case for dialog window procedure */
if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
WIN_ReleasePtr( wndPtr );
return retvalue;
}
switch(offset)
{
case GWLP_USERDATA: retvalue = wndPtr->userdata; break;
case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
case GWLP_ID: retvalue = wndPtr->wIDmenu; break;
case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
case GWLP_WNDPROC:
/* This looks like a hack only for the edit control (see tests). This makes these controls
* more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
* that the hack is in GetWindowLongPtr[AW], not in winprocs.
*/
if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
retvalue = (ULONG_PTR)wndPtr->winproc;
else
retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
break;
default:
WARN("Unknown offset %d\n", offset );
SetLastError( ERROR_INVALID_INDEX );
break;
}
WIN_ReleasePtr(wndPtr);
return retvalue;
}
/**********************************************************************
* WIN_SetWindowLong * WIN_SetWindowLong
* *
* Helper function for SetWindowLong(). * Helper function for SetWindowLong().
...@@ -2539,7 +2414,7 @@ LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, B ...@@ -2539,7 +2414,7 @@ LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, B
{ {
WNDPROC proc; WNDPROC proc;
UINT old_flags = wndPtr->flags; UINT old_flags = wndPtr->flags;
retval = WIN_GetWindowLong( hwnd, offset, size, unicode ); retval = unicode ? GetWindowLongPtrW( hwnd, offset ) : GetWindowLongPtrA( hwnd, offset );
proc = WINPROC_AllocProc( (WNDPROC)newval, unicode ); proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
if (proc) wndPtr->winproc = proc; if (proc) wndPtr->winproc = proc;
if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE; if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
...@@ -2680,27 +2555,22 @@ LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, B ...@@ -2680,27 +2555,22 @@ LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, B
} }
/* FIXME: move to win32u */
static ULONG_PTR get_hwnd_parent( HWND hwnd )
{
HWND parent = GetAncestor( hwnd, GA_PARENT );
if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
return (ULONG_PTR)parent;
}
/********************************************************************** /**********************************************************************
* GetWindowWord (USER32.@) * GetWindowWord (USER32.@)
*/ */
WORD WINAPI GetWindowWord( HWND hwnd, INT offset ) WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
{ {
switch(offset) if (offset == GWLP_HWNDPARENT) return get_hwnd_parent( hwnd );
{ return NtUserCallHwndParam( hwnd, offset, NtUserGetWindowWord );
case GWLP_ID:
case GWLP_HINSTANCE:
case GWLP_HWNDPARENT:
break;
default:
if (offset < 0)
{
WARN("Invalid offset %d\n", offset );
SetLastError( ERROR_INVALID_INDEX );
return 0;
}
break;
}
return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
} }
...@@ -2720,7 +2590,8 @@ LONG WINAPI GetWindowLongA( HWND hwnd, INT offset ) ...@@ -2720,7 +2590,8 @@ LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
return 0; return 0;
#endif #endif
default: default:
return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE ); if (offset == GWLP_HWNDPARENT) return get_hwnd_parent( hwnd );
return NtUserCallHwndParam( hwnd, offset, NtUserGetWindowLongA );
} }
} }
...@@ -2741,7 +2612,8 @@ LONG WINAPI GetWindowLongW( HWND hwnd, INT offset ) ...@@ -2741,7 +2612,8 @@ LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
return 0; return 0;
#endif #endif
default: default:
return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE ); if (offset == GWLP_HWNDPARENT) return get_hwnd_parent( hwnd );
return NtUserCallHwndParam( hwnd, offset, NtUserGetWindowLongW );
} }
} }
...@@ -4075,7 +3947,8 @@ BOOL WINAPI SetProcessDefaultLayout( DWORD layout ) ...@@ -4075,7 +3947,8 @@ BOOL WINAPI SetProcessDefaultLayout( DWORD layout )
*/ */
LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset ) LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
{ {
return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE ); if (offset == GWLP_HWNDPARENT) return get_hwnd_parent( hwnd );
return NtUserCallHwndParam( hwnd, offset, NtUserGetWindowLongPtrW );
} }
/***************************************************************************** /*****************************************************************************
...@@ -4083,7 +3956,8 @@ LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset ) ...@@ -4083,7 +3956,8 @@ LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
*/ */
LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset ) LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
{ {
return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE ); if (offset == GWLP_HWNDPARENT) return get_hwnd_parent( hwnd );
return NtUserCallHwndParam( hwnd, offset, NtUserGetWindowLongPtrA );
} }
/***************************************************************************** /*****************************************************************************
......
...@@ -33,16 +33,6 @@ ...@@ -33,16 +33,6 @@
struct tagCLASS; struct tagCLASS;
struct tagDIALOGINFO; struct tagDIALOGINFO;
/* WND flags values */
#define WIN_RESTORE_MAX 0x0001 /* Maximize when restoring */
#define WIN_NEED_SIZE 0x0002 /* Internal WM_SIZE is needed */
#define WIN_NCACTIVATED 0x0004 /* last WM_NCACTIVATE was positive */
#define WIN_ISMDICLIENT 0x0008 /* Window is an MDIClient */
#define WIN_ISUNICODE 0x0010 /* Window is Unicode */
#define WIN_NEEDS_SHOW_OWNEDPOPUP 0x0020 /* WM_SHOWWINDOW:SC_SHOW must be sent in the next ShowOwnedPopup call */
#define WIN_CHILDREN_MOVED 0x0040 /* children may have moved, ignore stored positions */
#define WIN_HAS_IME_WIN 0x0080 /* the window has been registered with imm32 */
/* Window functions */ /* Window functions */
extern HWND get_hwnd_message_parent(void) DECLSPEC_HIDDEN; extern HWND get_hwnd_message_parent(void) DECLSPEC_HIDDEN;
extern BOOL is_desktop_window( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL is_desktop_window( HWND hwnd ) DECLSPEC_HIDDEN;
......
...@@ -135,7 +135,7 @@ WNDPROC alloc_winproc( WNDPROC func, BOOL ansi ) ...@@ -135,7 +135,7 @@ WNDPROC alloc_winproc( WNDPROC func, BOOL ansi )
} }
/* Get a window procedure pointer that can be passed to the Windows program. */ /* Get a window procedure pointer that can be passed to the Windows program. */
static WNDPROC get_winproc( WNDPROC proc, BOOL ansi ) WNDPROC get_winproc( WNDPROC proc, BOOL ansi )
{ {
WINDOWPROC *ptr = get_winproc_ptr( proc ); WINDOWPROC *ptr = get_winproc_ptr( proc );
......
...@@ -91,6 +91,16 @@ typedef struct tagWND ...@@ -91,6 +91,16 @@ typedef struct tagWND
DWORD wExtra[1]; /* Window extra bytes */ DWORD wExtra[1]; /* Window extra bytes */
} WND; } WND;
/* WND flags values */
#define WIN_RESTORE_MAX 0x0001 /* Maximize when restoring */
#define WIN_NEED_SIZE 0x0002 /* Internal WM_SIZE is needed */
#define WIN_NCACTIVATED 0x0004 /* last WM_NCACTIVATE was positive */
#define WIN_ISMDICLIENT 0x0008 /* Window is an MDIClient */
#define WIN_ISUNICODE 0x0010 /* Window is Unicode */
#define WIN_NEEDS_SHOW_OWNEDPOPUP 0x0020 /* WM_SHOWWINDOW:SC_SHOW must be sent in the next ShowOwnedPopup call */
#define WIN_CHILDREN_MOVED 0x0040 /* children may have moved, ignore stored positions */
#define WIN_HAS_IME_WIN 0x0080 /* the window has been registered with imm32 */
#define WND_OTHER_PROCESS ((WND *)1) /* returned by WIN_GetPtr on unknown window handles */ #define WND_OTHER_PROCESS ((WND *)1) /* returned by WIN_GetPtr on unknown window handles */
#define WND_DESKTOP ((WND *)2) /* returned by WIN_GetPtr on the desktop window */ #define WND_DESKTOP ((WND *)2) /* returned by WIN_GetPtr on the desktop window */
...@@ -207,6 +217,7 @@ WINDOWPROC *get_winproc_ptr( WNDPROC handle ) DECLSPEC_HIDDEN; ...@@ -207,6 +217,7 @@ WINDOWPROC *get_winproc_ptr( WNDPROC handle ) DECLSPEC_HIDDEN;
DWORD get_class_long( HWND hwnd, INT offset, BOOL ansi ) DECLSPEC_HIDDEN; DWORD get_class_long( HWND hwnd, INT offset, BOOL ansi ) DECLSPEC_HIDDEN;
ULONG_PTR get_class_long_ptr( HWND hwnd, INT offset, BOOL ansi ) DECLSPEC_HIDDEN; ULONG_PTR get_class_long_ptr( HWND hwnd, INT offset, BOOL ansi ) DECLSPEC_HIDDEN;
WORD get_class_word( HWND hwnd, INT offset ) DECLSPEC_HIDDEN; WORD get_class_word( HWND hwnd, INT offset ) DECLSPEC_HIDDEN;
WNDPROC get_winproc( WNDPROC proc, BOOL ansi ) DECLSPEC_HIDDEN;
/* cursoricon.c */ /* cursoricon.c */
HICON alloc_cursoricon_handle( BOOL is_icon ) DECLSPEC_HIDDEN; HICON alloc_cursoricon_handle( BOOL is_icon ) DECLSPEC_HIDDEN;
......
...@@ -155,6 +155,60 @@ WND *next_thread_window_ptr( HWND *hwnd ) ...@@ -155,6 +155,60 @@ WND *next_thread_window_ptr( HWND *hwnd )
} }
/******************************************************************* /*******************************************************************
* get_hwnd_message_parent
*
* Return the parent for HWND_MESSAGE windows.
*/
static HWND get_hwnd_message_parent(void)
{
struct user_thread_info *thread_info = get_user_thread_info();
if (!thread_info->msg_window && user_callbacks)
user_callbacks->pGetDesktopWindow(); /* trigger creation */
return thread_info->msg_window;
}
/***********************************************************************
* get_full_window_handle
*
* Convert a possibly truncated window handle to a full 32-bit handle.
*/
static HWND get_full_window_handle( HWND hwnd )
{
WND *win;
if (!hwnd || (ULONG_PTR)hwnd >> 16) return hwnd;
if (LOWORD(hwnd) <= 1 || LOWORD(hwnd) == 0xffff) return hwnd;
/* do sign extension for -2 and -3 */
if (LOWORD(hwnd) >= (WORD)-3) return (HWND)(LONG_PTR)(INT16)LOWORD(hwnd);
if (!(win = get_win_ptr( hwnd ))) return hwnd;
if (win == WND_DESKTOP)
{
if (user_callbacks && LOWORD(hwnd) == LOWORD(user_callbacks->pGetDesktopWindow()))
return user_callbacks->pGetDesktopWindow();
else return get_hwnd_message_parent();
}
if (win != WND_OTHER_PROCESS)
{
hwnd = win->obj.handle;
release_win_ptr( win );
}
else /* may belong to another process */
{
SERVER_START_REQ( get_window_info )
{
req->handle = wine_server_user_handle( hwnd );
if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle );
}
SERVER_END_REQ;
}
return hwnd;
}
/*******************************************************************
* register_window_surface * register_window_surface
* *
* Register a window surface in the global list, possibly replacing another one. * Register a window surface in the global list, possibly replacing another one.
...@@ -307,6 +361,179 @@ static DWORD get_window_thread( HWND hwnd, DWORD *process ) ...@@ -307,6 +361,179 @@ static DWORD get_window_thread( HWND hwnd, DWORD *process )
return tid; return tid;
} }
static LONG_PTR get_win_data( const void *ptr, UINT size )
{
if (size == sizeof(WORD))
{
WORD ret;
memcpy( &ret, ptr, sizeof(ret) );
return ret;
}
else if (size == sizeof(DWORD))
{
DWORD ret;
memcpy( &ret, ptr, sizeof(ret) );
return ret;
}
else
{
LONG_PTR ret;
memcpy( &ret, ptr, sizeof(ret) );
return ret;
}
}
static LONG_PTR get_window_long_size( HWND hwnd, INT offset, UINT size, BOOL ansi )
{
LONG_PTR retval = 0;
WND *win;
if (offset == GWLP_HWNDPARENT)
{
FIXME( "GWLP_HWNDPARENT not supported\n" );
return 0;
}
if (!(win = get_win_ptr( hwnd )))
{
SetLastError( ERROR_INVALID_WINDOW_HANDLE );
return 0;
}
if (win == WND_DESKTOP)
{
switch (offset)
{
case GWL_STYLE:
retval = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; /* message parent is not visible */
if (user_callbacks && get_full_window_handle( hwnd ) == user_callbacks->pGetDesktopWindow())
retval |= WS_VISIBLE;
return retval;
case GWL_EXSTYLE:
case GWLP_USERDATA:
case GWLP_ID:
case GWLP_HINSTANCE:
return 0;
case GWLP_WNDPROC:
SetLastError( ERROR_ACCESS_DENIED );
return 0;
}
SetLastError( ERROR_INVALID_INDEX );
return 0;
}
if (win == WND_OTHER_PROCESS)
{
if (offset == GWLP_WNDPROC)
{
SetLastError( ERROR_ACCESS_DENIED );
return 0;
}
SERVER_START_REQ( set_window_info )
{
req->handle = wine_server_user_handle( hwnd );
req->flags = 0; /* don't set anything, just retrieve */
req->extra_offset = (offset >= 0) ? offset : -1;
req->extra_size = (offset >= 0) ? size : 0;
if (!wine_server_call_err( req ))
{
switch(offset)
{
case GWL_STYLE: retval = reply->old_style; break;
case GWL_EXSTYLE: retval = reply->old_ex_style; break;
case GWLP_ID: retval = reply->old_id; break;
case GWLP_HINSTANCE: retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
case GWLP_USERDATA: retval = reply->old_user_data; break;
default:
if (offset >= 0) retval = get_win_data( &reply->old_extra_value, size );
else SetLastError( ERROR_INVALID_INDEX );
break;
}
}
}
SERVER_END_REQ;
return retval;
}
/* now we have a valid win */
if (offset >= 0)
{
if (offset > (int)(win->cbWndExtra - size))
{
WARN("Invalid offset %d\n", offset );
release_win_ptr( win );
SetLastError( ERROR_INVALID_INDEX );
return 0;
}
retval = get_win_data( (char *)win->wExtra + offset, size );
/* Special case for dialog window procedure */
if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && win->dlgInfo)
retval = (LONG_PTR)get_winproc( (WNDPROC)retval, ansi );
release_win_ptr( win );
return retval;
}
switch(offset)
{
case GWLP_USERDATA: retval = win->userdata; break;
case GWL_STYLE: retval = win->dwStyle; break;
case GWL_EXSTYLE: retval = win->dwExStyle; break;
case GWLP_ID: retval = win->wIDmenu; break;
case GWLP_HINSTANCE: retval = (ULONG_PTR)win->hInstance; break;
case GWLP_WNDPROC:
/* This looks like a hack only for the edit control (see tests). This makes these controls
* more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
* that the hack is in GetWindowLongPtr[AW], not in winprocs.
*/
if (win->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!!ansi != !(win->flags & WIN_ISUNICODE)))
retval = (ULONG_PTR)win->winproc;
else
retval = (ULONG_PTR)get_winproc( win->winproc, ansi );
break;
default:
WARN("Unknown offset %d\n", offset );
SetLastError( ERROR_INVALID_INDEX );
break;
}
release_win_ptr( win );
return retval;
}
/* see GetWindowLongW */
static DWORD get_window_long( HWND hwnd, INT offset )
{
return get_window_long_size( hwnd, offset, sizeof(LONG), FALSE );
}
/* see GetWindowLongPtr */
static ULONG_PTR get_window_long_ptr( HWND hwnd, INT offset, BOOL ansi )
{
return get_window_long_size( hwnd, offset, sizeof(LONG_PTR), ansi );
}
/* see GetWindowWord */
static WORD get_window_word( HWND hwnd, INT offset )
{
switch(offset)
{
case GWLP_ID:
case GWLP_HINSTANCE:
case GWLP_HWNDPARENT:
break;
default:
if (offset < 0)
{
WARN("Invalid offset %d\n", offset );
SetLastError( ERROR_INVALID_INDEX );
return 0;
}
break;
}
return get_window_long_size( hwnd, offset, sizeof(WORD), TRUE );
}
/*********************************************************************** /***********************************************************************
* NtUserGetProp (win32u.@) * NtUserGetProp (win32u.@)
* *
...@@ -502,8 +729,18 @@ ULONG_PTR WINAPI NtUserCallHwndParam( HWND hwnd, DWORD_PTR param, DWORD code ) ...@@ -502,8 +729,18 @@ ULONG_PTR WINAPI NtUserCallHwndParam( HWND hwnd, DWORD_PTR param, DWORD code )
return get_class_long_ptr( hwnd, param, FALSE ); return get_class_long_ptr( hwnd, param, FALSE );
case NtUserGetClassWord: case NtUserGetClassWord:
return get_class_word( hwnd, param ); return get_class_word( hwnd, param );
case NtUserGetWindowLongA:
return get_window_long_size( hwnd, param, sizeof(LONG), TRUE );
case NtUserGetWindowLongW:
return get_window_long( hwnd, param );
case NtUserGetWindowLongPtrA:
return get_window_long_ptr( hwnd, param, TRUE );
case NtUserGetWindowLongPtrW:
return get_window_long_ptr( hwnd, param, FALSE );
case NtUserGetWindowThread: case NtUserGetWindowThread:
return get_window_thread( hwnd, (DWORD *)param ); return get_window_thread( hwnd, (DWORD *)param );
case NtUserGetWindowWord:
return get_window_word( hwnd, param );
default: default:
FIXME( "invalid code %u\n", code ); FIXME( "invalid code %u\n", code );
return 0; return 0;
......
...@@ -151,7 +151,12 @@ enum ...@@ -151,7 +151,12 @@ enum
NtUserGetClassLongPtrA, NtUserGetClassLongPtrA,
NtUserGetClassLongPtrW, NtUserGetClassLongPtrW,
NtUserGetClassWord, NtUserGetClassWord,
NtUserGetWindowLongA,
NtUserGetWindowLongW,
NtUserGetWindowLongPtrA,
NtUserGetWindowLongPtrW,
NtUserGetWindowThread, NtUserGetWindowThread,
NtUserGetWindowWord,
}; };
/* color index used to retrieve system 55aa brush */ /* color index used to retrieve system 55aa brush */
......
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