user32: Add support for RTL window layouts in MapWindowPoints.

This commit is contained in:
Alexandre Julliard 2010-09-22 20:27:52 +02:00
parent cf72f406ec
commit 5702324b37
7 changed files with 113 additions and 41 deletions

View File

@ -6164,6 +6164,44 @@ static void test_winregion(void)
DestroyWindow(hwnd); DestroyWindow(hwnd);
} }
static void test_rtl_layout(void)
{
HWND parent, child;
RECT r;
POINT pt;
if (!pSetProcessDefaultLayout)
{
win_skip( "SetProcessDefaultLayout not supported\n" );
return;
}
parent = CreateWindowExA(WS_EX_LAYOUTRTL, "static", NULL, WS_POPUP, 100, 100, 300, 300, NULL, 0, 0, NULL);
child = CreateWindowExA(0, "static", NULL, WS_CHILD, 10, 10, 20, 20, parent, 0, 0, NULL);
GetWindowRect( parent, &r );
ok( r.left == 100 && r.right == 400, "wrong rect %d,%d - %d,%d\n", r.left, r.top, r.right, r.bottom );
GetClientRect( parent, &r );
ok( r.left == 0 && r.right == 300, "wrong rect %d,%d - %d,%d\n", r.left, r.top, r.right, r.bottom );
GetClientRect( child, &r );
ok( r.left == 0 && r.right == 20, "wrong rect %d,%d - %d,%d\n", r.left, r.top, r.right, r.bottom );
MapWindowPoints( child, parent, (POINT *)&r, 2 );
ok( r.left == 10 && r.right == 30, "wrong rect %d,%d - %d,%d\n", r.left, r.top, r.right, r.bottom );
GetWindowRect( child, &r );
ok( r.left == 370 && r.right == 390, "wrong rect %d,%d - %d,%d\n", r.left, r.top, r.right, r.bottom );
MapWindowPoints( NULL, parent, (POINT *)&r, 2 );
ok( r.left == 10 && r.right == 30, "wrong rect %d,%d - %d,%d\n", r.left, r.top, r.right, r.bottom );
GetWindowRect( child, &r );
MapWindowPoints( NULL, parent, (POINT *)&r, 1 );
MapWindowPoints( NULL, parent, (POINT *)&r + 1, 1 );
ok( r.left == 30 && r.right == 10, "wrong rect %d,%d - %d,%d\n", r.left, r.top, r.right, r.bottom );
pt.x = pt.y = 12;
MapWindowPoints( child, parent, &pt, 1 );
ok( pt.x == 22 && pt.y == 22, "wrong point %d,%d\n", pt.x, pt.y );
DestroyWindow( child );
DestroyWindow( parent );
}
START_TEST(win) START_TEST(win)
{ {
HMODULE user32 = GetModuleHandleA( "user32.dll" ); HMODULE user32 = GetModuleHandleA( "user32.dll" );
@ -6218,6 +6256,7 @@ START_TEST(win)
test_capture_2(); test_capture_2();
test_capture_3(hwndMain, hwndMain2); test_capture_3(hwndMain, hwndMain2);
test_capture_4(); test_capture_4();
test_rtl_layout();
test_CreateWindow(); test_CreateWindow();
test_parent_owner(); test_parent_owner();

View File

@ -422,75 +422,83 @@ HWND WINAPI ChildWindowFromPointEx( HWND hwndParent, POINT pt, UINT uFlags)
* Calculate the offset between the origin of the two windows. Used * Calculate the offset between the origin of the two windows. Used
* to implement MapWindowPoints. * to implement MapWindowPoints.
*/ */
static void WINPOS_GetWinOffset( HWND hwndFrom, HWND hwndTo, POINT *offset ) static POINT WINPOS_GetWinOffset( HWND hwndFrom, HWND hwndTo, BOOL *mirrored )
{ {
WND * wndPtr; WND * wndPtr;
POINT offset;
BOOL mirror_from, mirror_to;
HWND hwnd;
offset->x = offset->y = 0; offset.x = offset.y = 0;
*mirrored = mirror_from = mirror_to = FALSE;
/* Translate source window origin to screen coords */ /* Translate source window origin to screen coords */
if (hwndFrom) if (hwndFrom)
{ {
HWND hwnd = hwndFrom; if (!(wndPtr = WIN_GetPtr( hwndFrom ))) return offset;
if (wndPtr == WND_OTHER_PROCESS) goto other_process;
while (hwnd) if (wndPtr != WND_DESKTOP)
{ {
if (hwnd == hwndTo) return; if (wndPtr->dwExStyle & WS_EX_LAYOUTRTL)
if (!(wndPtr = WIN_GetPtr( hwnd )))
{ {
ERR( "bad hwndFrom = %p\n", hwnd ); mirror_from = TRUE;
return; offset.x += wndPtr->rectClient.right - wndPtr->rectClient.left;
} }
if (wndPtr == WND_DESKTOP) break; while (wndPtr != WND_DESKTOP)
if (wndPtr == WND_OTHER_PROCESS) goto other_process;
if (wndPtr->parent)
{ {
offset->x += wndPtr->rectClient.left; offset.x += wndPtr->rectClient.left;
offset->y += wndPtr->rectClient.top; offset.y += wndPtr->rectClient.top;
hwnd = wndPtr->parent;
WIN_ReleasePtr( wndPtr );
if (!(wndPtr = WIN_GetPtr( hwnd ))) break;
if (wndPtr == WND_OTHER_PROCESS) goto other_process;
} }
hwnd = wndPtr->parent;
WIN_ReleasePtr( wndPtr );
} }
} }
/* Translate origin to destination window coords */ /* Translate origin to destination window coords */
if (hwndTo) if (hwndTo)
{ {
HWND hwnd = hwndTo; if (!(wndPtr = WIN_GetPtr( hwndTo ))) return offset;
if (wndPtr == WND_OTHER_PROCESS) goto other_process;
while (hwnd) if (wndPtr != WND_DESKTOP)
{ {
if (!(wndPtr = WIN_GetPtr( hwnd ))) if (wndPtr->dwExStyle & WS_EX_LAYOUTRTL)
{ {
ERR( "bad hwndTo = %p\n", hwnd ); mirror_to = TRUE;
return; offset.x -= wndPtr->rectClient.right - wndPtr->rectClient.left;
} }
if (wndPtr == WND_DESKTOP) break; while (wndPtr != WND_DESKTOP)
if (wndPtr == WND_OTHER_PROCESS) goto other_process;
if (wndPtr->parent)
{ {
offset->x -= wndPtr->rectClient.left; offset.x -= wndPtr->rectClient.left;
offset->y -= wndPtr->rectClient.top; offset.y -= wndPtr->rectClient.top;
hwnd = wndPtr->parent;
WIN_ReleasePtr( wndPtr );
if (!(wndPtr = WIN_GetPtr( hwnd ))) break;
if (wndPtr == WND_OTHER_PROCESS) goto other_process;
} }
hwnd = wndPtr->parent;
WIN_ReleasePtr( wndPtr );
} }
} }
return;
*mirrored = mirror_from ^ mirror_to;
if (mirror_from) offset.x = -offset.x;
return offset;
other_process: /* one of the parents may belong to another process, do it the hard way */ other_process: /* one of the parents may belong to another process, do it the hard way */
offset->x = offset->y = 0; offset.x = offset.y = 0;
SERVER_START_REQ( get_windows_offset ) SERVER_START_REQ( get_windows_offset )
{ {
req->from = wine_server_user_handle( hwndFrom ); req->from = wine_server_user_handle( hwndFrom );
req->to = wine_server_user_handle( hwndTo ); req->to = wine_server_user_handle( hwndTo );
if (!wine_server_call( req )) if (!wine_server_call( req ))
{ {
offset->x = reply->x; offset.x = reply->x;
offset->y = reply->y; offset.y = reply->y;
*mirrored = reply->mirror;
} }
} }
SERVER_END_REQ; SERVER_END_REQ;
return offset;
} }
@ -499,14 +507,21 @@ static void WINPOS_GetWinOffset( HWND hwndFrom, HWND hwndTo, POINT *offset )
*/ */
INT WINAPI MapWindowPoints( HWND hwndFrom, HWND hwndTo, LPPOINT lppt, UINT count ) INT WINAPI MapWindowPoints( HWND hwndFrom, HWND hwndTo, LPPOINT lppt, UINT count )
{ {
POINT offset; BOOL mirrored;
POINT offset = WINPOS_GetWinOffset( hwndFrom, hwndTo, &mirrored );
UINT i;
WINPOS_GetWinOffset( hwndFrom, hwndTo, &offset ); for (i = 0; i < count; i++)
while (count--)
{ {
lppt->x += offset.x; lppt[i].x += offset.x;
lppt->y += offset.y; lppt[i].y += offset.y;
lppt++; if (mirrored) lppt[i].x = -lppt[i].x;
}
if (mirrored && count == 2) /* special case for rectangle */
{
int tmp = lppt[0].x;
lppt[0].x = lppt[1].x;
lppt[1].x = tmp;
} }
return MAKELONG( LOWORD(offset.x), LOWORD(offset.y) ); return MAKELONG( LOWORD(offset.x), LOWORD(offset.y) );
} }

View File

@ -3328,6 +3328,8 @@ struct get_windows_offset_reply
struct reply_header __header; struct reply_header __header;
int x; int x;
int y; int y;
int mirror;
char __pad_20[4];
}; };
@ -5517,6 +5519,6 @@ union generic_reply
struct set_cursor_reply set_cursor_reply; struct set_cursor_reply set_cursor_reply;
}; };
#define SERVER_PROTOCOL_VERSION 409 #define SERVER_PROTOCOL_VERSION 410
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */ #endif /* __WINE_WINE_SERVER_PROTOCOL_H */

View File

@ -2383,6 +2383,7 @@ enum coords_relative
@REPLY @REPLY
int x; /* x coordinate offset */ int x; /* x coordinate offset */
int y; /* y coordinate offset */ int y; /* y coordinate offset */
int mirror; /* whether to mirror the x coordinate */
@END @END

View File

@ -1605,7 +1605,8 @@ C_ASSERT( FIELD_OFFSET(struct get_windows_offset_request, to) == 16 );
C_ASSERT( sizeof(struct get_windows_offset_request) == 24 ); C_ASSERT( sizeof(struct get_windows_offset_request) == 24 );
C_ASSERT( FIELD_OFFSET(struct get_windows_offset_reply, x) == 8 ); C_ASSERT( FIELD_OFFSET(struct get_windows_offset_reply, x) == 8 );
C_ASSERT( FIELD_OFFSET(struct get_windows_offset_reply, y) == 12 ); C_ASSERT( FIELD_OFFSET(struct get_windows_offset_reply, y) == 12 );
C_ASSERT( sizeof(struct get_windows_offset_reply) == 16 ); C_ASSERT( FIELD_OFFSET(struct get_windows_offset_reply, mirror) == 16 );
C_ASSERT( sizeof(struct get_windows_offset_reply) == 24 );
C_ASSERT( FIELD_OFFSET(struct get_visible_region_request, window) == 12 ); C_ASSERT( FIELD_OFFSET(struct get_visible_region_request, window) == 12 );
C_ASSERT( FIELD_OFFSET(struct get_visible_region_request, flags) == 16 ); C_ASSERT( FIELD_OFFSET(struct get_visible_region_request, flags) == 16 );
C_ASSERT( sizeof(struct get_visible_region_request) == 24 ); C_ASSERT( sizeof(struct get_visible_region_request) == 24 );

View File

@ -2839,6 +2839,7 @@ static void dump_get_windows_offset_reply( const struct get_windows_offset_reply
{ {
fprintf( stderr, " x=%d", req->x ); fprintf( stderr, " x=%d", req->x );
fprintf( stderr, ", y=%d", req->y ); fprintf( stderr, ", y=%d", req->y );
fprintf( stderr, ", mirror=%d", req->mirror );
} }
static void dump_get_visible_region_request( const struct get_visible_region_request *req ) static void dump_get_visible_region_request( const struct get_visible_region_request *req )

View File

@ -2193,11 +2193,17 @@ DECL_HANDLER(set_window_text)
DECL_HANDLER(get_windows_offset) DECL_HANDLER(get_windows_offset)
{ {
struct window *win; struct window *win;
int mirror_from = 0, mirror_to = 0;
reply->x = reply->y = 0; reply->x = reply->y = 0;
if (req->from) if (req->from)
{ {
if (!(win = get_window( req->from ))) return; if (!(win = get_window( req->from ))) return;
if (win->ex_style & WS_EX_LAYOUTRTL)
{
mirror_from = 1;
reply->x += win->client_rect.right - win->client_rect.left - 1;
}
while (win && !is_desktop_window(win)) while (win && !is_desktop_window(win))
{ {
reply->x += win->client_rect.left; reply->x += win->client_rect.left;
@ -2208,6 +2214,11 @@ DECL_HANDLER(get_windows_offset)
if (req->to) if (req->to)
{ {
if (!(win = get_window( req->to ))) return; if (!(win = get_window( req->to ))) return;
if (win->ex_style & WS_EX_LAYOUTRTL)
{
mirror_to = 1;
reply->x -= win->client_rect.right - win->client_rect.left - 1;
}
while (win && !is_desktop_window(win)) while (win && !is_desktop_window(win))
{ {
reply->x -= win->client_rect.left; reply->x -= win->client_rect.left;
@ -2215,6 +2226,8 @@ DECL_HANDLER(get_windows_offset)
win = win->parent; win = win->parent;
} }
} }
if (mirror_from) reply->x = -reply->x;
reply->mirror = mirror_from ^ mirror_to;
} }