source: trunk/src/user32/wintrack.cpp@ 6941

Last change on this file since 6941 was 6941, checked in by sandervl, 24 years ago

window tracking rewrite + getdcex change (clipping)

File size: 16.2 KB
Line 
1/*
2 * Window position related functions.
3 *
4 * Copyright 1993, 1994, 1995, 2001 Alexandre Julliard
5 * Copyright 1995, 1996, 1999 Alex Korobka
6 *
7 * TODO: too much flickering when drawing sizing border.
8 * should be rewritten to only draw changed borders
9 *
10 */
11#include <os2win.h>
12#include <string.h>
13
14#include "win32wbase.h"
15#include "hook.h"
16
17#define ON_LEFT_BORDER(hit) \
18 (((hit) == HTLEFT) || ((hit) == HTTOPLEFT) || ((hit) == HTBOTTOMLEFT))
19#define ON_RIGHT_BORDER(hit) \
20 (((hit) == HTRIGHT) || ((hit) == HTTOPRIGHT) || ((hit) == HTBOTTOMRIGHT))
21#define ON_TOP_BORDER(hit) \
22 (((hit) == HTTOP) || ((hit) == HTTOPLEFT) || ((hit) == HTTOPRIGHT))
23#define ON_BOTTOM_BORDER(hit) \
24 (((hit) == HTBOTTOM) || ((hit) == HTBOTTOMLEFT) || ((hit) == HTBOTTOMRIGHT))
25
26#define RECT_WIDTH(a) ((a)->right - (a)->left)
27#define RECT_HEIGHT(a) ((a)->bottom - (a)->top)
28#define RECT_EQUAL(a,b) (memcmp(a, b, sizeof(RECT)) == 0)
29
30#ifdef CUSTOM_TRACKFRAME
31
32/***********************************************************************
33 * draw_moving_frame
34 *
35 * Draw the frame used when moving or resizing window.
36 *
37 * FIXME: This causes problems in Win95 mode. (why?)
38 */
39static void draw_moving_frame( HDC hdc, RECT *rect, BOOL thickframe )
40{
41 if (thickframe)
42 {
43 const int width = GetSystemMetrics(SM_CXFRAME);
44 const int height = GetSystemMetrics(SM_CYFRAME);
45
46 HBRUSH hbrush = SelectObject( hdc, GetStockObject( GRAY_BRUSH ) );
47 PatBlt( hdc, rect->left, rect->top,
48 rect->right - rect->left - width, height, PATINVERT );
49 PatBlt( hdc, rect->left, rect->top + height, width,
50 rect->bottom - rect->top - height, PATINVERT );
51 PatBlt( hdc, rect->left + width, rect->bottom - 1,
52 rect->right - rect->left - width, -height, PATINVERT );
53 PatBlt( hdc, rect->right - 1, rect->top, -width,
54 rect->bottom - rect->top - height, PATINVERT );
55 SelectObject( hdc, hbrush );
56 }
57 else DrawFocusRect( hdc, rect );
58}
59
60
61/***********************************************************************
62 * start_size_move
63 *
64 * Initialisation of a move or resize, when initiatied from a menu choice.
65 * Return hit test code for caption or sizing border.
66 */
67static LONG start_size_move( Win32BaseWindow *win32wnd, WPARAM wParam, POINT *capturePoint, LONG style )
68{
69 HWND hwnd = win32wnd->getWindowHandle();
70 LONG hittest = 0;
71 POINT pt;
72 MSG msg;
73 RECT rectWindow;
74
75 GetWindowRect( hwnd, &rectWindow );
76
77 if ((wParam & 0xfff0) == SC_MOVE)
78 {
79 /* Move pointer at the center of the caption */
80 RECT rect;
81 win32wnd->GetInsideRect( &rect );
82 if (style & WS_SYSMENU)
83 rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
84 if (style & WS_MINIMIZEBOX)
85 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
86 if (style & WS_MAXIMIZEBOX)
87 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
88 pt.x = rectWindow.left + (rect.right - rect.left) / 2;
89 pt.y = rectWindow.top + rect.top + GetSystemMetrics(SM_CYSIZE)/2;
90 hittest = HTCAPTION;
91 *capturePoint = pt;
92 }
93 else /* SC_SIZE */
94 {
95 while(!hittest)
96 {
97// GetMessageW( &msg, 0, WM_KEYFIRST, WM_MOUSELAST );
98 GetMessageW( &msg, 0, 0, 0 );
99 if (CallMsgFilterW( &msg, MSGF_SIZE )) continue;
100
101 switch(msg.message)
102 {
103 case WM_MOUSEMOVE:
104 hittest = win32wnd->HandleNCHitTest( msg.pt );
105// hittest = NC_HandleNCHitTest( hwnd, msg.pt );
106 if ((hittest < HTLEFT) || (hittest > HTBOTTOMRIGHT))
107 hittest = 0;
108 break;
109
110 case WM_LBUTTONUP:
111 return 0;
112
113 case WM_KEYDOWN:
114 switch(msg.wParam)
115 {
116 case VK_UP:
117 hittest = HTTOP;
118 pt.x =(rectWindow.left+rectWindow.right)/2;
119 pt.y = rectWindow.top + GetSystemMetrics(SM_CYFRAME) / 2;
120 break;
121 case VK_DOWN:
122 hittest = HTBOTTOM;
123 pt.x =(rectWindow.left+rectWindow.right)/2;
124 pt.y = rectWindow.bottom - GetSystemMetrics(SM_CYFRAME) / 2;
125 break;
126 case VK_LEFT:
127 hittest = HTLEFT;
128 pt.x = rectWindow.left + GetSystemMetrics(SM_CXFRAME) / 2;
129 pt.y =(rectWindow.top+rectWindow.bottom)/2;
130 break;
131 case VK_RIGHT:
132 hittest = HTRIGHT;
133 pt.x = rectWindow.right - GetSystemMetrics(SM_CXFRAME) / 2;
134 pt.y =(rectWindow.top+rectWindow.bottom)/2;
135 break;
136 case VK_RETURN:
137 case VK_ESCAPE: return 0;
138 }
139 }
140 }
141 *capturePoint = pt;
142 }
143 SetCursorPos( pt.x, pt.y );
144 win32wnd->DefWindowProcA(WM_SETCURSOR, (WPARAM)hwnd, MAKELONG( hittest, WM_MOUSEMOVE ));
145// NC_HandleSetCursor( hwnd, (WPARAM)hwnd, MAKELONG( hittest, WM_MOUSEMOVE ));
146 dprintf(("start_size_move: hittest %d", hittest));
147 return hittest;
148}
149
150
151/***********************************************************************
152 * SysCommandSizeMove (X11DRV.@)
153 *
154 * Perform SC_MOVE and SC_SIZE commands.
155 */
156void Frame_SysCommandSizeMove(Win32BaseWindow *win32wnd, WPARAM wParam )
157{
158 HWND hwnd = win32wnd->getWindowHandle();
159 MSG msg;
160 RECT sizingRect, mouseRect, origRect;
161 HDC hdc;
162 HWND parent;
163 LONG hittest = (LONG)(wParam & 0x0f);
164 HCURSOR16 hDragCursor = 0, hOldCursor = 0;
165 POINT minTrack, maxTrack;
166 POINT capturePoint, pt;
167 LONG style = GetWindowLongA( hwnd, GWL_STYLE );
168 LONG exstyle = GetWindowLongA( hwnd, GWL_EXSTYLE );
169 BOOL thickframe = HAS_THICKFRAME( style, exstyle );
170 BOOL iconic = style & WS_MINIMIZE;
171 BOOL moved = FALSE;
172 DWORD dwPoint = GetMessagePos ();
173 BOOL DragFullWindows = FALSE;
174 BOOL grab;
175 int iWndsLocks;
176
177 dprintf(("FrameTrackFrame %x", wParam));
178
179 SystemParametersInfoA(SPI_GETDRAGFULLWINDOWS, 0, &DragFullWindows, 0);
180
181 pt.x = SLOWORD(dwPoint);
182 pt.y = SHIWORD(dwPoint);
183 capturePoint = pt;
184
185// if (IsZoomed(hwnd) || !IsWindowVisible(hwnd) || (exstyle & WS_EX_MANAGED)) return;
186 if (IsZoomed(hwnd) || !IsWindowVisible(hwnd)) return;
187
188 if ((wParam & 0xfff0) == SC_MOVE)
189 {
190 if (!hittest) hittest = start_size_move( win32wnd, wParam, &capturePoint, style );
191 if (!hittest) return;
192 }
193 else /* SC_SIZE */
194 {
195 if (!thickframe) return;
196 if ( hittest && hittest != HTSYSMENU ) hittest += 2;
197 else
198 {
199 SetCapture(hwnd);
200 hittest = start_size_move( win32wnd, wParam, &capturePoint, style );
201 if (!hittest)
202 {
203 ReleaseCapture();
204 return;
205 }
206 }
207 }
208
209 /* Get min/max info */
210
211// WINPOS_GetMinMaxInfo( hwnd, NULL, NULL, &minTrack, &maxTrack );
212 win32wnd->AdjustTrackInfo(&minTrack, &maxTrack);
213 GetWindowRect( hwnd, &sizingRect );
214 if (style & WS_CHILD)
215 {
216 parent = GetParent(hwnd);
217 /* make sizing rect relative to parent */
218 MapWindowPoints( 0, parent, (POINT*)&sizingRect, 2 );
219 GetClientRect( parent, &mouseRect );
220 }
221 else
222 {
223 parent = GetDesktopWindow();
224 SetRect(&mouseRect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
225 }
226 origRect = sizingRect;
227
228 if (ON_LEFT_BORDER(hittest))
229 {
230 mouseRect.left = max( mouseRect.left, sizingRect.right-maxTrack.x );
231 mouseRect.right = min( mouseRect.right, sizingRect.right-minTrack.x );
232 }
233 else if (ON_RIGHT_BORDER(hittest))
234 {
235 mouseRect.left = max( mouseRect.left, sizingRect.left+minTrack.x );
236 mouseRect.right = min( mouseRect.right, sizingRect.left+maxTrack.x );
237 }
238 if (ON_TOP_BORDER(hittest))
239 {
240 mouseRect.top = max( mouseRect.top, sizingRect.bottom-maxTrack.y );
241 mouseRect.bottom = min( mouseRect.bottom,sizingRect.bottom-minTrack.y);
242 }
243 else if (ON_BOTTOM_BORDER(hittest))
244 {
245 mouseRect.top = max( mouseRect.top, sizingRect.top+minTrack.y );
246 mouseRect.bottom = min( mouseRect.bottom, sizingRect.top+maxTrack.y );
247 }
248 if (parent) MapWindowPoints( parent, 0, (LPPOINT)&mouseRect, 2 );
249
250 /* Retrieve a default cache DC (without using the window style) */
251 hdc = GetDCEx( parent, 0, DCX_CACHE);
252
253 if( iconic ) /* create a cursor for dragging */
254 {
255 HICON hIcon = GetClassLongA( hwnd, GCL_HICON);
256 if(!hIcon) hIcon = (HICON)SendMessageA( hwnd, WM_QUERYDRAGICON, 0, 0L);
257 if( hIcon ) hDragCursor = hIcon;
258// CURSORICON_IconToCursor( hIcon, TRUE );
259 if( !hDragCursor ) iconic = FALSE;
260 }
261
262 /* repaint the window before moving it around */
263 RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN );
264
265 SendMessageA( hwnd, WM_ENTERSIZEMOVE, 0, 0 );
266 SetCapture( hwnd );
267
268 //prevent the app from drawing to this window (or its children)
269 if(!DragFullWindows)
270 LockWindowUpdate(hwnd);
271
272 while(1)
273 {
274 int dx = 0, dy = 0;
275
276// if (!GetMessageW( &msg, 0, WM_KEYFIRST, WM_MOUSELAST )) break;
277 if (!GetMessageW( &msg, 0, 0, 0 )) break;
278 if (CallMsgFilterW( &msg, MSGF_SIZE )) continue;
279
280 /* Exit on button-up, Return, or Esc */
281 if ((msg.message == WM_LBUTTONUP) ||
282 ((msg.message == WM_KEYDOWN) &&
283 ((msg.wParam == VK_RETURN) || (msg.wParam == VK_ESCAPE)))) break;
284
285 if ((msg.message != WM_KEYDOWN) && (msg.message != WM_MOUSEMOVE)) {
286 DispatchMessageA(&msg);
287 continue; /* We are not interested in other messages */
288 }
289
290 pt = msg.pt;
291
292 if (msg.message == WM_KEYDOWN) switch(msg.wParam)
293 {
294 case VK_UP: pt.y -= 8; break;
295 case VK_DOWN: pt.y += 8; break;
296 case VK_LEFT: pt.x -= 8; break;
297 case VK_RIGHT: pt.x += 8; break;
298 }
299
300 pt.x = max( pt.x, mouseRect.left );
301 pt.x = min( pt.x, mouseRect.right );
302 pt.y = max( pt.y, mouseRect.top );
303 pt.y = min( pt.y, mouseRect.bottom );
304
305 dprintf(("mouseRect (%d,%d)(%d,%d)", mouseRect.left, mouseRect.top, mouseRect.right, mouseRect.bottom));
306 dprintf(("capturePoint (%d,%d)", capturePoint.x, capturePoint.y));
307 dx = pt.x - capturePoint.x;
308 dy = pt.y - capturePoint.y;
309
310 if (dx || dy)
311 {
312 if( !moved )
313 {
314 moved = TRUE;
315
316 if( iconic ) /* ok, no system popup tracking */
317 {
318 hOldCursor = SetCursor(hDragCursor);
319 ShowCursor( TRUE );
320// WINPOS_ShowIconTitle( hwnd, FALSE );
321 }
322 else if(!DragFullWindows)
323 draw_moving_frame( hdc, &sizingRect, thickframe );
324 }
325
326 if (msg.message == WM_KEYDOWN) SetCursorPos( pt.x, pt.y );
327 else
328 {
329 RECT newRect = sizingRect, tempRect;
330 WPARAM wpSizingHit = 0;
331
332 if (hittest == HTCAPTION) OffsetRect( &newRect, dx, dy );
333
334 if (ON_LEFT_BORDER(hittest)) newRect.left += dx;
335 else
336 if (ON_RIGHT_BORDER(hittest)) newRect.right += dx;
337
338 if (ON_TOP_BORDER(hittest)) newRect.top += dy;
339 else
340 if (ON_BOTTOM_BORDER(hittest)) newRect.bottom += dy;
341
342 if(!iconic && !DragFullWindows) draw_moving_frame( hdc, &sizingRect, thickframe );
343
344 /* determine the hit location */
345 if (hittest >= HTLEFT && hittest <= HTBOTTOMRIGHT)
346 wpSizingHit = WMSZ_LEFT + (hittest - HTLEFT);
347
348 tempRect = newRect;
349
350 dprintf(("WM_SIZING rect (%d,%d)(%d,%d)", newRect.left, newRect.top, newRect.right, newRect.bottom));
351
352 //Although the docs say the app should return TRUE when processing
353 //this message, experiments show that NT checks the rectangle
354 //regardless of the return value
355 if ((wParam & 0xfff0) == SC_MOVE) {
356 SendMessageA( hwnd, WM_MOVING, wpSizingHit, (LPARAM)&newRect );
357 }
358 else SendMessageA( hwnd, WM_SIZING, wpSizingHit, (LPARAM)&newRect );
359
360 dprintf(("WM_SIZING rect (%d,%d)(%d,%d)", newRect.left, newRect.top, newRect.right, newRect.bottom));
361
362#ifdef __WIN32OS2__
363 if(RECT_EQUAL(&newRect, &tempRect) ||
364 (dy > 0 && RECT_HEIGHT(&newRect) > RECT_HEIGHT(&tempRect)) ||
365 (dx > 0 && RECT_WIDTH(&newRect) > RECT_WIDTH(&tempRect)) )
366 {
367 dprintf(("update capture point dx %d dy %d", dx, dy));
368 capturePoint = pt;
369 sizingRect = newRect;
370 }
371#endif
372 if (!iconic)
373 {
374 if(!DragFullWindows)
375 draw_moving_frame( hdc, &newRect, thickframe );
376 else {
377 /* To avoid any deadlocks, all the locks on the windows
378 structures must be suspended before the SetWindowPos */
379// iWndsLocks = WIN_SuspendWndsLock();
380 SetWindowPos( hwnd, 0, newRect.left, newRect.top,
381 newRect.right - newRect.left,
382 newRect.bottom - newRect.top,
383 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
384// WIN_RestoreWndsLock(iWndsLocks);
385 }
386 }
387 }
388 }
389 }
390
391 //Enable window update
392 if(!DragFullWindows)
393 LockWindowUpdate(NULL);
394
395 ReleaseCapture();
396 if( iconic )
397 {
398 if( moved ) /* restore cursors, show icon title later on */
399 {
400 ShowCursor( FALSE );
401 SetCursor( hOldCursor );
402 }
403 DestroyCursor( hDragCursor );
404 }
405 else if (moved && !DragFullWindows)
406 draw_moving_frame( hdc, &sizingRect, thickframe );
407
408 ReleaseDC( parent, hdc );
409
410// wine_tsx11_lock();
411// XUngrabPointer( display, CurrentTime );
412// if (grab)
413// {
414// XSync( display, False );
415// XUngrabServer( display );
416// XSync( display, False );
417// gdi_display = old_gdi_display;
418// }
419// wine_tsx11_unlock();
420
421 if (HOOK_CallHooksA( WH_CBT, HCBT_MOVESIZE, (WPARAM)hwnd, (LPARAM)&sizingRect )) moved = FALSE;
422
423 SendMessageA( hwnd, WM_EXITSIZEMOVE, 0, 0 );
424 SendMessageA( hwnd, WM_SETVISIBLE, !IsIconic(hwnd), 0L);
425
426 /* window moved or resized */
427 if (moved)
428 {
429 /* To avoid any deadlocks, all the locks on the windows
430 structures must be suspended before the SetWindowPos */
431// iWndsLocks = WIN_SuspendWndsLock();
432
433 /* if the moving/resizing isn't canceled call SetWindowPos
434 * with the new position or the new size of the window
435 */
436 if (!((msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE)) )
437 {
438 /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */
439 if(!DragFullWindows)
440 SetWindowPos( hwnd, 0, sizingRect.left, sizingRect.top,
441 sizingRect.right - sizingRect.left,
442 sizingRect.bottom - sizingRect.top,
443 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
444 }
445 else
446 { /* restore previous size/position */
447 if(DragFullWindows)
448 SetWindowPos( hwnd, 0, origRect.left, origRect.top,
449 origRect.right - origRect.left,
450 origRect.bottom - origRect.top,
451 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
452 }
453
454// WIN_RestoreWndsLock(iWndsLocks);
455 }
456
457 if (IsIconic(hwnd))
458 {
459 /* Single click brings up the system menu when iconized */
460
461 if( !moved )
462 {
463 if(style & WS_SYSMENU )
464 SendMessageA( hwnd, WM_SYSCOMMAND,
465 SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x,pt.y));
466 }
467// else WINPOS_ShowIconTitle( hwnd, TRUE );
468 }
469}
470
471#endif //#ifdef CUSTOM_TRACKFRAME
Note: See TracBrowser for help on using the repository browser.