wine/windows/win.c
Alexandre Julliard e2991ea7bd Release 950727
Sat Jul 22 22:39:09 IDT 1995 Michael Veksler <e1678223@tochnapc2.technion.ac.il>

	* [ipc/*]
	New directory. This directory contains the new inter-wine
 	communications support. It enables DDE protocols between two wine
 	instances.  Currently it is limited to DDE, but can be enhanced to
 	support OLE between 2 different wine instances.  This is very
 	important for libwine.a DDE/OLE support.

	* [tools/ipcl]
    	A script to delete garbage IPC handles (shared memory, semaphores
 	and message queues).  The current inter-wine communication is not
 	perfect, and sometimes leaves garbage behind.

	* [if1632/relay.c] [include/atom.h] [include/global.h]
 	[loader/selector.c] [loader/task.c] [loader/module.c]
 	[loader/signal.c] [memory/global.c] [misc/atom.c]
 	[windows/class.c] [windows/message.c] [windows/win.c]
	[Imakefile]
    	Hooks for inter-wine DDE support, current Global.*Atom functions
 	renamed to Local.*Atom since Global.*Atom are used for Inter-Wine
 	DDE communication. (The first call to these functions sets up the
 	IPC structures - which otherwise cause unneeded overhead.

Mon Jul 17 19:55:21 1995  Alexandre Julliard  <julliard@sunsite.unc.edu>

	* [controls/menu.c]
	Don't crash if a NULL string is passed to menu functions.

	* [memory/selector.c]
	We now use a bit in ldt_flags_copy to indicate free LDT entries.
	Fixed a bug in SELECTOR_ReallocBlock that could cause it to
	overwrite valid LDT entries when growing a block.

	* [miscemu/instr.c]
	Emulate int xx instruction by storing the interrupt vector in
	CS:IP and returning directly. This allows a program to install an
	interrupt vector.

	* [windows/win.c]
	Added function WIN_GetTopParent to get the top-level parent of a
	window.

Sun Jul  16 18:17:17 1995  Gregory Trubetskoy <grisha@mira.com>

        * [loader/resource.c]
        Added LoadIconHandler. It doesn't do anything yet, but now you
        can use borland help files with winhelp.exe.

Sun Jul 16 11:58:45 1995 Anand Kumria <akumria@ozemail.com.au>

	* [misc/main.c]
	Fixed to return 386 Enhanced mode correctly. Also return the same
 	type of CPU, for both Enhanced and Standard mode, namely a 386.

Sun Jul 16 00:02:04 1995    Martin von Loewis <loewis@informatik.hu-berlin.de>

	* [Configure] [include/options.h] [include/wineopts.h]
	  [misc/main.c][misc/spy.c]
	  Removed support of spy file. Redirected spy messages to stddeb.
	  Removed -spy option. Added -debugmsg +spy option.

	* [debugger/dbg.y][debugger/debug.l]
	Enabled segmented addresses (seg:offs) for break and x commands.

	* [if1632/gdi.spec] [objects/region.c] [windows/graphics.c]
	  [include/region.h]
	FrameRgn, REGION_FrameRgn: New functions

	* [if1632/kernel.spec]
	IsWinOldApTask: Return false

	* [if1632/mouse.spec]
	CplApplet: Removed

	* [if1632/user.spec] [windows/win.c]
	ShowOwnedPopups: New function

	* [if1632/winsock.spec] [misc/winsocket.c]
	inet_addr, select: New prototypes in relay code
	Fixed memory layout for netdb functions (getXbyY).
	WINSOCK_ioctlsocket: Translated FIONREAD, FIONBIO, and FIOASYNC

	* [objects/clipping.c]
	RectVisible: Fixed call to LPToDP

	* [rc/winerc.c]
	main: Removed extra argument to getopt for Linux.

Tue Jul 11 00:14:41 1995   Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>

        * [controls/listbox.c]
	Yet another fix for ListBoxDirectory().
	
	* [loader/module.c] [if1632/kernel.spec]
	Make GetModuleHandle() accept instance handles as parameter.

        * [if1632/relay.c] [loader/task.c]
	Put a magic cookie at the bottom of the 32 bit stack, and check on
	each return from a 32 bit function whether it's still there. Complain
	if it's not.

        * [if1632/user.spec]
	Wrong entry for CloseDriver().

	* [misc/dos_fs.c] [loader/task.c] [include/dos_fs.h] [misc/file.c]
	[miscemu/int21.c]
	Large parts of dos_fs.c simplified. Changed it to use one
	current drive/directory per task, which is set to the module path on
	task creation.
	Prevent CorelPaint from closing stdin.
	open() with O_CREAT set must be passed three parameters.
	DOS FindFirst()/FindNext() could crash when FA_LABEL was set. Fixed,
	it's in DOS_readdir() now.

	* [misc/profile.c]
	Some badly written software (Lotus Freelance Graphics) passes a bogus
	size parameter that caused Wine to write off the end of a segment.
	Fixed. (It's probably too paranoid now.)
	
	* [multimedia/mmsystem.c] [multimedia/time.c] [multimedia/joystick.c]
	[multimedia/Imakefile] [if1632/winprocs.spec]
	16 bit entry point for MMSysTimeCallback.
	Split off time.c and joystick.c from mmsystem.c.
	
	* [objects/dib.c]
	GetDIBits(): call XGetImage() via CallTo32_LargeStack.

        * [windows/cursor.c]
	DestroyCursor(): do nothing for builtin cursors.
	
	* [windows/mdi.c]
	Half of WM_MDISETMENU implemented.
	
	* [windows/win.c]
	EnumWindows() and EnumTaskWindows() never enumerated any windows.
	Fixed.

	* [windows/*.c]
	Fixed GetParent() to return correct values for owned windows.

	* [windows/message.c]
	Don't try to activate disabled top-level windows.

        * [windows/nonclient.c]
	Work around a bug in gcc-2.7.0.
	
	* [tools/build.c] [include/stackframe.h] [memory/global.c] 
	[loader/task.c] [memory/selector.c]
	Some Visual Basic programs (and possibly others, too) expect ES to be 
	preserved by a call to an API function, so we have to save it.
	In GlobalFree() and FreeSelector(), we must clear CURRENT_STACK16->es 
	to prevent segfaults if ES contained the selector to be freed.

Sun Jul  9 20:21:20 1995  Jon Tombs  <jon@gtex02.us.es>

	* [*/*]
	Added missing prototypes to header files and relevant includes
	to reduce compile time warnings.

Sun Jul  9 18:32:56 1995  Michael Patra  <micky@marie.physik.tu-berlin.de>

	* [configure.in] [include/config.h] [*/Makefile.in]
	New configuration scheme based on autoconf.

Sat Jul  8 14:12:45 1995  Morten Welinder  <terra+@cs.cmu.edu>

	* [miscemu/ioports.c]
	Revamp to have only one in- and one out- variant, both really
 	implemented.

	* [miscemu/instr.c]
	INSTR_EmulateInstruction: Use new ioport interface.  Implement
 	string io.  Correct instruction pointer for 32-bit code.

	* [include/miscemu.h]
	Update port function prototypes.

	* [include/registers.h]
	Defined FS and GS.

Sat Jul  8 13:38:54 1995  Hans de Graaff  <graaff@twi72.twi.tudelft.nl>

	* [misc/dos_fs.c]
	ChopOffSlash(): A path consisting off a single slash is left
 	intact, and multiple slashes are all removed.
1995-07-29 13:09:43 +00:00

1209 lines
33 KiB
C

/*
* Window related functions
*
* Copyright 1993, 1994 Alexandre Julliard
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "options.h"
#include "class.h"
#include "win.h"
#include "user.h"
#include "dce.h"
#include "sysmetrics.h"
#include "menu.h"
#include "icon.h"
#include "cursor.h"
#include "event.h"
#include "message.h"
#include "nonclient.h"
#include "winpos.h"
#include "color.h"
#include "shm_main_blk.h"
#include "dde_proc.h"
#include "callback.h"
#include "stddebug.h"
/* #define DEBUG_WIN */
/* #define DEBUG_MENU */
#include "debug.h"
static HWND hwndDesktop = 0;
static HWND hWndSysModal = 0;
/***********************************************************************
* WIN_FindWndPtr
*
* Return a pointer to the WND structure corresponding to a HWND.
*/
WND * WIN_FindWndPtr( HWND hwnd )
{
WND * ptr;
if (!hwnd) return NULL;
ptr = (WND *) USER_HEAP_LIN_ADDR( hwnd );
if (ptr->dwMagic != WND_MAGIC) return NULL;
return ptr;
}
/***********************************************************************
* WIN_GetXWindow
*
* Return the X window associated to a window.
*/
Window WIN_GetXWindow( HWND hwnd )
{
WND *wndPtr = WIN_FindWndPtr( hwnd );
while (wndPtr && !wndPtr->window)
{
wndPtr = WIN_FindWndPtr( wndPtr->hwndParent );
}
return wndPtr ? wndPtr->window : 0;
}
/***********************************************************************
* WIN_UnlinkWindow
*
* Remove a window from the siblings linked list.
*/
BOOL WIN_UnlinkWindow( HWND hwnd )
{
HWND * curWndPtr;
WND *parentPtr, *wndPtr;
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
if (!(parentPtr = WIN_FindWndPtr( wndPtr->hwndParent ))) return FALSE;
curWndPtr = &parentPtr->hwndChild;
while (*curWndPtr != hwnd)
{
WND * curPtr = WIN_FindWndPtr( *curWndPtr );
curWndPtr = &curPtr->hwndNext;
}
*curWndPtr = wndPtr->hwndNext;
return TRUE;
}
/***********************************************************************
* WIN_LinkWindow
*
* Insert a window into the siblings linked list.
* The window is inserted after the specified window, which can also
* be specified as HWND_TOP or HWND_BOTTOM.
*/
BOOL WIN_LinkWindow( HWND hwnd, HWND hwndInsertAfter )
{
HWND * hwndPtr = NULL; /* pointer to hwnd to change */
WND *wndPtr, *parentPtr;
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
if (!(parentPtr = WIN_FindWndPtr( wndPtr->hwndParent ))) return FALSE;
if ((hwndInsertAfter == HWND_TOP) || (hwndInsertAfter == HWND_BOTTOM))
{
hwndPtr = &parentPtr->hwndChild; /* Point to first sibling hwnd */
if (hwndInsertAfter == HWND_BOTTOM) /* Find last sibling hwnd */
while (*hwndPtr)
{
WND * nextPtr = WIN_FindWndPtr( *hwndPtr );
hwndPtr = &nextPtr->hwndNext;
}
}
else /* Normal case */
{
WND * afterPtr = WIN_FindWndPtr( hwndInsertAfter );
if (afterPtr) hwndPtr = &afterPtr->hwndNext;
}
if (!hwndPtr) return FALSE;
wndPtr->hwndNext = *hwndPtr;
*hwndPtr = hwnd;
return TRUE;
}
/***********************************************************************
* WIN_FindWinToRepaint
*
* Find a window that needs repaint.
*/
HWND WIN_FindWinToRepaint( HWND hwnd )
{
WND * wndPtr;
/* Note: the desktop window never gets WM_PAINT messages */
if (!hwnd) hwnd = GetTopWindow( hwndDesktop );
for ( ; hwnd != 0; hwnd = wndPtr->hwndNext )
{
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
dprintf_win( stddeb, "WIN_FindWinToRepaint: %04x, style %08lx\n",
hwnd, wndPtr->dwStyle );
if (!(wndPtr->dwStyle & WS_VISIBLE) || (wndPtr->flags & WIN_NO_REDRAW))
continue;
if ((wndPtr->dwStyle & WS_MINIMIZE) && (WIN_CLASS_INFO(wndPtr).hIcon))
continue;
if (wndPtr->hrgnUpdate || (wndPtr->flags & WIN_INTERNAL_PAINT))
return hwnd;
if (wndPtr->hwndChild)
{
HWND child;
if ((child = WIN_FindWinToRepaint( wndPtr->hwndChild )))
return child;
}
}
return 0;
}
/***********************************************************************
* WIN_SendParentNotify
*
* Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
* the window has the WS_EX_NOPARENTNOTIFY style.
*/
void WIN_SendParentNotify( HWND hwnd, WORD event, LONG lParam )
{
WND *wndPtr = WIN_FindWndPtr( hwnd );
while (wndPtr && (wndPtr->dwStyle & WS_CHILD))
{
if (wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY) break;
SendMessage( wndPtr->hwndParent, WM_PARENTNOTIFY, event, lParam );
wndPtr = WIN_FindWndPtr( wndPtr->hwndParent );
}
}
/***********************************************************************
* WIN_DestroyWindow
*
* Destroy storage associated to a window
*/
static void WIN_DestroyWindow( HWND hwnd )
{
WND *wndPtr = WIN_FindWndPtr( hwnd );
CLASS *classPtr = CLASS_FindClassPtr( wndPtr->hClass );
if (main_block)
DDE_DestroyWindow(hwnd);
if (!wndPtr || !classPtr) return;
WIN_UnlinkWindow( hwnd ); /* Remove the window from the linked list */
wndPtr->dwMagic = 0; /* Mark it as invalid */
if ((wndPtr->hrgnUpdate) || (wndPtr->flags & WIN_INTERNAL_PAINT))
{
if (wndPtr->hrgnUpdate) DeleteObject( wndPtr->hrgnUpdate );
MSG_DecPaintCount( wndPtr->hmemTaskQ );
}
if (!(wndPtr->dwStyle & WS_CHILD))
{
if (wndPtr->wIDmenu) DestroyMenu( wndPtr->wIDmenu );
}
if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
if (wndPtr->window) XDestroyWindow( display, wndPtr->window );
if (classPtr->wc.style & CS_OWNDC) DCE_FreeDCE( wndPtr->hdce );
classPtr->cWindows--;
USER_HEAP_FREE( hwnd );
}
/***********************************************************************
* WIN_CreateDesktopWindow
*
* Create the desktop window.
*/
BOOL WIN_CreateDesktopWindow(void)
{
WND *wndPtr;
HCLASS hclass;
CLASS *classPtr;
HDC hdc;
if (!(hclass = CLASS_FindClassByName( DESKTOP_CLASS_NAME, 0, &classPtr )))
return FALSE;
hwndDesktop = USER_HEAP_ALLOC( sizeof(WND)+classPtr->wc.cbWndExtra );
if (!hwndDesktop) return FALSE;
wndPtr = (WND *) USER_HEAP_LIN_ADDR( hwndDesktop );
wndPtr->hwndNext = 0;
wndPtr->hwndChild = 0;
wndPtr->dwMagic = WND_MAGIC;
wndPtr->hwndParent = 0;
wndPtr->hwndOwner = 0;
wndPtr->hClass = hclass;
wndPtr->hInstance = 0;
wndPtr->rectWindow.left = 0;
wndPtr->rectWindow.top = 0;
wndPtr->rectWindow.right = SYSMETRICS_CXSCREEN;
wndPtr->rectWindow.bottom = SYSMETRICS_CYSCREEN;
wndPtr->rectClient = wndPtr->rectWindow;
wndPtr->rectNormal = wndPtr->rectWindow;
wndPtr->ptIconPos.x = -1;
wndPtr->ptIconPos.y = -1;
wndPtr->ptMaxPos.x = -1;
wndPtr->ptMaxPos.y = -1;
wndPtr->hmemTaskQ = 0; /* Desktop does not belong to a task */
wndPtr->hrgnUpdate = 0;
wndPtr->hwndLastActive = hwndDesktop;
wndPtr->lpfnWndProc = classPtr->wc.lpfnWndProc;
wndPtr->dwStyle = WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
wndPtr->dwExStyle = 0;
wndPtr->hdce = 0;
wndPtr->hVScroll = 0;
wndPtr->hHScroll = 0;
wndPtr->wIDmenu = 0;
wndPtr->hText = 0;
wndPtr->flags = 0;
wndPtr->window = rootWindow;
wndPtr->hSysMenu = 0;
wndPtr->hProp = 0;
EVENT_RegisterWindow( wndPtr->window, hwndDesktop );
SendMessage( hwndDesktop, WM_NCCREATE, 0, 0 );
if ((hdc = GetDC( hwndDesktop )) != 0)
{
SendMessage( hwndDesktop, WM_ERASEBKGND, hdc, 0 );
ReleaseDC( hwndDesktop, hdc );
}
return TRUE;
}
/***********************************************************************
* CreateWindow (USER.41)
*/
HWND CreateWindow( LPSTR className, LPSTR windowName,
DWORD style, short x, short y, short width, short height,
HWND parent, HMENU menu, HANDLE instance, SEGPTR data )
{
return CreateWindowEx( 0, className, windowName, style,
x, y, width, height, parent, menu, instance, data );
}
/***********************************************************************
* CreateWindowEx (USER.452)
*/
HWND CreateWindowEx( DWORD exStyle, LPSTR className, LPSTR windowName,
DWORD style, short x, short y, short width, short height,
HWND parent, HMENU menu, HANDLE instance, SEGPTR data )
{
HANDLE class, hwnd;
CLASS *classPtr;
WND *wndPtr;
POINT maxSize, maxPos, minTrack, maxTrack;
CREATESTRUCT createStruct;
HANDLE hwinName, hclassName;
int wmcreate;
XSetWindowAttributes win_attr;
if (windowName != NULL && HIWORD(windowName) == 0) {
dprintf_win(stddeb,"CreateWindowEx: %04x ", LOWORD(windowName));
} else {
dprintf_win(stddeb,"CreateWindowEx: '%s' ", windowName);
}
dprintf_win(stddeb, "%08lX '%s' %08lX %d,%d %dx%d %04X %04X %04X %08lx\n",
exStyle, className, style, x, y, width, height,
parent, menu, instance, data);
/* 'soundrec.exe' has negative position !
Why ? For now, here a patch : */
if (!strcmp(className, "SoundRec"))
{
if (x < 0) x = 0;
if (y < 0) y = 0;
}
if (x == CW_USEDEFAULT) x = y = 0;
if (width == CW_USEDEFAULT)
{
width = 600;
height = 400;
}
/* Find the parent and class */
if (parent)
{
/* Make sure parent is valid */
if (!IsWindow( parent )) {
dprintf_win(stddeb,"CreateWindowEx: Parent %x is not a windows\n", parent);
return 0;
}
}
else
{
if (style & WS_CHILD) {
dprintf_win(stddeb,"CreateWindowEx: no parent\n");
return 0; /* WS_CHILD needs a parent */
}
}
if (!(class = CLASS_FindClassByName( className, GetExePtr( instance ), &classPtr ))) {
fprintf(stderr,"CreateWindow BAD CLASSNAME '%s' !\n", className);
return 0;
}
/* Correct the window style */
if (!(style & (WS_POPUP | WS_CHILD))) /* Overlapped window */
style |= WS_CAPTION | WS_CLIPSIBLINGS;
if (exStyle & WS_EX_DLGMODALFRAME) style &= ~WS_THICKFRAME;
/* Create the window structure */
hwnd = USER_HEAP_ALLOC( sizeof(WND)+classPtr->wc.cbWndExtra );
if (!hwnd) {
dprintf_win(stddeb,"CreateWindowEx: Out of memory\n");
return 0;
}
/* Fill the structure */
wndPtr = (WND *) USER_HEAP_LIN_ADDR( hwnd );
wndPtr->hwndNext = 0;
wndPtr->hwndChild = 0;
wndPtr->window = 0;
wndPtr->dwMagic = WND_MAGIC;
wndPtr->hwndParent = (style & WS_CHILD) ? parent : hwndDesktop;
wndPtr->hwndOwner = (style & WS_CHILD) ? 0 : WIN_GetTopParent(parent);
wndPtr->hClass = class;
wndPtr->hInstance = instance;
wndPtr->ptIconPos.x = -1;
wndPtr->ptIconPos.y = -1;
wndPtr->ptMaxPos.x = -1;
wndPtr->ptMaxPos.y = -1;
wndPtr->hmemTaskQ = GetTaskQueue(0);
wndPtr->hrgnUpdate = 0;
wndPtr->hwndPrevActive = 0;
wndPtr->hwndLastActive = hwnd;
wndPtr->lpfnWndProc = classPtr->wc.lpfnWndProc;
wndPtr->dwStyle = style;
wndPtr->dwExStyle = exStyle;
wndPtr->wIDmenu = 0;
wndPtr->hText = 0;
wndPtr->flags = 0;
wndPtr->hVScroll = 0;
wndPtr->hHScroll = 0;
wndPtr->hSysMenu = 0;
wndPtr->hProp = 0;
if (classPtr->wc.cbWndExtra)
memset( wndPtr->wExtra, 0, classPtr->wc.cbWndExtra );
classPtr->cWindows++;
/* Get class or window DC if needed */
if (classPtr->wc.style & CS_OWNDC)
wndPtr->hdce = DCE_AllocDCE( DCE_WINDOW_DC );
else if (classPtr->wc.style & CS_CLASSDC)
wndPtr->hdce = classPtr->hdce;
else
wndPtr->hdce = 0;
/* Insert the window in the linked list */
WIN_LinkWindow( hwnd, HWND_TOP );
/* Send the WM_GETMINMAXINFO message and fix the size if needed */
NC_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack );
if (maxSize.x < width) width = maxSize.x;
if (maxSize.y < height) height = maxSize.y;
if (width <= 0) width = 1;
if (height <= 0) height = 1;
wndPtr->rectWindow.left = x;
wndPtr->rectWindow.top = y;
wndPtr->rectWindow.right = x + width;
wndPtr->rectWindow.bottom = y + height;
wndPtr->rectClient = wndPtr->rectWindow;
wndPtr->rectNormal = wndPtr->rectWindow;
/* Create the X window (only for top-level windows, and then only */
/* when there's no desktop window) */
if (!(style & WS_CHILD) && (rootWindow == DefaultRootWindow(display)))
{
CURSORALLOC *cursor;
HCURSOR hCursor = classPtr->wc.hCursor;
if (!hCursor) hCursor = LoadCursor( 0, IDC_ARROW );
cursor = (CURSORALLOC *) GlobalLock(hCursor);
win_attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask |
PointerMotionMask | ButtonPressMask |
ButtonReleaseMask | FocusChangeMask;
win_attr.override_redirect = TRUE;
win_attr.colormap = COLOR_WinColormap;
win_attr.backing_store = Options.backingstore ? WhenMapped : NotUseful;
win_attr.save_under = ((classPtr->wc.style & CS_SAVEBITS) != 0);
win_attr.cursor = cursor ? cursor->xcursor : None;
wndPtr->window = XCreateWindow( display, rootWindow, x, y,
width, height, 0, CopyFromParent,
InputOutput, CopyFromParent,
CWEventMask | CWOverrideRedirect |
CWColormap | CWCursor | CWSaveUnder |
CWBackingStore, &win_attr );
XStoreName( display, wndPtr->window, windowName );
EVENT_RegisterWindow( wndPtr->window, hwnd );
GlobalUnlock( hCursor );
}
if ((style & WS_CAPTION) && !(style & WS_CHILD))
{
if (menu) SetMenu(hwnd, menu);
else if (classPtr->wc.lpszMenuName)
SetMenu(hwnd,LoadMenu(instance,(SEGPTR)classPtr->wc.lpszMenuName));
}
else wndPtr->wIDmenu = menu;
/* Send the WM_CREATE message */
hclassName = USER_HEAP_ALLOC( strlen(className)+1 );
strcpy( USER_HEAP_LIN_ADDR(hclassName), className );
createStruct.lpCreateParams = (LPSTR)data;
createStruct.hInstance = instance;
createStruct.hMenu = menu;
createStruct.hwndParent = parent;
createStruct.cx = width;
createStruct.cy = height;
createStruct.x = x;
createStruct.y = y;
createStruct.style = style;
createStruct.lpszClass = (LPSTR)USER_HEAP_SEG_ADDR(hclassName);
createStruct.dwExStyle = 0;
if (windowName)
{
if (HIWORD(windowName) == 0) {
/* Hack for SS_ICON controls */
createStruct.lpszName = windowName;
hwinName = 0;
} else {
hwinName = USER_HEAP_ALLOC( strlen(windowName)+1 );
strcpy( USER_HEAP_LIN_ADDR(hwinName), windowName );
createStruct.lpszName = (LPSTR)USER_HEAP_SEG_ADDR(hwinName);
}
}
else
{
hwinName = 0;
createStruct.lpszName = NULL;
}
wmcreate = SendMessage( hwnd, WM_NCCREATE, 0, MAKE_SEGPTR(&createStruct) );
if (!wmcreate) {
dprintf_win(stddeb,"CreateWindowEx: WM_NCCREATE return 0\n");
wmcreate = -1;
}
else
{
WINPOS_SendNCCalcSize( hwnd, FALSE, &wndPtr->rectWindow,
NULL, NULL, NULL, &wndPtr->rectClient );
wmcreate = SendMessage(hwnd, WM_CREATE, 0, MAKE_SEGPTR(&createStruct));
}
USER_HEAP_FREE( hclassName );
if (hwinName) USER_HEAP_FREE( hwinName );
if (wmcreate == -1)
{
/* Abort window creation */
dprintf_win(stddeb,"CreateWindowEx: wmcreate==-1, aborting\n");
WIN_DestroyWindow( hwnd );
return 0;
}
/* Create a copy of SysMenu */
if (style & WS_SYSMENU) wndPtr->hSysMenu = CopySysMenu();
WIN_SendParentNotify( hwnd, WM_CREATE, MAKELONG( hwnd, wndPtr->wIDmenu ) );
if (style & WS_VISIBLE) ShowWindow( hwnd, SW_SHOW );
/* if (style & WS_MINIMIZE) ShowWindow( hwnd, SW_MINIMIZE ); */
dprintf_win(stddeb, "CreateWindowEx: return %04X \n", hwnd);
return hwnd;
}
/***********************************************************************
* DestroyWindow (USER.53)
*/
BOOL DestroyWindow( HWND hwnd )
{
WND * wndPtr;
CLASS * classPtr;
dprintf_win(stddeb, "DestroyWindow (%04x)\n", hwnd);
/* Initialisation */
if (hwnd == hwndDesktop) return FALSE; /* Can't destroy desktop */
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
if (!(classPtr = CLASS_FindClassPtr( wndPtr->hClass ))) return FALSE;
/* Hide the window */
if (wndPtr->dwStyle & WS_VISIBLE)
SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOACTIVATE |
SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE );
if ((hwnd == GetCapture()) || IsChild( hwnd, GetCapture() ))
ReleaseCapture();
WIN_SendParentNotify( hwnd, WM_DESTROY, MAKELONG(hwnd, wndPtr->wIDmenu) );
/* Recursively destroy owned windows */
for (;;)
{
HWND hwndSibling = GetWindow( hwnd, GW_HWNDFIRST );
while (hwndSibling)
{
WND *siblingPtr = WIN_FindWndPtr( hwndSibling );
if (siblingPtr->hwndOwner == hwnd) break;
hwndSibling = siblingPtr->hwndNext;
}
if (hwndSibling) DestroyWindow( hwndSibling );
else break;
}
/* Send destroy messages and destroy children */
SendMessage( hwnd, WM_DESTROY, 0, 0 );
while (wndPtr->hwndChild) /* The child removes itself from the list */
DestroyWindow( wndPtr->hwndChild );
SendMessage( hwnd, WM_NCDESTROY, 0, 0 );
/* Destroy the window */
WIN_DestroyWindow( hwnd );
return TRUE;
}
/***********************************************************************
* CloseWindow (USER.43)
*/
void CloseWindow(HWND hWnd)
{
WND * wndPtr = WIN_FindWndPtr(hWnd);
if (wndPtr->dwStyle & WS_CHILD) return;
ShowWindow(hWnd, SW_MINIMIZE);
}
/***********************************************************************
* OpenIcon (USER.44)
*/
BOOL OpenIcon(HWND hWnd)
{
if (!IsIconic(hWnd)) return FALSE;
ShowWindow(hWnd, SW_SHOWNORMAL);
return(TRUE);
}
/***********************************************************************
* FindWindow (USER.50)
*/
HWND FindWindow(LPSTR ClassMatch, LPSTR TitleMatch)
{
HCLASS hclass;
CLASS *classPtr;
HWND hwnd;
if (ClassMatch)
{
hclass = CLASS_FindClassByName( ClassMatch, 0xffff, &classPtr );
if (!hclass) return 0;
}
else hclass = 0;
hwnd = GetTopWindow( hwndDesktop );
while(hwnd)
{
WND *wndPtr = WIN_FindWndPtr( hwnd );
if (!hclass || (wndPtr->hClass == hclass))
{
/* Found matching class */
if (!TitleMatch) return hwnd;
if (wndPtr->hText)
{
char *textPtr = (char *) USER_HEAP_LIN_ADDR( wndPtr->hText );
if (!strcmp( textPtr, TitleMatch )) return hwnd;
}
}
hwnd = wndPtr->hwndNext;
}
return 0;
}
/**********************************************************************
* GetDesktopWindow (USER.286)
* GetDeskTopHwnd (USER.278)
*/
HWND GetDesktopWindow(void)
{
return hwndDesktop;
}
/*******************************************************************
* EnableWindow (USER.34)
*/
BOOL EnableWindow( HWND hwnd, BOOL enable )
{
WND *wndPtr;
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
if (enable && (wndPtr->dwStyle & WS_DISABLED))
{
/* Enable window */
wndPtr->dwStyle &= ~WS_DISABLED;
SendMessage( hwnd, WM_ENABLE, TRUE, 0 );
return TRUE;
}
else if (!enable && !(wndPtr->dwStyle & WS_DISABLED))
{
/* Disable window */
wndPtr->dwStyle |= WS_DISABLED;
if ((hwnd == GetFocus()) || IsChild( hwnd, GetFocus() ))
SetFocus( 0 ); /* A disabled window can't have the focus */
if ((hwnd == GetCapture()) || IsChild( hwnd, GetCapture() ))
ReleaseCapture(); /* A disabled window can't capture the mouse */
SendMessage( hwnd, WM_ENABLE, FALSE, 0 );
return FALSE;
}
return ((wndPtr->dwStyle & WS_DISABLED) != 0);
}
/***********************************************************************
* IsWindowEnabled (USER.35)
*/
BOOL IsWindowEnabled(HWND hWnd)
{
WND * wndPtr;
if (!(wndPtr = WIN_FindWndPtr(hWnd))) return FALSE;
return !(wndPtr->dwStyle & WS_DISABLED);
}
/**********************************************************************
* GetWindowWord (USER.133)
*/
WORD GetWindowWord( HWND hwnd, short offset )
{
WND * wndPtr = WIN_FindWndPtr( hwnd );
if (!wndPtr) return 0;
if (offset >= 0) return *(WORD *)(((char *)wndPtr->wExtra) + offset);
switch(offset)
{
case GWW_ID: return wndPtr->wIDmenu;
case GWW_HWNDPARENT: return wndPtr->hwndParent;
case GWW_HINSTANCE: return wndPtr->hInstance;
}
return 0;
}
/**********************************************************************
* SetWindowWord (USER.134)
*/
WORD SetWindowWord( HWND hwnd, short offset, WORD newval )
{
WORD *ptr, retval;
WND * wndPtr = WIN_FindWndPtr( hwnd );
if (!wndPtr) return 0;
if (offset >= 0) ptr = (WORD *)(((char *)wndPtr->wExtra) + offset);
else switch(offset)
{
case GWW_ID: ptr = &wndPtr->wIDmenu; break;
case GWW_HINSTANCE: ptr = &wndPtr->hInstance; break;
default: return 0;
}
retval = *ptr;
*ptr = newval;
return retval;
}
/**********************************************************************
* GetWindowLong (USER.135)
*/
LONG GetWindowLong( HWND hwnd, short offset )
{
WND * wndPtr = WIN_FindWndPtr( hwnd );
if (!wndPtr) return 0;
if (offset >= 0) return *(LONG *)(((char *)wndPtr->wExtra) + offset);
switch(offset)
{
case GWL_STYLE: return wndPtr->dwStyle;
case GWL_EXSTYLE: return wndPtr->dwExStyle;
case GWL_WNDPROC: return (LONG)wndPtr->lpfnWndProc;
}
return 0;
}
/**********************************************************************
* SetWindowLong (USER.136)
*/
LONG SetWindowLong( HWND hwnd, short offset, LONG newval )
{
LONG *ptr, retval;
WND * wndPtr = WIN_FindWndPtr( hwnd );
if (!wndPtr) return 0;
if (offset >= 0) ptr = (LONG *)(((char *)wndPtr->wExtra) + offset);
else switch(offset)
{
case GWL_STYLE: ptr = &wndPtr->dwStyle; break;
case GWL_EXSTYLE: ptr = &wndPtr->dwExStyle; break;
case GWL_WNDPROC: ptr = (LONG *)&wndPtr->lpfnWndProc; break;
default: return 0;
}
retval = *ptr;
*ptr = newval;
return retval;
}
/*******************************************************************
* GetWindowText (USER.36)
*/
int WIN16_GetWindowText( HWND hwnd, SEGPTR lpString, int nMaxCount )
{
return (int)SendMessage(hwnd, WM_GETTEXT, (WORD)nMaxCount,
(DWORD)lpString);
}
int GetWindowText( HWND hwnd, LPSTR lpString, int nMaxCount )
{
int len;
HANDLE handle;
/* We have to allocate a buffer on the USER heap */
/* to be able to pass its address to 16-bit code */
if (!(handle = USER_HEAP_ALLOC( nMaxCount ))) return 0;
len = (int)SendMessage( hwnd, WM_GETTEXT, (WORD)nMaxCount,
USER_HEAP_SEG_ADDR(handle) );
strncpy( lpString, USER_HEAP_LIN_ADDR(handle), nMaxCount );
USER_HEAP_FREE( handle );
return len;
}
/*******************************************************************
* SetWindowText (USER.37)
*/
void WIN16_SetWindowText( HWND hwnd, SEGPTR lpString )
{
SendMessage( hwnd, WM_SETTEXT, 0, (DWORD)lpString );
}
void SetWindowText( HWND hwnd, LPSTR lpString )
{
HANDLE handle;
/* We have to allocate a buffer on the USER heap */
/* to be able to pass its address to 16-bit code */
if (!(handle = USER_HEAP_ALLOC( strlen(lpString)+1 ))) return;
strcpy( USER_HEAP_LIN_ADDR(handle), lpString );
SendMessage( hwnd, WM_SETTEXT, 0, USER_HEAP_SEG_ADDR(handle) );
USER_HEAP_FREE( handle );
}
/*******************************************************************
* GetWindowTextLength (USER.38)
*/
int GetWindowTextLength(HWND hwnd)
{
return (int)SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0 );
}
/*******************************************************************
* IsWindow (USER.47)
*/
BOOL IsWindow( HWND hwnd )
{
WND * wndPtr = WIN_FindWndPtr( hwnd );
return ((wndPtr != NULL) && (wndPtr->dwMagic == WND_MAGIC));
}
/*****************************************************************
* GetParent (USER.46)
*/
HWND GetParent(HWND hwnd)
{
WND *wndPtr = WIN_FindWndPtr(hwnd);
if (!wndPtr) return 0;
return (wndPtr->dwStyle & WS_CHILD) ?
wndPtr->hwndParent : wndPtr->hwndOwner;
}
/*****************************************************************
* WIN_GetTopParent
*
* Get the top-level parent for a child window.
*/
HWND WIN_GetTopParent( HWND hwnd )
{
while (hwnd)
{
WND *wndPtr = WIN_FindWndPtr( hwnd );
if (wndPtr->dwStyle & WS_CHILD) hwnd = wndPtr->hwndParent;
else break;
}
return hwnd;
}
/*****************************************************************
* SetParent (USER.233)
*/
HWND SetParent(HWND hwndChild, HWND hwndNewParent)
{
HWND temp;
WND *wndPtr = WIN_FindWndPtr(hwndChild);
if (!wndPtr || !(wndPtr->dwStyle & WS_CHILD)) return 0;
temp = wndPtr->hwndParent;
WIN_UnlinkWindow(hwndChild);
if (hwndNewParent)
wndPtr->hwndParent = hwndNewParent;
else
wndPtr->hwndParent = GetDesktopWindow();
WIN_LinkWindow(hwndChild, HWND_BOTTOM);
if (IsWindowVisible(hwndChild)) UpdateWindow(hwndChild);
return temp;
}
/*******************************************************************
* IsChild (USER.48)
*/
BOOL IsChild( HWND parent, HWND child )
{
WND * wndPtr = WIN_FindWndPtr( child );
while (wndPtr && (wndPtr->dwStyle & WS_CHILD))
{
if (wndPtr->hwndParent == parent) return TRUE;
wndPtr = WIN_FindWndPtr( wndPtr->hwndParent );
}
return FALSE;
}
/***********************************************************************
* IsWindowVisible (USER.49)
*/
BOOL IsWindowVisible( HWND hwnd )
{
WND *wndPtr = WIN_FindWndPtr( hwnd );
while (wndPtr && (wndPtr->dwStyle & WS_CHILD))
{
if (!(wndPtr->dwStyle & WS_VISIBLE)) return FALSE;
wndPtr = WIN_FindWndPtr( wndPtr->hwndParent );
}
return (wndPtr && (wndPtr->dwStyle & WS_VISIBLE));
}
/*******************************************************************
* GetTopWindow (USER.229)
*/
HWND GetTopWindow( HWND hwnd )
{
WND * wndPtr = WIN_FindWndPtr( hwnd );
if (wndPtr) return wndPtr->hwndChild;
else return 0;
}
/*******************************************************************
* GetWindow (USER.262)
*/
HWND GetWindow( HWND hwnd, WORD rel )
{
WND * wndPtr = WIN_FindWndPtr( hwnd );
if (!wndPtr) return 0;
switch(rel)
{
case GW_HWNDFIRST:
if (wndPtr->hwndParent)
{
WND * parentPtr = WIN_FindWndPtr( wndPtr->hwndParent );
return parentPtr->hwndChild;
}
else return 0;
case GW_HWNDLAST:
if (!wndPtr->hwndParent) return 0; /* Desktop window */
while (wndPtr->hwndNext)
{
hwnd = wndPtr->hwndNext;
wndPtr = WIN_FindWndPtr( hwnd );
}
return hwnd;
case GW_HWNDNEXT:
return wndPtr->hwndNext;
case GW_HWNDPREV:
{
HWND hwndPrev;
if (wndPtr->hwndParent)
{
WND * parentPtr = WIN_FindWndPtr( wndPtr->hwndParent );
hwndPrev = parentPtr->hwndChild;
}
else return 0; /* Desktop window */
if (hwndPrev == hwnd) return 0;
while (hwndPrev)
{
wndPtr = WIN_FindWndPtr( hwndPrev );
if (wndPtr->hwndNext == hwnd) break;
hwndPrev = wndPtr->hwndNext;
}
return hwndPrev;
}
case GW_OWNER:
return wndPtr->hwndOwner;
case GW_CHILD:
return wndPtr->hwndChild;
}
return 0;
}
/*******************************************************************
* GetNextWindow (USER.230)
*/
HWND GetNextWindow( HWND hwnd, WORD flag )
{
if ((flag != GW_HWNDNEXT) && (flag != GW_HWNDPREV)) return 0;
return GetWindow( hwnd, flag );
}
/*******************************************************************
* ShowOwnedPopups (USER.265)
*/
void ShowOwnedPopups( HWND owner, BOOL fShow )
{
HWND hwnd = GetWindow( hwndDesktop, GW_CHILD );
while (hwnd)
{
WND *wnd = WIN_FindWndPtr(hwnd);
if (wnd->hwndOwner == owner && (wnd->dwStyle & WS_POPUP))
ShowWindow( hwnd, fShow ? SW_SHOW : SW_HIDE );
hwnd = wnd->hwndNext;
}
}
/*******************************************************************
* GetLastActivePopup (USER.287)
*/
HWND GetLastActivePopup(HWND hwnd)
{
WND *wndPtr;
wndPtr = WIN_FindWndPtr(hwnd);
if (wndPtr == NULL) return hwnd;
return wndPtr->hwndLastActive;
}
/*******************************************************************
* EnumWindows (USER.54)
*/
BOOL EnumWindows( FARPROC lpEnumFunc, LPARAM lParam )
{
HWND hwnd;
WND *wndPtr;
HWND *list, *pWnd;
int count;
/* We have to build a list of all windows first, to avoid */
/* unpleasant side-effects, for instance if the callback */
/* function changes the Z-order of the windows. */
/* First count the windows */
count = 0;
for (hwnd = GetTopWindow(hwndDesktop); hwnd != 0; hwnd = wndPtr->hwndNext)
{
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
count++;
}
if (!count) return TRUE;
/* Now build the list of all windows */
if (!(list = (HWND *)malloc( sizeof(HWND) * count ))) return FALSE;
for (hwnd = GetTopWindow(hwndDesktop), pWnd = list; hwnd != 0; hwnd = wndPtr->hwndNext)
{
wndPtr = WIN_FindWndPtr( hwnd );
*pWnd++ = hwnd;
}
/* Now call the callback function for every window */
for (pWnd = list; count > 0; count--, pWnd++)
{
/* Make sure that window still exists */
if (!IsWindow(*pWnd)) continue;
if (!CallEnumWindowsProc( lpEnumFunc, *pWnd, lParam )) break;
}
free( list );
return TRUE;
}
/**********************************************************************
* EnumTaskWindows (USER.225)
*/
BOOL EnumTaskWindows( HTASK hTask, FARPROC lpEnumFunc, LONG lParam )
{
HWND hwnd;
WND *wndPtr;
HWND *list, *pWnd;
HANDLE hQueue = GetTaskQueue( hTask );
int count;
/* This function is the same as EnumWindows(), */
/* except for an added check on the window queue. */
/* First count the windows */
count = 0;
for (hwnd = GetTopWindow(hwndDesktop); hwnd != 0; hwnd = wndPtr->hwndNext)
{
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
if (wndPtr->hmemTaskQ == hQueue) count++;
}
if (!count) return TRUE;
/* Now build the list of all windows */
if (!(list = (HWND *)malloc( sizeof(HWND) * count ))) return FALSE;
for (hwnd = GetTopWindow(hwndDesktop), pWnd = list; hwnd != 0; hwnd = wndPtr->hwndNext)
{
wndPtr = WIN_FindWndPtr( hwnd );
if (wndPtr->hmemTaskQ == hQueue) *pWnd++ = hwnd;
}
/* Now call the callback function for every window */
for (pWnd = list; count > 0; count--, pWnd++)
{
/* Make sure that window still exists */
if (!IsWindow(*pWnd)) continue;
if (!CallEnumTaskWndProc( lpEnumFunc, *pWnd, lParam )) break;
}
free( list );
return TRUE;
}
/*******************************************************************
* WIN_EnumChildWin
*
* o hwnd is the first child to use, loop until all next windows
* are processed
*
* o call wdnenumprc
*
* o call ourselves with the next child window
*
*/
static BOOL WIN_EnumChildWin(HWND hwnd, FARPROC wndenumprc, LPARAM lParam)
{
WND *wndPtr;
while (hwnd)
{
if (!(wndPtr=WIN_FindWndPtr(hwnd))) return 0;
if (!CallEnumWindowsProc( wndenumprc, hwnd, lParam )) return 0;
if (!WIN_EnumChildWin(wndPtr->hwndChild, wndenumprc, lParam)) return 0;
hwnd=wndPtr->hwndNext;
}
return 1;
}
/*******************************************************************
* EnumChildWindows (USER.55)
*
* o gets the first child of hwnd
*
* o calls WIN_EnumChildWin to do a recursive decent of child windows
*/
BOOL EnumChildWindows(HWND hwnd, FARPROC wndenumprc, LPARAM lParam)
{
WND *wndPtr;
dprintf_enum(stddeb,"EnumChildWindows\n");
if (hwnd == 0) return 0;
if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
hwnd = wndPtr->hwndChild;
return WIN_EnumChildWin(hwnd, wndenumprc, lParam);
}
/*******************************************************************
* AnyPopup [USER.52]
*/
BOOL AnyPopup()
{
dprintf_win(stdnimp,"EMPTY STUB !! AnyPopup !\n");
return FALSE;
}
/*******************************************************************
* FlashWindow [USER.105]
*/
BOOL FlashWindow(HWND hWnd, BOOL bInvert)
{
dprintf_win(stdnimp,"EMPTY STUB !! FlashWindow !\n");
return FALSE;
}
/*******************************************************************
* SetSysModalWindow [USER.188]
*/
HWND SetSysModalWindow(HWND hWnd)
{
HWND hWndOldModal = hWndSysModal;
hWndSysModal = hWnd;
dprintf_win(stdnimp,"EMPTY STUB !! SetSysModalWindow(%04X) !\n", hWnd);
return hWndOldModal;
}
/*******************************************************************
* GetSysModalWindow [USER.189]
*/
HWND GetSysModalWindow(void)
{
return hWndSysModal;
}