Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-cw
Commits
b2db69ef
Commit
b2db69ef
authored
Jun 08, 2022
by
Jacek Caban
Committed by
Alexandre Julliard
Jun 09, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
win32u: Move NtUserScrollWindowEx implementation from user32.
Signed-off-by:
Jacek Caban
<
jacek@codeweavers.com
>
parent
ff66d8ee
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
239 additions
and
251 deletions
+239
-251
edit.c
dlls/user32/edit.c
+2
-2
listbox.c
dlls/user32/listbox.c
+4
-4
mdi.c
dlls/user32/mdi.c
+4
-4
painting.c
dlls/user32/painting.c
+2
-238
user32.spec
dlls/user32/user32.spec
+1
-1
dce.c
dlls/win32u/dce.c
+204
-0
gdiobj.c
dlls/win32u/gdiobj.c
+1
-0
win32u.spec
dlls/win32u/win32u.spec
+1
-1
win32u_private.h
dlls/win32u/win32u_private.h
+4
-0
window.c
dlls/win32u/window.c
+1
-1
wrappers.c
dlls/win32u/wrappers.c
+9
-0
ntuser.h
include/ntuser.h
+6
-0
No files found.
dlls/user32/edit.c
View file @
b2db69ef
...
...
@@ -1708,8 +1708,8 @@ static BOOL EDIT_EM_LineScroll_internal(EDITSTATE *es, INT dx, INT dy)
GetClientRect
(
es
->
hwndSelf
,
&
rc1
);
IntersectRect
(
&
rc
,
&
rc1
,
&
es
->
format_rect
);
ScrollWindowEx
(
es
->
hwndSelf
,
-
dx
,
dy
,
NULL
,
&
rc
,
NULL
,
NULL
,
SW_INVALIDATE
);
NtUser
ScrollWindowEx
(
es
->
hwndSelf
,
-
dx
,
dy
,
NULL
,
&
rc
,
NULL
,
NULL
,
SW_INVALIDATE
);
/* force scroll info update */
EDIT_UpdateScrollInfo
(
es
);
}
...
...
dlls/user32/listbox.c
View file @
b2db69ef
...
...
@@ -439,8 +439,8 @@ static LRESULT LISTBOX_SetTopItem( LB_DESCR *descr, INT index, BOOL scroll )
else
dy
=
(
descr
->
top_item
-
index
)
*
descr
->
item_height
;
ScrollWindowEx
(
descr
->
self
,
dx
,
dy
,
NULL
,
NULL
,
0
,
NULL
,
SW_INVALIDATE
|
SW_ERASE
|
SW_SCROLLCHILDREN
);
NtUser
ScrollWindowEx
(
descr
->
self
,
dx
,
dy
,
NULL
,
NULL
,
0
,
NULL
,
SW_INVALIDATE
|
SW_ERASE
|
SW_SCROLLCHILDREN
);
}
else
InvalidateRect
(
descr
->
self
,
NULL
,
TRUE
);
...
...
@@ -1340,8 +1340,8 @@ static void LISTBOX_SetHorizontalPos( LB_DESCR *descr, INT pos )
/* Invalidate the focused item so it will be repainted correctly */
if
(
LISTBOX_GetItemRect
(
descr
,
descr
->
focus_item
,
&
rect
)
==
1
)
InvalidateRect
(
descr
->
self
,
&
rect
,
TRUE
);
ScrollWindowEx
(
descr
->
self
,
diff
,
0
,
NULL
,
NULL
,
0
,
NULL
,
SW_INVALIDATE
|
SW_ERASE
|
SW_SCROLLCHILDREN
);
NtUser
ScrollWindowEx
(
descr
->
self
,
diff
,
0
,
NULL
,
NULL
,
0
,
NULL
,
SW_INVALIDATE
|
SW_ERASE
|
SW_SCROLLCHILDREN
);
}
else
InvalidateRect
(
descr
->
self
,
NULL
,
TRUE
);
...
...
dlls/user32/mdi.c
View file @
b2db69ef
...
...
@@ -1822,11 +1822,11 @@ void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam,
SetScrollPos
(
hWnd
,
(
uMsg
==
WM_VSCROLL
)
?
SB_VERT
:
SB_HORZ
,
newPos
,
TRUE
);
if
(
uMsg
==
WM_VSCROLL
)
ScrollWindowEx
(
hWnd
,
0
,
curPos
-
newPos
,
NULL
,
NULL
,
0
,
NULL
,
SW_INVALIDATE
|
SW_ERASE
|
SW_SCROLLCHILDREN
);
NtUserScrollWindowEx
(
hWnd
,
0
,
curPos
-
newPos
,
NULL
,
NULL
,
0
,
NULL
,
SW_INVALIDATE
|
SW_ERASE
|
SW_SCROLLCHILDREN
);
else
ScrollWindowEx
(
hWnd
,
curPos
-
newPos
,
0
,
NULL
,
NULL
,
0
,
NULL
,
SW_INVALIDATE
|
SW_ERASE
|
SW_SCROLLCHILDREN
);
NtUserScrollWindowEx
(
hWnd
,
curPos
-
newPos
,
0
,
NULL
,
NULL
,
0
,
NULL
,
SW_INVALIDATE
|
SW_ERASE
|
SW_SCROLLCHILDREN
);
done:
SetThreadDpiAwarenessContext
(
context
);
}
...
...
dlls/user32/painting.c
View file @
b2db69ef
...
...
@@ -19,72 +19,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <assert.h>
#include <stdarg.h>
#include <string.h>
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "user_private.h"
#include "win.h"
#include "controls.h"
#include "wine/server.h"
#include "wine/list.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL
(
win
);
/*************************************************************************
* fix_caret
*
* Helper for ScrollWindowEx:
* If the return value is 0, no special caret handling is necessary.
* Otherwise the return value is the handle of the window that owns the
* caret. Its caret needs to be hidden during the scroll operation and
* moved to new_caret_pos if move_caret is TRUE.
*/
static
HWND
fix_caret
(
HWND
hWnd
,
const
RECT
*
scroll_rect
,
INT
dx
,
INT
dy
,
UINT
flags
,
LPBOOL
move_caret
,
LPPOINT
new_caret_pos
)
{
GUITHREADINFO
info
;
RECT
rect
,
mapped_rcCaret
;
info
.
cbSize
=
sizeof
(
info
);
if
(
!
NtUserGetGUIThreadInfo
(
GetCurrentThreadId
(),
&
info
))
return
0
;
if
(
!
info
.
hwndCaret
)
return
0
;
mapped_rcCaret
=
info
.
rcCaret
;
if
(
info
.
hwndCaret
==
hWnd
)
{
/* The caret needs to be moved along with scrolling even if it's
* outside the visible area. Otherwise, when the caret is scrolled
* out from the view, the position won't get updated anymore and
* the caret will never scroll back again. */
*
move_caret
=
TRUE
;
new_caret_pos
->
x
=
info
.
rcCaret
.
left
+
dx
;
new_caret_pos
->
y
=
info
.
rcCaret
.
top
+
dy
;
}
else
{
*
move_caret
=
FALSE
;
if
(
!
(
flags
&
SW_SCROLLCHILDREN
)
||
!
IsChild
(
hWnd
,
info
.
hwndCaret
))
return
0
;
MapWindowPoints
(
info
.
hwndCaret
,
hWnd
,
(
LPPOINT
)
&
mapped_rcCaret
,
2
);
}
/* If the caret is not in the src/dest rects, all is fine done. */
if
(
!
IntersectRect
(
&
rect
,
scroll_rect
,
&
mapped_rcCaret
))
{
rect
=
*
scroll_rect
;
OffsetRect
(
&
rect
,
dx
,
dy
);
if
(
!
IntersectRect
(
&
rect
,
&
rect
,
&
mapped_rcCaret
))
return
0
;
}
/* Indicate that the caret needs to be updated during the scrolling. */
return
info
.
hwndCaret
;
}
/***********************************************************************
...
...
@@ -197,177 +132,6 @@ BOOL WINAPI ValidateRect( HWND hwnd, const RECT *rect )
}
static
INT
scroll_window
(
HWND
hwnd
,
INT
dx
,
INT
dy
,
const
RECT
*
rect
,
const
RECT
*
clipRect
,
HRGN
hrgnUpdate
,
LPRECT
rcUpdate
,
UINT
flags
,
BOOL
is_ex
)
{
INT
retVal
=
NULLREGION
;
BOOL
bOwnRgn
=
TRUE
;
BOOL
bUpdate
=
(
rcUpdate
||
hrgnUpdate
||
flags
&
(
SW_INVALIDATE
|
SW_ERASE
));
int
rdw_flags
;
HRGN
hrgnTemp
;
HRGN
hrgnWinupd
=
0
;
HDC
hDC
;
RECT
rc
,
cliprc
;
HWND
hwndCaret
=
NULL
;
BOOL
moveCaret
=
FALSE
;
POINT
newCaretPos
;
TRACE
(
"%p, %d,%d hrgnUpdate=%p rcUpdate = %p %s %04x
\n
"
,
hwnd
,
dx
,
dy
,
hrgnUpdate
,
rcUpdate
,
wine_dbgstr_rect
(
rect
),
flags
);
TRACE
(
"clipRect = %s
\n
"
,
wine_dbgstr_rect
(
clipRect
));
if
(
flags
&
~
(
SW_SCROLLCHILDREN
|
SW_INVALIDATE
|
SW_ERASE
))
FIXME
(
"some flags (%04x) are unhandled
\n
"
,
flags
);
rdw_flags
=
(
flags
&
SW_ERASE
)
&&
(
flags
&
SW_INVALIDATE
)
?
RDW_INVALIDATE
|
RDW_ERASE
:
RDW_INVALIDATE
;
if
(
!
WIN_IsWindowDrawable
(
hwnd
,
TRUE
))
return
ERROR
;
hwnd
=
WIN_GetFullHandle
(
hwnd
);
GetClientRect
(
hwnd
,
&
rc
);
if
(
clipRect
)
IntersectRect
(
&
cliprc
,
&
rc
,
clipRect
);
else
cliprc
=
rc
;
if
(
rect
)
IntersectRect
(
&
rc
,
&
rc
,
rect
);
if
(
hrgnUpdate
)
bOwnRgn
=
FALSE
;
else
if
(
bUpdate
)
hrgnUpdate
=
CreateRectRgn
(
0
,
0
,
0
,
0
);
newCaretPos
.
x
=
newCaretPos
.
y
=
0
;
if
(
!
IsRectEmpty
(
&
cliprc
)
&&
(
dx
||
dy
))
{
DWORD
dcxflags
=
0
;
DWORD
style
=
GetWindowLongW
(
hwnd
,
GWL_STYLE
);
hwndCaret
=
fix_caret
(
hwnd
,
&
rc
,
dx
,
dy
,
flags
,
&
moveCaret
,
&
newCaretPos
);
if
(
hwndCaret
)
NtUserHideCaret
(
hwndCaret
);
if
(
is_ex
)
dcxflags
|=
DCX_CACHE
;
if
(
style
&
WS_CLIPSIBLINGS
)
dcxflags
|=
DCX_CLIPSIBLINGS
;
if
(
GetClassLongW
(
hwnd
,
GCL_STYLE
)
&
CS_PARENTDC
)
dcxflags
|=
DCX_PARENTCLIP
;
if
(
!
(
flags
&
SW_SCROLLCHILDREN
)
&&
(
style
&
WS_CLIPCHILDREN
))
dcxflags
|=
DCX_CLIPCHILDREN
;
hDC
=
NtUserGetDCEx
(
hwnd
,
0
,
dcxflags
);
if
(
hDC
)
{
NtUserScrollDC
(
hDC
,
dx
,
dy
,
&
rc
,
&
cliprc
,
hrgnUpdate
,
rcUpdate
);
NtUserReleaseDC
(
hwnd
,
hDC
);
if
(
!
bUpdate
)
NtUserRedrawWindow
(
hwnd
,
NULL
,
hrgnUpdate
,
rdw_flags
);
}
/* If the windows has an update region, this must be
* scrolled as well. Keep a copy in hrgnWinupd
* to be added to hrngUpdate at the end. */
hrgnTemp
=
CreateRectRgn
(
0
,
0
,
0
,
0
);
retVal
=
NtUserGetUpdateRgn
(
hwnd
,
hrgnTemp
,
FALSE
);
if
(
retVal
!=
NULLREGION
)
{
HRGN
hrgnClip
=
CreateRectRgnIndirect
(
&
cliprc
);
if
(
!
bOwnRgn
)
{
hrgnWinupd
=
CreateRectRgn
(
0
,
0
,
0
,
0
);
CombineRgn
(
hrgnWinupd
,
hrgnTemp
,
0
,
RGN_COPY
);
}
OffsetRgn
(
hrgnTemp
,
dx
,
dy
);
CombineRgn
(
hrgnTemp
,
hrgnTemp
,
hrgnClip
,
RGN_AND
);
if
(
!
bOwnRgn
)
CombineRgn
(
hrgnWinupd
,
hrgnWinupd
,
hrgnTemp
,
RGN_OR
);
NtUserRedrawWindow
(
hwnd
,
NULL
,
hrgnTemp
,
rdw_flags
);
/* Catch the case where the scrolling amount exceeds the size of the
* original window. This generated a second update area that is the
* location where the original scrolled content would end up.
* This second region is not returned by the ScrollDC and sets
* ScrollWindowEx apart from just a ScrollDC.
*
* This has been verified with testing on windows.
*/
if
(
abs
(
dx
)
>
abs
(
rc
.
right
-
rc
.
left
)
||
abs
(
dy
)
>
abs
(
rc
.
bottom
-
rc
.
top
))
{
SetRectRgn
(
hrgnTemp
,
rc
.
left
+
dx
,
rc
.
top
+
dy
,
rc
.
right
+
dx
,
rc
.
bottom
+
dy
);
CombineRgn
(
hrgnTemp
,
hrgnTemp
,
hrgnClip
,
RGN_AND
);
CombineRgn
(
hrgnUpdate
,
hrgnUpdate
,
hrgnTemp
,
RGN_OR
);
if
(
rcUpdate
)
{
RECT
rcTemp
;
GetRgnBox
(
hrgnTemp
,
&
rcTemp
);
UnionRect
(
rcUpdate
,
rcUpdate
,
&
rcTemp
);
}
if
(
!
bOwnRgn
)
CombineRgn
(
hrgnWinupd
,
hrgnWinupd
,
hrgnTemp
,
RGN_OR
);
}
DeleteObject
(
hrgnClip
);
}
DeleteObject
(
hrgnTemp
);
}
else
{
/* nothing was scrolled */
if
(
!
bOwnRgn
)
SetRectRgn
(
hrgnUpdate
,
0
,
0
,
0
,
0
);
SetRectEmpty
(
rcUpdate
);
}
if
(
flags
&
SW_SCROLLCHILDREN
)
{
HWND
*
list
=
WIN_ListChildren
(
hwnd
);
if
(
list
)
{
int
i
;
RECT
r
,
dummy
;
for
(
i
=
0
;
list
[
i
];
i
++
)
{
WIN_GetRectangles
(
list
[
i
],
COORDS_PARENT
,
&
r
,
NULL
);
if
(
!
rect
||
IntersectRect
(
&
dummy
,
&
r
,
rect
))
NtUserSetWindowPos
(
list
[
i
],
0
,
r
.
left
+
dx
,
r
.
top
+
dy
,
0
,
0
,
SWP_NOZORDER
|
SWP_NOSIZE
|
SWP_NOACTIVATE
|
SWP_NOREDRAW
|
SWP_DEFERERASE
);
}
HeapFree
(
GetProcessHeap
(),
0
,
list
);
}
}
if
(
flags
&
(
SW_INVALIDATE
|
SW_ERASE
)
)
NtUserRedrawWindow
(
hwnd
,
NULL
,
hrgnUpdate
,
rdw_flags
|
((
flags
&
SW_SCROLLCHILDREN
)
?
RDW_ALLCHILDREN
:
0
)
);
if
(
hrgnWinupd
)
{
CombineRgn
(
hrgnUpdate
,
hrgnUpdate
,
hrgnWinupd
,
RGN_OR
);
DeleteObject
(
hrgnWinupd
);
}
if
(
moveCaret
)
SetCaretPos
(
newCaretPos
.
x
,
newCaretPos
.
y
);
if
(
hwndCaret
)
NtUserShowCaret
(
hwndCaret
);
if
(
bOwnRgn
&&
hrgnUpdate
)
DeleteObject
(
hrgnUpdate
);
return
retVal
;
}
/*************************************************************************
* ScrollWindowEx (USER32.@)
*
* Note: contrary to what the doc says, pixels that are scrolled from the
* outside of clipRect to the inside are NOT painted.
*
*/
INT
WINAPI
ScrollWindowEx
(
HWND
hwnd
,
INT
dx
,
INT
dy
,
const
RECT
*
rect
,
const
RECT
*
clipRect
,
HRGN
hrgnUpdate
,
LPRECT
rcUpdate
,
UINT
flags
)
{
return
scroll_window
(
hwnd
,
dx
,
dy
,
rect
,
clipRect
,
hrgnUpdate
,
rcUpdate
,
flags
,
TRUE
);
}
/*************************************************************************
* ScrollWindow (USER32.@)
*
...
...
@@ -375,8 +139,8 @@ INT WINAPI ScrollWindowEx( HWND hwnd, INT dx, INT dy,
BOOL
WINAPI
ScrollWindow
(
HWND
hwnd
,
INT
dx
,
INT
dy
,
const
RECT
*
rect
,
const
RECT
*
clipRect
)
{
return
scroll_window
(
hwnd
,
dx
,
dy
,
rect
,
clipRect
,
0
,
NULL
,
SW_INVALIDATE
|
SW_ERASE
|
(
rect
?
0
:
SW_SCROLLCHILDREN
),
FALSE
)
!=
ERROR
;
UINT
flags
=
SW_INVALIDATE
|
SW_ERASE
|
(
rect
?
0
:
SW_SCROLLCHILDREN
)
|
SW_NODCCACHE
;
return
NtUserScrollWindowEx
(
hwnd
,
dx
,
dy
,
rect
,
clipRect
,
0
,
NULL
,
flags
)
;
}
/************************************************************************
...
...
dlls/user32/user32.spec
View file @
b2db69ef
...
...
@@ -630,7 +630,7 @@
@ stdcall ScrollChildren(long long long long)
@ stdcall ScrollDC(long long long ptr ptr long ptr) NtUserScrollDC
@ stdcall ScrollWindow(long long long ptr ptr)
@ stdcall ScrollWindowEx(long long long ptr ptr long ptr long)
@ stdcall ScrollWindowEx(long long long ptr ptr long ptr long)
NtUserScrollWindowEx
@ stdcall SendDlgItemMessageA(long long long long long)
@ stdcall SendDlgItemMessageW(long long long long long)
@ stdcall SendIMEMessageExA(long long)
...
...
dlls/win32u/dce.c
View file @
b2db69ef
...
...
@@ -1591,3 +1591,207 @@ BOOL WINAPI NtUserLockWindowUpdate( HWND hwnd )
}
return
!
InterlockedCompareExchangePointer
(
(
void
**
)
&
locked_hwnd
,
hwnd
,
0
);
}
/*************************************************************************
* fix_caret
*
* Helper for NtUserScrollWindowEx:
* If the return value is 0, no special caret handling is necessary.
* Otherwise the return value is the handle of the window that owns the
* caret. Its caret needs to be hidden during the scroll operation and
* moved to new_caret_pos if move_caret is TRUE.
*/
static
HWND
fix_caret
(
HWND
hwnd
,
const
RECT
*
scroll_rect
,
INT
dx
,
INT
dy
,
UINT
flags
,
BOOL
*
move_caret
,
POINT
*
new_caret_pos
)
{
RECT
rect
,
mapped_caret
;
GUITHREADINFO
info
;
info
.
cbSize
=
sizeof
(
info
);
if
(
!
NtUserGetGUIThreadInfo
(
GetCurrentThreadId
(),
&
info
))
return
0
;
if
(
!
info
.
hwndCaret
)
return
0
;
mapped_caret
=
info
.
rcCaret
;
if
(
info
.
hwndCaret
==
hwnd
)
{
/* The caret needs to be moved along with scrolling even if it's
* outside the visible area. Otherwise, when the caret is scrolled
* out from the view, the position won't get updated anymore and
* the caret will never scroll back again. */
*
move_caret
=
TRUE
;
new_caret_pos
->
x
=
info
.
rcCaret
.
left
+
dx
;
new_caret_pos
->
y
=
info
.
rcCaret
.
top
+
dy
;
}
else
{
*
move_caret
=
FALSE
;
if
(
!
(
flags
&
SW_SCROLLCHILDREN
)
||
!
is_child
(
hwnd
,
info
.
hwndCaret
))
return
0
;
map_window_points
(
info
.
hwndCaret
,
hwnd
,
(
POINT
*
)
&
mapped_caret
,
2
,
get_thread_dpi
()
);
}
/* If the caret is not in the src/dest rects, all is fine done. */
if
(
!
intersect_rect
(
&
rect
,
scroll_rect
,
&
mapped_caret
))
{
rect
=
*
scroll_rect
;
OffsetRect
(
&
rect
,
dx
,
dy
);
if
(
!
intersect_rect
(
&
rect
,
&
rect
,
&
mapped_caret
))
return
0
;
}
/* Indicate that the caret needs to be updated during the scrolling. */
return
info
.
hwndCaret
;
}
/*************************************************************************
* NtUserScrollWindowEx (win32u.@)
*
* Note: contrary to what the doc says, pixels that are scrolled from the
* outside of clipRect to the inside are NOT painted.
*/
INT
WINAPI
NtUserScrollWindowEx
(
HWND
hwnd
,
INT
dx
,
INT
dy
,
const
RECT
*
rect
,
const
RECT
*
clip_rect
,
HRGN
update_rgn
,
RECT
*
update_rect
,
UINT
flags
)
{
BOOL
update
=
update_rect
||
update_rgn
||
flags
&
(
SW_INVALIDATE
|
SW_ERASE
);
BOOL
own_rgn
=
TRUE
,
move_caret
=
FALSE
;
HRGN
temp_rgn
,
winupd_rgn
=
0
;
INT
retval
=
NULLREGION
;
HWND
caret_hwnd
=
NULL
;
POINT
new_caret_pos
;
RECT
rc
,
cliprc
;
int
rdw_flags
;
HDC
hdc
;
TRACE
(
"%p, %d,%d update_rgn=%p update_rect = %p %s %04x
\n
"
,
hwnd
,
dx
,
dy
,
update_rgn
,
update_rect
,
wine_dbgstr_rect
(
rect
),
flags
);
TRACE
(
"clip_rect = %s
\n
"
,
wine_dbgstr_rect
(
clip_rect
)
);
if
(
flags
&
~
(
SW_SCROLLCHILDREN
|
SW_INVALIDATE
|
SW_ERASE
))
FIXME
(
"some flags (%04x) are unhandled
\n
"
,
flags
);
rdw_flags
=
(
flags
&
SW_ERASE
)
&&
(
flags
&
SW_INVALIDATE
)
?
RDW_INVALIDATE
|
RDW_ERASE
:
RDW_INVALIDATE
;
if
(
!
is_window_drawable
(
hwnd
,
TRUE
))
return
ERROR
;
hwnd
=
get_full_window_handle
(
hwnd
);
get_client_rect
(
hwnd
,
&
rc
);
if
(
clip_rect
)
intersect_rect
(
&
cliprc
,
&
rc
,
clip_rect
);
else
cliprc
=
rc
;
if
(
rect
)
intersect_rect
(
&
rc
,
&
rc
,
rect
);
if
(
update_rgn
)
own_rgn
=
FALSE
;
else
if
(
update
)
update_rgn
=
NtGdiCreateRectRgn
(
0
,
0
,
0
,
0
);
new_caret_pos
.
x
=
new_caret_pos
.
y
=
0
;
if
(
!
IsRectEmpty
(
&
cliprc
)
&&
(
dx
||
dy
))
{
DWORD
style
=
get_window_long
(
hwnd
,
GWL_STYLE
);
DWORD
dcxflags
=
0
;
caret_hwnd
=
fix_caret
(
hwnd
,
&
rc
,
dx
,
dy
,
flags
,
&
move_caret
,
&
new_caret_pos
);
if
(
caret_hwnd
)
NtUserHideCaret
(
caret_hwnd
);
if
(
!
(
flags
&
SW_NODCCACHE
))
dcxflags
|=
DCX_CACHE
;
if
(
style
&
WS_CLIPSIBLINGS
)
dcxflags
|=
DCX_CLIPSIBLINGS
;
if
(
get_class_long
(
hwnd
,
GCL_STYLE
,
FALSE
)
&
CS_PARENTDC
)
dcxflags
|=
DCX_PARENTCLIP
;
if
(
!
(
flags
&
SW_SCROLLCHILDREN
)
&&
(
style
&
WS_CLIPCHILDREN
))
dcxflags
|=
DCX_CLIPCHILDREN
;
hdc
=
NtUserGetDCEx
(
hwnd
,
0
,
dcxflags
);
if
(
hdc
)
{
NtUserScrollDC
(
hdc
,
dx
,
dy
,
&
rc
,
&
cliprc
,
update_rgn
,
update_rect
);
NtUserReleaseDC
(
hwnd
,
hdc
);
if
(
!
update
)
NtUserRedrawWindow
(
hwnd
,
NULL
,
update_rgn
,
rdw_flags
);
}
/* If the windows has an update region, this must be scrolled as well.
* Keep a copy in winupd_rgn to be added to hrngUpdate at the end. */
temp_rgn
=
NtGdiCreateRectRgn
(
0
,
0
,
0
,
0
);
retval
=
NtUserGetUpdateRgn
(
hwnd
,
temp_rgn
,
FALSE
);
if
(
retval
!=
NULLREGION
)
{
HRGN
clip_rgn
=
NtGdiCreateRectRgn
(
cliprc
.
left
,
cliprc
.
top
,
cliprc
.
right
,
cliprc
.
bottom
);
if
(
!
own_rgn
)
{
winupd_rgn
=
NtGdiCreateRectRgn
(
0
,
0
,
0
,
0
);
NtGdiCombineRgn
(
winupd_rgn
,
temp_rgn
,
0
,
RGN_COPY
);
}
NtGdiOffsetRgn
(
temp_rgn
,
dx
,
dy
);
NtGdiCombineRgn
(
temp_rgn
,
temp_rgn
,
clip_rgn
,
RGN_AND
);
if
(
!
own_rgn
)
NtGdiCombineRgn
(
winupd_rgn
,
winupd_rgn
,
temp_rgn
,
RGN_OR
);
NtUserRedrawWindow
(
hwnd
,
NULL
,
temp_rgn
,
rdw_flags
);
/*
* Catch the case where the scrolling amount exceeds the size of the
* original window. This generated a second update area that is the
* location where the original scrolled content would end up.
* This second region is not returned by the ScrollDC and sets
* ScrollWindowEx apart from just a ScrollDC.
*
* This has been verified with testing on windows.
*/
if
(
abs
(
dx
)
>
abs
(
rc
.
right
-
rc
.
left
)
||
abs
(
dy
)
>
abs
(
rc
.
bottom
-
rc
.
top
))
{
NtGdiSetRectRgn
(
temp_rgn
,
rc
.
left
+
dx
,
rc
.
top
+
dy
,
rc
.
right
+
dx
,
rc
.
bottom
+
dy
);
NtGdiCombineRgn
(
temp_rgn
,
temp_rgn
,
clip_rgn
,
RGN_AND
);
NtGdiCombineRgn
(
update_rgn
,
update_rgn
,
temp_rgn
,
RGN_OR
);
if
(
update_rect
)
{
RECT
temp_rect
;
NtGdiGetRgnBox
(
temp_rgn
,
&
temp_rect
);
union_rect
(
update_rect
,
update_rect
,
&
temp_rect
);
}
if
(
!
own_rgn
)
NtGdiCombineRgn
(
winupd_rgn
,
winupd_rgn
,
temp_rgn
,
RGN_OR
);
}
NtGdiDeleteObjectApp
(
clip_rgn
);
}
NtGdiDeleteObjectApp
(
temp_rgn
);
}
else
{
/* nothing was scrolled */
if
(
!
own_rgn
)
NtGdiSetRectRgn
(
update_rgn
,
0
,
0
,
0
,
0
);
SetRectEmpty
(
update_rect
);
}
if
(
flags
&
SW_SCROLLCHILDREN
)
{
HWND
*
list
=
list_window_children
(
0
,
hwnd
,
NULL
,
0
);
if
(
list
)
{
RECT
r
,
dummy
;
int
i
;
for
(
i
=
0
;
list
[
i
];
i
++
)
{
get_window_rects
(
list
[
i
],
COORDS_PARENT
,
&
r
,
NULL
,
get_thread_dpi
()
);
if
(
!
rect
||
intersect_rect
(
&
dummy
,
&
r
,
rect
))
NtUserSetWindowPos
(
list
[
i
],
0
,
r
.
left
+
dx
,
r
.
top
+
dy
,
0
,
0
,
SWP_NOZORDER
|
SWP_NOSIZE
|
SWP_NOACTIVATE
|
SWP_NOREDRAW
|
SWP_DEFERERASE
);
}
free
(
list
);
}
}
if
(
flags
&
(
SW_INVALIDATE
|
SW_ERASE
))
NtUserRedrawWindow
(
hwnd
,
NULL
,
update_rgn
,
rdw_flags
|
((
flags
&
SW_SCROLLCHILDREN
)
?
RDW_ALLCHILDREN
:
0
)
);
if
(
winupd_rgn
)
{
NtGdiCombineRgn
(
update_rgn
,
update_rgn
,
winupd_rgn
,
RGN_OR
);
NtGdiDeleteObjectApp
(
winupd_rgn
);
}
if
(
move_caret
)
set_caret_pos
(
new_caret_pos
.
x
,
new_caret_pos
.
y
);
if
(
caret_hwnd
)
NtUserShowCaret
(
caret_hwnd
);
if
(
own_rgn
&&
update_rgn
)
NtGdiDeleteObjectApp
(
update_rgn
);
return
retval
;
}
dlls/win32u/gdiobj.c
View file @
b2db69ef
...
...
@@ -1200,6 +1200,7 @@ static struct unix_funcs unix_funcs =
NtUserRegisterHotKey
,
NtUserReleaseDC
,
NtUserScrollDC
,
NtUserScrollWindowEx
,
NtUserSelectPalette
,
NtUserSendInput
,
NtUserSetActiveWindow
,
...
...
dlls/win32u/win32u.spec
View file @
b2db69ef
...
...
@@ -1156,7 +1156,7 @@
@ stub NtUserRestoreWindowDpiChanges
@ stub NtUserSBGetParms
@ stdcall NtUserScrollDC(long long long ptr ptr long ptr)
@ st
ub NtUserScrollWindowEx
@ st
dcall NtUserScrollWindowEx(long long long ptr ptr long ptr long)
@ stdcall NtUserSelectPalette(long long long)
@ stub NtUserSendEventMessage
@ stdcall NtUserSendInput(long ptr long)
...
...
dlls/win32u/win32u_private.h
View file @
b2db69ef
...
...
@@ -268,6 +268,9 @@ struct unix_funcs
INT
(
WINAPI
*
pNtUserReleaseDC
)(
HWND
hwnd
,
HDC
hdc
);
BOOL
(
WINAPI
*
pNtUserScrollDC
)(
HDC
hdc
,
INT
dx
,
INT
dy
,
const
RECT
*
scroll
,
const
RECT
*
clip
,
HRGN
ret_update_rgn
,
RECT
*
update_rect
);
INT
(
WINAPI
*
pNtUserScrollWindowEx
)(
HWND
hwnd
,
INT
dx
,
INT
dy
,
const
RECT
*
rect
,
const
RECT
*
clip_rect
,
HRGN
update_rgn
,
RECT
*
update_rect
,
UINT
flags
);
HPALETTE
(
WINAPI
*
pNtUserSelectPalette
)(
HDC
hdc
,
HPALETTE
hpal
,
WORD
bkg
);
UINT
(
WINAPI
*
pNtUserSendInput
)(
UINT
count
,
INPUT
*
inputs
,
int
size
);
HWND
(
WINAPI
*
pNtUserSetActiveWindow
)(
HWND
hwnd
);
...
...
@@ -449,6 +452,7 @@ extern HWND is_current_process_window( HWND hwnd ) DECLSPEC_HIDDEN;
extern
HWND
is_current_thread_window
(
HWND
hwnd
)
DECLSPEC_HIDDEN
;
extern
BOOL
is_desktop_window
(
HWND
hwnd
)
DECLSPEC_HIDDEN
;
extern
BOOL
is_iconic
(
HWND
hwnd
)
DECLSPEC_HIDDEN
;
extern
BOOL
is_window_drawable
(
HWND
hwnd
,
BOOL
icon
)
DECLSPEC_HIDDEN
;
extern
BOOL
is_window_enabled
(
HWND
hwnd
)
DECLSPEC_HIDDEN
;
extern
BOOL
is_window_unicode
(
HWND
hwnd
)
DECLSPEC_HIDDEN
;
extern
DWORD
get_window_long
(
HWND
hwnd
,
INT
offset
)
DECLSPEC_HIDDEN
;
...
...
dlls/win32u/window.c
View file @
b2db69ef
...
...
@@ -762,7 +762,7 @@ static BOOL is_window_visible( HWND hwnd )
* minimized, and it is itself not minimized unless we are
* trying to draw its default class icon.
*/
static
BOOL
is_window_drawable
(
HWND
hwnd
,
BOOL
icon
)
BOOL
is_window_drawable
(
HWND
hwnd
,
BOOL
icon
)
{
HWND
*
list
;
BOOL
retval
=
TRUE
;
...
...
dlls/win32u/wrappers.c
View file @
b2db69ef
...
...
@@ -1112,6 +1112,15 @@ BOOL WINAPI NtUserScrollDC( HDC hdc, INT dx, INT dy, const RECT *scroll, const R
return
unix_funcs
->
pNtUserScrollDC
(
hdc
,
dx
,
dy
,
scroll
,
clip
,
ret_update_rgn
,
update_rect
);
}
INT
WINAPI
NtUserScrollWindowEx
(
HWND
hwnd
,
INT
dx
,
INT
dy
,
const
RECT
*
rect
,
const
RECT
*
clip_rect
,
HRGN
update_rgn
,
RECT
*
update_rect
,
UINT
flags
)
{
if
(
!
unix_funcs
)
return
0
;
return
unix_funcs
->
pNtUserScrollWindowEx
(
hwnd
,
dx
,
dy
,
rect
,
clip_rect
,
update_rgn
,
update_rect
,
flags
);
}
HPALETTE
WINAPI
NtUserSelectPalette
(
HDC
hdc
,
HPALETTE
hpal
,
WORD
bkg
)
{
if
(
!
unix_funcs
)
return
0
;
...
...
include/ntuser.h
View file @
b2db69ef
...
...
@@ -227,6 +227,9 @@ struct send_message_callback_params
#define NTUSER_OBJ_ACCEL 0x08
#define NTUSER_OBJ_HOOK 0x0f
/* NtUserScrollWindowEx flag */
#define SW_NODCCACHE 0x8000
/* NtUserInitializeClientPfnArrays parameter, not compatible with Windows */
struct
user_client_procs
{
...
...
@@ -615,6 +618,9 @@ BOOL WINAPI NtUserRemoveMenu( HMENU menu, UINT id, UINT flags );
HANDLE
WINAPI
NtUserRemoveProp
(
HWND
hwnd
,
const
WCHAR
*
str
);
BOOL
WINAPI
NtUserScrollDC
(
HDC
hdc
,
INT
dx
,
INT
dy
,
const
RECT
*
scroll
,
const
RECT
*
clip
,
HRGN
ret_update_rgn
,
RECT
*
update_rect
);
INT
WINAPI
NtUserScrollWindowEx
(
HWND
hwnd
,
INT
dx
,
INT
dy
,
const
RECT
*
rect
,
const
RECT
*
clip_rect
,
HRGN
update_rgn
,
RECT
*
update_rect
,
UINT
flags
)
DECLSPEC_HIDDEN
;
HPALETTE
WINAPI
NtUserSelectPalette
(
HDC
hdc
,
HPALETTE
palette
,
WORD
force_background
);
UINT
WINAPI
NtUserSendInput
(
UINT
count
,
INPUT
*
inputs
,
int
size
);
HWND
WINAPI
NtUserSetActiveWindow
(
HWND
hwnd
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment