From 5f721f81fd9afd332ec5bba762a7010663b427af Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 4 Jan 1994 20:14:34 +0000 Subject: [PATCH] Release 0.5 Sun Jan 2 12:38:53 1994 David Metcalfe * [windows/class.c] Implemented GetClassName and GetClassInfo. * [windows/caret.c] Various improvements to text caret code. Fri Dec 31 15:22:22 1993 John Brezak * [misc/comm.c] Patches to work with NetBSD. Thu Dec 30 12:11:55 1993 John Richardson * [objects/bitblt.c] Added StretchBlt(). Tue Jan 4 05:22:07 1994 julliard@di.epfl.ch (Alexandre Julliard) * [misc/user.c] Added creation of system message queue. * [objects/bitmap.c] [objects/dcvalues.c] [windows/dc.c] Added DC size fields into DC structure. * [objects/clipping.c] Bug fix in CLIPPING_IntersectRect(). * [windows/class.c] Allocate a DCE instead of a DC for CS_CLASSDC classes. * [windows/clipping.c] Fixed GetUpdateRect() and GetUpdateRgn() to clip to the client area. * [windows/dce.c] Implemented GetDCEx() and GetWindowDC(). * [windows/defwnd.c] Implemented WM_WINDOWPOSCHANGED handling. * [windows/event.c] Preliminary support for Xlib event handling instead of Xt callbacks. Changed MSG_AddMsg() calls to hardware_event() or PostMessage(). * [windows/message.c] Preliminary support for multiple message queues. Implemented hardware_event() to store messages into the system queue. Implemented Get/SetTaskQueue(). Better WM_PAINT and WM_TIMER handling. Changes to use Xlib instead of Xt for events. * [windows/painting.c] Use GetDCEx() to retrieve the DC, to get a correct visible region. * [windows/timer.c] Moved the timer procedure callback into DispatchMessage(). Changed implementation to get rid of Xt timeouts. Timer checking is now done inside GetMessage(). * [windows/win.c] Allocate a DCE instead of a DC for CS_OWNDC windows. Replaced Xt calls with Xlib calls. Moved window positioning functions into windows/winpos.c * [windows/winpos.c] (New file) Rewritten most of the window positioning functions. Implemented SetWindowPos() and MapWindowPoints(). Jan 3, 94 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte) * [if1632/user.spec] Bad arguments description for function SetDlgItemText. * [objects/text.c] Function DrawText now handle DT_CALCRECT request. * [misc/message.c] Message boxes now use DrawText with DT_CALCRECT. * [windows/graphics.c] Bug fix in function FrameRect, (it was using PEN instead of BRUSH). * [windows/win.c] Bug fix for flags in function ShowWindow. More accurate WM_SIZE generated by function ShowWindow. * [controls/listbox.c] More code for LBS_MULTIPLESEL. More code for LBS_MULTICOLUMN. * [include/windows.h] Bad define for MF_SEPARATOR. * [controls/menu.c] New functions: PopMenuWndProc() with 'glues', CreatePopupMenu(), AppendMenu(), InsertMenu(), RemoveMenu(), DeleteMenu(), ModifyMenu(), TrackPopupMenu(). Code in stubs: CreateMenu(), DestroyMenu(). Sat Jan 1 10:22:43 1994 Bob Amstadt (bob@pooh) * loader/wine.c: Added support for relocation types 5 and 6. Mon Dec 27 11:06:03 1993 Erik Bos (erik@trashcan.hacktic.nl) * [misc/comm.c] new functions: BuildCommDCB(), OpenComm(), CloseComm(), SetCommBreak(), ClearCommBreak(), EscapeCommFunction(), FlushComm(), GetCommError(), SetCommEventMask(), GetCommEventMask(), SetCommState(), GetCommState(), TransmitCommChar(), ReadComm(), WriteComm(). Wed Dec 22 13:00:15 1993 David Metcalfe * [windows/caret.c] Implemented text caret functions. Tue Dec 21 06:13:58 1993 julliard@di.epfl.ch (Alexandre Julliard) * [loader/wine.c] Bug fix in LoadImage(). * [objects/bitblt.c] [objects/clipping.c] [objects/text.c] [windows/dc.c] [windows/dce.c] [windows/graphics.c] Modified graphics calls to take into account the DC origin. * [windows/defwnd.c] Added preliminary WM_NCCALCSIZE handling. * [windows/event.c] Send WM_NCCALCSIZE message on resize event. * [windows/win.c] Send WM_NCCALCSIZE message in CreateWindow(). Realize widgets at creation time (should prevent problems with unrealized widgets). Dec 19, 93 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte) * [controls/static.c] Send mouse & keyboard message received to its parent. * [controls/scroll.c] Send keyboard message received to its parent. * [controls/listbox.c] Add Navigation keys . ListBox now use VSCROLL & HSCROLL instead of children. Alpha version of LBS_MULTIPLESEL. Alpha version of LBS_MULTICOLUMN. * [controls/combo.c] Add Navigation keys on closed ComboBox. Remove useless 'COMBOBOX_CreateComboBox' function. Mon Dec 19 20:39:34 1993 Erik Bos (erik@trashcan.hacktic.nl) * [loader/wine. LoadImage() modified to use FindFile(). * [misc/file.c] SetErrorMode added * [misc/dos_fs.c] bug fixes. Dec 13, 93 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte) * [memory/global.c] bug fix in GlobalGetFreeSegment : good ptr in 'g_prev'. * [sysres.dll] preliminary version of a 'glass of wine' bitmap * [windows/event.c] New function 'GetCapture'. * [controls/scroll.c] Remove useless 'SCROLLBAR_CreateScrollBar' function. * [controls/listbox.c] Remove useless 'LISTBOX_CreateListBox' function. Mon Dec 13 13:51:00 1993 David Metcalfe * [objects/font.c] Corrected bugs in GetCharWidth(). * [windows/event.c] Modified EVENT_key to send Windows virtual key codes for WM_KEYDOWN and WM_KEYUP messages, and a WM_CHAR message for printable characters. Wed Dec 08 19:20:00 1993 Karl Guenter Wuensch (hn324wu@unidui.uni-duisburg.de) * [windows/graphics.c] Added Polyline and Polygon Mon Dec 13 14:51:54 1993 Erik Bos (erik@trashcan.hacktic.nl) * [controls/listbox.c] ListBoxDirectory() modified to use dos_fs.c's functions to access files&|drives. Sat Dec 04 17:04:23 1993 Erik Bos (erik@trashcan.hacktic.nl) * [misc/dos_fs.c] Added FindFile() to search a file in a dos/unix style path. * [misc/file.c] New Win31 functions: OpenFile, _lcreate, _llseek, GetTempDrive, GetTempFileName, GetWindowsDirectory, GetSystemDirectory, GetDriveType. * [misc/int21.c] Modified. Wed Dec 1 16:20:45 1993 Miguel de Icaza (miguel@roxanne.nuclecu.unam.mx) * [misc/profile.c] The Profile functions now return the correct values. They now implement all the features described in the SDK. Tue Nov 30 13:55:27 1993 Bob Amstadt (bob at amscons) * [loader/selector.c] Rewrote selector aliasing routines to use System V IPC routine to alias memory segments. Nov 28, 93 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte) * [controls/listbox.c] More consistency in functions using wIndexes * [controls/scroll.c] New function : ShowScrollBar(). * [loader/cursor.c] ... New file Move cursor functions from [loader/resource.c]. New function : ClipCursor(). New function : GetClipCursor(). New function : CreateCursor(). SetCursor() now working using gloabal variable 'winHasCursor'. *[object/palette.c] New stub only : SelectPalette(). New stub only : RealizePalette(). *[win/event.c] New function : EVENT_enter_notify(), update 'winHasCursor' and send WM_SETCURSOR. *[win/defwnd.c] Add processing of WM_SETCURSOR message. *[win/win.c] New members in WND structure : hCursor, hWndVScroll & hWndHScroll. CreateWindowEx() now create children for WM_HSCROLL & WM_VSCROLL. New function ClientToScreen(). New function ScreenToClient(). Mon Nov 25 18:25:40 1993 Erik Bos (erik@trashcan.hacktic.nl) * [files.h / regfunc.h / misc/dos.c] Removed. * [misc/dos_fs.c] Added support for loading dosdrive cfg from wine.ini. * [misc/int21.c] Modified. Wed Nov 24 11:37:33 1993 julliard@disuns2.epfl.ch (Alexandre Julliard) * [include/atom.h] [memory/atom.c] Implemented atoms. * [windows/class.c] Modified RegisterClass() to use atoms. Implemented CS_GLOBALCLASS style. * [windows/message.c] Implemented RegisterWindowMessage(). * [loader/resource.c] Bug fix in LoadResource(). * [windows/dialog.c] Modified CreateDialogParam() to use Find/LoadResource(). --- ChangeLog | 293 +++++++++++- Imakefile | 66 +++ LICENSE | 1 + Makefile | 8 +- PROPOSED_LICENSE | 29 ++ README | 54 ++- WARRANTY | 7 + Wine.tmpl | 29 ++ bsdmake.patch | 2 +- controls/Imakefile | 37 ++ controls/combo.c | 108 +++-- controls/listbox.c | 675 +++++++++++++++++--------- controls/menu.c | 616 +++++++++++++++++++++++- controls/scroll.c | 151 +++--- controls/static.c | 12 + controls/widgets.c | 31 +- debugger/Imakefile | 62 +++ debugger/readline/Imakefile | 25 + etc/Imakefile | 11 + etc/Makefile | 358 ++++++++++++++ if1632/Imakefile | 37 ++ if1632/callback.c | 4 +- if1632/gdi.spec | 5 + if1632/kernel.spec | 10 + if1632/relay.c | 2 +- if1632/user.spec | 60 ++- include/Imakefile | 38 ++ include/Makefile | 360 ++++++++++++++ include/atom.h | 27 ++ include/class.h | 2 +- include/dce.h | 13 +- include/files.h | 17 - include/gdi.h | 5 +- include/int21.h | 40 +- include/listbox.h | 9 +- include/menu.h | 15 +- include/message.h | 17 +- include/neexe.h | 4 +- include/prototypes.h | 13 +- include/segmem.h | 21 +- include/user.h | 2 + include/win.h | 24 +- include/windows.h | 331 +++++++++++-- include/wine.h | 11 +- loader/Imakefile | 35 ++ loader/Makefile | 4 +- loader/cursor.c | 385 +++++++++++++++ loader/files.c | 109 ----- loader/library.c | 2 +- loader/resource.c | 178 +------ loader/selector.c | 269 ++++++++--- loader/signal.c | 12 +- loader/wine.c | 141 ++++-- memory/Imakefile | 21 + memory/Makefile | 2 +- memory/atom.c | 328 +++++++++++++ memory/global.c | 25 +- misc/Imakefile | 45 ++ misc/Makefile | 7 +- misc/comm.c | 872 +++++++++++++++++++++++++++++++++ misc/dos.c | 76 --- misc/dos_fs.c | 756 +++++++++++++++++++++++++++++ misc/file.c | 291 +++++++---- {loader => misc}/int1a.c | 2 +- {loader => misc}/int21.c | 929 ++++++++++++++++++------------------ misc/message.c | 70 ++- misc/profile.c | 55 ++- misc/user.c | 21 +- misc/xt.c | 17 +- objects/Imakefile | 43 ++ objects/bitblt.c | 99 +++- objects/bitmap.c | 3 + objects/clipping.c | 75 +-- objects/dcvalues.c | 2 + objects/font.c | 42 +- objects/gdiobj.c | 6 +- objects/palette.c | 18 + objects/region.c | 1 + objects/text.c | 22 +- sysres.dll | Bin 66048 -> 86528 bytes test/Imakefile | 8 + test/Makefile | 347 ++++++++++++++ test/widget.exe | Bin 140094 -> 306490 bytes tools/Imakefile | 5 + windows/Imakefile | 53 ++ windows/Makefile | 2 +- windows/caret.c | 250 ++++++++++ windows/class.c | 116 ++++- windows/clipping.c | 50 +- windows/dc.c | 31 +- windows/dce.c | 242 +++++++--- windows/defwnd.c | 70 ++- windows/dialog.c | 19 +- windows/event.c | 435 ++++++++++++++--- windows/focus.c | 2 +- windows/graphics.c | 128 +++-- windows/message.c | 503 +++++++++++++------ windows/painting.c | 30 +- windows/timer.c | 126 +++-- windows/win.c | 446 ++++++++--------- windows/winpos.c | 389 +++++++++++++++ wine.ini | 19 + 102 files changed, 9613 insertions(+), 2263 deletions(-) create mode 100644 Imakefile create mode 100644 LICENSE create mode 100644 PROPOSED_LICENSE create mode 100644 WARRANTY create mode 100644 Wine.tmpl create mode 100644 controls/Imakefile create mode 100644 debugger/Imakefile create mode 100644 debugger/readline/Imakefile create mode 100644 etc/Imakefile create mode 100644 etc/Makefile create mode 100644 if1632/Imakefile create mode 100644 include/Imakefile create mode 100644 include/Makefile create mode 100644 include/atom.h delete mode 100644 include/files.h create mode 100644 loader/Imakefile create mode 100644 loader/cursor.c delete mode 100644 loader/files.c create mode 100644 memory/Imakefile create mode 100644 memory/atom.c create mode 100644 misc/Imakefile create mode 100644 misc/comm.c delete mode 100644 misc/dos.c create mode 100644 misc/dos_fs.c rename {loader => misc}/int1a.c (93%) rename {loader => misc}/int21.c (52%) create mode 100644 objects/Imakefile create mode 100644 test/Imakefile create mode 100644 test/Makefile create mode 100644 tools/Imakefile create mode 100644 windows/Imakefile create mode 100644 windows/caret.c create mode 100644 windows/winpos.c create mode 100644 wine.ini diff --git a/ChangeLog b/ChangeLog index ebf46f14a76..151f65bfec9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,295 @@ +Sun Jan 2 12:38:53 1994 David Metcalfe + + * [windows/class.c] + Implemented GetClassName and GetClassInfo. + + * [windows/caret.c] + Various improvements to text caret code. + +Fri Dec 31 15:22:22 1993 John Brezak + + * [misc/comm.c] + Patches to work with NetBSD. + +Thu Dec 30 12:11:55 1993 John Richardson + + * [objects/bitblt.c] Added StretchBlt(). + +Tue Jan 4 05:22:07 1994 julliard@di.epfl.ch (Alexandre Julliard) + + * [misc/user.c] + Added creation of system message queue. + + * [objects/bitmap.c] [objects/dcvalues.c] [windows/dc.c] + Added DC size fields into DC structure. + + * [objects/clipping.c] + Bug fix in CLIPPING_IntersectRect(). + + * [windows/class.c] + Allocate a DCE instead of a DC for CS_CLASSDC classes. + + * [windows/clipping.c] + Fixed GetUpdateRect() and GetUpdateRgn() to clip to the client area. + + * [windows/dce.c] + Implemented GetDCEx() and GetWindowDC(). + + * [windows/defwnd.c] + Implemented WM_WINDOWPOSCHANGED handling. + + * [windows/event.c] + Preliminary support for Xlib event handling instead of Xt callbacks. + Changed MSG_AddMsg() calls to hardware_event() or PostMessage(). + + * [windows/message.c] + Preliminary support for multiple message queues. + Implemented hardware_event() to store messages into the system queue. + Implemented Get/SetTaskQueue(). + Better WM_PAINT and WM_TIMER handling. + Changes to use Xlib instead of Xt for events. + + * [windows/painting.c] + Use GetDCEx() to retrieve the DC, to get a correct visible region. + + * [windows/timer.c] + Moved the timer procedure callback into DispatchMessage(). + Changed implementation to get rid of Xt timeouts. Timer checking + is now done inside GetMessage(). + + * [windows/win.c] + Allocate a DCE instead of a DC for CS_OWNDC windows. + Replaced Xt calls with Xlib calls. + Moved window positioning functions into windows/winpos.c + + * [windows/winpos.c] (New file) + Rewritten most of the window positioning functions. + Implemented SetWindowPos() and MapWindowPoints(). + +Jan 3, 94 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte) + + * [if1632/user.spec] + Bad arguments description for function SetDlgItemText. + + * [objects/text.c] + Function DrawText now handle DT_CALCRECT request. + + * [misc/message.c] + Message boxes now use DrawText with DT_CALCRECT. + + * [windows/graphics.c] + Bug fix in function FrameRect, (it was using PEN instead of BRUSH). + + * [windows/win.c] + Bug fix for flags in function ShowWindow. + More accurate WM_SIZE generated by function ShowWindow. + + * [controls/listbox.c] + More code for LBS_MULTIPLESEL. + More code for LBS_MULTICOLUMN. + + * [include/windows.h] + Bad define for MF_SEPARATOR. + + * [controls/menu.c] + New functions: PopMenuWndProc() with 'glues', + CreatePopupMenu(), AppendMenu(), InsertMenu(), RemoveMenu(), + DeleteMenu(), ModifyMenu(), TrackPopupMenu(). + Code in stubs: CreateMenu(), DestroyMenu(). + +Sat Jan 1 10:22:43 1994 Bob Amstadt (bob@pooh) + + * loader/wine.c: Added support for relocation types 5 and 6. + +---------------------------------------------------------------------- +Mon Dec 27 11:06:03 1993 Erik Bos (erik@trashcan.hacktic.nl) + + * [misc/comm.c] + new functions: BuildCommDCB(), OpenComm(), CloseComm(), + SetCommBreak(), ClearCommBreak(), EscapeCommFunction(), FlushComm(), + GetCommError(), SetCommEventMask(), GetCommEventMask(), + SetCommState(), GetCommState(), TransmitCommChar(), ReadComm(), + WriteComm(). + +Wed Dec 22 13:00:15 1993 David Metcalfe + + * [windows/caret.c] + Implemented text caret functions. + +Tue Dec 21 06:13:58 1993 julliard@di.epfl.ch (Alexandre Julliard) + + * [loader/wine.c] + Bug fix in LoadImage(). + + * [objects/bitblt.c] [objects/clipping.c] [objects/text.c] + [windows/dc.c] [windows/dce.c] [windows/graphics.c] + Modified graphics calls to take into account the DC origin. + + * [windows/defwnd.c] + Added preliminary WM_NCCALCSIZE handling. + + * [windows/event.c] + Send WM_NCCALCSIZE message on resize event. + + * [windows/win.c] + Send WM_NCCALCSIZE message in CreateWindow(). + Realize widgets at creation time (should prevent problems with + unrealized widgets). + +Dec 19, 93 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte) + + * [controls/static.c] + Send mouse & keyboard message received to its parent. + + * [controls/scroll.c] + Send keyboard message received to its parent. + + * [controls/listbox.c] + Add Navigation keys . + ListBox now use VSCROLL & HSCROLL instead of children. + Alpha version of LBS_MULTIPLESEL. + Alpha version of LBS_MULTICOLUMN. + + * [controls/combo.c] + Add Navigation keys on closed ComboBox. + Remove useless 'COMBOBOX_CreateComboBox' function. + +Mon Dec 19 20:39:34 1993 Erik Bos (erik@trashcan.hacktic.nl) + + * [loader/wine. + LoadImage() modified to use FindFile(). + + * [misc/file.c] + SetErrorMode added + + * [misc/dos_fs.c] + bug fixes. + +Dec 13, 93 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte) + + * [memory/global.c] + bug fix in GlobalGetFreeSegment : good ptr in 'g_prev'. + + * [sysres.dll] + preliminary version of a 'glass of wine' bitmap + + * [windows/event.c] + New function 'GetCapture'. + + * [controls/scroll.c] + Remove useless 'SCROLLBAR_CreateScrollBar' function. + + * [controls/listbox.c] + Remove useless 'LISTBOX_CreateListBox' function. + +Mon Dec 13 13:51:00 1993 David Metcalfe + + * [objects/font.c] + Corrected bugs in GetCharWidth(). + + * [windows/event.c] + Modified EVENT_key to send Windows virtual key codes for + WM_KEYDOWN and WM_KEYUP messages, and a WM_CHAR message + for printable characters. + +Wed Dec 08 19:20:00 1993 Karl Guenter Wuensch (hn324wu@unidui.uni-duisburg.de) + + * [windows/graphics.c] + Added Polyline and Polygon + +Mon Dec 13 14:51:54 1993 Erik Bos (erik@trashcan.hacktic.nl) + + * [controls/listbox.c] + ListBoxDirectory() modified to use dos_fs.c's functions to + access files&|drives. + +Sat Dec 04 17:04:23 1993 Erik Bos (erik@trashcan.hacktic.nl) + + * [misc/dos_fs.c] + Added FindFile() to search a file in a dos/unix style path. + + * [misc/file.c] + New Win31 functions: OpenFile, _lcreate, _llseek, GetTempDrive, + GetTempFileName, GetWindowsDirectory, GetSystemDirectory, + GetDriveType. + + * [misc/int21.c] + Modified. + +Wed Dec 1 16:20:45 1993 Miguel de Icaza (miguel@roxanne.nuclecu.unam.mx) + + * [misc/profile.c] + The Profile functions now return the correct values. They now + implement all the features described in the SDK. + +Tue Nov 30 13:55:27 1993 Bob Amstadt (bob at amscons) + + * [loader/selector.c] + Rewrote selector aliasing routines to use System V IPC + routine to alias memory segments. + +Nov 28, 93 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte) + + * [controls/listbox.c] + More consistency in functions using wIndexes + + * [controls/scroll.c] + New function : ShowScrollBar(). + + * [loader/cursor.c] ... New file + Move cursor functions from [loader/resource.c]. + New function : ClipCursor(). + New function : GetClipCursor(). + New function : CreateCursor(). + SetCursor() now working using gloabal variable 'winHasCursor'. + + *[object/palette.c] + New stub only : SelectPalette(). + New stub only : RealizePalette(). + + *[win/event.c] + New function : EVENT_enter_notify(), + update 'winHasCursor' and send WM_SETCURSOR. + + *[win/defwnd.c] + Add processing of WM_SETCURSOR message. + + *[win/win.c] + New members in WND structure : hCursor, hWndVScroll & hWndHScroll. + CreateWindowEx() now create children for WM_HSCROLL & WM_VSCROLL. + New function ClientToScreen(). + New function ScreenToClient(). + +Mon Nov 25 18:25:40 1993 Erik Bos (erik@trashcan.hacktic.nl) + + * [files.h / regfunc.h / misc/dos.c] + Removed. + + * [misc/dos_fs.c] + Added support for loading dosdrive cfg from wine.ini. + + * [misc/int21.c] + Modified. + + +Wed Nov 24 11:37:33 1993 julliard@disuns2.epfl.ch (Alexandre Julliard) + + * [include/atom.h] [memory/atom.c] + Implemented atoms. + + * [windows/class.c] + Modified RegisterClass() to use atoms. + Implemented CS_GLOBALCLASS style. + + * [windows/message.c] + Implemented RegisterWindowMessage(). + + * [loader/resource.c] + Bug fix in LoadResource(). + + * [windows/dialog.c] + Modified CreateDialogParam() to use Find/LoadResource(). + Mon Nov 22 13:58:56 1993 David Metcalfe * [windows/scroll.c] @@ -37,7 +329,6 @@ Nov 21, 93 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte) * [sysres.dll] Resources only 16bits DLL for System Resources, icons, etc... ----------------------------------------------------------------------- Sun Nov 14 14:39:06 1993 julliard@di.epfl.ch (Alexandre Julliard) * [include/dialog.h] [windows/dialog.c] diff --git a/Imakefile b/Imakefile new file mode 100644 index 00000000000..26b35f407aa --- /dev/null +++ b/Imakefile @@ -0,0 +1,66 @@ +#include "Wine.tmpl" + +/* + * This is the first try at using Imakefiles. There are probably many + * problems and things I haven't even considered. I do not have a Linux + * system to test them on, just NetBSD, so you may need to change things + * like the the SYSLIBS definition below... + * + * Peter Galbavy, 5th Dec 1993 peter@wonderland.org + */ + +#define IHaveSubDirs +#define PassCDebugFlags 'CDEBUGFLAGS=$(CDEBUGFLAGS)' 'CC=$(CC)' + +SUBDIRS = \ + tools \ + controls \ + debugger \ + etc \ + if1632 \ + include \ + loader \ + memory \ + misc \ + objects \ + test \ + windows + +WINEDIR = $(LIBDIR)/wine + +OBJS = \ + if1632.o \ + controls.o \ + loader.o \ + memory.o \ + misc.o \ + objects.o \ + windows.o \ + debugger.o \ + readline.o + +#ifdef i386BsdArchitecture +SYSLIBS = -ll -lm -li386 -lgnumalloc +#else +#ifdef LinuxArchitechture +SYSLIBS = -lm +#endif +#endif + +AllTarget(wine) + +NamedTargetSubdirs($(OBJS),$(SUBDIRS),"making",PassCDebugFlags,all) +MakefileSubdirs($(SUBDIRS)) +DependSubdirs($(SUBDIRS)) +IncludesSubdirs($(SUBDIRS)) +CleanSubdirs($(SUBDIRS)) + +NormalProgramTarget(wine,$(OBJS),XawClientDepLibs,XawClientLibs,$(SYSLIBS)) + +depend:: + +install:: + +includes:: + +clean:: diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000000..3854e932ad3 --- /dev/null +++ b/LICENSE @@ -0,0 +1 @@ +All code unless stated otherwise is covered by the GNU Pubic License. diff --git a/Makefile b/Makefile index 11a884a9bbf..1f7221cbd49 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ ###################################################################### # These variables are inherited by the sub-makefiles -DEBUGOPTS= +DEBUGOPTS=-DUSE_XLIB COPTS=-O2 -m486 INCLUDE_DIR=include LDFLAGS= @@ -12,11 +12,17 @@ LIBS=-L. -L/usr/X386/lib -lXext -lXaw -lXt -lXmu -lX11 -lm OBJS=if1632/if1632.o controls/controls.o loader/loader.o \ memory/memory.o misc/misc.o objects/objects.o windows/windows.o debugger/debugger.o SUBDIRS=if1632 controls loader memory misc objects windows debugger +TAGFILES=if1632/{*.c,*.S} controls/{*.c,*.S} loader/{*.c,*.S} \ + memory/{*.c,*.S} misc/{*.c,*.S} objects/{*.c,*.S} \ + windows/{*.c,*.S} debugger/{*.c,*.S} all: $(TARGET) dummy: +tags: + etags $(TAGFILES) + clean: rm -f *~ *.o *# @for i in tools $(SUBDIRS); do (cd $$i && $(MAKE) clean) || exit; done diff --git a/PROPOSED_LICENSE b/PROPOSED_LICENSE new file mode 100644 index 00000000000..a7d2f7a94a3 --- /dev/null +++ b/PROPOSED_LICENSE @@ -0,0 +1,29 @@ +You may without charge, royalty or other payment, copy and +distribute copies of this work and derivative works of this work +in source or binary form provided that: (1) +you appropriately publish on each copy an appropriate copyright +notice; (2) faithfully reproduce all prior copyright notices +included in the original work (you may also add your own +copyright notice); and (3) agree to indemnify and hold all prior +authors, copyright holders and licensors of the work harmless +from and against all damages arising from use of the work. + +You may distribute sources of derivative works of the work +provided that (1) (a) all source files of the original work that +have been modified, (b) all source files of the derivative work +that contain any party of the original work, and (c) all source +files of the derivative work that are necessary to compile, link +and run the derivative work without unresolved external calls and +with the same functionality of the original work ("Necessary +Sources") carry a prominent notice explaining the nature and date +of the modification and/or creation. You are encouraged to make +the Necessary Sources available under this license in order to +further the development and acceptance of the work. + +EXCEPT AS OTHERWISE RESTRICTED BY LAW, THIS WORK IS PROVIDED +WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES OF ANY KIND, INCLUDING +BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF FITNESS FOR A +PARTICULAR PURPOSE, MERCHANTABILITY OR TITLE. EXCEPT AS +OTHERWISE PROVIDED BY LAW, NO AUTHOR, COPYRIGHT HOLDER OR +LICENSOR SHALL BE LIABLE TO YOU FOR DAMAGES OF ANY KIND, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. diff --git a/README b/README index ba0b81b1a75..1b090d42f7a 100644 --- a/README +++ b/README @@ -1,6 +1,6 @@ Copyright Robert J. Amstadt, 1993. All code is provided without -warranty. It is my intent to cover this code with the Gnu Public -License. +warranty. All code is covered by the license contained in the file +LICENSE unless explicitly stated in the individual source file. INSTALLATION: @@ -19,18 +19,56 @@ All: To build Wine, first do a "make depend" and then a "make". The executable "wine" will be built. "wine" will load and run Windows' -executables. You must specify the entire path to the executable, -have the executable in the current directory, or specify a load -path with environment variable WINEPATH. +executables. You must have a file "wine.ini" in the current directory, +your homedirectory, or in the path specified by the environment +variable WINEPATH. Multiple directories in WINEPATH should be seperated +by semi-colons and NOT by colons! -For example, to run Windows' solitaire: +You must specify the entire path to the executable, or a filename only +(using the path= statement in wine.ini as the search path) - export WINEPATH=/dos/windows;/dos/windows/system - wine sol +For example: to run Windows' solitaire: + + export WINEPATH=/etc;/usr/windows + + wine sol (using the path= statement in wine.ini + wine sol.exe as the search path) + + wine c:\\windows\\sol.exe (using a dosfilename) + + wine /usr/windows/sol.exe (using a unixfilename) Have a nice game of solitaire, but be careful. Emulation isn't perfect. So, occassionally it will crash. +WHAT'S NEW with version 0.5: (see ChangeLog for details) + - Working towards elimination of Xt-dependent code. + - StretchBlt() + - GetClassName() & GetClassInfo() + - Implemented loader relocation types 5 and 6. + +WHAT'S NEW with version 0.4.14: (see ChangeLog for details) + - Bug fixes and enhancements + - Comm functions + - Text caret functions + +WHAT'S NEW with version 0.4.13: (see ChangeLog for details) + - Bug fixes + - GetCapture() + - More keyboard handling + - Polyline() and Polygon() + +WHAT'S NEW with version 0.4.12: (see ChangeLog for details) + - Bug fixes + - New DOS file functions + - Experimental Imakefiles + +WHAT'S NEW with version 0.4.11: (see ChangeLog for details) + - Bug fixes + - New cursor functions + - New file system handling + - Atoms + WHAT'S NEW with version 0.4.10: (see ChangeLog for details) - Bug fixes - More scroll bar functions diff --git a/WARRANTY b/WARRANTY new file mode 100644 index 00000000000..492af846b2e --- /dev/null +++ b/WARRANTY @@ -0,0 +1,7 @@ +EXCEPT AS OTHERWISE RESTRICTED BY LAW, THIS WORK IS PROVIDED +WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES OF ANY KIND, INCLUDING +BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF FITNESS FOR A +PARTICULAR PURPOSE, MERCHANTABILITY OR TITLE. EXCEPT AS +OTHERWISE PROVIDED BY LAW, NO AUTHOR, COPYRIGHT HOLDER OR +LICENSOR SHALL BE LIABLE TO YOU FOR DAMAGES OF ANY KIND, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. diff --git a/Wine.tmpl b/Wine.tmpl new file mode 100644 index 00000000000..3bb9466ace7 --- /dev/null +++ b/Wine.tmpl @@ -0,0 +1,29 @@ +XCOMM $Id$ + +INCLUDES = -I$(TOP)/include + +XCOMM Imake rules go here + +XCOMM First, dll description to files etc +#ifndef MakeDllFromSpec +#define MakeDllFromSpec(name,objfile) @@\ +objfile.o: Concat(dll_,name.o) Concat3(dll_,name,_tab.o) @@\ + @@\ +Concat(dll_,name.S) Concat3(dll_,name,_tab.c): name.spec $(TOP)/tools/build @@\ + $(TOP)/tools/build name.spec @@\ + +#endif + +/* + * WineRelocatableTarget - generate rules to produce a relocatable object + * file instead of a library. + */ +#ifndef WineRelocatableTarget +#define WineRelocatableTarget(objname,objlist,depobj) @@\ +AllTarget(objname.o) @@\ + @@\ +objname.o: depobj @@\ + $(RM) $@ @@\ + $(LD) $(LDCOMBINEFLAGS) objlist depobj -o $@ +#endif /* WineRelocatableTarget */ + diff --git a/bsdmake.patch b/bsdmake.patch index 99fa57a116e..68fa15782a3 100644 --- a/bsdmake.patch +++ b/bsdmake.patch @@ -6,7 +6,7 @@ diff -ruN ../Backup//Makefile ./Makefile # These definitions are for the top level TARGET=wine -LIBS=-L. -L/usr/X386/lib -lXext -lXaw -lXt -lXmu -lX11 -lm -+LIBS=-L. -L/usr/X386/lib -lXext -lXaw -lXt -lXmu -lX11 -lm -li386 -lgnumalloc ++LIBS=-L. -L/usr/X386/lib -lXext -lXaw -lXt -lXmu -lX11 -lm -li386 -lgnumalloc -ll OBJS=if1632/if1632.o controls/controls.o loader/loader.o \ memory/memory.o misc/misc.o objects/objects.o windows/windows.o SUBDIRS=if1632 controls loader memory misc objects windows diff --git a/controls/Imakefile b/controls/Imakefile new file mode 100644 index 00000000000..aee3e147848 --- /dev/null +++ b/controls/Imakefile @@ -0,0 +1,37 @@ +#include "../Wine.tmpl" + +MODULE = controls + +SRCS = \ + menu.c \ + widgets.c \ + button.c \ + scroll.c \ + listbox.c \ + combo.c \ + static.c \ + SmeMenuButto.c \ + WinLabel.c \ + WinCommand.c \ + WinMenuButto.c + +OBJS = \ + menu.o \ + widgets.o \ + button.o \ + scroll.o \ + listbox.o \ + combo.o \ + static.o \ + SmeMenuButto.o \ + WinLabel.o \ + WinCommand.o \ + WinMenuButto.o + +WineRelocatableTarget($(TOP)/$(MODULE),,$(OBJS)) +DependTarget() +CleanTarget() + +includes:: + +install:: diff --git a/controls/combo.c b/controls/combo.c index e4715891a87..c8e32b9794a 100644 --- a/controls/combo.c +++ b/controls/combo.c @@ -17,60 +17,24 @@ static char Copyright[] = "Copyright Martin Ayotte, 1993"; #include "combo.h" #include "heap.h" #include "win.h" -#include "dirent.h" +#include +#include #include LPHEADCOMBO ComboGetStorageHeader(HWND hwnd); int CreateComboStruct(HWND hwnd); -void COMBOBOX_CreateComboBox(LPSTR className, LPSTR comboLabel, HWND hwnd) -{ - WND *wndPtr = WIN_FindWndPtr(hwnd); - WND *parentPtr = WIN_FindWndPtr(wndPtr->hwndParent); - DWORD style; - char widgetName[15]; - -#ifdef DEBUG_COMBO - printf("combo: label = %s, x = %d, y = %d\n", comboLabel, - wndPtr->rectClient.left, wndPtr->rectClient.top); - printf(" width = %d, height = %d\n", - wndPtr->rectClient.right - wndPtr->rectClient.left, - wndPtr->rectClient.bottom - wndPtr->rectClient.top); -#endif - - if (!wndPtr) - return; - - style = wndPtr->dwStyle & 0x0000FFFF; -/* - if ((style & LBS_NOTIFY) == LBS_NOTIFY) -*/ - sprintf(widgetName, "%s%d", className, wndPtr->wIDmenu); - wndPtr->winWidget = XtVaCreateManagedWidget(widgetName, - compositeWidgetClass, - parentPtr->winWidget, - XtNx, wndPtr->rectClient.left, - XtNy, wndPtr->rectClient.top, - XtNwidth, wndPtr->rectClient.right - - wndPtr->rectClient.left, - XtNheight, 16, - NULL ); - GlobalUnlock(hwnd); - GlobalUnlock(wndPtr->hwndParent); -} - - /*********************************************************************** - * WIDGETS_ComboWndProc + * ComboWndProc */ -LONG COMBOBOX_ComboBoxWndProc( HWND hwnd, WORD message, - WORD wParam, LONG lParam ) +LONG ComboBoxWndProc( HWND hwnd, WORD message, WORD wParam, LONG lParam ) { WORD wRet; RECT rect; - int y; + int y, count; int width, height; + int AltState; WND *wndPtr; LPHEADCOMBO lphc; char str[128]; @@ -106,17 +70,20 @@ LONG COMBOBOX_ComboBoxWndProc( HWND hwnd, WORD message, case WM_DESTROY: lphc = ComboGetStorageHeader(hwnd); if (lphc == 0) return 0; +/* DestroyWindow(lphc->hWndDrop); DestroyWindow(lphc->hWndEdit); -/* - DestroyWindow(lphc->hWndLBox); */ + DestroyWindow(lphc->hWndLBox); free(lphc); - *((LPHEADCOMBO *)&wndPtr->wExtra[1]) = 0; +/* + *((LPHEADCOMBO *)&wndPtr->wExtra[1]) = 0; + printf("Combo WM_DESTROY after clearing wExtra !\n"); +*/ #ifdef DEBUG_COMBO printf("Combo WM_DESTROY %lX !\n", lphc); #endif - return 0; + return DefWindowProc( hwnd, message, wParam, lParam ); case WM_COMMAND: wndPtr = WIN_FindWndPtr(hwnd); @@ -169,9 +136,56 @@ LONG COMBOBOX_ComboBoxWndProc( HWND hwnd, WORD message, break; case WM_LBUTTONDOWN: printf("Combo WM_LBUTTONDOWN wParam=%x lParam=%lX !\n", wParam, lParam); + wndPtr = WIN_FindWndPtr(hwnd); + lphc = ComboGetStorageHeader(hwnd); + lphc->dwState = lphc->dwState ^ CB_SHOWDROPDOWN; + if ((lphc->dwState & CB_SHOWDROPDOWN) == CB_SHOWDROPDOWN) + ShowWindow(lphc->hWndLBox, SW_SHOW); break; case WM_KEYDOWN: - printf("Combo WM_KEYDOWN wParam %X!\n", wParam); + wndPtr = WIN_FindWndPtr(hwnd); + lphc = ComboGetStorageHeader(hwnd); + y = SendMessage(lphc->hWndLBox, LB_GETCURSEL, 0, 0L); + count = SendMessage(lphc->hWndLBox, LB_GETCOUNT, 0, 0L); + printf("COMBOBOX // GetKeyState(VK_MENU)=%d\n", GetKeyState(VK_MENU)); + if (GetKeyState(VK_MENU) < 0) { + lphc->dwState = lphc->dwState ^ CB_SHOWDROPDOWN; + if ((lphc->dwState & CB_SHOWDROPDOWN) == CB_SHOWDROPDOWN) { + ShowWindow(lphc->hWndLBox, SW_SHOW); + } + else { + ShowWindow(lphc->hWndLBox, SW_HIDE); + y = SendMessage(lphc->hWndLBox, LB_GETCURSEL, 0, 0L); + if (y != LB_ERR) { + SendMessage(lphc->hWndLBox, LB_GETTEXT, (WORD)y, (LPARAM)str); + SendMessage(lphc->hWndEdit, WM_SETTEXT, (WORD)y, (LPARAM)str); + } + } + } + else + { + switch(wParam) { + case VK_HOME: + y = 0; + break; + case VK_END: + y = count - 1; + break; + case VK_UP: + y--; + break; + case VK_DOWN: + y++; + break; + } + if (y < 0) y = 0; + if (y >= count) y = count - 1; + SendMessage(lphc->hWndLBox, LB_SETCURSEL, y, 0L); + SendMessage(lphc->hWndLBox, LB_GETTEXT, (WORD)y, (LPARAM)str); + SendMessage(lphc->hWndEdit, WM_SETTEXT, (WORD)y, (LPARAM)str); + SendMessage(GetParent(hwnd), WM_COMMAND, wndPtr->wIDmenu, + MAKELONG(hwnd, CBN_SELCHANGE)); + } break; case WM_CTLCOLOR: return(SendMessage(GetParent(hwnd), WM_CTLCOLOR, wParam, lParam)); diff --git a/controls/listbox.c b/controls/listbox.c index a71eb92b3fe..b1dfb731b25 100644 --- a/controls/listbox.c +++ b/controls/listbox.c @@ -11,16 +11,21 @@ static char Copyright[] = "Copyright Martin Ayotte, 1993"; +#include #include #include +#include +#include +#include #include "windows.h" #include "user.h" #include "heap.h" #include "win.h" +#include "wine.h" #include "listbox.h" #include "scroll.h" -#include "dirent.h" -#include +#include "int21.h" +#include "prototypes.h" #define GMEM_ZEROINIT 0x0040 @@ -38,7 +43,8 @@ int ListBoxDeleteString(HWND hwnd, UINT uIndex); int ListBoxFindString(HWND hwnd, UINT nFirst, LPSTR MatchStr); int ListBoxResetContent(HWND hwnd); int ListBoxSetCurSel(HWND hwnd, WORD wIndex); -int ListBoxSetSel(HWND hwnd, WORD wIndex); +int ListBoxSetSel(HWND hwnd, WORD wIndex, WORD state); +int ListBoxGetSel(HWND hwnd, WORD wIndex); int ListBoxDirectory(HWND hwnd, UINT attrib, LPSTR filespec); int ListBoxGetItemRect(HWND hwnd, WORD wIndex, LPRECT rect); int ListBoxSetItemHeight(HWND hwnd, WORD wIndex, long height); @@ -47,59 +53,16 @@ int ListBoxDefaultItem(HWND hwnd, WND *wndPtr, int ListBoxFindNextMatch(HWND hwnd, WORD wChar); - -void LISTBOX_CreateListBox(LPSTR className, LPSTR listboxLabel, HWND hwnd) -{ - WND *wndPtr = WIN_FindWndPtr(hwnd); - WND *parentPtr = WIN_FindWndPtr(wndPtr->hwndParent); - DWORD style; - char widgetName[15]; - -#ifdef DEBUG_LISTBOX - printf("listbox: label = %s, x = %d, y = %d\n", listboxLabel, - wndPtr->rectClient.left, wndPtr->rectClient.top); - printf(" width = %d, height = %d\n", - wndPtr->rectClient.right - wndPtr->rectClient.left, - wndPtr->rectClient.bottom - wndPtr->rectClient.top); -#endif - - if (!wndPtr) - return; - - style = wndPtr->dwStyle & 0x0000FFFF; -/* - if ((style & LBS_NOTIFY) == LBS_NOTIFY) - if ((style & LBS_SORT) == LBS_SORT) -*/ - sprintf(widgetName, "%s%d", className, wndPtr->wIDmenu); - wndPtr->winWidget = XtVaCreateManagedWidget(widgetName, - compositeWidgetClass, - parentPtr->winWidget, - XtNx, wndPtr->rectClient.left, - XtNy, wndPtr->rectClient.top, - XtNwidth, wndPtr->rectClient.right - - wndPtr->rectClient.left, - XtNheight, wndPtr->rectClient.bottom - - wndPtr->rectClient.top, - NULL ); - GlobalUnlock(hwnd); - GlobalUnlock(wndPtr->hwndParent); -} - - - /*********************************************************************** - * WIDGETS_ListBoxWndProc + * ListBoxWndProc */ -LONG LISTBOX_ListBoxWndProc( HWND hwnd, WORD message, - WORD wParam, LONG lParam ) +LONG ListBoxWndProc( HWND hwnd, WORD message, WORD wParam, LONG lParam ) { WND *wndPtr; LPHEADLIST lphl; WORD wRet; RECT rect; int y; - int width, height; CREATESTRUCT *createStruct; static RECT rectsel; switch(message) @@ -115,19 +78,23 @@ LONG LISTBOX_ListBoxWndProc( HWND hwnd, WORD message, lphl->hWndLogicParent = (HWND)HIWORD(createStruct->lpCreateParams); else lphl->hWndLogicParent = GetParent(hwnd); - width = wndPtr->rectClient.right - wndPtr->rectClient.left; - height = wndPtr->rectClient.bottom - wndPtr->rectClient.top; - lphl->hWndScroll = CreateWindow("SCROLLBAR", "", - WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBS_VERT, - width - 17, 0, 16, height, hwnd, 1, wndPtr->hInstance, NULL); - ShowWindow(lphl->hWndScroll, SW_HIDE); - SetScrollRange(lphl->hWndScroll, WM_VSCROLL, 1, lphl->ItemsCount, TRUE); + lphl->ColumnsWidth = wndPtr->rectClient.right - wndPtr->rectClient.left; + if (wndPtr->hWndVScroll != (HWND)NULL) { + SetScrollRange(hwnd, SB_VERT, 1, lphl->ItemsCount, TRUE); + ShowScrollBar(hwnd, SB_VERT, FALSE); + } + if (wndPtr->hWndHScroll != (HWND)NULL) { + SetScrollRange(hwnd, SB_HORZ, 1, 1, TRUE); + ShowScrollBar(hwnd, SB_HORZ, FALSE); + } + if (wndPtr->hCursor == (HCURSOR)NULL) + wndPtr->hCursor = LoadCursor((HINSTANCE)NULL, IDC_ARROW); return 0; case WM_DESTROY: - lphl = ListBoxGetStorageHeader(hwnd); + lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr); if (lphl == 0) return 0; ListBoxResetContent(hwnd); - DestroyWindow(lphl->hWndScroll); + DestroyCursor(wndPtr->hCursor); free(lphl); *((LPHEADLIST *)&wndPtr->wExtra[1]) = 0; #ifdef DEBUG_LISTBOX @@ -164,23 +131,74 @@ LONG LISTBOX_ListBoxWndProc( HWND hwnd, WORD message, if (lphl->FirstVisible > lphl->ItemsCount) lphl->FirstVisible = lphl->ItemsCount; if (y != lphl->FirstVisible) { - SetScrollPos(lphl->hWndScroll, WM_VSCROLL, lphl->FirstVisible, TRUE); + SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE); InvalidateRect(hwnd, NULL, TRUE); UpdateWindow(hwnd); } return 0; + case WM_HSCROLL: + lphl = ListBoxGetStorageHeader(hwnd); + if (lphl == NULL) return 0; + y = lphl->FirstVisible; + switch(wParam) { + case SB_LINEUP: + if (lphl->FirstVisible > 1) + lphl->FirstVisible -= lphl->ItemsPerColumn; + break; + case SB_LINEDOWN: + if (lphl->FirstVisible < lphl->ItemsCount) + lphl->FirstVisible += lphl->ItemsPerColumn; + break; + case SB_PAGEUP: + if (lphl->FirstVisible > 1 && lphl->ItemsPerColumn != 0) + lphl->FirstVisible -= lphl->ItemsVisible / + lphl->ItemsPerColumn * lphl->ItemsPerColumn; + break; + case SB_PAGEDOWN: + if (lphl->FirstVisible < lphl->ItemsCount && + lphl->ItemsPerColumn != 0) + lphl->FirstVisible += lphl->ItemsVisible / + lphl->ItemsPerColumn * lphl->ItemsPerColumn; + break; + case SB_THUMBTRACK: + lphl->FirstVisible = lphl->ItemsPerColumn * + (LOWORD(lParam) - 1) + 1; + break; + } + if (lphl->FirstVisible < 1) lphl->FirstVisible = 1; + if (lphl->FirstVisible > lphl->ItemsCount) + lphl->FirstVisible = lphl->ItemsCount; + if (lphl->ItemsPerColumn != 0) { + lphl->FirstVisible = lphl->FirstVisible / + lphl->ItemsPerColumn * lphl->ItemsPerColumn + 1; + if (y != lphl->FirstVisible) { + SetScrollPos(hwnd, SB_HORZ, lphl->FirstVisible / + lphl->ItemsPerColumn + 1, TRUE); + InvalidateRect(hwnd, NULL, TRUE); + UpdateWindow(hwnd); + } + } + return 0; + case WM_LBUTTONDOWN: /* SetFocus(hwnd); */ SetCapture(hwnd); - lphl = ListBoxGetStorageHeader(hwnd); + lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr); if (lphl == NULL) return 0; - lphl->PrevSelected = lphl->ItemSelected; - wRet = ListBoxFindMouse(hwnd, LOWORD(lParam), HIWORD(lParam)); - ListBoxSetCurSel(hwnd, wRet); - ListBoxGetItemRect(hwnd, wRet, &rectsel); + lphl->PrevFocused = lphl->ItemFocused; + y = ListBoxFindMouse(hwnd, LOWORD(lParam), HIWORD(lParam)); + if ((wndPtr->dwStyle & LBS_MULTIPLESEL) == LBS_MULTIPLESEL) { + lphl->ItemFocused = y; + wRet = ListBoxGetSel(hwnd, y); + ListBoxSetSel(hwnd, y, !wRet); + } + else { + ListBoxSetCurSel(hwnd, y); + } + ListBoxGetItemRect(hwnd, y, &rectsel); InvalidateRect(hwnd, NULL, TRUE); UpdateWindow(hwnd); return 0; @@ -188,7 +206,7 @@ LONG LISTBOX_ListBoxWndProc( HWND hwnd, WORD message, ReleaseCapture(); lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr); if (lphl == NULL) return 0; - if (lphl->PrevSelected != lphl->ItemSelected) + if (lphl->PrevFocused != lphl->ItemFocused) SendMessage(lphl->hWndLogicParent, WM_COMMAND, wndPtr->wIDmenu, MAKELONG(hwnd, LBN_SELCHANGE)); return 0; @@ -200,9 +218,102 @@ LONG LISTBOX_ListBoxWndProc( HWND hwnd, WORD message, MAKELONG(hwnd, LBN_DBLCLK)); printf("ListBox Send LBN_DBLCLK !\n"); return 0; + case WM_MOUSEMOVE: + if ((wParam & MK_LBUTTON) != 0) { + y = HIWORD(lParam); + if (y < 4) { + lphl = ListBoxGetStorageHeader(hwnd); + if (lphl->FirstVisible > 1) { + lphl->FirstVisible--; + if (wndPtr->hWndVScroll != (HWND)NULL) + SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE); + InvalidateRect(hwnd, NULL, TRUE); + UpdateWindow(hwnd); + break; + } + } + GetClientRect(hwnd, &rect); + if (y > (rect.bottom - 4)) { + lphl = ListBoxGetStorageHeader(hwnd); + if (lphl->FirstVisible < lphl->ItemsCount) { + lphl->FirstVisible++; + if (wndPtr->hWndVScroll != (HWND)NULL) + SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE); + InvalidateRect(hwnd, NULL, TRUE); + UpdateWindow(hwnd); + break; + } + } + if ((y > 0) && (y < (rect.bottom - 4))) { + if ((y < rectsel.top) || (y > rectsel.bottom)) { + wRet = ListBoxFindMouse(hwnd, LOWORD(lParam), HIWORD(lParam)); + if ((wndPtr->dwStyle & LBS_MULTIPLESEL) == LBS_MULTIPLESEL) { + lphl->ItemFocused = wRet; + } + else { + ListBoxSetCurSel(hwnd, wRet); + } + ListBoxGetItemRect(hwnd, wRet, &rectsel); + InvalidateRect(hwnd, NULL, TRUE); + UpdateWindow(hwnd); + } + + } + } + break; case WM_KEYDOWN: - printf("ListBox WM_KEYDOWN wParam %X!\n", wParam); - ListBoxFindNextMatch(hwnd, wParam); + lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr); + if (lphl == NULL) return 0; + switch(wParam) { + case VK_HOME: + lphl->ItemFocused = 0; + break; + case VK_END: + lphl->ItemFocused = lphl->ItemsCount - 1; + break; + case VK_LEFT: + if ((wndPtr->dwStyle & LBS_MULTICOLUMN) == LBS_MULTICOLUMN) { + lphl->ItemFocused -= lphl->ItemsPerColumn; + break; + } + case VK_UP: + lphl->ItemFocused--; + break; + case VK_RIGHT: + if ((wndPtr->dwStyle & LBS_MULTICOLUMN) == LBS_MULTICOLUMN) { + lphl->ItemFocused += lphl->ItemsPerColumn; + break; + } + case VK_DOWN: + lphl->ItemFocused++; + break; + case VK_PRIOR: + lphl->ItemFocused -= lphl->ItemsVisible; + break; + case VK_NEXT: + lphl->ItemFocused += lphl->ItemsVisible; + break; + case VK_SPACE: + wRet = ListBoxGetSel(hwnd, lphl->ItemFocused); + ListBoxSetSel(hwnd, lphl->ItemFocused, !wRet); + break; + default: + ListBoxFindNextMatch(hwnd, wParam); + return 0; + } + if (lphl->ItemFocused < 0) lphl->ItemFocused = 0; + if (lphl->ItemFocused >= lphl->ItemsCount) + lphl->ItemFocused = lphl->ItemsCount - 1; + lphl->FirstVisible = lphl->ItemFocused / lphl->ItemsVisible * + lphl->ItemsVisible + 1; + if (lphl->FirstVisible < 1) lphl->FirstVisible = 1; + if ((wndPtr->dwStyle & LBS_MULTIPLESEL) != LBS_MULTIPLESEL) { + ListBoxSetCurSel(hwnd, lphl->ItemFocused); + } + if (wndPtr->hWndVScroll != (HWND)NULL) + SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE); + InvalidateRect(hwnd, NULL, TRUE); + UpdateWindow(hwnd); break; case WM_PAINT: wndPtr = WIN_FindWndPtr(hwnd); @@ -216,42 +327,6 @@ LONG LISTBOX_ListBoxWndProc( HWND hwnd, WORD message, } StdDrawListBox(hwnd); break; - case WM_MOUSEMOVE: - if ((wParam & MK_LBUTTON) != 0) { - y = HIWORD(lParam); - if (y < 4) { - lphl = ListBoxGetStorageHeader(hwnd); - if (lphl->FirstVisible > 1) { - lphl->FirstVisible--; - SetScrollPos(lphl->hWndScroll, WM_VSCROLL, lphl->FirstVisible, TRUE); - InvalidateRect(hwnd, NULL, TRUE); - UpdateWindow(hwnd); - break; - } - } - GetClientRect(hwnd, &rect); - if (y > (rect.bottom - 4)) { - lphl = ListBoxGetStorageHeader(hwnd); - if (lphl->FirstVisible < lphl->ItemsCount) { - lphl->FirstVisible++; - SetScrollPos(lphl->hWndScroll, WM_VSCROLL, lphl->FirstVisible, TRUE); - InvalidateRect(hwnd, NULL, TRUE); - UpdateWindow(hwnd); - break; - } - } - if ((y > 0) && (y < (rect.bottom - 4))) { - if ((y < rectsel.top) || (y > rectsel.bottom)) { - wRet = ListBoxFindMouse(hwnd, LOWORD(lParam), HIWORD(lParam)); - ListBoxSetCurSel(hwnd, wRet); - ListBoxGetItemRect(hwnd, wRet, &rectsel); - InvalidateRect(hwnd, NULL, TRUE); - UpdateWindow(hwnd); - } - - } - } - break; case LB_RESETCONTENT: printf("ListBox LB_RESETCONTENT !\n"); @@ -260,17 +335,17 @@ LONG LISTBOX_ListBoxWndProc( HWND hwnd, WORD message, case LB_DIR: printf("ListBox LB_DIR !\n"); wRet = ListBoxDirectory(hwnd, wParam, (LPSTR)lParam); - if (IsWindowVisible(hwnd)) { - InvalidateRect(hwnd, NULL, TRUE); - UpdateWindow(hwnd); - } + InvalidateRect(hwnd, NULL, TRUE); + UpdateWindow(hwnd); return wRet; case LB_ADDSTRING: wRet = ListBoxAddString(hwnd, (LPSTR)lParam); return wRet; case LB_GETTEXT: wRet = ListBoxGetText(hwnd, wParam, (LPSTR)lParam); +#ifdef DEBUG_LISTBOX printf("ListBox LB_GETTEXT #%u '%s' !\n", wParam, (LPSTR)lParam); +#endif return wRet; case LB_INSERTSTRING: wRet = ListBoxInsertString(hwnd, wParam, (LPSTR)lParam); @@ -289,9 +364,8 @@ LONG LISTBOX_ListBoxWndProc( HWND hwnd, WORD message, return lphl->ItemsCount; case LB_GETCURSEL: lphl = ListBoxGetStorageHeader(hwnd); - printf("ListBox LB_GETCURSEL %u !\n", lphl->ItemSelected); - if (lphl->ItemSelected == 0) return LB_ERR; - return lphl->ItemSelected; + printf("ListBox LB_GETCURSEL %u !\n", lphl->ItemFocused); + return lphl->ItemFocused; case LB_GETHORIZONTALEXTENT: return wRet; case LB_GETITEMDATA: @@ -301,6 +375,7 @@ LONG LISTBOX_ListBoxWndProc( HWND hwnd, WORD message, case LB_GETITEMRECT: return wRet; case LB_GETSEL: + wRet = ListBoxGetSel(hwnd, wParam); return wRet; case LB_GETSELCOUNT: return wRet; @@ -317,7 +392,9 @@ LONG LISTBOX_ListBoxWndProc( HWND hwnd, WORD message, case LB_SETCARETINDEX: return wRet; case LB_SETCOLUMNWIDTH: - return wRet; + lphl = ListBoxGetStorageHeader(hwnd); + lphl->ColumnsWidth = wParam; + break; case LB_SETHORIZONTALEXTENT: return wRet; case LB_SETITEMDATA: @@ -329,38 +406,29 @@ LONG LISTBOX_ListBoxWndProc( HWND hwnd, WORD message, printf("ListBox LB_SETCURSEL wParam=%x !\n", wParam); #endif wRet = ListBoxSetCurSel(hwnd, wParam); - if (IsWindowVisible(hwnd)) { - InvalidateRect(hwnd, NULL, TRUE); - UpdateWindow(hwnd); - } + InvalidateRect(hwnd, NULL, TRUE); + UpdateWindow(hwnd); return wRet; case LB_SETSEL: printf("ListBox LB_SETSEL wParam=%x lParam=%lX !\n", wParam, lParam); - wRet = ListBoxSetSel(hwnd, wParam); - if (IsWindowVisible(hwnd)) { - InvalidateRect(hwnd, NULL, TRUE); - UpdateWindow(hwnd); - } + wRet = ListBoxSetSel(hwnd, LOWORD(lParam), wParam); + InvalidateRect(hwnd, NULL, TRUE); + UpdateWindow(hwnd); return wRet; case LB_SETTOPINDEX: printf("ListBox LB_SETTOPINDEX wParam=%x !\n", wParam); lphl = ListBoxGetStorageHeader(hwnd); lphl->FirstVisible = wParam; - SetScrollPos(lphl->hWndScroll, WM_VSCROLL, lphl->FirstVisible, TRUE); - if (IsWindowVisible(hwnd)) { - InvalidateRect(hwnd, NULL, TRUE); - UpdateWindow(hwnd); - } + if (wndPtr->hWndVScroll != (HWND)NULL) + SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE); + InvalidateRect(hwnd, NULL, TRUE); + UpdateWindow(hwnd); break; case LB_SETITEMHEIGHT: #ifdef DEBUG_LISTBOX printf("ListBox LB_SETITEMHEIGHT wParam=%x lParam=%lX !\n", wParam, lParam); #endif wRet = ListBoxSetItemHeight(hwnd, wParam, lParam); - if (IsWindowVisible(hwnd)) { - InvalidateRect(hwnd, NULL, TRUE); - UpdateWindow(hwnd); - } return wRet; default: @@ -392,6 +460,7 @@ LPHEADLIST ListBoxGetStorageHeader(HWND hwnd) void StdDrawListBox(HWND hwnd) { + WND *wndPtr; LPHEADLIST lphl; LPLISTSTRUCT lpls; PAINTSTRUCT ps; @@ -399,7 +468,7 @@ void StdDrawListBox(HWND hwnd) HWND hWndParent; HDC hdc; RECT rect; - UINT i, h, h2; + UINT i, h, h2, maxwidth, ipc; char C[128]; h = 0; hdc = BeginPaint( hwnd, &ps ); @@ -407,41 +476,64 @@ void StdDrawListBox(HWND hwnd) EndPaint( hwnd, &ps ); return; } - GetClientRect(hwnd, &rect); - lphl = ListBoxGetStorageHeader(hwnd); + lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr); if (lphl == NULL) goto EndOfPaint; hBrush = SendMessage(lphl->hWndLogicParent, WM_CTLCOLOR, (WORD)hdc, MAKELONG(hwnd, CTLCOLOR_LISTBOX)); if (hBrush == (HBRUSH)NULL) hBrush = GetStockObject(WHITE_BRUSH); - if (lphl->ItemsCount > lphl->ItemsVisible) rect.right -= 16; + GetClientRect(hwnd, &rect); + if ((wndPtr->hWndVScroll != (HWND)NULL) && + IsWindowVisible(wndPtr->hWndVScroll)) rect.right -= 16; + if ((wndPtr->hWndHScroll != (HWND)NULL) && + IsWindowVisible(wndPtr->hWndHScroll)) rect.bottom -= 16; FillRect(hdc, &rect, hBrush); + maxwidth = rect.right; + rect.right = lphl->ColumnsWidth; if (lphl->ItemsCount == 0) goto EndOfPaint; lpls = lphl->lpFirst; if (lpls == NULL) goto EndOfPaint; lphl->ItemsVisible = 0; + lphl->ItemsPerColumn = ipc = 0; for(i = 1; i <= lphl->ItemsCount; i++) { if (i >= lphl->FirstVisible) { h2 = lpls->dis.rcItem.bottom - lpls->dis.rcItem.top; lpls->dis.rcItem.top = h; lpls->dis.rcItem.bottom = h + h2; + lpls->dis.rcItem.left = rect.left; lpls->dis.rcItem.right = rect.right; - TextOut(hdc, 5, h + 2, (char *)lpls->dis.itemData, + TextOut(hdc, rect.left + 5, h + 2, (char *)lpls->dis.itemData, strlen((char *)lpls->dis.itemData)); if (lpls->dis.itemState != 0) { InvertRect(hdc, &lpls->dis.rcItem); } + if (lphl->ItemFocused == i - 1) { + DrawFocusRect(hdc, &lpls->dis.rcItem); + } h += h2; lphl->ItemsVisible++; - if (h > rect.bottom) break; + ipc++; + if (h > rect.bottom) { + if ((wndPtr->dwStyle & LBS_MULTICOLUMN) == LBS_MULTICOLUMN) { + lphl->ItemsPerColumn = max(lphl->ItemsPerColumn, ipc); + ipc = 0; + h = 0; + rect.left += lphl->ColumnsWidth; + rect.right += lphl->ColumnsWidth; + if (rect.left > maxwidth) break; + } + else + break; + } } if (lpls->lpNext == NULL) goto EndOfPaint; lpls = (LPLISTSTRUCT)lpls->lpNext; } EndOfPaint: EndPaint( hwnd, &ps ); - if (lphl->ItemsCount > lphl->ItemsVisible) { - InvalidateRect(lphl->hWndScroll, NULL, TRUE); - UpdateWindow(lphl->hWndScroll); + if ((lphl->ItemsCount > lphl->ItemsVisible) & + (wndPtr->hWndVScroll != (HWND)NULL)) { + InvalidateRect(wndPtr->hWndVScroll, NULL, TRUE); + UpdateWindow(wndPtr->hWndVScroll); } } @@ -449,6 +541,7 @@ EndOfPaint: void OwnerDrawListBox(HWND hwnd) { + WND *wndPtr; LPHEADLIST lphl; LPLISTSTRUCT lpls; PAINTSTRUCT ps; @@ -456,38 +549,47 @@ void OwnerDrawListBox(HWND hwnd) HWND hWndParent; HDC hdc; RECT rect; - UINT i, h, h2; + UINT i, h, h2, maxwidth; char C[128]; h = 0; - hdc = BeginPaint( hwnd, &ps ); + hdc = BeginPaint(hwnd, &ps); if (!IsWindowVisible(hwnd)) { EndPaint( hwnd, &ps ); return; } - GetClientRect(hwnd, &rect); - lphl = ListBoxGetStorageHeader(hwnd); + lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr); if (lphl == NULL) goto EndOfPaint; hBrush = SendMessage(lphl->hWndLogicParent, WM_CTLCOLOR, (WORD)hdc, MAKELONG(hwnd, CTLCOLOR_LISTBOX)); if (hBrush == (HBRUSH)NULL) hBrush = GetStockObject(WHITE_BRUSH); - if (lphl->ItemsCount > lphl->ItemsVisible) rect.right -= 16; + GetClientRect(hwnd, &rect); + if ((wndPtr->hWndVScroll != (HWND)NULL) && + IsWindowVisible(wndPtr->hWndVScroll)) rect.right -= 16; + if ((wndPtr->hWndHScroll != (HWND)NULL) && + IsWindowVisible(wndPtr->hWndHScroll)) rect.bottom -= 16; FillRect(hdc, &rect, hBrush); + maxwidth = rect.right; + rect.right = lphl->ColumnsWidth; if (lphl->ItemsCount == 0) goto EndOfPaint; lpls = lphl->lpFirst; if (lpls == NULL) goto EndOfPaint; lphl->ItemsVisible = 0; - for(i = 1; i <= lphl->ItemsCount; i++) { + for (i = 1; i <= lphl->ItemsCount; i++) { if (i >= lphl->FirstVisible) { lpls->dis.hDC = hdc; - lpls->dis.itemID = i; + lpls->dis.itemID = i - 1; h2 = lpls->dis.rcItem.bottom - lpls->dis.rcItem.top; lpls->dis.rcItem.top = h; lpls->dis.rcItem.bottom = h + h2; + lpls->dis.rcItem.left = rect.left; lpls->dis.rcItem.right = rect.right; lpls->dis.itemAction = ODA_DRAWENTIRE; if (lpls->dis.itemState != 0) { lpls->dis.itemAction |= ODA_SELECT; } + if (lphl->ItemFocused == i - 1) { + lpls->dis.itemAction |= ODA_FOCUS; + } #ifdef DEBUT_LISTBOX printf("LBOX WM_DRAWITEM #%d left=%d top=%d right=%d bottom=%d !\n", i, lpls->dis.rcItem.left, lpls->dis.rcItem.top, @@ -502,16 +604,17 @@ void OwnerDrawListBox(HWND hwnd) } h += h2; lphl->ItemsVisible++; - if (h > rect.bottom) break; + if (h > rect.bottom) goto EndOfPaint; } if (lpls->lpNext == NULL) goto EndOfPaint; lpls = (LPLISTSTRUCT)lpls->lpNext; } EndOfPaint: EndPaint( hwnd, &ps ); - if (lphl->ItemsCount > lphl->ItemsVisible) { - InvalidateRect(lphl->hWndScroll, NULL, TRUE); - UpdateWindow(lphl->hWndScroll); + if ((lphl->ItemsCount > lphl->ItemsVisible) & + (wndPtr->hWndVScroll != (HWND)NULL)) { + InvalidateRect(wndPtr->hWndVScroll, NULL, TRUE); + UpdateWindow(wndPtr->hWndVScroll); } } @@ -519,27 +622,42 @@ EndOfPaint: int ListBoxFindMouse(HWND hwnd, int X, int Y) { -LPHEADLIST lphl; -LPLISTSTRUCT lpls; -RECT rect; -UINT i, h, h2; -char C[128]; -h = 0; -lphl = ListBoxGetStorageHeader(hwnd); -if (lphl == NULL) return LB_ERR; -if (lphl->ItemsCount == 0) return LB_ERR; -lpls = lphl->lpFirst; -if (lpls == NULL) return LB_ERR; -for(i = 1; i <= lphl->ItemsCount; i++) { - if (i >= lphl->FirstVisible) { - h2 = h; - h += lpls->dis.rcItem.bottom - lpls->dis.rcItem.top; - if ((Y > h2) && (Y < h)) return(i); + WND *wndPtr; + LPHEADLIST lphl; + LPLISTSTRUCT lpls; + RECT rect; + UINT i, h, h2, w, w2; + char C[128]; + lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr); + if (lphl == NULL) return LB_ERR; + if (lphl->ItemsCount == 0) return LB_ERR; + lpls = lphl->lpFirst; + if (lpls == NULL) return LB_ERR; + GetClientRect(hwnd, &rect); + if ((wndPtr->hWndVScroll != (HWND)NULL) && + IsWindowVisible(wndPtr->hWndVScroll)) rect.right -= 16; + if ((wndPtr->hWndHScroll != (HWND)NULL) && + IsWindowVisible(wndPtr->hWndHScroll)) rect.bottom -= 16; + h = w2 = 0; + w = lphl->ColumnsWidth; + for(i = 1; i <= lphl->ItemsCount; i++) { + if (i >= lphl->FirstVisible) { + h2 = h; + h += lpls->dis.rcItem.bottom - lpls->dis.rcItem.top; + if ((Y > h2) && (Y < h) && + (X > w2) && (X < w)) return(i - 1); + if (h > rect.bottom) { + if ((wndPtr->dwStyle & LBS_MULTICOLUMN) != LBS_MULTICOLUMN) return LB_ERR; + h = 0; + w2 = w; + w += lphl->ColumnsWidth; + if (w2 > rect.right) return LB_ERR; + } + } + if (lpls->lpNext == NULL) return LB_ERR; + lpls = (LPLISTSTRUCT)lpls->lpNext; } - if (lpls->lpNext == NULL) return LB_ERR; - lpls = (LPLISTSTRUCT)lpls->lpNext; - } -return(LB_ERR); + return(LB_ERR); } @@ -602,14 +720,22 @@ int ListBoxAddString(HWND hwnd, LPSTR newstr) lplsnew->dis.itemID = lphl->ItemsCount; lplsnew->dis.itemData = (DWORD)newstr; lplsnew->hData = hTemp; - SetScrollRange(lphl->hWndScroll, WM_VSCROLL, 1, lphl->ItemsCount, - (lphl->FirstVisible != 1)); + if (wndPtr->hWndVScroll != (HWND)NULL) + SetScrollRange(hwnd, SB_VERT, 1, lphl->ItemsCount, + (lphl->FirstVisible != 1)); + if (wndPtr->hWndHScroll != (HWND)NULL && lphl->ItemsPerColumn != 0) + SetScrollRange(hwnd, SB_HORZ, 1, lphl->ItemsVisible / + lphl->ItemsPerColumn + 1, (lphl->FirstVisible != 1)); if (lphl->FirstVisible >= (lphl->ItemsCount - lphl->ItemsVisible)) { InvalidateRect(hwnd, NULL, TRUE); UpdateWindow(hwnd); } - if ((lphl->ItemsCount - lphl->FirstVisible) == lphl->ItemsVisible) - ShowWindow(lphl->hWndScroll, SW_NORMAL); + if ((lphl->ItemsCount - lphl->FirstVisible) == lphl->ItemsVisible) { + if (wndPtr->hWndVScroll != (HWND)NULL) + ShowScrollBar(hwnd, SB_VERT, TRUE); + if (wndPtr->hWndHScroll != (HWND)NULL) + ShowScrollBar(hwnd, SB_HORZ, TRUE); + } return lphl->ItemsCount; } @@ -624,7 +750,7 @@ int ListBoxInsertString(HWND hwnd, UINT uIndex, LPSTR newstr) UINT Count; lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr); if (lphl == NULL) return LB_ERR; - if (uIndex < 1 || uIndex > lphl->ItemsCount) return LB_ERR; + if (uIndex >= lphl->ItemsCount) return LB_ERR; lpls = lphl->lpFirst; if (lpls == NULL) return LB_ERR; if (uIndex > lphl->ItemsCount) return LB_ERR; @@ -653,11 +779,19 @@ int ListBoxInsertString(HWND hwnd, UINT uIndex, LPSTR newstr) lplsnew->dis.itemID = lphl->ItemsCount; lplsnew->dis.itemData = (DWORD)newstr; lplsnew->hData = hTemp; - SetScrollRange(lphl->hWndScroll, WM_VSCROLL, 1, lphl->ItemsCount, - (lphl->FirstVisible != 1)); + if (wndPtr->hWndVScroll != (HWND)NULL) + SetScrollRange(hwnd, SB_VERT, 1, lphl->ItemsCount, + (lphl->FirstVisible != 1)); + if (wndPtr->hWndHScroll != (HWND)NULL && lphl->ItemsPerColumn != 0) + SetScrollRange(hwnd, SB_HORZ, 1, lphl->ItemsVisible / + lphl->ItemsPerColumn + 1, (lphl->FirstVisible != 1)); if (((lphl->ItemsCount - lphl->FirstVisible) == lphl->ItemsVisible) && - (lphl->ItemsVisible != 0)) - ShowWindow(lphl->hWndScroll, SW_NORMAL); + (lphl->ItemsVisible != 0)) { + if (wndPtr->hWndVScroll != (HWND)NULL) + ShowScrollBar(hwnd, SB_VERT, TRUE); + if (wndPtr->hWndHScroll != (HWND)NULL) + ShowScrollBar(hwnd, SB_HORZ, TRUE); + } if ((lphl->FirstVisible <= uIndex) && ((lphl->FirstVisible + lphl->ItemsVisible) >= uIndex)) { InvalidateRect(hwnd, NULL, TRUE); @@ -675,11 +809,11 @@ int ListBoxGetText(HWND hwnd, UINT uIndex, LPSTR OutStr) UINT Count; lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr); if (lphl == NULL) return LB_ERR; - if (uIndex < 1 || uIndex > lphl->ItemsCount) return LB_ERR; + if (uIndex >= lphl->ItemsCount) return LB_ERR; lpls = lphl->lpFirst; if (lpls == NULL) return LB_ERR; if (uIndex > lphl->ItemsCount) return LB_ERR; - for(Count = 1; Count < uIndex; Count++) { + for(Count = 0; Count < uIndex; Count++) { if (lpls->lpNext == NULL) return LB_ERR; lpls = (LPLISTSTRUCT)lpls->lpNext; } @@ -698,12 +832,13 @@ int ListBoxGetText(HWND hwnd, UINT uIndex, LPSTR OutStr) int ListBoxDeleteString(HWND hwnd, UINT uIndex) { + WND *wndPtr; LPHEADLIST lphl; LPLISTSTRUCT lpls, lpls2; UINT Count; - lphl = ListBoxGetStorageHeader(hwnd); + lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr); if (lphl == NULL) return LB_ERR; - if (uIndex < 1 || uIndex > lphl->ItemsCount) return LB_ERR; + if (uIndex >= lphl->ItemsCount) return LB_ERR; lpls = lphl->lpFirst; if (lpls == NULL) return LB_ERR; if (uIndex > lphl->ItemsCount) return LB_ERR; @@ -716,9 +851,17 @@ int ListBoxDeleteString(HWND hwnd, UINT uIndex) lphl->ItemsCount--; if (lpls->hData != 0) USER_HEAP_FREE(lpls->hData); if (lpls->hMem != 0) USER_HEAP_FREE(lpls->hMem); - SetScrollRange(lphl->hWndScroll, WM_VSCROLL, 1, lphl->ItemsCount, TRUE); - if (lphl->ItemsCount < lphl->ItemsVisible) - ShowWindow(lphl->hWndScroll, SW_HIDE); + if (wndPtr->hWndVScroll != (HWND)NULL) + SetScrollRange(hwnd, SB_VERT, 1, lphl->ItemsCount, TRUE); + if (wndPtr->hWndHScroll != (HWND)NULL && lphl->ItemsPerColumn != 0) + SetScrollRange(hwnd, SB_HORZ, 1, lphl->ItemsVisible / + lphl->ItemsPerColumn + 1, TRUE); + if (lphl->ItemsCount < lphl->ItemsVisible) { + if (wndPtr->hWndVScroll != (HWND)NULL) + ShowScrollBar(hwnd, SB_VERT, FALSE); + if (wndPtr->hWndHScroll != (HWND)NULL) + ShowScrollBar(hwnd, SB_HORZ, FALSE); + } if ((lphl->FirstVisible <= uIndex) && ((lphl->FirstVisible + lphl->ItemsVisible) >= uIndex)) { InvalidateRect(hwnd, NULL, TRUE); @@ -735,13 +878,12 @@ int ListBoxFindString(HWND hwnd, UINT nFirst, LPSTR MatchStr) UINT Count; lphl = ListBoxGetStorageHeader(hwnd); if (lphl == NULL) return LB_ERR; - if (nFirst < 1 || nFirst > lphl->ItemsCount) return LB_ERR; + if (nFirst > lphl->ItemsCount) return LB_ERR; lpls = lphl->lpFirst; if (lpls == NULL) return LB_ERR; - Count = 1; + Count = 0; while(lpls != NULL) { - if (strcmp((char *)lpls->dis.itemData, MatchStr) == 0) - return Count; + if (strcmp((char *)lpls->dis.itemData, MatchStr) == 0) return Count; lpls = (LPLISTSTRUCT)lpls->lpNext; Count++; } @@ -774,14 +916,21 @@ int ListBoxResetContent(HWND hwnd) lphl->lpFirst = NULL; lphl->FirstVisible = 1; lphl->ItemsCount = 0; - lphl->ItemSelected = 0; - lphl->PrevSelected = 0; + lphl->ItemFocused = 0; + lphl->PrevFocused = 0; if ((wndPtr->dwStyle && LBS_NOTIFY) != 0) SendMessage(wndPtr->hwndParent, WM_COMMAND, wndPtr->wIDmenu, MAKELONG(hwnd, LBN_SELCHANGE)); - SetScrollRange(lphl->hWndScroll, WM_VSCROLL, 1, lphl->ItemsCount, TRUE); - ShowWindow(lphl->hWndScroll, SW_HIDE); + if (wndPtr->hWndVScroll != (HWND)NULL) + SetScrollRange(hwnd, SB_VERT, 1, lphl->ItemsCount, TRUE); + if (wndPtr->hWndHScroll != (HWND)NULL && lphl->ItemsPerColumn != 0) + SetScrollRange(hwnd, SB_HORZ, 1, lphl->ItemsVisible / + lphl->ItemsPerColumn + 1, TRUE); + if (wndPtr->hWndVScroll != (HWND)NULL) + ShowScrollBar(hwnd, SB_VERT, FALSE); + if (wndPtr->hWndHScroll != (HWND)NULL) + ShowScrollBar(hwnd, SB_HORZ, FALSE); InvalidateRect(hwnd, NULL, TRUE); UpdateWindow(hwnd); return TRUE; @@ -796,8 +945,8 @@ int ListBoxSetCurSel(HWND hwnd, WORD wIndex) UINT i; lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr); if (lphl == NULL) return LB_ERR; - lphl->ItemSelected = LB_ERR; - if (wIndex < 0 || wIndex >= lphl->ItemsCount) return LB_ERR; + lphl->ItemFocused = LB_ERR; + if (wIndex >= lphl->ItemsCount) return LB_ERR; lpls = lphl->lpFirst; if (lpls == NULL) return LB_ERR; for(i = 0; i < lphl->ItemsCount; i++) { @@ -810,7 +959,7 @@ int ListBoxSetCurSel(HWND hwnd, WORD wIndex) lpls2->dis.itemState = 0; if (lpls == NULL) break; } - lphl->ItemSelected = wIndex; + lphl->ItemFocused = wIndex; if ((wndPtr->dwStyle && LBS_NOTIFY) != 0) SendMessage(wndPtr->hwndParent, WM_COMMAND, wndPtr->wIDmenu, MAKELONG(hwnd, LBN_SELCHANGE)); @@ -819,22 +968,44 @@ int ListBoxSetCurSel(HWND hwnd, WORD wIndex) -int ListBoxSetSel(HWND hwnd, WORD wIndex) +int ListBoxSetSel(HWND hwnd, WORD wIndex, WORD state) { LPHEADLIST lphl; LPLISTSTRUCT lpls, lpls2; UINT i; lphl = ListBoxGetStorageHeader(hwnd); if (lphl == NULL) return LB_ERR; - if (wIndex < 0 || wIndex >= lphl->ItemsCount) return LB_ERR; + if (wIndex >= lphl->ItemsCount) return LB_ERR; + lpls = lphl->lpFirst; + if (lpls == NULL) return LB_ERR; + for(i = 0; i < lphl->ItemsCount; i++) { + lpls2 = lpls; + lpls = (LPLISTSTRUCT)lpls->lpNext; + if ((i == wIndex) || (wIndex == (WORD)-1)) { + lpls2->dis.itemState = state; + break; + } + if (lpls == NULL) break; + } + return LB_ERR; +} + + +int ListBoxGetSel(HWND hwnd, WORD wIndex) +{ + LPHEADLIST lphl; + LPLISTSTRUCT lpls, lpls2; + UINT i; + lphl = ListBoxGetStorageHeader(hwnd); + if (lphl == NULL) return LB_ERR; + if (wIndex >= lphl->ItemsCount) return LB_ERR; lpls = lphl->lpFirst; if (lpls == NULL) return LB_ERR; for(i = 0; i < lphl->ItemsCount; i++) { lpls2 = lpls; lpls = (LPLISTSTRUCT)lpls->lpNext; if (i == wIndex) { - lpls2->dis.itemState = 1; - break; + return lpls2->dis.itemState; } if (lpls == NULL) break; } @@ -844,28 +1015,56 @@ int ListBoxSetSel(HWND hwnd, WORD wIndex) int ListBoxDirectory(HWND hwnd, UINT attrib, LPSTR filespec) { -DIR *dirp; -struct dirent *dp; -struct stat st; -char str[128]; -int wRet; -dirp = opendir("."); -while ( (dp = readdir(dirp)) != NULL) - { - stat(dp->d_name, &st); -#ifdef DEBUG_LBDIR - printf("LB_DIR : st_mode=%lX / d_name='%s'\n", st.st_mode, dp->d_name); -#endif - if S_ISDIR(st.st_mode) { - sprintf(str, "[%s]", dp->d_name); + struct dosdirent *dp; + struct stat st; + int x, wRet; + char temp[256]; + + fprintf(stderr,"ListBoxDirectory: %s, %4x\n",filespec,attrib); + + + if ((dp = (struct dosdirent *)DOS_opendir(filespec)) ==NULL) + return 0; + + while (1) + { + dp = (struct dosdirent *)DOS_readdir(dp); + if (!dp->inuse) + break; + + if (dp->attribute & 0x08) + { + if (attrib & DDL_DIRECTORY) { + sprintf(temp, "[%s]", dp->filename); + if ( (wRet = ListBoxAddString(hwnd, temp)) == LB_ERR) + break; + } + } else + if (attrib & DDL_EXCLUSIVE) { + if (attrib & (DDL_READWRITE | DDL_READONLY | DDL_HIDDEN | DDL_SYSTEM) ) + if ( (wRet = ListBoxAddString(hwnd, dp->filename)) == LB_ERR) + break; + } else { + if ( (wRet = ListBoxAddString(hwnd, dp->filename)) == LB_ERR) + break; + } } - else - strcpy(str, dp->d_name); - wRet = ListBoxAddString(hwnd, str); - if (wRet == LB_ERR) break; - } -closedir(dirp); -return wRet; + DOS_closedir(dp); + + if (attrib & DDL_DRIVES) + { + for (x=0;x!=MAX_DOS_DRIVES;x++) + { + if (DOS_ValidDrive(x)) + { + sprintf(temp, "[-%c-]", 'A'+x); + if ( (wRet = ListBoxAddString(hwnd, temp)) == LB_ERR) + break; + } + } + } + + return wRet; } @@ -876,10 +1075,10 @@ int ListBoxGetItemRect(HWND hwnd, WORD wIndex, LPRECT lprect) UINT i; lphl = ListBoxGetStorageHeader(hwnd); if (lphl == NULL) return LB_ERR; - if (wIndex < 1 || wIndex > lphl->ItemsCount) return LB_ERR; + if (wIndex > lphl->ItemsCount) return LB_ERR; lpls = lphl->lpFirst; if (lpls == NULL) return LB_ERR; - for(i = 0; i <= lphl->ItemsCount; i++) { + for(i = 0; i < lphl->ItemsCount; i++) { lpls2 = lpls; lpls = (LPLISTSTRUCT)lpls->lpNext; if (i == wIndex) { @@ -900,14 +1099,16 @@ int ListBoxSetItemHeight(HWND hwnd, WORD wIndex, long height) UINT i; lphl = ListBoxGetStorageHeader(hwnd); if (lphl == NULL) return LB_ERR; - if (wIndex < 1 || wIndex > lphl->ItemsCount) return LB_ERR; + if (wIndex > lphl->ItemsCount) return LB_ERR; lpls = lphl->lpFirst; if (lpls == NULL) return LB_ERR; - for(i = 0; i <= lphl->ItemsCount; i++) { + for(i = 0; i < lphl->ItemsCount; i++) { lpls2 = lpls; lpls = (LPLISTSTRUCT)lpls->lpNext; if (i == wIndex) { lpls2->dis.rcItem.bottom = lpls2->dis.rcItem.top + (short)height; + InvalidateRect(hwnd, NULL, TRUE); + UpdateWindow(hwnd); break; } if (lpls == NULL) break; @@ -954,14 +1155,19 @@ int ListBoxFindNextMatch(HWND hwnd, WORD wChar) return LB_ERR; } } - Count = 1; + Count = 0; while(lpls != NULL) { - if (Count > lphl->ItemSelected) { + if (Count > lphl->ItemFocused) { if (*((char *)lpls->dis.itemData) == (char)wChar) { lphl->FirstVisible = Count - lphl->ItemsVisible / 2; if (lphl->FirstVisible < 1) lphl->FirstVisible = 1; - ListBoxSetCurSel(hwnd, Count); - SetScrollPos(lphl->hWndScroll, WM_VSCROLL, lphl->FirstVisible, TRUE); + if ((wndPtr->dwStyle & LBS_MULTIPLESEL) == LBS_MULTIPLESEL) { + lphl->ItemFocused = Count; + } + else { + ListBoxSetCurSel(hwnd, Count); + } + SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE); InvalidateRect(hwnd, NULL, TRUE); UpdateWindow(hwnd); return Count; @@ -970,15 +1176,20 @@ int ListBoxFindNextMatch(HWND hwnd, WORD wChar) lpls = (LPLISTSTRUCT)lpls->lpNext; Count++; } - Count = 1; + Count = 0; lpls = lphl->lpFirst; while(lpls != NULL) { if (*((char *)lpls->dis.itemData) == (char)wChar) { - if (Count == lphl->ItemSelected) return LB_ERR; + if (Count == lphl->ItemFocused) return LB_ERR; lphl->FirstVisible = Count - lphl->ItemsVisible / 2; if (lphl->FirstVisible < 1) lphl->FirstVisible = 1; - ListBoxSetCurSel(hwnd, Count); - SetScrollPos(lphl->hWndScroll, WM_VSCROLL, lphl->FirstVisible, TRUE); + if ((wndPtr->dwStyle & LBS_MULTIPLESEL) == LBS_MULTIPLESEL) { + lphl->ItemFocused = Count; + } + else { + ListBoxSetCurSel(hwnd, Count); + } + SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE); InvalidateRect(hwnd, NULL, TRUE); UpdateWindow(hwnd); return Count; diff --git a/controls/menu.c b/controls/menu.c index 2d22115fa0d..c1cd758484d 100644 --- a/controls/menu.c +++ b/controls/menu.c @@ -1,6 +1,8 @@ static char RCSId[] = "$Id$"; static char Copyright[] = "Copyright Robert J. Amstadt, 1993"; +#define DEBUG_MENU + #include #include #include @@ -22,7 +24,306 @@ static int lastLevel; static int menuId = 0; static Pixmap checkBitmap = XtUnspecifiedPixmap; static Pixmap nocheckBitmap = XtUnspecifiedPixmap; - + +LPPOPUPMENU PopupMenuGetStorageHeader(HWND hwnd); +LPPOPUPMENU PopupMenuGetWindowAndStorage(HWND hwnd, WND **wndPtr); +void StdDrawPopupMenu(HWND hwnd); +LPMENUITEM PopupMenuFindItem(HWND hwnd, int x, int y, WORD *lpRet); +LPMENUITEM GetMenuItemPtr(LPPOPUPMENU menu, WORD nPos); + +/*********************************************************************** + * PopupMenuWndProc + */ +LONG PopupMenuWndProc( HWND hwnd, WORD message, WORD wParam, LONG lParam ) +{ + CREATESTRUCT *createStruct; + WORD wRet; + short x, y; + WND *wndPtr; + LPPOPUPMENU lppop; + LPMENUITEM lpitem, lpitem2; + HMENU hSubMenu; + RECT rect; + HDC hDC; + switch(message) + { + case WM_CREATE: +#ifdef DEBUG_MENU + printf("PopupMenu WM_CREATE lParam=%08X !\n", lParam); +#endif + createStruct = (CREATESTRUCT *)lParam; + lppop = (LPPOPUPMENU)createStruct->lpCreateParams; + if (lppop == 0) break; + wndPtr = WIN_FindWndPtr(hwnd); + *((LPPOPUPMENU *)&wndPtr->wExtra[1]) = lppop; +#ifdef DEBUG_MENU + printf("PopupMenu WM_CREATE lppop=%08X !\n", lppop); +#endif + return 0; + case WM_DESTROY: + lppop = PopupMenuGetWindowAndStorage(hwnd, &wndPtr); +#ifdef DEBUG_MENU + printf("PopupMenu WM_DESTROY %lX !\n", lppop); +#endif + return 0; + + case WM_LBUTTONDOWN: + lppop = PopupMenuGetWindowAndStorage(hwnd, &wndPtr); + SetCapture(hwnd); + lpitem = PopupMenuFindItem(hwnd, LOWORD(lParam), HIWORD(lParam), &wRet); + printf("PopupMenu WM_LBUTTONDOWN wRet=%d lpitem=%08X !\n", wRet, lpitem); + if (lpitem != NULL) { + lppop->FocusedItem = wRet; + if (((lpitem->item_flags & MF_SEPARATOR) != MF_SEPARATOR) && + ((lpitem->item_flags & MF_MENUBREAK) != MF_MENUBREAK)) { + hDC = GetDC(hwnd); + InvertRect(hDC, &lpitem->rect); + ReleaseDC(hwnd, hDC); + } + } + break; + case WM_LBUTTONUP: + lppop = PopupMenuGetStorageHeader(hwnd); + ReleaseCapture(); + lpitem = PopupMenuFindItem(hwnd, LOWORD(lParam), HIWORD(lParam), &wRet); + printf("PopupMenu WM_LBUTTONUP wRet=%d lpitem=%08X !\n", wRet, lpitem); + if (lpitem != NULL) { + if (lppop->FocusedItem != (WORD)-1) { + lpitem2 = GetMenuItemPtr(lppop, lppop->FocusedItem); + if (((lpitem2->item_flags & MF_SEPARATOR) != MF_SEPARATOR) && + ((lpitem2->item_flags & MF_MENUBREAK) != MF_MENUBREAK)) { + hDC = GetDC(hwnd); + InvertRect(hDC, &lpitem2->rect); + ReleaseDC(hwnd, hDC); + } + } + if ((lpitem->item_flags & MF_POPUP) == MF_POPUP) { + hSubMenu = (HMENU)lpitem->item_id; + printf("ShowSubmenu hSubMenu=%04X !\n", hSubMenu); + GetClientRect(hwnd, &rect); + x = rect.right; + GetWindowRect(hwnd, &rect); + x += rect.left; + TrackPopupMenu(hSubMenu, TPM_LEFTBUTTON, + x, rect.top + HIWORD(lParam), + 0, lppop->ownerWnd, (LPRECT)NULL); + break; + } + if (((lpitem->item_flags & MF_SEPARATOR) != MF_SEPARATOR) && + ((lpitem->item_flags & MF_POPUP) != MF_POPUP)) { + SendMessage(lppop->ownerWnd, WM_COMMAND, lpitem->item_id, 0L); + printf("PopupMenu // SendMessage WM_COMMAND wParam=%d !\n", + lpitem->item_id); + ShowWindow(lppop->hWnd, SW_HIDE); + break; + } + } + break; + case WM_MOUSEMOVE: + if ((wParam & MK_LBUTTON) != 0) { + lppop = PopupMenuGetStorageHeader(hwnd); + lpitem = PopupMenuFindItem(hwnd, LOWORD(lParam), HIWORD(lParam), &wRet); + if ((lpitem != NULL) && (lppop->FocusedItem != wRet)) { + lpitem2 = GetMenuItemPtr(lppop, lppop->FocusedItem); + hDC = GetDC(hwnd); + if (((lpitem2->item_flags & MF_POPUP) == MF_POPUP) || + ((lpitem2->item_flags & MF_STRING) == MF_STRING)) { + InvertRect(hDC, &lpitem2->rect); + } + lppop->FocusedItem = wRet; + printf("PopupMenu WM_MOUSEMOVE wRet=%d lpitem=%08X !\n", wRet, lpitem); + InvertRect(hDC, &lpitem->rect); + ReleaseDC(hwnd, hDC); + } + } + break; + + case WM_KEYDOWN: + case WM_KEYUP: + case WM_CHAR: + lppop = PopupMenuGetWindowAndStorage(hwnd, &wndPtr); + return(SendMessage(wndPtr->hwndParent, message, wParam, lParam)); + + case WM_PAINT: + printf("PopupMenu WM_PAINT !\n"); + StdDrawPopupMenu(hwnd); + break; + default: + return DefWindowProc( hwnd, message, wParam, lParam ); + } +return(0); +} + + + +LPPOPUPMENU PopupMenuGetWindowAndStorage(HWND hwnd, WND **wndPtr) +{ + WND *Ptr; + LPPOPUPMENU lppop; + *(wndPtr) = Ptr = WIN_FindWndPtr(hwnd); + if (Ptr == 0) { + printf("Bad Window handle on PopupMenu !\n"); + return 0; + } + lppop = *((LPPOPUPMENU *)&Ptr->wExtra[1]); + return lppop; +} + + +LPPOPUPMENU PopupMenuGetStorageHeader(HWND hwnd) +{ + WND *Ptr; + LPPOPUPMENU lppop; + Ptr = WIN_FindWndPtr(hwnd); + if (Ptr == 0) { + printf("Bad Window handle on PopupMenu !\n"); + return 0; + } + lppop = *((LPPOPUPMENU *)&Ptr->wExtra[1]); + return lppop; +} + + +void StdDrawPopupMenu(HWND hwnd) +{ + WND *wndPtr; + LPPOPUPMENU lppop; + LPMENUITEM lpitem; + PAINTSTRUCT ps; + HBRUSH hBrush; + HPEN hOldPen; + HWND hWndParent; + HDC hDC, hMemDC; + RECT rect, rect2, rect3; + HBITMAP hBitMap; + BITMAP bm; + UINT i; + hDC = BeginPaint( hwnd, &ps ); + if (!IsWindowVisible(hwnd)) { + EndPaint( hwnd, &ps ); + return; + } + lppop = PopupMenuGetWindowAndStorage(hwnd, &wndPtr); + if (lppop == NULL) goto EndOfPaint; + hBrush = SendMessage(lppop->ownerWnd, WM_CTLCOLOR, (WORD)hDC, + MAKELONG(hwnd, CTLCOLOR_LISTBOX)); + if (hBrush == (HBRUSH)NULL) hBrush = GetStockObject(WHITE_BRUSH); + GetClientRect(hwnd, &rect); + GetClientRect(hwnd, &rect2); + FillRect(hDC, &rect, hBrush); + if (lppop->nItems == 0) goto EndOfPaint; + lpitem = lppop->firstItem->next; + if (lpitem == NULL) goto EndOfPaint; + for(i = 0; i < lppop->nItems; i++) { + if ((lpitem->item_flags & MF_SEPARATOR) == MF_SEPARATOR) { + rect2.bottom = rect2.top + 3; + CopyRect(&lpitem->rect, &rect2); + hOldPen = SelectObject(hDC, GetStockObject(BLACK_PEN)); + MoveTo(hDC, rect2.left, rect2.top + 1); + LineTo(hDC, rect2.right, rect2.top + 1); + SelectObject(hDC, hOldPen); + rect2.top += 3; + } + if ((lpitem->item_flags & MF_BITMAP) == MF_BITMAP) { + hBitMap = (HBITMAP)LOWORD(lpitem->item_text); + rect2.bottom = rect2.top + bm.bmHeight; + CopyRect(&lpitem->rect, &rect2); + hMemDC = CreateCompatibleDC(hDC); + SelectObject(hMemDC, hBitMap); + GetObject(hBitMap, sizeof(BITMAP), (LPSTR)&bm); + BitBlt(hDC, rect2.left, rect2.top, + bm.bmWidth, bm.bmHeight, hMemDC, 0, 0, SRCCOPY); + DeleteDC(hMemDC); + rect2.top += bm.bmHeight; + } + if (((lpitem->item_flags & MF_BITMAP) != MF_BITMAP) && + ((lpitem->item_flags & MF_SEPARATOR) != MF_SEPARATOR) && + ((lpitem->item_flags & MF_MENUBREAK) != MF_MENUBREAK)) { + rect2.bottom = rect2.top + 15; + CopyRect(&lpitem->rect, &rect2); + TextOut(hDC, rect2.left + 5, rect2.top + 2, + (char *)lpitem->item_text, strlen((char *)lpitem->item_text)); + rect2.top += 15; + } + if ((lpitem->item_flags & MF_CHECKED) == MF_CHECKED) { + CopyRect(&rect3, &rect2); + rect3.left = rect3.right - rect3.bottom + rect3.top; + InvertRect(hDC, &rect3); + } + if ((lpitem->item_flags & MF_POPUP) == MF_POPUP) { + CopyRect(&rect3, &rect2); + rect3.left = rect3.right - rect3.bottom + rect3.top; + FillRect(hDC, &rect3, GetStockObject(BLACK_BRUSH)); + } + if (lpitem->next == NULL) goto EndOfPaint; + lpitem = (LPMENUITEM)lpitem->next; + } +EndOfPaint: + EndPaint( hwnd, &ps ); +} + + + +LPMENUITEM PopupMenuFindItem(HWND hwnd, int x, int y, WORD *lpRet) +{ + WND *wndPtr; + LPPOPUPMENU lppop; + LPMENUITEM lpitem; + RECT rect, rect2; + HBITMAP hBitMap; + BITMAP bm; + UINT i; + lppop = PopupMenuGetWindowAndStorage(hwnd, &wndPtr); + if (lppop == NULL) return NULL; + GetClientRect(hwnd, &rect); + if (lppop->nItems == 0) return NULL; + lpitem = lppop->firstItem->next; + if (lpitem == NULL) return NULL; + for(i = 0; i < lppop->nItems; i++) { + if (y < rect2.top) return NULL; + if ((lpitem->item_flags & MF_SEPARATOR) == MF_SEPARATOR) { + rect2.bottom = rect2.top + 3; + rect2.top += 3; + } + if ((lpitem->item_flags & MF_BITMAP) == MF_BITMAP) { + hBitMap = (HBITMAP)LOWORD(lpitem->item_text); + GetObject(hBitMap, sizeof(BITMAP), (LPSTR)&bm); + rect2.bottom = rect2.top + bm.bmHeight; + rect2.top += bm.bmHeight; + } + if (((lpitem->item_flags & MF_BITMAP) != MF_BITMAP) && + ((lpitem->item_flags & MF_SEPARATOR) != MF_SEPARATOR) && + ((lpitem->item_flags & MF_MENUBREAK) != MF_MENUBREAK)) { + rect2.bottom = rect2.top + 15; + rect2.top += 15; + } + if (y < rect2.bottom) { + if (lpRet != NULL) *lpRet = i; + return lpitem; + } + if (lpitem->next == NULL) return NULL; + lpitem = (LPMENUITEM)lpitem->next; + } + return NULL; +} + + + +LPMENUITEM GetMenuItemPtr(LPPOPUPMENU menu, WORD nPos) +{ + LPMENUITEM lpitem; + int i; + if (menu == NULL) return NULL; + lpitem = menu->firstItem; + for (i = 0; i < menu->nItems; i++) { + if (lpitem->next == NULL) return NULL; + lpitem = (LPMENUITEM)lpitem->next; + if (i == nPos) return(lpitem); + } + return NULL; +} + + /********************************************************************** * MENU_CheckWidget */ @@ -565,3 +866,316 @@ LoadMenu(HINSTANCE instance, char *menu_name) return GlobalHandleFromPointer(menu->firstItem); } + + +/********************************************************************** + * CheckMenuItem [USER.154] + */ +BOOL CheckMenuItem(HMENU hMenu, WORD wItemID, WORD wFlags) +{ +} + + +/********************************************************************** + * EnableMenuItem [USER.155] + */ +BOOL EnableMenuItem(HMENU hMenu, WORD wItemID, WORD wFlags) +{ +} + + +/********************************************************************** + * InsertMenu [USER.410] + */ +BOOL InsertMenu(HMENU hMenu, WORD nPos, WORD wFlags, WORD wItemID, LPSTR lpNewItem) +{ + WND *wndPtr; + LPPOPUPMENU menu; + HANDLE hNewItem; + LPMENUITEM lpitem, lpitem2; + int i; +#ifdef DEBUG_MENU + printf("InsertMenu (%04X, %04X, %04X, %04X, %08X) !\n", + hMenu, nPos, wFlags, wItemID, lpNewItem); +#endif + menu = (LPPOPUPMENU) GlobalLock(hMenu); + if (menu == NULL) return FALSE; + lpitem = menu->firstItem; + for (i = 0; i < menu->nItems; i++) { + if (lpitem->next == NULL) break; + lpitem = (LPMENUITEM)lpitem->next; + printf("InsertMenu // during loop items !\n"); + } + printf("InsertMenu // after loop items !\n"); + hNewItem = GlobalAlloc(GMEM_MOVEABLE, sizeof(MENUITEM)); + if (hNewItem == 0) return FALSE; + lpitem2 = (LPMENUITEM)GlobalLock(hNewItem); + if (lpitem2 == 0) { + GlobalFree(hNewItem); + return FALSE; + } + lpitem2->item_flags = wFlags; + lpitem2->item_id = wItemID; + if ((wFlags & MF_STRING) == MF_STRING) { + lpitem2->item_text = lpNewItem; + } + else + lpitem2->item_text = lpNewItem; + lpitem2->prev = lpitem; + if (lpitem->next != NULL) + lpitem2->next = lpitem->next; + else + lpitem2->next = NULL; + lpitem->next = lpitem2; + lpitem2->child = NULL; + lpitem2->parent = NULL; + lpitem2->w = NULL; + lpitem2->menu_w = NULL; + menu->nItems++; + return TRUE; +} + + +/********************************************************************** + * AppendMenu [USER.411] + */ +BOOL AppendMenu(HMENU hMenu, WORD wFlags, WORD wItemID, LPSTR lpNewItem) +{ + WND *wndPtr; + LPPOPUPMENU menu; + HANDLE hNewItem; + LPMENUITEM lpitem, lpitem2; +#ifdef DEBUG_MENU + printf("AppendMenu (%04X, %04X, %04X, %08X) !\n", + hMenu, wFlags, wItemID, lpNewItem); +#endif + menu = (LPPOPUPMENU) GlobalLock(hMenu); + if (menu == NULL) return FALSE; + lpitem = menu->firstItem; + while (lpitem->next != NULL) { + lpitem = (LPMENUITEM)lpitem->next; + printf("AppendMenu // during loop items !\n"); + } + printf("AppendMenu // after loop items !\n"); + hNewItem = GlobalAlloc(GMEM_MOVEABLE, sizeof(MENUITEM)); + if (hNewItem == 0) return FALSE; + lpitem2 = (LPMENUITEM)GlobalLock(hNewItem); + if (lpitem2 == 0) { + GlobalFree(hNewItem); + return FALSE; + } + lpitem2->item_flags = wFlags; + lpitem2->item_id = wItemID; + if ((wFlags & MF_STRING) == MF_STRING) { + lpitem2->item_text = lpNewItem; + } + else + lpitem2->item_text = lpNewItem; + lpitem->next = lpitem2; + lpitem2->prev = lpitem; + lpitem2->next = NULL; + lpitem2->child = NULL; + lpitem2->parent = NULL; + lpitem2->w = NULL; + lpitem2->menu_w = NULL; + menu->nItems++; + return TRUE; +} + + +/********************************************************************** + * RemoveMenu [USER.412] + */ +BOOL RemoveMenu(HMENU hMenu, WORD nPos, WORD wFlags) +{ + WND *wndPtr; + LPPOPUPMENU menu; + LPMENUITEM lpitem; + int i; +#ifdef DEBUG_MENU + printf("RemoveMenu (%04X, %04X, %04X) !\n", hMenu, nPos, wFlags); +#endif + menu = (LPPOPUPMENU) GlobalLock(hMenu); + if (menu == NULL) return FALSE; + lpitem = menu->firstItem; + for (i = 0; i < menu->nItems; i++) { + if (lpitem->next == NULL) break; + lpitem = (LPMENUITEM)lpitem->next; + if (i == nPos) { + lpitem->prev->next = lpitem->next; + lpitem->next->prev = lpitem->prev; + GlobalFree(HIWORD(lpitem)); + return(TRUE); + } + printf("RemoveMenu // during loop items !\n"); + } + printf("RemoveMenu // after loop items !\n"); + return FALSE; +} + + +/********************************************************************** + * DeleteMenu [USER.413] + */ +BOOL DeleteMenu(HMENU hMenu, WORD nPos, WORD wFlags) +{ +#ifdef DEBUG_MENU + printf("DeleteMenu (%04X, %04X, %04X) !\n", hMenu, nPos, wFlags); +#endif + return TRUE; +} + + +/********************************************************************** + * ModifyMenu [USER.414] + */ +BOOL ModifyMenu(HMENU hMenu, WORD nPos, WORD wFlags, WORD wItemID, LPSTR lpNewItem) +{ +#ifdef DEBUG_MENU + printf("ModifyMenu (%04X, %04X, %04X, %04X, %08X) !\n", + hMenu, nPos, wFlags, wItemID, lpNewItem); +#endif + return TRUE; +} + + +/********************************************************************** + * CreatePopupMenu [USER.415] + */ +HMENU CreatePopupMenu() +{ + HANDLE hItem; + HMENU hMenu; + LPPOPUPMENU menu; +#ifdef DEBUG_MENU + printf("CreatePopupMenu !\n"); +#endif + hMenu = GlobalAlloc(GMEM_MOVEABLE, sizeof(POPUPMENU)); + menu = (LPPOPUPMENU) GlobalLock(hMenu); + if (menu == NULL) { + GlobalFree(hMenu); + return 0; + } + hItem = GlobalAlloc(GMEM_MOVEABLE, sizeof(MENUITEM)); + if (hItem == 0) { + GlobalFree(hMenu); + return 0; + } + menu->nItems = 0; + menu->firstItem = (LPMENUITEM)GlobalLock(hItem); + menu->ownerWnd = 0; + menu->hWnd = 0; + + menu->firstItem->next = NULL; + menu->firstItem->prev = NULL; + menu->firstItem->child = NULL; + menu->firstItem->parent = NULL; + menu->firstItem->item_flags = 0; + menu->firstItem->item_id = 0; + menu->firstItem->item_text = NULL; + menu->firstItem->w = NULL; + menu->firstItem->menu_w = NULL; + return hMenu; +} + + +/********************************************************************** + * TrackPopupMenu [USER.414] + */ +BOOL TrackPopupMenu(HMENU hMenu, WORD wFlags, short x, short y, + short nReserved, HWND hWnd, LPRECT lpRect) +{ + WND *wndPtr; + LPPOPUPMENU menu; +#ifdef DEBUG_MENU + printf("TrackPopupMenu (%04X, %04X, %d, %d, %04X, %04X, %08X) !\n", + hMenu, wFlags, x, y, nReserved, hWnd, lpRect); +#endif + menu = (LPPOPUPMENU) GlobalLock(hMenu); + if (menu == NULL) return FALSE; + wndPtr = WIN_FindWndPtr(hWnd); + menu->ownerWnd = hWnd; + if (menu->hWnd == NULL) { + menu->hWnd = CreateWindow("POPUPMENU", "", WS_CHILD | WS_VISIBLE, + x, y, 100, 150, hWnd, 0, wndPtr->hInstance, (LPSTR)menu); + } + else + ShowWindow(menu->hWnd, SW_SHOW); + return TRUE; +} + + +/********************************************************************** + * CreateMenu [USER.151] + */ +HMENU CreateMenu() +{ + HANDLE hItem; + HMENU hMenu; + LPMENUBAR menu; +#ifdef DEBUG_MENU + printf("CreateMenu !\n"); +#endif + hMenu = GlobalAlloc(GMEM_MOVEABLE, sizeof(MENUBAR)); + menu = (LPMENUBAR) GlobalLock(hMenu); + if (menu == NULL) { + GlobalFree(hMenu); + return 0; + } + hItem = GlobalAlloc(GMEM_MOVEABLE, sizeof(MENUITEM)); + if (hItem == 0) { + GlobalFree(hMenu); + return 0; + } + menu->menuDescription = 0; + menu->nItems = 0; + menu->parentWidget = NULL; + menu->firstItem = (LPMENUITEM) GlobalLock(hItem); + menu->ownerWnd = 0; + menu->menuBarWidget = NULL; + + menu->firstItem->next = NULL; + menu->firstItem->prev = NULL; + menu->firstItem->child = NULL; + menu->firstItem->parent = NULL; + menu->firstItem->item_flags = 0; + menu->firstItem->item_id = 0; + menu->firstItem->item_text = NULL; + menu->firstItem->w = NULL; + menu->firstItem->menu_w = NULL; + return hMenu; +} + + +/********************************************************************** + * DestroyMenu [USER.152] + */ +BOOL DestroyMenu(HMENU hMenu) +{ + LPPOPUPMENU lppop; + LPMENUITEM lpitem, lpitem2; +#ifdef DEBUG_MENU + printf("DestroyMenu (%04X) !\n", hMenu); +#endif + if (hMenu == 0) return FALSE; + lppop = (LPPOPUPMENU) GlobalLock(hMenu); + if (lppop == NULL) return FALSE; + if (lppop->hWnd) DestroyWindow (lppop->hWnd); + lpitem = lppop->firstItem; + while (lpitem->next != NULL) { +#ifdef DEBUG_MENU + printf("DestroyMenu (%04X) // during loop items !\n", hMenu); +#endif + if ((lpitem->item_flags & MF_POPUP) == MF_POPUP) { + DestroyMenu((HMENU)lpitem->item_id); + } + lpitem = (LPMENUITEM)lpitem->next; + } + GlobalFree(hMenu); +#ifdef DEBUG_MENU + printf("DestroyMenu (%04X) // End !\n", hMenu); +#endif + return TRUE; +} + + diff --git a/controls/scroll.c b/controls/scroll.c index fd8e45a24ee..9cfa55010d1 100644 --- a/controls/scroll.c +++ b/controls/scroll.c @@ -17,7 +17,8 @@ static char Copyright[] = "Copyright Martin Ayotte, 1993"; #include "scroll.h" #include "heap.h" #include "win.h" -#include "dirent.h" +#include +#include #include LPHEADSCROLL ScrollBarGetWindowAndStorage(HWND hwnd, WND **wndPtr); @@ -26,50 +27,10 @@ void StdDrawScrollBar(HWND hwnd); int CreateScrollBarStruct(HWND hwnd); -void SCROLLBAR_CreateScrollBar(LPSTR className, LPSTR scrollLabel, HWND hwnd) -{ - WND *wndPtr = WIN_FindWndPtr(hwnd); - WND *parentPtr = WIN_FindWndPtr(wndPtr->hwndParent); - DWORD style; - char widgetName[15]; - -#ifdef DEBUG_SCROLLBAR - printf("scroll: label = %s, x = %d, y = %d\n", scrollLabel, - wndPtr->rectClient.left, wndPtr->rectClient.top); - printf(" width = %d, height = %d\n", - wndPtr->rectClient.right - wndPtr->rectClient.left, - wndPtr->rectClient.bottom - wndPtr->rectClient.top); -#endif - - if (!wndPtr) - return; - - style = wndPtr->dwStyle & 0x0000FFFF; -/* - if ((style & SBS_NOTIFY) == SBS_NOTIFY) -*/ - sprintf(widgetName, "%s%d", className, wndPtr->wIDmenu); - wndPtr->winWidget = XtVaCreateManagedWidget(widgetName, - compositeWidgetClass, - parentPtr->winWidget, - XtNx, wndPtr->rectClient.left, - XtNy, wndPtr->rectClient.top, - XtNwidth, wndPtr->rectClient.right - - wndPtr->rectClient.left, - XtNheight, wndPtr->rectClient.bottom - - wndPtr->rectClient.top, - NULL ); - GlobalUnlock(hwnd); - GlobalUnlock(wndPtr->hwndParent); -} - - - /*********************************************************************** * WIDGETS_ScrollBarWndProc */ -LONG SCROLLBAR_ScrollBarWndProc( HWND hwnd, WORD message, - WORD wParam, LONG lParam ) +LONG ScrollBarWndProc( HWND hwnd, WORD message, WORD wParam, LONG lParam ) { WORD wRet; short x, y; @@ -169,8 +130,11 @@ LONG SCROLLBAR_ScrollBarWndProc( HWND hwnd, WORD message, break; case WM_KEYDOWN: - printf("ScrollBar WM_KEYDOWN wParam %X !\n", wParam); - break; + case WM_KEYUP: + case WM_CHAR: + lphs = ScrollBarGetWindowAndStorage(hwnd, &wndPtr); + return(SendMessage(wndPtr->hwndParent, message, wParam, lParam)); + case WM_PAINT: StdDrawScrollBar(hwnd); break; @@ -330,36 +294,36 @@ int CreateScrollBarStruct(HWND hwnd) wndPtr->hInstance, 0L); } if (lphs->MaxPix < 1) lphs->MaxPix = 1; + if (wndPtr->hCursor == (HCURSOR)NULL) + wndPtr->hCursor = LoadCursor((HINSTANCE)NULL, IDC_ARROW); return TRUE; } - -int GetScrollPos(HWND hwnd, int nBar) +/************************************************************************* + * GetScrollWindowHandle + */ +HWND GetScrollWindowHandle(HWND hWnd, int nBar) { - LPHEADSCROLL lphs; - lphs = ScrollBarGetStorageHeader(hwnd); - if (lphs == NULL) return 0; - return lphs->CurVal; + WND *wndPtr; + if (nBar != SB_CTL) { + wndPtr = WIN_FindWndPtr(hWnd); + if (nBar == SB_VERT) return wndPtr->hWndVScroll; + if (nBar == SB_HORZ) return wndPtr->hWndHScroll; + return (HWND)NULL; + } + return hWnd; } - -void GetScrollRange(HWND hwnd, int nBar, LPINT lpMin, LPINT lpMax) -{ - LPHEADSCROLL lphs; - lphs = ScrollBarGetStorageHeader(hwnd); - if (lphs == NULL) return; - *lpMin = lphs->MinVal; - *lpMax = lphs->MaxVal; -} - - - +/************************************************************************* + * SetScrollPos [USER.62] + */ int SetScrollPos(HWND hwnd, int nBar, int nPos, BOOL bRedraw) { int nRet; LPHEADSCROLL lphs; + hwnd = GetScrollWindowHandle(hwnd, nBar); lphs = ScrollBarGetStorageHeader(hwnd); if (lphs == NULL) return 0; nRet = lphs->CurVal; @@ -383,9 +347,27 @@ int SetScrollPos(HWND hwnd, int nBar, int nPos, BOOL bRedraw) +/************************************************************************* + * GetScrollPos [USER.63] + */ +int GetScrollPos(HWND hwnd, int nBar) +{ + LPHEADSCROLL lphs; + hwnd = GetScrollWindowHandle(hwnd, nBar); + lphs = ScrollBarGetStorageHeader(hwnd); + if (lphs == NULL) return 0; + return lphs->CurVal; +} + + + +/************************************************************************* + * SetScrollRange [USER.64] + */ void SetScrollRange(HWND hwnd, int nBar, int MinPos, int MaxPos, BOOL bRedraw) { LPHEADSCROLL lphs; + hwnd = GetScrollWindowHandle(hwnd, nBar); lphs = ScrollBarGetStorageHeader(hwnd); if (lphs == NULL) return; lphs->MinVal = (short)MinPos; @@ -406,5 +388,50 @@ void SetScrollRange(HWND hwnd, int nBar, int MinPos, int MaxPos, BOOL bRedraw) +/************************************************************************* + * GetScrollRange [USER.65] + */ +void GetScrollRange(HWND hwnd, int nBar, LPINT lpMin, LPINT lpMax) +{ + LPHEADSCROLL lphs; + hwnd = GetScrollWindowHandle(hwnd, nBar); + lphs = ScrollBarGetStorageHeader(hwnd); + if (lphs == NULL) return; + *lpMin = lphs->MinVal; + *lpMax = lphs->MaxVal; +} + + + +/************************************************************************* + * ShowScrollBar [USER.267] + */ +void ShowScrollBar(HWND hWnd, WORD wBar, BOOL bFlag) +{ + WND *wndPtr; +#ifdef DEBUG_SCROLL + printf("ShowScrollBar hWnd=%04X wBar=%d bFlag=%d\n", hWnd, wBar, bFlag); +#endif + if (wBar == SB_CTL) { + if (bFlag) + ShowWindow(hWnd, SW_SHOW); + else + ShowWindow(hWnd, SW_HIDE); + return; + } + wndPtr = WIN_FindWndPtr(hWnd); + if ((wBar == SB_VERT) || (wBar == SB_BOTH)) { + if (bFlag) + ShowWindow(wndPtr->hWndVScroll, SW_SHOW); + else + ShowWindow(wndPtr->hWndVScroll, SW_HIDE); + } + if ((wBar == SB_HORZ) || (wBar == SB_BOTH)) { + if (bFlag) + ShowWindow(wndPtr->hWndHScroll, SW_SHOW); + else + ShowWindow(wndPtr->hWndHScroll, SW_HIDE); + } +} diff --git a/controls/static.c b/controls/static.c index 692813973d8..558110b6659 100644 --- a/controls/static.c +++ b/controls/static.c @@ -109,6 +109,18 @@ LONG StaticWndProc(HWND hWnd, WORD uMsg, WORD wParam, LONG lParam) InvalidateRect(hWnd, NULL, TRUE); break; + case WM_KEYDOWN: + case WM_KEYUP: + case WM_CHAR: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_MOUSEMOVE: + return(SendMessage(wndPtr->hwndParent, uMsg, wParam, lParam)); + default: lResult = DefWindowProc(hWnd, uMsg, wParam, lParam); break; diff --git a/controls/widgets.c b/controls/widgets.c index 673348685a9..c88ac448a07 100644 --- a/controls/widgets.c +++ b/controls/widgets.c @@ -13,23 +13,28 @@ static char Copyright[] = "Copyright Alexandre Julliard, 1993"; LONG ButtonWndProc( HWND hwnd, WORD message, WORD wParam, LONG lParam ); LONG StaticWndProc( HWND hwnd, WORD message, WORD wParam, LONG lParam ); - -LONG SCROLLBAR_ScrollBarWndProc( HWND hwnd, WORD message, - WORD wParam, LONG lParam ); -LONG LISTBOX_ListBoxWndProc( HWND hwnd, WORD message, - WORD wParam, LONG lParam ); -LONG COMBOBOX_ComboBoxWndProc( HWND hwnd, WORD message, - WORD wParam, LONG lParam ); +LONG ScrollBarWndProc( HWND hwnd, WORD message, WORD wParam, LONG lParam ); +LONG ListBoxWndProc ( HWND hwnd, WORD message, WORD wParam, LONG lParam ); +LONG ComboBoxWndProc ( HWND hwnd, WORD message, WORD wParam, LONG lParam ); +LONG PopupMenuWndProc ( HWND hwnd, WORD message, WORD wParam, LONG lParam ); static WNDCLASS WIDGETS_BuiltinClasses[] = { - { 0, (LONG(*)())ButtonWndProc, 0, 2, 0, 0, 0, 0, NULL, "BUTTON" }, - { 0, (LONG(*)())StaticWndProc, 0, 0, 0, 0, 0, 0, NULL, "STATIC" }, - { 0, (LONG(*)())SCROLLBAR_ScrollBarWndProc, 0, 8, 0, 0, 0, 0, NULL, "SCROLLBAR" }, - { 0, (LONG(*)())LISTBOX_ListBoxWndProc, 0, 8, 0, 0, 0, 0, NULL, "LISTBOX" }, - { 0, (LONG(*)())COMBOBOX_ComboBoxWndProc, 0, 8, 0, 0, 0, 0, NULL, "COMBOBOX" }, - { 0, (LONG(*)())DefDlgProc, 0, DLGWINDOWEXTRA, 0, 0, 0, 0, NULL, DIALOG_CLASS_NAME } + { CS_GLOBALCLASS, (LONG(*)())ButtonWndProc, 0, 2, + 0, 0, 0, 0, NULL, "BUTTON" }, + { CS_GLOBALCLASS, (LONG(*)())StaticWndProc, 0, 0, + 0, 0, 0, 0, NULL, "STATIC" }, + { CS_GLOBALCLASS, (LONG(*)())ScrollBarWndProc, 0, 8, + 0, 0, 0, 0, NULL, "SCROLLBAR" }, + { CS_GLOBALCLASS, (LONG(*)())ListBoxWndProc, 0, 8, + 0, 0, 0, 0, NULL, "LISTBOX" }, + { CS_GLOBALCLASS, (LONG(*)())ComboBoxWndProc, 0, 8, + 0, 0, 0, 0, NULL, "COMBOBOX" }, + { CS_GLOBALCLASS, (LONG(*)())PopupMenuWndProc, 0, 8, + 0, 0, 0, 0, NULL, "POPUPMENU" }, + { CS_GLOBALCLASS, (LONG(*)())DefDlgProc, 0, DLGWINDOWEXTRA, + 0, 0, 0, 0, NULL, DIALOG_CLASS_NAME } }; #define NB_BUILTIN_CLASSES \ diff --git a/debugger/Imakefile b/debugger/Imakefile new file mode 100644 index 00000000000..4b4ed0442c9 --- /dev/null +++ b/debugger/Imakefile @@ -0,0 +1,62 @@ +#include "../Wine.tmpl" + +#define IHavSubDirs +#define PassCDebugFlags 'CDEBUGFLAGS=$(CDEBUGFLAGS)' 'CC=$(CC)' + +MODULE = debugger + +DEFINES = -DUSE_READLINE + +SUBDIRS = readline + +/* Quick and dirt hack, since i386 is defined as 1. sigh */ +#define temp i386 +#undef i386 + +SRCS = \ + dbg.tab.c \ + hash.c \ + lex.yy.c \ + info.c \ + i386-pinsn.c + +OBJS = \ + dbg.tab.o \ + hash.o \ + lex.yy.o \ + info.o \ + i386-pinsn.o + +#define i386 temp +#undef temp + +/* + * All the SUBDIR stuff + */ +MakeSubdirs($(SUBDIRS)) +MakefileSubdirs($(SUBDIRS)) +DependSubdirs($(SUBDIRS)) +CleanSubdirs($(SUBDIRS)) +IncludesSubdirs($(SUBDIRS)) + +/* + * The main act + */ +WineRelocatableTarget($(TOP)/$(MODULE),,$(OBJS)) + +depend:: dbg.tab.c dbg.tab.h lex.yy.c + +DependTarget() + +includes:: + +install:: + +clean:: + $(RM) lex.yy.c dbg.tab* y.tab.c + +dbg.tab.c dbg.tab.h: dbg.y + $(YACC) -b dbg -d dbg.y + +lex.yy.c: debug.l + $(LEX) -I debug.l diff --git a/debugger/readline/Imakefile b/debugger/readline/Imakefile new file mode 100644 index 00000000000..817f4afea06 --- /dev/null +++ b/debugger/readline/Imakefile @@ -0,0 +1,25 @@ +#include "../../Wine.tmpl" + +MODULE = readline + +YACC = yacc -b dbg -d + +DEFINES = -DANSI_ARROWS -DHAVE_TCGETATTR -DHIDE -DUSE_DIRENT -DSYS_UNIX + +SRCS = \ + complete.c \ + editline.c \ + sysunix.c + +OBJS = \ + complete.o \ + editline.o \ + sysunix.o + +WineRelocatableTarget($(TOP)/$(MODULE),,$(OBJS)) +DependTarget() +CleanTarget() + +includes:: + +install:: diff --git a/etc/Imakefile b/etc/Imakefile new file mode 100644 index 00000000000..b39880926cc --- /dev/null +++ b/etc/Imakefile @@ -0,0 +1,11 @@ +#include "../Wine.tmpl" + +MODULE = etc + +AllTarget() + +depend:: + +CleanTarget() + +includes:: diff --git a/etc/Makefile b/etc/Makefile new file mode 100644 index 00000000000..87948b04a9d --- /dev/null +++ b/etc/Makefile @@ -0,0 +1,358 @@ +# Makefile generated by imake - do not edit! +# $XConsortium: imake.c,v 1.65 91/07/25 17:50:17 rws Exp $ + +# ------------------------------------------------------------------------- +# Makefile generated from "Imake.tmpl" and +# $XFree86: mit/config/Imake.tmpl,v 1.17 1993/06/03 15:26:36 dawes Exp $ +# $XConsortium: Imake.tmpl,v 1.139 91/09/16 08:52:48 rws Exp $ +# +# Platform-specific parameters may be set in the appropriate .cf +# configuration files. Site-specific parameters should be set in the file +# site.def. Full rebuilds are recommended if any parameters are changed. +# +# If your C preprocessor does not define any unique symbols, you will need +# to set BOOTSTRAPCFLAGS when rebuilding imake (usually when doing +# "make World" the first time). +# + +# ------------------------------------------------------------------------- +# site-specific configuration parameters that need to come before +# the platform-specific parameters - edit site.def to change + +# $XFree86: mit/config/site.def,v 1.65 1993/06/04 16:02:47 dawes Exp $ +# site: $XConsortium: site.def,v 1.2 91/07/30 20:26:44 rws Exp $ + +# obz: changes for making Linux distribution + +# ------------------------------------------------------------------------- +# platform-specific configuration parameters - edit x386.cf to change + +# $XFree86: mit/config/x386.cf,v 1.90 1993/06/04 16:02:50 dawes Exp $ +# platform: $XConsortium: x386.cf,v 1.7 91/08/16 19:30:10 gildea Exp $ + +# ------------------------------------------------------------------------- +# XFree86 version definition +# $XFree86: mit/config/xf86_vers.def,v 1.5 1993/06/01 09:12:47 dawes Exp $ + +# ------------------------------------------------------------------------- +# XFree86 version: 1300 +# ------------------------------------------------------------------------- + +# $XFree86: mit/config/lnuxLib.rules,v 1.2 1993/06/02 13:48:12 dawes Exp $ + +DLL_BINDIR = /usr/dll/bin + +# operating system: Linux + +# ------------------------------------------------------------------------- +# site-specific configuration parameters that go after +# the platform-specific parameters - edit site.def to change + +# $XFree86: mit/config/site.def,v 1.65 1993/06/04 16:02:47 dawes Exp $ +# site: $XConsortium: site.def,v 1.2 91/07/30 20:26:44 rws Exp $ + +# obz: changes for making Linux distribution + + SHELL = /bin/sh + + TOP = ../. + CURRENT_DIR = ./etc + + AR = ar clq + BOOTSTRAPCFLAGS = + CC = gcc + AS = as + + LEX = flex + + YACC = bison -y + + COMPRESS = compress + CPP = /lib/cpp $(STD_CPP_DEFINES) + PREPROCESSCMD = /lib/cpp $(STD_CPP_DEFINES) + INSTALL = install + LD = ld + LINT = lint + LINTLIBFLAG = -C + LINTOPTS = -axz + LN = ln -s + MAKE = make + MV = mv + CP = cp + + RANLIB = ranlib + RANLIBINSTFLAGS = + + RM = rm -f + TROFF = psroff + MSMACROS = -ms + TBL = tbl + EQN = eqn + STD_INCLUDES = + STD_CPP_DEFINES = -traditional -D_POSIX_SOURCE -D_BSD_SOURCE -D_GNU_SOURCE -Dlinux + STD_DEFINES = -D_POSIX_SOURCE -D_BSD_SOURCE -D_GNU_SOURCE -Dlinux + EXTRA_LOAD_FLAGS = + EXTRA_LIBRARIES = + OS_LIBRARIES = + TAGS = ctags + + SHAREDCODEDEF = + SHLIBDEF = + + PROTO_DEFINES = -DFUNCPROTO=11 -DNARROWPROTO + + INSTPGMFLAGS = -s + + INSTBINFLAGS = -m 0755 + INSTUIDFLAGS = -s -m 4755 + INSTLIBFLAGS = -m 0644 + INSTINCFLAGS = -m 0444 + INSTMANFLAGS = -m 0444 + INSTDATFLAGS = -m 0444 + INSTKMEMFLAGS = -s -m 4755 + + PROJECTROOT = /usr/X386 + + TOP_INCLUDES = -I$(INCROOT) + + CDEBUGFLAGS = -O2 + CCOPTIONS = -m486 -DNO_ASM -fwritable-strings + ANSICCOPTIONS = + + ALLINCLUDES = $(INCLUDES) $(EXTRA_INCLUDES) $(TOP_INCLUDES) $(STD_INCLUDES) + ALLDEFINES = $(ALLINCLUDES) $(STD_DEFINES) $(EXTRA_DEFINES) $(PROTO_DEFINES) $(DEFINES) + CFLAGS = $(ANSICCOPTIONS) $(CDEBUGFLAGS) $(CCOPTIONS) $(ALLDEFINES) + LINTFLAGS = $(LINTOPTS) -DLINT $(ALLDEFINES) + + LDLIBS = $(OS_LIBRARIES) $(SYS_LIBRARIES) $(EXTRA_LIBRARIES) + + LDOPTIONS = $(ANSICCOPTIONS) $(CDEBUGFLAGS) $(CCOPTIONS) $(LOCAL_LDFLAGS) -L$(USRLIBDIR) + + LDCOMBINEFLAGS = -r + DEPENDFLAGS = + + MACROFILE = x386.cf + RM_CMD = $(RM) *.CKP *.ln *.BAK *.bak *.o core errs ,* *~ *.a .emacs_* tags TAGS make.log MakeOut + + IMAKE_DEFINES = + + IRULESRC = $(CONFIGDIR) + IMAKE_CMD = $(IMAKE) -DUseInstalled -I$(IRULESRC) $(IMAKE_DEFINES) + + ICONFIGFILES = $(IRULESRC)/Imake.tmpl $(IRULESRC)/Imake.rules $(IRULESRC)/Project.tmpl $(IRULESRC)/site.def $(IRULESRC)/$(MACROFILE) $(EXTRA_ICONFIGFILES) + +# ------------------------------------------------------------------------- +# X Window System Build Parameters +# $XFree86: mit/config/Project.tmpl,v 1.13 1993/03/27 03:32:45 dawes Exp $ +# $XConsortium: Project.tmpl,v 1.138.1.1 92/11/11 09:49:19 rws Exp $ + +_percentC_ = %C + +# ------------------------------------------------------------------------- +# X Window System make variables; this need to be coordinated with rules + + PATHSEP = / + USRLIBDIR = /usr/X386/lib + BINDIR = /usr/X386/bin + INCROOT = /usr/X386/include + BUILDINCROOT = $(TOP) + BUILDINCDIR = $(BUILDINCROOT)/X11 + BUILDINCTOP = .. + INCDIR = $(INCROOT)/X11 + ADMDIR = /usr/adm + LIBDIR = $(USRLIBDIR)/X11 + CONFIGDIR = $(LIBDIR)/config + LINTLIBDIR = $(USRLIBDIR)/lint + + FONTDIR = $(LIBDIR)/fonts + XINITDIR = $(LIBDIR)/xinit + XDMDIR = $(LIBDIR)/xdm + TWMDIR = $(LIBDIR)/twm + MANPATH = /usr/X386/man + MANSOURCEPATH = $(MANPATH)/man + MANSUFFIX = 1x + LIBMANSUFFIX = 3x + MANDIR = $(MANSOURCEPATH)1 + LIBMANDIR = $(MANSOURCEPATH)3 + NLSDIR = $(LIBDIR)/nls + PEXAPIDIR = $(LIBDIR)/PEX + XAPPLOADDIR = $(LIBDIR)/app-defaults + FONTCFLAGS = -t + LINKKITDIR = $(USRLIBDIR)/Server + + INSTAPPFLAGS = $(INSTDATFLAGS) + + IMAKE = imake + DEPEND = makedepend + RGB = rgb + + FONTC = bdftopcf + + MKFONTDIR = mkfontdir + MKDIRHIER = /bin/sh $(BINDIR)/mkdirhier + + CONFIGSRC = $(TOP)/config + DOCUTILSRC = $(TOP)/doc/util + CLIENTSRC = $(TOP)/clients + DEMOSRC = $(TOP)/demos + LIBSRC = $(TOP)/lib + FONTSRC = $(TOP)/fonts + INCLUDESRC = $(TOP)/X11 + SERVERSRC = $(TOP)/server + UTILSRC = $(TOP)/util + SCRIPTSRC = $(UTILSRC)/scripts + EXAMPLESRC = $(TOP)/examples + CONTRIBSRC = $(TOP)/../contrib + DOCSRC = $(TOP)/doc + RGBSRC = $(TOP)/rgb + DEPENDSRC = $(UTILSRC)/makedepend + IMAKESRC = $(CONFIGSRC) + XAUTHSRC = $(LIBSRC)/Xau + XLIBSRC = $(LIBSRC)/X + XMUSRC = $(LIBSRC)/Xmu + TOOLKITSRC = $(LIBSRC)/Xt + AWIDGETSRC = $(LIBSRC)/Xaw + OLDXLIBSRC = $(LIBSRC)/oldX + XDMCPLIBSRC = $(LIBSRC)/Xdmcp + BDFTOSNFSRC = $(FONTSRC)/bdftosnf + BDFTOSNFSRC = $(FONTSRC)/clients/bdftosnf + BDFTOPCFSRC = $(FONTSRC)/clients/bdftopcf + MKFONTDIRSRC = $(FONTSRC)/clients/mkfontdir + FSLIBSRC = $(FONTSRC)/lib/fs + FONTSERVERSRC = $(FONTSRC)/server + EXTENSIONSRC = $(TOP)/extensions + XILIBSRC = $(EXTENSIONSRC)/lib/xinput + PEXLIBSRC = $(EXTENSIONSRC)/lib/PEXlib + PHIGSLIBSRC = $(EXTENSIONSRC)/lib/PEX + +# $XFree86: mit/config/lnuxLib.tmpl,v 1.1 1993/04/16 14:06:06 dawes Exp $ + +SHLIBLDFLAGS = +PICFLAGS = -B/usr/dll/jump/ + + DEPEXTENSIONLIB = + EXTENSIONLIB = -lXext + + DEPXLIB = $(DEPEXTENSIONLIB) + XLIB = $(EXTENSIONLIB) -lX11 + + DEPXMULIB = + XMULIB = -lXmu + + DEPXTOOLLIB = + XTOOLLIB = -lXt + + DEPXAWLIB = + XAWLIB = -lXaw + + DEPXILIB = + XILIB = -lXi + + DEPXTESTLIB = + XTESTLIB = -lXtst + + DEPPEXLIB = + PEXLIB = -lPEX5 + + SOXLIBREV = 3.0.1 + SOXTREV = 3.0.1 + SOXAWREV = 3.0.1 + SOOLDXREV = 3.0.1 + SOXMUREV = 3.0.1 + SOXEXTREV = 3.0.1 + SOXINPUTREV = 3.0.1 + SOPEXREV = 1.0.1 + + DEPXAUTHLIB = $(USRLIBDIR)/libXau.a + XAUTHLIB = -lXau + DEPXDMCPLIB = $(USRLIBDIR)/libXdmcp.a + XDMCPLIB = -lXdmcp + + DEPOLDXLIB = $(USRLIBDIR)/liboldX.a + OLDXLIB = -loldX + + DEPPHIGSLIB = $(USRLIBDIR)/libphigs.a + PHIGSLIB = -lphigs + + DEPXBSDLIB = $(USRLIBDIR)/libXbsd.a + XBSDLIB = -lXbsd + + LINTEXTENSIONLIB = $(LINTLIBDIR)/llib-lXext.ln + LINTXLIB = $(LINTLIBDIR)/llib-lX11.ln + LINTXMU = $(LINTLIBDIR)/llib-lXmu.ln + LINTXTOOL = $(LINTLIBDIR)/llib-lXt.ln + LINTXAW = $(LINTLIBDIR)/llib-lXaw.ln + LINTXI = $(LINTLIBDIR)/llib-lXi.ln + LINTPEX = $(LINTLIBDIR)/llib-lPEX5.ln + LINTPHIGS = $(LINTLIBDIR)/llib-lphigs.ln + + DEPLIBS = $(DEPXAWLIB) $(DEPXMULIB) $(DEPXTOOLLIB) $(DEPXLIB) + + DEPLIBS1 = $(DEPLIBS) + DEPLIBS2 = $(DEPLIBS) + DEPLIBS3 = $(DEPLIBS) + +# ------------------------------------------------------------------------- +# Imake rules for building libraries, programs, scripts, and data files +# $XFree86: mit/config/Imake.rules,v 1.9 1993/03/23 12:56:27 dawes Exp $ +# rules: $XConsortium: Imake.rules,v 1.123 91/09/16 20:12:16 rws Exp $ + +# ------------------------------------------------------------------------- +# start of Imakefile + +# $Id$ + +INCLUDES = -I$(TOP)/include + +# Imake rules go here + +# First, dll description to files etc + +MODULE = etc + +all:: + +depend:: + +clean:: + $(RM_CMD) "#"* + +includes:: + +# ------------------------------------------------------------------------- +# common rules for all Makefiles - do not edit + +emptyrule:: + +clean:: + $(RM_CMD) "#"* + +Makefile:: + -@if [ -f Makefile ]; then set -x; \ + $(RM) Makefile.bak; $(MV) Makefile Makefile.bak; \ + else exit 0; fi + $(IMAKE_CMD) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT_DIR) + +tags:: + $(TAGS) -w *.[ch] + $(TAGS) -xw *.[ch] > TAGS + +# ------------------------------------------------------------------------- +# empty rules for directories that do not have SUBDIRS - do not edit + +install:: + @echo "install in $(CURRENT_DIR) done" + +install.man:: + @echo "install.man in $(CURRENT_DIR) done" + +install.linkkit:: + @echo "install.linkkit in $(CURRENT_DIR) done" + +Makefiles:: + +includes:: + +# ------------------------------------------------------------------------- +# dependencies generated by makedepend + diff --git a/if1632/Imakefile b/if1632/Imakefile new file mode 100644 index 00000000000..8c11afdfe95 --- /dev/null +++ b/if1632/Imakefile @@ -0,0 +1,37 @@ +#include "../Wine.tmpl" + +MODULE = if1632 + +SRCS = \ + call.S \ + callback.c \ + relay.c + +OBJS = \ + call.o \ + callback.o \ + relay.o + +/* + * If you add a new spec file, copy one of these lines + */ +MakeDllFromSpec(gdi,$(TOP)/$(MODULE)) +MakeDllFromSpec(kernel,$(TOP)/$(MODULE)) +MakeDllFromSpec(keyboard,$(TOP)/$(MODULE)) +MakeDllFromSpec(shell,$(TOP)/$(MODULE)) +MakeDllFromSpec(sound,$(TOP)/$(MODULE)) +MakeDllFromSpec(unixlib,$(TOP)/$(MODULE)) +MakeDllFromSpec(user,$(TOP)/$(MODULE)) +MakeDllFromSpec(win87em,$(TOP)/$(MODULE)) + +/* + * Yes I know *.o is not veru clever, but can you do it cleaner ? + */ +WineRelocatableTarget($(TOP)/$(MODULE),*.o,$(OBJS)) + +clean:: + $(RM) dll* + +depend:: + +includes:: diff --git a/if1632/callback.c b/if1632/callback.c index 1852185f8d5..82c71de459b 100644 --- a/if1632/callback.c +++ b/if1632/callback.c @@ -7,7 +7,7 @@ static char Copyright[] = "Copyright Robert J. Amstadt, 1993"; #include "segmem.h" #include -extern unsigned short SelectorOwners[]; +extern SEGDESC Segments[]; extern unsigned short IF1632_Saved16_ss; extern unsigned long IF1632_Saved16_ebp; extern unsigned long IF1632_Saved16_esp; @@ -56,7 +56,7 @@ FindDataSegmentForCode(unsigned long csip) unsigned int seg_idx; seg_idx = (unsigned short) (csip >> 19); - return SelectorOwners[seg_idx]; + return Segments[seg_idx].owner; } /********************************************************************** diff --git a/if1632/gdi.spec b/if1632/gdi.spec index a1fc5c59847..f2e2baae437 100644 --- a/if1632/gdi.spec +++ b/if1632/gdi.spec @@ -43,6 +43,11 @@ length 490 33 pascal TextOut(word s_word s_word ptr word) TextOut(1 2 3 4 5) 34 pascal BitBlt( word s_word s_word s_word s_word word s_word s_word long) BitBlt(1 2 3 4 5 6 7 8 9) +35 pascal StrechBlt( word s_word s_word s_word s_word word s_word s_word s_word s_word long) + StrechBlt(1 2 3 4 5 6 7 8 9 10 11) + +36 pascal Polygon (word ptr word) Polygon (1 2 3) +37 pascal Polyline (word ptr word) Polyline (1 2 3) 39 pascal RestoreDC(word s_word) RestoreDC(1 2) 40 pascal FillRgn(word word word) FillRgn(1 2 3) 43 pascal PaintRgn(word word) PaintRgn(1 2) diff --git a/if1632/kernel.spec b/if1632/kernel.spec index 142f4512f59..86a15087b2d 100644 --- a/if1632/kernel.spec +++ b/if1632/kernel.spec @@ -28,6 +28,8 @@ length 415 24 pascal UnlockSegment(s_word) KERNEL_UnlockSegment(1) 25 pascal GlobalCompact(long) GlobalCompact(1) 30 pascal WaitEvent(word) KERNEL_WaitEvent(1) +34 pascal SetTaskQueue(word word) SetTaskQueue(1 2) +35 pascal GetTaskQueue(word) GetTaskQueue(1) 49 pascal GetModuleFileName(word ptr s_word) KERNEL_GetModuleFileName(1 2 3) 50 pascal GetProcAddress(word ptr) GetProcAddress(1 2) 51 pascal MakeProcInstance(ptr word) CALLBACK_MakeProcInstance(1 2) @@ -43,6 +45,8 @@ length 415 74 pascal OpenFile(ptr ptr word) KERNEL_OpenFile(1 2 3) 81 pascal _lclose(word) KERNEL__lclose(1) 82 pascal _lread(word ptr word) KERNEL__lread(1 2 3) +83 pascal _lcreate(ptr word) KERNEL__lcreate(1 2) +84 pascal _llseek(word long word) KERNEL__llseek(1 2 3) 85 pascal _lopen(ptr word) KERNEL__lopen(1 2) 86 pascal _lwrite(word ptr word) KERNEL__lwrite(1 2 3) 88 pascal lstrcpy(ptr ptr) lstrcpy(1 2) @@ -51,11 +55,14 @@ length 415 91 register InitTask(word word word word word word word word word word) KERNEL_InitTask() +92 pascal GetTempDrive(byte) GetTempDrive(1) 95 pascal LoadLibrary(ptr) LoadLibrary(1) 96 pascal FreeLibrary(word) FreeLibrary(1) +97 pascal GetTempFileName(byte ptr word ptr) GetTempDrive(1 2 3 4) 102 register DOS3Call(word word word word word word word word word word) KERNEL_DOS3Call() +107 pascal SetErrorMode(word) SetErrorMode(1) 111 pascal GlobalWire(word) GlobalLock(1) 112 pascal GlobalUnWire(word) GlobalUnlock(1) 115 pascal OutputDebugString(ptr) OutputDebugString(1) @@ -68,6 +75,9 @@ length 415 WritePrivateProfileString(1 2 3 4) 131 pascal GetDOSEnvironment() GetDOSEnvironment() 132 return GetWinFlags 0 0x413 +134 pascal GetWindowsDirectory(ptr word) GetWindowsDirectory(1 2) +135 pascal GetSystemDirectory(ptr word) GetSystemDirectory(1 2) +136 pascal GetDriveType(byte) GetWindowsDirectory(1) 154 return GlobalNotify 4 0 163 pascal GlobalLRUOldest(word) ReturnArg(1) 164 pascal GlobalLRUNewest(word) ReturnArg(1) diff --git a/if1632/relay.c b/if1632/relay.c index 859144c7274..d6ad3353fdb 100644 --- a/if1632/relay.c +++ b/if1632/relay.c @@ -173,7 +173,7 @@ DLLRelay(unsigned int func_num, unsigned int seg_off) case DLL_ARGTYPE_FARPTR: ip = (int *) ((char *) arg_ptr + offset); if (*ip & 0xffff0000) - arg_table[i] = SAFEMAKEPTR((unsigned) *ip >> 16, *ip); + arg_table[i] = FIXPTR(*ip); else arg_table[i] = *ip; break; diff --git a/if1632/user.spec b/if1632/user.spec index bf032d68149..86682f18c6e 100644 --- a/if1632/user.spec +++ b/if1632/user.spec @@ -13,12 +13,16 @@ length 540 13 pascal GetTickCount() GetTickCount() 14 return GetTimerResolution 0 1000 15 pascal GetCurrentTime() GetTickCount() +16 pascal ClipCursor(ptr) ClipCursor(1) +17 pascal GetCursorPos(ptr) GetCursorPos(1) 18 pascal SetCapture(word) SetCapture(1) 19 pascal ReleaseCapture() ReleaseCapture() 20 pascal SetDoubleClickTime(word) SetDoubleClickTime(1) 21 pascal GetDoubleClickTime() GetDoubleClickTime() 22 pascal SetFocus(word) SetFocus(1) 23 pascal GetFocus() GetFocus() +28 pascal ClientToScreen(word ptr) ClientToScreen(1 2) +29 pascal ScreenToClient(word ptr) ScreenToClient(1 2) 31 pascal IsIconic(word) IsIconic(1) 32 pascal GetWindowRect(word ptr) GetWindowRect(1 2) 33 pascal GetClientRect(word ptr) GetClientRect(1 2) @@ -41,13 +45,18 @@ length 540 56 pascal MoveWindow(word word word word word word) MoveWindow(1 2 3 4 5 6) 57 pascal RegisterClass(ptr) RegisterClass(1) +58 pascal GetClassName(word ptr word) GetClassName(1 2 3) 61 pascal ScrollWindow(word s_word s_word ptr ptr) ScrollWindow(1 2 3 4 5) 62 pascal SetScrollPos(word word word word) SetScrollPos(1 2 3 4) +63 pascal GetScrollPos(word word) GetScrollPos(1 2) 64 pascal SetScrollRange(word word word word word) SetScrollRange(1 2 3 4 5) +65 pascal GetScrollRange(word word ptr ptr) GetScrollRange(1 2 3 4) 66 pascal GetDC(word) GetDC(1) +67 pascal GetWindowDC(word) GetWindowDC(1) 68 pascal ReleaseDC(word word) ReleaseDC(1 2) -69 pascal SetCursor(word word) SetCursor(1 2) -71 pascal ShowCursor(word word) ShowCursor(1 2) +69 pascal SetCursor(word) SetCursor(1) +70 pascal SetCursorPos(word word) SetCursorPos(1 2) +71 pascal ShowCursor(word) ShowCursor(1) 72 pascal SetRect(ptr s_word s_word s_word s_word) SetRect(1 2 3 4 5) 73 pascal SetRectEmpty(ptr) SetRectEmpty(1) 74 pascal CopyRect(ptr ptr) CopyRect(1 2) @@ -67,7 +76,7 @@ length 540 89 pascal CreateDialog(word ptr word ptr) CreateDialog(1 2 3 4) 90 pascal IsDialogMessage(word ptr) IsDialogMessage(1 2) 91 pascal GetDlgItem(word word) GetDlgItem(1 2) -92 pascal SetDlgItemText(word ptr) SetDlgItemText(1 2) +92 pascal SetDlgItemText(word word ptr) SetDlgItemText(1 2 3) 93 pascal GetDlgItemText(word word ptr word) GetDlgItemText(1 2 3 4) 94 pascal SetDlgItemInt(word word word word) SetDlgItemInt(1 2 3 4) 95 pascal GetDlgItemInt(word word ptr word) GetDlgItemInt(1 2 3 4) @@ -106,9 +115,18 @@ length 540 136 pascal SetWindowLong(word s_word long) SetWindowLong(1 2 3) 150 pascal LoadMenu(word ptr) LoadMenu(1 2) 151 pascal CreateMenu() CreateMenu() -154 pascal CheckMenu(word word word) CheckMenu(1 2 3) +152 pascal DestroyMenu(word) DestroyMenu(1) +154 pascal CheckMenuItem(word word word) CheckMenuItem(1 2 3) +155 pascal EnableMenuItem(word word word) EnableMenuItem(1 2 3) 157 pascal GetMenu(word) GetMenu(1) 158 pascal SetMenu(word word) SetMenu(1 2) +163 pascal CreateCaret(word word word word) CreateCaret(1 2 3 4) +164 pascal DestroyCaret() DestroyCaret() +165 pascal SetCaretPos(word word) SetCaretPos(1 2) +166 pascal HideCaret(word) HideCaret(1) +167 pascal ShowCaret(word) ShowCaret(1) +166 pascal SetCaretBlinkTime(word) SetCaretBlinkTime(1) +169 pascal GetCaretBlinkTime() GetCaretBlinkTime() 171 pascal WinHelp(word word long) WinHelp(1 2 3) 173 pascal LoadCursor(word ptr) LoadCursor(1 2) 174 pascal LoadIcon(word ptr) LoadIcon(1 2) @@ -119,7 +137,24 @@ length 540 180 pascal GetSysColor(word) GetSysColor(1) 181 pascal SetSysColors(word ptr ptr) SetSysColors(1 2 3) 182 pascal KillSystemTimer(word word) KillSystemTimer(1 2) +183 pascal GetCaretPos(ptr) GetCaretPos(1) 190 pascal GetUpdateRect(word ptr word) GetUpdateRect(1 2 3) +200 pascal OpenComm(ptr word word) OpenComm(1 2 3) +201 pascal SetCommState(ptr) SetCommState(1) +202 pascal GetCommState(word ptr) GetCommState(1 2) +203 pascal GetCommError(word ptr) GetCommError(1 2) +204 pascal ReadComm(word ptr word) ReadComm(1 2 3) +205 pascal WriteComm(word ptr word) WriteComm(1 2 3) +206 pascal TransmitCommChar(word byte) TransmitCommChar (1 2) +207 pascal CloseComm(word) CloseComm(1) +208 pascal SetCommEventMask(word word) SetCommEventMask(1 2) +209 pascal GetCommEventMask(word word) GetCommEventMask(1 2) +210 pascal SetCommBreak(word) SetCommBreak(1) +211 pascal ClearCommBreak(word) ClearCommBreak(1) +212 pascal UngetCommChar(word byte) UngetCommChar(1 2) +213 pascal BuildCommDCB(ptr ptr) BuildCommDCB(1 2) +214 pascal EscapeCommFunction(word word) EscapeCommFunction(1 2) +215 pascal FlushComm(word word) FlushComm(1 2) 218 pascal DialogBoxIndirect(word word word ptr) DialogBoxIndirect(1 2 3 4) 219 pascal CreateDialogIndirect(word ptr word ptr) CreateDialogIndirect(1 2 3 4) @@ -131,6 +166,7 @@ length 540 230 pascal GetNextWindow(word word) GetNextWindow(1 2) 232 pascal SetWindowPos(word word word word word word word) SetWindowPos(1 2 3 4 5 6 7) +236 pascal GetCapture() GetCapture() 237 pascal GetUpdateRgn(word word word) GetUpdateRgn(1 2 3) 239 pascal DialogBoxParam(word ptr word ptr long) DialogBoxParam(1 2 3 4 5) 240 pascal DialogBoxIndirectParam(word word word ptr long) @@ -140,9 +176,14 @@ length 540 242 pascal CreateDialogIndirectParam(word ptr word ptr long) CreateDialogIndirectParam(1 2 3 4 5) 244 pascal EqualRect(ptr ptr) EqualRect(1 2) +258 pascal MapWindowPoints(word word ptr word) MapWindowPoints(1 2 3 4) 262 pascal GetWindow(word word) GetWindow(1 2) 266 pascal SetMessageQueue(word) SetMessageQueue(1) +267 pascal ShowScrollBar(word word word) ShowScrollBar(1 2 3) +272 pascal IsZoomed(word) IsZoomed(1) 277 pascal GetDlgCtrlID(word) GetDlgCtrlID(1) +282 pascal SelectPalette(word word word) SelectPalette(1 2 3) +283 pascal RealizePalette(word) RealizePalette(1) 286 pascal GetDesktopWindow() GetDesktopWindow() 288 pascal GetMessageExtraInfo() GetMessageExtraInfo() 319 pascal ScrollWindowEx(word s_word s_word ptr ptr word ptr word) @@ -151,9 +192,20 @@ length 540 325 pascal PaintRect(word word word word ptr) PaintRect(1 2 3 4 5) 334 pascal GetQueueStatus(word) GetQueueStatus(1) 335 pascal GetInputState() GetInputState() +359 pascal GetDCEx(word word long) GetDCEx(1 2 3) 373 pascal SubtractRect(ptr ptr ptr) SubtractRect(1 2 3) 403 pascal UnregisterClass(ptr word) UnregisterClass(1 2) +404 pascal GetClassInfo(word ptr ptr) GetClassInfo(1 2 3) +406 pascal CreateCursor(word word word word word ptr ptr) + CreateCursor(1 2 3 4 5 6 7) +410 pascal InsertMenu(word word word word ptr) InsertMenu(1 2 3 4 5) 411 pascal AppendMenu(word word word ptr) AppendMenu(1 2 3 4) +412 pascal RemoveMenu(word word word) RemoveMenu(1 2 3) +413 pascal DeleteMenu(word word word) DeleteMenu(1 2 3) +414 pascal ModifyMenu(word word word word ptr) ModifyMenu(1 2 3 4 5) +415 pascal CreatePopupMenu() CreatePopupMenu() +416 pascal TrackPopupMenu(word word word word word word ptr) + TrackPopupMenu(1 2 3 4 5 6 7) 420 pascal wsprintf(ptr ptr) wsprintf(1 2) 421 pascal wvsprintf(ptr ptr ptr) wvsprintf(1 2 3) 430 pascal lstrcmp(ptr ptr) lstrcmp(1 2) diff --git a/include/Imakefile b/include/Imakefile new file mode 100644 index 00000000000..4e3798738ac --- /dev/null +++ b/include/Imakefile @@ -0,0 +1,38 @@ +#include "../Wine.tmpl" + +MODULE = include + +HEADERS = \ + atom.h \ + callback.h \ + class.h \ + combo.h \ + cursor.h \ + dce.h \ + dialog.h \ + dlls.h \ + files.h \ + gdi.h \ + heap.h \ + icon.h \ + int21.h \ + listbox.h \ + menu.h \ + message.h \ + neexe.h \ + prototypes.h \ + regfunc.h \ + scroll.h \ + segmem.h \ + user.h \ + win.h \ + windows.h \ + wine.h + +AllTarget() + +depend:: + +CleanTarget() + +includes:: diff --git a/include/Makefile b/include/Makefile new file mode 100644 index 00000000000..97bc6f4a06b --- /dev/null +++ b/include/Makefile @@ -0,0 +1,360 @@ +# Makefile generated by imake - do not edit! +# $XConsortium: imake.c,v 1.65 91/07/25 17:50:17 rws Exp $ + +# ------------------------------------------------------------------------- +# Makefile generated from "Imake.tmpl" and +# $XFree86: mit/config/Imake.tmpl,v 1.17 1993/06/03 15:26:36 dawes Exp $ +# $XConsortium: Imake.tmpl,v 1.139 91/09/16 08:52:48 rws Exp $ +# +# Platform-specific parameters may be set in the appropriate .cf +# configuration files. Site-specific parameters should be set in the file +# site.def. Full rebuilds are recommended if any parameters are changed. +# +# If your C preprocessor does not define any unique symbols, you will need +# to set BOOTSTRAPCFLAGS when rebuilding imake (usually when doing +# "make World" the first time). +# + +# ------------------------------------------------------------------------- +# site-specific configuration parameters that need to come before +# the platform-specific parameters - edit site.def to change + +# $XFree86: mit/config/site.def,v 1.65 1993/06/04 16:02:47 dawes Exp $ +# site: $XConsortium: site.def,v 1.2 91/07/30 20:26:44 rws Exp $ + +# obz: changes for making Linux distribution + +# ------------------------------------------------------------------------- +# platform-specific configuration parameters - edit x386.cf to change + +# $XFree86: mit/config/x386.cf,v 1.90 1993/06/04 16:02:50 dawes Exp $ +# platform: $XConsortium: x386.cf,v 1.7 91/08/16 19:30:10 gildea Exp $ + +# ------------------------------------------------------------------------- +# XFree86 version definition +# $XFree86: mit/config/xf86_vers.def,v 1.5 1993/06/01 09:12:47 dawes Exp $ + +# ------------------------------------------------------------------------- +# XFree86 version: 1300 +# ------------------------------------------------------------------------- + +# $XFree86: mit/config/lnuxLib.rules,v 1.2 1993/06/02 13:48:12 dawes Exp $ + +DLL_BINDIR = /usr/dll/bin + +# operating system: Linux + +# ------------------------------------------------------------------------- +# site-specific configuration parameters that go after +# the platform-specific parameters - edit site.def to change + +# $XFree86: mit/config/site.def,v 1.65 1993/06/04 16:02:47 dawes Exp $ +# site: $XConsortium: site.def,v 1.2 91/07/30 20:26:44 rws Exp $ + +# obz: changes for making Linux distribution + + SHELL = /bin/sh + + TOP = ../. + CURRENT_DIR = ./include + + AR = ar clq + BOOTSTRAPCFLAGS = + CC = gcc + AS = as + + LEX = flex + + YACC = bison -y + + COMPRESS = compress + CPP = /lib/cpp $(STD_CPP_DEFINES) + PREPROCESSCMD = /lib/cpp $(STD_CPP_DEFINES) + INSTALL = install + LD = ld + LINT = lint + LINTLIBFLAG = -C + LINTOPTS = -axz + LN = ln -s + MAKE = make + MV = mv + CP = cp + + RANLIB = ranlib + RANLIBINSTFLAGS = + + RM = rm -f + TROFF = psroff + MSMACROS = -ms + TBL = tbl + EQN = eqn + STD_INCLUDES = + STD_CPP_DEFINES = -traditional -D_POSIX_SOURCE -D_BSD_SOURCE -D_GNU_SOURCE -Dlinux + STD_DEFINES = -D_POSIX_SOURCE -D_BSD_SOURCE -D_GNU_SOURCE -Dlinux + EXTRA_LOAD_FLAGS = + EXTRA_LIBRARIES = + OS_LIBRARIES = + TAGS = ctags + + SHAREDCODEDEF = + SHLIBDEF = + + PROTO_DEFINES = -DFUNCPROTO=11 -DNARROWPROTO + + INSTPGMFLAGS = -s + + INSTBINFLAGS = -m 0755 + INSTUIDFLAGS = -s -m 4755 + INSTLIBFLAGS = -m 0644 + INSTINCFLAGS = -m 0444 + INSTMANFLAGS = -m 0444 + INSTDATFLAGS = -m 0444 + INSTKMEMFLAGS = -s -m 4755 + + PROJECTROOT = /usr/X386 + + TOP_INCLUDES = -I$(INCROOT) + + CDEBUGFLAGS = -O2 + CCOPTIONS = -m486 -DNO_ASM -fwritable-strings + ANSICCOPTIONS = + + ALLINCLUDES = $(INCLUDES) $(EXTRA_INCLUDES) $(TOP_INCLUDES) $(STD_INCLUDES) + ALLDEFINES = $(ALLINCLUDES) $(STD_DEFINES) $(EXTRA_DEFINES) $(PROTO_DEFINES) $(DEFINES) + CFLAGS = $(ANSICCOPTIONS) $(CDEBUGFLAGS) $(CCOPTIONS) $(ALLDEFINES) + LINTFLAGS = $(LINTOPTS) -DLINT $(ALLDEFINES) + + LDLIBS = $(OS_LIBRARIES) $(SYS_LIBRARIES) $(EXTRA_LIBRARIES) + + LDOPTIONS = $(ANSICCOPTIONS) $(CDEBUGFLAGS) $(CCOPTIONS) $(LOCAL_LDFLAGS) -L$(USRLIBDIR) + + LDCOMBINEFLAGS = -r + DEPENDFLAGS = + + MACROFILE = x386.cf + RM_CMD = $(RM) *.CKP *.ln *.BAK *.bak *.o core errs ,* *~ *.a .emacs_* tags TAGS make.log MakeOut + + IMAKE_DEFINES = + + IRULESRC = $(CONFIGDIR) + IMAKE_CMD = $(IMAKE) -DUseInstalled -I$(IRULESRC) $(IMAKE_DEFINES) + + ICONFIGFILES = $(IRULESRC)/Imake.tmpl $(IRULESRC)/Imake.rules $(IRULESRC)/Project.tmpl $(IRULESRC)/site.def $(IRULESRC)/$(MACROFILE) $(EXTRA_ICONFIGFILES) + +# ------------------------------------------------------------------------- +# X Window System Build Parameters +# $XFree86: mit/config/Project.tmpl,v 1.13 1993/03/27 03:32:45 dawes Exp $ +# $XConsortium: Project.tmpl,v 1.138.1.1 92/11/11 09:49:19 rws Exp $ + +_percentC_ = %C + +# ------------------------------------------------------------------------- +# X Window System make variables; this need to be coordinated with rules + + PATHSEP = / + USRLIBDIR = /usr/X386/lib + BINDIR = /usr/X386/bin + INCROOT = /usr/X386/include + BUILDINCROOT = $(TOP) + BUILDINCDIR = $(BUILDINCROOT)/X11 + BUILDINCTOP = .. + INCDIR = $(INCROOT)/X11 + ADMDIR = /usr/adm + LIBDIR = $(USRLIBDIR)/X11 + CONFIGDIR = $(LIBDIR)/config + LINTLIBDIR = $(USRLIBDIR)/lint + + FONTDIR = $(LIBDIR)/fonts + XINITDIR = $(LIBDIR)/xinit + XDMDIR = $(LIBDIR)/xdm + TWMDIR = $(LIBDIR)/twm + MANPATH = /usr/X386/man + MANSOURCEPATH = $(MANPATH)/man + MANSUFFIX = 1x + LIBMANSUFFIX = 3x + MANDIR = $(MANSOURCEPATH)1 + LIBMANDIR = $(MANSOURCEPATH)3 + NLSDIR = $(LIBDIR)/nls + PEXAPIDIR = $(LIBDIR)/PEX + XAPPLOADDIR = $(LIBDIR)/app-defaults + FONTCFLAGS = -t + LINKKITDIR = $(USRLIBDIR)/Server + + INSTAPPFLAGS = $(INSTDATFLAGS) + + IMAKE = imake + DEPEND = makedepend + RGB = rgb + + FONTC = bdftopcf + + MKFONTDIR = mkfontdir + MKDIRHIER = /bin/sh $(BINDIR)/mkdirhier + + CONFIGSRC = $(TOP)/config + DOCUTILSRC = $(TOP)/doc/util + CLIENTSRC = $(TOP)/clients + DEMOSRC = $(TOP)/demos + LIBSRC = $(TOP)/lib + FONTSRC = $(TOP)/fonts + INCLUDESRC = $(TOP)/X11 + SERVERSRC = $(TOP)/server + UTILSRC = $(TOP)/util + SCRIPTSRC = $(UTILSRC)/scripts + EXAMPLESRC = $(TOP)/examples + CONTRIBSRC = $(TOP)/../contrib + DOCSRC = $(TOP)/doc + RGBSRC = $(TOP)/rgb + DEPENDSRC = $(UTILSRC)/makedepend + IMAKESRC = $(CONFIGSRC) + XAUTHSRC = $(LIBSRC)/Xau + XLIBSRC = $(LIBSRC)/X + XMUSRC = $(LIBSRC)/Xmu + TOOLKITSRC = $(LIBSRC)/Xt + AWIDGETSRC = $(LIBSRC)/Xaw + OLDXLIBSRC = $(LIBSRC)/oldX + XDMCPLIBSRC = $(LIBSRC)/Xdmcp + BDFTOSNFSRC = $(FONTSRC)/bdftosnf + BDFTOSNFSRC = $(FONTSRC)/clients/bdftosnf + BDFTOPCFSRC = $(FONTSRC)/clients/bdftopcf + MKFONTDIRSRC = $(FONTSRC)/clients/mkfontdir + FSLIBSRC = $(FONTSRC)/lib/fs + FONTSERVERSRC = $(FONTSRC)/server + EXTENSIONSRC = $(TOP)/extensions + XILIBSRC = $(EXTENSIONSRC)/lib/xinput + PEXLIBSRC = $(EXTENSIONSRC)/lib/PEXlib + PHIGSLIBSRC = $(EXTENSIONSRC)/lib/PEX + +# $XFree86: mit/config/lnuxLib.tmpl,v 1.1 1993/04/16 14:06:06 dawes Exp $ + +SHLIBLDFLAGS = +PICFLAGS = -B/usr/dll/jump/ + + DEPEXTENSIONLIB = + EXTENSIONLIB = -lXext + + DEPXLIB = $(DEPEXTENSIONLIB) + XLIB = $(EXTENSIONLIB) -lX11 + + DEPXMULIB = + XMULIB = -lXmu + + DEPXTOOLLIB = + XTOOLLIB = -lXt + + DEPXAWLIB = + XAWLIB = -lXaw + + DEPXILIB = + XILIB = -lXi + + DEPXTESTLIB = + XTESTLIB = -lXtst + + DEPPEXLIB = + PEXLIB = -lPEX5 + + SOXLIBREV = 3.0.1 + SOXTREV = 3.0.1 + SOXAWREV = 3.0.1 + SOOLDXREV = 3.0.1 + SOXMUREV = 3.0.1 + SOXEXTREV = 3.0.1 + SOXINPUTREV = 3.0.1 + SOPEXREV = 1.0.1 + + DEPXAUTHLIB = $(USRLIBDIR)/libXau.a + XAUTHLIB = -lXau + DEPXDMCPLIB = $(USRLIBDIR)/libXdmcp.a + XDMCPLIB = -lXdmcp + + DEPOLDXLIB = $(USRLIBDIR)/liboldX.a + OLDXLIB = -loldX + + DEPPHIGSLIB = $(USRLIBDIR)/libphigs.a + PHIGSLIB = -lphigs + + DEPXBSDLIB = $(USRLIBDIR)/libXbsd.a + XBSDLIB = -lXbsd + + LINTEXTENSIONLIB = $(LINTLIBDIR)/llib-lXext.ln + LINTXLIB = $(LINTLIBDIR)/llib-lX11.ln + LINTXMU = $(LINTLIBDIR)/llib-lXmu.ln + LINTXTOOL = $(LINTLIBDIR)/llib-lXt.ln + LINTXAW = $(LINTLIBDIR)/llib-lXaw.ln + LINTXI = $(LINTLIBDIR)/llib-lXi.ln + LINTPEX = $(LINTLIBDIR)/llib-lPEX5.ln + LINTPHIGS = $(LINTLIBDIR)/llib-lphigs.ln + + DEPLIBS = $(DEPXAWLIB) $(DEPXMULIB) $(DEPXTOOLLIB) $(DEPXLIB) + + DEPLIBS1 = $(DEPLIBS) + DEPLIBS2 = $(DEPLIBS) + DEPLIBS3 = $(DEPLIBS) + +# ------------------------------------------------------------------------- +# Imake rules for building libraries, programs, scripts, and data files +# $XFree86: mit/config/Imake.rules,v 1.9 1993/03/23 12:56:27 dawes Exp $ +# rules: $XConsortium: Imake.rules,v 1.123 91/09/16 20:12:16 rws Exp $ + +# ------------------------------------------------------------------------- +# start of Imakefile + +# $Id$ + +INCLUDES = -I$(TOP)/include + +# Imake rules go here + +# First, dll description to files etc + +MODULE = include + +HEADERS = atom.h callback.h class.h combo.h cursor.h dce.h dialog.h dlls.h files.h gdi.h heap.h icon.h int21.h listbox.h menu.h message.h neexe.h prototypes.h regfunc.h scroll.h segmem.h user.h win.h windows.h wine.h + +all:: + +depend:: + +clean:: + $(RM_CMD) "#"* + +includes:: + +# ------------------------------------------------------------------------- +# common rules for all Makefiles - do not edit + +emptyrule:: + +clean:: + $(RM_CMD) "#"* + +Makefile:: + -@if [ -f Makefile ]; then set -x; \ + $(RM) Makefile.bak; $(MV) Makefile Makefile.bak; \ + else exit 0; fi + $(IMAKE_CMD) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT_DIR) + +tags:: + $(TAGS) -w *.[ch] + $(TAGS) -xw *.[ch] > TAGS + +# ------------------------------------------------------------------------- +# empty rules for directories that do not have SUBDIRS - do not edit + +install:: + @echo "install in $(CURRENT_DIR) done" + +install.man:: + @echo "install.man in $(CURRENT_DIR) done" + +install.linkkit:: + @echo "install.linkkit in $(CURRENT_DIR) done" + +Makefiles:: + +includes:: + +# ------------------------------------------------------------------------- +# dependencies generated by makedepend + diff --git a/include/atom.h b/include/atom.h new file mode 100644 index 00000000000..61cf6b1b7c7 --- /dev/null +++ b/include/atom.h @@ -0,0 +1,27 @@ +/* + * Atom table definitions + * + * Copyright 1993 Alexandre Julliard + */ + +#ifndef ATOM_H +#define ATOM_H + +#include "windows.h" + + +typedef struct +{ + HANDLE next; + WORD refCount; + BYTE length; + BYTE str[1]; +} ATOMENTRY; + +typedef struct +{ + WORD size; + HANDLE entries[1]; +} ATOMTABLE; + +#endif /* ATOM_H */ diff --git a/include/class.h b/include/class.h index 9ab50e4e2f5..285e81bf746 100644 --- a/include/class.h +++ b/include/class.h @@ -17,7 +17,7 @@ typedef struct tagCLASS HCLASS hNext; /* Next class */ WORD wMagic; /* Magic number (must be CLASS_MAGIC) */ ATOM atomName; /* Name of the class */ - HDC hdc; /* Class DC (if CS_CLASSDC) */ + HANDLE hdce; /* Class DCE (if CS_CLASSDC) */ WORD cWindows; /* Count of existing windows of this class */ WNDCLASS wc __attribute__ ((packed)); /* Class information */ WORD wExtra[1]; /* Class extra bytes */ diff --git a/include/dce.h b/include/dce.h index eff58a5a890..d95c7812e6a 100644 --- a/include/dce.h +++ b/include/dce.h @@ -9,16 +9,27 @@ #include "windows.h" +typedef enum +{ + DCE_CACHE_DC, /* This is a cached DC (allocated by USER) */ + DCE_CLASS_DC, /* This is a class DC (style CS_CLASSDC) */ + DCE_WINDOW_DC /* This is a window DC (style CS_OWNDC) */ +} DCE_TYPE; + + typedef struct tagDCE { HANDLE hNext; HWND hwndCurrent; HDC hdc; - BYTE flags; + DCE_TYPE type; BOOL inUse; WORD xOrigin; WORD yOrigin; } DCE; +extern HANDLE DCE_AllocDCE( DCE_TYPE type ); +extern void DCE_FreeDCE( HANDLE hdce ); + #endif /* DCE_H */ diff --git a/include/files.h b/include/files.h deleted file mode 100644 index 1b628a23d4f..00000000000 --- a/include/files.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _FILES_H -#define _FILES_H - -#define OPEN_MAX 256 - -/*************************************************************************** - This structure stores the infomation needed for a single DOS drive - ***************************************************************************/ -struct DosDriveStruct -{ - char RootDirectory [256]; /* Unix base for this drive letter */ - char CurrentDirectory [256]; /* Current directory for this drive */ - char VolumeLabel [11]; - unsigned long serialnumber; -}; - -#endif /*_FILES_H*/ diff --git a/include/gdi.h b/include/gdi.h index bb5b6323b27..aade98d919f 100644 --- a/include/gdi.h +++ b/include/gdi.h @@ -7,7 +7,7 @@ #ifndef GDI_H #define GDI_H -#include +#include #include "windows.h" #include "segmem.h" @@ -158,6 +158,8 @@ typedef struct WORD MapMode; short DCOrgX; /* DC origin */ short DCOrgY; + short DCSizeX; /* DC dimensions */ + short DCSizeY; short CursPosX; /* Current position */ short CursPosY; short WndOrgX; @@ -200,7 +202,6 @@ typedef struct { GC gc; /* X Window GC */ Drawable drawable; - Widget widget; X_PHYSFONT font; X_PHYSPEN pen; X_PHYSBRUSH brush; diff --git a/include/int21.h b/include/int21.h index 92cabc559da..f44c9a433fa 100644 --- a/include/int21.h +++ b/include/int21.h @@ -1,15 +1,40 @@ #ifndef INT21_H #define INT21_H +#include + +struct dosdirent { + int inuse; + DIR *ds; + char unixpath[256]; + char filename[256]; + char attribute; + long filesize; + long filetime; + long filedate; +}; + +struct diskinfo { + unsigned int infolevel; + unsigned long serialnumber; + char label[11]; + char fstype[8]; +}; #define DosVersion 0x0303; #define SectorSize 0x200; #define SectorsPerCluster 0x04; -#define AX context->sc_eax -#define BX context->sc_ebx -#define CX context->sc_ecx -#define DX context->sc_edx +#define EAX context->sc_eax +#define EBX context->sc_ebx +#define ECX context->sc_ecx +#define EDX context->sc_edx + +#define AX (context->sc_eax & 0x0000ffffL) +#define BX (context->sc_ebx & 0x0000ffffL) +#define CX (context->sc_ecx & 0x0000ffffL) +#define DX (context->sc_edx & 0x0000ffffL) + #define ES context->sc_es #define DS context->sc_ds #define DI context->sc_edi @@ -22,13 +47,6 @@ #define SetCflag (context->sc_efl |= 0x00000001L) #define ResetCflag (context->sc_efl &= 0xfffffffeL) -struct diskinfo { - WORD infolevel; - DWORD serialnumber; - char label[11]; - char fstype[8]; -}; - /* extended error codes */ #define NoError 0x00 diff --git a/include/listbox.h b/include/listbox.h index f44cf8ce8ee..5d89f9eba22 100644 --- a/include/listbox.h +++ b/include/listbox.h @@ -14,16 +14,17 @@ typedef LISTSTRUCT FAR* LPLISTSTRUCT; typedef struct tagHEADLIST { short FirstVisible; - short ItemSelect; short ItemsCount; short ItemsVisible; - short ItemSelected; - short PrevSelected; + short ColumnsVisible; + short ItemsPerColumn; + short ItemFocused; + short PrevFocused; short StdItemHeight; + short ColumnsWidth; short DrawCtlType; void *lpFirst; DWORD dwStyle; - HWND hWndScroll; HWND hWndLogicParent; } HEADLIST; typedef HEADLIST FAR* LPHEADLIST; diff --git a/include/menu.h b/include/menu.h index 15d251adf53..edc0bec12b0 100644 --- a/include/menu.h +++ b/include/menu.h @@ -27,7 +27,10 @@ typedef struct tagMENUITEM Widget w; Widget menu_w; char menu_name[10]; -} MENUITEM; + RECT rect; + HBITMAP hCheckBit; + HBITMAP hUnCheckBit; +} MENUITEM, *LPMENUITEM; typedef struct tagMENUBAR { @@ -40,6 +43,16 @@ typedef struct tagMENUBAR MENUITEM *firstItem; } MENUBAR, *LPMENUBAR; +typedef struct tagPOPUPMENU +{ + HWND hWnd; /* PopupMenu window handle */ + HWND ownerWnd; /* Owner window */ + WORD nItems; /* Number of items on menu */ + MENUITEM *firstItem; + WORD FocusedItem; + WORD MouseFlags; +} POPUPMENU, *LPPOPUPMENU; + typedef struct { WORD version; /* Should be zero */ diff --git a/include/message.h b/include/message.h index 0bbfc9a3ef0..d64b4fcbb2f 100644 --- a/include/message.h +++ b/include/message.h @@ -12,8 +12,8 @@ /* Message as stored in the queue (contains the extraInfo field) */ typedef struct tagQMSG { + DWORD extraInfo; /* Only in 3.1 */ MSG msg; - DWORD extraInfo __attribute__ ((packed)); /* Only in 3.1 */ } QMSG; @@ -28,17 +28,28 @@ typedef struct tagMESSAGEQUEUE WORD queueSize; /* Size of the queue */ DWORD GetMessageTimeVal; /* Value returned by GetMessageTime */ DWORD GetMessagePosVal; /* Value returned by GetMessagePos */ - WORD GetMessageExtraInfoVal; /* Value returned by GetMessageExtraInfo */ - DWORD lParam; /* Next four values set by SetMessage */ + DWORD GetMessageExtraInfoVal; /* Value returned by GetMessageExtraInfo */ + DWORD lParam; /* Next four values set by SendMessage */ WORD wParam; WORD msg; WORD hWnd; WORD wPostQMsg; /* PostQuitMessage flag */ WORD wExitCode; /* PostQuitMessage exit code */ WORD InSendMessageHandle; /* Handle of task that sent a message */ + WORD wPaintCount; /* Number of WM_PAINT needed */ + WORD wTimerCount; /* Number of timers for this application */ WORD tempStatus; /* State reset by GetQueueStatus */ WORD status; /* Queue state */ QMSG messages[1]; /* Queue messages */ } MESSAGEQUEUE; + +extern void MSG_IncPaintCount( HANDLE hQueue ); +extern void MSG_DecPaintCount( HANDLE hQueue ); +extern void MSG_IncTimerCount( HANDLE hQueue ); +extern void MSG_DecTimerCount( HANDLE hQueue ); +extern BOOL MSG_CreateSysMsgQueue( int size ); +extern void hardware_event(HWND hwnd, WORD message, WORD wParam, LONG lParam, + WORD xPos, WORD yPos, DWORD time, DWORD extraInfo); + #endif /* MESSAGE_H */ diff --git a/include/neexe.h b/include/neexe.h index e610ba45ad0..58e67ccc275 100644 --- a/include/neexe.h +++ b/include/neexe.h @@ -136,7 +136,9 @@ struct relocation_entry_s /* Used by Windows 3.0 programs, like when getting selector to be given to makeprocinst */ #define NE_RELTYPE_INT1 4 -#define NE_RELTYPE_OFFSET16 5 +#define NE_RELTYPE_ORDINALADD 5 +#define NE_RELTYPE_NAMEADD 6 + /* * DOS PSP */ diff --git a/include/prototypes.h b/include/prototypes.h index c1c7bf9f483..69fc97bd4a9 100644 --- a/include/prototypes.h +++ b/include/prototypes.h @@ -10,6 +10,7 @@ #include "neexe.h" #include "segmem.h" #include "wine.h" +#include "int21.h" extern struct segment_descriptor_s * CreateSelectors(struct w_files *); @@ -33,5 +34,15 @@ extern int CurrentNEFile; extern do_int1A(struct sigcontext_struct * context); extern do_int21(struct sigcontext_struct * context); -#endif /* PROTOTYPES_H */ +extern void GetUnixDirName(char *rootdir, char *name); +extern char *GetDirectUnixFileName(char *dosfilename); +extern char *GetUnixFileName(char *dosfilename); +extern char *FindFile(char *buffer, int buflen, char *rootname, char **extensions, char *path); +extern char *WineIniFileName(void); +extern char *WinIniFileName(void); +extern struct dosdirent *DOS_opendir(char *dosdirname); +extern struct dosdirent *DOS_readdir(struct dosdirent *de); +extern void DOS_closedir(struct dosdirent *de); + +#endif /* PROTOTYPES_H */ diff --git a/include/segmem.h b/include/segmem.h index ea9f8512402..437dfd98c38 100644 --- a/include/segmem.h +++ b/include/segmem.h @@ -6,6 +6,12 @@ #ifndef SEGMEM_H #define SEGMEM_H +#ifdef __linux__ +#define HAVE_IPC +#include +#include +#endif + /* * Array to track selector allocation. */ @@ -15,21 +21,32 @@ extern unsigned short SelectorMap[MAX_SELECTORS]; +#ifdef HAVE_IPC +#define SAFEMAKEPTR(s, o) (((int) (s) << 16) | ((o) & 0xffff)) +#define FIXPTR(p) (p) +#else #define SAFEMAKEPTR(s, o) \ (((int) SelectorMap[SelectorMap[(s) >> 3] & SELECTOR_INDEXMASK] << 19) \ | 0x70000 | ((o) & 0xffff)) +#define FIXPTR(p) SAFEMAKEPTR((unsigned long) (p) >> 16, (p)) +#endif /* * Structure to hold info about each selector we create. */ -struct segment_descriptor_s +typedef struct segment_descriptor_s { void *base_addr; /* Pointer to segment in flat memory */ unsigned int length; /* Length of segment */ unsigned int flags; /* Segment flags (see neexe.h and below)*/ unsigned short selector; /* Selector used to access this segment */ -}; + unsigned short owner; /* Handle of owner program */ + unsigned char type; /* DATA or CODE */ +#ifdef HAVE_IPC + key_t shm_key; /* Shared memory key or IPC_PRIVATE */ +#endif +} SEGDESC; /* * Additional flags diff --git a/include/user.h b/include/user.h index 3db21d2dc82..3b9867db86b 100644 --- a/include/user.h +++ b/include/user.h @@ -15,6 +15,8 @@ extern MDESC *USER_Heap; #define USER_HEAP_ALLOC(f,size) ((int)HEAP_Alloc(&USER_Heap,f,size) & 0xffff) +#define USER_HEAP_REALLOC(handle,size,f) ((int)HEAP_ReAlloc(&USER_Heap, \ + USER_HEAP_ADDR(handle),size,f) & 0xffff) #define USER_HEAP_ADDR(handle) ((void *)(handle|((int)USER_Heap & 0xffff0000))) #define USER_HEAP_FREE(handle) (HEAP_Free(&USER_Heap,USER_HEAP_ADDR(handle))) diff --git a/include/win.h b/include/win.h index 894da98ff12..b90675db260 100644 --- a/include/win.h +++ b/include/win.h @@ -8,8 +8,6 @@ #define WIN_H #include -#include -#include #include "windows.h" #include "menu.h" @@ -26,31 +24,41 @@ typedef struct tagWND HWND hwndOwner; /* Window owner */ HCLASS hClass; /* Window class */ HANDLE hInstance; /* Window hInstance (from CreateWindow) */ - RECT rectClient; /* Window client area screen coords */ - RECT rectWindow; /* Window whole area screen coords */ + RECT rectClient; /* Client area rel. to parent client area */ + RECT rectWindow; /* Whole window rel. to parent client area */ + HANDLE hmemTaskQ; /* Task queue global memory handle */ HRGN hrgnUpdate; /* Update region */ HWND hwndLastActive; /* Last active popup hwnd */ FARPROC lpfnWndProc; /* Window procedure */ DWORD dwStyle; /* Window style (from CreateWindow) */ DWORD dwExStyle; /* Extended style (from CreateWindowEx) */ - HDC hdc; /* Window DC (if CS_OWNDC) */ + HANDLE hdce; /* Window DCE (if CS_OWNDC or CS_CLASSDC) */ HMENU hmenuSystem; /* System menu */ + HCURSOR hCursor; /* Window Current Cursor */ + HWND hWndVScroll; /* Verti. ScrollBar handle of the window */ + HWND hWndHScroll; /* Horiz. ScrollBar handle of the window */ WORD wIDmenu; /* ID or hmenu (from CreateWindow) */ HANDLE hText; /* Handle of window text */ WORD flags; /* Misc. flags */ Widget shellWidget; /* For top-level windows */ Widget winWidget; /* For all windows */ Widget compositeWidget;/* For top-level windows */ + Window window; /* X window */ LPMENUBAR menuBarPtr; /* Menu bar */ WORD wExtra[1]; /* Window extra bytes */ } WND; /* WND flags values */ -#define WIN_ERASE_UPDATERGN 1 /* Update region needs erasing */ - +#define WIN_ERASE_UPDATERGN 0x01 /* Update region needs erasing */ +#define WIN_NEEDS_BEGINPAINT 0x02 /* WM_PAINT sent to window */ +#define WIN_GOT_SIZEMSG 0x04 /* WM_SIZE has been sent to the window */ +#define WIN_OWN_DC 0x08 /* Win class has style CS_OWNDC */ +#define WIN_CLASS_DC 0x10 /* Win class has style CS_CLASSDC */ /* Window functions */ -WND * WIN_FindWndPtr( HWND hwnd ); +WND *WIN_FindWndPtr( HWND hwnd ); +BOOL WIN_UnlinkWindow( HWND hwnd ); +BOOL WIN_LinkWindow( HWND hwnd, HWND hwndInsertAfter ); HWND WIN_FindWinToRepaint( HWND hwnd ); diff --git a/include/windows.h b/include/windows.h index 9d3eaf3ba76..ae37d54da4e 100644 --- a/include/windows.h +++ b/include/windows.h @@ -64,7 +64,8 @@ typedef int *LPCATCHBUF; #define LOWORD(l) ((WORD)(l)) #define HIWORD(l) ((WORD)((DWORD)(l) >> 16)) -#define MAKELONG(low, high) ((LONG)(((WORD)(low)) | (((DWORD)((WORD)(high))) << 16))) +#define MAKELONG(low, high) ((LONG)(((WORD)(low)) | \ + (((DWORD)((WORD)(high))) << 16))) #ifndef max #define max(a,b) (((a) > (b)) ? (a) : (b)) @@ -208,6 +209,36 @@ typedef struct { #define GW_OWNER 4 #define GW_CHILD 5 + /* WM_WINDOWPOSCHANGING/CHANGED struct */ +typedef struct +{ + HWND hwnd; + HWND hwndInsertAfter; + int x; + int y; + int cx; + int cy; + UINT flags; +} WINDOWPOS; + + /* WM_NCCALCSIZE parameter structure */ +typedef struct +{ + RECT rgrc[3]; + WINDOWPOS FAR* lppos; +} NCCALCSIZE_PARAMS; + + /* WM_NCCALCSIZE return flags */ +#define WVR_ALIGNTOP 0x0010 +#define WVR_ALIGNLEFT 0x0020 +#define WVR_ALIGNBOTTOM 0x0040 +#define WVR_ALIGNRIGHT 0x0080 +#define WVR_HREDRAW 0x0100 +#define WVR_VREDRAW 0x0200 +#define WVR_REDRAW (WVR_HREDRAW | WVR_VREDRAW) +#define WVR_VALIDRECTS 0x0400 + + /* Dialogs */ /* cbWndExtra bytes for dialog class */ @@ -275,6 +306,9 @@ typedef struct tagMSG typedef WORD ATOM; +#define MAKEINTATOM(i) ((LPCSTR)MAKELP(0, (i))) + + /* Raster operations */ #define R2_BLACK 1 @@ -558,6 +592,19 @@ typedef struct tagLOGPEN #define RGN_DIFF 4 #define RGN_COPY 5 + /* Device contexts */ + +/* GetDCEx flags */ +#define DCX_WINDOW 0x00000001 +#define DCX_CACHE 0x00000002 +#define DCX_CLIPCHILDREN 0x00000008 +#define DCX_CLIPSIBLINGS 0x00000010 +#define DCX_PARENTCLIP 0x00000020 +#define DCX_EXCLUDERGN 0x00000040 +#define DCX_INTERSECTRGN 0x00000080 +#define DCX_LOCKWINDOWUPDATE 0x00000400 +#define DCX_USESTYLE 0x00010000 + /* Polygon modes */ #define ALTERNATE 1 #define WINDING 2 @@ -797,18 +844,6 @@ typedef struct tagBITMAPCOREHEADER #define DIB_PAL_COLORS 1 #define CBM_INIT 4 - -/* Unimplemented structs */ -typedef struct { - BYTE Id; /* much more .... */ -} DCB; - -typedef struct { - BYTE i; /* much more .... */ -} COMSTAT; - - - typedef struct { BYTE i; /* much more .... */ } KANJISTRUCT; @@ -842,6 +877,160 @@ typedef OFSTRUCT *LPOFSTRUCT; #define OF_SHARE_EXCLUSIVE 0x0010 #define OF_VERIFY 0x0400 +#define DRIVE_REMOVABLE 2 +#define DRIVE_FIXED 3 +#define DRIVE_REMOTE 4 + +#define HFILE_ERROR -1 + +#define DDL_READWRITE 0x0000 +#define DDL_READONLY 0x0001 +#define DDL_HIDDEN 0x0002 +#define DDL_SYSTEM 0x0004 +#define DDL_DIRECTORY 0x0010 +#define DDL_ARCHIVE 0x0020 + +#define DDL_POSTMSGS 0x2000 +#define DDL_DRIVES 0x4000 +#define DDL_EXCLUSIVE 0x8000 + +/* comm */ + +#define CBR_110 0xFF10 +#define CBR_300 0xFF11 +#define CBR_600 0xFF12 +#define CBR_1200 0xFF13 +#define CBR_2400 0xFF14 +#define CBR_4800 0xFF15 +#define CBR_9600 0xFF16 +#define CBR_14400 0xFF17 +#define CBR_19200 0xFF18 +#define CBR_38400 0xFF1B +#define CBR_56000 0xFF1F +#define CBR_128000 0xFF23 +#define CBR_256000 0xFF27 + +#define NOPARITY 0 +#define ODDPARITY 1 +#define EVENPARITY 2 +#define MARKPARITY 3 +#define SPACEPARITY 4 +#define ONESTOPBIT 0 +#define ONE5STOPBITS 1 +#define TWOSTOPBITS 2 +#define IGNORE 0 +#define INFINITE 0xFFFF + +#define CE_RXOVER 0x0001 +#define CE_OVERRUN 0x0002 +#define CE_RXPARITY 0x0004 +#define CE_FRAME 0x0008 +#define CE_BREAK 0x0010 +#define CE_CTSTO 0x0020 +#define CE_DSRTO 0x0040 +#define CE_RLSDTO 0x0080 +#define CE_TXFULL 0x0100 +#define CE_PTO 0x0200 +#define CE_IOE 0x0400 +#define CE_DNS 0x0800 +#define CE_OOP 0x1000 +#define CE_MODE 0x8000 + +#define IE_BADID -1 +#define IE_OPEN -2 +#define IE_NOPEN -3 +#define IE_MEMORY -4 +#define IE_DEFAULT -5 +#define IE_HARDWARE -10 +#define IE_BYTESIZE -11 +#define IE_BAUDRATE -12 + +#define EV_RXCHAR 0x0001 +#define EV_RXFLAG 0x0002 +#define EV_TXEMPTY 0x0004 +#define EV_CTS 0x0008 +#define EV_DSR 0x0010 +#define EV_RLSD 0x0020 +#define EV_BREAK 0x0040 +#define EV_ERR 0x0080 +#define EV_RING 0x0100 +#define EV_PERR 0x0200 +#define EV_CTSS 0x0400 +#define EV_DSRS 0x0800 +#define EV_RLSDS 0x1000 +#define EV_RINGTE 0x2000 +#define EV_RingTe EV_RINGTE + +#define SETXOFF 1 +#define SETXON 2 +#define SETRTS 3 +#define CLRRTS 4 +#define SETDTR 5 +#define CLRDTR 6 +#define RESETDEV 7 +#define GETMAXLPT 8 +#define GETMAXCOM 9 +#define GETBASEIRQ 10 + +#define CN_RECEIVE 0x0001 +#define CN_TRANSMIT 0x0002 +#define CN_EVENT 0x0004 + +typedef struct tagDCB +{ + BYTE Id; + UINT BaudRate; + BYTE ByteSize; + BYTE Parity; + BYTE StopBits; + UINT RlsTimeout; + UINT CtsTimeout; + UINT DsrTimeout; + + UINT fBinary :1; + UINT fRtsDisable :1; + UINT fParity :1; + UINT fOutxCtsFlow :1; + UINT fOutxDsrFlow :1; + UINT fDummy :2; + UINT fDtrDisable :1; + + UINT fOutX :1; + UINT fInX :1; + UINT fPeChar :1; + UINT fNull :1; + UINT fChEvt :1; + UINT fDtrflow :1; + UINT fRtsflow :1; + UINT fDummy2 :1; + + char XonChar; + char XoffChar; + UINT XonLim; + UINT XoffLim; + char PeChar; + char EofChar; + char EvtChar; + UINT TxDelay; +} DCB; +typedef DCB FAR* LPDCB; + +typedef struct tagCOMSTAT +{ + BYTE status; + UINT cbInQue; + UINT cbOutQue; +} COMSTAT; + +#define CSTF_CTSHOLD 0x01 +#define CSTF_DSRHOLD 0x02 +#define CSTF_RLSDHOLD 0x04 +#define CSTF_XOFFHOLD 0x08 +#define CSTF_XOFFSENT 0x10 +#define CSTF_EOF 0x20 +#define CSTF_TXIM 0x40 + +/* */ typedef struct { @@ -903,8 +1092,12 @@ enum { WM_NULL, WM_CREATE, WM_DESTROY, WM_MOVE, WM_UNUSED0, WM_SIZE, WM_ACTIVATE WM_DELETEITEM, WM_VKEYTOITEM, WM_CHARTOITEM, WM_SETFONT, WM_GETFONT }; +#define WM_WINDOWPOSCHANGING 0x0046 +#define WM_WINDOWPOSCHANGED 0x0047 + #define WM_NCCREATE 0x0081 #define WM_NCDESTROY 0x0082 +#define WM_NCCALCSIZE 0x0083 #define WM_GETDLGCODE 0x0087 @@ -1008,6 +1201,12 @@ enum { SW_HIDE, SW_SHOWNORMAL, SW_NORMAL, SW_SHOWMINIMIZED, SW_SHOWMAXIMIZED, #define HWND_TOPMOST ((HWND)-1) #define HWND_NOTOPMOST ((HWND)-2) +/* Flags for TrackPopupMenu */ +#define TPM_LEFTBUTTON 0x0000 +#define TPM_RIGHTBUTTON 0x0002 +#define TPM_LEFTALIGN 0x0000 +#define TPM_CENTERALIGN 0x0004 +#define TPM_RIGHTALIGN 0x0008 #define MF_INSERT 0 #define MF_CHANGE 0x0080 @@ -1016,7 +1215,7 @@ enum { SW_HIDE, SW_SHOWNORMAL, SW_NORMAL, SW_SHOWMINIMIZED, SW_SHOWMAXIMIZED, #define MF_REMOVE 0x1000 #define MF_BYCOMMAND 0 #define MF_BYPOSITION 0x0400 -#define MF_SEPARATOR 0x080 +#define MF_SEPARATOR 0x0800 #define MF_ENABLED 0 #define MF_GRAYED 0x0001 #define MF_DISABLED 0x0002 @@ -1492,6 +1691,80 @@ typedef struct tagCOMPAREITEMSTRUCT typedef COMPAREITEMSTRUCT NEAR* PCOMPAREITEMSTRUCT; typedef COMPAREITEMSTRUCT FAR* LPCOMPAREITEMSTRUCT; +/* Virtual key codes */ +#define VK_LBUTTON 0x01 +#define VK_RBUTTON 0x02 +#define VK_CANCEL 0x03 +#define VK_MBUTTON 0x04 +#define VK_BACK 0x08 +#define VK_TAB 0x09 +#define VK_CLEAR 0x0C +#define VK_RETURN 0x0D +#define VK_SHIFT 0x10 +#define VK_CONTROL 0x11 +#define VK_MENU 0x12 +#define VK_PAUSE 0x13 +#define VK_CAPITAL 0x14 +#define VK_ESCAPE 0x1B +#define VK_SPACE 0x20 +#define VK_PRIOR 0x21 +#define VK_NEXT 0x22 +#define VK_END 0x23 +#define VK_HOME 0x24 +#define VK_LEFT 0x25 +#define VK_UP 0x26 +#define VK_RIGHT 0x27 +#define VK_DOWN 0x28 +#define VK_SELECT 0x29 +#define VK_PRINT 0x2A +#define VK_EXECUTE 0x2B +#define VK_SNAPSHOT 0x2C +#define VK_INSERT 0x2D +#define VK_DELETE 0x2E +#define VK_HELP 0x2F +#define VK_NUMPAD0 0x60 +#define VK_NUMPAD1 0x61 +#define VK_NUMPAD2 0x62 +#define VK_NUMPAD3 0x63 +#define VK_NUMPAD4 0x64 +#define VK_NUMPAD5 0x65 +#define VK_NUMPAD6 0x66 +#define VK_NUMPAD7 0x67 +#define VK_NUMPAD8 0x68 +#define VK_NUMPAD9 0x69 +#define VK_MULTIPLY 0x6A +#define VK_ADD 0x6B +#define VK_SEPARATOR 0x6C +#define VK_SUBTRACT 0x6D +#define VK_DECIMAL 0x6E +#define VK_DIVIDE 0x6F +#define VK_F1 0x70 +#define VK_F2 0x71 +#define VK_F3 0x72 +#define VK_F4 0x73 +#define VK_F5 0x74 +#define VK_F6 0x75 +#define VK_F7 0x76 +#define VK_F8 0x77 +#define VK_F9 0x78 +#define VK_F10 0x79 +#define VK_F11 0x7A +#define VK_F12 0x7B +#define VK_F13 0x7C +#define VK_F14 0x7D +#define VK_F15 0x7E +#define VK_F16 0x7F +#define VK_F17 0x80 +#define VK_F18 0x81 +#define VK_F19 0x82 +#define VK_F20 0x83 +#define VK_F21 0x84 +#define VK_F22 0x85 +#define VK_F23 0x86 +#define VK_F24 0x87 +#define VK_NUMLOCK 0x90 +#define VK_SCROLL 0x91 + #define LMEM_MOVEABLE 0x0002 @@ -1719,6 +1992,7 @@ Fa(WORD,EnumClipboardFormats,WORD,a) Fa(WORD,FreeSelector,WORD,a) Fa(WORD,GetDriveType,int,a) Fa(WORD,GetMenuItemCount,HMENU,a) +Fa(WORD,GetTaskQueue,HANDLE,a) Fa(WORD,GetTextAlign,HDC,a) Fa(WORD,GlobalFlags,HANDLE,a) Fa(WORD,GlobalPageLock,HANDLE,a) @@ -1726,9 +2000,9 @@ Fa(WORD,GlobalPageUnlock,HANDLE,a) Fa(WORD,LocalCompact,WORD,a) Fa(WORD,LocalFlags,HANDLE,a) Fa(WORD,LocalSize,HANDLE,a) -Fa(WORD,RealizePalette,HDC,a) -Fa(WORD,RegisterClipboardFormat,LPSTR,a) -Fa(WORD,RegisterWindowMessage,LPSTR,a) +Fa(int,RealizePalette,HDC,a) +Fa(WORD,RegisterClipboardFormat,LPCSTR,a) +Fa(WORD,RegisterWindowMessage,LPCSTR,a) Fa(WORD,SetHandleCount,WORD,a) Fa(WORD,VkKeyScan,WORD,a) Fa(char NEAR*,LocalLock,HANDLE,a) @@ -1872,6 +2146,7 @@ Fb(WORD,IsDlgButtonChecked,HWND,a,WORD,b) Fb(WORD,LocalShrink,HANDLE,a,WORD,b) Fb(WORD,MapVirtualKey,WORD,a,WORD,b) Fb(WORD,SetSystemPaletteUse,HDC,a,WORD,b) +Fb(WORD,SetTaskQueue,HANDLE,a,HANDLE,b) Fb(WORD,SetTextAlign,HDC,a,WORD,b) Fb(WORD,SizeofResource,HANDLE,a,HANDLE,b) Fb(WORD,WinExec,LPSTR,a,WORD,b) @@ -1881,7 +2156,7 @@ Fb(int,BuildCommDCB,LPSTR,a,DCB*,b) Fb(int,ConvertRequest,HWND,a,LPKANJISTRUCT,b) Fb(void,CopyRect,LPRECT,a,LPRECT,b) Fb(int,EnumProps,HWND,a,FARPROC,b) -Fb(int,EscapeCommFunction,int,a,int,b) +Fb(LONG,EscapeCommFunction,int,a,int,b) Fb(int,ExcludeUpdateRgn,HDC,a,HWND,b) Fb(int,FlushComm,int,a,int,b) Fb(int,GetClipBox,HDC,a,LPRECT,b) @@ -1910,8 +2185,8 @@ Fb(void,MapDialogRect,HWND,a,LPRECT,b) Fb(void,ProfSampRate,int,a,int,b) Fb(void,ProfSetup,int,a,int,b) Fb(void,ScreenToClient,HWND,a,LPPOINT,b) -Fb(void,SetCaretPos,int,a,int,b) -Fb(void,SetCursorPos,int,a,int,b) +Fb(void,SetCaretPos,short,a,short,b) +Fb(void,SetCursorPos,short,a,short,b) Fb(void,SetWindowText,HWND,a,LPSTR,b) Fb(void,ShowOwnedPopups,HWND,a,BOOL,b) Fb(void,Throw,LPCATCHBUF,a,int,b) @@ -1963,6 +2238,7 @@ Fc(HANDLE,GlobalReAlloc,HANDLE,a,DWORD,b,WORD,c) Fc(HANDLE,LocalReAlloc,HANDLE,a,WORD,b,WORD,c) Fc(HBITMAP,CreateCompatibleBitmap,HDC,a,short,b,short,c) Fc(HBITMAP,CreateDiscardableBitmap,HDC,a,short,b,short,c) +Fc(HDC,GetDCEx,HWND,a,HRGN,b,DWORD,c) Fc(HPALETTE,SelectPalette,HDC,a,HPALETTE,b,BOOL,c) Fc(HPEN,CreatePen,short,a,short,b,COLORREF,c) Fc(HRGN,CreatePolygonRgn,LPPOINT,a,short,b,short,c) @@ -1985,7 +2261,7 @@ Fb(WORD,SetRelAbs,HDC,a,WORD,b) Fb(WORD,SetROP2,HDC,a,WORD,b) Fb(WORD,SetStretchBltMode,HDC,a,WORD,b) Fc(int,FrameRect,HDC,a,LPRECT,b,HBRUSH,c) -Fc(int,GetClassName,HWND,a,LPSTR,b,int,c) +Fc(int,GetClassName,HWND,a,LPSTR,b,short,c) Fc(int,GetClipboardFormatName,WORD,a,LPSTR,b,int,c) Fc(int,GetEnvironment,LPSTR,a,LPSTR,b,WORD,c) Fc(int,GetInstanceData,HANDLE,a,NPSTR,b,int,c) @@ -2066,7 +2342,7 @@ Fd(int,DialogBoxIndirect,HANDLE,a,HANDLE,b,HWND,c,FARPROC,d) Fd(int,EnumFonts,HDC,a,LPSTR,b,FARPROC,c,LPSTR,d) Fd(int,EnumObjects,HDC,a,int,b,FARPROC,c,LPSTR,d) Fd(int,GetDlgItemText,HWND,a,WORD,b,LPSTR,c,WORD,d) -Fd(int,GetTempFileName,BYTE,a,LPSTR,b,WORD,c,LPSTR,d) +Fd(int,GetTempFileName,BYTE,a,LPCSTR,b,UINT,c,LPSTR,d) Fd(int,LoadString,HANDLE,a,WORD,b,LPSTR,c,int,d) Fd(int,MessageBox,HWND,a,LPSTR,b,LPSTR,c,WORD,d) Fd(int,SetScrollPos,HWND,a,int,b,int,c,BOOL,d) @@ -2074,9 +2350,10 @@ Fd(int,SetVoiceNote,int,a,int,b,int,c,int,d) Fd(void,AdjustWindowRectEx,LPRECT,a,LONG,b,BOOL,c,DWORD,d) Fd(void,AnimatePalette,HPALETTE,a,WORD,b,WORD,c,LPPALETTEENTRY,d) Fd(void,CheckRadioButton,HWND,a,WORD,b,WORD,c,WORD,d) -Fd(void,CreateCaret,HWND,a,HBITMAP,b,int,c,int,d) +Fd(void,CreateCaret,HWND,a,HBITMAP,b,short,c,short,d) Fd(void,FillWindow,HWND,a,HWND,b,HDC,c,HBRUSH,d) Fd(void,GetScrollRange,HWND,a,int,b,LPINT,c,LPINT,d) +Fd(void,MapWindowPoints,HWND,a,HWND,b,LPPOINT,c,WORD,d) Fd(void,PlayMetaFileRecord,HDC,a,LPHANDLETABLE,b,LPMETARECORD,c,WORD,d) Fd(void,SetDlgItemInt,HWND,a,WORD,b,WORD,c,BOOL,d) Fe(BOOL,Rectangle,HDC,a,int,xLeft,int,yTop,int,xRight,int,yBottom) @@ -2122,17 +2399,17 @@ Ff(HBITMAP,CreateDIBitmap,HDC,a,LPBITMAPINFOHEADER,b,DWORD,c,LPSTR,d,LPBITMAPINF Ff(HRGN,CreateRoundRectRgn,short,a,short,b,short,c,short,d,short,e,short,f) Ff(short,GetPrivateProfileString,LPSTR,a,LPSTR,b,LPSTR,c,LPSTR,d,short,e,LPSTR,f) Ff(void,LineDDA,short,a,short,b,short,c,short,d,FARPROC,e,long,f) -Ff(void,MoveWindow,HWND,a,short,b,short,c,short,d,short,e,BOOL,f) +Ff(BOOL,MoveWindow,HWND,a,short,b,short,c,short,d,short,e,BOOL,f) Ff(BOOL,ScaleViewportExtEx,HDC,a,short,b,short,c,short,d,short,e,LPSIZE,f) Ff(BOOL,ScaleWindowExtEx,HDC,a,short,b,short,c,short,d,short,e,LPSIZE,f) Fg(BOOL,RoundRect,HDC,a,short,b,short,c,short,d,short,e,short,f,short,g) Fg(BOOL,ScrollDC,HDC,a,short,b,short,c,LPRECT,d,LPRECT,e,HRGN,f,LPRECT,g) -Fg(BOOL,TrackPopupMenu,HMENU,a,WORD,b,int,c,int,d,int,e,HWND,f,LPRECT,g) -Fg(HCURSOR,CreateCursor,HANDLE,a,int,b,int,c,int,d,int,e,LPSTR,f,LPSTR,g) +Fg(BOOL,TrackPopupMenu,HMENU,a,WORD,b,short,c,short,d,short,e,HWND,f,LPRECT,g) +Fg(HCURSOR,CreateCursor,HANDLE,a,short,b,short,c,short,d,short,e,LPSTR,f,LPSTR,g) Fg(HICON,CreateIcon,HANDLE,a,int,b,int,c,BYTE,d,BYTE,e,LPSTR,f,LPSTR,g) Fg(int,GetDIBits,HDC,a,HANDLE,a2,WORD,b,WORD,c,LPSTR,d,LPBITMAPINFO,e,WORD,f) Fg(int,SetDIBits,HDC,a,HANDLE,a2,WORD,b,WORD,c,LPSTR,d,LPBITMAPINFO,e,WORD,f) -Fg(void,SetWindowPos,HWND,a,HWND,b,short,c,short,d,short,e,short,f,WORD,g) +Fg(BOOL,SetWindowPos,HWND,a,HWND,b,short,c,short,d,short,e,short,f,WORD,g) Fh(BOOL,ExtTextOut,HDC,a,int,b,int,c,WORD,d,LPRECT,e,LPSTR,f,WORD,g,LPINT,h) Fh(HANDLE,DeferWindowPos,HANDLE,hWinPosInfo,HWND,hWnd,HWND,hWndInsertAfter,int,x,int,y,int,cx,int,cy,WORD,wFlags) Fh(LONG,TabbedTextOut,HDC,a,int,b,int,c,LPSTR,d,int,e,int,f,LPINT,g,int,h) diff --git a/include/wine.h b/include/wine.h index 6a602e9da40..dbc034cd806 100644 --- a/include/wine.h +++ b/include/wine.h @@ -22,9 +22,14 @@ extern struct w_files * wine_files; extern char *GetFilenameFromInstance(unsigned short instance); extern struct w_files *GetFileInfo(unsigned short instance); -extern char *FindFileInPath(char *buffer, int buflen, char *rootname, - char **extensions, char *path); -extern char *GetSystemIniFilename(void); +extern char *WineIniFileName(void); +extern char *WinIniFileName(void); + +#define MAX_DOS_DRIVES 26 + +#define WINE_INI WineIniFileName() +#define WIN_INI WinIniFileName() + #ifdef linux struct sigcontext_struct { unsigned short sc_gs, __gsh; diff --git a/loader/Imakefile b/loader/Imakefile new file mode 100644 index 00000000000..9c5130a48a6 --- /dev/null +++ b/loader/Imakefile @@ -0,0 +1,35 @@ +#include "../Wine.tmpl" + +MODULE = loader + +SRCS = \ + dump.c \ + files.c \ + ldt.c \ + ldtlib.c \ + resource.c \ + selector.c \ + signal.c \ + library.c \ + wine.c \ + cursor.c + +OBJS = \ + dump.o \ + files.o \ + ldt.o \ + ldtlib.o \ + resource.o \ + selector.o \ + signal.o \ + library.o \ + wine.o \ + cursor.o + +WineRelocatableTarget($(TOP)/$(MODULE),,$(OBJS)) +DependTarget() +CleanTarget() + +includes:: + +install:: diff --git a/loader/Makefile b/loader/Makefile index 873a6acd59d..083d8f68a65 100644 --- a/loader/Makefile +++ b/loader/Makefile @@ -1,7 +1,7 @@ CFLAGS=$(COPTS) $(DEBUGOPTS) -I../include -OBJS=dump.o files.o ldt.o ldtlib.o resource.o selector.o signal.o int1a.o \ - int21.o wine.o library.o +OBJS=dump.o ldt.o ldtlib.o resource.o selector.o signal.o library.o \ + wine.o cursor.o default: loader.o diff --git a/loader/cursor.c b/loader/cursor.c new file mode 100644 index 00000000000..039c1c35bf9 --- /dev/null +++ b/loader/cursor.c @@ -0,0 +1,385 @@ +/* + * WINE +*/ +static char Copyright[] = "Copyright Martin Ayotte, 1993"; + +/* +#define DEBUG_CURSOR +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "prototypes.h" +#include "windows.h" +#include "win.h" +#include "gdi.h" +#include "wine.h" +#include "cursor.h" + +static int ShowCursCount = 0; +static HCURSOR hActiveCursor; +static HCURSOR hEmptyCursor = 0; +RECT ClipCursorRect; +extern HINSTANCE hSysRes; +extern Window winHasCursor; + +/********************************************************************** + * LoadCursor [USER.173] + */ +HCURSOR LoadCursor(HANDLE instance, LPSTR cursor_name) +{ + XColor bkcolor; + XColor fgcolor; + HCURSOR hCursor; + HANDLE rsc_mem; + WORD *lp; + CURSORDESCRIP *lpcurdesc; + CURSORALLOC *lpcur; + BITMAP BitMap; + HBITMAP hBitMap; + HDC hMemDC; + HDC hdc; + int i, j, image_size; +#ifdef DEBUG_RESOURCE + printf("LoadCursor: instance = %04x, name = %08x\n", + instance, cursor_name); +#endif + hCursor = GlobalAlloc(GMEM_MOVEABLE, sizeof(CURSORALLOC) + 1024L); + if (hCursor == (HCURSOR)NULL) return 0; +#ifdef DEBUG_CURSOR + printf("LoadCursor Alloc hCursor=%X\n", hCursor); +#endif + lpcur = (CURSORALLOC *)GlobalLock(hCursor); + memset(lpcur, 0, sizeof(CURSORALLOC)); + if (instance == (HANDLE)NULL) { + instance = hSysRes; + switch((LONG)cursor_name) { + case IDC_ARROW: + lpcur->xcursor = XCreateFontCursor(XT_display, XC_top_left_arrow); + GlobalUnlock(hCursor); + return hCursor; + case IDC_CROSS: + lpcur->xcursor = XCreateFontCursor(XT_display, XC_crosshair); + GlobalUnlock(hCursor); + return hCursor; + case IDC_IBEAM: + lpcur->xcursor = XCreateFontCursor(XT_display, XC_xterm); + GlobalUnlock(hCursor); + return hCursor; + case IDC_WAIT: + lpcur->xcursor = XCreateFontCursor(XT_display, XC_watch); + GlobalUnlock(hCursor); + return hCursor; + default: + break; + } + } + if (!(hdc = GetDC(GetDesktopWindow()))) return 0; + rsc_mem = RSC_LoadResource(instance, cursor_name, NE_RSCTYPE_GROUP_CURSOR, + &image_size); + if (rsc_mem == (HANDLE)NULL) { + printf("LoadCursor / Cursor %08X not Found !\n", cursor_name); + ReleaseDC(GetDesktopWindow(), hdc); + return 0; + } + lp = (WORD *)GlobalLock(rsc_mem); + if (lp == NULL) { + GlobalFree(rsc_mem); + ReleaseDC(GetDesktopWindow(), hdc); + return 0; + } + lpcurdesc = (CURSORDESCRIP *)(lp + 3); +#ifdef DEBUG_CURSOR + printf("LoadCursor / image_size=%d\n", image_size); + printf("LoadCursor / curReserved=%X\n", *lp); + printf("LoadCursor / curResourceType=%X\n", *(lp + 1)); + printf("LoadCursor / curResourceCount=%X\n", *(lp + 2)); + printf("LoadCursor / cursor Width=%d\n", (int)lpcurdesc->Width); + printf("LoadCursor / cursor Height=%d\n", (int)lpcurdesc->Height); + printf("LoadCursor / cursor curXHotspot=%d\n", (int)lpcurdesc->curXHotspot); + printf("LoadCursor / cursor curYHotspot=%d\n", (int)lpcurdesc->curYHotspot); + printf("LoadCursor / cursor curDIBSize=%lX\n", (DWORD)lpcurdesc->curDIBSize); + printf("LoadCursor / cursor curDIBOffset=%lX\n", (DWORD)lpcurdesc->curDIBOffset); +#endif + lpcur->descriptor = *lpcurdesc; + GlobalUnlock(rsc_mem); + GlobalFree(rsc_mem); + rsc_mem = RSC_LoadResource(instance, + MAKEINTRESOURCE(lpcurdesc->curDIBOffset), + NE_RSCTYPE_CURSOR, &image_size); + if (rsc_mem == (HANDLE)NULL) { + printf("LoadCursor / Cursor %08X Bitmap not Found !\n", cursor_name); + ReleaseDC(GetDesktopWindow(), hdc); + return 0; + } + lp = (WORD *)GlobalLock(rsc_mem); + if (lp == NULL) { + GlobalFree(rsc_mem); + ReleaseDC(GetDesktopWindow(), hdc); + return 0; + } + lp += 2; + for (j = 0; j < 16; j++) + printf("%04X ", *(lp + j)); +/* + if (*lp == sizeof(BITMAPINFOHEADER)) + lpcur->hBitmap = ConvertInfoBitmap(hdc, (BITMAPINFO *)lp); + else +*/ + lpcur->hBitmap = 0; + lp += sizeof(BITMAP); + for (i = 0; i < 81; i++) { + char temp = *((char *)lp + 162 + i); + *((char *)lp + 162 + i) = *((char *)lp + 324 - i); + *((char *)lp + 324 - i) = temp; + } + lpcur->pixshape = XCreatePixmapFromBitmapData( + XT_display, DefaultRootWindow(XT_display), + ((char *)lp + 211), 32, 32, +/* + lpcurdesc->Width / 2, lpcurdesc->Height / 4, +*/ + WhitePixel(XT_display, DefaultScreen(XT_display)), + BlackPixel(XT_display, DefaultScreen(XT_display)), 1); + lpcur->pixmask = XCreatePixmapFromBitmapData( + XT_display, DefaultRootWindow(XT_display), + ((char *)lp + 211), 32, 32, + WhitePixel(XT_display, DefaultScreen(XT_display)), + BlackPixel(XT_display, DefaultScreen(XT_display)), 1); + memset(&bkcolor, 0, sizeof(XColor)); + memset(&fgcolor, 0, sizeof(XColor)); + bkcolor.pixel = WhitePixel(XT_display, DefaultScreen(XT_display)); + fgcolor.pixel = BlackPixel(XT_display, DefaultScreen(XT_display)); +printf("LoadCursor / before XCreatePixmapCursor !\n"); + lpcur->xcursor = XCreatePixmapCursor(XT_display, + lpcur->pixshape, lpcur->pixmask, + &fgcolor, &bkcolor, lpcur->descriptor.curXHotspot, + lpcur->descriptor.curYHotspot); + GlobalUnlock(rsc_mem); + GlobalFree(rsc_mem); +/* + hCursor = CreateCursor(instance, lpcur->descriptor.curXHotspot, + lpcur->descriptor.curYHotspot, 32, 32, + (LPSTR)lp + 211, , (LPSTR)lp + 211); +*/ + XFreePixmap(XT_display, lpcur->pixshape); + XFreePixmap(XT_display, lpcur->pixmask); + ReleaseDC(GetDesktopWindow(), hdc); + GlobalUnlock(hCursor); + return hCursor; +} + + + +/********************************************************************** + * CreateCursor [USER.406] + */ +HCURSOR CreateCursor(HANDLE instance, short nXhotspot, short nYhotspot, + short nWidth, short nHeight, LPSTR lpANDbitPlane, LPSTR lpXORbitPlane) +{ + XColor bkcolor; + XColor fgcolor; + HCURSOR hCursor; + CURSORALLOC *lpcur; + BITMAP BitMap; + HBITMAP hBitMap; + HDC hMemDC; + HDC hdc; + int i, j; +#ifdef DEBUG_RESOURCE + printf("CreateCursor: inst=%04x nXhotspot=%d nYhotspot=%d nWidth=%d nHeight=%d\n", + nXhotspot, nYhotspot, nWidth, nHeight); + printf("CreateCursor: inst=%04x lpANDbitPlane=%08X lpXORbitPlane=%08X\n", + LPSTR lpANDbitPlane, LPSTR lpXORbitPlane); +#endif + if (!(hdc = GetDC(GetDesktopWindow()))) return 0; + hCursor = GlobalAlloc(GMEM_MOVEABLE, sizeof(CURSORALLOC) + 1024L); + if (hCursor == (HCURSOR)NULL) { + ReleaseDC(GetDesktopWindow(), hdc); + return 0; + } + printf("CreateCursor Alloc hCursor=%X\n", hCursor); + lpcur = (CURSORALLOC *)GlobalLock(hCursor); + memset(lpcur, 0, sizeof(CURSORALLOC)); + lpcur->descriptor.curXHotspot = nXhotspot; + lpcur->descriptor.curYHotspot = nYhotspot; + lpcur->pixshape = XCreatePixmapFromBitmapData( + XT_display, DefaultRootWindow(XT_display), + lpXORbitPlane, nWidth, nHeight, + WhitePixel(XT_display, DefaultScreen(XT_display)), + BlackPixel(XT_display, DefaultScreen(XT_display)), 1); + lpcur->pixmask = XCreatePixmapFromBitmapData( + XT_display, DefaultRootWindow(XT_display), + lpANDbitPlane, nWidth, nHeight, + WhitePixel(XT_display, DefaultScreen(XT_display)), + BlackPixel(XT_display, DefaultScreen(XT_display)), 1); + memset(&bkcolor, 0, sizeof(XColor)); + memset(&fgcolor, 0, sizeof(XColor)); + bkcolor.pixel = WhitePixel(XT_display, DefaultScreen(XT_display)); + fgcolor.pixel = BlackPixel(XT_display, DefaultScreen(XT_display)); + lpcur->xcursor = XCreatePixmapCursor(XT_display, + lpcur->pixshape, lpcur->pixmask, + &fgcolor, &bkcolor, lpcur->descriptor.curXHotspot, + lpcur->descriptor.curYHotspot); + XFreePixmap(XT_display, lpcur->pixshape); + XFreePixmap(XT_display, lpcur->pixmask); + ReleaseDC(GetDesktopWindow(), hdc); + GlobalUnlock(hCursor); + return hCursor; +} + + + +/********************************************************************** + * DestroyCursor [USER.458] + */ +BOOL DestroyCursor(HCURSOR hCursor) +{ + CURSORALLOC *lpcur; + if (hCursor == (HCURSOR)NULL) return FALSE; + lpcur = (CURSORALLOC *)GlobalLock(hCursor); + if (lpcur->hBitmap != (HBITMAP)NULL) DeleteObject(lpcur->hBitmap); + GlobalUnlock(hCursor); + GlobalFree(hCursor); + return TRUE; +} + + +/********************************************************************** + * SetCursor [USER.69] + */ +HCURSOR SetCursor(HCURSOR hCursor) +{ + HDC hDC; + HDC hMemDC; + BITMAP bm; + CURSORALLOC *lpcur; + HCURSOR hOldCursor; + Window root, child; + int rootX, rootY; + int childX, childY; + unsigned int mousebut; +#ifdef DEBUG_CURSOR + printf("SetCursor / hCursor=%04X !\n", hCursor); +#endif + if (hCursor == (HCURSOR)NULL) return FALSE; + lpcur = (CURSORALLOC *)GlobalLock(hCursor); + hOldCursor = hActiveCursor; +#ifdef DEBUG_CURSOR + printf("SetCursor / lpcur->xcursor=%08X !\n", &lpcur->xcursor); + XQueryPointer(XT_display, DefaultRootWindow(XT_display), + &root, &child, &rootX, &rootY, &childX, &childY, &mousebut); + printf("SetCursor / winHasCursor=%08X !\n", winHasCursor); + printf("SetCursor / child=%08X !\n", child); +#endif + if (hActiveCursor != hCursor) ShowCursCount = 0; + if ((ShowCursCount >= 0) & (winHasCursor != 0)) { +/* XUndefineCursor(XT_display, winHasCursor); */ + XDefineCursor(XT_display, winHasCursor, lpcur->xcursor); + } + GlobalUnlock(hCursor); + hActiveCursor = hCursor; + return hOldCursor; +} + + +/********************************************************************** + * SetCursorPos [USER.70] + */ +void SetCursorPos(short x, short y) +{ + Window root, child; + int rootX, rootY; + int childX, childY; + unsigned int mousebut; +#ifdef DEBUG_CURSOR + printf("SetCursorPos // x=%d y=%d\n", x, y); +#endif + XQueryPointer(XT_display, DefaultRootWindow(XT_display), + &root, &child, &rootX, &rootY, &childX, &childY, &mousebut); + XWarpPointer(XT_display, child, root, 0, 0, + DisplayWidth(XT_display, DefaultScreen(XT_display)), + DisplayHeight(XT_display, DefaultScreen(XT_display)), + (int)x, (int)y); +} + + +/********************************************************************** + * GetCursorPos [USER.17] + */ +void GetCursorPos(LPPOINT lpRetPoint) +{ + Window root, child; + int rootX, rootY; + int childX, childY; + unsigned int mousebut; + if (lpRetPoint != NULL) { + XQueryPointer(XT_display, DefaultRootWindow(XT_display), + &root, &child, &rootX, &rootY, &childX, &childY, &mousebut); +#ifdef DEBUG_CURSOR + printf("GetCursorPos // x=%d y=%d\n", rootX, rootY); +#endif + lpRetPoint->x = rootX; + lpRetPoint->y = rootY; + } +} + + +/********************************************************************** + * ShowCursor [USER.71] + */ +int ShowCursor(BOOL bShow) +{ + HCURSOR hCursor; +#ifdef DEBUG_CURSOR + printf("ShowCursor bShow=%d ShowCount=%d !\n", bShow, ShowCursCount); +#endif + if (bShow) + ShowCursCount++; + else + ShowCursCount--; + if (ShowCursCount >= 0) { +/* if (hCursor == (HCURSOR)NULL) */ + hCursor = LoadCursor((HINSTANCE)NULL, IDC_ARROW); + SetCursor(hCursor); + } + else { +/* XUndefineCursor(XT_display, winHasCursor); */ + if (hEmptyCursor == (HCURSOR)NULL) + hEmptyCursor = CreateCursor((HINSTANCE)NULL, 1, 1, 1, 1, + "\xFF\xFF", "\xFF\xFF"); + hCursor = SetCursor(hEmptyCursor); + hActiveCursor = hCursor; + } + return 0; +} + + +/********************************************************************** + * ClipCursor [USER.16] + */ +void ClipCursor(LPRECT lpNewClipRect) +{ + CopyRect(&ClipCursorRect, lpNewClipRect); +} + + +/********************************************************************** + * GetClipCursor [USER.309] + */ +void GetClipCursor(LPRECT lpRetClipRect) +{ + if (lpRetClipRect != NULL) + CopyRect(lpRetClipRect, &ClipCursorRect); +} + + + + diff --git a/loader/files.c b/loader/files.c deleted file mode 100644 index a4371c6e8ac..00000000000 --- a/loader/files.c +++ /dev/null @@ -1,109 +0,0 @@ -static char RCSId[] = "$Id: wine.c,v 1.2 1993/07/04 04:04:21 root Exp root $"; -static char Copyright[] = "Copyright Robert J. Amstadt, 1993"; - -#include -#include -#include - -/********************************************************************** - * FindFileInPath - */ -char * -FindFileInPath(char *buffer, int buflen, char *rootname, - char **extensions, char *path) -{ - char *workingpath; - char *dirname; - DIR *d; - struct dirent *f; - char **e; - int rootnamelen; - int found = 0; - - if (strchr(rootname, '/') != NULL) - { - strncpy(buffer, rootname, buflen); - return buffer; - } - - rootnamelen = strlen(rootname); - workingpath = malloc(strlen(path) + 1); - if (workingpath == NULL) - return NULL; - strcpy(workingpath, path); - - for(dirname = strtok(workingpath, ":;"); - dirname != NULL; - dirname = strtok(NULL, ":;")) - { - d = opendir(dirname); - if (d != NULL) - { - while ((f = readdir(d)) != NULL) - { - if (strncasecmp(rootname, f->d_name, rootnamelen) == 0) - { - if (extensions == NULL || - strcasecmp(rootname, f->d_name) == 0) - { - found = 1; - } - else if (f->d_name[rootnamelen] == '.') - { - for (e = extensions; *e != NULL; e++) - { - if (strcasecmp(*e, f->d_name + rootnamelen + 1) - == 0) - { - found = 1; - break; - } - } - } - - if (found) - { - strncpy(buffer, dirname, buflen); - strncat(buffer, "/", buflen - strlen(buffer)); - strncat(buffer, f->d_name, buflen - strlen(buffer)); - closedir(d); - return buffer; - } - } - } - closedir(d); - } - } - - return NULL; -} - -/********************************************************************** - * GetSystemIniFilename - */ -char * -GetSystemIniFilename() -{ - static char *IniName = NULL; - char inipath[256]; - - if (IniName) - return IniName; - - getcwd(inipath, 256); - strcat(inipath, ":"); - strcat(inipath, getenv("HOME")); - strcat(inipath, ":"); - strcat(inipath, getenv("WINEPATH")); - - IniName = malloc(1024); - if (FindFileInPath(IniName, 1024, "wine.ini", NULL, inipath) == NULL) - { - free(IniName); - IniName = NULL; - return NULL; - } - - IniName = realloc(IniName, strlen(IniName) + 1); - return IniName; -} diff --git a/loader/library.c b/loader/library.c index 6e96351de24..fe7813e26e3 100644 --- a/loader/library.c +++ b/loader/library.c @@ -20,7 +20,7 @@ HANDLE LoadLibrary(LPSTR libname) { HANDLE hRet; printf("LoadLibrary '%s'\n", libname); - hRet = LoadImage(libname, NULL); + hRet = LoadImage(libname); printf("after LoadLibrary hRet=%04X\n", hRet); return hRet; } diff --git a/loader/resource.c b/loader/resource.c index a0c986c49f1..9d973058c68 100644 --- a/loader/resource.c +++ b/loader/resource.c @@ -14,7 +14,6 @@ static char Copyright[] = "Copyright Robert J. Amstadt, 1993"; #include "gdi.h" #include "wine.h" #include "icon.h" -#include "cursor.h" #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -31,7 +30,6 @@ static int ResourceFd = -1; static HANDLE ResourceInst = 0; static struct w_files *ResourceFileInfo = NULL; static RESOURCE *Top = NULL; -static HCURSOR hActiveCursor; extern HINSTANCE hSysRes; HANDLE RSC_LoadResource(int instance, char *rsc_name, int type, int *image_size_ret); @@ -313,23 +311,26 @@ HICON LoadIcon(HANDLE instance, LPSTR icon_name) instance, icon_name); #endif - if (instance == (HANDLE)NULL) instance = hSysRes; if (!(hdc = GetDC(GetDesktopWindow()))) return 0; + if (instance == (HANDLE)NULL) instance = hSysRes; rsc_mem = RSC_LoadResource(instance, icon_name, NE_RSCTYPE_GROUP_ICON, &image_size); if (rsc_mem == (HANDLE)NULL) { printf("LoadIcon / Icon %04X not Found !\n", icon_name); + ReleaseDC(GetDesktopWindow(), hdc); return 0; } lp = (WORD *)GlobalLock(rsc_mem); if (lp == NULL) { GlobalFree(rsc_mem); + ReleaseDC(GetDesktopWindow(), hdc); return 0; } lpicodesc = (ICONDESCRIP *)(lp + 3); hIcon = GlobalAlloc(GMEM_MOVEABLE, sizeof(ICONALLOC) + 1024); if (hIcon == (HICON)NULL) { GlobalFree(rsc_mem); + ReleaseDC(GetDesktopWindow(), hdc); return 0; } printf("LoadIcon Alloc hIcon=%X\n", hIcon); @@ -344,11 +345,13 @@ HICON LoadIcon(HANDLE instance, LPSTR icon_name) NE_RSCTYPE_ICON, &image_size); if (rsc_mem == (HANDLE)NULL) { printf("LoadIcon / Icon %04X Bitmaps not Found !\n", icon_name); + ReleaseDC(GetDesktopWindow(), hdc); return 0; } lp = (WORD *)GlobalLock(rsc_mem); if (lp == NULL) { GlobalFree(rsc_mem); + ReleaseDC(GetDesktopWindow(), hdc); return 0; } bmi = (BITMAPINFO *)lp; @@ -378,7 +381,6 @@ HICON LoadIcon(HANDLE instance, LPSTR icon_name) (BITMAPINFO *)bih, DIB_RGB_COLORS ); GlobalUnlock(rsc_mem); GlobalFree(rsc_mem); - hMemDC = CreateCompatibleDC(hdc); hMemDC2 = CreateCompatibleDC(hdc); SelectObject(hMemDC, lpico->hBitmap); @@ -386,8 +388,7 @@ HICON LoadIcon(HANDLE instance, LPSTR icon_name) BitBlt(hMemDC, 0, 0, bih->biWidth, bih->biHeight, hMemDC2, 0, 0, SRCINVERT); DeleteDC(hMemDC); DeleteDC(hMemDC2); - - ReleaseDC(0, hdc); + ReleaseDC(GetDesktopWindow(), hdc); return hIcon; } @@ -406,165 +407,6 @@ BOOL DestroyIcon(HICON hIcon) } -/********************************************************************** - * LoadCursor [USER.173] - */ -HCURSOR LoadCursor(HANDLE instance, LPSTR cursor_name) -{ - XColor bkcolor; - XColor fgcolor; - HCURSOR hCursor; - HANDLE rsc_mem; - WORD *lp; - CURSORDESCRIP *lpcurdesc; - CURSORALLOC *lpcur; - BITMAP BitMap; - HBITMAP hBitMap; - HDC hMemDC; - HDC hdc; - int i, j, image_size; -#ifdef DEBUG_RESOURCE - printf("LoadCursor: instance = %04x, name = %08x\n", - instance, cursor_name); -#endif - if (!(hdc = GetDC(GetDesktopWindow()))) return 0; - if (instance == (HANDLE)NULL) instance = hSysRes; - rsc_mem = RSC_LoadResource(instance, cursor_name, NE_RSCTYPE_GROUP_CURSOR, - &image_size); - if (rsc_mem == (HANDLE)NULL) { - printf("LoadCursor / Cursor %08X not Found !\n", cursor_name); - return 0; - } - lp = (WORD *)GlobalLock(rsc_mem); - if (lp == NULL) { - GlobalFree(rsc_mem); - return 0; - } - lpcurdesc = (CURSORDESCRIP *)(lp + 3); -#ifdef DEBUG_CURSOR - printf("LoadCursor / image_size=%d\n", image_size); - printf("LoadCursor / curReserved=%X\n", *lp); - printf("LoadCursor / curResourceType=%X\n", *(lp + 1)); - printf("LoadCursor / curResourceCount=%X\n", *(lp + 2)); - printf("LoadCursor / cursor Width=%d\n", (int)lpcurdesc->Width); - printf("LoadCursor / cursor Height=%d\n", (int)lpcurdesc->Height); - printf("LoadCursor / cursor curXHotspot=%d\n", (int)lpcurdesc->curXHotspot); - printf("LoadCursor / cursor curYHotspot=%d\n", (int)lpcurdesc->curYHotspot); - printf("LoadCursor / cursor curDIBSize=%lX\n", (DWORD)lpcurdesc->curDIBSize); - printf("LoadCursor / cursor curDIBOffset=%lX\n", (DWORD)lpcurdesc->curDIBOffset); -#endif - hCursor = GlobalAlloc(GMEM_MOVEABLE, sizeof(CURSORALLOC) + 1024L); - if (hCursor == (HCURSOR)NULL) { - GlobalFree(rsc_mem); - return 0; - } - printf("LoadCursor Alloc hCursor=%X\n", hCursor); - lpcur = (CURSORALLOC *)GlobalLock(hCursor); - lpcur->descriptor = *lpcurdesc; - GlobalUnlock(rsc_mem); - GlobalFree(rsc_mem); - rsc_mem = RSC_LoadResource(instance, - MAKEINTRESOURCE(lpcurdesc->curDIBOffset), - NE_RSCTYPE_CURSOR, &image_size); - if (rsc_mem == (HANDLE)NULL) { - printf("LoadCursor / Cursor %08X Bitmap not Found !\n", cursor_name); - return 0; - } - lp = (WORD *)GlobalLock(rsc_mem); - if (lp == NULL) { - GlobalFree(rsc_mem); - return 0; - } - lp += 2; - for (j = 0; j < 16; j++) - printf("%04X ", *(lp + j)); - if (*lp == sizeof(BITMAPINFOHEADER)) - lpcur->hBitmap = ConvertInfoBitmap(hdc, (BITMAPINFO *)lp); - else - lpcur->hBitmap = 0; - lp += sizeof(BITMAP); - for (i = 0; i < 81; i++) { - char temp = *((char *)lp + 162 + i); - *((char *)lp + 162 + i) = *((char *)lp + 324 - i); - *((char *)lp + 324 - i) = temp; - } -printf("LoadCursor / before XCreatePixmapFromBitmapData !\n"); - lpcur->pixshape = XCreatePixmapFromBitmapData( - XT_display, DefaultRootWindow(XT_display), - ((char *)lp + 211), 32, 32, -/* - lpcurdesc->Width / 2, lpcurdesc->Height / 4, -*/ - WhitePixel(XT_display, DefaultScreen(XT_display)), - BlackPixel(XT_display, DefaultScreen(XT_display)), 1); - lpcur->pixmask = lpcur->pixshape; - bkcolor.pixel = WhitePixel(XT_display, DefaultScreen(XT_display)); - fgcolor.pixel = BlackPixel(XT_display, DefaultScreen(XT_display)); -printf("LoadCursor / before XCreatePixmapCursor !\n"); - lpcur->xcursor = XCreatePixmapCursor(XT_display, - lpcur->pixshape, lpcur->pixmask, - &fgcolor, &bkcolor, lpcur->descriptor.curXHotspot, - lpcur->descriptor.curYHotspot); - - ReleaseDC(0, hdc); - GlobalUnlock(rsc_mem); - GlobalFree(rsc_mem); - return hCursor; -} - - - -/********************************************************************** - * DestroyCursor [USER.458] - */ -BOOL DestroyCursor(HCURSOR hCursor) -{ - CURSORALLOC *lpcur; - if (hCursor == (HCURSOR)NULL) return FALSE; - lpcur = (CURSORALLOC *)GlobalLock(hCursor); - if (lpcur->hBitmap != (HBITMAP)NULL) DeleteObject(lpcur->hBitmap); - GlobalUnlock(hCursor); - GlobalFree(hCursor); - return TRUE; -} - - -/********************************************************************** - * SetCursor [USER.69] - */ -HCURSOR SetCursor(HCURSOR hCursor) -{ - HDC hDC; - HDC hMemDC; - BITMAP bm; - CURSORALLOC *lpcur; - HCURSOR hOldCursor; -#ifdef DEBUG_CURSOR - printf("SetCursor / hCursor=%04X !\n", hCursor); -#endif - if (hCursor == (HCURSOR)NULL) return FALSE; - lpcur = (CURSORALLOC *)GlobalLock(hCursor); - hOldCursor = hActiveCursor; - -printf("SetCursor / before XDefineCursor !\n"); - XDefineCursor(XT_display, DefaultRootWindow(XT_display), lpcur->xcursor); - GlobalUnlock(hCursor); - hActiveCursor = hCursor; - return hOldCursor; -} - - -/********************************************************************** - * ShowCursor [USER.71] - */ -int ShowCursor(BOOL bShow) -{ - if (bShow) { - } - return 0; -} - - /********************************************************************** * LoadAccelerators */ @@ -586,6 +428,10 @@ HANDLE FindResource(HANDLE instance, LPSTR resource_name, LPSTR type_name) if (instance == 0) return 0; +#ifdef DEBUG_RESOURCE + printf("FindResource hInst=%04X typename=%08X resname=%08X\n", + instance, type_name, resource_name); +#endif if (OpenResourceFile(instance) < 0) return 0; @@ -644,6 +490,8 @@ HANDLE LoadResource(HANDLE instance, HANDLE hResInfo) h = r->rsc_mem = GlobalAlloc(GMEM_MOVEABLE, image_size); image = GlobalLock(h); + lseek(ResourceFd, ((int) r->nameinfo.offset << r->size_shift), SEEK_SET); + if (image == NULL || read(ResourceFd, image, image_size) != image_size) { GlobalFree(h); diff --git a/loader/selector.c b/loader/selector.c index f091d1da963..5edee7fa4d7 100644 --- a/loader/selector.c +++ b/loader/selector.c @@ -7,7 +7,7 @@ static char Copyright[] = "Copyright Robert J. Amstadt, 1993"; #include #include #include -#ifdef linux +#ifdef __linux__ #include #include #include @@ -38,17 +38,16 @@ static char Copyright[] = "Copyright Robert J. Amstadt, 1993"; #define UTEXTSEL 0x1f #endif -static struct segment_descriptor_s * EnvironmentSelector = NULL; -static struct segment_descriptor_s * PSP_Selector = NULL; -struct segment_descriptor_s * MakeProcThunks = NULL; +static SEGDESC * EnvironmentSelector = NULL; +static SEGDESC * PSP_Selector = NULL; +SEGDESC * MakeProcThunks = NULL; unsigned short PSPSelector; unsigned char ran_out = 0; -unsigned short SelectorOwners[MAX_SELECTORS]; -unsigned short SelectorMap[MAX_SELECTORS]; -unsigned short SelectorLimits[MAX_SELECTORS]; -unsigned char SelectorTypes[MAX_SELECTORS]; int LastUsedSelector = FIRST_SELECTOR - 1; +unsigned short SelectorMap[MAX_SELECTORS]; +SEGDESC Segments[MAX_SELECTORS]; + #ifdef DEV_ZERO static FILE *zfile = NULL; #endif @@ -83,6 +82,74 @@ FindUnusedSelector(void) return i; } +#ifdef HAVE_IPC +/********************************************************************** + * IPCCopySelector + */ +int +IPCCopySelector(int i_old, int i_new, int swap_type) +{ + SEGDESC *s_new, *s_old; + + s_old = &Segments[i_old]; + s_new = &Segments[i_new]; + + SelectorMap[i_new] = i_new; + + s_new->selector = (i_new << 3) | 0x0007; + s_new->base_addr = (void *) ((long) s_new->selector << 16); + s_new->length = s_old->length; + s_new->flags = s_old->flags; + s_new->owner = s_old->owner; + if (swap_type) + { + if (s_old->type == MODIFY_LDT_CONTENTS_DATA) + s_new->type = MODIFY_LDT_CONTENTS_CODE; + else + s_new->type = MODIFY_LDT_CONTENTS_DATA; + } + else + s_new->type = s_old->type; + + if (s_old->shm_key == 0) + { + s_old->shm_key = shmget(IPC_PRIVATE, s_old->length, 0600); + if (s_old->shm_key == 0) + { + memset(s_new, 0, sizeof(*s_new)); + return 0; + } + if (shmat(s_old->shm_key, s_new->base_addr, 0) == NULL) + { + memset(s_new, 0, sizeof(*s_new)); + shmctl(s_old->shm_key, IPC_RMID, NULL); + return 0; + } + memcpy(s_new->base_addr, s_old->base_addr, s_new->length); + munmap(s_old->base_addr, + ((s_old->length + PAGE_SIZE) & ~(PAGE_SIZE - 1))); + shmat(s_old->shm_key, s_old->base_addr, 0); + } + else + { + if (shmat(s_old->shm_key, s_new->base_addr, 0) == NULL) + { + memset(s_new, 0, sizeof(*s_new)); + return 0; + } + } + s_new->shm_key = s_old->shm_key; + + if (set_ldt_entry(i_new, (unsigned long) s_new->base_addr, + s_new->length - 1, 0, s_new->type, 0, 0) < 0) + { + return 0; + } + + return s_new->selector; +} +#endif + /********************************************************************** * AllocSelector * @@ -92,32 +159,38 @@ FindUnusedSelector(void) unsigned int AllocSelector(unsigned int old_selector) { + SEGDESC *s_new, *s_old; int i_new, i_old; - long base; i_new = FindUnusedSelector(); + s_new = &Segments[i_new]; + if (old_selector) { i_old = (old_selector >> 3); - SelectorMap[i_new] = i_old; - base = SAFEMAKEPTR(old_selector, 0); - if (set_ldt_entry(i_new, base, - SelectorLimits[i_old], 0, - SelectorTypes[i_old], 0, 0) < 0) +#ifdef HAVE_IPC + return IPCCopySelector(i_old, i_new, 0); +#else + s_old = &Segments[i_old]; + s_new->selector = (i_new << 3) | 0x0007; + *s_new = *s_old; + SelectorMap[i_new] = SelectorMap[i_old]; + + if (set_ldt_entry(i_new, s_new->base_addr, + s_new->length - 1, 0, + s_new->type, 0, 0) < 0) { return 0; } - - SelectorLimits[i_new] = SelectorLimits[i_old]; - SelectorTypes[i_new] = SelectorTypes[i_old]; - SelectorMap[i_new] = SelectorMap[i_old]; +#endif } else { + memset(s_new, 0, sizeof(*s_new)); SelectorMap[i_new] = i_new; } - return i_new; + return (i_new << 3) | 0x0007; } /********************************************************************** @@ -128,35 +201,64 @@ AllocSelector(unsigned int old_selector) */ unsigned int PrestoChangoSelector(unsigned src_selector, unsigned dst_selector) { - long dst_base, src_base; +#ifdef HAVE_IPC + SEGDESC *src_s; + int src_idx, dst_idx; + + src_idx = src_selector >> 3; + dst_idx = dst_selector >> 3; + + if (src_idx == dst_idx) + { + src_s = &Segments[src_idx]; + + if (src_s->type == MODIFY_LDT_CONTENTS_DATA) + src_s->type = MODIFY_LDT_CONTENTS_CODE; + else + src_s->type = MODIFY_LDT_CONTENTS_DATA; + + if (set_ldt_entry(src_idx, (long) src_s->base_addr, + src_s->length - 1, 0, src_s->type, 0, 0) < 0) + { + return 0; + } + + return src_s->selector; + } + else + { + return IPCCopySelector(src_idx, dst_idx, 1); + } +#else /* HAVE_IPC */ + SEGDESC *src_s, *dst_s; char *p; int src_idx, dst_idx; int alias_count; int i; - + src_idx = (SelectorMap[src_selector >> 3]); dst_idx = dst_selector >> 3; - src_base = (src_idx << 19) | 0x70000; - dst_base = (dst_idx << 19) | 0x70000; + src_s = &Segments[src_idx]; + dst_s = &Segments[dst_idx]; alias_count = 0; for (i = FIRST_SELECTOR; i < MAX_SELECTORS; i++) if (SelectorMap[i] == src_idx) alias_count++; - if (SelectorTypes[src_idx] == MODIFY_LDT_CONTENTS_DATA + if (src_s->type == MODIFY_LDT_CONTENTS_DATA || alias_count > 1 || src_idx == dst_idx) { - if (SelectorTypes[src_idx] == MODIFY_LDT_CONTENTS_DATA) - SelectorTypes[dst_idx] = MODIFY_LDT_CONTENTS_CODE; + *dst_s = *src_s; + + if (src_s->type == MODIFY_LDT_CONTENTS_DATA) + dst_s->type = MODIFY_LDT_CONTENTS_CODE; else - SelectorTypes[dst_idx] = MODIFY_LDT_CONTENTS_DATA; + dst_s->type = MODIFY_LDT_CONTENTS_DATA; SelectorMap[dst_idx] = SelectorMap[src_idx]; - SelectorLimits[dst_idx] = SelectorLimits[src_idx]; - if (set_ldt_entry(dst_idx, src_base, - SelectorLimits[dst_idx], 0, - SelectorTypes[dst_idx], 0, 0) < 0) + if (set_ldt_entry(dst_idx, (long) dst_s->base_addr, + dst_s->length - 1, 0, dst_s->type, 0, 0) < 0) { return 0; } @@ -168,20 +270,22 @@ unsigned int PrestoChangoSelector(unsigned src_selector, unsigned dst_selector) * segment. The SAFEST (but ugliest) way to deal with * this is to map the new segment and copy all the contents. */ - SelectorTypes[dst_idx] = MODIFY_LDT_CONTENTS_DATA; - SelectorMap[dst_idx] = SelectorMap[src_idx]; - SelectorLimits[dst_idx] = SelectorLimits[src_idx]; + SelectorMap[dst_idx] = dst_idx; + *dst_s = *src_s; + dst_s->selector = (dst_idx << 3) | 0x0007; + dst_s->base_addr = (void *) ((unsigned int) dst_s->selector << 16); + dst_s->type = MODIFY_LDT_CONTENTS_DATA; #ifdef DEV_ZERO if (zfile == NULL) zfile = fopen("/dev/zero","r"); - p = (void *) mmap((char *) dst_base, - ((SelectorLimits[dst_idx] + PAGE_SIZE) + p = (void *) mmap((char *) dst_s->base_addr, + ((dst_s->length + PAGE_SIZE) & ~(PAGE_SIZE - 1)), PROT_EXEC | PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE, fileno(zfile), 0); #else - p = (void *) mmap((char *) dst_base, - ((SelectorLimits[dst_idx] + PAGE_SIZE) + p = (void *) mmap((char *) dst_s->base_addr, + ((dst_s->length + PAGE_SIZE) & ~(PAGE_SIZE - 1)), PROT_EXEC | PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0); @@ -189,23 +293,27 @@ unsigned int PrestoChangoSelector(unsigned src_selector, unsigned dst_selector) if (p == NULL) return 0; - memcpy((void *) dst_base, (void *) src_base, - SelectorLimits[dst_idx] + 1); - if (set_ldt_entry(src_idx, dst_base, - SelectorLimits[dst_idx], 0, - SelectorTypes[dst_idx], 0, 0) < 0) + memcpy((void *) dst_s->base_addr, (void *) src_s->base_addr, + dst_s->length); + if (set_ldt_entry(src_idx, dst_s->base_addr, + dst_s->length - 1, 0, dst_s->type, 0, 0) < 0) { return 0; } - if (set_ldt_entry(dst_idx, dst_base, - SelectorLimits[dst_idx], 0, - SelectorTypes[dst_idx], 0, 0) < 0) + if (set_ldt_entry(dst_idx, dst_s->base_addr, + dst_s->length - 1, 0, dst_s->type, 0, 0) < 0) { return 0; } + + munmap(src_s->base_addr, + (src_s->length + PAGE_SIZE) & ~(PAGE_SIZE - 1)); + SelectorMap[src_idx] = dst_idx; + src_s->base_addr = dst_s->base_addr; } - return (dst_idx << 3) | 0x0007; + return dst_s->selector; +#endif /* HAVE_IPC */ } /********************************************************************** @@ -227,12 +335,46 @@ AllocDStoCSAlias(unsigned int ds_selector) */ unsigned int FreeSelector(unsigned int sel) { + SEGDESC *s; int sel_idx; int alias_count; int i; + +#ifdef HAVE_IPC + sel_idx = sel >> 3; + + if (sel_idx < FIRST_SELECTOR || sel_idx >= MAX_SELECTORS) + return 0; + s = &Segments[sel_idx]; + if (s->shm_key == 0) + { + munmap(s->base_addr, ((s->length + PAGE_SIZE) & ~(PAGE_SIZE - 1))); + memcpy(s, 0, sizeof(*s)); + SelectorMap[sel_idx] = 0; + } + else + { + shmdt(s->base_addr); + + alias_count = 0; + for (i = FIRST_SELECTOR; i < MAX_SELECTORS; i++) + if (SelectorMap[i] && Segments[i].shm_key == s->shm_key) + alias_count++; + + if (alias_count == 1) + shmctl(s->shm_key, IPC_RMID, NULL); + + memcpy(s, 0, sizeof(*s)); + SelectorMap[sel_idx] = 0; + } + +#else /* HAVE_IPC */ sel_idx = SelectorMap[sel >> 3]; + if (sel_idx < FIRST_SELECTOR || sel_idx >= MAX_SELECTORS) + return 0; + if (sel_idx != (sel >> 3)) { SelectorMap[sel >> 3] = 0; @@ -246,10 +388,12 @@ unsigned int FreeSelector(unsigned int sel) if (alias_count == 1) { - munmap((char *) (sel << 16), - ((SelectorLimits[sel_idx] + PAGE_SIZE) & ~(PAGE_SIZE - 1))); + s = &Segments[sel_idx]; + munmap(s->base_addr, ((s->length + PAGE_SIZE) & ~(PAGE_SIZE - 1))); + memcpy(s, 0, sizeof(*s)); SelectorMap[sel >> 3] = 0; } +#endif /* HAVE_IPC */ return 0; } @@ -257,10 +401,10 @@ unsigned int FreeSelector(unsigned int sel) /********************************************************************** * CreateNewSegment */ -struct segment_descriptor_s * +SEGDESC * CreateNewSegment(int code_flag, int read_only, int length) { - struct segment_descriptor_s *s; + SEGDESC *s; int contents; int i; @@ -269,7 +413,7 @@ CreateNewSegment(int code_flag, int read_only, int length) /* * Fill in selector info. */ - s = malloc(sizeof(*s)); + s = &Segments[i]; if (code_flag) { contents = MODIFY_LDT_CONTENTS_CODE; @@ -305,13 +449,12 @@ CreateNewSegment(int code_flag, int read_only, int length) (s->length - 1) & 0xffff, 0, contents, read_only, 0) < 0) { - free(s); + memset(s, 0, sizeof(*s)); return NULL; } SelectorMap[i] = (unsigned short) i; - SelectorLimits[i] = s->length - 1; - SelectorTypes[i] = contents; + s->type = contents; return s; } @@ -319,7 +462,7 @@ CreateNewSegment(int code_flag, int read_only, int length) /********************************************************************** * GetNextSegment */ -struct segment_descriptor_s * +SEGDESC * GetNextSegment(unsigned int flags, unsigned int limit) { return CreateNewSegment(0, 0, limit); @@ -494,11 +637,11 @@ GetDOSEnvironment() /********************************************************************** * CreateEnvironment */ -static struct segment_descriptor_s * +static SEGDESC * CreateEnvironment(void) { char *p; - struct segment_descriptor_s * s; + SEGDESC * s; s = CreateNewSegment(0, 0, PAGE_SIZE); if (s == NULL) @@ -521,12 +664,12 @@ CreateEnvironment(void) /********************************************************************** * CreatePSP */ -static struct segment_descriptor_s * +static SEGDESC * CreatePSP(void) { struct dos_psp_s *psp; unsigned short *usp; - struct segment_descriptor_s * s; + SEGDESC * s; char *p1, *p2; int i; @@ -572,13 +715,13 @@ CreatePSP(void) /********************************************************************** * CreateSelectors */ -struct segment_descriptor_s * +SEGDESC * CreateSelectors(struct w_files * wpnt) { int fd = wpnt->fd; struct ne_segment_table_entry_s *seg_table = wpnt->seg_table; struct ne_header_s *ne_header = wpnt->ne_header; - struct segment_descriptor_s *selectors, *s, *stmp; + SEGDESC *selectors, *s, *stmp; unsigned short auto_data_sel; int contents, read_only; int SelectorTableLength; @@ -692,7 +835,7 @@ CreateSelectors(struct w_files * wpnt) s = selectors; for (i = 0; i < ne_header->n_segment_tab; i++, s++) - SelectorOwners[s->selector >> 3] = auto_data_sel; + Segments[s->selector >> 3].owner = auto_data_sel; if(!EnvironmentSelector) { EnvironmentSelector = CreateEnvironment(); diff --git a/loader/signal.c b/loader/signal.c index 7b2727cae54..b2a492e221f 100644 --- a/loader/signal.c +++ b/loader/signal.c @@ -3,7 +3,11 @@ #include #include +#ifdef __NetBSD__ +#include +#else #include +#endif #include #include #ifdef linux @@ -85,11 +89,11 @@ static void win_fault(int signal, int code, struct sigcontext *scp){ if(!do_int21(scp)) goto oops; break; case 0x11: - scp->sc_eax = 0x00000000; /* get equipment list: we haven't */ - break; /* got anything */ + scp->sc_eax = (scp->sc_eax & 0xffff0000L) | DOS_GetEquipment(); + break; case 0x12: - scp->sc_eax = 640L; /* get base mem size */ - break; + scp->sc_eax = (scp->sc_eax & 0xffff0000L) | 640L; + break; /* get base mem size */ case 0x1A: if(!do_int1A(scp)) goto oops; break; diff --git a/loader/wine.c b/loader/wine.c index 7124317f09a..60b606bbf4a 100644 --- a/loader/wine.c +++ b/loader/wine.c @@ -28,11 +28,14 @@ extern void CallTo32(); char * GetModuleName(struct w_files * wpnt, int index, char *buffer); extern unsigned char ran_out; +extern char WindowsPath[256]; unsigned short WIN_StackSize; unsigned short WIN_HeapSize; struct w_files * wine_files = NULL; +int WineForceFail = 0; + char **Argv; int Argc; struct mz_header_s *CurrentMZHeader; @@ -40,11 +43,9 @@ struct ne_header_s *CurrentNEHeader; int CurrentNEFile; HINSTANCE hSysRes; -static char *dllExtensions[] = { "dll", "exe", NULL }; -static char *exeExtensions[] = { "exe", NULL }; +static char *Extensions[] = { "dll", "exe", NULL }; static char *WinePath = NULL; - /********************************************************************** * DebugPrintString */ @@ -101,12 +102,13 @@ GetFileInfo(unsigned short instance) * LoadImage * Load one NE format executable into memory */ -HINSTANCE LoadImage(char * filename, char * modulename) +HINSTANCE LoadImage(char *modulename) { unsigned int read_size; int i; struct w_files * wpnt, *wpnt1; unsigned int status; + char buffer[256]; /* First allocate a spot to store the info we collect, and add it to * our linked list. @@ -122,10 +124,24 @@ HINSTANCE LoadImage(char * filename, char * modulename) }; wpnt->next = NULL; + /* + * search file + */ + + if (FindFile(buffer, sizeof(buffer), modulename, Extensions, WindowsPath) + ==NULL) + { + char temp[256]; + + sprintf(temp,"LoadImage: I can't find %s !\n",modulename); + myerror(temp); + } + fprintf(stderr,"LoadImage: loading %s (%s)\n", modulename, buffer); + /* * Open file for reading. */ - wpnt->fd = open(filename, O_RDONLY); + wpnt->fd = open(buffer, O_RDONLY); if (wpnt->fd < 0) { myerror(NULL); @@ -133,7 +149,7 @@ HINSTANCE LoadImage(char * filename, char * modulename) /* * Establish header pointers. */ - wpnt->filename = strdup(filename); + wpnt->filename = strdup(buffer); wpnt->name = NULL; if(modulename) wpnt->name = strdup(modulename); @@ -181,7 +197,7 @@ HINSTANCE LoadImage(char * filename, char * modulename) wpnt->selector_table = CreateSelectors(wpnt); wpnt->hinstance = wpnt-> - selector_table[wine_files->ne_header->auto_data_seg-1].selector; + selector_table[wpnt->ne_header->auto_data_seg-1].selector; /* Get the lookup table. This is used for looking up the addresses of functions that are exported */ @@ -227,16 +243,10 @@ HINSTANCE LoadImage(char * filename, char * modulename) if(FindDLLTable(buff)) continue; /* This module already loaded */ - if (FindFileInPath(buff2, sizeof(buff2), - buff, dllExtensions, WinePath) != NULL && - (fd = open(buff2, O_RDONLY)) >= 0) - { - close(fd); - LoadImage(buff2, buff); - continue; - } - + LoadImage(buff); +/* fprintf(stderr,"Unable to load:%s\n", buff); +*/ } return(wpnt->hinstance); } @@ -249,6 +259,8 @@ _WinMain(int argc, char **argv) { int segment; char *p; + char *sysresname; + char syspath[256]; char exe_path[256]; #ifdef WINESTAT char * cp; @@ -273,19 +285,20 @@ _WinMain(int argc, char **argv) strcat(WinePath, ";"); strcat(WinePath, p); - if (FindFileInPath(exe_path, 256, argv[1], exeExtensions, WinePath) - == NULL) - { - fprintf(stderr, "Could not find file '%s'\n", argv[1]); - exit(1); - } - - LoadImage(exe_path, NULL); - hSysRes = LoadImage("sysres.dll", NULL); + LoadImage(argv[1]); + hSysRes = LoadImage("sysres.dll"); + if (hSysRes == (HINSTANCE)NULL) + printf("Error Loading System Resources !!!\n"); + else + printf("System Resources Loaded // hSysRes='%04X'\n", hSysRes); if(ran_out) exit(1); #ifdef DEBUG - GetEntryDLLName("USER", "INITAPP", 0, 0); + { + int dummy1, dummy2; + + GetEntryDLLName("USER", "INITAPP", &dummy1, &dummy2); + } for(i=0; i<1024; i++) { int j; j = GetEntryPointFromOrdinal(wine_files, i); @@ -327,6 +340,21 @@ _WinMain(int argc, char **argv) init_wine_signals(); + if (WineForceFail) + { + p = (char *) ((cs_reg << 16) | ip_reg); + + *p++ = 0xcd; + *p++ = 0x20; + } + + if (ss_reg == 0) + { + fprintf(stderr, "SS is 0. Send email to bob@amscons.com.\n"); + fprintf(stderr, " No. Really. I want to know what programs\n"); + fprintf(stderr, " do this.\n"); + } + rv = CallToInit16(cs_reg << 16 | ip_reg, ss_reg << 16 | sp_reg, ds_reg); printf ("rv = %x\n", rv); } @@ -392,12 +420,11 @@ GetModuleName(struct w_files * wpnt, int index, char *buffer) int FixupSegment(struct w_files * wpnt, int segment_num) { - int fd = wpnt->fd; - struct mz_header_s * mz_header = wpnt->mz_header; - struct ne_header_s *ne_header = wpnt->ne_header; - struct ne_segment_table_entry_s *seg_table = wpnt->seg_table; - struct segment_descriptor_s *selector_table = wpnt->selector_table; - + int fd = wpnt->fd; + struct mz_header_s * mz_header = wpnt->mz_header; + struct ne_header_s *ne_header = wpnt->ne_header; + struct ne_segment_table_entry_s *seg_table = wpnt->seg_table; + struct segment_descriptor_s *selector_table = wpnt->selector_table; struct relocation_entry_s *rep, *rep1; struct ne_segment_table_entry_s *seg; struct segment_descriptor_s *sel; @@ -410,10 +437,14 @@ FixupSegment(struct w_files * wpnt, int segment_num) char dll_name[257]; char func_name[257]; int i, n_entries; + int additive; seg = &seg_table[segment_num]; sel = &selector_table[segment_num]; + fprintf(stderr, "Segment fixups for %s, segment %d, selector %x\n", + wpnt->name, segment_num, (int) sel->base_addr >> 16); + if ((seg->seg_data_offset == 0) || !(seg->seg_flags & NE_SEGFLAGS_RELOC_DATA)) return 0; @@ -445,8 +476,13 @@ FixupSegment(struct w_files * wpnt, int segment_num) /* * Get the target address corresponding to this entry. */ + additive = 0; + switch (rep->relocation_type) { + case NE_RELTYPE_ORDINALADD: + additive = 1; + case NE_RELTYPE_ORDINAL: if (GetModuleName(wpnt, rep->target1, dll_name) == NULL) @@ -474,6 +510,9 @@ FixupSegment(struct w_files * wpnt, int segment_num) #endif break; + case NE_RELTYPE_NAMEADD: + additive = 1; + case NE_RELTYPE_NAME: if (GetModuleName(wpnt, rep->target1, dll_name) == NULL) @@ -543,30 +582,50 @@ FixupSegment(struct w_files * wpnt, int segment_num) continue; default: -#ifndef DEBUG_FIXUP fprintf(stderr,"%d: ADDR TYPE %d, TYPE %d, OFFSET %04.4x, ", i + 1, rep->address_type, rep->relocation_type, rep->offset); - fprintf(stderr,"TARGET %04.4x %04.4x\n", rep->target1, rep->target2); -#endif + fprintf(stderr,"TARGET %04.4x %04.4x\n", + rep->target1, rep->target2); free(rep1); - return -1; +#if 0 + sp = (unsigned short *) ((char *) sel->base_addr + rep->offset); + fprintf(stderr, " FIXUP ADDRESS %04.4x:%04.4x\n", + (int) sel->base_addr >> 16, rep->offset); + WineForceFail = 1; + continue; +#endif } /* * Stuff the right size result in. */ sp = (unsigned short *) ((char *) sel->base_addr + rep->offset); + if (additive) + { + if (FindDLLTable(dll_name) == NULL) + additive = 2; + + fprintf(stderr,"%d: ADDR TYPE %d, TYPE %d, OFFSET %04.4x, ", + i + 1, rep->address_type, rep->relocation_type, + rep->offset); + fprintf(stderr,"TARGET %04.4x %04.4x\n", + rep->target1, rep->target2); + fprintf(stderr, " Additive = %d\n", additive); + } + switch (rep->address_type) { case NE_RADDR_OFFSET16: do { next_addr = *sp; *sp = (unsigned short) address; + if (additive == 2) + *sp += next_addr; sp = (unsigned short *) ((char *) sel->base_addr + next_addr); } - while (next_addr != 0xffff); + while (next_addr != 0xffff && !additive); break; @@ -574,10 +633,12 @@ FixupSegment(struct w_files * wpnt, int segment_num) do { next_addr = *sp; *sp = (unsigned short) address; + if (additive == 2) + *sp += next_addr; *(sp+1) = (unsigned short) selector; sp = (unsigned short *) ((char *) sel->base_addr + next_addr); } - while (next_addr != 0xffff); + while (next_addr != 0xffff && !additive); break; @@ -589,17 +650,15 @@ FixupSegment(struct w_files * wpnt, int segment_num) if (rep->relocation_type == NE_RELTYPE_INT1) break; } - while (next_addr != 0xffff); + while (next_addr != 0xffff && !additive); break; default: -#ifndef DEBUG_FIXUP printf("%d: ADDR TYPE %d, TYPE %d, OFFSET %04.4x, ", i + 1, rep->address_type, rep->relocation_type, rep->offset); printf("TARGET %04.4x %04.4x\n", rep->target1, rep->target2); -#endif free(rep1); return -1; } diff --git a/memory/Imakefile b/memory/Imakefile new file mode 100644 index 00000000000..edf4b6d5604 --- /dev/null +++ b/memory/Imakefile @@ -0,0 +1,21 @@ +#include "../Wine.tmpl" + +MODULE = memory + +SRCS = \ + global.c \ + heap.c \ + atom.c + +OBJS = \ + global.o \ + heap.o \ + atom.o + +WineRelocatableTarget($(TOP)/$(MODULE),,$(OBJS)) +DependTarget() +CleanTarget() + +includes:: + +install:: diff --git a/memory/Makefile b/memory/Makefile index b624e09fd6f..f3ff2c766b6 100644 --- a/memory/Makefile +++ b/memory/Makefile @@ -1,6 +1,6 @@ CFLAGS=$(COPTS) $(DEBUGOPTS) -I$(INCLUDE_DIR) -OBJS=global.o heap.o +OBJS=global.o heap.o atom.o default: memory.o diff --git a/memory/atom.c b/memory/atom.c new file mode 100644 index 00000000000..1fd5f489f89 --- /dev/null +++ b/memory/atom.c @@ -0,0 +1,328 @@ +/* + * Atom table functions + * + * Copyright 1993 Alexandre Julliard + */ + +/* + * Current limitations: + * + * - This code should work fine when called from the emulation library, + * but probably not when called from the Windows program. The reason + * is that everything is allocated on the current local heap, instead + * of taking into account the DS register. Correcting this will also + * require some changes in the local heap management to bring it closer + * to Windows. + * + * - The code assumes that LocalAlloc() returns a block aligned on a + * 4-bytes boundary (because of the shifting done in HANDLETOATOM). + * If this is not the case, the allocation code will have to be changed. + * + * - Integer atoms created with MAKEINTATOM are not supported. This is + * because they can't generally be differentiated from string constants + * located below 0x10000 in the emulation library. If you need + * integer atoms, use the "#1234" form. + */ + +#include +#include + +#include "atom.h" + + +#define DEFAULT_ATOMTABLE_SIZE 37 +#define MIN_STR_ATOM 0xc000 + +#define ATOMTOHANDLE(atom) ((HANDLE)(atom) << 2) +#define HANDLETOATOM(handle) ((ATOM)(0xc000 | ((handle) >> 2))) + + +static ATOMTABLE * localTable = NULL; +static ATOMTABLE * globalTable = NULL; + + +/*********************************************************************** + * ATOM_InitTable + */ +static BOOL ATOM_InitTable( ATOMTABLE ** table, WORD entries ) +{ + int i; + HANDLE handle; + + handle = LocalAlloc( LMEM_MOVEABLE, sizeof(ATOMTABLE) + + (entries-1) * sizeof(HANDLE) ); + if (!handle) return FALSE; + *table = (ATOMTABLE *) LocalLock( handle ); + (*table)->size = entries; + for (i = 0; i < entries; i++) (*table)->entries[i] = 0; + return TRUE; + +} + + +/*********************************************************************** + * ATOM_Init + * + * Global table initialisation. + */ +BOOL ATOM_Init() +{ + return ATOM_InitTable( &globalTable, DEFAULT_ATOMTABLE_SIZE ); +} + + +/*********************************************************************** + * ATOM_MakePtr + * + * Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()). + * Is is assumed that the atom is in the same segment as the table. + */ +static ATOMENTRY * ATOM_MakePtr( ATOMTABLE * table, HANDLE handle ) +{ + return (ATOMENTRY *) (((int)table & 0xffff0000) | (int)handle); +} + + +/*********************************************************************** + * ATOM_Hash + */ +static WORD ATOM_Hash( WORD entries, LPCSTR str, WORD len ) +{ + WORD i, hash = 0; + + for (i = 0; i < len; i++) hash ^= str[i] + i; + return hash % entries; +} + + +/*********************************************************************** + * ATOM_AddAtom + */ +static ATOM ATOM_AddAtom( ATOMTABLE * table, LPCSTR str ) +{ + WORD hash; + HANDLE entry; + ATOMENTRY * entryPtr; + int len; + + if ((len = strlen( str )) > 255) len = 255; + + /* Check for integer atom */ +/* if (!((int)str & 0xffff0000)) return (ATOM)((int)str & 0xffff); */ + if (str[0] == '#') return atoi( &str[1] ); + + hash = ATOM_Hash( table->size, str, len ); + entry = table->entries[hash]; + while (entry) + { + entryPtr = ATOM_MakePtr( table, entry ); + if ((entryPtr->length == len) && + (!strncasecmp( entryPtr->str, str, len ))) + { + entryPtr->refCount++; + return HANDLETOATOM( entry ); + } + entry = entryPtr->next; + } + + entry = (int)LocalAlloc( LMEM_MOVEABLE, sizeof(ATOMENTRY)+len-1 ) & 0xffff; + if (!entry) return 0; + entryPtr = ATOM_MakePtr( table, entry ); + entryPtr->next = table->entries[hash]; + entryPtr->refCount = 1; + entryPtr->length = len; + memcpy( entryPtr->str, str, len ); + table->entries[hash] = entry; + return HANDLETOATOM( entry ); +} + + +/*********************************************************************** + * ATOM_DeleteAtom + */ +static ATOM ATOM_DeleteAtom( ATOMTABLE * table, ATOM atom ) +{ + ATOMENTRY * entryPtr; + HANDLE entry, *prevEntry; + WORD hash; + + if (atom < MIN_STR_ATOM) return 0; /* Integer atom */ + + entry = ATOMTOHANDLE( atom ); + entryPtr = ATOM_MakePtr( table, entry ); + + /* Find previous atom */ + hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length ); + prevEntry = &table->entries[hash]; + while (*prevEntry && *prevEntry != entry) + { + ATOMENTRY * prevEntryPtr = ATOM_MakePtr( table, *prevEntry ); + prevEntry = &prevEntryPtr->next; + } + if (!*prevEntry) return atom; + + /* Delete atom */ + if (--entryPtr->refCount == 0) + { + *prevEntry = entryPtr->next; + LocalFree( entry ); + } + return 0; +} + + +/*********************************************************************** + * ATOM_FindAtom + */ +static ATOM ATOM_FindAtom( ATOMTABLE * table, LPCSTR str ) +{ + WORD hash; + HANDLE entry; + int len; + + if ((len = strlen( str )) > 255) len = 255; + + /* Check for integer atom */ +/* if (!((int)str & 0xffff0000)) return (ATOM)((int)str & 0xffff); */ + if (str[0] == '#') return atoi( &str[1] ); + + hash = ATOM_Hash( table->size, str, len ); + entry = table->entries[hash]; + while (entry) + { + ATOMENTRY * entryPtr = ATOM_MakePtr( table, entry ); + if ((entryPtr->length == len) && + (!strncasecmp( entryPtr->str, str, len ))) + return HANDLETOATOM( entry ); + entry = entryPtr->next; + } + return 0; +} + + +/*********************************************************************** + * ATOM_GetAtomName + */ +static WORD ATOM_GetAtomName( ATOMTABLE * table, ATOM atom, + LPSTR buffer, short count ) +{ + ATOMENTRY * entryPtr; + HANDLE entry; + char * strPtr; + int len; + char text[8]; + + if (!count) return 0; + if (atom < MIN_STR_ATOM) + { + sprintf( text, "#%d", atom ); + len = strlen(text); + strPtr = text; + } + else + { + entry = ATOMTOHANDLE( atom ); + entryPtr = ATOM_MakePtr( table, entry ); + len = entryPtr->length; + strPtr = entryPtr->str; + } + if (len >= count) len = count-1; + memcpy( buffer, strPtr, len ); + buffer[len] = '\0'; + return len; +} + + +/*********************************************************************** + * InitAtomTable (KERNEL.68) + */ +BOOL InitAtomTable( WORD entries ) +{ + return ATOM_InitTable( &localTable, entries ); +} + + +/*********************************************************************** + * GetAtomHandle (KERNEL.73) + */ +HANDLE GetAtomHandle( ATOM atom ) +{ + if (atom < MIN_STR_ATOM) return 0; + return ATOMTOHANDLE( atom ); +} + + +/*********************************************************************** + * AddAtom (KERNEL.70) + */ +ATOM AddAtom( LPCSTR str ) +{ + if (!localTable) InitAtomTable( DEFAULT_ATOMTABLE_SIZE ); + return ATOM_AddAtom( localTable, str ); +} + + +/*********************************************************************** + * DeleteAtom (KERNEL.71) + */ +ATOM DeleteAtom( ATOM atom ) +{ + if (!localTable) InitAtomTable( DEFAULT_ATOMTABLE_SIZE ); + return ATOM_DeleteAtom( localTable, atom ); +} + + +/*********************************************************************** + * FindAtom (KERNEL.69) + */ +ATOM FindAtom( LPCSTR str ) +{ + if (!localTable) InitAtomTable( DEFAULT_ATOMTABLE_SIZE ); + return ATOM_FindAtom( localTable, str ); +} + + +/*********************************************************************** + * GetAtomName (KERNEL.72) + */ +WORD GetAtomName( ATOM atom, LPSTR buffer, short count ) +{ + if (!localTable) InitAtomTable( DEFAULT_ATOMTABLE_SIZE ); + return ATOM_GetAtomName( localTable, atom, buffer, count ); +} + + +/*********************************************************************** + * GlobalAddAtom (USER.268) + */ +ATOM GlobalAddAtom( LPCSTR str ) +{ + return ATOM_AddAtom( globalTable, str ); +} + + +/*********************************************************************** + * GlobalDeleteAtom (USER.269) + */ +ATOM GlobalDeleteAtom( ATOM atom ) +{ + return ATOM_DeleteAtom( globalTable, atom ); +} + + +/*********************************************************************** + * GlobalFindAtom (USER.270) + */ +ATOM GlobalFindAtom( LPCSTR str ) +{ + return ATOM_FindAtom( globalTable, str ); +} + + +/*********************************************************************** + * GlobalGetAtomName (USER.271) + */ +WORD GlobalGetAtomName( ATOM atom, LPSTR buffer, short count ) +{ + return ATOM_GetAtomName( globalTable, atom, buffer, count ); +} diff --git a/memory/global.c b/memory/global.c index 169ebc3878a..bf11b370f13 100644 --- a/memory/global.c +++ b/memory/global.c @@ -75,7 +75,7 @@ GlobalGetFreeSegments(unsigned int flags, int n_segments) else if (count) count = 0; } - + /* * If we couldn't find enough segments, then we need to create some. */ @@ -87,18 +87,22 @@ GlobalGetFreeSegments(unsigned int flags, int n_segments) g_prev = NULL; for (g = GlobalList; g != NULL; g = g->next) g_prev = g; - + /* * Allocate segments. */ for (count = 0; count < n_segments; count++) { s = GetNextSegment(flags, 0x10000); - if (s == NULL) + if (s == NULL) { + printf("GlobalGetFreeSegments // bad GetNextSegment !\n"); return NULL; - + } g = (GDESC *) malloc(sizeof(*g)); - + if (g == NULL) { + printf("GlobalGetFreeSegments // bad GDESC malloc !\n"); + return NULL; + } g->prev = g_prev; g->next = NULL; g->handle = s->selector; @@ -110,18 +114,15 @@ GlobalGetFreeSegments(unsigned int flags, int n_segments) else g->lock_count = 0; - free(s); - - if (count == 0) - g_start = g; + if (count == 0) g_start = g; if (g_prev != NULL) { g_prev->next = g; - g->prev = g_prev; } else GlobalList = g; + g_prev = g; } } @@ -131,6 +132,10 @@ GlobalGetFreeSegments(unsigned int flags, int n_segments) g = g_start; for (i = 0; i < n_segments; i++, g = g->next) { + if (g == NULL) { + printf("GlobalGetFreeSegments // bad Segments chain !\n"); + return NULL; + } g->sequence = i + 1; g->length = n_segments; } diff --git a/misc/Imakefile b/misc/Imakefile new file mode 100644 index 00000000000..53eda7629f5 --- /dev/null +++ b/misc/Imakefile @@ -0,0 +1,45 @@ +#include "../Wine.tmpl" + +MODULE = misc + +SRCS = \ + kernel.c \ + user.c \ + rect.c \ + file.c \ + sound.c \ + emulate.c \ + keyboard.c \ + profile.c \ + lstr.c \ + exec.c \ + message.c \ + int1a.c \ + int21.c \ + dos_fs.c \ + xt.c + +OBJS = \ + kernel.o \ + user.o \ + rect.o \ + file.o \ + sound.o \ + emulate.o \ + keyboard.o \ + profile.o \ + lstr.o \ + exec.o \ + message.o \ + int1a.o \ + int21.o \ + dos_fs.o \ + xt.o + +WineRelocatableTarget($(TOP)/$(MODULE),,$(OBJS)) +DependTarget() +CleanTarget() + +includes:: + +install:: diff --git a/misc/Makefile b/misc/Makefile index 12180d04200..8cdcee9ea77 100644 --- a/misc/Makefile +++ b/misc/Makefile @@ -1,7 +1,8 @@ -CFLAGS=$(COPTS) $(DEBUGOPTS) -I$(INCLUDE_DIR) +CFLAGS=$(COPTS) $(DEBUGOPTS) -I../include -OBJS=dos.o kernel.o user.o xt.o rect.o file.o sound.o emulate.o \ - keyboard.o profile.o lstr.o exec.o message.o +OBJS=kernel.o user.o xt.o rect.o file.o sound.o emulate.o \ + keyboard.o profile.o lstr.o exec.o message.o int1a.o int21.o \ + dos_fs.o comm.o default: misc.o diff --git a/misc/comm.c b/misc/comm.c new file mode 100644 index 00000000000..c0db9d590ff --- /dev/null +++ b/misc/comm.c @@ -0,0 +1,872 @@ +/* + * DEC 93 Erik Bos (erik@trashcan.hacktic.nl) + */ + +#include +#include +#include +#include +#include +#include +#ifdef __NetBSD__ +#include +#include +#endif +#include "wine.h" +#include "windows.h" + +#define DEBUG_COMM + +#define MAX_PORTS 16 + +int commerror = 0, eventmask = 0; + +struct DosDeviceStruct { + char *devicename; /* /dev/cua1 */ + int fd; + int suspended; +}; + +struct DosDeviceStruct COM[MAX_PORTS]; +struct DosDeviceStruct LPT[MAX_PORTS]; + +void Comm_DeInit(void); + +void Comm_Init(void) +{ + int x, serial = 0, parallel = 0; + char option[10], temp[256], *ptr; + struct stat st; + + for (x=0; x!=MAX_PORTS; x++) { + strcpy(option,"COMx"); + option[3] = '0' + x; + option[4] = '\0'; + + GetPrivateProfileString("serialports", option, "*", temp, sizeof(temp), WINE_INI); + if (!strcmp(temp, "*") || *temp == '\0') + COM[serial].devicename = NULL; + else { + stat(temp, &st); + if (!S_ISCHR(st.st_mode)) + fprintf(stderr,"comm: can 't use `%s' as COM%d !\n", temp, x); + else + if ((ptr = malloc(strlen(temp)+1)) == NULL) + fprintf(stderr,"comm: can't malloc for device info!\n"); + else { + COM[serial].fd = 0; + COM[serial].devicename = ptr; + strcpy(COM[serial++].devicename, temp); + } + } + + strcpy(option, "LPTx"); + option[3] = '0' + x; + option[4] = '\0'; + + GetPrivateProfileString("parallelports", option, "*", temp, sizeof(temp), WINE_INI); + if (!strcmp(temp, "*") || *temp == '\0') + LPT[parallel].devicename = NULL; + else { + stat(temp, &st); + if (!S_ISCHR(st.st_mode)) + fprintf(stderr,"comm: can 't use `%s' as LPT%d !\n", temp, x); + else + if ((ptr = malloc(strlen(temp)+1)) == NULL) + fprintf(stderr,"comm: can't malloc for device info!\n"); + else { + LPT[serial].fd = 0; + LPT[serial].devicename = ptr; + strcpy(LPT[serial++].devicename, temp); + } + } + + } + atexit(Comm_DeInit); + +#ifdef DEBUG_COMM + for (x=0; x!=MAX_PORTS; x++) { + if (COM[x].devicename) + fprintf(stderr, "comm: COM%d = %s\n", x, COM[x].devicename); + if (LPT[x].devicename) + fprintf(stderr, "comm: LPT%d = %s\n", x, LPT[x].devicename); + } +#endif +} + +void Comm_DeInit(void) +{ + int x; + + for (x=0; x!=MAX_PORTS; x++) { + + if (COM[x].devicename) { + if (COM[x].fd) + close(COM[x].fd); + fprintf(stderr, "comm: COM%d = %s\n",x,COM[x].devicename); + free(COM[x].devicename); + } + if (LPT[x].devicename) { + if (LPT[x].fd) + close(LPT[x].fd); + fprintf(stderr, "comm: LPT%d = %s\n",x,LPT[x].devicename); + free(LPT[x].devicename); + } + } +} + +struct DosDeviceStruct *GetDeviceStruct(int fd) +{ + int x; + + for (x=0; x!=MAX_PORTS; x++) { + if (COM[x].fd == fd) + return &COM[x]; + if (LPT[x].fd == fd) + return &LPT[x]; + } + + return NULL; +} + +int ValidCOMPort(int x) +{ + return(x < MAX_PORTS ? (int) COM[x].devicename : 0); +} + +int ValidLPTPort(int x) +{ + return(x < MAX_PORTS ? (int) LPT[x].devicename : 0); +} + +int WinError(void) +{ + perror("comm"); + switch (errno) { + default: + return CE_IOE; + } +} + +int BuildCommDCB(LPSTR device, DCB FAR *lpdcb) +{ + /* "COM1:9600,n,8,1" */ + /* 012345 */ + + int port; + char *ptr, *ptr2, temp[256],temp2[10]; + +#ifdef DEBUG_COMM +fprintf(stderr,"BuildCommDCB: (%s), ptr %d\n", device, lpdcb); +#endif + commerror = 0; + + if (!strncmp(device,"COM",3)) { + port = device[3] - '0'; + + if (!ValidCOMPort(port)) { + commerror = IE_BADID; + return -1; + } + + if (!COM[port].fd) { + commerror = IE_NOPEN; + return -1; + } + lpdcb->Id = COM[port].fd; + + if (!*(device+4)) + return 0; + + if (*(device+4) != ':') + return -1; + + strcpy(temp,device+5); + ptr = strtok(temp, ","); + + fprintf(stderr,"BuildCommDCB: baudrate (%s)\n", ptr); + lpdcb->BaudRate = atoi(ptr); + + ptr = strtok(NULL, ","); + if (islower(*ptr)) + *ptr = toupper(*ptr); + + fprintf(stderr,"BuildCommDCB: parity (%c)\n", *ptr); + switch (*ptr) { + case 'N': + lpdcb->Parity = NOPARITY; + lpdcb->fParity = 0; + break; + + lpdcb->fParity = 1; + + case 'E': + lpdcb->Parity = EVENPARITY; + break; + case 'M': + lpdcb->Parity = MARKPARITY; + break; + case 'O': + lpdcb->Parity = ODDPARITY; + break; + default: + fprintf(stderr,"comm: unknown parity `%c'!\n", *ptr); + return -1; + } + + ptr = strtok(NULL, ","); + fprintf(stderr, "BuildCommDCB: charsize (%c)\n", *ptr); + lpdcb->ByteSize = *ptr - '0'; + + ptr = strtok(NULL, ","); + fprintf(stderr, "BuildCommDCB: stopbits (%c)\n", *ptr); + switch (*ptr) { + case '1': + lpdcb->StopBits = ONESTOPBIT; + break; + case '2': + lpdcb->StopBits = TWOSTOPBITS; + break; + default: + fprintf(stderr,"comm: unknown # of stopbits `%c'!\n", *ptr); + return -1; + } + } + + return 0; +} + +int OpenComm(LPSTR device, UINT cbInQueue, UINT cbOutQueue) +{ + int port, fd; + +#ifdef DEBUG_COMM +fprintf(stderr,"OpenComm: %s, %d, %d\n", device, cbInQueue, cbOutQueue); +#endif + + commerror = 0; + + if (!strncmp(device,"COM",3)) { + port = device[3] - '0'; + + if (!ValidCOMPort(port)) { + commerror = IE_BADID; + return -1; + } + if (COM[port].fd) { + commerror = IE_OPEN; + return -1; + } + + fd = open(COM[port].devicename, O_RDWR | O_NONBLOCK, 0); + if (fd == -1) { + commerror = WinError(); + return -1; + } else { + COM[port].fd = fd; + return fd; + } + } + else + if (!strncmp(device,"LPT",3)) { + port = device[3] - '0'; + + if (!ValidLPTPort(port)) { + commerror = IE_BADID; + return -1; + } + if (LPT[port].fd) { + commerror = IE_OPEN; + return -1; + } + + fd = open(LPT[port].devicename, O_RDWR | O_NONBLOCK, 0); + if (fd == -1) { + commerror = WinError(); + return -1; + } else { + LPT[port].fd = fd; + return fd; + } + } + return 0; +} + +int CloseComm(int fd) +{ + int status; + +#ifdef DEBUG_COMM +fprintf(stderr,"CloseComm: fd %d\n", fd); +#endif + + if (close(fd) == -1) { + commerror = WinError(); + return -1; + } else { + commerror = 0; + return 0; + } +} + +int SetCommBreak(int fd) +{ + struct DosDeviceStruct *ptr; + +#ifdef DEBUG_COMM +fprintf(stderr,"SetCommBreak: fd: %d\n", fd); +#endif + + if ((ptr = GetDeviceStruct(fd)) == NULL) { + commerror = IE_BADID; + return -1; + } + + ptr->suspended = 1; + commerror = 0; + return 0; +} + +int ClearCommBreak(int fd) +{ + struct DosDeviceStruct *ptr; + +#ifdef DEBUG_COMM +fprintf(stderr,"ClearCommBreak: fd: %d\n", fd); +#endif + + if ((ptr = GetDeviceStruct(fd)) == NULL) { + commerror = IE_BADID; + return -1; + } + + ptr->suspended = 0; + commerror = 0; + return 0; +} + +LONG EscapeCommFunction(int fd, int nFunction) +{ + int max; + struct termios port; + +#ifdef DEBUG_COMM +fprintf(stderr,"EscapeCommFunction fd: %d, function: %d\n", fd, nFunction); +#endif + + if (tcgetattr(fd, &port) == -1) { + commerror = WinError(); + return -1; + } + + switch (nFunction) { + case RESETDEV: + break; + + case GETMAXCOM: + for (max = 0;COM[max].devicename;max++) + ; + return max; + break; + + case GETMAXLPT: + for (max = 0;LPT[max].devicename;max++) + ; + return 0x80 + max; + break; + + case CLRDTR: + port.c_cflag &= TIOCM_DTR; + break; + + case CLRRTS: + port.c_cflag &= TIOCM_RTS; + break; + + case SETDTR: + port.c_cflag |= CRTSCTS; + break; + + case SETRTS: + port.c_cflag |= CRTSCTS; + break; + + case SETXOFF: + port.c_iflag |= IXOFF; + break; + + case SETXON: + port.c_iflag |= IXON; + break; + + default: + fprintf(stderr,"EscapeCommFunction fd: %d, unknown function: %d\n", fd, nFunction); + break; + } + + if (tcsetattr(fd, TCSADRAIN, &port) == -1) { + commerror = WinError(); + return -1; + } else { + commerror = 0; + return 0; + } +} + +int FlushComm(int fd, int fnQueue) +{ + int queue; + +#ifdef DEBUG_COMM +fprintf(stderr,"FlushComm fd: %d, queue: %d\n", fd, fnQueue); +#endif + + switch (fnQueue) { + case 0: + queue = TCOFLUSH; + break; + case 1: + queue = TCIFLUSH; + break; + default: + fprintf(stderr,"FlushComm fd: %d, UNKNOWN queue: %d\n", fd, fnQueue); + return -1; + } + + if (tcflush(fd, fnQueue)) { + commerror = WinError(); + return -1; + } else { + commerror = 0; + return 0; + } +} + +int GetCommError(int fd, COMSTAT FAR *lpStat) +{ +#ifdef DEBUG_COMM +fprintf(stderr,"GetCommError: fd %d (current error %d)\n", fd, commerror); +#endif + + return(commerror); +} + +UINT FAR* SetCommEventMask(int fd, UINT fuEvtMask) +{ +#ifdef DEBUG_COMM +fprintf(stderr,"SetCommEventMask: fd %d, mask %d\n", fd, fuEvtMask); +#endif + + eventmask |= fuEvtMask; + return (UINT *)&eventmask; +} + +UINT GetCommEventMask(int fd, int fnEvtClear) +{ +#ifdef DEBUG_COMM +fprintf(stderr,"GetCommEventMask: fd %d, mask %d\n", fd, fnEvtClear); +#endif + eventmask &= ~fnEvtClear; + return eventmask; +} + +int SetCommState(DCB FAR *lpdcb) +{ + struct termios port; + +#ifdef DEBUG_COMM +fprintf(stderr,"SetCommState: fd %d, ptr %d\n", lpdcb->Id, lpdcb); +#endif + + if (tcgetattr(lpdcb->Id, &port) == -1) { + commerror = WinError(); + return -1; + } + cfmakeraw(&port); + port.c_cc[VMIN] = 0; + port.c_cc[VTIME] = 0; + + fprintf(stderr,"SetCommState: baudrate %d\n",lpdcb->BaudRate); +#ifdef CBAUD + port.c_cflag &= ~CBAUD; + switch (lpdcb->BaudRate) { + case 110: + case CBR_110: + port.c_cflag |= B110; + break; + case 300: + case CBR_300: + port.c_cflag |= B300; + break; + case 600: + case CBR_600: + port.c_cflag |= B600; + break; + case 1200: + case CBR_1200: + port.c_cflag |= B1200; + break; + case 2400: + case CBR_2400: + port.c_cflag |= B2400; + break; + case 4800: + case CBR_4800: + port.c_cflag |= B4800; + break; + case 9600: + case CBR_9600: + port.c_cflag |= B9600; + break; + case 19200: + case CBR_19200: + port.c_cflag |= B19200; + break; + case 38400: + case CBR_38400: + port.c_cflag |= B38400; + break; + default: + commerror = IE_BAUDRATE; + return -1; + } +#else + switch (lpdcb->BaudRate) { + case 110: + case CBR_110: + port.c_ospeed = B110; + break; + case 300: + case CBR_300: + port.c_ospeed = B300; + break; + case 600: + case CBR_600: + port.c_ospeed = B600; + break; + case 1200: + case CBR_1200: + port.c_ospeed = B1200; + break; + case 2400: + case CBR_2400: + port.c_ospeed = B2400; + break; + case 4800: + case CBR_4800: + port.c_ospeed = B4800; + break; + case 9600: + case CBR_9600: + port.c_ospeed = B9600; + break; + case 19200: + case CBR_19200: + port.c_ospeed = B19200; + break; + case 38400: + case CBR_38400: + port.c_ospeed = B38400; + break; + default: + commerror = IE_BAUDRATE; + return -1; + } + port.c_ispeed = port.c_ospeed; +#endif + fprintf(stderr,"SetCommState: bytesize %d\n",lpdcb->ByteSize); + port.c_cflag &= ~CSIZE; + switch (lpdcb->ByteSize) { + case 5: + port.c_cflag |= CS5; + break; + case 6: + port.c_cflag |= CS6; + break; + case 7: + port.c_cflag |= CS7; + break; + case 8: + port.c_cflag |= CS8; + break; + default: + commerror = IE_BYTESIZE; + return -1; + } + + fprintf(stderr,"SetCommState: parity %d\n",lpdcb->Parity); + port.c_cflag &= ~(PARENB | PARODD); + if (lpdcb->fParity) + switch (lpdcb->Parity) { + case NOPARITY: + port.c_iflag &= ~INPCK; + break; + case ODDPARITY: + port.c_cflag |= (PARENB | PARODD); + port.c_iflag |= INPCK; + break; + case EVENPARITY: + port.c_cflag |= PARENB; + port.c_iflag |= INPCK; + break; + default: + commerror = IE_BYTESIZE; + return -1; + } + + + fprintf(stderr,"SetCommState: stopbits %d\n",lpdcb->StopBits); + switch (lpdcb->StopBits) { + case ONESTOPBIT: + port.c_cflag &= ~CSTOPB; + break; + case TWOSTOPBITS: + port.c_cflag |= CSTOPB; + break; + default: + commerror = IE_BYTESIZE; + return -1; + } + + if (lpdcb->fDtrflow || lpdcb->fRtsflow || lpdcb->fOutxCtsFlow) + port.c_cflag |= CRTSCTS; + + if (lpdcb->fDtrDisable) + port.c_cflag &= ~CRTSCTS; + + if (lpdcb->fInX) + port.c_iflag |= IXON; + if (lpdcb->fOutX) + port.c_iflag |= IXOFF; + + if (tcsetattr(lpdcb->Id, TCSADRAIN, &port) == -1) { + commerror = WinError(); + return -1; + } else { + commerror = 0; + return 0; + } +} + +int GetCommState(int fd, DCB FAR *lpdcb) +{ + struct termios port; + +#ifdef DEBUG_COMM +fprintf(stderr,"GetCommState: fd %d, ptr %d\n", fd, lpdcb); +#endif + + if (tcgetattr(fd, &port) == -1) { + commerror = WinError(); + return -1; + } + + lpdcb->Id = fd; + +#ifdef CBAUD + switch (port.c_cflag & CBAUD) { +#else + switch (port.c_ospeed) { +#endif + case B110: + lpdcb->BaudRate = 110; + break; + case B300: + lpdcb->BaudRate = 300; + break; + case B600: + lpdcb->BaudRate = 600; + break; + case B1200: + lpdcb->BaudRate = 1200; + break; + case B2400: + lpdcb->BaudRate = 2400; + break; + case B4800: + lpdcb->BaudRate = 4800; + break; + case B9600: + lpdcb->BaudRate = 9600; + break; + case B19200: + lpdcb->BaudRate = 19200; + break; + case B38400: + lpdcb->BaudRate = 38400; + break; + } + + switch (port.c_cflag & CSIZE) { + case CS5: + lpdcb->ByteSize = 5; + break; + case CS6: + lpdcb->ByteSize = 6; + break; + case CS7: + lpdcb->ByteSize = 7; + break; + case CS8: + lpdcb->ByteSize = 8; + break; + } + + switch (port.c_cflag & ~(PARENB | PARODD)) { + case 0: + lpdcb->fParity = NOPARITY; + break; + case PARENB: + lpdcb->fParity = EVENPARITY; + break; + case (PARENB | PARODD): + lpdcb->fParity = ODDPARITY; + break; + } + + if (port.c_cflag & CSTOPB) + lpdcb->StopBits = TWOSTOPBITS; + else + lpdcb->StopBits = ONESTOPBIT; + + lpdcb->RlsTimeout = 50; + lpdcb->CtsTimeout = 50; + lpdcb->DsrTimeout = 50; + lpdcb->fNull = 0; + lpdcb->fChEvt = 0; + lpdcb->fBinary = 1; + + lpdcb->fDtrDisable = 0; + if (port.c_cflag & CRTSCTS) { + lpdcb->fDtrflow = 1; + lpdcb->fRtsflow = 1; + lpdcb->fOutxCtsFlow = 1; + lpdcb->fOutxDsrFlow = 1; + } else + lpdcb->fDtrDisable = 1; + + if (port.c_iflag & IXON) + lpdcb->fInX = 1; + else + lpdcb->fInX = 0; + + if (port.c_iflag & IXOFF) + lpdcb->fOutX = 1; + else + lpdcb->fOutX = 0; +/* + lpdcb->XonChar = + lpdcb->XoffChar = + */ + lpdcb->XonLim = 10; + lpdcb->XoffLim = 10; + + commerror = 0; + return 0; +} + +int TransmitCommChar(int fd, char chTransmit) +{ + struct DosDeviceStruct *ptr; + +#ifdef DEBUG_COMM +fprintf(stderr,"TransmitCommChar: fd %d, data %d \n", fd, chTransmit); +#endif + + if ((ptr = GetDeviceStruct(fd)) == NULL) { + commerror = IE_BADID; + return -1; + } + + if (ptr->suspended) { + commerror = IE_HARDWARE; + return -1; + } + + if (write(fd, (void *) &chTransmit, 1) == -1) { + commerror = WinError(); + return -1; + } else { + commerror = 0; + return 0; + } +} + +int UngetCommChar(int fd, char chUnget) +{ + struct DosDeviceStruct *ptr; + +#ifdef DEBUG_COMM +fprintf(stderr,"UngetCommChar: fd %d (char %d)\n", fd, chUnget); +#endif + fprintf(stderr,"NOT implemented!\n"); + + if ((ptr = GetDeviceStruct(fd)) == NULL) { + commerror = IE_BADID; + return -1; + } + + if (ptr->suspended) { + commerror = IE_HARDWARE; + return -1; + } + + commerror = 0; + return 0; +} + +int ReadComm(int fd, LPSTR lpvBuf, int cbRead) +{ + struct DosDeviceStruct *ptr; +#ifdef DEBUG_COMM +fprintf(stderr,"ReadComm: fd %d, ptr %d, length %d\n", fd, lpvBuf, cbRead); +#endif + if ((ptr = GetDeviceStruct(fd)) == NULL) { + commerror = IE_BADID; + return -1; + } + + if (ptr->suspended) { + commerror = IE_HARDWARE; + return -1; + } + + if (read(fd, (void *) lpvBuf, cbRead) == -1) { + commerror = WinError(); + return -1; + } else { + commerror = 0; + return 0; + } +} + +int WriteComm(int fd, LPSTR lpvBuf, int cbWrite) +{ + int x; + struct DosDeviceStruct *ptr; + +#ifdef DEBUG_COMM +fprintf(stderr,"WriteComm: fd %d, ptr %d, length %d\n", fd, lpvBuf, cbWrite); +#endif + + if ((ptr = GetDeviceStruct(fd)) == NULL) { + commerror = IE_BADID; + return -1; + } + + if (ptr->suspended) { + commerror = IE_HARDWARE; + return -1; + } + + for (x=0; x != cbWrite ; x++) + fprintf(stderr,"%c", *(lpvBuf + x) ); + + if (write(fd, (void *) lpvBuf, cbWrite) == -1) { + commerror = WinError(); + return -1; + } else { + commerror = 0; + return 0; + } +} diff --git a/misc/dos.c b/misc/dos.c deleted file mode 100644 index f5f80fcced5..00000000000 --- a/misc/dos.c +++ /dev/null @@ -1,76 +0,0 @@ -static char RCSId[] = "$Id$"; -static char Copyright[] = "Copyright Robert J. Amstadt, 1993"; - -#include -#include -#include -#include "prototypes.h" -#include "regfunc.h" - -static void -GetTimeDate(int time_flag) -{ - struct tm *now; - time_t ltime; - - ltime = time(NULL); - now = localtime(<ime); - if (time_flag) - { - _CX = (now->tm_hour << 8) | now->tm_min; - _DX = now->tm_sec << 8; - } - else - { - _CX = now->tm_year + 1900; - _DX = ((now->tm_mon + 1) << 8) | now->tm_mday; - _AX &= 0xff00; - _AX |= now->tm_wday; - } -#ifdef DEBUG_DOS - printf("GetTimeDate: AX = %04x, CX = %04x, DX = %04x\n", _AX, _CX, _DX); -#endif - - ReturnFromRegisterFunc(); - /* Function does not return */ -} - -/********************************************************************** - * KERNEL_DOS3Call - */ -int -KERNEL_DOS3Call() -{ - switch ((_AX >> 8) & 0xff) - { - case 0x30: - _AX = 0x0303; - ReturnFromRegisterFunc(); - /* Function does not return */ - - case 0x25: - case 0x35: - return 0; - - case 0x2a: - GetTimeDate(0); - /* Function does not return */ - - case 0x2c: - GetTimeDate(1); - /* Function does not return */ - - case 0x4c: - exit(_AX & 0xff); - - default: - fprintf(stderr, "DOS: AX %04x, BX %04x, CX %04x, DX %04x\n", - _AX, _BX, _CX, _DX); - fprintf(stderr, " SP %04x, BP %04x, SI %04x, DI %04x\n", - _SP, _BP, _SI, _DI); - fprintf(stderr, " DS %04x, ES %04x\n", - _DS, _ES); - } - - return 0; -} diff --git a/misc/dos_fs.c b/misc/dos_fs.c new file mode 100644 index 00000000000..e0722741415 --- /dev/null +++ b/misc/dos_fs.c @@ -0,0 +1,756 @@ +/* + * DOS-FS + * NOV 1993 Erik Bos (erik@(trashcan.)hacktic.nl) + * + * FindFile by Bob, hacked for dos & unixpaths by Erik. + */ + +#include +#include +#include +#include +#include +#ifdef __linux__ +#include +#endif +#ifdef __NetBSD__ +#include +#include +#endif +#include +#include "windows.h" +#include "wine.h" +#include "int21.h" + +/* + #define DEBUG +*/ +#define MAX_OPEN_DIRS 16 + +extern char WindowsDirectory[256], SystemDirectory[256],TempDirectory[256]; + +char WindowsPath[256]; + +void DOS_DeInitFS(void); +int DOS_SetDefaultDrive(int); +char *GetDirectUnixFileName(char *); +void ToDos(char *); +void ToUnix(char *); + +int CurrentDrive = 2; + +struct DosDriveStruct { /* eg: */ + char *rootdir; /* /usr/windows */ + char cwd[256]; /* / */ + char label[13]; /* DRIVE-A */ + unsigned int serialnumber; /* ABCD5678 */ + int disabled; /* 0 */ +}; + +struct DosDriveStruct DosDrives[MAX_DOS_DRIVES]; + +struct dosdirent DosDirs[MAX_OPEN_DIRS]; + +void DOS_InitFS(void) +{ + int x; + char drive[2], temp[256], *ptr; + + GetPrivateProfileString("wine", "windows", "c:\\windows", + WindowsDirectory, sizeof(WindowsDirectory), WINE_INI); + + GetPrivateProfileString("wine", "system", "c:\\windows\\system", + SystemDirectory, sizeof(SystemDirectory), WINE_INI); + + GetPrivateProfileString("wine", "temp", "c:\\windows", + TempDirectory, sizeof(TempDirectory), WINE_INI); + + GetPrivateProfileString("wine", "path", "c:\\windows;c:\\windows\\system", + WindowsPath, sizeof(WindowsPath), WINE_INI); + + ToDos(WindowsDirectory); + ToDos(SystemDirectory); + ToDos(TempDirectory); + ToDos(WindowsPath); + +#ifdef DEBUG + fprintf(stderr,"wine.ini = %s\n",WINE_INI); + fprintf(stderr,"win.ini = %s\n",WIN_INI); + fprintf(stderr,"windir = %s\n",WindowsDirectory); + fprintf(stderr,"sysdir = %s\n",SystemDirectory); + fprintf(stderr,"tempdir = %s\n",TempDirectory); + fprintf(stderr,"path = %s\n",WindowsPath); +#endif + + for (x=0; x!=MAX_DOS_DRIVES; x++) { + DosDrives[x].serialnumber = (0xEB0500L | x); + + drive[0] = 'A' + x; + drive[1] = '\0'; + GetPrivateProfileString("drives", drive, "*", temp, sizeof(temp), WINE_INI); + if (!strcmp(temp, "*") || *temp == '\0') { + DosDrives[x].rootdir = NULL; + DosDrives[x].cwd[0] = '\0'; + DosDrives[x].label[0] = '\0'; + DosDrives[x].disabled = 1; + continue; + } + + if ((ptr = (char *) malloc(strlen(temp)+1)) == NULL) { + fprintf(stderr,"DOSFS: can't malloc for drive info!"); + continue; + } + if (temp[strlen(temp)-1] == '/') + temp[strlen(temp)] = '\0'; + DosDrives[x].rootdir = ptr; + strcpy(DosDrives[x].rootdir, temp); + strcpy(DosDrives[x].cwd, "/windows/"); + strcpy(DosDrives[x].label, "DRIVE-"); + strcat(DosDrives[x].label, drive); + DosDrives[x].disabled = 0; + } + + atexit(DOS_DeInitFS); + + DOS_SetDefaultDrive(2); + + for (x=0; x!=MAX_DOS_DRIVES; x++) { + if (DosDrives[x].rootdir != NULL) { +#ifdef DEBUG + fprintf(stderr, "DOSFS: %c: => %-40s %s %s %X %d\n", + 'A'+x, + DosDrives[x].rootdir, + DosDrives[x].cwd, + DosDrives[x].label, + DosDrives[x].serialnumber, + DosDrives[x].disabled + ); +#endif + } + } + + for (x=0; x!=MAX_OPEN_DIRS ; x++) + DosDirs[x].inuse = 0; + +} + +void DOS_DeInitFS(void) +{ + int x; + + for (x=0; x!=MAX_DOS_DRIVES ; x++) + if (DosDrives[x].rootdir != NULL) { +#ifdef DEBUG + + fprintf(stderr, "DOSFS: %c: => %s %s %s %X %d\n", + 'A'+x, + DosDrives[x].rootdir, + DosDrives[x].cwd, + DosDrives[x].label, + DosDrives[x].serialnumber, + DosDrives[x].disabled + ); + free(DosDrives[x].rootdir); +#endif + } +} + +WORD DOS_GetEquipment(void) +{ + WORD equipment; + int diskdrives = 0; + +/* borrowed from Ralph Brown's interrupt lists + + bits 15-14: number of parallel devices + bit 13: [Conv] Internal modem + bit 12: reserved + bits 11- 9: number of serial devices + bit 8: reserved + bits 7- 6: number of diskette drives minus one + bits 5- 4: Initial video mode: + 00b = EGA,VGA,PGA + 01b = 40 x 25 color + 10b = 80 x 25 color + 11b = 80 x 25 mono + bit 3: reserved + bit 2: [PS] =1 if pointing device + [non-PS] reserved + bit 1: =1 if math co-processor + bit 0: =1 if diskette available for boot +*/ + + if (DosDrives[0].rootdir != NULL) + diskdrives++; + if (DosDrives[1].rootdir != NULL) + diskdrives++; + if (diskdrives) + diskdrives--; + + equipment = diskdrives << 6; + + return (equipment); +} + +int DOS_ValidDrive(int drive) +{ +/* +#ifdef DEBUG + fprintf(stderr,"ValidDrive %c (%d)\n",'A'+drive,drive); +#endif +*/ + if (drive >= MAX_DOS_DRIVES) + return 0; + if (DosDrives[drive].rootdir == NULL) + return 0; + if (DosDrives[drive].disabled) + return 0; + + return 1; +} + +int DOS_GetDefaultDrive(void) +{ +#ifdef DEBUG + fprintf(stderr,"GetDefaultDrive (%c)\n",'A'+CurrentDrive); +#endif + + return( CurrentDrive); +} + +int DOS_SetDefaultDrive(int drive) +{ +#ifdef DEBUG + fprintf(stderr,"SetDefaultDrive to %c:\n",'A'+drive); +#endif + + if (!DOS_ValidDrive(drive)) + return 1; + + CurrentDrive = drive; +} + +void ToUnix(char *s) +{ + while (*s) { + if (*s == '/') + break; + if (*s == '\\') + *s = '/'; + if (isupper(*s)) + *s = tolower(*s); + s++; + } +} + +void ToDos(char *s) +{ + while (*s) { + if (*s == '/') + *s = '\\'; + if (islower(*s)) + *s = toupper(*s); + s++; + } +} + +int DOS_DisableDrive(int drive) +{ + if (drive >= MAX_DOS_DRIVES) + return 0; + if (DosDrives[drive].rootdir == NULL) + return 0; + + DosDrives[drive].disabled = 1; + return 1; +} + +int DOS_EnableDrive(int drive) +{ + if (drive >= MAX_DOS_DRIVES) + return 0; + if (DosDrives[drive].rootdir == NULL) + return 0; + + DosDrives[drive].disabled = 0; + return 1; +} + +void GetUnixDirName(char *rootdir, char *name) +{ + int filename; + char *nameptr, *cwdptr; + + cwdptr = rootdir + strlen(rootdir); + nameptr = name; +/* +#ifdef DEBUG + fprintf(stderr,"GetUnixDirName: %s <=> %s => ",rootdir, name); +#endif +*/ + while (*nameptr) { + if (*nameptr == '.' & !filename) { + nameptr++; + if (*nameptr == '\0') { + cwdptr--; + break; + } + if (*nameptr == '.') { + cwdptr--; + while (cwdptr != rootdir) { + cwdptr--; + if (*cwdptr == '/') { + *(cwdptr+1) = '\0'; + goto next; + } + + } + goto next; + } + if (*nameptr == '\\' || *nameptr == '/') { + next: nameptr++; + filename = 0; + continue; + } + } + if (*nameptr == '\\' || *nameptr == '/') { + filename = 0; + if (nameptr == name) + cwdptr = rootdir; + *cwdptr++='/'; + nameptr++; + continue; + } + filename = 1; + *cwdptr++ = *nameptr++; + } + *cwdptr = '\0'; + + ToUnix(rootdir); +/* +#ifdef DEBUG + fprintf(stderr,"%s\n", rootdir); +#endif +*/ +} + +char *GetDirectUnixFileName(char *dosfilename) +{ + /* a:\windows\system.ini => /dos/windows/system.ini */ + + int drive; + char x, temp[256]; + + if (dosfilename[1] == ':') + { + drive = (islower(*dosfilename) ? toupper(*dosfilename) : *dosfilename) - 'A'; + + if (!DOS_ValidDrive(drive)) + return NULL; + else + dosfilename+=2; + } else + drive = CurrentDrive; + + strcpy(temp,DosDrives[drive].rootdir); + strcat(temp, DosDrives[drive].cwd); + GetUnixDirName(temp + strlen(DosDrives[drive].rootdir), dosfilename); + + ToUnix(temp); + +#ifdef DEBUG + fprintf(stderr,"GetDirectUnixFileName: %c:%s => %s\n",'A'+ drive, dosfilename, temp); +#endif + + return(temp); +} + +char *GetUnixFileName(char *dosfilename) +{ + char *dirname, *unixname, workingpath[256], temp[256]; + + /* check if program specified a path */ + + if (*dosfilename == '.' || *dosfilename == '\\') + return( GetDirectUnixFileName(dosfilename) ); + + /* nope, lets find it */ + +#ifdef DEBUG + fprintf(stderr,"GetUnixFileName: %s\n",dosfilename); +#endif + + strcpy(workingpath, WindowsPath); + + for(dirname = strtok(workingpath, ";") ; + dirname != NULL; + dirname = strtok(NULL, ";")) + { + strcpy(temp,dirname); + if (temp[strlen(temp)-1] != '\\') + strcat(temp,"\\"); + strcat(temp,dosfilename); + +#ifdef DEBUG + fprintf(stderr,"trying %s\n",temp); +#endif + + if ( (unixname = GetDirectUnixFileName(temp)) != NULL) + return unixname; + } + puts("FAILED!"); + return NULL; +} + +char *DOS_GetCurrentDir(int drive, char *dirname) +{ + /* should return 'windows\system' */ + + char temp[256]; + + if (!DOS_ValidDrive(drive)) + return 0; + + strcpy(temp, DosDrives[drive].cwd); + ToDos(temp); + + if (temp[strlen(temp)-1] == '\\') + temp[strlen(temp)] = '\0'; + +#ifdef DEBUG + fprintf(stderr,"DOS_GetCWD: %c:\%s",'A'+drive, temp+1); +#endif + return (temp+1); +} + +int DOS_ChangeDir(int drive, char *dirname) +{ + if (!DOS_ValidDrive(drive)) + return 0; + + GetUnixDirName(DosDrives[drive].cwd, dirname); + strcat(DosDrives[drive].cwd,"/"); +#ifdef DEBUG + fprintf(stderr,"DOS_SetCWD: %c:\%s",'A'+drive, DosDrives[drive].cwd); +#endif + return 1; +} + +int DOS_MakeDir(int drive, char *dirname) +{ + char temp[256]; + + if (!DOS_ValidDrive(drive)) + return 0; + + strcpy(temp, DosDrives[drive].cwd); + GetUnixDirName(temp, dirname); + strcat(DosDrives[drive].cwd,"/"); + + ToUnix(temp); + mkdir(temp,0); + +#ifdef DEBUG + fprintf(stderr,"DOS_MakeDir: %c:\%s => %s",'A'+drive, dirname, temp); +#endif +} + +/* +void main(void) +{ + strcpy(DosDrives[0].cwd, "1/2/3/"); + + puts(DosDrives[0].cwd); + ChangeDir(0,".."); + puts(DosDrives[0].cwd); + + ChangeDir(0,"..\\.."); + puts(DosDrives[0].cwd); + + ChangeDir(0,"."); + puts(DosDrives[0].cwd); + + ChangeDir(0,"test"); + puts(DosDrives[0].cwd); + + ChangeDir(0,"\\qwerty\\ab"); + puts(DosDrives[0].cwd); + + ChangeDir(0,"erik\\.\\bos\\..\\24"); + puts(DosDrives[0].cwd); + +} +*/ + +int DOS_GetSerialNumber(int drive, unsigned long *serialnumber) +{ + if (!DOS_ValidDrive(drive)) + return 0; + + *serialnumber = DosDrives[drive].serialnumber; + return 1; +} + +int DOS_SetSerialNumber(int drive, unsigned long serialnumber) +{ + if (!DOS_ValidDrive(drive)) + return 0; + + DosDrives[drive].serialnumber = serialnumber; + return 1; +} + +int DOS_GetFreeSpace(int drive, long *size, long *available) +{ + struct statfs info; + + if (!DOS_ValidDrive(drive)) + return 0; + + if (statfs(DosDrives[drive].rootdir, &info) < 0) { + fprintf(stderr,"dosfs: cannot do statfs(%s)\n",DosDrives[drive].rootdir); + return 0; + } + + *size = info.f_bsize * info.f_blocks / 1024; + *available = info.f_bavail * info.f_bsize / 1024; + + return 1; +} + +char *FindFile(char *buffer, int buflen, char *rootname, char **extensions, + char *path) +{ + char *workingpath; + char *dirname; + DIR *d; + struct dirent *f; + char **e; + int rootnamelen; + int found = 0; + + + if (strchr(rootname, '\\') != NULL) + { + strncpy(buffer, GetDirectUnixFileName(rootname), buflen); + ToUnix(buffer); + +#ifdef DEBUG +fprintf(stderr,"FindFile: %s -> %s\n",rootname,buffer); +#endif + + return buffer; + } + + if (strchr(rootname, '/') != NULL) + { + strncpy(buffer, rootname, buflen); + +#ifdef DEBUG +fprintf(stderr,"FindFile: %s -> %s\n",rootname,buffer); +#endif + + return buffer; + } + +#ifdef DEBUG +fprintf(stderr,"FindFile: looking for %s\n",rootname); +#endif + + ToUnix(rootname); + + rootnamelen = strlen(rootname); + workingpath = malloc(strlen(path) + 1); + if (workingpath == NULL) + return NULL; + strcpy(workingpath, path); + + for(dirname = strtok(workingpath, ";"); + dirname != NULL; + dirname = strtok(NULL, ";")) + { + if (strchr(dirname, '\\')!=NULL) + d = opendir( GetDirectUnixFileName(dirname) ); + else + d = opendir( dirname ); + +#ifdef DEBUG + fprintf(stderr,"in %s\n",dirname); +#endif + + if (d != NULL) + { + while ((f = readdir(d)) != NULL) + { + if (strncasecmp(rootname, f->d_name, rootnamelen) == 0) + { + if (extensions == NULL || + strcasecmp(rootname, f->d_name) == 0) + { + found = 1; + } + else if (f->d_name[rootnamelen] == '.') + { + for (e = extensions; *e != NULL; e++) + { + if (strcasecmp(*e, f->d_name + rootnamelen + 1) + == 0) + { + found = 1; + break; + } + } + } + + if (found) + { + if (strchr(dirname, '\\')!=NULL) + strncpy(buffer, GetDirectUnixFileName(dirname), buflen); + else + strncpy(buffer, dirname, buflen); + + if (buffer[strlen(buffer)-1]!='/') + strncat(buffer, "/", buflen - strlen(buffer)); + + strncat(buffer, f->d_name, buflen - strlen(buffer)); + closedir(d); + + ToUnix(buffer); + + return buffer; + } + } + } + closedir(d); + } + } + return NULL; +} + +/********************************************************************** + * WineIniFileName + */ +char *WineIniFileName(void) +{ + static char *IniName = NULL; + char inipath[256]; + + if (IniName) + return IniName; + + getcwd(inipath, 256); + strcat(inipath, ";"); + strcat(inipath, getenv("HOME")); + strcat(inipath, ";"); + strcat(inipath, getenv("WINEPATH")); + + IniName = malloc(1024); + if (FindFile(IniName, 1024, "wine.ini", NULL, inipath) == NULL) + { + free(IniName); + IniName = NULL; + return NULL; + } + + IniName = realloc(IniName, strlen(IniName) + 1); + + ToUnix(IniName); + + return IniName; +} + +char *WinIniFileName() +{ + char name[256]; + + strcpy(name,GetDirectUnixFileName(WindowsDirectory)); + strcat(name,"win.ini"); + + ToUnix(name); + + return name; +} + +struct dosdirent *DOS_opendir(char *dosdirname) +{ + int x,y; + char *unixdirname; + char temp[256]; + + for (x=0; x != MAX_OPEN_DIRS && DosDirs[x].inuse; x++) + ; + + if (x == MAX_OPEN_DIRS) + return NULL; + + if ((unixdirname = GetDirectUnixFileName(dosdirname)) == NULL) + return NULL; + + strcpy(temp,unixdirname); + + + y = strlen(temp); + + while (y--) + { + if (temp[y] == '/') + { + temp[y] = '\0'; + break; + } + } + + fprintf(stderr,"%s -> %s\n",unixdirname,temp); + + DosDirs[x].inuse = 1; + strcpy(DosDirs[x].unixpath, temp); + + if ((DosDirs[x].ds = opendir(temp)) == NULL) + return NULL; + + return &DosDirs[x]; +} + + +struct dosdirent *DOS_readdir(struct dosdirent *de) +{ + char temp[256]; + struct dirent *d; + struct stat st; + + if (!de->inuse) + return NULL; + + if ((d = readdir(de->ds)) == NULL) + { + closedir(de->ds); + de->inuse = 0; + return de; + } + + strcpy(de->filename, d->d_name); + if (d->d_reclen > 12) + de->filename[12] = '\0'; + ToDos (de->filename); + + de->attribute = 0x0; + + strcpy(temp,de->unixpath); + strcat(temp,"/"); + strcat(temp,de->filename); + ToUnix(temp); + stat (temp, &st); + if S_ISDIR(st.st_mode) + de->attribute |= 0x08; + + return de; +} + +void DOS_closedir(struct dosdirent *de) +{ + if (de->inuse) + { + closedir(de->ds); + de->inuse = 0; + } +} diff --git a/misc/file.c b/misc/file.c index 559fac09cd3..adc43683313 100644 --- a/misc/file.c +++ b/misc/file.c @@ -3,98 +3,29 @@ * * File I/O routines for the Linux Wine Project. * - * There are two main parts to this module - first there are the - * actual emulation functions, and secondly a routine for translating - * DOS filenames into UNIX style filenames. - * - * For each DOS drive letter, we need to store the location in the unix - * file system to map that drive to, and the current directory for that - * drive. - * - * Finally we need to store the current drive letter in this module. - * * WARNING : Many options of OpenFile are not yet implemeted. * - * + * NOV 93 Erik Bos (erik@(trashcan.)hacktic.nl + * - removed ParseDosFileName, and DosDrive structures. + * - structures dynamically configured at runtime. + * - _lopen modified to use GetUnixFileName. + * + * DEC 93 Erik Bos (erik@(trashcan.)hacktic.nl) + * - Existing functions modified to use dosfs functions. + * - Added _llseek, _lcreate, GetDriveType, GetTempDrive, + * GetWindowsDirectory, GetSystemDirectory, GetTempFileName. + * ************************************************************************/ +#define DEBUG_FILE + #include -#include #include #include -#include #include +#include "prototypes.h" -#define OPEN_MAX 256 - -/*************************************************************************** - This structure stores the infomation needed for a single DOS drive - ***************************************************************************/ -struct DosDriveStruct -{ - char RootDirectory [256]; /* Unix base for this drive letter */ - char CurrentDirectory [256]; /* Current directory for this drive */ -}; - -/*************************************************************************** - Table for DOS drives - ***************************************************************************/ -struct DosDriveStruct DosDrives[] = -{ - {"/mnt/floppy1" , ""}, - {"/mnt/floppy2" , ""}, - {"/mnt/HardDisk", "/wine"}, - {"" , "/wine/Wine"} -}; - -#define NUM_DRIVES (sizeof (DosDrives) / sizeof (struct DosDriveStruct)) - - -/************************************************************************** - Global variable to store current drive letter (0 = A, 1 = B etc) - **************************************************************************/ -int CurrentDrive = 2; - -/************************************************************************** - ParseDOSFileName - - Return a fully specified DOS filename with the disk letter separated from - the path information. - **************************************************************************/ -void ParseDOSFileName (char *UnixFileName, char *DosFileName, int *Drive) -{ - int character; - - for (character = 0; character < strlen(DosFileName); character++) - { - if (DosFileName[character] == '\\') - DosFileName[character] = '/'; - } - - - if (DosFileName[1] == ':') - { - *Drive = DosFileName[0] - 'A'; - if (*Drive > 26) - *Drive = *Drive - 'a' + 'A'; - DosFileName = DosFileName + 2; - } - else - *Drive = CurrentDrive; - - if (DosFileName[0] == '/') - { - strcpy (UnixFileName, DosDrives[*Drive].RootDirectory); - strcat (UnixFileName, DosFileName); - return; - } - - strcpy (UnixFileName, DosDrives[*Drive].RootDirectory); - strcat (UnixFileName, DosDrives[*Drive].CurrentDirectory); - strcat (UnixFileName, "/"); - strcat (UnixFileName, DosFileName); - return; -} +char WindowsDirectory[256], SystemDirectory[256], TempDirectory[256]; /*************************************************************************** @@ -104,20 +35,26 @@ void ParseDOSFileName (char *UnixFileName, char *DosFileName, int *Drive) ***************************************************************************/ WORD KERNEL__lopen (LPSTR lpPathName, WORD iReadWrite) { - char UnixFileName[256]; - int Drive; int handle; + char *UnixFileName; - ParseDOSFileName (UnixFileName, lpPathName, &Drive); - +#ifdef DEBUG_FILE + fprintf (stderr, "_lopen: open %s\n", lpPathName); +#endif + if ((UnixFileName = GetUnixFileName(lpPathName)) == NULL) + return HFILE_ERROR; handle = open (UnixFileName, iReadWrite); #ifdef DEBUG_FILE - fprintf (stderr, "_lopen: %s (Handle = %d)\n", UnixFileName, handle); + fprintf (stderr, "_lopen: open: %s (handle %d)\n", UnixFileName, handle); #endif - return handle; + + if (handle == -1) + return HFILE_ERROR; + else + return handle; } /*************************************************************************** @@ -126,26 +63,37 @@ WORD KERNEL__lopen (LPSTR lpPathName, WORD iReadWrite) WORD KERNEL__lread (WORD hFile, LPSTR lpBuffer, WORD wBytes) { int result; + +#ifdef DEBUG_FILE + fprintf(stderr, "_lread: handle %d, buffer = %ld, length = %d\n", + hFile, lpBuffer, wBytes); +#endif result = read (hFile, lpBuffer, wBytes); -#ifdef DEBUG_FILE - fprintf(stderr, "_lread: hFile = %d, lpBuffer = %s, wBytes = %d\n", - hFile, lpBuffer, wBytes); -#endif - return result; -} + if (result == -1) + return HFILE_ERROR; + else + return result; +} /**************************************************************************** _lwrite ****************************************************************************/ WORD KERNEL__lwrite (WORD hFile, LPSTR lpBuffer, WORD wBytes) { + int result; + #ifdef DEBUG_FILE - fprintf(stderr, "_lwrite: hFile = %d, lpBuffer = %s, wBytes = %d\n", - hFile, lpBuffer, wBytes); + fprintf(stderr, "_lwrite: handle %d, buffer = %ld, length = %d\n", + hFile, lpBuffer, wBytes); #endif - return write (hFile, lpBuffer, wBytes); + result = write (hFile, lpBuffer, wBytes); + + if (result == -1) + return HFILE_ERROR; + else + return result; } /*************************************************************************** @@ -153,6 +101,10 @@ WORD KERNEL__lwrite (WORD hFile, LPSTR lpBuffer, WORD wBytes) ***************************************************************************/ WORD KERNEL__lclose (WORD hFile) { +#ifdef DEBUG_FILE + fprintf(stderr, "_lclose: handle %d\n", hFile); +#endif + close (hFile); } @@ -166,7 +118,9 @@ WORD KERNEL_OpenFile (LPSTR lpFileName, LPOFSTRUCT ofs, WORD wStyle) { int base,flags; +#ifdef DEBUG_FILE fprintf(stderr,"Openfile(%s,,%d) ",lpFileName,wStyle); +#endif base=wStyle&0xF; flags=wStyle&0xFFF0; @@ -204,7 +158,148 @@ WORD SetHandleCount (WORD wNumber) return((wNumber %s\n",bDriveLetter, + lpszPrefixString,uUnique,lpszTempFileName); +#endif + + return unique; +} + +/*************************************************************************** + SetErrorMode + ***************************************************************************/ +WORD SetErrorMode(WORD x) +{ + fprintf(stderr,"wine: SetErrorMode %4x (ignored)\n",x); +} diff --git a/loader/int1a.c b/misc/int1a.c similarity index 93% rename from loader/int1a.c rename to misc/int1a.c index 2441d77f526..addfdbcbb92 100644 --- a/loader/int1a.c +++ b/misc/int1a.c @@ -51,7 +51,7 @@ int do_int1A(struct sigcontext_struct * context){ break; default: - fprintf(stderr,"Unable to handle int 0x1A AX %x\n", context->sc_eax); + fprintf(stderr,"Unable to handle int 0x1A AX %04x\n", context->sc_eax & 0xffffL); return 1; }; return 1; diff --git a/loader/int21.c b/misc/int21.c similarity index 52% rename from loader/int21.c rename to misc/int21.c index fdf506aa486..4d1ae704d76 100644 --- a/loader/int21.c +++ b/misc/int21.c @@ -5,34 +5,23 @@ #include #include #include -#ifdef linux -#include -#endif -#ifdef __NetBSD__ -#include -#endif #include #include #include +#include "prototypes.h" +#include "regfunc.h" #include "windows.h" #include "wine.h" #include "int21.h" -#include "files.h" -#define MAX_DRIVES 26 - -static char Copyright[] = "int21.c, copyright Erik Bos, 1993"; - -extern struct DosDriveStruct DosDrives[]; -extern int CurrentDrive; -extern void ParseDOSFileName(); - -int ValidDrive(int); +static char Copyright[] = "copyright Erik Bos, 1993"; WORD ExtendedError, CodePage = 437; BYTE ErrorClass, Action, ErrorLocus; +extern char *TempDirectory; + void Error(int e, int class, int el) { ExtendedError = e; @@ -44,115 +33,99 @@ void Error(int e, int class, int el) void GetFreeDiskSpace(struct sigcontext_struct *context) { int drive; - struct statfs info; - long size,avail; + long size,available; - if (!(DX & 0xff)) - drive = CurrentDrive; + if (!(EDX & 0xffL)) + drive = DOS_GetDefaultDrive(); else - drive = (DX & 0xff) - 1; + drive = (EDX & 0xffL) - 1; - if (!ValidDrive(drive)) { + if (!DOS_ValidDrive(drive)) { Error(InvalidDrive, EC_MediaError , EL_Disk); - AX = 0xffff; + EAX |= 0xffffL; return; } - { - if (statfs(DosDrives[drive].RootDirectory, &info) < 0) { - fprintf(stderr,"cannot do statfs(%s)\n",DosDrives[drive].RootDirectory); - Error(GeneralFailure, EC_MediaError , EL_Disk); - AX = 0xffff; - return; - } - - size = info.f_bsize * info.f_blocks / 1024; - avail = info.f_bavail * info.f_bsize / 1024; - - #ifdef DOSDEBUG - fprintf(stderr,"statfs: size: %8d avail: %8d\n",size,avail); - #endif - - AX = SectorsPerCluster; - CX = SectorSize; - - BX = (avail / (CX * AX)); - DX = (size / (CX * AX)); - Error (0,0,0); + if (!DOS_GetFreeSpace(drive, &size, &available)) { + Error(GeneralFailure, EC_MediaError , EL_Disk); + EAX |= 0xffffL; + return; } + + EAX = (EAX & 0xffff0000L) | SectorsPerCluster; + ECX = (ECX & 0xffff0000L) | SectorSize; + + EBX = (EBX & 0xffff0000L) | (available / (CX * AX)); + EDX = (EDX & 0xffff0000L) | (size / (CX * AX)); + Error (0,0,0); } void SetDefaultDrive(struct sigcontext_struct *context) { - if ((DX & 0xff) < MAX_DRIVES) { - CurrentDrive = DX & 0xff; - AX &= 0xff00; - AX |= MAX_DRIVES; /* # of valid drive letters */ - Error (0,0,0); - } else + int drive; + + drive = EDX & 0xffL; + + if (!DOS_ValidDrive(drive)) { Error (InvalidDrive, EC_MediaError, EL_Disk); + return; + } else { + DOS_SetDefaultDrive(drive); + EAX = (EAX &0xffffff00L) | MAX_DOS_DRIVES; + Error (0,0,0); + } } void GetDefaultDrive(struct sigcontext_struct *context) { - AX &= 0xff00; - AX |= CurrentDrive; + EAX = (EAX & 0xffffff00L) | DOS_GetDefaultDrive(); Error (0,0,0); } void GetDriveAllocInfo(struct sigcontext_struct *context) { int drive; - long size; + long size, available; BYTE mediaID; - struct statfs info; - drive = DX & 0xff; + drive = EDX & 0xffL; - if (!ValidDrive(drive)) { - AX = SectorsPerCluster; - CX = SectorSize; - DX = 0; + if (!DOS_ValidDrive(drive)) { + EAX = (EAX & 0xffff0000L) | SectorsPerCluster; + ECX = (ECX & 0xffff0000L) | SectorSize; + EDX = (EDX & 0xffff0000L); Error (InvalidDrive, EC_MediaError, EL_Disk); return; } - { - if (statfs(DosDrives[drive].RootDirectory, &info) < 0) { - fprintf(stderr,"cannot do statfs(%s)\n",DosDrives[drive].RootDirectory); - Error(GeneralFailure, EC_MediaError , EL_Disk); - AX = 0xffff; - return; - } - - size = info.f_bsize * info.f_blocks / 1024; - - #ifdef DOSDEBUG - fprintf(stderr,"statfs: size: %8d\n",size); - #endif - - AX = SectorsPerCluster; - CX = SectorSize; - DX = (size / (CX * AX)); - - mediaID = 0xf0; - - DS = segment(mediaID); - BX = offset(mediaID); - Error (0,0,0); + if (!DOS_GetFreeSpace(drive, &size, &available)) { + Error(GeneralFailure, EC_MediaError , EL_Disk); + EAX |= 0xffffL; + return; } + + EAX = (EAX & 0xffff0000L) | SectorsPerCluster; + ECX = (ECX & 0xffff0000L) | SectorSize; + EDX = (EDX & 0xffff0000L) | (size / (CX * AX)); + + mediaID = 0xf0; + + DS = segment(mediaID); + EBX = offset(mediaID); + Error (0,0,0); } void GetDefDriveAllocInfo(struct sigcontext_struct *context) { - DX = CurrentDrive; + EDX = DOS_GetDefaultDrive(); GetDriveAllocInfo(context); } void GetDrivePB(struct sigcontext_struct *context) { Error (InvalidDrive, EC_MediaError, EL_Disk); - AX = 0xff; /* I'm sorry but I only got networked drives :-) */ + EAX = (EAX & 0xffff0000L) | 0xffL; + /* I'm sorry but I only got networked drives :-) */ } void ReadFile(struct sigcontext_struct *context) @@ -162,26 +135,26 @@ void ReadFile(struct sigcontext_struct *context) /* can't read from stdout / stderr */ - if (((BX & 0xffff) == 1) ||((BX & 0xffff) == 2)) { + if ((BX == 1) || (BX == 2)) { Error (InvalidHandle, EL_Unknown, EC_Unknown); - AX = InvalidHandle; + EAX = (EAX & 0xffff0000L) | InvalidHandle; SetCflag; return; } ptr = (char *) pointer (DS,DX); - if ((BX & 0xffff) == 0) { + if (BX == 0) { *ptr = EOF; Error (0,0,0); - AX = 1; + EAX = (EAX & 0xffff0000L) | 1; ResetCflag; return; } else { size = read(BX, ptr, CX); if (size == 0) { Error (ReadFault, EC_Unknown, EL_Unknown); - AX = ExtendedError; + EAX = (EAX & 0xffffff00L) | ExtendedError; return; } @@ -197,12 +170,12 @@ void ReadFile(struct sigcontext_struct *context) Error (GeneralFailure, EC_SystemFailure, EL_Unknown); break; } - AX = ExtendedError; + EAX = (EAX & 0xffffff00L) | ExtendedError; SetCflag; return; } Error (0,0,0); - AX = size; + EAX = (EAX & 0xffff0000L) | size; ResetCflag; } } @@ -214,27 +187,27 @@ void WriteFile(struct sigcontext_struct *context) ptr = (char *) pointer (DS,DX); - if ((BX & 0xffff) == 0) { + if (BX == 0) { Error (InvalidHandle, EC_Unknown, EL_Unknown); - AX = InvalidHandle; + EAX = InvalidHandle; SetCflag; return; } - if ((BX & 0xffff) < 3) { + if (BX < 3) { for (x = 0;x != CX;x++) { fprintf(stderr, "%c", *ptr++); } fflush(stderr); Error (0,0,0); - AX = CX; + EAX = (EAX & 0xffffff00L) | CX; ResetCflag; } else { size = write(BX, ptr , CX); if (size == 0) { Error (WriteFault, EC_Unknown, EL_Unknown); - AX = ExtendedError; + EAX = (EAX & 0xffffff00L) | ExtendedError; return; } @@ -253,105 +226,82 @@ void WriteFile(struct sigcontext_struct *context) Error (GeneralFailure, EC_SystemFailure, EL_Unknown); break; } - AX = ExtendedError; + EAX = (EAX & 0xffffff00L) | ExtendedError; SetCflag; return; } Error (0,0,0); - AX = size; + EAX = (EAX & 0xffff0000L) | size; ResetCflag; } } void UnlinkFile(struct sigcontext_struct *context) { - char UnixFileName[256]; - int drive, status; - - ParseDOSFileName(UnixFileName, (char *) pointer(DS,DX), &drive); - - { - status = unlink((char *) pointer(DS,DX)); - if (status == -1) { - switch (errno) { - case EACCES: - case EPERM: - case EROFS: - Error (WriteProtected, EC_AccessDenied, EL_Unknown); - break; - case EBUSY: - Error (LockViolation, EC_AccessDenied, EL_Unknown); - break; - case EAGAIN: - Error (ShareViolation, EC_Temporary, EL_Unknown); - break; - case ENOENT: - Error (FileNotFound, EC_NotFound, EL_Unknown); - break; - default: - Error (GeneralFailure, EC_SystemFailure, EL_Unknown); - break; - } - AX = ExtendedError; - SetCflag; - return; - } - Error (0,0,0); - ResetCflag; - } + if (unlink( GetUnixFileName((char *) pointer(DS,DX)) ) == -1) { + switch (errno) { + case EACCES: + case EPERM: + case EROFS: + Error (WriteProtected, EC_AccessDenied, EL_Unknown); + break; + case EBUSY: + Error (LockViolation, EC_AccessDenied, EL_Unknown); + break; + case EAGAIN: + Error (ShareViolation, EC_Temporary, EL_Unknown); + break; + case ENOENT: + Error (FileNotFound, EC_NotFound, EL_Unknown); + break; + default: + Error (GeneralFailure, EC_SystemFailure, EL_Unknown); + break; + } + EAX = (EAX & 0xffffff00L) | ExtendedError; SetCflag; + return; + } + Error (0,0,0); + ResetCflag; } void SeekFile(struct sigcontext_struct *context) { - char UnixFileName[256]; - int drive, handle, status, fileoffset; + int handle, status, fileoffset; - - ParseDOSFileName(UnixFileName, (char *) pointer(DS,DX), &drive); - - { - switch (AX & 0xff) { - case 1: fileoffset = SEEK_CUR; + switch (EAX & 0xffL) { + case 1: fileoffset = SEEK_CUR; + break; + case 2: fileoffset = SEEK_END; + break; + default: + case 0: fileoffset = SEEK_SET; + break; + } + status = lseek(BX, (CX * 0x100) + DX, fileoffset); + if (status == -1) { + switch (errno) { + case EBADF: + Error (InvalidHandle, EC_AppError, EL_Unknown); break; - case 2: fileoffset = SEEK_END; + case EINVAL: + Error (DataInvalid, EC_AppError, EL_Unknown); break; default: - case 0: fileoffset = SEEK_SET; + Error (GeneralFailure, EC_SystemFailure, EL_Unknown); break; } - status = lseek(BX, (CX * 0x100) + DX, fileoffset); - if (status == -1) { - switch (errno) { - case EBADF: - Error (InvalidHandle, EC_AppError, EL_Unknown); - break; - case EINVAL: - Error (DataInvalid, EC_AppError, EL_Unknown); - break; - default: - Error (GeneralFailure, EC_SystemFailure, EL_Unknown); - break; - } - AX = ExtendedError; - SetCflag; - return; - } - Error (0,0,0); - ResetCflag; - } + EAX = (EAX & 0xffffff00L) | ExtendedError; SetCflag; + return; + } + Error (0,0,0); + ResetCflag; } void GetFileAttributes(struct sigcontext_struct *context) { - char UnixFileName[256]; - int drive,handle; - - ParseDOSFileName(UnixFileName, (char *) pointer(DS,DX), &drive); - - { - CX = 0x0; - ResetCflag; - } + EAX &= 0xfffff00L; + ResetCflag; } void SetFileAttributes(struct sigcontext_struct *context) @@ -361,13 +311,14 @@ void SetFileAttributes(struct sigcontext_struct *context) void DosIOCTL(struct sigcontext_struct *context) { - AX = UnknownUnit; + fprintf(stderr,"int21: IOCTL\n"); + EAX = (EAX & 0xfffff00L) | UnknownUnit; SetCflag; } void DupeFileHandle(struct sigcontext_struct *context) { - AX = dup(BX); + EAX = (EAX & 0xffff0000L) | dup(BX); ResetCflag; } @@ -379,10 +330,9 @@ void GetSystemDate(struct sigcontext_struct *context) ltime = time(NULL); now = localtime(<ime); - CX = now->tm_year + 1900; - DX = ((now->tm_mon + 1) << 8) | now->tm_mday; - AX &= 0xff00; - AX |= now->tm_wday; + ECX = (ECX & 0xffff0000L) | now->tm_year + 1900; + EDX = (EDX & 0xffff0000L) | ((now->tm_mon + 1) << 8) | now->tm_mday; + EAX = (EAX & 0xffff0000L) | now->tm_wday; } void GetSystemTime(struct sigcontext_struct *context) @@ -393,115 +343,102 @@ void GetSystemTime(struct sigcontext_struct *context) ltime = time(NULL); now = localtime(<ime); - CX = (now->tm_hour << 8) | now->tm_min; - DX = now->tm_sec << 8; + ECX = (ECX & 0xffffff00L) | (now->tm_hour << 8) | now->tm_min; + EDX = (EDX & 0xffffff00L) | now->tm_sec << 8; } void GetExtendedErrorInfo(struct sigcontext_struct *context) { - AX = ExtendedError; - BX = (0x100 * ErrorClass) | Action; - CX &= 0x00ff; - CX |= (0x100 * ErrorLocus); + EAX = (EAX & 0xffffff00L) | ExtendedError; + EBX = (EBX & 0xffff0000L) | (0x100 * ErrorClass) | Action; + ECX = (ECX & 0xffff00ffL) | (0x100 * ErrorLocus); } void GetInDosFlag(struct sigcontext_struct *context) { const BYTE InDosFlag = 0; - ES = segment(InDosFlag); - BX = offset(InDosFlag); + ES = (ES & 0xffff0000L) | segment(InDosFlag); + EBX = (EBX & 0xffff0000L) | offset(InDosFlag); } void CreateFile(struct sigcontext_struct *context) { - char UnixFileName[256]; - int drive,handle; - - ParseDOSFileName(UnixFileName, (char *) pointer(DS,DX), &drive); + int handle; - { - handle = open(UnixFileName, O_CREAT | O_TRUNC); - - if (handle == -1) { - switch (errno) { - case EACCES: - case EPERM: - case EROFS: - Error (WriteProtected, EC_AccessDenied, EL_Unknown); - break; - case EISDIR: - Error (CanNotMakeDir, EC_AccessDenied, EL_Unknown); - break; - case ENFILE: - case EMFILE: - Error (NoMoreFiles, EC_MediaError, EL_Unknown); - case EEXIST: - Error (FileExists, EC_Exists, EL_Disk); - break; - case ENOSPC: - Error (DiskFull, EC_MediaError, EL_Disk); - break; - default: - Error (GeneralFailure, EC_SystemFailure, EL_Unknown); - break; - } - AX = ExtendedError; - SetCflag; - return; - } - Error (0,0,0); - BX = handle; - AX = NoError; - ResetCflag; - } + if ((handle = open(GetUnixFileName((char *) pointer(DS,DX)), O_CREAT | O_TRUNC)) == -1) { + switch (errno) { + case EACCES: + case EPERM: + case EROFS: + Error (WriteProtected, EC_AccessDenied, EL_Unknown); + break; + case EISDIR: + Error (CanNotMakeDir, EC_AccessDenied, EL_Unknown); + break; + case ENFILE: + case EMFILE: + Error (NoMoreFiles, EC_MediaError, EL_Unknown); + case EEXIST: + Error (FileExists, EC_Exists, EL_Disk); + break; + case ENOSPC: + Error (DiskFull, EC_MediaError, EL_Disk); + break; + default: + Error (GeneralFailure, EC_SystemFailure, EL_Unknown); + break; + } + EAX = (EAX & 0xffffff00L) | ExtendedError; + SetCflag; + return; + } + Error (0,0,0); + EBX = (EBX & 0xffff0000L) | handle; + EAX = (EAX & 0xffffff00L) | NoError; + ResetCflag; } void OpenExistingFile(struct sigcontext_struct *context) { - char UnixFileName[256]; - int drive, handle; - - ParseDOSFileName(UnixFileName, (char *) pointer(DS,DX), &drive); - - { - handle = open(UnixFileName, O_RDWR); + int handle; - if (handle == -1) { - switch (errno) { - case EACCES: - case EPERM: - case EROFS: - Error (WriteProtected, EC_AccessDenied, EL_Unknown); - break; - case EISDIR: - Error (CanNotMakeDir, EC_AccessDenied, EL_Unknown); - break; - case ENFILE: - case EMFILE: - Error (NoMoreFiles, EC_MediaError, EL_Unknown); - case EEXIST: - Error (FileExists, EC_Exists, EL_Disk); - break; - case ENOSPC: - Error (DiskFull, EC_MediaError, EL_Disk); - break; - case ENOENT: - Error (FileNotFound, EC_MediaError, EL_Disk); - break; - default: - Error (GeneralFailure, EC_SystemFailure, EL_Unknown); - break; - } - AX = ExtendedError; - SetCflag; - return; - } - Error (0,0,0); - BX = handle; - AX = NoError; - ResetCflag; - } + fprintf(stderr,"OpenExistingFile (%s)\n",(char *) pointer(DS,DX)); + + if ((handle = open(GetUnixFileName((char*) pointer(DS,DX)), O_RDWR)) == -1) { + switch (errno) { + case EACCES: + case EPERM: + case EROFS: + Error (WriteProtected, EC_AccessDenied, EL_Unknown); + break; + case EISDIR: + Error (CanNotMakeDir, EC_AccessDenied, EL_Unknown); + break; + case ENFILE: + case EMFILE: + Error (NoMoreFiles, EC_MediaError, EL_Unknown); + case EEXIST: + Error (FileExists, EC_Exists, EL_Disk); + break; + case ENOSPC: + Error (DiskFull, EC_MediaError, EL_Disk); + break; + case ENOENT: + Error (FileNotFound, EC_MediaError, EL_Disk); + break; + default: + Error (GeneralFailure, EC_SystemFailure, EL_Unknown); + break; + } + EAX = (EAX & 0xffffff00L) | ExtendedError; + SetCflag; + return; + } + Error (0,0,0); + EBX = (EBX & 0xffff0000L) | handle; + EAX = (EAX & 0xffffff00L) | NoError; + ResetCflag; } void CloseFile(struct sigcontext_struct *context) @@ -515,105 +452,109 @@ void CloseFile(struct sigcontext_struct *context) Error (GeneralFailure, EC_SystemFailure, EL_Unknown); break; } - AX = ExtendedError; + EAX = (EAX & 0xffffff00L) | ExtendedError; SetCflag; return; } Error (0,0,0); - AX = NoError; + EAX = (EAX & 0xffffff00L) | NoError; ResetCflag; } void RenameFile(struct sigcontext_struct *context) { - rename((char *) pointer(DS,DX), (char *) pointer(ES,DI)); + char *newname, *oldname; + + fprintf(stderr,"int21: renaming %s to %s\n",(char *) pointer(DS,DX), pointer(ES,DI) ); + + oldname = GetUnixFileName( (char *) pointer(DS,DX) ); + newname = GetUnixFileName( (char *) pointer(ES,DI) ); + + rename( oldname, newname); ResetCflag; } void GetTrueFileName(struct sigcontext_struct *context) -{ +{ + fprintf(stderr,"int21: GetTrueFileName of %s\n",(char *) pointer(DS,SI)); + strncpy((char *) pointer(ES,DI), (char *) pointer(DS,SI), strlen((char *) pointer(DS,SI)) & 0x7f); ResetCflag; } void MakeDir(struct sigcontext_struct *context) { - int drive; char *dirname; - char unixname[256]; + + fprintf(stderr,"int21: makedir %s\n",(char *) pointer(DS,DX) ); - dirname = (char *) pointer(DS,DX); - - ParseDOSFileName(unixname,dirname,&drive); - - { - if (mkdir(unixname,0) == -1) { - AX = CanNotMakeDir; - SetCflag; - } - ResetCflag; + if ((dirname = GetUnixFileName( (char *) pointer(DS,DX) ))== NULL) { + EAX = (EAX & 0xffffff00L) | CanNotMakeDir; + SetCflag; + return; } + + if (mkdir(dirname,0) == -1) { + EAX = (EAX & 0xffffff00L) | CanNotMakeDir; + SetCflag; + return; + } + ResetCflag; } void ChangeDir(struct sigcontext_struct *context) { - int drive; - char *dirname; - char unixname[256]; - - dirname = (char *) pointer(DS,DX); + fprintf(stderr,"int21: changedir %s\n",(char *) pointer(DS,DX) ); - ParseDOSFileName(unixname,dirname,&drive); - - { - strcpy(unixname,DosDrives[drive].CurrentDirectory); - ResetCflag; - } + DOS_ChangeDir(DOS_GetDefaultDrive(), (char *) pointer (DS,DX)); } void RemoveDir(struct sigcontext_struct *context) { - int drive; char *dirname; - char unixname[256]; - - dirname = (char *) pointer(DS,DX); - ParseDOSFileName(unixname,dirname,&drive); + fprintf(stderr,"int21: removedir %s\n",(char *) pointer(DS,DX) ); - { - if (strcmp(unixname,DosDrives[drive].CurrentDirectory)) { - AX = CanNotRemoveCwd; - SetCflag; - } - - #ifdef DOSDEBUG - fprintf(stderr,"rmdir %s\n",unixname); - #endif - - if (rmdir(unixname) == -1) { - AX = CanNotMakeDir; /* HUH ?*/ - SetCflag; - } - ResetCflag; + if ((dirname = GetUnixFileName( (char *) pointer(DS,DX) ))== NULL) { + EAX = (EAX & 0xffffff00L) | CanNotMakeDir; + SetCflag; + return; } + +/* + if (strcmp(unixname,DosDrives[drive].CurrentDirectory)) { + EAX = (EAX & 0xffffff00L) | CanNotRemoveCwd; + SetCflag; + } +*/ + if (rmdir(dirname) == -1) { + EAX = (EAX & 0xffffff00L) | CanNotMakeDir; + SetCflag; + } + ResetCflag; } void AllocateMemory(struct sigcontext_struct *context) { char *ptr; + fprintf(stderr,"int21: malloc %d bytes\n", BX * 0x10 ); + if ((ptr = (void *) memalign((size_t) (BX * 0x10), 0x10)) == NULL) { - AX = OutOfMemory; - BX = 0x0; /* out of memory */ + EAX = (EAX & 0xffffff00L) | OutOfMemory; + EBX = (EBX & 0xffffff00L); /* out of memory */ SetCflag; } - AX = segment((unsigned long) ptr); + fprintf(stderr,"int21: malloc (ptr = %d)\n", ptr ); + + EAX = (EAX & 0xffff0000L) | segment((unsigned long) ptr); ResetCflag; } void FreeMemory(struct sigcontext_struct *context) { + fprintf(stderr,"int21: freemem (ptr = %d)\n", ES * 0x10 ); + free((void *)(ES * 0x10)); ResetCflag; } @@ -621,24 +562,26 @@ void FreeMemory(struct sigcontext_struct *context) void ResizeMemoryBlock(struct sigcontext_struct *context) { char *ptr; + + fprintf(stderr,"int21: realloc (ptr = %d)\n", ES * 0x10 ); if ((ptr = (void *) realloc((void *)(ES * 0x10), (size_t) BX * 0x10)) == NULL) { - AX = OutOfMemory; - BX = 0x0; /* out of memory */ + EAX = (EAX & 0xffffff00L) | OutOfMemory; + EBX = (EBX & 0xffffff00L); /* out of memory */ SetCflag; } - BX = segment((unsigned long) ptr); + EBX = (EBX & 0xffff0000L) | segment((unsigned long) ptr); ResetCflag; } void ExecProgram(struct sigcontext_struct *context) { - execl("wine",(char *) pointer(DS,DX)); + execl("wine", GetUnixFileName((char *) pointer(DS,DX)) ); } void GetReturnCode(struct sigcontext_struct *context) { - AX = NoError; /* normal exit */ + EAX = (EAX & 0xffffff00L) | NoError; /* normal exit */ } void FindFirst(struct sigcontext_struct *context) @@ -653,97 +596,83 @@ void FindNext(struct sigcontext_struct *context) void GetSysVars(struct sigcontext_struct *context) { + /* return a null pointer, to encourage anyone who tries to + use the pointer */ + ES = 0x0; - BX = 0x0; + EBX = (EBX & 0xffff0000L); } void GetFileDateTime(struct sigcontext_struct *context) { - int drive; - char *dirname; - char unixname[256]; + char *filename; struct stat filestat; struct tm *now; - dirname = (char *) pointer(DS,DX); - ParseDOSFileName(unixname, dirname, &drive); - - { - stat(unixname, &filestat); - - now = localtime (&filestat.st_mtime); - - CX = (now->tm_hour * 0x2000) + (now->tm_min * 0x20) + now->tm_sec/2; - DX = (now->tm_year * 0x200) + (now->tm_mon * 0x20) + now->tm_mday; - - ResetCflag; + if ((filename = GetUnixFileName( (char *) pointer(DS,DX) ))== NULL) { + EAX = (EAX & 0xffffff00L) | FileNotFound; + SetCflag; + return; } + stat(filename, &filestat); + + now = localtime (&filestat.st_mtime); + + ECX = (ECX & 0xffff0000L) | (now->tm_hour * 0x2000) + (now->tm_min * 0x20) + now->tm_sec/2; + EDX = (EDX & 0xffff0000L) | (now->tm_year * 0x200) + (now->tm_mon * 0x20) + now->tm_mday; + + ResetCflag; } void SetFileDateTime(struct sigcontext_struct *context) { - int drive; - char *dirname; - char unixname[256]; + char *filename; struct utimbuf filetime; - dirname = (char *) pointer(DS,DX); + filename = GetUnixFileName((char *) pointer(DS,DX)); - ParseDOSFileName(unixname, dirname, &drive); + filetime.actime = 0L; + filetime.modtime = filetime.actime; - { - filetime.actime = 0L; - filetime.modtime = filetime.actime; - - utime(unixname,&filetime); - ResetCflag; - } + utime(filename, &filetime); + ResetCflag; } void CreateTempFile(struct sigcontext_struct *context) { - char UnixFileName[256],TempString[256]; - int drive,handle; + char *filename, temp[256]; + int drive, handle; - ParseDOSFileName(UnixFileName, (char *) pointer(DS,DX), &drive); - - sprintf(TempString,"%s%s%d",UnixFileName,"eb",(int) getpid()); + sprintf(temp,"%s\\win%d.tmp",TempDirectory,(int) getpid()); - { - handle = open(TempString, O_CREAT | O_TRUNC | O_RDWR); + fprintf(stderr,"CreateTempFile %s\n",temp); - if (handle == -1) { - AX = WriteProtected; - SetCflag; - return; - } - - strcpy((char *) pointer(DS,DX), UnixFileName); - - AX = handle; - ResetCflag; + handle = open(GetUnixFileName(temp), O_CREAT | O_TRUNC | O_RDWR); + + if (handle == -1) { + EAX = (EAX & 0xffffff00L) | WriteProtected; + SetCflag; + return; } + + strcpy((char *) pointer(DS,DX), temp); + + EAX = (EAX & 0xffff0000L) | handle; + ResetCflag; } void CreateNewFile(struct sigcontext_struct *context) { - char UnixFileName[256]; - int drive,handle; + int handle; - ParseDOSFileName(UnixFileName, (char *) pointer(DS,DX), &drive); - - { - handle = open(UnixFileName, O_CREAT | O_TRUNC | O_RDWR); - - if (handle == -1) { - AX = WriteProtected; - SetCflag; - return; - } - - AX = handle; - ResetCflag; + if ((handle = open(GetUnixFileName((char *) pointer(DS,DX)), O_CREAT | O_TRUNC | O_RDWR)) == -1) { + EAX = (EAX & 0xffffff00L) | WriteProtected; + SetCflag; + return; } + + EAX = (EAX & 0xffff0000L) | handle; + ResetCflag; } void FileLock(struct sigcontext_struct *context) @@ -756,30 +685,23 @@ void GetExtendedCountryInfo(struct sigcontext_struct *context) ResetCflag; } -int ValidDrive(int d) -{ - return 1; -} - void GetCurrentDirectory(struct sigcontext_struct *context) { int drive; - char *ptr; - if ((DX & 0xff) == 0) - drive = CurrentDrive; + if ((EDX & 0xffL) == 0) + drive = DOS_GetDefaultDrive(); else - drive = (DX & 0xff)-1; + drive = (EDX & 0xffL)-1; - if (!ValidDrive(drive)) { - AX = InvalidDrive; + if (!DOS_ValidDrive(drive)) { + EAX = (EAX & 0xffffff00L) | InvalidDrive; SetCflag; return; } - - strcpy((char *) pointer(DS,SI), DosDrives[drive].CurrentDirectory); + + DOS_GetCurrentDir(drive, (char *) pointer(DS,SI) ); ResetCflag; - AX = 0x0100; } void GetCurrentPSP(struct sigcontext_struct *context) @@ -790,53 +712,48 @@ void GetCurrentPSP(struct sigcontext_struct *context) void GetDiskSerialNumber(struct sigcontext_struct *context) { int drive; + unsigned long serialnumber; struct diskinfo *ptr; - if ((BX & 0xff)== 0) - drive = CurrentDrive; + if ((EBX & 0xffL) == 0) + drive = DOS_GetDefaultDrive(); else - drive = (BX & 0xff)-1; + drive = (EBX & 0xffL) - 1; - if (!ValidDrive(drive)) { - AX = InvalidDrive; + if (!DOS_ValidDrive(drive)) { + EAX = (EAX & 0xffffff00L) |InvalidDrive; SetCflag; return; } - { - ptr =(struct diskinfo *) pointer(DS,SI); + DOS_GetSerialNumber(drive,&serialnumber); - ptr->infolevel = 0; - ptr->serialnumber = 0xEBEBEB00 | drive; - strcpy(ptr->label,"NO NAME "); - strcpy(ptr->fstype,"FAT16 "); + ptr = (struct diskinfo *) pointer(DS,SI); + + ptr->infolevel = 0; + ptr->serialnumber = serialnumber; + strcpy(ptr->label,"NO NAME "); + strcpy(ptr->fstype,"FAT16 "); - AX = NoError; - ResetCflag; - } + EAX = (EAX & 0xffffff00L) | NoError; + ResetCflag; } void SetDiskSerialNumber(struct sigcontext_struct *context) { - AX &= 0xff00; - AX |= 1; + EAX = (EAX & 0xffffff00L) | 1L; ResetCflag; } -void CommitFile(struct sigcontext_struct *context) -{ - -} - /************************************************************************/ int do_int21(struct sigcontext_struct * context){ int ah; - fprintf(stderr,"int21: doing AX=%4x BX=%4x CX=%4x DX=%4x\n", - AX & 0xffff,BX & 0xffff,CX & 0xffff,DX & 0xffff); + fprintf(stderr,"int21: doing AX=%04x BX=%04x CX=%04x DX=%04x\n", + EAX & 0xffffL,EBX & 0xffffL,ECX & 0xffffL,EDX & 0xffffL); - ah = (AX >> 8) & 0xff; + ah = (EAX >> 8) & 0xffL; if (ah == 0x59) { GetExtendedErrorInfo(context); @@ -901,7 +818,7 @@ int do_int21(struct sigcontext_struct * context){ case 0x54: /* GET VERIFY FLAG */ case 0x61: /* UNUSED */ case 0x6b: /* NULL FUNCTION */ - AX &= 0xff00; + EAX &= 0xff00; break; case 0x67: /* SET HANDLE COUNT */ @@ -945,36 +862,37 @@ int do_int21(struct sigcontext_struct * context){ break; case 0x30: /* GET DOS VERSION */ - AX = DosVersion; /* Hey folks, this is DOS V3.3! */ - BX = 0x0012; /* 0x123456 is Wine's serial # */ - CX = 0x3456; + fprintf(stderr,"int21: GetDosVersion\n"); + EAX = DosVersion; /* Hey folks, this is DOS V3.3! */ + EBX = 0x0012; /* 0x123456 is Wine's serial # */ + ECX = 0x3456; break; case 0x31: /* TERMINATE AND STAY RESIDENT */ break; case 0x33: /* MULTIPLEXED */ - switch (AX & 0xff) { + switch (EAX & 0xff) { case 0x00: /* GET CURRENT EXTENDED BREAK STATE */ - if (!(AX & 0xff)) - DX &= 0xff00; + if (!(EAX & 0xffL)) + EDX &= 0xff00L; break; case 0x01: /* SET EXTENDED BREAK STATE */ break; case 0x02: /* GET AND SET EXTENDED CONTROL-BREAK CHECKING STATE */ - DX &= 0xff00; + EDX &= 0xff00L; break; case 0x05: /* GET BOOT DRIVE */ - DX &= 0xff00; - DX |= 2; /* c: is Wine's bootdrive */ + EDX = (EDX & 0xff00L) | 2; + /* c: is Wine's bootdrive */ break; case 0x06: /* GET TRUE VERSION NUMBER */ - BX = DosVersion; - DX = 0x00; + EBX = DosVersion; + EDX = 0x00; break; default: break; @@ -989,7 +907,7 @@ int do_int21(struct sigcontext_struct * context){ /* Return a NULL segment selector - this will bomb, if anyone ever tries to use it */ ES = 0; - BX = 0; + EBX = 0; break; case 0x36: /* GET FREE DISK SPACE */ @@ -997,8 +915,8 @@ int do_int21(struct sigcontext_struct * context){ break; case 0x38: /* GET COUNTRY-SPECIFIC INFORMATION */ - AX &= 0xff00; - AX |= 0x02; /* no country support available */ + EAX &= 0xff00; + EAX |= 0x02; /* no country support available */ SetCflag; break; @@ -1023,9 +941,6 @@ int do_int21(struct sigcontext_struct * context){ break; case 0x3e: /* "CLOSE" - CLOSE FILE */ - case 0x68: /* "FFLUSH" - COMMIT FILE */ - case 0x6a: /* COMMIT FILE */ - CloseFile(context); break; @@ -1046,7 +961,7 @@ int do_int21(struct sigcontext_struct * context){ break; case 0x43: /* FILE ATTRIBUTES */ - switch (AX & 0xff) { + switch (EAX & 0xff) { case 0x00: GetFileAttributes(context); break; @@ -1067,8 +982,8 @@ int do_int21(struct sigcontext_struct * context){ case 0x47: /* "CWD" - GET CURRENT DIRECTORY */ GetCurrentDirectory(context); - AX = 0x0100; /* many Microsoft products for Windows rely - on this */ + EAX = (EAX & 0xffff0000L) | 0x0100; + /* many Microsoft products for Windows rely on this */ break; case 0x48: /* ALLOCATE MEMORY */ @@ -1088,8 +1003,10 @@ int do_int21(struct sigcontext_struct * context){ break; case 0x4c: /* "EXIT" - TERMINATE WITH RETURN CODE */ - exit(AX & 0xff); - + fprintf(stderr,"int21: DosExit\n"); + exit(EAX & 0xff); + break; + case 0x4d: /* GET RETURN CODE */ GetReturnCode(context); break; @@ -1111,7 +1028,7 @@ int do_int21(struct sigcontext_struct * context){ break; case 0x57: /* FILE DATE AND TIME */ - switch (AX & 0xff) { + switch (EAX & 0xff) { case 0x00: GetFileDateTime(context); break; @@ -1122,12 +1039,12 @@ int do_int21(struct sigcontext_struct * context){ break; case 0x58: /* GET OR SET MEMORY/UMB ALLOCATION STRATEGY */ - switch (AX & 0xff) { + switch (EAX & 0xff) { case 0x00: - AX = 0x01; + EAX = (EAX & 0xffffff00L) | 0x01L; break; case 0x02: - AX &= 0xff00; + EAX &= 0xff00L; break; case 0x01: case 0x03: @@ -1154,11 +1071,38 @@ int do_int21(struct sigcontext_struct * context){ case 0x5d: /* NETWORK */ case 0x5e: - case 0x5f: - AX &= 0xff00; - AX |= NoNetwork; /* network software not installed */ + EAX = (EAX & 0xfffff00L) | NoNetwork; /* network software not installed */ SetCflag; break; + + case 0x5f: /* NETWORK */ + switch (EAX & 0xffL) { + case 0x07: /* ENABLE DRIVE */ + if (!DOS_EnableDrive(EDX & 0xffL)) { + Error(InvalidDrive, EC_MediaError , EL_Disk); + EAX = (EAX & 0xfffff00L) | InvalidDrive; + SetCflag; + break; + } else { + ResetCflag; + break; + } + case 0x08: /* DISABLE DRIVE */ + if (!DOS_DisableDrive(EDX & 0xffL)) { + Error(InvalidDrive, EC_MediaError , EL_Disk); + EAX = (EAX & 0xfffff00L) | InvalidDrive; + SetCflag; + break; + } else { + ResetCflag; + break; + } + default: + EAX = (EAX & 0xfffff00L) | NoNetwork; /* network software not installed */ + SetCflag; + break; + } + break; case 0x60: /* "TRUENAME" - CANONICALIZE FILENAME OR PATH */ GetTrueFileName(context); @@ -1173,21 +1117,25 @@ int do_int21(struct sigcontext_struct * context){ break; case 0x66: /* GLOBAL CODE PAGE TABLE */ - switch (AX & 0xff) { + switch (EAX & 0xffL) { case 0x01: - BX = CodePage; - DX = BX; + EBX = CodePage; + EDX = EBX; ResetCflag; break; case 0x02: - CodePage = BX; + CodePage = EBX; ResetCflag; break; } break; + + case 0x68: /* "FFLUSH" - COMMIT FILE */ + ResetCflag; + break; case 0x69: /* DISK SERIAL NUMBER */ - switch (AX & 0xff) { + switch (EAX & 0xff) { case 0x00: GetDiskSerialNumber(context); break; @@ -1197,6 +1145,10 @@ int do_int21(struct sigcontext_struct * context){ } break; + case 0x6a: /* COMMIT FILE */ + ResetCflag; + break; + default: fprintf(stderr,"Unable to handle int 0x21 %x\n", context->sc_eax); return 1; @@ -1204,3 +1156,72 @@ int do_int21(struct sigcontext_struct * context){ } return 1; } + +/********************************************************************/ + +static void +GetTimeDate(int time_flag) +{ + struct tm *now; + time_t ltime; + + ltime = time(NULL); + now = localtime(<ime); + if (time_flag) + { + _CX = (now->tm_hour << 8) | now->tm_min; + _DX = now->tm_sec << 8; + } + else + { + _CX = now->tm_year + 1900; + _DX = ((now->tm_mon + 1) << 8) | now->tm_mday; + _AX &= 0xff00; + _AX |= now->tm_wday; + } +#ifdef DEBUG_DOS + printf("GetTimeDate: AX = %04x, CX = %04x, DX = %04x\n", _AX, _CX, _DX); +#endif + + ReturnFromRegisterFunc(); + /* Function does not return */ +} + +/********************************************************************** + * KERNEL_DOS3Call + */ +int KERNEL_DOS3Call() +{ + switch ((_AX >> 8) & 0xff) + { + case 0x30: + _AX = 0x0303; + ReturnFromRegisterFunc(); + /* Function does not return */ + + case 0x25: + case 0x35: + return 0; + + case 0x2a: + GetTimeDate(0); + /* Function does not return */ + + case 0x2c: + GetTimeDate(1); + /* Function does not return */ + + case 0x4c: + exit(_AX & 0xff); + + default: + fprintf(stderr, "DOS: AX %04x, BX %04x, CX %04x, DX %04x\n", + _AX, _BX, _CX, _DX); + fprintf(stderr, " SP %04x, BP %04x, SI %04x, DI %04x\n", + _SP, _BP, _SI, _DI); + fprintf(stderr, " DS %04x, ES %04x\n", + _DS, _ES); + } + + return 0; +} diff --git a/misc/message.c b/misc/message.c index 281b0121a14..cde516415a0 100644 --- a/misc/message.c +++ b/misc/message.c @@ -21,6 +21,8 @@ typedef struct tagMSGBOX { HWND hWndNo; HWND hWndCancel; HICON hIcon; + RECT rectIcon; + RECT rectStr; } MSGBOX; typedef MSGBOX FAR* LPMSGBOX; @@ -46,7 +48,7 @@ int MessageBox( HWND hWnd, LPSTR str, LPSTR title, WORD type ) wndClass.cbWndExtra = 0; wndClass.hInstance = wndPtr->hInstance; wndClass.hIcon = (HICON)NULL; - wndClass.hCursor = LoadCursor((HANDLE)NULL, IDC_ARROW); + wndClass.hCursor = LoadCursor((HANDLE)NULL, IDC_ARROW); wndClass.hbrBackground = GetStockObject(WHITE_BRUSH); wndClass.lpszMenuName = NULL; wndClass.lpszClassName = "MESSAGEBOX"; @@ -57,7 +59,7 @@ int MessageBox( HWND hWnd, LPSTR str, LPSTR title, WORD type ) mb.wType = type; mb.ActiveFlg = TRUE; hDlg = CreateWindow("MESSAGEBOX", title, - WS_POPUP | WS_DLGFRAME | WS_VISIBLE, 100, 150, 320, 120, + WS_POPUP | WS_DLGFRAME | WS_VISIBLE, 100, 150, 400, 120, (HWND)NULL, (HMENU)NULL, wndPtr->hInstance, (LPSTR)&mb); if (hDlg == 0) return 0; while(TRUE) { @@ -113,47 +115,63 @@ LONG SystemMessageBoxProc(HWND hWnd, WORD message, WORD wParam, LONG lParam) *((LPMSGBOX *)&wndPtr->wExtra[1]) = lpmbInit; lpmb = MsgBoxGetStorageHeader(hWnd); GetClientRect(hWnd, &rect); + CopyRect(&lpmb->rectStr, &rect); + lpmb->rectStr.bottom -= 32; switch(lpmb->wType & MB_TYPEMASK) { case MB_OK : lpmb->hWndYes = CreateWindow("BUTTON", "&Ok", WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | BS_PUSHBUTTON, - rect.right / 2 - 70, rect.bottom - 25, + rect.right / 2 - 30, rect.bottom - 25, 60, 18, hWnd, 1, wndPtr->hInstance, 0L); break; case MB_OKCANCEL : lpmb->hWndYes = CreateWindow("BUTTON", "&Ok", WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | BS_PUSHBUTTON, - rect.right / 2 - 70, rect.bottom - 25, + rect.right / 2 - 65, rect.bottom - 25, 60, 18, hWnd, 1, wndPtr->hInstance, 0L); lpmb->hWndCancel = CreateWindow("BUTTON", "&Cancel", WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | BS_PUSHBUTTON, - rect.right / 2 + 10, rect.bottom - 25, + rect.right / 2 + 5, rect.bottom - 25, 60, 18, hWnd, 2, wndPtr->hInstance, 0L); break; case MB_ABORTRETRYIGNORE : lpmb->hWndYes = CreateWindow("BUTTON", "&Retry", WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | BS_PUSHBUTTON, - rect.right / 2 - 70, rect.bottom - 25, + rect.right / 2 - 100, rect.bottom - 25, 60, 18, hWnd, 1, wndPtr->hInstance, 0L); lpmb->hWndNo = CreateWindow("BUTTON", "&Ignore", WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | BS_PUSHBUTTON, - rect.right / 2 + 10, rect.bottom - 25, + rect.right / 2 - 30, rect.bottom - 25, 60, 18, hWnd, 2, wndPtr->hInstance, 0L); lpmb->hWndCancel = CreateWindow("BUTTON", "&Abort", WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | BS_PUSHBUTTON, - rect.right / 2 + 80, rect.bottom - 25, + rect.right / 2 + 40, rect.bottom - 25, 60, 18, hWnd, 3, wndPtr->hInstance, 0L); break; case MB_YESNO : lpmb->hWndYes = CreateWindow("BUTTON", "&Yes", WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | BS_PUSHBUTTON, - rect.right / 2 - 70, rect.bottom - 25, + rect.right / 2 - 65, rect.bottom - 25, 60, 18, hWnd, 1, wndPtr->hInstance, 0L); lpmb->hWndNo = CreateWindow("BUTTON", "&No", WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | BS_PUSHBUTTON, - rect.right / 2 + 10, rect.bottom - 25, + rect.right / 2 + 5, rect.bottom - 25, 60, 18, hWnd, 2, wndPtr->hInstance, 0L); break; + case MB_YESNOCANCEL : + lpmb->hWndYes = CreateWindow("BUTTON", "&Yes", + WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | BS_PUSHBUTTON, + rect.right / 2 - 100, rect.bottom - 25, + 60, 18, hWnd, 1, wndPtr->hInstance, 0L); + lpmb->hWndNo = CreateWindow("BUTTON", "&No", + WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | BS_PUSHBUTTON, + rect.right / 2 - 30, rect.bottom - 25, + 60, 18, hWnd, 2, wndPtr->hInstance, 0L); + lpmb->hWndCancel = CreateWindow("BUTTON", "&Cancel", + WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | BS_PUSHBUTTON, + rect.right / 2 + 40, rect.bottom - 25, + 60, 18, hWnd, 3, wndPtr->hInstance, 0L); + break; } switch(lpmb->wType & MB_ICONMASK) { case MB_ICONEXCLAMATION: @@ -173,16 +191,25 @@ LONG SystemMessageBoxProc(HWND hWnd, WORD message, WORD wParam, LONG lParam) lpmb->hIcon = LoadIcon((HINSTANCE)NULL, IDI_HAND); break; } + if (lpmb->hIcon != (HICON)NULL) { + SetRect(&lpmb->rectIcon, 16, + lpmb->rectStr.bottom / 2 - 16, 48, + lpmb->rectStr.bottom / 2 + 16); + lpmb->rectStr.left += 64; + } break; case WM_PAINT: lpmb = MsgBoxGetStorageHeader(hWnd); - GetClientRect(hWnd, &rect); + CopyRect(&rect, &lpmb->rectStr); hDC = BeginPaint(hWnd, &ps); - if (lpmb->hIcon) DrawIcon(hDC, 30, 20, lpmb->hIcon); - TextOut(hDC, rect.right / 2, 15, - lpmb->Title, strlen(lpmb->Title)); - TextOut(hDC, rect.right / 2, 30, - lpmb->Str, strlen(lpmb->Str)); + if (lpmb->hIcon) + DrawIcon(hDC, lpmb->rectIcon.left, + lpmb->rectIcon.top, lpmb->hIcon); + DrawText(hDC, lpmb->Str, -1, &rect, + DT_CALCRECT | DT_CENTER | DT_WORDBREAK); + rect.top = lpmb->rectStr.bottom / 2 - rect.bottom / 2; + rect.bottom = lpmb->rectStr.bottom / 2 + rect.bottom / 2; + DrawText(hDC, lpmb->Str, -1, &rect, DT_CENTER | DT_WORDBREAK); EndPaint(hWnd, &ps); break; case WM_DESTROY: @@ -216,7 +243,7 @@ LONG SystemMessageBoxProc(HWND hWnd, WORD message, WORD wParam, LONG lParam) DeleteDC(hMemDC); } */ - hBitMap = LoadBitmap((HINSTANCE)NULL, "SMILE"); + hBitMap = LoadBitmap((HINSTANCE)NULL, "WINELOGO"); GetObject(hBitMap, sizeof(BITMAP), (LPSTR)&bm); printf("bm.bmWidth=%d bm.bmHeight=%d\n", bm.bmWidth, bm.bmHeight); @@ -234,12 +261,15 @@ LONG SystemMessageBoxProc(HWND hWnd, WORD message, WORD wParam, LONG lParam) break; case 3: hDC = GetDC(hWnd); - hInst2 = LoadImage("ev3lite.exe", NULL); + hInst2 = LoadImage("ev3lite.exe"); + printf("hInst2=%04X\n", hInst2); hIcon = LoadIcon(hInst2, "EV3LITE"); DrawIcon(hDC, 20, 20, hIcon); DestroyIcon(hIcon); - hInst2 = LoadImage("sysres.dll", NULL); - hIcon = LoadIcon(hInst2, "WINEICON"); + hInst2 = LoadImage("moricons.dll"); + printf("hInst2=%04X\n", hInst2); + hIcon = LoadIcon(hInst2, MAKEINTRESOURCE(1)); +/* hIcon = LoadIcon(hInst2, "WINEICON"); */ DrawIcon(hDC, 60, 20, hIcon); DestroyIcon(hIcon); hIcon = LoadIcon((HINSTANCE)NULL, IDI_EXCLAMATION); diff --git a/misc/profile.c b/misc/profile.c index ac50d862833..12d12fe2704 100644 --- a/misc/profile.c +++ b/misc/profile.c @@ -3,6 +3,12 @@ * * Copyright (c) 1993 Miguel de Icaza * + * 1/Dec o Corrected return values for Get*ProfileString + * + * o Now, if AppName == NULL in Get*ProfileString it returns a list + * of the KeyNames (as documented in the MS-SDK). + * + * o if KeyValue == NULL now clears the value in Get*ProfileString */ static char Copyright [] = "Copyright (C) 1993 Miguel de Icaza"; @@ -12,7 +18,8 @@ static char Copyright [] = "Copyright (C) 1993 Miguel de Icaza"; #include "windows.h" #include "wine.h" -#define INIFILE GetSystemIniFilename() +/* #define DEBUG */ + #define STRSIZE 255 #define xmalloc(x) malloc(x) #define overflow (next == &CharBuffer [STRSIZE-1]) @@ -63,9 +70,15 @@ static TSecHeader *load (char *file) char *next; char c; +#ifdef DEBUG + printf("Load %s\n", file); +#endif if ((f = fopen (file, "r"))==NULL) return NULL; +#ifdef DEBUG + printf("Loading %s\n", file); +#endif state = FirstBrace; while ((c = getc (f)) != EOF){ if (c == '\r') /* Ignore Carriage Return */ @@ -79,6 +92,9 @@ static TSecHeader *load (char *file) next = CharBuffer; SecHeader->AppName = strdup (CharBuffer); state = IgnoreToEOL; +#ifdef DEBUG + printf("%s: section %s\n", file, CharBuffer); +#endif } else *next++ = c; break; @@ -122,6 +138,9 @@ static TSecHeader *load (char *file) SecHeader->Keys->KeyName = strdup (CharBuffer); state = KeyValue; next = CharBuffer; +#ifdef DEBUG + printf("%s: key %s\n", file, CharBuffer); +#endif } else *next++ = c; break; @@ -175,22 +194,36 @@ static short GetSetProfile (int set, LPSTR AppName, LPSTR KeyName, section = New->Section; Current = New; } - /* Start search */ for (; section; section = section->link){ if (strcasecmp (section->AppName, AppName)) continue; + + /* If no key value given, then list all the keys */ + if ((!AppName) && (!set)){ + char *p = ReturnedString; + int left = Size - 1; + int slen; + + for (key = section->Keys; key; key = key->link){ + strncpy (p, key->KeyName, left); + slen = strlen (key->KeyName) + 1; + left -= slen+1; + p += slen; + } + return left; + } for (key = section->Keys; key; key = key->link){ if (strcasecmp (key->KeyName, KeyName)) continue; if (set){ free (key->Value); - key->Value = strdup (Default); + key->Value = strdup (Default ? Default : ""); return 1; } ReturnedString [Size-1] = 0; strncpy (ReturnedString, key->Value, Size-1); - return 1; + return 1; } /* If Getting the information, then don't write the information to the INI file, need to run a couple of tests with windog */ @@ -222,14 +255,20 @@ short GetPrivateProfileString (LPSTR AppName, LPSTR KeyName, LPSTR Default, LPSTR ReturnedString, short Size, LPSTR FileName) { - return (GetSetProfile (0, AppName, KeyName, Default, ReturnedString, Size, FileName)); + int v; + + v = GetSetProfile (0,AppName,KeyName,Default,ReturnedString,Size,FileName); + if (AppName) + return strlen (ReturnedString); + else + return Size - v; } int GetProfileString (LPSTR AppName, LPSTR KeyName, LPSTR Default, LPSTR ReturnedString, int Size) { return GetPrivateProfileString (AppName, KeyName, Default, - ReturnedString, Size, INIFILE); + ReturnedString, Size, WIN_INI); } WORD GetPrivateProfileInt (LPSTR AppName, LPSTR KeyName, short Default, @@ -251,7 +290,7 @@ WORD GetPrivateProfileInt (LPSTR AppName, LPSTR KeyName, short Default, WORD GetProfileInt (LPSTR AppName, LPSTR KeyName, int Default) { - return GetPrivateProfileInt (AppName, KeyName, Default, INIFILE); + return GetPrivateProfileInt (AppName, KeyName, Default, WIN_INI); } BOOL WritePrivateProfileString (LPSTR AppName, LPSTR KeyName, LPSTR String, @@ -262,7 +301,7 @@ BOOL WritePrivateProfileString (LPSTR AppName, LPSTR KeyName, LPSTR String, BOOL WriteProfileString (LPSTR AppName, LPSTR KeyName, LPSTR String) { - return (WritePrivateProfileString (AppName, KeyName, String, INIFILE)); + return (WritePrivateProfileString (AppName, KeyName, String, WIN_INI)); } static void dump_keys (FILE *profile, TKeys *p) diff --git a/misc/user.c b/misc/user.c index 58087eeaaa8..501448cd55d 100644 --- a/misc/user.c +++ b/misc/user.c @@ -6,8 +6,7 @@ static char Copyright[] = "Copyright Robert J. Amstadt, 1993"; #include "prototypes.h" #include "windows.h" #include "user.h" - -#define DEFAULT_MSG_QUEUE_SIZE 8 +#include "message.h" #define USER_HEAP_SIZE 0x10000 @@ -15,6 +14,9 @@ static char Copyright[] = "Copyright Robert J. Amstadt, 1993"; MDESC *USER_Heap = NULL; +extern BOOL ATOM_Init(); +extern BOOL GDI_Init(); + /*********************************************************************** * USER_HeapInit */ @@ -24,7 +26,6 @@ static BOOL USER_HeapInit() s = GetNextSegment( 0, 0x10000 ); if (s == NULL) return FALSE; HEAP_Init( &USER_Heap, s->base_addr, USER_HEAP_SIZE ); - free(s); return TRUE; } @@ -37,6 +38,11 @@ static BOOL USER_HeapInit() int USER_InitApp(int hInstance) { + int queueSize; + + /* Global atom table initialisation */ + if (!ATOM_Init()) return 0; + /* GDI initialisation */ if (!GDI_Init()) return 0; @@ -54,9 +60,14 @@ USER_InitApp(int hInstance) /* Initialize dialog manager */ if (!DIALOG_Init()) return 0; - + + /* Create system message queue */ + queueSize = GetProfileInt( "windows", "TypeAhead", 120 ); + if (!MSG_CreateSysMsgQueue( queueSize )) return 0; + /* Create task message queue */ - if (!SetMessageQueue( DEFAULT_MSG_QUEUE_SIZE )) return 0; + queueSize = GetProfileInt( "windows", "DefaultQueueSize", 8 ); + if (!SetMessageQueue( queueSize )) return 0; return 1; } diff --git a/misc/xt.c b/misc/xt.c index 8d386ae87d4..a829a5b8429 100644 --- a/misc/xt.c +++ b/misc/xt.c @@ -41,6 +41,8 @@ void main(int argc, char **argv) XT_display = XtDisplay( topLevelWidget ); XT_screen = XtScreen( topLevelWidget ); + DOS_InitFS(); + Comm_Init(); _WinMain( argc, argv ); } @@ -58,12 +60,6 @@ void MessageBeep( WORD i ) XBell(XT_display, 100); } -WORD RegisterWindowMessage( LPSTR str ) -{ - printf( "RegisterWindowMessage: '%s'\n", str ); - return 0xc000; -} - /*********************************************************************** * GetTickCount (USER.13) */ @@ -94,11 +90,10 @@ void AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu ) { printf( "AdjustWindowRect: (%d,%d)-(%d,%d) %d %d\n", rect->left, rect->top, rect->right, rect->bottom, style, menu ); +#ifdef USE_XLIB + rect->right += 8; + rect->bottom += 34; +#endif } -HMENU CreateMenu() { return 0; } - -BOOL AppendMenu( HMENU hmenu, WORD flags, WORD id, LPSTR text ) { return TRUE;} - -BOOL DestroyMenu( HMENU hmenu ) { return TRUE; } diff --git a/objects/Imakefile b/objects/Imakefile new file mode 100644 index 00000000000..458761d9172 --- /dev/null +++ b/objects/Imakefile @@ -0,0 +1,43 @@ +#include "../Wine.tmpl" + +MODULE = objects + +SRCS = \ + bitmap.c \ + brush.c \ + font.c \ + gdiobj.c \ + palette.c \ + pen.c \ + dib.c \ + region.c \ + text.c \ + dcvalues.c \ + clipping.c \ + bitblt.c \ + linedda.c \ + color.c + +OBJS = \ + bitmap.o \ + brush.o \ + font.o \ + gdiobj.o \ + palette.o \ + pen.o \ + dib.o \ + region.o \ + text.o \ + dcvalues.o \ + clipping.o \ + bitblt.o \ + linedda.o \ + color.o + +WineRelocatableTarget($(TOP)/$(MODULE),,$(OBJS)) +DependTarget() +CleanTarget() + +includes:: + +install:: diff --git a/objects/bitblt.c b/objects/bitblt.c index 53e9ba1a03a..c4ed6bc516c 100644 --- a/objects/bitblt.c +++ b/objects/bitblt.c @@ -38,10 +38,10 @@ BOOL PatBlt( HDC hdc, short left, short top, else rop = (rop & 0x03) | ((rop >> 4) & 0x0c); XSetFunction( XT_display, dc->u.x.gc, DC_XROPfunction[rop] ); - x1 = XLPTODP( dc, left ); - x2 = XLPTODP( dc, left + width ); - y1 = YLPTODP( dc, top ); - y2 = YLPTODP( dc, top + height ); + x1 = dc->w.DCOrgX + XLPTODP( dc, left ); + x2 = dc->w.DCOrgX + XLPTODP( dc, left + width ); + y1 = dc->w.DCOrgY + YLPTODP( dc, top ); + y2 = dc->w.DCOrgY + YLPTODP( dc, top + height ); XFillRectangle( XT_display, dc->u.x.drawable, dc->u.x.gc, MIN(x1,x2), MIN(y1,y2), abs(x2-x1), abs(y2-y1) ); return TRUE; @@ -78,14 +78,14 @@ BOOL BitBlt( HDC hdcDest, short xDest, short yDest, short width, short height, dcSrc = (DC *) GDI_GetObjPtr( hdcSrc, DC_MAGIC ); if (!dcSrc) return FALSE; - xs1 = XLPTODP( dcSrc, xSrc ); - xs2 = XLPTODP( dcSrc, xSrc + width ); - ys1 = YLPTODP( dcSrc, ySrc ); - ys2 = YLPTODP( dcSrc, ySrc + height ); - xd1 = XLPTODP( dcDest, xDest ); - xd2 = XLPTODP( dcDest, xDest + width ); - yd1 = YLPTODP( dcDest, yDest ); - yd2 = YLPTODP( dcDest, yDest + height ); + xs1 = dcSrc->w.DCOrgX + XLPTODP( dcSrc, xSrc ); + xs2 = dcSrc->w.DCOrgX + XLPTODP( dcSrc, xSrc + width ); + ys1 = dcSrc->w.DCOrgY + YLPTODP( dcSrc, ySrc ); + ys2 = dcSrc->w.DCOrgY + YLPTODP( dcSrc, ySrc + height ); + xd1 = dcDest->w.DCOrgX + XLPTODP( dcDest, xDest ); + xd2 = dcDest->w.DCOrgX + XLPTODP( dcDest, xDest + width ); + yd1 = dcDest->w.DCOrgY + YLPTODP( dcDest, yDest ); + yd2 = dcDest->w.DCOrgY + YLPTODP( dcDest, yDest + height ); if ((abs(xs2-xs1) != abs(xd2-xd1)) || (abs(ys2-ys1) != abs(yd2-yd1))) return FALSE; /* Should call StretchBlt here */ @@ -109,3 +109,78 @@ BOOL BitBlt( HDC hdcDest, short xDest, short yDest, short width, short height, } return TRUE; } + + + +/*********************************************************************** + * StrechBlt (GDI.35) + */ +BOOL StrechBlt( HDC hdcDest, short xDest, short yDest, short widthDest, short heightDest, + HDC hdcSrc, short xSrc, short ySrc, short widthSrc, short heightSrc, DWORD rop ) +{ + int xs1, xs2, ys1, ys2; + int xd1, xd2, yd1, yd2; + DC *dcDest, *dcSrc; + +/*#ifdef DEBUG_GDI */ + + printf( "StrechBlt: %d %d,%d %dx%d %d %d,%d %dx%d %08x\n", + hdcDest, xDest, yDest, widthDest, heightDest, hdcSrc, xSrc, + ySrc, widthSrc, heightSrc, rop ); +/*#endif */ + + + + if ((rop & 0xcc0000) == ((rop & 0x330000) << 2)) + return PatBlt( hdcDest, xDest, yDest, widthDest, heightDest, rop ); + + printf("here\n"); + + rop >>= 16; + if ((rop & 0x0f) != (rop >> 4)) + { + printf( "BitBlt: Unimplemented ROP %02x\n", rop ); + return FALSE; + } + + printf("here2\n"); + + dcDest = (DC *) GDI_GetObjPtr( hdcDest, DC_MAGIC ); + if (!dcDest) return FALSE; + dcSrc = (DC *) GDI_GetObjPtr( hdcSrc, DC_MAGIC ); + if (!dcSrc) return FALSE; + + xs1 = XLPTODP( dcSrc, xSrc ); + xs2 = XLPTODP( dcSrc, xSrc + widthSrc ); + ys1 = YLPTODP( dcSrc, ySrc ); + ys2 = YLPTODP( dcSrc, ySrc + heightSrc ); + xd1 = XLPTODP( dcDest, xDest ); + xd2 = XLPTODP( dcDest, xDest + widthDest ); + yd1 = YLPTODP( dcDest, yDest ); + yd2 = YLPTODP( dcDest, yDest + heightDest ); + + DC_SetupGCForText( dcDest ); + XSetFunction( XT_display, dcDest->u.x.gc, DC_XROPfunction[rop & 0x0f] ); + + if (dcSrc->w.bitsPerPixel == dcDest->w.bitsPerPixel) + { + printf("XCopyArea\n"); + XCopyArea( XT_display, dcSrc->u.x.drawable, + dcDest->u.x.drawable, dcDest->u.x.gc, + MIN(xs1,xs2), MIN(ys1,ys2), abs(xd2-xd1), abs(yd2-yd1), + MIN(xd1,xd2), MIN(yd1,yd2) ); + } + else + { + printf("XCopyPlane\n"); + if (dcSrc->w.bitsPerPixel != 1) return FALSE; + XCopyPlane( XT_display, dcSrc->u.x.drawable, + dcDest->u.x.drawable, dcDest->u.x.gc, + MIN(xs1,xs2), MIN(ys1,ys2), abs(xd2-xd1), abs(yd2-yd1), + MIN(xd1,xd2), MIN(yd1,yd2), 1 ); + } + return TRUE; + + +} + diff --git a/objects/bitmap.c b/objects/bitmap.c index 9de4c1c31a5..ffec3e9a760 100644 --- a/objects/bitmap.c +++ b/objects/bitmap.c @@ -46,6 +46,7 @@ BOOL BITMAP_Init() if (tmpPixmap) { bitmapGC[i] = XCreateGC( XT_display, tmpPixmap, 0, NULL ); + XSetGraphicsExposures( XT_display, bitmapGC[i], False ); XFreePixmap( XT_display, tmpPixmap ); } else bitmapGC[i] = 0; @@ -355,6 +356,8 @@ HBITMAP BITMAP_SelectObject( HDC hdc, DC * dc, HBITMAP hbitmap, DefaultRootWindow( XT_display ), bmp->bmWidth, bmp->bmHeight, bmp->bmBitsPixel ); + dc->w.DCSizeX = bmp->bmWidth; + dc->w.DCSizeY = bmp->bmHeight; BITMAP_CopyToPixmap( bmp, dc->u.x.drawable, 0, 0, bmp->bmWidth, bmp->bmHeight ); diff --git a/objects/clipping.c b/objects/clipping.c index ec9de9ccde5..5776eb857d0 100644 --- a/objects/clipping.c +++ b/objects/clipping.c @@ -10,10 +10,33 @@ static char Copyright[] = "Copyright Alexandre Julliard, 1993"; #include "gdi.h" +/*********************************************************************** + * CLIPPING_SetDeviceClipping + * + * Set the clip region of the physical device. + */ +void CLIPPING_SetDeviceClipping( DC * dc ) +{ + if (dc->w.hGCClipRgn) + { + RGNOBJ *obj = (RGNOBJ *) GDI_GetObjPtr(dc->w.hGCClipRgn, REGION_MAGIC); + XSetClipMask( XT_display, dc->u.x.gc, obj->region.pixmap ); + XSetClipOrigin( XT_display, dc->u.x.gc, + dc->w.DCOrgX + obj->region.box.left, + dc->w.DCOrgY + obj->region.box.top ); + } + else + { + XSetClipMask( XT_display, dc->u.x.gc, None ); + XSetClipOrigin( XT_display, dc->u.x.gc, dc->w.DCOrgX, dc->w.DCOrgY ); + } +} + + /*********************************************************************** * CLIPPING_UpdateGCRegion * - * Update the GC clip region when the ClipRgn of VisRgn have changed. + * Update the GC clip region when the ClipRgn or VisRgn have changed. */ static void CLIPPING_UpdateGCRegion( DC * dc ) { @@ -36,19 +59,7 @@ static void CLIPPING_UpdateGCRegion( DC * dc ) else CombineRgn( dc->w.hGCClipRgn, dc->w.hClipRgn, dc->w.hVisRgn, RGN_AND ); } - - if (dc->w.hGCClipRgn) - { - RGNOBJ *obj = (RGNOBJ *) GDI_GetObjPtr( dc->w.hGCClipRgn, REGION_MAGIC ); - XSetClipMask( XT_display, dc->u.x.gc, obj->region.pixmap ); - XSetClipOrigin( XT_display, dc->u.x.gc, - obj->region.box.left, obj->region.box.top ); - } - else - { - XSetClipMask( XT_display, dc->u.x.gc, None ); - XSetClipOrigin( XT_display, dc->u.x.gc, 0, 0 ); - } + CLIPPING_SetDeviceClipping( dc ); } @@ -157,26 +168,40 @@ int OffsetVisRgn( HDC hdc, short x, short y ) int CLIPPING_IntersectRect( DC * dc, HRGN * hrgn, short left, short top, short right, short bottom, int exclude ) { - HRGN tempRgn, newRgn; + HRGN tempRgn = 0, prevRgn = 0, newRgn = 0; RGNOBJ *newObj, *prevObj; int retval; - if (!*hrgn) return NULLREGION; - if (!(newRgn = CreateRectRgn( 0, 0, 0, 0))) return ERROR; - if (!(tempRgn = CreateRectRgn( left, top, right, bottom ))) + if (!*hrgn) { - DeleteObject( newRgn ); - return ERROR; + if (!(*hrgn = CreateRectRgn( 0, 0, dc->w.DCSizeX, dc->w.DCSizeY ))) + goto Error; + prevRgn = *hrgn; } + if (!(newRgn = CreateRectRgn( 0, 0, 0, 0))) goto Error; + if (!(tempRgn = CreateRectRgn( left, top, right, bottom ))) goto Error; + retval = CombineRgn( newRgn, *hrgn, tempRgn, exclude ? RGN_DIFF : RGN_AND); + if (retval == ERROR) goto Error; + newObj = (RGNOBJ *) GDI_GetObjPtr( newRgn, REGION_MAGIC ); prevObj = (RGNOBJ *) GDI_GetObjPtr( *hrgn, REGION_MAGIC ); if (newObj && prevObj) newObj->header.hNext = prevObj->header.hNext; DeleteObject( tempRgn ); - DeleteObject( *hrgn ); + if (*hrgn) DeleteObject( *hrgn ); *hrgn = newRgn; CLIPPING_UpdateGCRegion( dc ); return retval; + + Error: + if (tempRgn) DeleteObject( tempRgn ); + if (newRgn) DeleteObject( newRgn ); + if (prevRgn) + { + DeleteObject( prevRgn ); + *hrgn = 0; + } + return ERROR; } @@ -292,13 +317,9 @@ int GetClipBox( HDC hdc, LPRECT rect ) if (dc->w.hGCClipRgn) return GetRgnBox( dc->w.hGCClipRgn, rect ); else { - Window root; - int width, height, x, y, border, depth; - XGetGeometry( XT_display, dc->u.x.drawable, &root, &x, &y, - &width, &height, &border, &depth ); rect->top = rect->left = 0; - rect->right = width & 0xffff; - rect->bottom = height & 0xffff; + rect->right = dc->w.DCSizeX; + rect->bottom = dc->w.DCSizeY; return SIMPLEREGION; } } diff --git a/objects/dcvalues.c b/objects/dcvalues.c index b496e2e3609..73c98aabedd 100644 --- a/objects/dcvalues.c +++ b/objects/dcvalues.c @@ -45,6 +45,8 @@ const WIN_DC_INFO DCVAL_defaultValues = MM_TEXT, /* MapMode */ 0, /* DCOrgX */ 0, /* DCOrgY */ + 0, /* DCSizeX */ + 0, /* DCSizeY */ 0, /* CursPosX */ 0, /* CursPosY */ 0, /* WndOrgX */ diff --git a/objects/font.c b/objects/font.c index 1299a26ac51..10bc76b7b08 100644 --- a/objects/font.c +++ b/objects/font.c @@ -331,6 +331,36 @@ BOOL GetTextMetrics( HDC hdc, LPTEXTMETRIC metrics ) } +/***********************************************************************/ + +#define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \ + (((cs)->rbearing|(cs)->lbearing| \ + (cs)->ascent|(cs)->descent) == 0)) + +/* + * CI_GET_CHAR_INFO - return the charinfo struct for the indicated 8bit + * character. If the character is in the column and exists, then return the + * appropriate metrics (note that fonts with common per-character metrics will + * return min_bounds). If none of these hold true, try again with the default + * char. + */ +#define CI_GET_CHAR_INFO(fs,col,def,cs) \ +{ \ + cs = def; \ + if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \ + if (fs->per_char == NULL) { \ + cs = &fs->min_bounds; \ + } else { \ + cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \ + if (CI_NONEXISTCHAR(cs)) cs = def; \ + } \ + } \ +} + +#define CI_GET_DEFAULT_INFO(fs,cs) \ + CI_GET_CHAR_INFO(fs, fs->default_char, NULL, cs) + + /*********************************************************************** * GetCharWidth (GDI.350) */ @@ -338,8 +368,7 @@ BOOL GetCharWidth(HDC hdc, WORD wFirstChar, WORD wLastChar, LPINT lpBuffer) { int i, j; XFontStruct *xfont; - XCharStruct *charPtr; - int default_width; + XCharStruct *cs, *def; DC *dc = (DC *)GDI_GetObjPtr(hdc, DC_MAGIC); if (!dc) return FALSE; @@ -353,15 +382,12 @@ BOOL GetCharWidth(HDC hdc, WORD wFirstChar, WORD wLastChar, LPINT lpBuffer) return TRUE; } - charPtr = xfont->per_char; - default_width = (charPtr + xfont->default_char)->width; + CI_GET_DEFAULT_INFO(xfont, def); for (i = wFirstChar, j = 0; i <= wLastChar; i++, j++) { - if (i < xfont->min_char_or_byte2 || i > xfont->max_char_or_byte2) - *(lpBuffer + j) = default_width; - else - *(lpBuffer + j) = charPtr->width; + CI_GET_CHAR_INFO(xfont, i, def, cs); + *(lpBuffer + j) = cs->width; } return TRUE; } diff --git a/objects/gdiobj.c b/objects/gdiobj.c index 32bb4b8ae01..cc539a49025 100644 --- a/objects/gdiobj.c +++ b/objects/gdiobj.c @@ -153,7 +153,6 @@ BOOL GDI_Init() s = (struct segment_descriptor_s *)GetNextSegment( 0, 0x10000 ); if (s == NULL) return FALSE; HEAP_Init( &GDI_Heap, s->base_addr, GDI_HEAP_SIZE ); - free(s); /* Create default palette */ @@ -200,8 +199,11 @@ HANDLE GDI_AllocObject( WORD size, WORD magic ) GDIOBJHDR * obj; HANDLE handle = GDI_HEAP_ALLOC( GMEM_MOVEABLE, size ); if (!handle) return 0; - obj = (GDIOBJHDR *) GDI_HEAP_ADDR( handle ); + if (obj == NULL) { + printf("GDI_AllocObject // Error trying to get GDI_HEAD_ADDR !\n"); + return 0; + } obj->hNext = 0; obj->wMagic = magic; obj->dwCount = ++count; diff --git a/objects/palette.c b/objects/palette.c index 3b101b2608f..511cf3f0efb 100644 --- a/objects/palette.c +++ b/objects/palette.c @@ -177,3 +177,21 @@ int PALETTE_GetObject( PALETTEOBJ * palette, int count, LPSTR buffer ) memcpy( buffer, &palette->logpalette.palNumEntries, count ); return count; } + + +/*********************************************************************** + * SelectPalette (USER.282) + */ +HPALETTE SelectPalette(HDC hDC, HPALETTE hPal, BOOL bForceBackground) +{ + return (HPALETTE)NULL; +} + +/*********************************************************************** + * RealizePalette (USER.283) + */ +int RealizePalette(HDC hDC) +{ + return 0; +} + diff --git a/objects/region.c b/objects/region.c index 08274ca08aa..3a7b9ef290a 100644 --- a/objects/region.c +++ b/objects/region.c @@ -31,6 +31,7 @@ BOOL REGION_Init() XFreePixmap( XT_display, tmpPixmap ); if (!regionGC) return FALSE; XSetForeground( XT_display, regionGC, 1 ); + XSetGraphicsExposures( XT_display, regionGC, False ); return TRUE; } else return FALSE; diff --git a/objects/text.c b/objects/text.c index bbb2740085d..07aef5835c4 100644 --- a/objects/text.c +++ b/objects/text.c @@ -229,7 +229,8 @@ int DrawText( HDC hdc, LPSTR str, int count, LPRECT rect, WORD flags ) else if (flags & DT_BOTTOM) y = rect->bottom - size.cy; } - if (!TextOut(hdc, x, y, line, len)) return 0; + if (!(flags & DT_CALCRECT)) + if (!TextOut(hdc, x, y, line, len)) return 0; if (prefix_offset != -1) { MoveTo(hdc, x + prefix_x, y + size.cy); @@ -247,7 +248,7 @@ int DrawText( HDC hdc, LPSTR str, int count, LPRECT rect, WORD flags ) } } while (strPtr); - + if (flags & DT_CALCRECT) rect->bottom = y; return 1; } @@ -314,10 +315,10 @@ BOOL TextOut( HDC hdc, short x, short y, LPSTR str, short count ) { if (dc->w.backgroundMode == TRANSPARENT) XDrawString( XT_display, dc->u.x.drawable, dc->u.x.gc, - x, y, str, count ); + dc->w.DCOrgX + x, dc->w.DCOrgY + y, str, count ); else XDrawImageString( XT_display, dc->u.x.drawable, dc->u.x.gc, - x, y, str, count ); + dc->w.DCOrgX + x, dc->w.DCOrgY + y, str, count ); } else { @@ -340,14 +341,15 @@ BOOL TextOut( HDC hdc, short x, short y, LPSTR str, short count ) if (dc->w.backgroundMode == TRANSPARENT) XDrawString( XT_display, dc->u.x.drawable, dc->u.x.gc, - xchar, y, p, 1 ); + dc->w.DCOrgX + xchar, dc->w.DCOrgY + y, p, 1 ); else { XDrawImageString( XT_display, dc->u.x.drawable, dc->u.x.gc, - xchar, y, p, 1 ); + dc->w.DCOrgX + xchar, dc->w.DCOrgY + y, p, 1 ); XSetForeground( XT_display, dc->u.x.gc, dc->w.backgroundPixel); XFillRectangle( XT_display, dc->u.x.drawable, dc->u.x.gc, - xchar + charStr->width, y - font->ascent, + dc->w.DCOrgX + xchar + charStr->width, + dc->w.DCOrgY + y - font->ascent, extraWidth, font->ascent + font->descent ); XSetForeground( XT_display, dc->u.x.gc, dc->w.textPixel ); } @@ -368,7 +370,8 @@ BOOL TextOut( HDC hdc, short x, short y, LPSTR str, short count ) XSetLineAttributes( XT_display, dc->u.x.gc, lineWidth, LineSolid, CapRound, JoinBevel ); XDrawLine( XT_display, dc->u.x.drawable, dc->u.x.gc, - x, y + linePos, x + info.width, y + linePos ); + dc->w.DCOrgX + x, dc->w.DCOrgY + y + linePos, + dc->w.DCOrgX + x + info.width, dc->w.DCOrgY + y + linePos ); } if (dc->u.x.font.metrics.tmStruckOut) { @@ -380,7 +383,8 @@ BOOL TextOut( HDC hdc, short x, short y, LPSTR str, short count ) XSetLineAttributes( XT_display, dc->u.x.gc, lineAscent + lineDescent, LineSolid, CapRound, JoinBevel ); XDrawLine( XT_display, dc->u.x.drawable, dc->u.x.gc, - x, y - lineAscent, x + info.width, y - lineAscent ); + dc->w.DCOrgX + x, dc->w.DCOrgY + y - lineAscent, + dc->w.DCOrgX + x + info.width, dc->w.DCOrgY + y - lineAscent ); } return TRUE; diff --git a/sysres.dll b/sysres.dll index 44a53abd38e2eccc301fd1aa8481aa829a9fce04..38c7ca909d2540ae5515dee73c18b4706a6d6a08 100755 GIT binary patch literal 86528 zcmeFae|*-}efR%Cty&vfY@Jf2HgOPerWGb&NU+reC7_Lvgn(kxEXxmOs3u5B15VPL z>R3dkLMJ#kwY9Dlwpxd)E84oYx1}51^sbw_uT;LXTAbo-zpY`{;Ax<1$E$2srwIN~S{zJL4Mzguztm)G z^5vhny!;cFcXll=|H$wC?(!?HyrO$W`J&&uyz`2ID?fPbF%u5%e&cy>JLX@;92Fc%+w>i?d|*>cJ$#H+{=zR{D|zZ!_GPOu)~hbp2~jb z*r&K!Hk4{Pny06XKkPty#^ZHy{LZ1HJ(V33*N=#E?}+2Wy|;Pr$`xH7FK_C)^2#edvHW+t%Db;v zE+4wM_*QuffwvI&uY|xKe(1ef>!MQ@9NGHJv8SB*(EJ6r9KZ_R_)P1W51n$<*DuZf z=Be!Te|-JNcW%RW`Rya$ogJOM`i&#v_;?J(`X@F#^tDSf9{To? zCudpt-Ye5VdgwYDYWw^9v#jl?i{JmTw!i=Ok?-S~;q#B!j^Fv_DT{A7Z{c+>p0eSI z)(SljzQ`jNjoESt}x-#-7aG1*67 zcwzg2>mI-E`?XK6II(i*!v|KBRaWcEjJj;cKHvBQpf;oFr57V-AbH@9cMSi$oDOa+-e`RGUf-nSRZt~;eQd-Rz{pE+>b zrP&>=*@1VqX770D6VKDTy<-ks%x&DY_Cu{%`6u3X|CsEB@!tRC!@l>-b>|;_UF(s5 z_y=v-AKrXvcHqd??97Kg`uExW2M&~gx^Cq=ue-V|zw!K||FHGQwO1dLt#~{4%n#_S zFiRjEGwMm|jVlSfqq4)tyqlpog7+!Be>yun>*D>MF^6Y=#{0jGIV^jDzj<7La?F@) z9KPtw@%g_J&)<^uS3;ofisj3G=km_-`qNJ@|3G>D6@7!tf3Iihit?#5XHG3IF3!Dt z#j+1FdvFGk{(hyl{*OO&I81JW!7VVkF@K*I@Bhb}daJ^>5cn^OfU~ml>>OUlWX^`t zZ0f&gXWkO~KaIel^*9d__$3JD4evJV5HSg-7 z}63f1@1O|Em^cIqFv|`+au* zfnTK@m7e`o8m7r;H$D5)D5L8cL2>libbQdWKh0|xbsK|`N;c|bemMGB9{m~RsH5^a zyd?&d#t;0v&+;74|7y=3b<}IG@$^CM{)c7$-+1etwqpI1Y|7$kv^6bT z_l0R$Sy^>fU0t1Z_El#?o2#?U_f%)&#?8vgC(p{pPMejDKWA1})i5i&bp5RC!o}xg zeOH~6RZW|noilqj7|hNVFP)uTwSIQC{?^&qtq;u3%EmQh$4_p^#$VWwb#89RK6!gX zcEdK#&AKpK+IL~L?V$^^36tm3=KSo!3+HDom(I_|jc>`0p3su5xT+-^x}hbz;r5p7 z)_YpA$qkFM`O6k(+jar=@t0!-cV<;Bo!O^1b!MCH?99ejEzPD)TbkW|&(f@H+Oll&>}6TQ zvSrA$EPLRoWm#6~9dn?HXjTh=#}wX7S; zKD~Y@+q8KoyXT>y?2#V~WyhcM=`5SFE}OM@UG~YV)@8SUVO{pr%j=M9eKx*jeRk=k z>$7P~*JqtW>$3-TtxcVr9Zc3S6y{$wrSI?*|#3KHJiQccKCH?w(Xufv&Wvg zlL^olvdNczA)9s87qWGq{zA6*Ctt`mZ{C*e+_fz$TYOJe-F^>s-;+J?z&%-Z;r6U* z+4gMqy6xFhd$(sld3}3!^sM`{@r&=z9(m$^+IS$laPtFMRr^EP@k<}dX7N|`$%nGr zZ+|E&oByqB+qQ3IPwn|u_WJAJ%4U6XXLjMx&aAwBS2ktYu54`QBiXF=k7NzEK9W85 z*dtl_vL~`xeNS-j6V&k(_db>VV9!(8tWWQOlY6q`JAaUkzv>5B!wo;kCNJHaRegFd z_r8c;y_`*3@p3j{Xn$7y>HS&Dt^2ddH@u$B+VpzXdHd_x>^omaN6^bzLmxl3Xwjl&pSkn9FTV8BOD{h6t@EeO>1=Bo z7#dj6(6GSLK$$tSp>2V$e&jVi%$zxM+BD8l+Ik0uHV*Z+dAz`@oLbN@?WBoZ^^UgQ z-Zo3r(GZWN7wU-nQ#Ced)4kp|le+WMeu`sGPKGU4BVpLoa3HmR_KU zR#G#z7l=lK%AJZQfhX|e4iTRza6Ich@fes4Q72M+iVo3ri&aHQVA>FMahv#YTYgud znFAE3Cr%VTN&!iTV@<*jenUBaZ8PJpsL1-JO>4AIj3(l=C2{~~+t9`>TNpOl9@x0G zgnMIS_)1`V9vI?*{1H9|{t3Q~$UFoHTekp7TT~;~BJE=+lF%uU z0LFL?060&jx8SWB(9qDiq;U=meCJR9>ic`17r~cbc$V_y?%hxN2Y&oLdFOZcK+P9G z@9|GxaocCNZd@=Eegoacp^e+NL1hl*yERhm9Ip)xcEskRDPT~Vyx5%uArhpE{wSV$ zNiRfAzSwQ`%?hGxC}a)`I-LfAdr&?;P;opewZS4mCME^=oD^t<-5A=tCA2UNO;YyM zB)32hloY}_R6G$wn+A9b#N~796!e?ZSUvTWGfw@(XP$w75D@qPPx!!V_nsGDd>qZ) zhh_`upIxzh>%-f&3{WXG*!8d>swP#2?nU=S5xKQM4KPnQ;V3s0@Yz4d*^|M|p)Fgt z0AXH5x=lQ|5v&5gnG;VsE|svFaSnh)%DV~;^*Dc$OPoƉV(tl$TD(ksTr+vKwK zc$@k}*OHoQ@zgMHmy~pPAiBiO)e|RHqr%lw&pqqZkN@z;KmPHL0zQy?j=w#7p85V0 z-@NO}MKA4pj`L6M-uq`)tX;F?;cZb>GFzCDEgQ8CkY}iOf%01NcdZ!aT8KbA6cOzR z9!e}EQ-kFWcS(x@)JewhCyj+MSLEoQR!szxy2;Rln)e4|gJGO2o>H8kr4peF4p>sc z0M8n7R>DnuCy^Hqk+bep&cg>n1YQTD=!HaHh+ctzZcEnJ=G>BA=AOU4~ zI|o|feHTbSqS%x;C0H@$UI_F>OK8$)aH=#S^fTnneXA%3%<`R^yfql-<3)*+;wO6H zJP#dGqHS{izx=*Ep}FhP8u3R*i|0vIi-it4N`tqATJKVbfvTfY*@D5lU-R>RUwpG`OZ@{0@ zUK(>phXD_Y#aJu8o}z#ZQNk{&n}`_Z(GI8XBU|E94vDCUlpUsKIq3KxK>-q10Z{Xg z;Vrt&ae4@;Pz8Fw75#(g(RPfAS47N~C8LK+!XqxJwvlMo%DEI#7BU2M-ik@#mc}JZ z=A3^n2>uDcVe|IvybI#Zox7;DRrnS?D|#<|;@oTgdh5pC#+jX=YZ%{v4DM~!GYJL( z9TEs3!($hNbipyMXu1V3by*w*E9B#~O-2M5;?(F7jI~B@3jET?gr9N;wvL!LNI;IL zHaQl@go+f(3*MxW*tTQGwyhcpt^l`{TYnU9bC^Q3P)~+qK@zyQh65sM4FGu-{Ahkj zCjf%r89)6K!29O*O=7nQ^nh$dq7Ubum-ww@s(sMf>4n9{0Vw(a737=)o~leYHY5`w_VSfG)~s2%4-8@DX^^}5C|uMP z9E|aiTLb`{j@UFc?sMXrZVgaEhA@u_9aZZbnv|+)<9nK+8;p(XqPJR14Y+f>ZixyqG zY5V<8?Ap0|?;jjLm8W4uII$QldJ>|MN>J1=9ASong(X&Lek~2t8Y5mtMFK#Dvp9~S zO2YS!<0c}bQi_k=p)wUuqDOxP&^vf61w=uexFO7x*C@hpaM8buz1}8)9J~tv&16KiR%>*REYVckbN# z#QTodTt|`73>k5dgr_YKGX8^n*3U}_HZ;uKCq~N==KeHArvE&kK5|U~1FU3+J>TGD5>Sr79&kO7Oye5)}@pV zu!G(h`5uQf#$1zQUC0r`s6@(SJ?WT6#EKHboL&@73^}Jw+PD?=wY7D2;)AD7IR5RE z7J=RN`*-cy`FNBkzQ6n9V~;!OxKQ_K4_ae|2?f(At5rEK^yfrbgjo+iykiH+fan3q z4yH@quIb667)b^QiEQZa#AzqJ1O6#KviaZ|fqU@YyYIgHUh#|f2X9+x=hS!mY4xGS z5Hy&X9`$^xMa|#>cL5+iS3K-{V4Q|f%tMxhq9WykOJ}*2YsthYByFqIZF)<`(3mU* zLk%&Jn{diI-@XFu5_FG04gq)V{O0ke;F184rc>pZZXlX96tc0+F6fdD zmD?H{naRx|m2mtUGXlLQfDqlaES)fwCy#rF;Y3iLFx7Y&I)%V7nAE{YI@}Z(_wWue zqXcZ>CLOEjgkUF{DJMM<#K6$er352qRU#SldjEvi60ORzeG0w{LDy@>w@>7#e+|p%={}j~uly z4QZS@;gsV~?RflAz}vNJ=dLF#yUr)i0RB`ov5~OWdTnE7!y55OW9^99BFMzp6BGfJ zB>)NBL07;N+|2hKNPQ!78I(yPpp2PTn!{78}7iX)q_1 zTCT>SCPks*bJTQGPPN28)izW&V2qc0@9k7OsXx8O&;_L(uE3Pm!m&UQZEuc~CPF(W zcj8Wt)yx1DSaZ>lJYu{Ac;5Gj*_Bnc#v?G_0F*Z4(a1(mm~j4OAJ`s-PYk~cgiDwT z2%s-EVaps(oJJ0R8)~X_aZ(rxRmdfwA)8#Fhm@-r&YXAAbvhe{$o`17uM1X|l=a^4 zeCOUfuD<;8%de(j`cjdW04QEy6ybQ%V4h85=}?h^GCEX;O^b!VdA~!ZFdND%cBxlI zCpe*gd72k{8W3s)qcBMdbWTE{8jR5jI zweq|*QN0E_T&vL8ATgr1D3Bk;Bqf8LysOay7>rL9rN?;AhbVUBHt;iG0j&q`*u3^e z!Am74UjVp-TeZMp541@3zEoJBA%$T)UYfc58233y^Eq>P8Yhub~CR zj_xPkh63w-p}6@^rv)BIl;>=a5@M+vsmMOS3LtZvNL~D2tPY4;?tc@0foa~i1q(Xc z)(mePFt%^B=EiALr#3EMe(|Xv-?Inefn8TieO1nvAfE<=67;iWnJbI2HTg`Gp-CaZ!HDiP1qwxW zPIR9)S;#%xt6WJG2Y#E&*83?{A;_&gM|%&6`KUz)r=I z!xVBLE-P+~h-EAAMOYEi1QrTQQCyFbVfM2pY}9T9ghD2Wxr*gTqISTS-yZ#-$7mhU zLBOqBhl%RAJn^LJNTp6V_1$7;DX*wVgt7m@=A#ckTm-{`B%V^Qd%5;*{@eRd-_4t0WAZCFl6%+S z)Abs*-OD6?s|#BkhvRkSkxK$h;~^`(&x;a?B1KW+zz+px#kJxlNQKzaQw$Xr0?;VN z0syx%Qyo~)7%`s9NlZc}ob~osU(H@EuZcp0=fqV@W+eHJqsJUR2K-X}0UY=x&=fd1VLl^Q>U!Mh zN7~Y2u#`45{MpYAuUTU75@qUf6W;NTspp zjThdU&)5cxShs9LdAG4v7x9GyDnvG2cuYCzNrykA<)++VHQo(8LWn1c==p{(-hdgr z`o=qAN-RCU^Wd;^iXJ2> zRJbz7B1DOJ*bXFZl2V~PL|`oR3u5fkip~Nd%R~#52^qM}=|hZ)kJ2Ith+FL%dVCdXG`1_gU!Y&=9L1DRf~|8%zuao>eLJqVyWd4@L5c8f8~%LalX-+z6yC za!?h@t5RHp2y21NX()HwGyh^V5itoFb674bZ`dm*Q>?H}U9SEL-}kyOIm^ay;#xY%u}75E`-m^GIU&?o^xbWu_Dsm#t&@;Cb? z`o-z|V%tC`tXtCAwjkVZHG7I!4Xz5^6~LJbwwesp$b@C#K3a7FhoV)B=nG9kCWj9u zpVZifLTg`58HloN+PMTdcHXEvKvmJ5yQHo|Kv|7dnzm-kj{pAO1GoF`yDw(M_uhTS zHA|+g+4k5D!OBy=DzCd<%K!}^SUEm0 z2ZP+$yOr?SymRUrPdT98>>z~vVws9wIz_`V#HgDT*+>kuW6Q?jHEX|k-yMH_?`=1A zl61k*lk*Wi<2)lxso~XISD^reFA|t z+MjJqj-Gz{;jL+;;tGRdHHiWFs9P~J8+V(;WRzZWrH~966oDbtifJJcE%u%|cQ!O{ z#63Lr^uIm*u<$(twvlrGIV2z;U0#dxK+!;YIz{$Uw`QHA1*@`S~9Jxm3iT z($>2TP2m3qJ-w9z8CO5)Jw z%E0!CX@no!7_EPMdMo7YT`*_!7crNSA{Z92c!(xco?dr$M;xme6&p`Ryz2bQT6JsD z1D}X?!cA%Ua;FjW14l6xXH~0!F9B%ys^#%hids_p*xtBxL8JDsamm2&R;D8>S6(vV zDCV{g8?GP@R|G0mW`8uiN!&0@(jHCR79`OGFj|NafSJBFe+_Tk zngW^ZIghD`14AH){q%5&_@M)u8dV{cG^QK3?7*&s3pSX|3n<%RE24XfXeW3a@p8); zo+D|muj(!L#huY%kLXtP&5#kYh2>5`pP%h)v}2u1I$1yJT$yyZb4m3n5kLoqQ7iYe zb7)`()ATTFX=r_(r(;wYHJyk?G1P$YA{q1!<4#&>BZ|6(O4vUeM_Am@fly+1 z8Hk>ssr~s9-pc##SfYstW7*rA6cKS$X~K4prz0s3t}J%Uo_i!Y;@JMipZr3!@TCQA zCE$v#+F3Qr3x;dpXZv~QlCs;5v4df4TW@D0;8BJ#ft}_M68~D8n%ZfL(MfF}DZ!`e zwTEK9d`WC)7Z6WKm*g*gGX*g07DNY1&|?vK^$+xVW&YEFF_3EfIm^+tz74%lvQ@A8#8j|AVG>IvZ2+SJ$AM-E#5R4__$ zFv^%xut*j!^(ESN%#tM92tI(k9ND3cxz;2eLwE*qGawnbs?1JR&~OtDlFwszFobsV zX)XBS$VrG<(bl-bw-V)L5ozivAE+~bUv+F*naUVNOw!Nghs6N`HUkh0Z{9ZV@M`~4K@QJ2A$&D5c-)&df{PGVZ6!4Km9a-U31@N z?Oz&aRUAV3O#%%u^s|fFP|Q;bF9c97InZb?5*GRnwX}J`yNF;M=)fcKiU-|Zl+Kyc z)Ur}-(9Tz9z!TYs?y#iP9UJTzW&UmwK&Qe^fG3>t_NvI=mt~pF1#~fR4kPu)Nr^Wc;%956G^|Y415a213SJgT%LOa8kT=iFo2P5VYJx4g&hPx zqY>5649m2srU;3Id4s(ThI3B(F@X$~>TBnPl;MV1Te+;gi#fA|Qb20j$h>iDFZg+n z-q^F?9zb(92G7Bi+R-8VFZmQQ9R)N&!7$0(96FJ1NK`Nz6WT8Aq5{rSs3<0tYIPu+ z&<8&6N+4sKwji_?>89I;S2mhNoyyk=r=G?4=d^f*uA$AxJ(P@QC)rhspaL-u?p2y5#bhyCO ztnKQ*-Rzvr8B{N`vIvOqCe*ZT2!J>#0QOeqf`bx92>^qcy!h^<*!i`6Nnc3GP2`A1 z21Nkc3VaJ3Lt9aPJ|#?pf;5;%6UhD9o6O`-Lwl=9pjOE|;j5_$q-Zc9<`@|WC0&+) z1I#cUBT!V-mmPP9n(_TEMqN@CAv152vUOKsvd`|Ku8W2nV4FUIaI)no2^= z+;Hd2#W!9apOZD>EVmm6xkw&9HfLB)7qNKj+w)~XpfuT%YFdTYdXgUmjD_MSva#o%_6~DA3FJK8la=$STqyZ%rK*Kd7 zVke$$GXp@-gLrDV;qexxvrkKN^9d2M2}Ur5UX!5(KC)HDZ+dHrGrEl%S6+Nxb6sfQCK|BP;`srw*gK&l1aQX_YUCrTB0z{CaR1Agm9=NrjV4Rm$sVm?k zMm|ij!bCqWr+adXC@14q2T|~NxoP>zm23f&f7Me@9gQDNp^;P;6K-k>{v|v)51zym zcuo-1H!37s1}&lAf~uK-URZqemcoR?VN7By*qD-qnmB_8AWtS~wM#w_FT> zkQ2>!(;SSB=*eM_#?hTf(HK*CB2MXCY)Rdhga53-E%lA8gjz%B0b(YQ6;Z&H`@ zfvESzF|TMZ*}3>q)5d`%myiM!K+1%wJb7PJGjAT)!FFDX5+2Ai7AY8}*cq#oaGH(k zNiMILQ#3S&=gv7Km2@P4R#7eVUu1%Hb{z?+u&rUvc_ZkFVRQW)qos&f@gh664m%Oz zF*}<&Y#3mc#1loqhU(sgFVQK;m87#Vi6(w=zYiv$fjo4K`#BL zt4qj+XMl=&9*$C|>c@>+7DGJ%w6suoYpy?sEn{l7+WXj!VQ^M2qr>!!_VpgoM_$qy zQ3&wT(0Cko;7LlXOPB@eMbQWSzyY=bu5&I`%#%Kxnwhp>(af2^8OY<5QV1eC{M>l;W;RpTrO@!oqa}WHdxB@YXSPuF{ zU@Q+U2|p1GNL6MVqZBir&lxkS`TL>+bGe zy_y#>tZ!KiH<<)FgGm{619p+%K|5mOo&pQUgU

^T}v~g10!-ii%3(0ZrfJLdL3u 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

txdxMDR%9S2UU4 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 Xeso>;kICXh8Vu2s!)$qeljHvfW$j!c literal 66048 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 O96bhI>Ca!}_WuV;YmdqR diff --git a/test/Imakefile b/test/Imakefile new file mode 100644 index 00000000000..d45263d3c95 --- /dev/null +++ b/test/Imakefile @@ -0,0 +1,8 @@ +all:: + +depend:: + +clean:: + +includes:: + diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 00000000000..535cc4716d3 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,347 @@ +# Makefile generated by imake - do not edit! +# $XConsortium: imake.c,v 1.65 91/07/25 17:50:17 rws Exp $ + +# ------------------------------------------------------------------------- +# Makefile generated from "Imake.tmpl" and +# $XFree86: mit/config/Imake.tmpl,v 1.17 1993/06/03 15:26:36 dawes Exp $ +# $XConsortium: Imake.tmpl,v 1.139 91/09/16 08:52:48 rws Exp $ +# +# Platform-specific parameters may be set in the appropriate .cf +# configuration files. Site-specific parameters should be set in the file +# site.def. Full rebuilds are recommended if any parameters are changed. +# +# If your C preprocessor does not define any unique symbols, you will need +# to set BOOTSTRAPCFLAGS when rebuilding imake (usually when doing +# "make World" the first time). +# + +# ------------------------------------------------------------------------- +# site-specific configuration parameters that need to come before +# the platform-specific parameters - edit site.def to change + +# $XFree86: mit/config/site.def,v 1.65 1993/06/04 16:02:47 dawes Exp $ +# site: $XConsortium: site.def,v 1.2 91/07/30 20:26:44 rws Exp $ + +# obz: changes for making Linux distribution + +# ------------------------------------------------------------------------- +# platform-specific configuration parameters - edit x386.cf to change + +# $XFree86: mit/config/x386.cf,v 1.90 1993/06/04 16:02:50 dawes Exp $ +# platform: $XConsortium: x386.cf,v 1.7 91/08/16 19:30:10 gildea Exp $ + +# ------------------------------------------------------------------------- +# XFree86 version definition +# $XFree86: mit/config/xf86_vers.def,v 1.5 1993/06/01 09:12:47 dawes Exp $ + +# ------------------------------------------------------------------------- +# XFree86 version: 1300 +# ------------------------------------------------------------------------- + +# $XFree86: mit/config/lnuxLib.rules,v 1.2 1993/06/02 13:48:12 dawes Exp $ + +DLL_BINDIR = /usr/dll/bin + +# operating system: Linux + +# ------------------------------------------------------------------------- +# site-specific configuration parameters that go after +# the platform-specific parameters - edit site.def to change + +# $XFree86: mit/config/site.def,v 1.65 1993/06/04 16:02:47 dawes Exp $ +# site: $XConsortium: site.def,v 1.2 91/07/30 20:26:44 rws Exp $ + +# obz: changes for making Linux distribution + + SHELL = /bin/sh + + TOP = ../. + CURRENT_DIR = ./test + + AR = ar clq + BOOTSTRAPCFLAGS = + CC = gcc + AS = as + + LEX = flex + + YACC = bison -y + + COMPRESS = compress + CPP = /lib/cpp $(STD_CPP_DEFINES) + PREPROCESSCMD = /lib/cpp $(STD_CPP_DEFINES) + INSTALL = install + LD = ld + LINT = lint + LINTLIBFLAG = -C + LINTOPTS = -axz + LN = ln -s + MAKE = make + MV = mv + CP = cp + + RANLIB = ranlib + RANLIBINSTFLAGS = + + RM = rm -f + TROFF = psroff + MSMACROS = -ms + TBL = tbl + EQN = eqn + STD_INCLUDES = + STD_CPP_DEFINES = -traditional -D_POSIX_SOURCE -D_BSD_SOURCE -D_GNU_SOURCE -Dlinux + STD_DEFINES = -D_POSIX_SOURCE -D_BSD_SOURCE -D_GNU_SOURCE -Dlinux + EXTRA_LOAD_FLAGS = + EXTRA_LIBRARIES = + OS_LIBRARIES = + TAGS = ctags + + SHAREDCODEDEF = + SHLIBDEF = + + PROTO_DEFINES = -DFUNCPROTO=11 -DNARROWPROTO + + INSTPGMFLAGS = -s + + INSTBINFLAGS = -m 0755 + INSTUIDFLAGS = -s -m 4755 + INSTLIBFLAGS = -m 0644 + INSTINCFLAGS = -m 0444 + INSTMANFLAGS = -m 0444 + INSTDATFLAGS = -m 0444 + INSTKMEMFLAGS = -s -m 4755 + + PROJECTROOT = /usr/X386 + + TOP_INCLUDES = -I$(INCROOT) + + CDEBUGFLAGS = -O2 + CCOPTIONS = -m486 -DNO_ASM -fwritable-strings + ANSICCOPTIONS = + + ALLINCLUDES = $(INCLUDES) $(EXTRA_INCLUDES) $(TOP_INCLUDES) $(STD_INCLUDES) + ALLDEFINES = $(ALLINCLUDES) $(STD_DEFINES) $(EXTRA_DEFINES) $(PROTO_DEFINES) $(DEFINES) + CFLAGS = $(ANSICCOPTIONS) $(CDEBUGFLAGS) $(CCOPTIONS) $(ALLDEFINES) + LINTFLAGS = $(LINTOPTS) -DLINT $(ALLDEFINES) + + LDLIBS = $(OS_LIBRARIES) $(SYS_LIBRARIES) $(EXTRA_LIBRARIES) + + LDOPTIONS = $(ANSICCOPTIONS) $(CDEBUGFLAGS) $(CCOPTIONS) $(LOCAL_LDFLAGS) -L$(USRLIBDIR) + + LDCOMBINEFLAGS = -r + DEPENDFLAGS = + + MACROFILE = x386.cf + RM_CMD = $(RM) *.CKP *.ln *.BAK *.bak *.o core errs ,* *~ *.a .emacs_* tags TAGS make.log MakeOut + + IMAKE_DEFINES = + + IRULESRC = $(CONFIGDIR) + IMAKE_CMD = $(IMAKE) -DUseInstalled -I$(IRULESRC) $(IMAKE_DEFINES) + + ICONFIGFILES = $(IRULESRC)/Imake.tmpl $(IRULESRC)/Imake.rules $(IRULESRC)/Project.tmpl $(IRULESRC)/site.def $(IRULESRC)/$(MACROFILE) $(EXTRA_ICONFIGFILES) + +# ------------------------------------------------------------------------- +# X Window System Build Parameters +# $XFree86: mit/config/Project.tmpl,v 1.13 1993/03/27 03:32:45 dawes Exp $ +# $XConsortium: Project.tmpl,v 1.138.1.1 92/11/11 09:49:19 rws Exp $ + +_percentC_ = %C + +# ------------------------------------------------------------------------- +# X Window System make variables; this need to be coordinated with rules + + PATHSEP = / + USRLIBDIR = /usr/X386/lib + BINDIR = /usr/X386/bin + INCROOT = /usr/X386/include + BUILDINCROOT = $(TOP) + BUILDINCDIR = $(BUILDINCROOT)/X11 + BUILDINCTOP = .. + INCDIR = $(INCROOT)/X11 + ADMDIR = /usr/adm + LIBDIR = $(USRLIBDIR)/X11 + CONFIGDIR = $(LIBDIR)/config + LINTLIBDIR = $(USRLIBDIR)/lint + + FONTDIR = $(LIBDIR)/fonts + XINITDIR = $(LIBDIR)/xinit + XDMDIR = $(LIBDIR)/xdm + TWMDIR = $(LIBDIR)/twm + MANPATH = /usr/X386/man + MANSOURCEPATH = $(MANPATH)/man + MANSUFFIX = 1x + LIBMANSUFFIX = 3x + MANDIR = $(MANSOURCEPATH)1 + LIBMANDIR = $(MANSOURCEPATH)3 + NLSDIR = $(LIBDIR)/nls + PEXAPIDIR = $(LIBDIR)/PEX + XAPPLOADDIR = $(LIBDIR)/app-defaults + FONTCFLAGS = -t + LINKKITDIR = $(USRLIBDIR)/Server + + INSTAPPFLAGS = $(INSTDATFLAGS) + + IMAKE = imake + DEPEND = makedepend + RGB = rgb + + FONTC = bdftopcf + + MKFONTDIR = mkfontdir + MKDIRHIER = /bin/sh $(BINDIR)/mkdirhier + + CONFIGSRC = $(TOP)/config + DOCUTILSRC = $(TOP)/doc/util + CLIENTSRC = $(TOP)/clients + DEMOSRC = $(TOP)/demos + LIBSRC = $(TOP)/lib + FONTSRC = $(TOP)/fonts + INCLUDESRC = $(TOP)/X11 + SERVERSRC = $(TOP)/server + UTILSRC = $(TOP)/util + SCRIPTSRC = $(UTILSRC)/scripts + EXAMPLESRC = $(TOP)/examples + CONTRIBSRC = $(TOP)/../contrib + DOCSRC = $(TOP)/doc + RGBSRC = $(TOP)/rgb + DEPENDSRC = $(UTILSRC)/makedepend + IMAKESRC = $(CONFIGSRC) + XAUTHSRC = $(LIBSRC)/Xau + XLIBSRC = $(LIBSRC)/X + XMUSRC = $(LIBSRC)/Xmu + TOOLKITSRC = $(LIBSRC)/Xt + AWIDGETSRC = $(LIBSRC)/Xaw + OLDXLIBSRC = $(LIBSRC)/oldX + XDMCPLIBSRC = $(LIBSRC)/Xdmcp + BDFTOSNFSRC = $(FONTSRC)/bdftosnf + BDFTOSNFSRC = $(FONTSRC)/clients/bdftosnf + BDFTOPCFSRC = $(FONTSRC)/clients/bdftopcf + MKFONTDIRSRC = $(FONTSRC)/clients/mkfontdir + FSLIBSRC = $(FONTSRC)/lib/fs + FONTSERVERSRC = $(FONTSRC)/server + EXTENSIONSRC = $(TOP)/extensions + XILIBSRC = $(EXTENSIONSRC)/lib/xinput + PEXLIBSRC = $(EXTENSIONSRC)/lib/PEXlib + PHIGSLIBSRC = $(EXTENSIONSRC)/lib/PEX + +# $XFree86: mit/config/lnuxLib.tmpl,v 1.1 1993/04/16 14:06:06 dawes Exp $ + +SHLIBLDFLAGS = +PICFLAGS = -B/usr/dll/jump/ + + DEPEXTENSIONLIB = + EXTENSIONLIB = -lXext + + DEPXLIB = $(DEPEXTENSIONLIB) + XLIB = $(EXTENSIONLIB) -lX11 + + DEPXMULIB = + XMULIB = -lXmu + + DEPXTOOLLIB = + XTOOLLIB = -lXt + + DEPXAWLIB = + XAWLIB = -lXaw + + DEPXILIB = + XILIB = -lXi + + DEPXTESTLIB = + XTESTLIB = -lXtst + + DEPPEXLIB = + PEXLIB = -lPEX5 + + SOXLIBREV = 3.0.1 + SOXTREV = 3.0.1 + SOXAWREV = 3.0.1 + SOOLDXREV = 3.0.1 + SOXMUREV = 3.0.1 + SOXEXTREV = 3.0.1 + SOXINPUTREV = 3.0.1 + SOPEXREV = 1.0.1 + + DEPXAUTHLIB = $(USRLIBDIR)/libXau.a + XAUTHLIB = -lXau + DEPXDMCPLIB = $(USRLIBDIR)/libXdmcp.a + XDMCPLIB = -lXdmcp + + DEPOLDXLIB = $(USRLIBDIR)/liboldX.a + OLDXLIB = -loldX + + DEPPHIGSLIB = $(USRLIBDIR)/libphigs.a + PHIGSLIB = -lphigs + + DEPXBSDLIB = $(USRLIBDIR)/libXbsd.a + XBSDLIB = -lXbsd + + LINTEXTENSIONLIB = $(LINTLIBDIR)/llib-lXext.ln + LINTXLIB = $(LINTLIBDIR)/llib-lX11.ln + LINTXMU = $(LINTLIBDIR)/llib-lXmu.ln + LINTXTOOL = $(LINTLIBDIR)/llib-lXt.ln + LINTXAW = $(LINTLIBDIR)/llib-lXaw.ln + LINTXI = $(LINTLIBDIR)/llib-lXi.ln + LINTPEX = $(LINTLIBDIR)/llib-lPEX5.ln + LINTPHIGS = $(LINTLIBDIR)/llib-lphigs.ln + + DEPLIBS = $(DEPXAWLIB) $(DEPXMULIB) $(DEPXTOOLLIB) $(DEPXLIB) + + DEPLIBS1 = $(DEPLIBS) + DEPLIBS2 = $(DEPLIBS) + DEPLIBS3 = $(DEPLIBS) + +# ------------------------------------------------------------------------- +# Imake rules for building libraries, programs, scripts, and data files +# $XFree86: mit/config/Imake.rules,v 1.9 1993/03/23 12:56:27 dawes Exp $ +# rules: $XConsortium: Imake.rules,v 1.123 91/09/16 20:12:16 rws Exp $ + +# ------------------------------------------------------------------------- +# start of Imakefile + +all:: + +depend:: + +clean:: + +includes:: + +# ------------------------------------------------------------------------- +# common rules for all Makefiles - do not edit + +emptyrule:: + +clean:: + $(RM_CMD) "#"* + +Makefile:: + -@if [ -f Makefile ]; then set -x; \ + $(RM) Makefile.bak; $(MV) Makefile Makefile.bak; \ + else exit 0; fi + $(IMAKE_CMD) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT_DIR) + +tags:: + $(TAGS) -w *.[ch] + $(TAGS) -xw *.[ch] > TAGS + +# ------------------------------------------------------------------------- +# empty rules for directories that do not have SUBDIRS - do not edit + +install:: + @echo "install in $(CURRENT_DIR) done" + +install.man:: + @echo "install.man in $(CURRENT_DIR) done" + +install.linkkit:: + @echo "install.linkkit in $(CURRENT_DIR) done" + +Makefiles:: + +includes:: + +# ------------------------------------------------------------------------- +# dependencies generated by makedepend + diff --git a/test/widget.exe b/test/widget.exe index 6afbf24984c0166f9304baee6c47ceacef6e88cd..ea5dc2f8bf328cb955a66477af23da5f561865ef 100755 GIT binary patch literal 306490 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 }_UEY{DFr!LN7XAfyMTx%aZp|)0? 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 L#ORC3IoEza^&On7 literal 140094 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≻E%_o+tes#D| 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 KR})jl68$%wrB1^D diff --git a/tools/Imakefile b/tools/Imakefile new file mode 100644 index 00000000000..7b739a187fa --- /dev/null +++ b/tools/Imakefile @@ -0,0 +1,5 @@ +#include "../Wine.tmpl" + +MODULE = tools + +SimpleProgramTarget(build) diff --git a/windows/Imakefile b/windows/Imakefile new file mode 100644 index 00000000000..b16652fcaab --- /dev/null +++ b/windows/Imakefile @@ -0,0 +1,53 @@ +#include "../Wine.tmpl" + +MODULE = windows + +SRCS = \ + class.c \ + dc.c \ + dce.c \ + event.c \ + message.c \ + win.c \ + timer.c \ + graphics.c \ + clipping.c \ + mapping.c \ + painting.c \ + keyboard.c \ + utility.c \ + syscolor.c \ + defwnd.c \ + defdlg.c \ + dialog.c \ + focus.c \ + scroll.c + +OBJS = \ + class.o \ + dc.o \ + dce.o \ + event.o \ + message.o \ + win.o \ + timer.o \ + graphics.o \ + clipping.o \ + mapping.o \ + painting.o \ + keyboard.o \ + utility.o \ + syscolor.o \ + defwnd.o \ + defdlg.o \ + dialog.o \ + focus.o \ + scroll.o + +WineRelocatableTarget($(TOP)/$(MODULE),,$(OBJS)) +DependTarget() +CleanTarget() + +includes:: + +install:: diff --git a/windows/Makefile b/windows/Makefile index 0c5d34add37..30570a109c9 100644 --- a/windows/Makefile +++ b/windows/Makefile @@ -2,7 +2,7 @@ CFLAGS=$(COPTS) $(DEBUGOPTS) -I$(INCLUDE_DIR) OBJS=class.o dc.o dce.o event.o message.o win.o timer.o graphics.o \ clipping.o mapping.o painting.o keyboard.o utility.o syscolor.o \ - defwnd.o defdlg.o dialog.o focus.o scroll.o + defwnd.o defdlg.o dialog.o focus.o scroll.o caret.o winpos.o default: windows.o diff --git a/windows/caret.c b/windows/caret.c new file mode 100644 index 00000000000..eb78dc80ec1 --- /dev/null +++ b/windows/caret.c @@ -0,0 +1,250 @@ +/* + * Caret functions + * + * Copyright 1993 David Metcalfe + */ + +static char Copyright[] = "Copyright David Metcalfe, 1993"; + +#include + +#include "windows.h" + +extern XtAppContext XT_app_context; + +typedef struct +{ + HWND hwnd; + short hidden; + BOOL on; + short x; + short y; + short width; + short height; + COLORREF color; + WORD timeout; + XtIntervalId xtid; +} CARET; + +static CARET Caret; +static BOOL LockCaret; + +static void CARET_Callback(XtPointer data, XtIntervalId *xtid); +static void CARET_HideCaret(CARET *pCaret); + + +/***************************************************************** + * CARET_Callback + */ + +static void CARET_Callback(XtPointer data, XtIntervalId *xtid) +{ + CARET *pCaret = (CARET *)data; + HDC hdc; + HBRUSH hBrush; + HRGN rgn; + +#ifdef DEBUG_CARET + printf("CARET_Callback: LockCaret=%d, hidden=%d, on=%d\n", + LockCaret, pCaret->hidden, pCaret->on); +#endif + if (!LockCaret && (!pCaret->hidden || pCaret->on)) + { + pCaret->on = (pCaret->on ? FALSE : TRUE); + hdc = GetDC(pCaret->hwnd); + hBrush = CreateSolidBrush(pCaret->color); + SelectObject(hdc, (HANDLE)hBrush); + SetROP2(hdc, R2_XORPEN); + rgn = CreateRectRgn(pCaret->x, pCaret->y, + pCaret->x + pCaret->width, + pCaret->y + pCaret->height); + FillRgn(hdc, rgn, hBrush); + DeleteObject((HANDLE)rgn); + DeleteObject((HANDLE)hBrush); + ReleaseDC(pCaret->hwnd, hdc); + } + + pCaret->xtid = XtAppAddTimeOut(XT_app_context, pCaret->timeout, + CARET_Callback, pCaret); +} + + +/***************************************************************** + * CARET_HideCaret + */ + +static void CARET_HideCaret(CARET *pCaret) +{ + HDC hdc; + HBRUSH hBrush; + HRGN rgn; + + pCaret->on = FALSE; + hdc = GetDC(pCaret->hwnd); + hBrush = CreateSolidBrush(pCaret->color); + SelectObject(hdc, (HANDLE)hBrush); + SetROP2(hdc, R2_XORPEN); + rgn = CreateRectRgn(pCaret->x, pCaret->y, + pCaret->x + pCaret->width, + pCaret->y + pCaret->height); + FillRgn(hdc, rgn, hBrush); + DeleteObject((HANDLE)rgn); + DeleteObject((HANDLE)hBrush); + ReleaseDC(pCaret->hwnd, hdc); +} + + +/***************************************************************** + * CreateCaret (USER.163) + */ + +void CreateCaret(HWND hwnd, HBITMAP bitmap, short width, short height) +{ + if (!hwnd) return; + + /* if cursor already exists, destroy it */ +/* if (Caret.hwnd) + DestroyCaret(); +*/ + if (bitmap) + { + printf("CreateCaret: Bitmaps are currently not supported\n"); + return; + } + + if (width) + Caret.width = width; + else + Caret.width = 3; /* should be SM_CXBORDER */ + + if (height) + Caret.height = height; + else + Caret.height = 3; /* should be SM_CYBORDER */ + + Caret.hwnd = hwnd; + Caret.hidden = 1; + Caret.on = FALSE; + Caret.x = 0; + Caret.y = 0; + Caret.color = GetSysColor(COLOR_WINDOWTEXT); + Caret.timeout = 750; + LockCaret = FALSE; + + Caret.xtid = XtAppAddTimeOut(XT_app_context, Caret.timeout, + CARET_Callback, &Caret); +} + + +/***************************************************************** + * DestroyCaret (USER.164) + */ + +void DestroyCaret() +{ +/* if (!Caret.hwnd) return; +*/ + XtRemoveTimeOut(Caret.xtid); + + if (Caret.on) + CARET_HideCaret(&Caret); + + Caret.hwnd = 0; /* cursor marked as not existing */ +} + + +/***************************************************************** + * SetCaretPos (USER.165) + */ + +void SetCaretPos(short x, short y) +{ + HDC hdc; + HBRUSH hBrush; + HRGN rgn; + + if (!Caret.hwnd) return; + +#ifdef DEBUG_CARET + printf("SetCaretPos: x=%d, y=%d\n", x, y); +#endif + + LockCaret = TRUE; + if (Caret.on) + CARET_HideCaret(&Caret); + + Caret.x = x; + Caret.y = y; + LockCaret = FALSE; +} + +/***************************************************************** + * HideCaret (USER.166) + */ + +void HideCaret(HWND hwnd) +{ + if (!Caret.hwnd) return; + if (hwnd && (Caret.hwnd != hwnd)) return; + + LockCaret = TRUE; + if (Caret.on) + CARET_HideCaret(&Caret); + + ++Caret.hidden; + LockCaret = FALSE; +} + + +/***************************************************************** + * ShowCaret (USER.167) + */ + +void ShowCaret(HWND hwnd) +{ + if (!Caret.hwnd) return; + if (hwnd && (Caret.hwnd != hwnd)) return; + +#ifdef DEBUG_CARET + printf("ShowCaret: hidden=%d\n", Caret.hidden); +#endif + if (Caret.hidden) + --Caret.hidden; +} + + +/***************************************************************** + * SetCaretBlinkTime (USER.168) + */ + +void SetCaretBlinkTime(WORD msecs) +{ + if (!Caret.hwnd) return; + + Caret.timeout = msecs; +} + + +/***************************************************************** + * GetCaretBlinkTime (USER.169) + */ + +WORD GetCaretBlinkTime() +{ + if (!Caret.hwnd) return; + + return Caret.timeout; +} + + +/***************************************************************** + * GetCaretPos (USER.183) + */ + +void GetCaretPos(LPPOINT pt) +{ + if (!Caret.hwnd || !pt) return; + + pt->x = Caret.x; + pt->y = Caret.y; +} diff --git a/windows/class.c b/windows/class.c index 23a2c495764..4ca2d9f5a2d 100644 --- a/windows/class.c +++ b/windows/class.c @@ -9,6 +9,7 @@ static char Copyright[] = "Copyright Alexandre Julliard, 1993"; #include "class.h" #include "user.h" #include "win.h" +#include "dce.h" static HCLASS firstClass = 0; @@ -18,19 +19,50 @@ static HCLASS firstClass = 0; * CLASS_FindClassByName * * Return a handle and a pointer to the class. + * 'ptr' can be NULL if the pointer is not needed. */ HCLASS CLASS_FindClassByName( char * name, CLASS **ptr ) { - HCLASS class = firstClass; - while(class) + ATOM atom; + HCLASS class; + CLASS * classPtr; + + /* First search task-specific classes */ + + if ((atom = FindAtom( name )) != 0) { - *ptr = (CLASS *) USER_HEAP_ADDR(class); - if (!strcasecmp( (*ptr)->wc.lpszClassName, name )) return class; - class = (*ptr)->hNext; + for (class = firstClass; (class); class = classPtr->hNext) + { + classPtr = (CLASS *) USER_HEAP_ADDR(class); + if (classPtr->wc.style & CS_GLOBALCLASS) continue; + if (classPtr->atomName == atom) + { + if (ptr) *ptr = classPtr; + return class; + } + } } + + /* Then search global classes */ + + if ((atom = GlobalFindAtom( name )) != 0) + { + for (class = firstClass; (class); class = classPtr->hNext) + { + classPtr = (CLASS *) USER_HEAP_ADDR(class); + if (!(classPtr->wc.style & CS_GLOBALCLASS)) continue; + if (classPtr->atomName == atom) + { + if (ptr) *ptr = classPtr; + return class; + } + } + } + return 0; } + /*********************************************************************** * CLASS_FindClassPtr * @@ -52,37 +84,50 @@ CLASS * CLASS_FindClassPtr( HCLASS hclass ) */ ATOM RegisterClass( LPWNDCLASS class ) { - CLASS * newClass; - HCLASS handle; + CLASS * newClass, * prevClassPtr; + HCLASS handle, prevClass; #ifdef DEBUG_CLASS printf( "RegisterClass: wndproc=%08x hinst=%d name='%s'\n", class->lpfnWndProc, class->hInstance, class->lpszClassName ); #endif + /* Check if a class with this name already exists */ + + prevClass = CLASS_FindClassByName( class->lpszClassName, &prevClassPtr ); + if (prevClass) + { + /* Class can be created only if it is local and */ + /* if the class with the same name is global. */ + + if (class->style & CS_GLOBALCLASS) return 0; + if (!(prevClassPtr->wc.style & CS_GLOBALCLASS)) return 0; + } + + /* Create class */ + handle = USER_HEAP_ALLOC( GMEM_MOVEABLE, sizeof(CLASS)+class->cbClsExtra ); if (!handle) return 0; newClass = (CLASS *) USER_HEAP_ADDR( handle ); newClass->hNext = firstClass; newClass->wMagic = CLASS_MAGIC; - newClass->atomName = handle; /* Should be an atom */ newClass->cWindows = 0; newClass->wc = *class; - if (newClass->wc.style & CS_CLASSDC) - newClass->hdc = CreateDC( "DISPLAY", NULL, NULL, NULL ); - else newClass->hdc = 0; + if (newClass->wc.style & CS_GLOBALCLASS) + newClass->atomName = GlobalAddAtom( class->lpszClassName ); + else newClass->atomName = AddAtom( class->lpszClassName ); - /* Class name should also be set to zero. For now we need the - * name because we don't have atoms. - */ - newClass->wc.lpszClassName = (char *)malloc(strlen(class->lpszClassName)+1); - strcpy( newClass->wc.lpszClassName, class->lpszClassName ); + if (newClass->wc.style & CS_CLASSDC) + newClass->hdce = DCE_AllocDCE( DCE_CLASS_DC ); + else newClass->hdce = 0; + + /* Menu name should also be set to zero. */ + newClass->wc.lpszClassName = NULL; if (class->cbClsExtra) memset( newClass->wExtra, 0, class->cbClsExtra ); - firstClass = handle; - return handle; /* Should be an atom */ + return newClass->atomName; } @@ -118,8 +163,10 @@ BOOL UnregisterClass( LPSTR className, HANDLE instance ) } /* Delete the class */ - if (classPtr->hdc) DeleteDC( classPtr->hdc ); + if (classPtr->hdce) DCE_FreeDCE( classPtr->hdce ); if (classPtr->wc.hbrBackground) DeleteObject( classPtr->wc.hbrBackground ); + if (classPtr->wc.style & CS_GLOBALCLASS) GlobalDeleteAtom( classPtr->atomName ); + else DeleteAtom( classPtr->atomName ); USER_HEAP_FREE( class ); return TRUE; } @@ -182,3 +229,34 @@ LONG SetClassLong( HWND hwnd, short offset, LONG newval ) *ptr = newval; return retval; } + + +/*********************************************************************** + * GetClassName (USER.58) + */ +int GetClassName(HWND hwnd, LPSTR lpClassName, short maxCount) +{ + WND *wndPtr; + CLASS *classPtr; + + if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0; + if (!(classPtr = CLASS_FindClassPtr(wndPtr->hClass))) return 0; + + return (GetAtomName(classPtr->atomName, lpClassName, maxCount)); +} + + +/*********************************************************************** + * GetClassInfo (USER.404) + */ +BOOL GetClassInfo(HANDLE hInstance, LPSTR lpClassName, + LPWNDCLASS lpWndClass) +{ + CLASS *classPtr; + + if (!(CLASS_FindClassByName(lpClassName, &classPtr))) return FALSE; + if (hInstance && (hInstance != classPtr->wc.hInstance)) return FALSE; + + memcpy(lpWndClass, &(classPtr->wc), sizeof(WNDCLASS)); + return TRUE; +} diff --git a/windows/clipping.c b/windows/clipping.c index 2126c287333..3c759a68790 100644 --- a/windows/clipping.c +++ b/windows/clipping.c @@ -10,6 +10,7 @@ static char Copyright[] = "Copyright Alexandre Julliard, 1993"; #include "windows.h" #include "win.h" +#include "message.h" /*********************************************************************** @@ -34,6 +35,7 @@ void InvalidateRgn( HWND hwnd, HRGN hrgn, BOOL erase ) else CombineRgn( newRgn, wndPtr->hrgnUpdate, hrgn, RGN_OR ); } if (wndPtr->hrgnUpdate) DeleteObject( wndPtr->hrgnUpdate ); + else MSG_IncPaintCount( wndPtr->hmemTaskQ ); wndPtr->hrgnUpdate = newRgn; if (erase) wndPtr->flags |= WIN_ERASE_UPDATERGN; } @@ -112,17 +114,14 @@ BOOL GetUpdateRect( HWND hwnd, LPRECT rect, BOOL erase ) if (rect) { - if (wndPtr->hrgnUpdate) GetRgnBox( wndPtr->hrgnUpdate, rect ); - else SetRectEmpty( rect ); - if (erase && wndPtr->hrgnUpdate) + if (wndPtr->hrgnUpdate) { - HDC hdc = GetDC( hwnd ); - if (hdc) - { - SendMessage( hwnd, WM_ERASEBKGND, hdc, 0 ); - ReleaseDC( hwnd, hdc ); - } + HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 ); + if (GetUpdateRgn( hwnd, hrgn, erase ) == ERROR) return FALSE; + GetRgnBox( hrgn, rect ); + DeleteObject( hrgn ); } + else SetRectEmpty( rect ); } return (wndPtr->hrgnUpdate != 0); } @@ -133,17 +132,34 @@ BOOL GetUpdateRect( HWND hwnd, LPRECT rect, BOOL erase ) */ int GetUpdateRgn( HWND hwnd, HRGN hrgn, BOOL erase ) { + HRGN hrgnClip; + int retval; WND * wndPtr = WIN_FindWndPtr( hwnd ); if (!wndPtr) return ERROR; - if (erase && wndPtr->hrgnUpdate) + if (!wndPtr->hrgnUpdate) { - HDC hdc = GetDC( hwnd ); - if (hdc) - { - SendMessage( hwnd, WM_ERASEBKGND, hdc, 0 ); - ReleaseDC( hwnd, hdc ); - } + if (!(hrgnClip = CreateRectRgn( 0, 0, 0, 0 ))) return ERROR; + retval = CombineRgn( hrgn, hrgnClip, 0, RGN_COPY ); } - return CombineRgn( hrgn, wndPtr->hrgnUpdate, 0, RGN_COPY ); + else + { + hrgnClip = CreateRectRgn( 0, 0, + wndPtr->rectClient.right-wndPtr->rectClient.left, + wndPtr->rectClient.bottom-wndPtr->rectClient.top ); + if (!hrgnClip) return ERROR; + retval = CombineRgn( hrgn, wndPtr->hrgnUpdate, hrgnClip, RGN_AND ); + if (erase) + { + HDC hdc = GetDCEx( hwnd, wndPtr->hrgnUpdate, + DCX_INTERSECTRGN | DCX_USESTYLE ); + if (hdc) + { + SendMessage( hwnd, WM_ERASEBKGND, hdc, 0 ); + ReleaseDC( hwnd, hdc ); + } + } + } + DeleteObject( hrgnClip ); + return retval; } diff --git a/windows/dc.c b/windows/dc.c index 1a65b415927..4224b3ad335 100644 --- a/windows/dc.c +++ b/windows/dc.c @@ -7,7 +7,6 @@ static char Copyright[] = "Copyright Alexandre Julliard, 1993"; #include -#include #include "gdi.h" @@ -17,6 +16,8 @@ static DeviceCaps * displayDevCaps = NULL; extern const WIN_DC_INFO DCVAL_defaultValues; +extern void CLIPPING_SetDeviceClipping( DC * dc ); /* in objects/clipping.c */ + /* ROP code to GC function conversion */ const int DC_XROPfunction[16] = @@ -100,18 +101,8 @@ void DC_SetDeviceInfo( HDC hdc, DC * dc ) SelectObject( hdc, dc->w.hBrush ); SelectObject( hdc, dc->w.hFont ); - if (dc->w.hGCClipRgn) - { - RGNOBJ *obj = (RGNOBJ *) GDI_GetObjPtr(dc->w.hGCClipRgn, REGION_MAGIC); - XSetClipMask( XT_display, dc->u.x.gc, obj->region.pixmap ); - XSetClipOrigin( XT_display, dc->u.x.gc, - obj->region.box.left, obj->region.box.top ); - } - else - { - XSetClipMask( XT_display, dc->u.x.gc, None ); - XSetClipOrigin( XT_display, dc->u.x.gc, 0, 0 ); - } + XSetGraphicsExposures( XT_display, dc->u.x.gc, False ); + CLIPPING_SetDeviceClipping( dc ); } @@ -145,8 +136,11 @@ int DC_SetupGCForBrush( DC * dc ) XSetFillStyle( XT_display, dc->u.x.gc, (dc->w.backgroundMode == OPAQUE) ? FillOpaqueStippled : FillStippled ); - XSetTSOrigin( XT_display, dc->u.x.gc, dc->w.brushOrgX, dc->w.brushOrgY ); + XSetTSOrigin( XT_display, dc->u.x.gc, dc->w.DCOrgX + dc->w.brushOrgX, + dc->w.DCOrgY + dc->w.brushOrgY ); XSetFunction( XT_display, dc->u.x.gc, DC_XROPfunction[dc->w.ROPmode-1] ); + XSetFillRule( XT_display, dc->u.x.gc, + (dc->w.polyFillMode == WINDING) ? WindingRule : EvenOddRule ); return 1; } @@ -226,8 +220,7 @@ HDC GetDCState( HDC hdc ) if (dc->w.hVisRgn) { newdc->w.hVisRgn = CreateRectRgn( 0, 0, 0, 0 ); - CombineRgn( newdc->w.hVisRgn, dc->w.hVisRgn, 0, RGN_COPY ); - + CombineRgn( newdc->w.hVisRgn, dc->w.hVisRgn, 0, RGN_COPY ); } newdc->w.hGCClipRgn = 0; return handle; @@ -255,7 +248,7 @@ void SetDCState( HDC hdc, HDC hdcs ) dc->w.flags &= ~DC_SAVED; DC_SetDeviceInfo( hdc, dc ); SelectClipRgn( hdc, dcs->w.hClipRgn ); - SelectVisRgn( hdc, dcs->w.hGCClipRgn ); + SelectVisRgn( hdc, dcs->w.hVisRgn ); } @@ -337,6 +330,8 @@ HDC CreateDC( LPSTR driver, LPSTR device, LPSTR output, LPSTR initData ) dc->w.devCaps = displayDevCaps; dc->w.planes = displayDevCaps->planes; dc->w.bitsPerPixel = displayDevCaps->bitsPixel; + dc->w.DCSizeX = displayDevCaps->horzRes; + dc->w.DCSizeY = displayDevCaps->vertRes; DC_SetDeviceInfo( handle, dc ); @@ -372,6 +367,8 @@ HDC CreateCompatibleDC( HDC hdc ) dc->w.planes = 1; dc->w.bitsPerPixel = 1; dc->w.devCaps = displayDevCaps; + dc->w.DCSizeX = 1; + dc->w.DCSizeY = 1; SelectObject( handle, BITMAP_hbitmapMemDC ); DC_SetDeviceInfo( handle, dc ); diff --git a/windows/dce.c b/windows/dce.c index aaea4b012c1..7b24f1d4d94 100644 --- a/windows/dce.c +++ b/windows/dce.c @@ -22,6 +22,53 @@ static HANDLE firstDCE = 0; static HDC defaultDCstate = 0; +/*********************************************************************** + * DCE_AllocDCE + * + * Allocate a new DCE. + */ +HANDLE DCE_AllocDCE( DCE_TYPE type ) +{ + DCE * dce; + HANDLE handle = USER_HEAP_ALLOC( GMEM_MOVEABLE, sizeof(DCE) ); + if (!handle) return 0; + dce = (DCE *) USER_HEAP_ADDR( handle ); + if (!(dce->hdc = CreateDC( "DISPLAY", NULL, NULL, NULL ))) + { + USER_HEAP_FREE( handle ); + return 0; + } + dce->hwndCurrent = 0; + dce->type = type; + dce->inUse = (type != DCE_CACHE_DC); + dce->xOrigin = 0; + dce->yOrigin = 0; + dce->hNext = firstDCE; + firstDCE = handle; + return handle; +} + + +/*********************************************************************** + * DCE_FreeDCE + */ +void DCE_FreeDCE( HANDLE hdce ) +{ + DCE * dce; + HANDLE *handle = &firstDCE; + + if (!(dce = (DCE *) USER_HEAP_ADDR( hdce ))) return; + while (*handle && (*handle != hdce)) + { + DCE * prev = (DCE *) USER_HEAP_ADDR( *handle ); + handle = &prev->hNext; + } + if (*handle == hdce) *handle = dce->hNext; + DeleteDC( dce->hdc ); + USER_HEAP_FREE( hdce ); +} + + /*********************************************************************** * DCE_Init */ @@ -33,84 +80,133 @@ void DCE_Init() for (i = 0; i < NB_DCE; i++) { - handle = USER_HEAP_ALLOC( GMEM_MOVEABLE, sizeof(DCE) ); - if (!handle) return; - dce = (DCE *) USER_HEAP_ADDR( handle ); - dce->hdc = CreateDC( "DISPLAY", NULL, NULL, NULL ); - if (!dce->hdc) - { - USER_HEAP_FREE( handle ); - return; - } - dce->hwndCurrent = 0; - dce->flags = 0; - dce->inUse = FALSE; - dce->xOrigin = 0; - dce->yOrigin = 0; - dce->hNext = firstDCE; - firstDCE = handle; + if (!(handle = DCE_AllocDCE( DCE_CACHE_DC ))) return; + dce = (DCE *) USER_HEAP_ADDR( handle ); if (!defaultDCstate) defaultDCstate = GetDCState( dce->hdc ); } } +/*********************************************************************** + * GetDCEx (USER.359) + */ +/* Unimplemented flags: DCX_CLIPSIBLINGS, DCX_LOCKWINDOWUPDATE, DCX_PARENTCLIP + */ +HDC GetDCEx( HWND hwnd, HRGN hrgnClip, DWORD flags ) +{ + HANDLE hdce; + HDC hdc = 0; + DCE * dce; + DC * dc; + WND * wndPtr; + + if (hwnd) + { + if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0; + } + else wndPtr = NULL; + + if (flags & DCX_USESTYLE) + { + /* Not sure if this is the real meaning of the DCX_USESTYLE flag... */ + flags &= ~(DCX_CACHE | DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS); + if (wndPtr) + { + if (!(wndPtr->flags & (WIN_CLASS_DC | WIN_OWN_DC))) + flags |= DCX_CACHE; + if (wndPtr->dwStyle & WS_CLIPCHILDREN) flags |= DCX_CLIPCHILDREN; + if (wndPtr->dwStyle & WS_CLIPSIBLINGS) flags |= DCX_CLIPSIBLINGS; + } + else flags |= DCX_CACHE; + } + + if (flags & DCX_CACHE) + { + for (hdce = firstDCE; (hdce); hdce = dce->hNext) + { + if (!(dce = (DCE *) USER_HEAP_ADDR( hdce ))) return 0; + if ((dce->type == DCE_CACHE_DC) && (!dce->inUse)) break; + } + } + else hdce = wndPtr->hdce; + + if (!hdce) return 0; + dce = (DCE *) USER_HEAP_ADDR( hdce ); + dce->hwndCurrent = hwnd; + dce->inUse = TRUE; + hdc = dce->hdc; + + /* Initialize DC */ + + if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0; + + if (wndPtr) + { + dc->u.x.drawable = wndPtr->window; + if (flags & DCX_WINDOW) + { + dc->w.DCOrgX = 0; + dc->w.DCOrgY = 0; + dc->w.DCSizeX = wndPtr->rectWindow.right - wndPtr->rectWindow.left; + dc->w.DCSizeY = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top; + } + else + { + dc->w.DCOrgX = wndPtr->rectClient.left - wndPtr->rectWindow.left; + dc->w.DCOrgY = wndPtr->rectClient.top - wndPtr->rectWindow.top; + dc->w.DCSizeX = wndPtr->rectClient.right - wndPtr->rectClient.left; + dc->w.DCSizeY = wndPtr->rectClient.bottom - wndPtr->rectClient.top; + IntersectVisRect( hdc, 0, 0, dc->w.DCSizeX, dc->w.DCSizeY ); + } + } + else dc->u.x.drawable = DefaultRootWindow( XT_display ); + + if (flags & DCX_CLIPCHILDREN) + XSetSubwindowMode( XT_display, dc->u.x.gc, ClipByChildren ); + else XSetSubwindowMode( XT_display, dc->u.x.gc, IncludeInferiors); + + if ((flags & DCX_INTERSECTRGN) || (flags & DCX_EXCLUDERGN)) + { + HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 ); + if (hrgn) + { + if (CombineRgn( hrgn, InquireVisRgn(hdc), hrgnClip, + (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF )) + SelectVisRgn( hdc, hrgn ); + DeleteObject( hrgn ); + } + } + +#ifdef DEBUG_DC + printf( "GetDCEx(%d,%d,0x%x): returning %d\n", hwnd, hrgnClip, flags, hdc); +#endif + return hdc; +} + + /*********************************************************************** * GetDC (USER.66) */ HDC GetDC( HWND hwnd ) { - HANDLE hdce; - HDC hdc = 0; - DCE * dce; - DC * dc; - WND * wndPtr = NULL; - CLASS * classPtr; - + return GetDCEx( hwnd, 0, DCX_USESTYLE ); +} + + +/*********************************************************************** + * GetWindowDC (USER.67) + */ +HDC GetWindowDC( HWND hwnd ) +{ + int flags = DCX_CACHE | DCX_WINDOW; if (hwnd) { + WND * wndPtr; if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0; - if (!(classPtr = CLASS_FindClassPtr( wndPtr->hClass ))) return 0; - if (wndPtr->hdc) hdc = wndPtr->hdc; - else if (classPtr->hdc) hdc = classPtr->hdc; + if (wndPtr->dwStyle & WS_CLIPCHILDREN) flags |= DCX_CLIPCHILDREN; + if (wndPtr->dwStyle & WS_CLIPSIBLINGS) flags |= DCX_CLIPSIBLINGS; } - - if (!hdc) - { - for (hdce = firstDCE; (hdce); hdce = dce->hNext) - { - dce = (DCE *) USER_HEAP_ADDR( hdce ); - if (!dce) return 0; - if (!dce->inUse) break; - } - if (!hdce) return 0; - dce->hwndCurrent = hwnd; - dce->inUse = TRUE; - hdc = dce->hdc; - } - - /* Initialize DC */ - - if (!(dc = (DC *) GDI_GetObjPtr( dce->hdc, DC_MAGIC ))) return 0; - - if (wndPtr) - { - dc->u.x.drawable = XtWindow( wndPtr->winWidget ); - dc->u.x.widget = wndPtr->winWidget; - if (wndPtr->dwStyle & WS_CLIPCHILDREN) - XSetSubwindowMode( XT_display, dc->u.x.gc, ClipByChildren ); - else XSetSubwindowMode( XT_display, dc->u.x.gc, IncludeInferiors); - } - else - { - dc->u.x.drawable = DefaultRootWindow( XT_display ); - dc->u.x.widget = 0; - XSetSubwindowMode( XT_display, dc->u.x.gc, IncludeInferiors ); - } - -#ifdef DEBUG_WIN - printf( "GetDC(%d): returning %d\n", hwnd, hdc ); -#endif - return hdc; + return GetDCEx( hwnd, 0, flags ); } @@ -119,33 +215,23 @@ HDC GetDC( HWND hwnd ) */ int ReleaseDC( HWND hwnd, HDC hdc ) { - HANDLE hdce, next; + HANDLE hdce; DCE * dce; - WND * wndPtr = NULL; - CLASS * classPtr; -#ifdef DEBUG_WIN +#ifdef DEBUG_DC printf( "ReleaseDC: %d %d\n", hwnd, hdc ); #endif - if (hwnd) - { - if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0; - if (wndPtr->hdc && (wndPtr->hdc == hdc)) return 1; - if (!(classPtr = CLASS_FindClassPtr( wndPtr->hClass ))) return 0; - if (classPtr->hdc && (classPtr->hdc == hdc)) return 1; - } - for (hdce = firstDCE; (hdce); hdce = dce->hNext) { if (!(dce = (DCE *) USER_HEAP_ADDR( hdce ))) return 0; if (dce->inUse && (dce->hdc == hdc)) break; } - if (hdce) + if (dce->type == DCE_CACHE_DC) { SetDCState( dce->hdc, defaultDCstate ); dce->inUse = FALSE; - } + } return (hdce != 0); } diff --git a/windows/defwnd.c b/windows/defwnd.c index 3d3a280cdf5..e2f9a397885 100644 --- a/windows/defwnd.c +++ b/windows/defwnd.c @@ -6,24 +6,27 @@ static char Copyright[] = "Copyright Alexandre Julliard, 1993"; +#ifndef USE_XLIB #include #include +#endif #include "windows.h" #include "win.h" #include "class.h" #include "user.h" +extern Display * XT_display; /*********************************************************************** * DefWindowProc (USER.107) */ LONG DefWindowProc( HWND hwnd, WORD msg, WORD wParam, LONG lParam ) { - WND * wndPtr; CLASS * classPtr; LPSTR textPtr; int len; + WND * wndPtr = WIN_FindWndPtr( hwnd ); #ifdef DEBUG_MESSAGE printf( "DefWindowProc: %d %d %d %08x\n", hwnd, msg, wParam, lParam ); @@ -34,24 +37,57 @@ LONG DefWindowProc( HWND hwnd, WORD msg, WORD wParam, LONG lParam ) case WM_NCCREATE: { CREATESTRUCT * createStruct = (CREATESTRUCT *)lParam; - wndPtr = WIN_FindWndPtr(hwnd); if (createStruct->lpszName) { /* Allocate space for window text */ wndPtr->hText = USER_HEAP_ALLOC(GMEM_MOVEABLE, - strlen(createStruct->lpszName) + 1); + strlen(createStruct->lpszName) + 2); textPtr = (LPSTR)USER_HEAP_ADDR(wndPtr->hText); strcpy(textPtr, createStruct->lpszName); + *(textPtr + strlen(createStruct->lpszName) + 1) = '\0'; + /* for use by edit control */ } return 1; } + + case WM_NCCALCSIZE: + { +#ifdef USE_XLIB + NCCALCSIZE_PARAMS *params = (NCCALCSIZE_PARAMS *)lParam; + if (wndPtr->dwStyle & WS_CHILD) + { + if (wndPtr->dwStyle & WS_BORDER) + { + params->rgrc[0].left += 1; /* SM_CXBORDER */ + params->rgrc[0].top += 1; /* SM_CYBORDER */ + params->rgrc[0].right -= 1; /* SM_CXBORDER */ + params->rgrc[0].bottom -= 1; /* SM_CYBORDER */ + } + } + else + { + params->rgrc[0].left += 4; /* SM_CXFRAME */ + params->rgrc[0].top += 30; /* SM_CYFRAME+SM_CYCAPTION */ + params->rgrc[0].right -= 4; /* SM_CXFRAME */ + params->rgrc[0].bottom -= 4; /* SM_CYFRAME */ + if (wndPtr->dwStyle & WS_VSCROLL) + { + params->rgrc[0].right -= 16; /* SM_CXVSCROLL */ + } + if (wndPtr->dwStyle & WS_HSCROLL) + { + params->rgrc[0].bottom += 16; /* SM_CYHSCROLL */ + } + } +#endif + return 0; + } case WM_CREATE: return 0; case WM_NCDESTROY: { - wndPtr = WIN_FindWndPtr(hwnd); if (wndPtr->hText) USER_HEAP_FREE(wndPtr->hText); wndPtr->hText = 0; return 0; @@ -69,10 +105,23 @@ LONG DefWindowProc( HWND hwnd, WORD msg, WORD wParam, LONG lParam ) DestroyWindow( hwnd ); return 0; + case WM_WINDOWPOSCHANGED: + { + WINDOWPOS * winPos = (WINDOWPOS *)lParam; + if (!(winPos->flags & SWP_NOMOVE)) + SendMessage( hwnd, WM_MOVE, 0, + MAKELONG( wndPtr->rectClient.left, + wndPtr->rectClient.top )); + if (!(winPos->flags & SWP_NOSIZE)) + SendMessage( hwnd, WM_SIZE, SIZE_RESTORED, + MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left, + wndPtr->rectClient.bottom-wndPtr->rectClient.top)); + return 0; + } + case WM_ERASEBKGND: case WM_ICONERASEBKGND: { - if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 1; if (!(classPtr = CLASS_FindClassPtr( wndPtr->hClass ))) return 1; if (!classPtr->wc.hbrBackground) return 1; FillWindow( GetParent(hwnd), hwnd, (HDC)wParam, @@ -106,7 +155,6 @@ LONG DefWindowProc( HWND hwnd, WORD msg, WORD wParam, LONG lParam ) { if (wParam) { - wndPtr = WIN_FindWndPtr(hwnd); if (wndPtr->hText) { textPtr = (LPSTR)USER_HEAP_ADDR(wndPtr->hText); @@ -123,7 +171,6 @@ LONG DefWindowProc( HWND hwnd, WORD msg, WORD wParam, LONG lParam ) case WM_GETTEXTLENGTH: { - wndPtr = WIN_FindWndPtr(hwnd); if (wndPtr->hText) { textPtr = (LPSTR)USER_HEAP_ADDR(wndPtr->hText); @@ -134,7 +181,6 @@ LONG DefWindowProc( HWND hwnd, WORD msg, WORD wParam, LONG lParam ) case WM_SETTEXT: { - wndPtr = WIN_FindWndPtr(hwnd); if (wndPtr->hText) USER_HEAP_FREE(wndPtr->hText); @@ -142,10 +188,18 @@ LONG DefWindowProc( HWND hwnd, WORD msg, WORD wParam, LONG lParam ) strlen((LPSTR)lParam) + 1); textPtr = (LPSTR)USER_HEAP_ADDR(wndPtr->hText); strcpy(textPtr, (LPSTR)lParam); +#ifdef USE_XLIB + XStoreName( XT_display, wndPtr->window, textPtr ); +#else if (wndPtr->shellWidget) XtVaSetValues( wndPtr->shellWidget, XtNtitle, textPtr, NULL ); +#endif return (0L); } + case WM_SETCURSOR: + if (wndPtr->hCursor != (HCURSOR)NULL) + SetCursor(wndPtr->hCursor); + return 0L; } return 0; } diff --git a/windows/dialog.c b/windows/dialog.c index 108c964c5cb..83a03899566 100644 --- a/windows/dialog.c +++ b/windows/dialog.c @@ -8,7 +8,6 @@ static char Copyright[] = "Copyright Alexandre Julliard, 1993"; #include "windows.h" #include "dialog.h" -#include "prototypes.h" #include "win.h" @@ -149,25 +148,19 @@ HWND CreateDialogParam( HINSTANCE hInst, LPCSTR dlgTemplate, HWND hwnd = 0; HANDLE hres, hmem; LPCSTR data; - int size; #ifdef DEBUG_DIALOG printf( "CreateDialogParam: %d,'%s',%d,%p,%d\n", hInst, dlgTemplate, owner, dlgProc, param ); #endif - -#if 0 - if (!(hres = FindResource( hInst, dlgTemplate, RT_DIALOG ))) return 0; + + /* FIXME: MAKEINTRESOURCE should be replaced by RT_DIALOG */ + if (!(hres = FindResource( hInst, dlgTemplate, MAKEINTRESOURCE(0x8005) ))) + return 0; if (!(hmem = LoadResource( hInst, hres ))) return 0; if (!(data = LockResource( hmem ))) hwnd = 0; else hwnd = CreateDialogIndirectParam(hInst, data, owner, dlgProc, param); FreeResource( hmem ); -#else - hmem = RSC_LoadResource( hInst, dlgTemplate, NE_RSCTYPE_DIALOG, &size ); - data = (LPCSTR) GlobalLock( hmem ); - hwnd = CreateDialogIndirectParam( hInst, data, owner, dlgProc, param ); - GlobalFree( hmem ); -#endif return hwnd; } @@ -314,8 +307,8 @@ HWND CreateDialogIndirectParam( HINSTANCE hInst, LPCSTR dlgTemplate, if (dlgInfo->hUserFont) SendMessage( hwnd, WM_SETFONT, dlgInfo->hUserFont, 0); SendMessage( hwnd, WM_INITDIALOG, dlgInfo->hwndFocus, param ); - if (SendMessage( hwnd, WM_INITDIALOG, dlgInfo->hwndFocus, param )) - SetFocus( dlgInfo->hwndFocus ); +/* if (SendMessage( hwnd, WM_INITDIALOG, dlgInfo->hwndFocus, param )) + SetFocus( dlgInfo->hwndFocus ); */ return hwnd; } diff --git a/windows/event.c b/windows/event.c index 31301896e61..5f3aa3d9e97 100644 --- a/windows/event.c +++ b/windows/event.c @@ -18,6 +18,8 @@ static char Copyright[] = "Copyright Alexandre Julliard, 1993"; #define NB_BUTTONS 3 /* Windows can handle 3 buttons */ static WORD dblclick_time = 300; /* Max. time for a double click (milliseconds) */ +extern Display * XT_display; + /* Event handlers */ static void EVENT_expose(); static void EVENT_key(); @@ -25,17 +27,175 @@ static void EVENT_mouse_motion(); static void EVENT_mouse_button(); static void EVENT_structure(); static void EVENT_focus_change(); +static void EVENT_enter_notify(); + + /* X context to associate a hwnd to an X window */ +static XContext winContext = 0; /* State variables */ static HWND captureWnd = 0; - +Window winHasCursor = 0; extern HWND hWndFocus; +/* Keyboard translation tables */ +static int special_key[] = +{ + VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */ + 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */ + 0, 0, 0, VK_ESCAPE /* FF18 */ +}; + +static cursor_key[] = +{ + VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_PRIOR, + VK_NEXT, VK_END /* FF50 */ +}; + +static misc_key[] = +{ + VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */ + VK_CANCEL, VK_HELP, VK_CANCEL, VK_MENU /* FF68 */ +}; + +static keypad_key[] = +{ + VK_MENU, VK_NUMLOCK, /* FF7E */ + 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */ + 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* FF90 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* FF98 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */ + 0, 0, VK_MULTIPLY, VK_ADD, VK_SEPARATOR, VK_SUBTRACT, + VK_DECIMAL, VK_DIVIDE, /* FFA8 */ + VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4, + VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, /* FFB0 */ + VK_NUMPAD8, VK_NUMPAD9 /* FFB8 */ +}; + +static function_key[] = +{ + VK_F1, VK_F2, /* FFBE */ + VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */ + VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16 /* FFC8 */ +}; + +static modifier_key[] = +{ + VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL, VK_CAPITAL, + 0, 0, /* FFE1 */ + 0, VK_MENU, VK_MENU /* FFE8 */ +}; + +typedef union +{ + struct + { + unsigned long count : 16; + unsigned long code : 8; + unsigned long extended : 1; + unsigned long : 4; + unsigned long context : 1; + unsigned long previous : 1; + unsigned long transition : 1; + } lp1; + unsigned long lp2; +} KEYLP; + +static BOOL KeyDown = FALSE; + + +#ifdef DEBUG_EVENT +static char *event_names[] = +{ + "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease", + "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut", + "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify", + "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest", + "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify", + "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify", + "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify", + "ClientMessage", "MappingNotify" +}; +#endif + + +/*********************************************************************** + * EVENT_ProcessEvent + * + * Process an X event. + */ +void EVENT_ProcessEvent( XEvent *event ) +{ + HWND hwnd; + XPointer ptr; + Boolean cont_dispatch = TRUE; + + XFindContext( XT_display, ((XAnyEvent *)event)->window, winContext, &ptr ); + hwnd = (HWND)ptr & 0xffff; + +#ifdef DEBUG_EVENT + printf( "Got event %s for hwnd %d\n", + event_names[event->type], hwnd ); +#endif + + switch(event->type) + { + case Expose: + EVENT_expose( 0, hwnd, event, &cont_dispatch ); + break; + + case KeyPress: + case KeyRelease: + EVENT_key( 0, hwnd, event, &cont_dispatch ); + break; + + case MotionNotify: + EVENT_mouse_motion( 0, hwnd, event, &cont_dispatch ); + break; + + case ButtonPress: + case ButtonRelease: + EVENT_mouse_button( 0, hwnd, event, &cont_dispatch ); + break; + + case CirculateNotify: + case ConfigureNotify: + case MapNotify: + case UnmapNotify: + EVENT_structure( 0, hwnd, event, &cont_dispatch ); + break; + + case FocusIn: + case FocusOut: + EVENT_focus_change( 0, hwnd, event, &cont_dispatch ); + break; + + case EnterNotify: + EVENT_enter_notify( 0, hwnd, event, &cont_dispatch ); + break; + +#ifdef DEBUG_EVENT + default: + printf( "Unprocessed event %s for hwnd %d\n", + event_names[event->type], hwnd ); + break; +#endif + } +} + + /*********************************************************************** * EVENT_AddHandlers * * Add the event handlers to the given window */ +#ifdef USE_XLIB +void EVENT_AddHandlers( Window w, int hwnd ) +{ + if (!winContext) winContext = XUniqueContext(); + XSaveContext( XT_display, w, winContext, (XPointer)hwnd ); +} +#else void EVENT_AddHandlers( Widget w, int hwnd ) { XtAddEventHandler(w, ExposureMask, FALSE, @@ -50,7 +210,10 @@ void EVENT_AddHandlers( Widget w, int hwnd ) EVENT_structure, (XtPointer)hwnd ); XtAddEventHandler(w, FocusChangeMask, FALSE, EVENT_focus_change, (XtPointer)hwnd ); + XtAddEventHandler(w, EnterWindowMask, FALSE, + EVENT_enter_notify, (XtPointer)hwnd ); } +#endif /*********************************************************************** @@ -60,6 +223,7 @@ void EVENT_AddHandlers( Widget w, int hwnd ) */ void EVENT_RemoveHandlers( Widget w, int hwnd ) { +#ifndef USE_XLIB XtRemoveEventHandler(w, ExposureMask, FALSE, EVENT_expose, (XtPointer)hwnd ); XtRemoveEventHandler(w, KeyPressMask | KeyReleaseMask, FALSE, @@ -72,6 +236,9 @@ void EVENT_RemoveHandlers( Widget w, int hwnd ) EVENT_structure, (XtPointer)hwnd ); XtRemoveEventHandler(w, FocusChangeMask, FALSE, EVENT_focus_change, (XtPointer)hwnd ); + XtRemoveEventHandler(w, EnterWindowMask, FALSE, + EVENT_enter_notify, (XtPointer)hwnd ); +#endif } @@ -103,10 +270,14 @@ static void EVENT_expose( Widget w, int hwnd, XExposeEvent *event, Boolean *cont_dispatch ) { RECT rect; - rect.left = event->x; - rect.top = event->y; - rect.right = event->x + event->width; - rect.bottom = event->y + event->height; + WND * wndPtr = WIN_FindWndPtr( hwnd ); + if (!wndPtr) return; + /* Make position relative to client area instead of window */ + rect.left = event->x - (wndPtr->rectClient.left - wndPtr->rectWindow.left); + rect.top = event->y - (wndPtr->rectClient.top - wndPtr->rectWindow.top); + rect.right = rect.left + event->width; + rect.bottom = rect.top + event->height; + winHasCursor = event->window; InvalidateRect( hwnd, &rect, TRUE ); } @@ -121,24 +292,128 @@ static void EVENT_key( Widget w, int hwnd, XKeyEvent *event, Boolean *cont_dispatch ) { MSG msg; - char Str[24]; XComposeStatus cs; - KeySym key; - int count = XLookupString(event, Str, 1, &key, &cs); + KeySym keysym; + WORD xkey, vkey, key_type, key; + KEYLP keylp; + BOOL extended = FALSE; + WND * wndPtr = WIN_FindWndPtr( hwnd ); + int count = XLookupString(event, Str, 1, &keysym, &cs); Str[count] = '\0'; #ifdef DEBUG_KEY - printf("WM_KEY??? : count=%u / %X / '%s'\n",count, Str[0], Str); -#endif - msg.hwnd = hwnd; - msg.message = (event->type == KeyRelease) ? WM_KEYUP : WM_KEYDOWN; - msg.wParam = Str[0]; - msg.lParam = (event->x & 0xffff) | (event->y << 16); - msg.time = event->time; - msg.pt.x = event->x & 0xffff; - msg.pt.y = event->y & 0xffff; + printf("WM_KEY??? : keysym=%lX, count=%u / %X / '%s'\n", + keysym, count, Str[0], Str); +#endif + + xkey = LOWORD(keysym); + key_type = HIBYTE(xkey); + key = LOBYTE(xkey); +#ifdef DEBUG_KEY + printf(" key_type=%X, key=%X\n", key_type, key); +#endif + + /* Position must be relative to client area */ + event->x -= wndPtr->rectClient.left - wndPtr->rectWindow.left; + event->y -= wndPtr->rectClient.top - wndPtr->rectWindow.top; + + if (key_type == 0xFF) /* non-character key */ + { + if (key >= 0x08 && key <= 0x1B) /* special key */ + vkey = special_key[key - 0x08]; + else if (key >= 0x50 && key <= 0x57) /* cursor key */ + vkey = cursor_key[key - 0x50]; + else if (key >= 0x60 && key <= 0x6B) /* miscellaneous key */ + vkey = misc_key[key - 0x60]; + else if (key >= 0x7E && key <= 0xB9) /* keypad key */ + { + vkey = keypad_key[key - 0x7E]; + extended = TRUE; + } + else if (key >= 0xBE && key <= 0xCD) /* function key */ + { + vkey = function_key[key - 0xBE]; + extended = TRUE; + } + else if (key >= 0xE1 && key <= 0xEA) /* modifier key */ + vkey = modifier_key[key - 0xE1]; + else if (key == 0xFF) /* DEL key */ + vkey = VK_DELETE; + } + else if (key_type == 0) /* character key */ + { + if (key >= 0x61 && key <= 0x7A) + vkey = key - 0x20; /* convert lower to uppercase */ + else + vkey = key; + } + + if (event->type == KeyPress) + { + msg.hwnd = hwnd; + msg.message = WM_KEYDOWN; + msg.wParam = vkey; + keylp.lp1.count = 1; + keylp.lp1.code = LOBYTE(event->keycode); + keylp.lp1.extended = (extended ? 1 : 0); + keylp.lp1.context = (event->state & Mod1Mask ? 1 : 0); + keylp.lp1.previous = (KeyDown ? 0 : 1); + keylp.lp1.transition = 0; + msg.lParam = keylp.lp2; +#ifdef DEBUG_KEY + printf(" wParam=%X, lParam=%lX\n", msg.wParam, msg.lParam); +#endif + msg.time = event->time; + msg.pt.x = event->x & 0xffff; + msg.pt.y = event->y & 0xffff; - MSG_AddMsg( &msg ); + hardware_event( hwnd, WM_KEYDOWN, vkey, keylp.lp2, + event->x & 0xffff, event->y & 0xffff, event->time, 0 ); + KeyDown = TRUE; + + /* The key translation ought to take place in TranslateMessage(). + * However, there is no way of passing the required information + * in a Windows message, so TranslateMessage does not currently + * do anything and the translation is done here. + */ + if (count == 1) /* key has an ASCII representation */ + { + msg.hwnd = hwnd; + msg.message = WM_CHAR; + msg.wParam = (WORD)Str[0]; + msg.lParam = keylp.lp2; +#ifdef DEBUG_KEY + printf("WM_CHAR : wParam=%X\n", msg.wParam); +#endif + msg.time = event->time; + msg.pt.x = event->x & 0xffff; + msg.pt.y = event->y & 0xffff; + PostMessage( hwnd, WM_CHAR, (WORD)Str[0], keylp.lp2 ); + } + } + else + { + msg.hwnd = hwnd; + msg.message = WM_KEYUP; + msg.wParam = vkey; + keylp.lp1.count = 1; + keylp.lp1.code = LOBYTE(event->keycode); + keylp.lp1.extended = (extended ? 1 : 0); + keylp.lp1.context = (event->state & Mod1Mask ? 1 : 0); + keylp.lp1.previous = 1; + keylp.lp1.transition = 1; + msg.lParam = keylp.lp2; +#ifdef DEBUG_KEY + printf(" wParam=%X, lParam=%lX\n", msg.wParam, msg.lParam); +#endif + msg.time = event->time; + msg.pt.x = event->x & 0xffff; + msg.pt.y = event->y & 0xffff; + + hardware_event( hwnd, WM_KEYUP, vkey, keylp.lp2, + event->x & 0xffff, event->y & 0xffff, event->time, 0 ); + KeyDown = FALSE; + } } @@ -150,17 +425,17 @@ static void EVENT_key( Widget w, int hwnd, XKeyEvent *event, static void EVENT_mouse_motion( Widget w, int hwnd, XMotionEvent *event, Boolean *cont_dispatch ) { - MSG msg; - - msg.hwnd = hwnd; - msg.message = WM_MOUSEMOVE; - msg.wParam = EVENT_XStateToKeyState( event->state ); - msg.lParam = (event->x & 0xffff) | (event->y << 16); - msg.time = event->time; - msg.pt.x = event->x & 0xffff; - msg.pt.y = event->y & 0xffff; - - MSG_AddMsg( &msg ); + WND * wndPtr = WIN_FindWndPtr( hwnd ); + if (!wndPtr) return; + + /* Position must be relative to client area */ + event->x -= wndPtr->rectClient.left - wndPtr->rectWindow.left; + event->y -= wndPtr->rectClient.top - wndPtr->rectWindow.top; + + hardware_event( hwnd, WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), + (event->x & 0xffff) | (event->y << 16), + event->x & 0xffff, event->y & 0xffff, + event->time, 0 ); } @@ -180,9 +455,15 @@ static void EVENT_mouse_button( Widget w, int hwnd, XButtonEvent *event, }; static unsigned long lastClickTime[NB_BUTTONS] = { 0, 0, 0 }; - MSG msg; int buttonNum, prevTime, type; - + + WND * wndPtr = WIN_FindWndPtr( hwnd ); + if (!wndPtr) return; + + /* Position must be relative to client area */ + event->x -= wndPtr->rectClient.left - wndPtr->rectWindow.left; + event->y -= wndPtr->rectClient.top - wndPtr->rectWindow.top; + buttonNum = event->button-1; if (buttonNum >= NB_BUTTONS) return; if (event->type == ButtonRelease) type = 1; @@ -201,15 +482,13 @@ static void EVENT_mouse_button( Widget w, int hwnd, XButtonEvent *event, else type = 0; } - msg.hwnd = hwnd; - msg.message = messages[type][buttonNum]; - msg.wParam = EVENT_XStateToKeyState( event->state ); - msg.lParam = (event->x & 0xffff) | (event->y << 16); - msg.time = event->time; - msg.pt.x = event->x & 0xffff; - msg.pt.y = event->y & 0xffff; + winHasCursor = event->window; - MSG_AddMsg( &msg ); + hardware_event( hwnd, messages[type][buttonNum], + EVENT_XStateToKeyState( event->state ), + (event->x & 0xffff) | (event->y << 16), + event->x & 0xffff, event->y & 0xffff, + event->time, 0 ); } @@ -232,13 +511,31 @@ static void EVENT_structure( Widget w, int hwnd, XEvent *event, { case ConfigureNotify: { + HANDLE handle; + NCCALCSIZE_PARAMS *params; XConfigureEvent * evt = (XConfigureEvent *)event; WND * wndPtr = WIN_FindWndPtr( hwnd ); if (!wndPtr) return; - wndPtr->rectClient.right = wndPtr->rectClient.left + evt->width; - wndPtr->rectClient.bottom = wndPtr->rectClient.top + evt->height; + wndPtr->rectWindow.left = evt->x; + wndPtr->rectWindow.top = evt->y; + wndPtr->rectWindow.right = evt->x + evt->width; + wndPtr->rectWindow.bottom = evt->y + evt->height; + + /* Send WM_NCCALCSIZE message */ + handle = GlobalAlloc( GMEM_MOVEABLE, sizeof(*params) ); + params = (NCCALCSIZE_PARAMS *)GlobalLock( handle ); + params->rgrc[0] = wndPtr->rectWindow; + params->lppos = NULL; /* Should be WINDOWPOS struct */ + SendMessage( hwnd, WM_NCCALCSIZE, FALSE, params ); + wndPtr->rectClient = params->rgrc[0]; + PostMessage( hwnd, WM_MOVE, 0, + MAKELONG( wndPtr->rectClient.left, + wndPtr->rectClient.top )); PostMessage( hwnd, WM_SIZE, SIZE_RESTORED, - (evt->width & 0xffff) | (evt->height << 16) ); + MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left, + wndPtr->rectClient.bottom-wndPtr->rectClient.top)); + GlobalUnlock( handle ); + GlobalFree( handle ); } break; @@ -254,21 +551,12 @@ static void EVENT_structure( Widget w, int hwnd, XEvent *event, static void EVENT_focus_change( Widget w, int hwnd, XEvent *event, Boolean *cont_dispatch ) { - MSG msg; - - msg.hwnd = hwnd; - msg.time = GetTickCount(); - msg.pt.x = 0; - msg.pt.y = 0; - switch(event->type) { case FocusIn: { - msg.message = WM_SETFOCUS; - msg.wParam = hwnd; + PostMessage( hwnd, WM_SETFOCUS, hwnd, 0 ); hWndFocus = hwnd; - } break; @@ -276,13 +564,32 @@ static void EVENT_focus_change( Widget w, int hwnd, XEvent *event, { if (hWndFocus) { - msg.message = WM_KILLFOCUS; - msg.wParam = hwnd; + PostMessage( hwnd, WM_KILLFOCUS, hwnd, 0 ); hWndFocus = 0; } } } - MSG_AddMsg( &msg ); +} + + +/********************************************************************** + * EVENT_enter_notify + * + * Handle an X EnterNotify event + */ +static void EVENT_enter_notify( Widget w, int hwnd, XCrossingEvent *event, + Boolean *cont_dispatch ) +{ + if (captureWnd != 0) return; + + winHasCursor = event->window; + + switch(event->type) + { + case EnterNotify: + PostMessage( hwnd, WM_SETCURSOR, hwnd, 0 ); + break; + } } @@ -297,9 +604,15 @@ HWND SetCapture(HWND wnd) if (wnd_p == NULL) return 0; +#ifdef USE_XLIB + rv = XGrabPointer(XT_display, wnd_p->window, False, + ButtonPressMask | ButtonReleaseMask | ButtonMotionMask, + GrabModeAsync, GrabModeSync, None, None, CurrentTime); +#else rv = XtGrabPointer(wnd_p->winWidget, False, ButtonPressMask | ButtonReleaseMask | ButtonMotionMask, GrabModeAsync, GrabModeSync, None, None, CurrentTime); +#endif if (rv == GrabSuccess) { @@ -324,11 +637,23 @@ void ReleaseCapture() if (wnd_p == NULL) return; +#ifdef USE_XLIB + XUngrabPointer( XT_display, CurrentTime ); +#else XtUngrabPointer(wnd_p->winWidget, CurrentTime); +#endif captureWnd = 0; } +/********************************************************************** + * GetCapture (USER.236) + */ +HWND GetCapture() +{ + return captureWnd; +} + /********************************************************************** * SetDoubleClickTime (USER.20) */ diff --git a/windows/focus.c b/windows/focus.c index ce1a91a25ff..639b2dfd85a 100644 --- a/windows/focus.c +++ b/windows/focus.c @@ -32,7 +32,7 @@ HWND SetFocus(HWND hwnd) else { wndPtr = WIN_FindWndPtr(hwnd); - XSetInputFocus(XT_display, XtWindow(wndPtr->winWidget), + XSetInputFocus(XT_display, wndPtr->window, RevertToParent, CurrentTime); } diff --git a/windows/graphics.c b/windows/graphics.c index a2a1e3254d6..9fd5d27a55f 100644 --- a/windows/graphics.c +++ b/windows/graphics.c @@ -23,8 +23,10 @@ BOOL LineTo( HDC hdc, short x, short y ) if (!dc) return FALSE; if (DC_SetupGCForPen( dc )) XDrawLine(XT_display, dc->u.x.drawable, dc->u.x.gc, - XLPTODP( dc, dc->w.CursPosX ), YLPTODP( dc, dc->w.CursPosY ), - XLPTODP( dc, x ), YLPTODP( dc, y ) ); + dc->w.DCOrgX + XLPTODP( dc, dc->w.CursPosX ), + dc->w.DCOrgY + YLPTODP( dc, dc->w.CursPosY ), + dc->w.DCOrgX + XLPTODP( dc, x ), + dc->w.DCOrgY + YLPTODP( dc, y ) ); dc->w.CursPosX = x; dc->w.CursPosY = y; return TRUE; @@ -97,20 +99,21 @@ BOOL GRAPH_DrawArc( HDC hdc, int left, int top, int right, int bottom, if (diff_angle < 0.0) diff_angle += 2*PI; XDrawArc( XT_display, dc->u.x.drawable, dc->u.x.gc, - left, top, right-left-1, bottom-top-1, + dc->w.DCOrgX + left, dc->w.DCOrgY + top, + right-left-1, bottom-top-1, (int)(start_angle * 180 * 64 / PI), (int)(diff_angle * 180 * 64 / PI) ); if (!lines) return TRUE; - points[0].x = xcenter + (int)(cos(start_angle) * (right-left) / 2); - points[0].y = ycenter - (int)(sin(start_angle) * (bottom-top) / 2); - points[1].x = xcenter + (int)(cos(end_angle) * (right-left) / 2); - points[1].y = ycenter - (int)(sin(end_angle) * (bottom-top) / 2); + points[0].x = dc->w.DCOrgX + xcenter + (int)(cos(start_angle) * (right-left) / 2); + points[0].y = dc->w.DCOrgY + ycenter - (int)(sin(start_angle) * (bottom-top) / 2); + points[1].x = dc->w.DCOrgX + xcenter + (int)(cos(end_angle) * (right-left) / 2); + points[1].y = dc->w.DCOrgY + ycenter - (int)(sin(end_angle) * (bottom-top) / 2); if (lines == 2) { points[2] = points[1]; - points[1].x = xcenter; - points[1].y = ycenter; + points[1].x = dc->w.DCOrgX + xcenter; + points[1].y = dc->w.DCOrgY + ycenter; } XDrawLines( XT_display, dc->u.x.drawable, dc->u.x.gc, points, lines+1, CoordModeOrigin ); @@ -167,10 +170,12 @@ BOOL Ellipse( HDC hdc, int left, int top, int right, int bottom ) if (DC_SetupGCForBrush( dc )) XFillArc( XT_display, dc->u.x.drawable, dc->u.x.gc, - left, top, right-left-1, bottom-top-1, 0, 360*64 ); + dc->w.DCOrgX + left, dc->w.DCOrgY + top, + right-left-1, bottom-top-1, 0, 360*64 ); if (DC_SetupGCForPen( dc )) XDrawArc( XT_display, dc->u.x.drawable, dc->u.x.gc, - left, top, right-left-1, bottom-top-1, 0, 360*64 ); + dc->w.DCOrgX + left, dc->w.DCOrgY + top, + right-left-1, bottom-top-1, 0, 360*64 ); return TRUE; } @@ -190,10 +195,12 @@ BOOL Rectangle( HDC hdc, int left, int top, int right, int bottom ) if (DC_SetupGCForBrush( dc )) XFillRectangle( XT_display, dc->u.x.drawable, dc->u.x.gc, - left, top, right-left-1, bottom-top-1 ); + dc->w.DCOrgX + left, dc->w.DCOrgY + top, + right-left-1, bottom-top-1 ); if (DC_SetupGCForPen( dc )) XDrawRectangle( XT_display, dc->u.x.drawable, dc->u.x.gc, - left, top, right-left-1, bottom-top-1 ); + dc->w.DCOrgX + left, dc->w.DCOrgY + top, + right-left-1, bottom-top-1 ); return TRUE; } @@ -244,10 +251,16 @@ int FrameRect( HDC hdc, LPRECT rect, HBRUSH hbrush ) right = XLPTODP( dc, rect->right ); bottom = YLPTODP( dc, rect->bottom ); - if (DC_SetupGCForBrush( dc )) - XDrawRectangle( XT_display, dc->u.x.drawable, dc->u.x.gc, - left, top, right-left-1, bottom-top-1 ); - + if (DC_SetupGCForBrush( dc )) { + PatBlt( hdc, rect->left, rect->top, 1, + rect->bottom - rect->top, PATCOPY ); + PatBlt( hdc, rect->right - 1, rect->top, 1, + rect->bottom - rect->top, PATCOPY ); + PatBlt( hdc, rect->left, rect->top, + rect->right - rect->left, 1, PATCOPY ); + PatBlt( hdc, rect->left, rect->bottom - 1, + rect->right - rect->left, 1, PATCOPY ); + } SelectObject( hdc, prevBrush ); return 1; } @@ -264,8 +277,8 @@ COLORREF SetPixel( HDC hdc, short x, short y, COLORREF color ) DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); if (!dc) return 0; - x = XLPTODP( dc, x ); - y = YLPTODP( dc, y ); + x = dc->w.DCOrgX + XLPTODP( dc, x ); + y = dc->w.DCOrgY + YLPTODP( dc, y ); pixel = GetNearestPaletteIndex( dc->w.hPalette, color ); GetPaletteEntries( dc->w.hPalette, pixel, 1, &entry ); @@ -288,15 +301,14 @@ COLORREF GetPixel( HDC hdc, short x, short y ) DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); if (!dc) return 0; - x = XLPTODP( dc, x ); - y = YLPTODP( dc, y ); + x = dc->w.DCOrgX + XLPTODP( dc, x ); + y = dc->w.DCOrgY + YLPTODP( dc, y ); if ((x < 0) || (y < 0)) return 0; - if (dc->u.x.widget) + if (!(dc->w.flags & DC_MEMORY)) { XWindowAttributes win_attr; - if (!XtIsRealized(dc->u.x.widget)) return 0; if (!XGetWindowAttributes( XT_display, dc->u.x.drawable, &win_attr )) return 0; if (win_attr.map_state != IsViewable) return 0; @@ -342,7 +354,7 @@ BOOL PaintRgn( HDC hdc, HRGN hrgn ) GetClipBox( hdc, &box ); if (DC_SetupGCForBrush( dc )) XFillRectangle( XT_display, dc->u.x.drawable, dc->u.x.gc, - box.left, box.top, + dc->w.DCOrgX + box.left, dc->w.DCOrgY + box.top, box.right-box.left, box.bottom-box.top ); /* Restore the visible region */ @@ -385,15 +397,16 @@ void DrawFocusRect( HDC hdc, LPRECT rc ) hPen = CreatePen(PS_DOT, 1, GetSysColor(COLOR_WINDOWTEXT)); hOldPen = (HPEN)SelectObject(hdc, (HANDLE)hPen); -/* oldDrawMode = SetROP2(hdc, R2_XORPEN); */ + oldDrawMode = SetROP2(hdc, R2_XORPEN); oldBkMode = SetBkMode(hdc, TRANSPARENT); if (DC_SetupGCForPen( dc )) XDrawRectangle( XT_display, dc->u.x.drawable, dc->u.x.gc, - left, top, right-left-1, bottom-top-1 ); + dc->w.DCOrgX + left, dc->w.DCOrgY + top, + right-left-1, bottom-top-1 ); SetBkMode(hdc, oldBkMode); -/* SetROP2(hdc, oldDrawMode); */ + SetROP2(hdc, oldDrawMode); SelectObject(hdc, (HANDLE)hOldPen); DeleteObject((HANDLE)hPen); } @@ -441,3 +454,64 @@ while(ThickNess > 0) { SelectObject(hDC, hOldPen); DeleteObject(hDKGRAYPen); } + +/********************************************************************** + * Polyline (GDI.37) + */ +BOOL Polyline (HDC hdc, LPPOINT pt, int count) +{ + register int i; + DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); + + if (DC_SetupGCForPen( dc )) + { + for (i = 0; i < count-1; i ++) + XDrawLine (XT_display, dc->u.x.drawable, dc->u.x.gc, + dc->w.DCOrgX + XLPTODP(dc, pt [i].x), + dc->w.DCOrgY + YLPTODP(dc, pt [i].y), + dc->w.DCOrgX + XLPTODP(dc, pt [i+1].x), + dc->w.DCOrgY + YLPTODP(dc, pt [i+1].y)); + XDrawLine (XT_display, dc->u.x.drawable, dc->u.x.gc, + dc->w.DCOrgX + XLPTODP(dc, pt [count-1].x), + dc->w.DCOrgY + YLPTODP(dc, pt [count-1].y), + dc->w.DCOrgX + XLPTODP(dc, pt [0].x), + dc->w.DCOrgY + YLPTODP(dc, pt [0].y)); + } + + return (TRUE); +} + + +/********************************************************************** + * Polygon (GDI.36) + */ +BOOL Polygon (HDC hdc, LPPOINT pt, int count) +{ + register int i; + DC * dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ); + XPoint *points = (XPoint *) malloc (sizeof (XPoint) * count+1); + + if (DC_SetupGCForBrush( dc )) + { + + for (i = 0; i < count; i++) + { + points [i].x = dc->w.DCOrgX + XLPTODP(dc, pt [i].x); + points [i].y = dc->w.DCOrgY + YLPTODP(dc, pt [i].y); + } + points [count] = points [0]; + + XFillPolygon( XT_display, dc->u.x.drawable, dc->u.x.gc, + points, count, Complex, CoordModeOrigin); + + if (DC_SetupGCForPen ( dc )) + { + XDrawLines( XT_display, dc->u.x.drawable, dc->u.x.gc, + points, count, CoordModeOrigin ); + } + } + free ((void *) points); + return (TRUE); +} + + diff --git a/windows/message.c b/windows/message.c index 7307461d99d..09b49e7861c 100644 --- a/windows/message.c +++ b/windows/message.c @@ -12,10 +12,8 @@ static char Copyright[] = "Copyright Alexandre Julliard, 1993"; #include - -#ifdef __NetBSD__ -#define HZ 100 -#endif +#include +#include #include "message.h" #include "win.h" @@ -23,30 +21,72 @@ static char Copyright[] = "Copyright Alexandre Julliard, 1993"; #define MAX_QUEUE_SIZE 120 /* Max. size of a message queue */ -extern HWND WIN_FindWinToRepaint( HWND hwnd ); +extern BOOL TIMER_CheckTimer( DWORD *next ); /* timer.c */ extern Display * XT_display; extern Screen * XT_screen; extern XtAppContext XT_app_context; -static MESSAGEQUEUE * msgQueue = NULL; + /* System message queue (for hardware events) */ +static HANDLE hmemSysMsgQueue = 0; +static MESSAGEQUEUE * sysMsgQueue = NULL; + + /* Application message queue (should be a list, one queue per task) */ +static HANDLE hmemAppMsgQueue = 0; +static MESSAGEQUEUE * appMsgQueue = NULL; + +/*********************************************************************** + * MSG_CreateMsgQueue + * + * Create a message queue. + */ +static HANDLE MSG_CreateMsgQueue( int size ) +{ + HANDLE hQueue; + MESSAGEQUEUE * msgQueue; + int queueSize; + + queueSize = sizeof(MESSAGEQUEUE) + size * sizeof(QMSG); + if (!(hQueue = GlobalAlloc( GMEM_FIXED, queueSize ))) return 0; + msgQueue = (MESSAGEQUEUE *) GlobalLock( hQueue ); + msgQueue->next = 0; + msgQueue->hTask = 0; + msgQueue->msgSize = sizeof(QMSG); + msgQueue->msgCount = 0; + msgQueue->nextMessage = 0; + msgQueue->nextFreeMessage = 0; + msgQueue->queueSize = size; + msgQueue->GetMessageTimeVal = 0; + msgQueue->GetMessagePosVal = 0; + msgQueue->GetMessageExtraInfoVal = 0; + msgQueue->lParam = 0; + msgQueue->wParam = 0; + msgQueue->msg = 0; + msgQueue->hWnd = 0; + msgQueue->wPostQMsg = 0; + msgQueue->wExitCode = 0; + msgQueue->InSendMessageHandle = 0; + msgQueue->wPaintCount = 0; + msgQueue->wTimerCount = 0; + msgQueue->tempStatus = 0; + msgQueue->status = 0; + GlobalUnlock( hQueue ); + return hQueue; +} /*********************************************************************** - * MSG_GetMessageType + * MSG_CreateSysMsgQueue * + * Create the system message queue. Must be called only once. */ -int MSG_GetMessageType( int msg ) +BOOL MSG_CreateSysMsgQueue( int size ) { - if ((msg >= WM_KEYFIRST) && (msg <= WM_KEYLAST)) return QS_KEY; - else if ((msg >= WM_MOUSEFIRST) && (msg <= WM_MOUSELAST)) - { - if (msg == WM_MOUSEMOVE) return QS_MOUSEMOVE; - else return QS_MOUSEBUTTON; - } - else if (msg == WM_PAINT) return QS_PAINT; - else if (msg == WM_TIMER) return QS_TIMER; - return QS_POSTMESSAGE; + if (size > MAX_QUEUE_SIZE) size = MAX_QUEUE_SIZE; + else if (size <= 0) size = 1; + if (!(hmemSysMsgQueue = MSG_CreateMsgQueue( size ))) return FALSE; + sysMsgQueue = (MESSAGEQUEUE *) GlobalLock( hmemSysMsgQueue ); + return TRUE; } @@ -55,16 +95,13 @@ int MSG_GetMessageType( int msg ) * * Add a message to the queue. Return FALSE if queue is full. */ -int MSG_AddMsg( MSG * msg, DWORD extraInfo ) +static int MSG_AddMsg( MESSAGEQUEUE * msgQueue, MSG * msg, DWORD extraInfo ) { - int pos, type; + int pos; if (!msgQueue) return FALSE; pos = msgQueue->nextFreeMessage; - /* No need to store WM_PAINT messages */ - if (msg->message == WM_PAINT) return TRUE; - /* Check if queue is full */ if ((pos == msgQueue->nextMessage) && (msgQueue->msgCount > 0)) return FALSE; @@ -72,17 +109,12 @@ int MSG_AddMsg( MSG * msg, DWORD extraInfo ) /* Store message */ msgQueue->messages[pos].msg = *msg; msgQueue->messages[pos].extraInfo = extraInfo; - - /* Store message type */ - type = MSG_GetMessageType( msg->message ); - msgQueue->status |= type; - msgQueue->tempStatus |= type; - if (pos < msgQueue->queueSize-1) pos++; else pos = 0; msgQueue->nextFreeMessage = pos; msgQueue->msgCount++; - + msgQueue->status |= QS_POSTMESSAGE; + msgQueue->tempStatus |= QS_POSTMESSAGE; return TRUE; } @@ -92,7 +124,7 @@ int MSG_AddMsg( MSG * msg, DWORD extraInfo ) * * Find a message matching the given parameters. Return -1 if none available. */ -int MSG_FindMsg( HWND hwnd, int first, int last ) +static int MSG_FindMsg(MESSAGEQUEUE * msgQueue, HWND hwnd, int first, int last) { int i, pos = msgQueue->nextMessage; @@ -120,9 +152,8 @@ int MSG_FindMsg( HWND hwnd, int first, int last ) * * Remove a message from the queue (pos must be a valid position). */ -void MSG_RemoveMsg( int pos ) +static void MSG_RemoveMsg( MESSAGEQUEUE * msgQueue, int pos ) { - int i, type; QMSG * qmsg; if (!msgQueue) return; @@ -147,56 +178,118 @@ void MSG_RemoveMsg( int pos ) else msgQueue->nextFreeMessage = msgQueue->queueSize-1; } msgQueue->msgCount--; - - /* Recalc status */ - type = 0; - pos = msgQueue->nextMessage; - for (i = 0; i < msgQueue->msgCount; i++) - { - type |= MSG_GetMessageType( msgQueue->messages[pos].msg.message ); - if (++pos >= msgQueue->queueSize-1) pos = 0; - } - msgQueue->status = (msgQueue->status & QS_SENDMESSAGE) | type; + if (!msgQueue->msgCount) msgQueue->status &= ~QS_POSTMESSAGE; msgQueue->tempStatus = 0; } +/*********************************************************************** + * MSG_IncPaintCount + */ +void MSG_IncPaintCount( HANDLE hQueue ) +{ + if (hQueue != hmemAppMsgQueue) return; + appMsgQueue->wPaintCount++; + appMsgQueue->status |= QS_PAINT; + appMsgQueue->tempStatus |= QS_PAINT; +} + + +/*********************************************************************** + * MSG_DecPaintCount + */ +void MSG_DecPaintCount( HANDLE hQueue ) +{ + if (hQueue != hmemAppMsgQueue) return; + appMsgQueue->wPaintCount--; + if (!appMsgQueue->wPaintCount) appMsgQueue->status &= ~QS_PAINT; +} + + +/*********************************************************************** + * MSG_IncTimerCount + */ +void MSG_IncTimerCount( HANDLE hQueue ) +{ + if (hQueue != hmemAppMsgQueue) return; + appMsgQueue->wTimerCount++; + appMsgQueue->status |= QS_TIMER; + appMsgQueue->tempStatus |= QS_TIMER; +} + + +/*********************************************************************** + * MSG_DecTimerCount + */ +void MSG_DecTimerCount( HANDLE hQueue ) +{ + if (hQueue != hmemAppMsgQueue) return; + appMsgQueue->wTimerCount--; + if (!appMsgQueue->wTimerCount) appMsgQueue->status &= ~QS_TIMER; +} + + +/*********************************************************************** + * hardware_event + * + * Add an event to the system message queue. + */ +void hardware_event( HWND hwnd, WORD message, WORD wParam, LONG lParam, + WORD xPos, WORD yPos, DWORD time, DWORD extraInfo ) +{ + MSG msg; + + msg.hwnd = hwnd; + msg.message = message; + msg.wParam = wParam; + msg.lParam = lParam; + msg.time = time; + msg.pt.x = xPos; + msg.pt.y = yPos; + if (!MSG_AddMsg( sysMsgQueue, &msg, extraInfo )) + printf( "hardware_event: Queue is full\n" ); +} + + +/*********************************************************************** + * SetTaskQueue (KERNEL.34) + */ +WORD SetTaskQueue( HANDLE hTask, HANDLE hQueue ) +{ + HANDLE prev = hmemAppMsgQueue; + hmemAppMsgQueue = hQueue; + return prev; +} + + +/*********************************************************************** + * GetTaskQueue (KERNEL.35) + */ +WORD GetTaskQueue( HANDLE hTask ) +{ + return hmemAppMsgQueue; +} + + /*********************************************************************** * SetMessageQueue (USER.266) */ BOOL SetMessageQueue( int size ) { - int queueSize; - + HANDLE hQueue; + + if ((size > MAX_QUEUE_SIZE) || (size <= 0)) return TRUE; + /* Free the old message queue */ - if (msgQueue) free(msgQueue); + if ((hQueue = GetTaskQueue(0)) != 0) + { + GlobalUnlock( hQueue ); + GlobalFree( hQueue ); + } - if ((size > MAX_QUEUE_SIZE) || (size <= 0)) return FALSE; - - queueSize = sizeof(MESSAGEQUEUE) + size * sizeof(QMSG); - msgQueue = (MESSAGEQUEUE *) malloc(queueSize); - if (!msgQueue) return FALSE; - - msgQueue->next = 0; - msgQueue->hTask = 0; - msgQueue->msgSize = sizeof(QMSG); - msgQueue->msgCount = 0; - msgQueue->nextMessage = 0; - msgQueue->nextFreeMessage = 0; - msgQueue->queueSize = size; - msgQueue->GetMessageTimeVal = 0; - msgQueue->GetMessagePosVal = 0; - msgQueue->GetMessageExtraInfoVal = 0; - msgQueue->lParam = 0; - msgQueue->wParam = 0; - msgQueue->msg = 0; - msgQueue->hWnd = 0; - msgQueue->wPostQMsg = 0; - msgQueue->wExitCode = 0; - msgQueue->InSendMessageHandle = 0; - msgQueue->tempStatus = 0; - msgQueue->status = 0; - + if (!(hQueue = MSG_CreateMsgQueue( size ))) return FALSE; + SetTaskQueue( 0, hQueue ); + appMsgQueue = (MESSAGEQUEUE *)GlobalLock( hQueue ); return TRUE; } @@ -206,9 +299,9 @@ BOOL SetMessageQueue( int size ) */ void PostQuitMessage( int exitCode ) { - if (!msgQueue) return; - msgQueue->wPostQMsg = TRUE; - msgQueue->wExitCode = exitCode; + if (!appMsgQueue) return; + appMsgQueue->wPostQMsg = TRUE; + appMsgQueue->wExitCode = exitCode; } @@ -217,12 +310,8 @@ void PostQuitMessage( int exitCode ) */ DWORD GetQueueStatus( int flags ) { - unsigned long ret = (msgQueue->status << 16) | msgQueue->tempStatus; - if (flags & QS_PAINT) - { - if (WIN_FindWinToRepaint(0)) ret |= QS_PAINT | (QS_PAINT << 16); - } - msgQueue->tempStatus = 0; + unsigned long ret = (appMsgQueue->status << 16) | appMsgQueue->tempStatus; + appMsgQueue->tempStatus = 0; return ret & ((flags << 16) | flags); } @@ -232,70 +321,169 @@ DWORD GetQueueStatus( int flags ) */ BOOL GetInputState() { - return msgQueue->status & (QS_KEY | QS_MOUSEBUTTON); + return appMsgQueue->status & (QS_KEY | QS_MOUSEBUTTON); } +#ifndef USE_XLIB +static XtIntervalId xt_timer = 0; + +/*********************************************************************** + * MSG_TimerCallback + */ +static void MSG_TimerCallback( XtPointer data, XtIntervalId * xtid ) +{ + DWORD nextExp; + TIMER_CheckTimer( &nextExp ); + if (nextExp != (DWORD)-1) + xt_timer = XtAppAddTimeOut( XT_app_context, nextExp, + MSG_TimerCallback, NULL ); + else xt_timer = 0; +} +#endif /* USE_XLIB */ + + /*********************************************************************** * MSG_PeekMessage */ -BOOL MSG_PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last, WORD flags ) +static BOOL MSG_PeekMessage( MESSAGEQUEUE * msgQueue, LPMSG msg, HWND hwnd, + WORD first, WORD last, WORD flags, BOOL peek ) { - int pos; + int pos, mask; + DWORD nextExp; /* Next timer expiration time */ +#ifdef USE_XLIB + XEvent event; +#endif - /* First handle a WM_QUIT message */ - if (msgQueue->wPostQMsg) + if (first || last) { - msg->hwnd = hwnd; - msg->message = WM_QUIT; - msg->wParam = msgQueue->wExitCode; - msg->lParam = 0; - return TRUE; + mask = QS_POSTMESSAGE; /* Always selectioned */ + if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY; + if ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) mask |= QS_MOUSE; + if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= WM_TIMER; + if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= WM_TIMER; + if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= WM_PAINT; } + else mask = QS_MOUSE | QS_KEY | QS_POSTMESSAGE | QS_TIMER | QS_PAINT; - /* Then handle a message put by SendMessage() */ - if (msgQueue->status & QS_SENDMESSAGE) +#ifdef USE_XLIB + while (XPending( XT_display )) { - if (!hwnd || (msgQueue->hWnd == hwnd)) + XNextEvent( XT_display, &event ); + EVENT_ProcessEvent( &event ); + } +#else + while (XtAppPending( XT_app_context )) + XtAppProcessEvent( XT_app_context, XtIMAll ); +#endif + + while(1) + { + /* First handle a WM_QUIT message */ + if (msgQueue->wPostQMsg) { - if ((!first && !last) || - ((msgQueue->msg >= first) && (msgQueue->msg <= last))) + msg->hwnd = hwnd; + msg->message = WM_QUIT; + msg->wParam = msgQueue->wExitCode; + msg->lParam = 0; + break; + } + + /* Then handle a message put by SendMessage() */ + if (msgQueue->status & QS_SENDMESSAGE) + { + if (!hwnd || (msgQueue->hWnd == hwnd)) { - msg->hwnd = msgQueue->hWnd; - msg->message = msgQueue->msg; - msg->wParam = msgQueue->wParam; - msg->lParam = msgQueue->lParam; - if (flags & PM_REMOVE) msgQueue->status &= ~QS_SENDMESSAGE; - return TRUE; + if ((!first && !last) || + ((msgQueue->msg >= first) && (msgQueue->msg <= last))) + { + msg->hwnd = msgQueue->hWnd; + msg->message = msgQueue->msg; + msg->wParam = msgQueue->wParam; + msg->lParam = msgQueue->lParam; + if (flags & PM_REMOVE) msgQueue->status &= ~QS_SENDMESSAGE; + break; + } } } - - } - /* Now find a normal message */ - pos = MSG_FindMsg( hwnd, first, last ); - if (pos != -1) - { - QMSG *qmsg = &msgQueue->messages[pos]; - *msg = qmsg->msg; - msgQueue->GetMessageTimeVal = msg->time; - msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt; - msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo; + /* Now find a normal message */ + pos = MSG_FindMsg( msgQueue, hwnd, first, last ); + if (pos != -1) + { + QMSG *qmsg = &msgQueue->messages[pos]; + *msg = qmsg->msg; + msgQueue->GetMessageTimeVal = msg->time; + msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt; + msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo; - if (flags & PM_REMOVE) MSG_RemoveMsg(pos); - return TRUE; + if (flags & PM_REMOVE) MSG_RemoveMsg( msgQueue, pos ); + break; + } + + /* Now find a hardware event */ + pos = MSG_FindMsg( sysMsgQueue, hwnd, first, last ); + if (pos != -1) + { + QMSG *qmsg = &sysMsgQueue->messages[pos]; + *msg = qmsg->msg; + msgQueue->GetMessageTimeVal = msg->time; + msgQueue->GetMessagePosVal = *(DWORD *)&msg->pt; + msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo; + + if (flags & PM_REMOVE) MSG_RemoveMsg( sysMsgQueue, pos ); + break; + } + + /* Now find a WM_PAINT message */ + if ((msgQueue->status & QS_PAINT) && (mask & QS_PAINT)) + { + msg->hwnd = WIN_FindWinToRepaint( hwnd ); + msg->message = WM_PAINT; + msg->wParam = 0; + msg->lParam = 0; + if (msg->hwnd != 0) break; + } + + /* Finally handle WM_TIMER messages */ + if ((msgQueue->status & QS_TIMER) && (mask & QS_TIMER)) + { + BOOL posted = TIMER_CheckTimer( &nextExp ); +#ifndef USE_XLIB + if (xt_timer) XtRemoveTimeOut( xt_timer ); + if (nextExp != (DWORD)-1) + xt_timer = XtAppAddTimeOut( XT_app_context, nextExp, + MSG_TimerCallback, NULL ); + else xt_timer = 0; +#endif + if (posted) continue; /* Restart the whole thing */ + } + + /* Wait until something happens */ + if (peek) return FALSE; +#ifdef USE_XLIB + if (!XPending( XT_display ) && (nextExp != -1)) + { + fd_set read_set; + struct timeval timeout; + int fd = ConnectionNumber(XT_display); + FD_ZERO( &read_set ); + FD_SET( fd, &read_set ); + timeout.tv_sec = nextExp / 1000; + timeout.tv_usec = (nextExp % 1000) * 1000; + if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1) + continue; /* On timeout or error, restart from the start */ + } + XNextEvent( XT_display, &event ); + EVENT_ProcessEvent( &event ); +#else + XtAppProcessEvent( XT_app_context, XtIMAll ); +#endif } - /* If nothing else, return a WM_PAINT message */ - if ((!first && !last) || ((first <= WM_PAINT) && (last >= WM_PAINT))) - { - msg->hwnd = WIN_FindWinToRepaint( hwnd ); - msg->message = WM_PAINT; - msg->wParam = 0; - msg->lParam = 0; - return (msg->hwnd != 0); - } - return FALSE; + /* We got a message */ + if (peek) return TRUE; + else return (msg->message != WM_QUIT); } @@ -304,10 +492,7 @@ BOOL MSG_PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last, WORD flags ) */ BOOL PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last, WORD flags ) { - while (XtAppPending( XT_app_context )) - XtAppProcessEvent( XT_app_context, XtIMAll ); - - return MSG_PeekMessage( msg, hwnd, first, last, flags ); + return MSG_PeekMessage( appMsgQueue, msg, hwnd, first, last, flags, TRUE ); } @@ -316,13 +501,7 @@ BOOL PeekMessage( LPMSG msg, HWND hwnd, WORD first, WORD last, WORD flags ) */ BOOL GetMessage( LPMSG msg, HWND hwnd, WORD first, WORD last ) { - while(1) - { - if (MSG_PeekMessage( msg, hwnd, first, last, PM_REMOVE )) break; - XtAppProcessEvent( XT_app_context, XtIMAll ); - } - - return (msg->message != WM_QUIT); + return MSG_PeekMessage( appMsgQueue, msg, hwnd, first, last, PM_REMOVE, FALSE ); } @@ -341,7 +520,7 @@ BOOL PostMessage( HWND hwnd, WORD message, WORD wParam, LONG lParam ) msg.pt.x = 0; msg.pt.y = 0; - return MSG_AddMsg( &msg, 0 ); + return MSG_AddMsg( appMsgQueue, &msg, 0 ); } @@ -380,16 +559,39 @@ BOOL TranslateMessage( LPMSG msg ) */ LONG DispatchMessage( LPMSG msg ) { - WND * wndPtr = WIN_FindWndPtr( msg->hwnd ); - + WND * wndPtr; + LONG retval; + int painting; + #ifdef DEBUG_MSG printf( "Dispatch message hwnd=%08x msg=%d w=%d l=%d time=%u pt=%d,%d\n", msg->hwnd, msg->message, msg->wParam, msg->lParam, msg->time, msg->pt.x, msg->pt.y ); #endif - if (!wndPtr) return 0; - return CallWindowProc( wndPtr->lpfnWndProc, msg->hwnd, msg->message, - msg->wParam, msg->lParam ); + + /* Process timer messages */ + if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER)) + { + if (msg->lParam) + return CallWindowProc( (FARPROC)msg->lParam, msg->hwnd, + msg->message, msg->wParam, GetTickCount() ); + } + + if (!msg->hwnd) return 0; + if (!(wndPtr = WIN_FindWndPtr( msg->hwnd ))) return 0; + if (!wndPtr->lpfnWndProc) return 0; + painting = (msg->message == WM_PAINT); + if (painting) wndPtr->flags |= WIN_NEEDS_BEGINPAINT; + retval = CallWindowProc( wndPtr->lpfnWndProc, msg->hwnd, msg->message, + msg->wParam, msg->lParam ); + if (painting && (wndPtr->flags & WIN_NEEDS_BEGINPAINT)) + { +#ifdef DEBUG_WIN + printf( "BeginPaint not called on WM_PAINT!\n" ); +#endif + wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT; + } + return retval; } @@ -398,7 +600,7 @@ LONG DispatchMessage( LPMSG msg ) */ DWORD GetMessagePos(void) { - return msgQueue->GetMessagePosVal; + return appMsgQueue->GetMessagePosVal; } @@ -407,14 +609,27 @@ DWORD GetMessagePos(void) */ LONG GetMessageTime(void) { - return msgQueue->GetMessageTimeVal; + return appMsgQueue->GetMessageTimeVal; } + /*********************************************************************** * GetMessageExtraInfo (USER.288) */ LONG GetMessageExtraInfo(void) { - return msgQueue->GetMessageExtraInfoVal; + return appMsgQueue->GetMessageExtraInfoVal; +} + + +/*********************************************************************** + * RegisterWindowMessage (USER.118) + */ +WORD RegisterWindowMessage( LPCSTR str ) +{ +#ifdef DEBUG_MSG + printf( "RegisterWindowMessage: '%s'\n", str ); +#endif + return GlobalAddAtom( str ); } diff --git a/windows/painting.c b/windows/painting.c index 4f21b13b0a5..5a8e60a0e11 100644 --- a/windows/painting.c +++ b/windows/painting.c @@ -10,6 +10,7 @@ static char Copyright[] = "Copyright Alexandre Julliard, 1993"; #include #include "win.h" +#include "message.h" /* Last CTLCOLOR id */ #define CTLCOLOR_MAX CTLCOLOR_STATIC @@ -23,27 +24,21 @@ HDC BeginPaint( HWND hwnd, LPPAINTSTRUCT lps ) WND * wndPtr = WIN_FindWndPtr( hwnd ); if (!wndPtr) return 0; - lps->hdc = GetDC( hwnd ); - if (!lps->hdc) return 0; - - SelectVisRgn( lps->hdc, wndPtr->hrgnUpdate ); + if (!(lps->hdc = GetDCEx( hwnd, wndPtr->hrgnUpdate, + DCX_INTERSECTRGN | DCX_USESTYLE ))) return 0; + GetRgnBox( InquireVisRgn(lps->hdc), &lps->rcPaint ); + if (wndPtr->hrgnUpdate) { - GetRgnBox( wndPtr->hrgnUpdate, &lps->rcPaint ); DeleteObject( wndPtr->hrgnUpdate ); wndPtr->hrgnUpdate = 0; + MSG_DecPaintCount( wndPtr->hmemTaskQ ); } - else - { - lps->rcPaint.left = 0; - lps->rcPaint.top = 0; - lps->rcPaint.right = wndPtr->rectClient.right-wndPtr->rectClient.left; - lps->rcPaint.bottom = wndPtr->rectClient.bottom-wndPtr->rectClient.top; - } - + wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT; + if (!(wndPtr->flags & WIN_ERASE_UPDATERGN)) lps->fErase = TRUE; else lps->fErase = !SendMessage( hwnd, WM_ERASEBKGND, lps->hdc, 0 ); - + return lps->hdc; } @@ -63,12 +58,7 @@ void EndPaint( HWND hwnd, LPPAINTSTRUCT lps ) void FillWindow( HWND hwndParent, HWND hwnd, HDC hdc, HBRUSH hbrush ) { RECT rect; - WND * wndPtr = WIN_FindWndPtr( hwnd ); - if (!wndPtr) return; - rect.left = 0; - rect.top = 0; - rect.right = wndPtr->rectClient.right - wndPtr->rectClient.left; - rect.bottom = wndPtr->rectClient.bottom - wndPtr->rectClient.top; + GetClientRect( hwnd, &rect ); PaintRect( hwndParent, hwnd, hdc, hbrush, &rect ); } diff --git a/windows/timer.c b/windows/timer.c index 2aeb88ee585..da649610fd2 100644 --- a/windows/timer.c +++ b/windows/timer.c @@ -6,21 +6,19 @@ static char Copyright[] = "Copyright Alexandre Julliard, 1993"; -#include - #include "windows.h" - -extern XtAppContext XT_app_context; +#include "message.h" -typedef struct +typedef struct tagTIMER { - HWND hwnd; - WORD msg; /* WM_TIMER or WM_SYSTIMER */ - WORD id; - WORD timeout; - FARPROC proc; - XtIntervalId xtid; + HWND hwnd; + WORD msg; /* WM_TIMER or WM_SYSTIMER */ + WORD id; + WORD timeout; + struct tagTIMER *next; + DWORD expires; + FARPROC proc; } TIMER; #define NB_TIMERS 34 @@ -28,39 +26,100 @@ typedef struct static TIMER TimersArray[NB_TIMERS]; +static TIMER * pNextTimer = NULL; /* Next timer to expire */ + /*********************************************************************** - * TIMER_callback + * TIMER_InsertTimer + * + * Insert the timer at its place in the chain. */ -static void TIMER_callback( XtPointer data, XtIntervalId * xtid ) +static void TIMER_InsertTimer( TIMER * pTimer ) { - TIMER * pTimer = (TIMER *) data; - - pTimer->xtid = 0; /* In case the timer procedure calls KillTimer */ - - if (pTimer->proc) + if (!pNextTimer || (pTimer->expires < pNextTimer->expires)) { - CallWindowProc(pTimer->proc, pTimer->hwnd, pTimer->msg, - pTimer->id, GetTickCount()); + pTimer->next = pNextTimer; + pNextTimer = pTimer; } - else - PostMessage( pTimer->hwnd, pTimer->msg, pTimer->id, 0 ); + else + { + TIMER * ptr = pNextTimer; + while (ptr->next && (pTimer->expires >= ptr->next->expires)) + ptr = ptr->next; + pTimer->next = ptr; + ptr->next = pTimer; + } +} + + +/*********************************************************************** + * TIMER_RemoveTimer + * + * Remove the timer from the chain. + */ +static void TIMER_RemoveTimer( TIMER * pTimer ) +{ + if (pTimer == pNextTimer) pNextTimer = pTimer->next; + else + { + TIMER * ptr = pNextTimer; + while (ptr && (ptr->next != pTimer)) ptr = ptr->next; + if (ptr) ptr->next = pTimer->next; + } + pTimer->next = NULL; +} + + +/*********************************************************************** + * TIMER_NextExpire + * + * Return time until next timer expiration (-1 if none). + */ +static DWORD TIMER_NextExpire( DWORD curTime ) +{ + if (!pNextTimer) return -1; + if (pNextTimer->expires <= curTime) return 0; + return pNextTimer->expires - curTime; +} + + +/*********************************************************************** + * TIMER_CheckTimer + * + * Check whether a timer has expired, and post a message if necessary. + * Return TRUE if msg posted, and return time until next expiration in 'next'. + */ +BOOL TIMER_CheckTimer( DWORD *next ) +{ + TIMER * pTimer = pNextTimer; + DWORD curTime = GetTickCount(); + + if ((*next = TIMER_NextExpire( curTime )) != 0) return FALSE; + + PostMessage( pTimer->hwnd, pTimer->msg, pTimer->id, (LONG)pTimer->proc ); + TIMER_RemoveTimer( pTimer ); /* If timeout == 0, the timer has been removed by KillTimer */ if (pTimer->timeout) - pTimer->xtid = XtAppAddTimeOut( XT_app_context, pTimer->timeout, - TIMER_callback, pTimer ); + { + /* Restart the timer */ + pTimer->expires = curTime + pTimer->timeout; + TIMER_InsertTimer( pTimer ); + } + *next = TIMER_NextExpire( curTime ); + return TRUE; } /*********************************************************************** * TIMER_SetTimer */ -WORD TIMER_SetTimer( HWND hwnd, WORD id, WORD timeout, FARPROC proc, BOOL sys ) +static WORD TIMER_SetTimer( HWND hwnd, WORD id, WORD timeout, + FARPROC proc, BOOL sys ) { int i; TIMER * pTimer; - + if (!timeout) return 0; if (!hwnd && !proc) return 0; @@ -79,9 +138,10 @@ WORD TIMER_SetTimer( HWND hwnd, WORD id, WORD timeout, FARPROC proc, BOOL sys ) pTimer->msg = sys ? WM_SYSTIMER : WM_TIMER; pTimer->id = id; pTimer->timeout = timeout; + pTimer->expires = GetTickCount() + timeout; pTimer->proc = proc; - pTimer->xtid = XtAppAddTimeOut( XT_app_context, timeout, - TIMER_callback, pTimer ); + TIMER_InsertTimer( pTimer ); + MSG_IncTimerCount( GetTaskQueue(0) ); return id; } @@ -89,7 +149,7 @@ WORD TIMER_SetTimer( HWND hwnd, WORD id, WORD timeout, FARPROC proc, BOOL sys ) /*********************************************************************** * TIMER_KillTimer */ -BOOL TIMER_KillTimer( HWND hwnd, WORD id, BOOL sys ) +static BOOL TIMER_KillTimer( HWND hwnd, WORD id, BOOL sys ) { int i; TIMER * pTimer; @@ -106,13 +166,13 @@ BOOL TIMER_KillTimer( HWND hwnd, WORD id, BOOL sys ) /* Delete the timer */ - if (pTimer->xtid) XtRemoveTimeOut( pTimer->xtid ); pTimer->hwnd = 0; pTimer->msg = 0; pTimer->id = 0; pTimer->timeout = 0; pTimer->proc = 0; - pTimer->xtid = 0; + TIMER_RemoveTimer( pTimer ); + MSG_DecTimerCount( GetTaskQueue(0) ); return TRUE; } @@ -123,7 +183,7 @@ BOOL TIMER_KillTimer( HWND hwnd, WORD id, BOOL sys ) WORD SetTimer( HWND hwnd, WORD id, WORD timeout, FARPROC proc ) { #ifdef DEBUG_TIMER - printf( "SetTimer: %d %d %d %08x\n", hwnd, id, timeout, proc ); + printf( "SetTimer: %d %d %d %p\n", hwnd, id, timeout, proc ); #endif return TIMER_SetTimer( hwnd, id, timeout, proc, FALSE ); } @@ -135,7 +195,7 @@ WORD SetTimer( HWND hwnd, WORD id, WORD timeout, FARPROC proc ) WORD SetSystemTimer( HWND hwnd, WORD id, WORD timeout, FARPROC proc ) { #ifdef DEBUG_TIMER - printf( "SetSystemTimer: %d %d %d %08x\n", hwnd, id, timeout, proc ); + printf( "SetSystemTimer: %d %d %d %p\n", hwnd, id, timeout, proc ); #endif return TIMER_SetTimer( hwnd, id, timeout, proc, TRUE ); } diff --git a/windows/win.c b/windows/win.c index d7fe3a2c88e..8411e489860 100644 --- a/windows/win.c +++ b/windows/win.c @@ -10,11 +10,11 @@ static char Copyright[] = "Copyright Alexandre Julliard, 1993"; #include #include #include -#include #include "class.h" #include "win.h" #include "user.h" +#include "dce.h" extern Display * XT_display; extern Screen * XT_screen; @@ -22,10 +22,6 @@ extern Colormap COLOR_WinColormap; static HWND firstWindow = 0; -void SCROLLBAR_CreateScrollBar(LPSTR className, LPSTR Label, HWND hwnd); -void LISTBOX_CreateListBox(LPSTR className, LPSTR Label, HWND hwnd); -void COMBOBOX_CreateComboBox(LPSTR className, LPSTR Label, HWND hwnd); - /*********************************************************************** * WIN_FindWndPtr * @@ -42,6 +38,76 @@ WND * WIN_FindWndPtr( HWND hwnd ) } +/*********************************************************************** + * WIN_UnlinkWindow + * + * Remove a window from the siblings linked list. + */ +BOOL WIN_UnlinkWindow( HWND hwnd ) +{ + HWND * curWndPtr; + WND * wndPtr = WIN_FindWndPtr( hwnd ); + + if (!wndPtr) return FALSE; + if (wndPtr->hwndParent) + { + WND * parentPtr = WIN_FindWndPtr( wndPtr->hwndParent ); + curWndPtr = &parentPtr->hwndChild; + } + else curWndPtr = &firstWindow; + + 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 = WIN_FindWndPtr( hwnd ); + if (!wndPtr) return FALSE; + + if ((hwndInsertAfter == HWND_TOP) || (hwndInsertAfter == HWND_BOTTOM)) + { + /* Make hwndPtr point to the first sibling hwnd */ + if (wndPtr->hwndParent) + { + WND * parentPtr = WIN_FindWndPtr( wndPtr->hwndParent ); + if (parentPtr) hwndPtr = &parentPtr->hwndChild; + } + else hwndPtr = &firstWindow; + 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 * @@ -55,8 +121,6 @@ HWND WIN_FindWinToRepaint( HWND hwnd ) for ( ; hwnd != 0; hwnd = wndPtr->hwndNext ) { if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0; - if (!wndPtr || !wndPtr->winWidget) continue; - if (!XtIsRealized( wndPtr->winWidget )) continue; if (wndPtr->hrgnUpdate) return hwnd; if (wndPtr->hwndChild) { @@ -114,9 +178,11 @@ HWND CreateWindowEx( DWORD exStyle, LPSTR className, LPSTR windowName, CREATESTRUCT *createStruct; HANDLE hcreateStruct; int wmcreate; + short newwidth, newheight; #ifdef DEBUG_WIN - printf( "CreateWindowEx: %s %s %d,%d %dx%d\n", className, windowName, x, y, width, height ); + printf( "CreateWindowEx: %s %s %d,%d %dx%d %08x\n", + className, windowName, x, y, width, height, style ); #endif if (x == CW_USEDEFAULT) x = 0; @@ -155,11 +221,12 @@ HWND CreateWindowEx( DWORD exStyle, LPSTR className, LPSTR windowName, wndPtr->hwndOwner = parent; /* What else? */ wndPtr->hClass = class; wndPtr->hInstance = instance; - wndPtr->rectClient.left = x; - wndPtr->rectClient.top = y; - wndPtr->rectClient.right = x + width; - wndPtr->rectClient.bottom = y + height; - wndPtr->rectWindow = wndPtr->rectClient; + wndPtr->rectWindow.left = x; + wndPtr->rectWindow.top = y; + wndPtr->rectWindow.right = x + width; + wndPtr->rectWindow.bottom = y + height; + wndPtr->rectClient = wndPtr->rectWindow; + wndPtr->hmemTaskQ = GetTaskQueue(0); wndPtr->hrgnUpdate = 0; wndPtr->hwndLastActive = 0; wndPtr->lpfnWndProc = classPtr->wc.lpfnWndProc; @@ -169,43 +236,70 @@ HWND CreateWindowEx( DWORD exStyle, LPSTR className, LPSTR windowName, wndPtr->wIDmenu = menu; wndPtr->hText = 0; wndPtr->flags = 0; + wndPtr->hCursor = 0; + wndPtr->hWndVScroll = 0; + wndPtr->hWndHScroll = 0; if (classPtr->wc.cbWndExtra) memset( wndPtr->wExtra, 0, classPtr->wc.cbWndExtra ); - if (classPtr->wc.style & CS_OWNDC) - wndPtr->hdc = CreateDC( "DISPLAY", NULL, NULL, NULL); - else wndPtr->hdc = 0; classPtr->cWindows++; + /* Get class or window DC if needed */ + if (classPtr->wc.style & CS_OWNDC) + { + wndPtr->flags |= WIN_OWN_DC; + wndPtr->hdce = DCE_AllocDCE( DCE_WINDOW_DC ); + } + else if (classPtr->wc.style & CS_CLASSDC) + { + wndPtr->flags |= WIN_CLASS_DC; + wndPtr->hdce = classPtr->hdce; + } + else wndPtr->hdce = 0; + /* Insert the window in the linked list */ - if (parent) - { - wndPtr->hwndNext = parentPtr->hwndChild; - parentPtr->hwndChild = hwnd; - } - else /* Top-level window */ - { - wndPtr->hwndNext = firstWindow; - firstWindow = hwnd; - } - - if (!strcasecmp(className, "SCROLLBAR")) - { - SCROLLBAR_CreateScrollBar(className, windowName, hwnd); - goto WinCreated; - } - if (!strcasecmp(className, "LISTBOX")) - { - LISTBOX_CreateListBox(className, windowName, hwnd); - goto WinCreated; - } + WIN_LinkWindow( hwnd, HWND_TOP ); + if (!strcasecmp(className, "COMBOBOX")) { - COMBOBOX_CreateComboBox(className, windowName, hwnd); - goto WinCreated; + height = 16; } - /* Create the widgets */ + +#ifdef USE_XLIB + { + XSetWindowAttributes win_attr; + Window parentWindow; + int x_rel, y_rel; + + win_attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | + PointerMotionMask | ButtonPressMask | + ButtonReleaseMask | StructureNotifyMask | + FocusChangeMask | EnterWindowMask; + win_attr.override_redirect = /*True*/ False; + win_attr.colormap = COLOR_WinColormap; + if (style & WS_CHILD) + { + parentWindow = parentPtr->window; + x_rel = x + parentPtr->rectClient.left-parentPtr->rectWindow.left; + y_rel = y + parentPtr->rectClient.top-parentPtr->rectWindow.top; + } + else + { + parentWindow = DefaultRootWindow( XT_display ); + x_rel = x; + y_rel = y; + } + wndPtr->window = XCreateWindow( XT_display, parentWindow, + x_rel, y_rel, width, height, 0, + CopyFromParent, InputOutput, + CopyFromParent, + CWEventMask | CWOverrideRedirect | + CWColormap, &win_attr ); + XStoreName( XT_display, wndPtr->window, windowName ); + } +#else + /* Create the widgets */ if (style & WS_CHILD) { @@ -223,6 +317,7 @@ HWND CreateWindowEx( DWORD exStyle, LPSTR className, LPSTR windowName, XtNwidth, width, XtNheight, height, XtNborderColor, borderCol, + XtNmappedWhenManaged, FALSE, NULL ); } else @@ -235,6 +330,7 @@ HWND CreateWindowEx( DWORD exStyle, LPSTR className, LPSTR windowName, XtNwidth, width, XtNheight, height, XtNborderWidth, 0, + XtNmappedWhenManaged, FALSE, NULL ); } } @@ -247,6 +343,7 @@ HWND CreateWindowEx( DWORD exStyle, LPSTR className, LPSTR windowName, XtNx, x, XtNy, y, XtNcolormap, COLOR_WinColormap, + XtNmappedWhenManaged, FALSE, NULL ); wndPtr->compositeWidget = XtVaCreateManagedWidget(className, formWidgetClass, @@ -296,8 +393,24 @@ HWND CreateWindowEx( DWORD exStyle, LPSTR className, LPSTR windowName, NULL ); } } + if (wndPtr->shellWidget) XtRealizeWidget( wndPtr->shellWidget ); + if (wndPtr->compositeWidget) XtRealizeWidget( wndPtr->compositeWidget ); + XtRealizeWidget( wndPtr->winWidget ); + wndPtr->window = XtWindow( wndPtr->winWidget ); +#endif /* USE_XLIB */ -WinCreated: + if ((style & WS_VSCROLL) == WS_VSCROLL) { + newheight = height - (((style & WS_HSCROLL) == WS_HSCROLL) ? 16 : 0); + wndPtr->hWndVScroll = CreateWindow("SCROLLBAR", "", + WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | SBS_VERT, + width - 16, 0, 16, newheight, hwnd, 2, instance, 0L); + } + if ((style & WS_HSCROLL) == WS_HSCROLL) { + newwidth = width - (((style & WS_VSCROLL) == WS_VSCROLL) ? 16 : 0); + wndPtr->hWndHScroll = CreateWindow("SCROLLBAR", "", + WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | SBS_HORZ, + 0, height - 16, newwidth, 16, hwnd, 3, instance, 0L); + } /* Send the WM_CREATE message */ @@ -318,7 +431,24 @@ WinCreated: wmcreate = SendMessage( hwnd, WM_NCCREATE, 0, (LONG)createStruct ); if (!wmcreate) wmcreate = -1; - else wmcreate = SendMessage( hwnd, WM_CREATE, 0, (LONG)createStruct ); + else + { + /* Send WM_NCCALCSIZE message */ + NCCALCSIZE_PARAMS *params; + HANDLE hparams; + hparams = GlobalAlloc( GMEM_MOVEABLE, sizeof(*params) ); + if (hparams) + { + params = (NCCALCSIZE_PARAMS *) GlobalLock( hparams ); + params->rgrc[0] = wndPtr->rectWindow; + params->lppos = NULL; + SendMessage( hwnd, WM_NCCALCSIZE, FALSE, (LONG)params ); + wndPtr->rectClient = params->rgrc[0]; + GlobalUnlock( hparams ); + GlobalFree( hparams ); + } + wmcreate = SendMessage( hwnd, WM_CREATE, 0, (LONG)createStruct ); + } GlobalUnlock( hcreateStruct ); GlobalFree( hcreateStruct ); @@ -329,18 +459,27 @@ WinCreated: if (parent) parentPtr->hwndChild = wndPtr->hwndNext; else firstWindow = wndPtr->hwndNext; +#ifdef USE_XLIB + XDestroyWindow( XT_display, wndPtr->window ); +#else if (wndPtr->shellWidget) XtDestroyWidget( wndPtr->shellWidget ); else XtDestroyWidget( wndPtr->winWidget ); - if (wndPtr->hdc) DeleteDC( wndPtr->hdc ); +#endif + if (wndPtr->flags & WIN_OWN_DC) DCE_FreeDCE( wndPtr->hdce ); classPtr->cWindows--; USER_HEAP_FREE( hwnd ); return 0; } - - EVENT_AddHandlers( wndPtr->winWidget, hwnd ); - if (style & WS_VISIBLE) ShowWindow( hwnd, SW_SHOW ); +#ifdef USE_XLIB + EVENT_AddHandlers( wndPtr->window, hwnd ); +#else + EVENT_AddHandlers( wndPtr->winWidget, hwnd ); +#endif + WIN_SendParentNotify( hwnd, wndPtr, WM_CREATE ); + + if (style & WS_VISIBLE) ShowWindow( hwnd, SW_SHOW ); return hwnd; } @@ -350,7 +489,6 @@ WinCreated: BOOL DestroyWindow( HWND hwnd ) { WND * wndPtr; - HWND * curWndPtr; CLASS * classPtr; /* Initialisation */ @@ -366,130 +504,30 @@ BOOL DestroyWindow( HWND hwnd ) /* Destroy all children */ + if (wndPtr->hWndVScroll) DestroyWindow(wndPtr->hWndVScroll); + if (wndPtr->hWndHScroll) DestroyWindow(wndPtr->hWndHScroll); while (wndPtr->hwndChild) /* The child removes itself from the list */ DestroyWindow( wndPtr->hwndChild ); /* Remove the window from the linked list */ - if (wndPtr->hwndParent) - { - WND * parentPtr = WIN_FindWndPtr( wndPtr->hwndParent ); - curWndPtr = &parentPtr->hwndChild; - } - else curWndPtr = &firstWindow; - - while (*curWndPtr != hwnd) - { - WND * curPtr = WIN_FindWndPtr( *curWndPtr ); - curWndPtr = &curPtr->hwndNext; - } - *curWndPtr = wndPtr->hwndNext; + WIN_UnlinkWindow( hwnd ); /* Destroy the window */ +#ifdef USE_XLIB + XDestroyWindow( XT_display, wndPtr->window ); +#else if (wndPtr->shellWidget) XtDestroyWidget( wndPtr->shellWidget ); else XtDestroyWidget( wndPtr->winWidget ); - if (wndPtr->hdc) DeleteDC( wndPtr->hdc ); +#endif + if (wndPtr->flags & WIN_OWN_DC) DCE_FreeDCE( wndPtr->hdce ); classPtr->cWindows--; USER_HEAP_FREE( hwnd ); return TRUE; } -/*********************************************************************** - * GetWindowRect (USER.32) - */ -void GetWindowRect( HWND hwnd, LPRECT rect ) -{ - int x, y, width, height; - WND * wndPtr = WIN_FindWndPtr( hwnd ); - - if (wndPtr) - { - XtVaGetValues(wndPtr->winWidget, - XtNx, &x, XtNy, &y, - XtNwidth, &width, - XtNheight, &height, - NULL ); - rect->left = x & 0xffff; - rect->top = y & 0xffff; - rect->right = width & 0xffff; - rect->bottom = height & 0xffff; - } -} - - -/*********************************************************************** - * GetClientRect (USER.33) - */ -void GetClientRect( HWND hwnd, LPRECT rect ) -{ - int width, height; - WND * wndPtr = WIN_FindWndPtr( hwnd ); - - rect->left = rect->top = rect->right = rect->bottom = 0; - if (wndPtr) - { - XtVaGetValues(wndPtr->winWidget, - XtNwidth, &width, - XtNheight, &height, - NULL ); - rect->right = width & 0xffff; - rect->bottom = height & 0xffff; - } -} - - -/*********************************************************************** - * ShowWindow (USER.42) - */ -BOOL ShowWindow( HWND hwnd, int cmd ) -{ - int width, height; - - WND * wndPtr = WIN_FindWndPtr( hwnd ); - if (wndPtr) - { - if (wndPtr->shellWidget) XtRealizeWidget( wndPtr->shellWidget ); - XtVaGetValues(wndPtr->winWidget, - XtNwidth, &width, - XtNheight, &height, - NULL ); - switch(cmd) - { - case SW_HIDE: - XtSetMappedWhenManaged(wndPtr->winWidget, FALSE); - wndPtr->dwStyle &= (WS_VISIBLE ^ 0xFFFFFFFL); - SendMessage( hwnd, WM_SHOWWINDOW, FALSE, 0 ); - break; - case SW_SHOWMINNOACTIVE: - case SW_SHOWMINIMIZED: - case SW_MINIMIZE: - wndPtr->dwStyle |= WS_ICONIC; - goto WINVisible; - case SW_SHOWNA: - case SW_SHOWNOACTIVATE: - case SW_MAXIMIZE: - case SW_SHOWMAXIMIZED: - case SW_SHOW: - case SW_NORMAL: - case SW_SHOWNORMAL: - wndPtr->dwStyle &= (WS_ICONIC ^ 0xFFFFFFFL); -WINVisible: - XtSetMappedWhenManaged(wndPtr->winWidget, TRUE); - wndPtr->dwStyle |= WS_VISIBLE; - SendMessage( hwnd, WM_SIZE, SIZE_RESTORED, - (width & 0xffff) | (height << 16) ); - SendMessage( hwnd, WM_SHOWWINDOW, TRUE, 0 ); - break; - default: - break; - } - } - return TRUE; -} - - /*********************************************************************** * CloseWindow (USER.43) */ @@ -498,7 +536,6 @@ void CloseWindow(HWND hWnd) WND * wndPtr = WIN_FindWndPtr(hWnd); if (wndPtr->dwStyle & WS_CHILD) return; ShowWindow(hWnd, SW_MINIMIZE); - PostMessage(hWnd, WM_CLOSE, 0, 0L); } @@ -508,7 +545,6 @@ void CloseWindow(HWND hWnd) */ BOOL OpenIcon(HWND hWnd) { - WND * wndPtr = WIN_FindWndPtr(hWnd); if (!IsIconic(hWnd)) return FALSE; ShowWindow(hWnd, SW_SHOWNORMAL); return(TRUE); @@ -523,34 +559,8 @@ HWND FindWindow(LPSTR ClassMatch, LPSTR TitleMatch) { return((HWND)NULL); } - -/*********************************************************************** - * MoveWindow (USER.56) - */ -void MoveWindow(HWND hWnd, short x, short y, short w, short h, BOOL bRepaint) -{ - WND * wndPtr = WIN_FindWndPtr( hWnd ); - if (wndPtr) - { - wndPtr->rectClient.left = x; - wndPtr->rectClient.top = y; - wndPtr->rectClient.right = x + w; - wndPtr->rectClient.bottom = y + h; - XtVaSetValues(wndPtr->winWidget, XtNx, x, XtNy, y, - XtNwidth, w, XtNheight, h, NULL ); - SendMessage(hWnd, WM_MOVE, 0, MAKELONG(x, y)); - printf("MoveWindow(%X, %d, %d, %d, %d, %d); !\n", - hWnd, x, y, w, h, bRepaint); - if (bRepaint) { - InvalidateRect(hWnd, NULL, TRUE); - UpdateWindow(hWnd); - } - } -} - - /*********************************************************************** * UpdateWindow (USER.124) */ @@ -578,8 +588,10 @@ HMENU GetMenu( HWND hwnd ) */ BOOL SetMenu(HWND hwnd, HMENU hmenu) { +#ifdef USE_XLIB + return FALSE; +#else WND *wndPtr; - wndPtr = WIN_FindWndPtr(hwnd); if (wndPtr == NULL) return FALSE; @@ -618,44 +630,7 @@ BOOL SetMenu(HWND hwnd, HMENU hmenu) } return TRUE; -} - - -/*********************************************************************** - * SetWindowPos (USER.232) - */ -void SetWindowPos(HWND hWnd, HWND hWndInsertAfter, short x, short y, short w, short h, WORD wFlag) -{ - WND * wndPtr = WIN_FindWndPtr( hWnd ); - if (wndPtr) - { - if ((wFlag & SWP_NOMOVE) != SWP_NOMOVE) { - wndPtr->rectClient.left = x; - wndPtr->rectClient.top = y; - XtVaSetValues(wndPtr->winWidget, XtNx, x, XtNy, y, NULL ); - } - if ((wFlag & SWP_NOSIZE) != SWP_NOSIZE) { - wndPtr->rectClient.right = x + w; - wndPtr->rectClient.bottom = y + h; - XtVaSetValues(wndPtr->winWidget, XtNwidth, w, XtNheight, h, NULL ); - } - if ((wFlag & SWP_NOREDRAW) != SWP_NOREDRAW) { - InvalidateRect(hWnd, NULL, TRUE); - UpdateWindow(hWnd); - } - if ((wFlag & SWP_HIDEWINDOW) == SWP_HIDEWINDOW) - ShowWindow(hWnd, SW_HIDE); - if ((wFlag & SWP_SHOWWINDOW) == SWP_SHOWWINDOW) - ShowWindow(hWnd, SW_SHOW); -/* - if ((wFlag & SWP_NOACTIVATE) != SWP_NOACTIVATE) - SetActiveWindow(hWnd); - if ((wFlag & SWP_NOZORDER) != SWP_NOZORDER) - { } -*/ - printf("SetWindowPos(%X, %X, %d, %d, %d, %d, %X); !\n", - hWnd, hWndInsertAfter, x, y, w, h, wFlag); - } +#endif /* USE_XLIB */ } @@ -748,21 +723,6 @@ LONG SetWindowLong( HWND hwnd, short offset, LONG newval ) } -/*********************************************************************** - * IsIconic (USER.31) - */ -BOOL IsIconic(HWND hWnd) -{ - WND * wndPtr; - if (hWnd == 0) return(FALSE); - wndPtr = WIN_FindWndPtr(hWnd); - if (wndPtr == 0) return(FALSE); - if (wndPtr->dwStyle & WS_ICONIC) return(TRUE); - return(FALSE); -} - - - /******************************************************************* * GetWindowText (USER.36) */ @@ -796,7 +756,7 @@ int GetWindowTextLength(HWND hwnd) BOOL IsWindow( HWND hwnd ) { WND * wndPtr = WIN_FindWndPtr( hwnd ); - return (wndPtr->dwMagic == WND_MAGIC); + return ((wndPtr != NULL) && (wndPtr->dwMagic == WND_MAGIC)); } @@ -806,6 +766,7 @@ BOOL IsWindow( HWND hwnd ) HWND GetParent(HWND hwnd) { WND *wndPtr = WIN_FindWndPtr(hwnd); + if (!wndPtr) return 0; return wndPtr->hwndParent; } @@ -838,14 +799,9 @@ BOOL IsChild( HWND parent, HWND child ) */ BOOL IsWindowVisible(HWND hWnd) { - WND * wndPtr; - if (hWnd == 0) return(FALSE); - wndPtr = WIN_FindWndPtr(hWnd); + WND * wndPtr = WIN_FindWndPtr(hWnd); if (wndPtr == 0) return(FALSE); - if (wndPtr->dwStyle & WS_VISIBLE) { - if (XtIsRealized(wndPtr->winWidget)) return(TRUE); - } - return(FALSE); + else return ((wndPtr->dwStyle & WS_VISIBLE) != 0); } diff --git a/windows/winpos.c b/windows/winpos.c new file mode 100644 index 00000000000..0b474e2e3ea --- /dev/null +++ b/windows/winpos.c @@ -0,0 +1,389 @@ +/* + * Window position related functions. + * + * Copyright 1993 Alexandre Julliard + */ + +static char Copyright[] = "Copyright Alexandre Julliard, 1993"; + +#include "win.h" + +extern Display * XT_display; +extern Screen * XT_screen; + + +/*********************************************************************** + * GetWindowRect (USER.32) + */ +void GetWindowRect( HWND hwnd, LPRECT rect ) +{ + WND * wndPtr = WIN_FindWndPtr( hwnd ); + if (!wndPtr) return; + + *rect = wndPtr->rectWindow; + if (wndPtr->hwndParent) + MapWindowPoints( wndPtr->hwndParent, 0, (POINT *)rect, 2 ); +} + + +/*********************************************************************** + * GetClientRect (USER.33) + */ +void GetClientRect( HWND hwnd, LPRECT rect ) +{ + WND * wndPtr = WIN_FindWndPtr( hwnd ); + + rect->left = rect->top = rect->right = rect->bottom = 0; + if (wndPtr) + { + rect->right = wndPtr->rectClient.right - wndPtr->rectClient.left; + rect->bottom = wndPtr->rectClient.bottom - wndPtr->rectClient.top; + } +} + + +/******************************************************************* + * ClientToScreen (USER.28) + */ +void ClientToScreen( HWND hwnd, LPPOINT lppnt ) +{ + MapWindowPoints( hwnd, 0, lppnt, 1 ); +} + + +/******************************************************************* + * ScreenToClient (USER.29) + */ +void ScreenToClient( HWND hwnd, LPPOINT lppnt ) +{ + MapWindowPoints( 0, hwnd, lppnt, 1 ); +} + + +/******************************************************************* + * MapWindowPoints (USER.258) + */ +void MapWindowPoints( HWND hwndFrom, HWND hwndTo, LPPOINT lppt, WORD count ) +{ + WND * wndPtr; + POINT * curpt; + POINT origin = { 0, 0 }; + WORD i; + + /* Translate source window origin to screen coords */ + while(hwndFrom) + { + wndPtr = WIN_FindWndPtr( hwndFrom ); + origin.x += wndPtr->rectClient.left; + origin.y += wndPtr->rectClient.top; + hwndFrom = wndPtr->hwndParent; + } + + /* Translate origin to destination window coords */ + while(hwndTo) + { + wndPtr = WIN_FindWndPtr( hwndTo ); + origin.x -= wndPtr->rectClient.left; + origin.y -= wndPtr->rectClient.top; + hwndTo = wndPtr->hwndParent; + } + + /* Translate points */ + for (i = 0, curpt = lppt; i < count; i++, curpt++) + { + curpt->x += origin.x; + curpt->y += origin.y; + } +} + + +/*********************************************************************** + * IsIconic (USER.31) + */ +BOOL IsIconic(HWND hWnd) +{ + WND * wndPtr = WIN_FindWndPtr(hWnd); + if (wndPtr == NULL) return FALSE; + return (wndPtr->dwStyle & WS_MINIMIZE) != 0; +} + + +/*********************************************************************** + * IsZoomed (USER.272) + */ +BOOL IsZoomed(HWND hWnd) +{ + WND * wndPtr = WIN_FindWndPtr(hWnd); + if (wndPtr == NULL) return FALSE; + return (wndPtr->dwStyle & WS_MAXIMIZE) != 0; +} + + +/*********************************************************************** + * MoveWindow (USER.56) + */ +BOOL MoveWindow( HWND hwnd, short x, short y, short cx, short cy, BOOL repaint) +{ + int flags = SWP_NOZORDER | SWP_NOACTIVATE; + if (!repaint) flags |= SWP_NOREDRAW; +#ifdef DEBUG_WIN + printf( "MoveWindow: %d %d,%d %dx%d %d\n", hwnd, x, y, cx, cy, repaint ); +#endif + return SetWindowPos( hwnd, 0, x, y, cx, cy, flags ); +} + + +/*********************************************************************** + * ShowWindow (USER.42) + */ +BOOL ShowWindow( HWND hwnd, int cmd ) +{ + WND * wndPtr = WIN_FindWndPtr( hwnd ); + BOOL wasVisible; + int swpflags = 0; + +#ifdef DEBUG_WIN + printf("ShowWindow: hwnd=%d, cmd=%d\n", hwnd, cmd); +#endif + + if (!wndPtr) return FALSE; + wasVisible = (wndPtr->dwStyle & WS_VISIBLE) != 0; + switch(cmd) + { + case SW_HIDE: + if (!wasVisible) return FALSE; /* Nothing to do */ + swpflags |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | + SWP_NOACTIVATE | SWP_NOZORDER; + break; + + case SW_SHOWMINNOACTIVE: + case SW_SHOWMINIMIZED: + case SW_MINIMIZE: + wndPtr->dwStyle |= WS_MINIMIZE; + swpflags |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | + SWP_NOACTIVATE | SWP_NOZORDER; + break; + + case SW_SHOWNA: + case SW_SHOWNOACTIVATE: + case SW_MAXIMIZE: + case SW_SHOWMAXIMIZED: + case SW_SHOW: + case SW_NORMAL: + case SW_SHOWNORMAL: + wndPtr->dwStyle &= ~WS_MINIMIZE; + swpflags |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | + SWP_NOACTIVATE | SWP_NOZORDER; + break; + } + SendMessage( hwnd, WM_SHOWWINDOW, (cmd != SW_HIDE), 0 ); + SetWindowPos( hwnd, 0, 0, 0, 0, 0, swpflags ); + + /* Send WM_SIZE and WM_MOVE messages if not already done */ + if (!(wndPtr->flags & WIN_GOT_SIZEMSG)) + { + int wParam = SIZE_RESTORED; + if (wndPtr->dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED; + else if (wndPtr->dwStyle & WS_MINIMIZE) wParam = SIZE_MINIMIZED; + wndPtr->flags |= WIN_GOT_SIZEMSG; + SendMessage( hwnd, WM_SIZE, wParam, + MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left, + wndPtr->rectClient.bottom-wndPtr->rectClient.top)); + SendMessage( hwnd, WM_MOVE, 0, + MAKELONG(wndPtr->rectClient.left, wndPtr->rectClient.top) ); + } + return wasVisible; +} + + +/*********************************************************************** + * SetWindowPos (USER.232) + */ +/* Unimplemented flags: SWP_NOREDRAW, SWP_NOACTIVATE + */ +/* Note: all this code should be in the DeferWindowPos() routines, + * and SetWindowPos() should simply call them. This will be implemented + * some day... + */ +BOOL SetWindowPos( HWND hwnd, HWND hwndInsertAfter, short x, short y, + short cx, short cy, WORD flags ) +{ + WINDOWPOS *winPos; + HANDLE hmem = 0; + RECT newWindowRect, newClientRect; + WND *wndPtr; + int calcsize_result = 0; +#ifdef USE_XLIB + XWindowChanges winChanges; + int changeMask = 0; +#endif + +#ifdef DEBUG_WIN + printf( "SetWindowPos: %d %d %d,%d %dx%d 0x%x\n", + hwnd, hwndInsertAfter, x, y, cx, cy, flags ); +#endif + + if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE; + if (flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW)) + flags |= SWP_NOMOVE | SWP_NOSIZE; + + /* Send WM_WINDOWPOSCHANGING message */ + + if (!(hmem = GlobalAlloc( GMEM_MOVEABLE,sizeof(WINDOWPOS) ))) return FALSE; + winPos = (WINDOWPOS *)GlobalLock( hmem ); + winPos->hwnd = hwnd; + winPos->hwndInsertAfter = hwndInsertAfter; + winPos->x = x; + winPos->y = y; + winPos->cx = cx; + winPos->cy = cy; + winPos->flags = flags; + SendMessage( hwnd, WM_WINDOWPOSCHANGING, 0, (LONG)winPos ); + + /* Calculate new position and size */ + + newWindowRect = wndPtr->rectWindow; + newClientRect = wndPtr->rectClient; + + if (!(winPos->flags & SWP_NOSIZE)) + { + newWindowRect.right = newWindowRect.left + winPos->cx; + newWindowRect.bottom = newWindowRect.top + winPos->cy; + } + + if (!(winPos->flags & SWP_NOMOVE)) + { + newWindowRect.left = winPos->x; + newWindowRect.top = winPos->y; + newWindowRect.right += winPos->x - wndPtr->rectWindow.left; + newWindowRect.bottom += winPos->y - wndPtr->rectWindow.top; + } + + /* Reposition window in Z order */ + + if (!(winPos->flags & SWP_NOZORDER)) + { + hwndInsertAfter = winPos->hwndInsertAfter; + + /* TOPMOST not supported yet */ + if ((hwndInsertAfter == HWND_TOPMOST) || + (hwndInsertAfter == HWND_NOTOPMOST)) hwndInsertAfter = HWND_TOP; + + /* Make sure hwndInsertAfter is a sibling of hwnd */ + if ((hwndInsertAfter != HWND_TOP) && (hwndInsertAfter != HWND_BOTTOM)) + if (wndPtr->hwndParent != GetParent(hwndInsertAfter)) goto Abort; + + WIN_UnlinkWindow( hwnd ); + WIN_LinkWindow( hwnd, hwndInsertAfter ); + } + + /* Recalculate client area position */ + + if (winPos->flags & SWP_FRAMECHANGED) + { + /* Send WM_NCCALCSIZE message */ + NCCALCSIZE_PARAMS *params; + HANDLE hparams; + + if (!(hparams = GlobalAlloc( GMEM_MOVEABLE, sizeof(*params) ))) + goto Abort; + params = (NCCALCSIZE_PARAMS *) GlobalLock( hparams ); + params->rgrc[0] = newWindowRect; + params->rgrc[1] = wndPtr->rectWindow; + params->rgrc[2] = wndPtr->rectClient; + params->lppos = winPos; + calcsize_result = SendMessage(hwnd, WM_NCCALCSIZE, TRUE, (LONG)params); + GlobalUnlock( hparams ); + GlobalFree( hparams ); + newClientRect = params->rgrc[0]; + /* Handle result here */ + } + else + { + newClientRect.left = newWindowRect.left + wndPtr->rectClient.left + - wndPtr->rectWindow.left; + newClientRect.top = newWindowRect.top + wndPtr->rectClient.top + - wndPtr->rectWindow.top; + newClientRect.right = newWindowRect.right + wndPtr->rectClient.right + - wndPtr->rectWindow.right; + newClientRect.bottom = newWindowRect.bottom + wndPtr->rectClient.bottom + - wndPtr->rectWindow.bottom; + } + + /* Perform the moving and resizing */ +#ifdef USE_XLIB + if (!(winPos->flags & SWP_NOMOVE)) + { + WND * parentPtr; + winChanges.x = newWindowRect.left; + winChanges.y = newWindowRect.top; + if (wndPtr->hwndParent) + { + parentPtr = WIN_FindWndPtr(wndPtr->hwndParent); + winChanges.x += parentPtr->rectClient.left-parentPtr->rectWindow.left; + winChanges.y += parentPtr->rectClient.top-parentPtr->rectWindow.top; + } + changeMask |= CWX | CWY; + } + if (!(winPos->flags & SWP_NOSIZE)) + { + winChanges.width = newWindowRect.right - newWindowRect.left; + winChanges.height = newWindowRect.bottom - newWindowRect.top; + changeMask |= CWWidth | CWHeight; + } + if (!(winPos->flags & SWP_NOZORDER)) + { + if (hwndInsertAfter == HWND_TOP) winChanges.stack_mode = Above; + else winChanges.stack_mode = Below; + if ((hwndInsertAfter != HWND_TOP) && (hwndInsertAfter != HWND_BOTTOM)) + { + WND * insertPtr = WIN_FindWndPtr( hwndInsertAfter ); + winChanges.sibling = insertPtr->window; + changeMask |= CWSibling; + } + changeMask |= CWStackMode; + } + if (changeMask) XConfigureWindow( XT_display, wndPtr->window, + changeMask, &winChanges ); +#endif + + if (winPos->flags & SWP_SHOWWINDOW) + { + wndPtr->dwStyle |= WS_VISIBLE; +#ifdef USE_XLIB + XMapWindow( XT_display, wndPtr->window ); +#else + if (wndPtr->shellWidget) XtMapWidget( wndPtr->shellWidget ); + else XtMapWidget( wndPtr->winWidget ); +#endif + } + else if (winPos->flags & SWP_HIDEWINDOW) + { + wndPtr->dwStyle &= ~WS_VISIBLE; +#ifdef USE_XLIB + XUnmapWindow( XT_display, wndPtr->window ); +#else + if (wndPtr->shellWidget) XtUnmapWidget( wndPtr->shellWidget ); + else XtUnmapWidget( wndPtr->winWidget ); +#endif + } + + /* Finally send the WM_WINDOWPOSCHANGED message */ + wndPtr->rectWindow = newWindowRect; + wndPtr->rectClient = newClientRect; + SendMessage( hwnd, WM_WINDOWPOSCHANGED, 0, (LONG)winPos ); + GlobalUnlock( hmem ); + GlobalFree( hmem ); + + return TRUE; + + Abort: /* Fatal error encountered */ + if (hmem) + { + GlobalUnlock( hmem ); + GlobalFree( hmem ); + } + return FALSE; +} + + diff --git a/wine.ini b/wine.ini new file mode 100644 index 00000000000..d9958bea4f0 --- /dev/null +++ b/wine.ini @@ -0,0 +1,19 @@ +[drives] +a=/mnt/fd0 +c=/dos +d=/usr/windows +e=/home/bob/Wine/work +f=/home/bob/test + +[wine] +windows=c:\windows +system=c:\windows\system +temp=c:\temp +path=c:\windows;c:\windows\system;e:\;e:\test;f:\ + +[serialports] +com1=/dev/cua0 +com2=/dev/cua1 + +[parallelports] +lpt1=/dev/lp0