2014-07-17 22:45:12 -05:00
// 17 july 2014
# include "winapi_windows.h"
2014-07-17 23:29:15 -05:00
# include "_cgo_export.h"
2014-07-17 22:45:12 -05:00
LRESULT getWindowTextLen ( HWND hwnd )
{
return SendMessageW ( hwnd , WM_GETTEXTLENGTH , 0 , 0 ) ;
}
2014-08-01 17:25:59 -05:00
void getWindowText ( HWND hwnd , WPARAM n , LPWSTR buf )
2014-07-17 22:45:12 -05:00
{
SetLastError ( 0 ) ;
2014-08-14 15:17:44 -05:00
if ( SendMessageW ( hwnd , WM_GETTEXT , n + 1 , ( LPARAM ) buf ) ! = ( LRESULT ) n )
2014-07-17 22:45:12 -05:00
xpanic ( " WM_GETTEXT did not copy the correct number of characters out " , GetLastError ( ) ) ;
}
2014-08-01 17:25:59 -05:00
void setWindowText ( HWND hwnd , LPWSTR text )
2014-07-17 22:45:12 -05:00
{
switch ( SendMessageW ( hwnd , WM_SETTEXT , 0 , ( LPARAM ) text ) ) {
case FALSE :
xpanic ( " WM_SETTEXT failed " , GetLastError ( ) ) ;
}
}
void updateWindow ( HWND hwnd )
{
if ( UpdateWindow ( hwnd ) = = 0 )
xpanic ( " error calling UpdateWindow() " , GetLastError ( ) ) ;
}
2014-10-18 16:03:07 -05:00
void * getWindowData ( HWND hwnd , UINT uMsg , WPARAM wParam , LPARAM lParam , LRESULT * lResult )
2014-07-17 22:45:12 -05:00
{
CREATESTRUCTW * cs = ( CREATESTRUCTW * ) lParam ;
2014-08-14 15:12:43 -05:00
void * data ;
data = ( void * ) GetWindowLongPtrW ( hwnd , GWLP_USERDATA ) ;
if ( data = = NULL ) {
// the lpParam is available during WM_NCCREATE and WM_CREATE
2014-10-18 16:03:07 -05:00
if ( uMsg = = WM_NCCREATE )
2014-08-14 15:12:43 -05:00
SetWindowLongPtrW ( hwnd , GWLP_USERDATA , ( LONG_PTR ) ( cs - > lpCreateParams ) ) ;
// act as if we're not ready yet, even during WM_NCCREATE (nothing important to the switch statement below happens here anyway)
* lResult = DefWindowProcW ( hwnd , uMsg , wParam , lParam ) ;
}
return data ;
2014-07-17 22:45:12 -05:00
}
2014-08-14 15:00:31 -05:00
2014-11-05 13:12:57 -06:00
// this is a helper function that takes the logic of determining window classes and puts it all in one place
// there are a number of places where we need to know what window class an arbitrary handle has
// theoretically we could use the class atom to avoid a _wcsicmp()
// however, raymond chen advises against this - http://blogs.msdn.com/b/oldnewthing/archive/2004/10/11/240744.aspx (and we're not in control of the Tab class, before you say anything)
// usage: windowClassOf(hwnd, L"class 1", L"class 2", ..., NULL)
int windowClassOf ( HWND hwnd , . . . )
{
// MSDN says 256 is the maximum length of a class name; add a few characters just to be safe (because it doesn't say whether this includes the terminating null character)
# define maxClassName 260
WCHAR classname [ maxClassName + 1 ] ;
va_list ap ;
WCHAR * curname ;
int i ;
if ( GetClassNameW ( hwnd , classname , maxClassName ) = = 0 )
xpanic ( " error getting name of window class in windowClassOf() " , GetLastError ( ) ) ;
va_start ( ap , hwnd ) ;
i = 0 ;
for ( ; ; ) {
curname = va_arg ( ap , WCHAR * ) ;
if ( curname = = NULL )
break ;
if ( _wcsicmp ( classname , curname ) = = 0 ) {
va_end ( ap ) ;
return i ;
}
i + + ;
}
// no match
va_end ( ap ) ;
return - 1 ;
}
2014-08-14 15:00:31 -05:00
/*
all container windows ( including the message - only window , hence this is not in container_windows . c ) have to call the sharedWndProc ( ) to ensure messages go in the right place and control colors are handled properly
*/
/*
all controls that have events receive the events themselves through subclasses
to do this , all container windows ( including the message - only window ; see http : //support.microsoft.com/default.aspx?scid=KB;EN-US;Q104069) forward WM_COMMAND to each control with this function, WM_NOTIFY with forwardNotify, etc.
*/
static LRESULT forwardCommand ( HWND hwnd , UINT uMsg , WPARAM wParam , LPARAM lParam )
{
HWND control = ( HWND ) lParam ;
// don't generate an event if the control (if there is one) is unparented (a child of the message-only window)
if ( control ! = NULL & & IsChild ( msgwin , control ) = = 0 )
return SendMessageW ( control , msgCOMMAND , wParam , lParam ) ;
return DefWindowProcW ( hwnd , uMsg , wParam , lParam ) ;
}
static LRESULT forwardNotify ( HWND hwnd , UINT uMsg , WPARAM wParam , LPARAM lParam )
{
NMHDR * nmhdr = ( NMHDR * ) lParam ;
HWND control = nmhdr - > hwndFrom ;
// don't generate an event if the control (if there is one) is unparented (a child of the message-only window)
if ( control ! = NULL & & IsChild ( msgwin , control ) = = 0 )
return SendMessageW ( control , msgNOTIFY , wParam , lParam ) ;
return DefWindowProcW ( hwnd , uMsg , wParam , lParam ) ;
}
BOOL sharedWndProc ( HWND hwnd , UINT uMsg , WPARAM wParam , LPARAM lParam , LRESULT * lResult )
{
switch ( uMsg ) {
case WM_COMMAND :
* lResult = forwardCommand ( hwnd , uMsg , wParam , lParam ) ;
return TRUE ;
case WM_NOTIFY :
* lResult = forwardNotify ( hwnd , uMsg , wParam , lParam ) ;
return TRUE ;
2014-08-14 16:13:52 -05:00
case WM_CTLCOLORSTATIC :
2014-08-28 09:30:53 -05:00
case WM_CTLCOLORBTN :
2014-11-05 15:36:44 -06:00
// read-only TextFields and Textboxes are exempt
// this is because read-only edit controls count under WM_CTLCOLORSTATIC
if ( windowClassOf ( ( HWND ) lParam , L " edit " , NULL ) = = 0 )
if ( textfieldReadOnly ( ( HWND ) lParam ) )
return FALSE ;
2014-08-28 14:38:47 -05:00
if ( SetBkMode ( ( HDC ) wParam , TRANSPARENT ) = = 0 )
xpanic ( " error setting transparent background mode to Labels " , GetLastError ( ) ) ;
paintControlBackground ( ( HWND ) lParam , ( HDC ) wParam ) ;
* lResult = ( LRESULT ) hollowBrush ;
return TRUE ;
2014-08-14 15:00:31 -05:00
}
return FALSE ;
}
2014-08-28 09:30:53 -05:00
void paintControlBackground ( HWND hwnd , HDC dc )
{
HWND parent ;
RECT r ;
2014-10-30 07:36:14 -05:00
POINT p , pOrig ;
2014-08-28 09:30:53 -05:00
2014-08-28 12:30:29 -05:00
parent = hwnd ;
2014-10-18 16:03:07 -05:00
for ( ; ; ) {
2014-08-28 12:30:29 -05:00
parent = GetParent ( parent ) ;
if ( parent = = NULL )
xpanic ( " error getting parent control of control in paintControlBackground() " , GetLastError ( ) ) ;
2014-10-18 16:03:07 -05:00
// wine sends these messages early, yay...
2014-08-30 21:39:59 -05:00
if ( parent = = msgwin )
return ;
2014-10-27 09:19:39 -05:00
// skip groupboxes; they're (supposed to be) transparent
2014-11-05 13:12:57 -06:00
if ( windowClassOf ( parent , L " button " , NULL ) ! = 0 )
2014-10-27 09:19:39 -05:00
break ;
2014-10-18 16:03:07 -05:00
}
2014-08-28 09:30:53 -05:00
if ( GetWindowRect ( hwnd , & r ) = = 0 )
xpanic ( " error getting control's window rect in paintControlBackground() " , GetLastError ( ) ) ;
// the above is a window rect; convert to client rect
p . x = r . left ;
p . y = r . top ;
if ( ScreenToClient ( parent , & p ) = = 0 )
xpanic ( " error getting client origin of control in paintControlBackground() " , GetLastError ( ) ) ;
2014-10-30 07:36:14 -05:00
if ( SetWindowOrgEx ( dc , p . x , p . y , & pOrig ) = = 0 )
2014-08-28 09:30:53 -05:00
xpanic ( " error moving window origin in paintControlBackground() " , GetLastError ( ) ) ;
SendMessageW ( parent , WM_PRINTCLIENT , ( WPARAM ) dc , PRF_CLIENT ) ;
2014-10-30 07:36:14 -05:00
if ( SetWindowOrgEx ( dc , pOrig . x , pOrig . y , NULL ) = = 0 )
xpanic ( " error resetting window origin in paintControlBackground() " , GetLastError ( ) ) ;
2014-08-28 09:30:53 -05:00
}