Made access to the wnd struct thread-safe.
[wine] / windows / defwnd.c
1 /*
2  * Default window procedure
3  *
4  * Copyright 1993, 1996 Alexandre Julliard
5  *           1995 Alex Korobka
6  */
7
8 #include <string.h>
9 #include "win.h"
10 #include "user.h"
11 #include "heap.h"
12 #include "nonclient.h"
13 #include "winpos.h"
14 #include "dce.h"
15 #include "sysmetrics.h"
16 #include "debug.h"
17 #include "spy.h"
18 #include "tweak.h"
19 #include "wine/winuser16.h"
20
21   /* Last COLOR id */
22 #define COLOR_MAX   COLOR_BTNHIGHLIGHT
23
24   /* bits in the dwKeyData */
25 #define KEYDATA_ALT             0x2000
26 #define KEYDATA_PREVSTATE       0x4000
27
28 static short iF10Key = 0;
29 static short iMenuSysKey = 0;
30
31 /***********************************************************************
32  *           DEFWND_HandleWindowPosChanged
33  *
34  * Handle the WM_WINDOWPOSCHANGED message.
35  */
36 static void DEFWND_HandleWindowPosChanged( WND *wndPtr, UINT flags )
37 {
38     WPARAM16 wp = SIZE_RESTORED;
39
40     if (!(flags & SWP_NOCLIENTMOVE))
41         SendMessage16( wndPtr->hwndSelf, WM_MOVE, 0,
42                     MAKELONG(wndPtr->rectClient.left, wndPtr->rectClient.top));
43     if (!(flags & SWP_NOCLIENTSIZE))
44     {
45         if (wndPtr->dwStyle & WS_MAXIMIZE) wp = SIZE_MAXIMIZED;
46         else if (wndPtr->dwStyle & WS_MINIMIZE) wp = SIZE_MINIMIZED;
47
48         SendMessage16( wndPtr->hwndSelf, WM_SIZE, wp, 
49                      MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
50                             wndPtr->rectClient.bottom-wndPtr->rectClient.top));
51     }
52 }
53
54
55 /***********************************************************************
56  *           DEFWND_SetText
57  *
58  * Set the window text.
59  */
60 void DEFWND_SetText( WND *wndPtr, LPCSTR text )
61 {
62     if (!text) text = "";
63     if (wndPtr->text) HeapFree( SystemHeap, 0, wndPtr->text );
64     wndPtr->text = HEAP_strdupA( SystemHeap, 0, text );    
65     wndPtr->pDriver->pSetText(wndPtr, wndPtr->text);
66 }
67
68 /***********************************************************************
69  *           DEFWND_ControlColor
70  *
71  * Default colors for control painting.
72  */
73 HBRUSH DEFWND_ControlColor( HDC hDC, UINT16 ctlType )
74 {
75     if( ctlType == CTLCOLOR_SCROLLBAR)
76     {
77         HBRUSH hb = GetSysColorBrush(COLOR_SCROLLBAR);
78         SetBkColor( hDC, RGB(255, 255, 255) );
79         SetTextColor( hDC, RGB(0, 0, 0) );
80         UnrealizeObject( hb );
81         return hb;
82     }
83
84     SetTextColor( hDC, GetSysColor(COLOR_WINDOWTEXT));
85
86     if (TWEAK_WineLook > WIN31_LOOK) {
87         if ((ctlType == CTLCOLOR_EDIT) || (ctlType == CTLCOLOR_LISTBOX))
88             SetBkColor( hDC, GetSysColor(COLOR_WINDOW) );
89         else {
90             SetBkColor( hDC, GetSysColor(COLOR_3DFACE) );
91             return GetSysColorBrush(COLOR_3DFACE);
92         }
93     }
94     else
95         SetBkColor( hDC, GetSysColor(COLOR_WINDOW) );
96     return GetSysColorBrush(COLOR_WINDOW);
97 }
98
99
100 /***********************************************************************
101  *           DEFWND_SetRedraw
102  */
103 static void DEFWND_SetRedraw( WND* wndPtr, WPARAM wParam )
104 {
105     BOOL bVisible = wndPtr->dwStyle & WS_VISIBLE;
106
107     TRACE(win,"%04x %i\n", wndPtr->hwndSelf, (wParam!=0) );
108
109     if( wParam )
110     {
111         if( !bVisible )
112         {
113             wndPtr->dwStyle |= WS_VISIBLE;
114             DCE_InvalidateDCE( wndPtr, &wndPtr->rectWindow );
115         }
116     }
117     else if( bVisible )
118     {
119         if( wndPtr->dwStyle & WS_MINIMIZE ) wParam = RDW_VALIDATE;
120         else wParam = RDW_ALLCHILDREN | RDW_VALIDATE;
121
122         PAINT_RedrawWindow( wndPtr->hwndSelf, NULL, 0, wParam, 0 );
123         DCE_InvalidateDCE( wndPtr, &wndPtr->rectWindow );
124         wndPtr->dwStyle &= ~WS_VISIBLE;
125     }
126 }
127
128 /***********************************************************************
129  *           DEFWND_DefWinProc
130  *
131  * Default window procedure for messages that are the same in Win16 and Win32.
132  */
133 static LRESULT DEFWND_DefWinProc( WND *wndPtr, UINT msg, WPARAM wParam,
134                                   LPARAM lParam )
135 {
136     switch(msg)
137     {
138     case WM_NCPAINT:
139         return NC_HandleNCPaint( wndPtr->hwndSelf, (HRGN)wParam );
140
141     case WM_NCHITTEST:
142         return NC_HandleNCHitTest( wndPtr->hwndSelf, MAKEPOINT16(lParam) );
143
144     case WM_NCLBUTTONDOWN:
145         return NC_HandleNCLButtonDown( wndPtr, wParam, lParam );
146
147     case WM_LBUTTONDBLCLK:
148     case WM_NCLBUTTONDBLCLK:
149         return NC_HandleNCLButtonDblClk( wndPtr, wParam, lParam );
150
151     case WM_RBUTTONDOWN:
152     case WM_NCRBUTTONDOWN:
153         if ((wndPtr->flags & WIN_ISWIN32) || (TWEAK_WineLook > WIN31_LOOK))
154         {
155             ClientToScreen16(wndPtr->hwndSelf, (LPPOINT16)&lParam);
156             SendMessageA( wndPtr->hwndSelf, WM_CONTEXTMENU,
157                             wndPtr->hwndSelf, lParam);
158         }
159         break;
160
161     case WM_CONTEXTMENU:
162         if( wndPtr->dwStyle & WS_CHILD )
163             SendMessageA( wndPtr->parent->hwndSelf, msg, wParam, lParam );
164         else
165           if (wndPtr->hSysMenu)
166           { /*
167             TrackPopupMenu32(wndPtr->hSysMenu,TPM_LEFTALIGN | TPM_RETURNCMD,LOWORD(lParam),HIWORD(lParam),0,wndPtr->hwndSelf,NULL);
168             DestroyMenu32(wndPtr->hSysMenu);
169             */
170             FIXME(win,"Display default popup menu\n");
171           /* Track system popup if click was in the caption area. */
172           }
173         break;
174
175     case WM_NCACTIVATE:
176         return NC_HandleNCActivate( wndPtr, wParam );
177
178     case WM_NCDESTROY:
179         if (wndPtr->text) HeapFree( SystemHeap, 0, wndPtr->text );
180         wndPtr->text = NULL;
181         if (wndPtr->pVScroll) HeapFree( SystemHeap, 0, wndPtr->pVScroll );
182         if (wndPtr->pHScroll) HeapFree( SystemHeap, 0, wndPtr->pHScroll );
183         wndPtr->pVScroll = wndPtr->pHScroll = NULL;
184         return 0;
185
186     case WM_PAINTICON:
187     case WM_PAINT:
188         {
189             PAINTSTRUCT16 ps;
190             HDC16 hdc = BeginPaint16( wndPtr->hwndSelf, &ps );
191             if( hdc ) 
192             {
193               if( (wndPtr->dwStyle & WS_MINIMIZE) && wndPtr->class->hIcon )
194               {
195                 int x = (wndPtr->rectWindow.right - wndPtr->rectWindow.left -
196                         SYSMETRICS_CXICON)/2;
197                 int y = (wndPtr->rectWindow.bottom - wndPtr->rectWindow.top -
198                         SYSMETRICS_CYICON)/2;
199                 TRACE(win,"Painting class icon: vis rect=(%i,%i - %i,%i)\n",
200                 ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom );
201                 DrawIcon( hdc, x, y, wndPtr->class->hIcon );
202               }
203               EndPaint16( wndPtr->hwndSelf, &ps );
204             }
205             return 0;
206         }
207
208     case WM_SETREDRAW:
209         DEFWND_SetRedraw( wndPtr, wParam );
210         return 0;
211
212     case WM_CLOSE:
213         DestroyWindow( wndPtr->hwndSelf );
214         return 0;
215
216     case WM_MOUSEACTIVATE:
217         if (wndPtr->dwStyle & WS_CHILD)
218         {
219             LONG ret = SendMessage16( wndPtr->parent->hwndSelf,
220                                       WM_MOUSEACTIVATE, wParam, lParam );
221             if (ret) return ret;
222         }
223
224         /* Caption clicks are handled by the NC_HandleNCLButtonDown() */ 
225         return (LOWORD(lParam) == HTCAPTION) ? MA_NOACTIVATE : MA_ACTIVATE;
226
227     case WM_ACTIVATE:
228         /* The default action in Windows is to set the keyboard focus to
229          * the window, if it's being activated and not minimized */
230         if (LOWORD(wParam) != WA_INACTIVE) {
231                 /* I don't know who put this SetWindowPos here, it does not
232                  * seem very logical to have it here... (FIXME?) */
233                 SetWindowPos(wndPtr->hwndSelf, HWND_TOP, 0, 0, 0, 0,
234                          SWP_NOMOVE | SWP_NOSIZE);
235                 if (!(wndPtr->dwStyle & WS_MINIMIZE))
236                         SetFocus(wndPtr->hwndSelf);
237         }
238         break;
239
240     case WM_ERASEBKGND:
241     case WM_ICONERASEBKGND:
242         {
243             if (!wndPtr->class->hbrBackground) return 0;
244
245             if (wndPtr->class->hbrBackground <= (HBRUSH16)(COLOR_MAX+1))
246             {
247                 HBRUSH hbrush = CreateSolidBrush( 
248                        GetSysColor(((DWORD)wndPtr->class->hbrBackground)-1));
249                  FillWindow16( GetParent16(wndPtr->hwndSelf), wndPtr->hwndSelf,
250                              (HDC16)wParam, hbrush);
251                  DeleteObject( hbrush );
252             }
253             else FillWindow16( GetParent16(wndPtr->hwndSelf), wndPtr->hwndSelf,
254                              (HDC16)wParam, wndPtr->class->hbrBackground );
255             return 1;
256         }
257
258     case WM_GETDLGCODE:
259         return 0;
260
261     case WM_CTLCOLORMSGBOX:
262     case WM_CTLCOLOREDIT:
263     case WM_CTLCOLORLISTBOX:
264     case WM_CTLCOLORBTN:
265     case WM_CTLCOLORDLG:
266     case WM_CTLCOLORSTATIC:
267     case WM_CTLCOLORSCROLLBAR:
268         return (LRESULT)DEFWND_ControlColor( (HDC)wParam, msg - WM_CTLCOLORMSGBOX );
269
270     case WM_CTLCOLOR:
271         return (LRESULT)DEFWND_ControlColor( (HDC)wParam, HIWORD(lParam) );
272         
273     case WM_GETTEXTLENGTH:
274         if (wndPtr->text) return (LRESULT)strlen(wndPtr->text);
275         return 0;
276
277     case WM_SETCURSOR:
278         if (wndPtr->dwStyle & WS_CHILD)
279             if (SendMessage16(wndPtr->parent->hwndSelf, WM_SETCURSOR,
280                             wParam, lParam))
281                 return TRUE;
282         return NC_HandleSetCursor( wndPtr->hwndSelf, wParam, lParam );
283
284     case WM_SYSCOMMAND:
285         return NC_HandleSysCommand( wndPtr->hwndSelf, wParam,
286                                     MAKEPOINT16(lParam) );
287
288     case WM_KEYDOWN:
289         if(wParam == VK_F10) iF10Key = VK_F10;
290         break;
291
292     case WM_SYSKEYDOWN:
293         if( HIWORD(lParam) & KEYDATA_ALT )
294         {
295             /* if( HIWORD(lParam) & ~KEYDATA_PREVSTATE ) */
296               if( wParam == VK_MENU && !iMenuSysKey )
297                 iMenuSysKey = 1;
298               else
299                 iMenuSysKey = 0;
300             
301             iF10Key = 0;
302
303             if( wParam == VK_F4 )       /* try to close the window */
304             {
305                 HWND hWnd = WIN_GetTopParent( wndPtr->hwndSelf );
306                 wndPtr = WIN_FindWndPtr( hWnd );
307                 if( wndPtr && !(wndPtr->class->style & CS_NOCLOSE) )
308                     PostMessage16( hWnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
309                 WIN_ReleaseWndPtr(wndPtr);
310             }
311         } 
312         else if( wParam == VK_F10 )
313                 iF10Key = 1;
314              else
315                 if( wParam == VK_ESCAPE && (GetKeyState(VK_SHIFT) & 0x8000))
316                     SendMessage16( wndPtr->hwndSelf, WM_SYSCOMMAND,
317                                   (WPARAM16)SC_KEYMENU, (LPARAM)VK_SPACE);
318         break;
319
320     case WM_KEYUP:
321     case WM_SYSKEYUP:
322         /* Press and release F10 or ALT */
323         if (((wParam == VK_MENU) && iMenuSysKey) ||
324             ((wParam == VK_F10) && iF10Key))
325               SendMessage16( WIN_GetTopParent(wndPtr->hwndSelf),
326                              WM_SYSCOMMAND, SC_KEYMENU, 0L );
327         iMenuSysKey = iF10Key = 0;
328         break;
329
330     case WM_SYSCHAR:
331         iMenuSysKey = 0;
332         if (wParam == VK_RETURN && (wndPtr->dwStyle & WS_MINIMIZE))
333         {
334             PostMessage16( wndPtr->hwndSelf, WM_SYSCOMMAND,
335                            (WPARAM16)SC_RESTORE, 0L ); 
336             break;
337         } 
338         if ((HIWORD(lParam) & KEYDATA_ALT) && wParam)
339         {
340             if (wParam == VK_TAB || wParam == VK_ESCAPE) break;
341             if (wParam == VK_SPACE && (wndPtr->dwStyle & WS_CHILD))
342                 SendMessage16( wndPtr->parent->hwndSelf, msg, wParam, lParam );
343             else
344                 SendMessage16( wndPtr->hwndSelf, WM_SYSCOMMAND,
345                                (WPARAM16)SC_KEYMENU, (LPARAM)(DWORD)wParam );
346         } 
347         else /* check for Ctrl-Esc */
348             if (wParam != VK_ESCAPE) MessageBeep(0);
349         break;
350
351     case WM_SHOWWINDOW:
352         if (!lParam) return 0; /* sent from ShowWindow */
353         if (!(wndPtr->dwStyle & WS_POPUP) || !wndPtr->owner) return 0;
354         if ((wndPtr->dwStyle & WS_VISIBLE) && wParam) return 0;
355         else if (!(wndPtr->dwStyle & WS_VISIBLE) && !wParam) return 0;
356         ShowWindow( wndPtr->hwndSelf, wParam ? SW_SHOWNOACTIVATE : SW_HIDE );
357         break; 
358
359     case WM_CANCELMODE:
360         if (wndPtr->parent == WIN_GetDesktop()) EndMenu();
361         if (GetCapture() == wndPtr->hwndSelf) ReleaseCapture();
362         WIN_ReleaseDesktop();
363         break;
364
365     case WM_VKEYTOITEM:
366     case WM_CHARTOITEM:
367         return -1;
368
369     case WM_DROPOBJECT:
370         return DRAG_FILE;  
371
372     case WM_QUERYDROPOBJECT:
373         if (wndPtr->dwExStyle & WS_EX_ACCEPTFILES) return 1;
374         break;
375
376     case WM_QUERYDRAGICON:
377         {
378             HICON16 hIcon=0;
379             UINT16 len;
380
381             if( (hIcon=wndPtr->class->hCursor) ) return (LRESULT)hIcon;
382             for(len=1; len<64; len++)
383                 if((hIcon=LoadIcon16(wndPtr->hInstance,MAKEINTRESOURCE16(len))))
384                     return (LRESULT)hIcon;
385             return (LRESULT)LoadIcon16(0,IDI_APPLICATION16);
386         }
387         break;
388
389     case WM_ISACTIVEICON:
390         return ((wndPtr->flags & WIN_NCACTIVATED) != 0);
391
392     case WM_QUERYOPEN:
393     case WM_QUERYENDSESSION:
394         return 1;
395     }
396     return 0;
397 }
398
399
400
401 /***********************************************************************
402  *           DefWindowProc16   (USER.107)
403  */
404 LRESULT WINAPI DefWindowProc16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam,
405                                 LPARAM lParam )
406 {
407     WND * wndPtr = WIN_FindWndPtr( hwnd );
408     LRESULT result = 0;
409
410     if (!wndPtr) return 0;
411     SPY_EnterMessage( SPY_DEFWNDPROC16, hwnd, msg, wParam, lParam );
412
413     switch(msg)
414     {
415     case WM_NCCREATE:
416         {
417             CREATESTRUCT16 *cs = (CREATESTRUCT16 *)PTR_SEG_TO_LIN(lParam);
418             if (cs->lpszName)
419                 DEFWND_SetText( wndPtr, (LPSTR)PTR_SEG_TO_LIN(cs->lpszName) );
420             result = 1;
421         }
422         break;
423
424     case WM_NCCALCSIZE:
425         {
426             RECT rect32;
427             CONV_RECT16TO32( (RECT16 *)PTR_SEG_TO_LIN(lParam), &rect32 );
428             result = NC_HandleNCCalcSize( wndPtr, &rect32 );
429             CONV_RECT32TO16( &rect32, (RECT16 *)PTR_SEG_TO_LIN(lParam) );
430         }
431         break;
432
433     case WM_WINDOWPOSCHANGING:
434         result = WINPOS_HandleWindowPosChanging16( wndPtr,
435                                        (WINDOWPOS16 *)PTR_SEG_TO_LIN(lParam) );
436         break;
437
438     case WM_WINDOWPOSCHANGED:
439         {
440             WINDOWPOS16 * winPos = (WINDOWPOS16 *)PTR_SEG_TO_LIN(lParam);
441             DEFWND_HandleWindowPosChanged( wndPtr, winPos->flags );
442         }
443         break;
444
445     case WM_GETTEXT:
446         if (wParam && wndPtr->text)
447         {
448             lstrcpynA( (LPSTR)PTR_SEG_TO_LIN(lParam), wndPtr->text, wParam );
449             result = (LRESULT)strlen( (LPSTR)PTR_SEG_TO_LIN(lParam) );
450         }
451         break;
452
453     case WM_SETTEXT:
454         DEFWND_SetText( wndPtr, (LPSTR)PTR_SEG_TO_LIN(lParam) );
455         if( wndPtr->dwStyle & WS_CAPTION ) NC_HandleNCPaint( hwnd , (HRGN)1 );
456         break;
457
458     default:
459         result = DEFWND_DefWinProc( wndPtr, msg, wParam, lParam );
460         break;
461     }
462
463     WIN_ReleaseWndPtr(wndPtr);
464     SPY_ExitMessage( SPY_RESULT_DEFWND16, hwnd, msg, result );
465     return result;
466 }
467
468
469 /***********************************************************************
470  *  DefWindowProc32A [USER32.126] 
471  *
472  */
473 LRESULT WINAPI DefWindowProcA( HWND hwnd, UINT msg, WPARAM wParam,
474                                  LPARAM lParam )
475 {
476     WND * wndPtr = WIN_FindWndPtr( hwnd );
477     LRESULT result = 0;
478
479     if (!wndPtr) return 0;
480     SPY_EnterMessage( SPY_DEFWNDPROC, hwnd, msg, wParam, lParam );
481
482     switch(msg)
483     {
484     case WM_NCCREATE:
485         {
486             CREATESTRUCTA *cs = (CREATESTRUCTA *)lParam;
487             if (cs->lpszName) DEFWND_SetText( wndPtr, cs->lpszName );
488             result = 1;
489         }
490         break;
491
492     case WM_NCCALCSIZE:
493         result = NC_HandleNCCalcSize( wndPtr, (RECT *)lParam );
494         break;
495
496     case WM_WINDOWPOSCHANGING:
497         result = WINPOS_HandleWindowPosChanging( wndPtr,
498                                                    (WINDOWPOS *)lParam );
499         break;
500
501     case WM_WINDOWPOSCHANGED:
502         {
503             WINDOWPOS * winPos = (WINDOWPOS *)lParam;
504             DEFWND_HandleWindowPosChanged( wndPtr, winPos->flags );
505         }
506         break;
507
508     case WM_GETTEXT:
509         if (wParam && wndPtr->text)
510         {
511             lstrcpynA( (LPSTR)lParam, wndPtr->text, wParam );
512             result = (LRESULT)strlen( (LPSTR)lParam );
513         }
514         break;
515
516     case WM_SETTEXT:
517         DEFWND_SetText( wndPtr, (LPSTR)lParam );
518         NC_HandleNCPaint( hwnd , (HRGN)1 );  /* Repaint caption */
519         break;
520
521     default:
522         result = DEFWND_DefWinProc( wndPtr, msg, wParam, lParam );
523         break;
524     }
525
526     WIN_ReleaseWndPtr(wndPtr);
527     SPY_ExitMessage( SPY_RESULT_DEFWND, hwnd, msg, result );
528     return result;
529 }
530
531
532 /***********************************************************************
533  * DefWindowProc32W [USER32.127] Calls default window message handler
534  * 
535  * Calls default window procedure for messages not processed 
536  *  by application.
537  *
538  *  RETURNS
539  *     Return value is dependent upon the message.
540 */
541 LRESULT WINAPI DefWindowProcW( 
542     HWND hwnd,      /* [in] window procedure recieving message */
543     UINT msg,       /* [in] message identifier */
544     WPARAM wParam,  /* [in] first message parameter */
545     LPARAM lParam )   /* [in] second message parameter */
546 {
547     LRESULT result;
548
549     switch(msg)
550     {
551     case WM_NCCREATE:
552         {
553             CREATESTRUCTW *cs = (CREATESTRUCTW *)lParam;
554             if (cs->lpszName)
555             {
556                 WND *wndPtr = WIN_FindWndPtr( hwnd );
557                 LPSTR str = HEAP_strdupWtoA(GetProcessHeap(), 0, cs->lpszName);
558                 DEFWND_SetText( wndPtr, str );
559                 HeapFree( GetProcessHeap(), 0, str );
560                 WIN_ReleaseWndPtr(wndPtr);
561             }
562             result = 1;
563         }
564         break;
565
566     case WM_GETTEXT:
567         {
568             LPSTR str = HeapAlloc( GetProcessHeap(), 0, wParam );
569             result = DefWindowProcA( hwnd, msg, wParam, (LPARAM)str );
570             lstrcpynAtoW( (LPWSTR)lParam, str, wParam );
571             HeapFree( GetProcessHeap(), 0, str );
572         }
573         break;
574
575     case WM_SETTEXT:
576         {
577             LPSTR str = HEAP_strdupWtoA( GetProcessHeap(), 0, (LPWSTR)lParam );
578             result = DefWindowProcA( hwnd, msg, wParam, (LPARAM)str );
579             HeapFree( GetProcessHeap(), 0, str );
580         }
581         break;
582
583     default:
584         result = DefWindowProcA( hwnd, msg, wParam, lParam );
585         break;
586     }
587     return result;
588 }