diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a7a3b8..4e52be3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,6 +64,9 @@ elseif(CURSES_HAVE_CURSES_H) add_definitions(-DHAVE_CURSES_H) endif() +# !!! FIXME +include_directories("/usr/local/include/SDL2") + foreach(_I doscalls;msg;nls;quecalls;viocalls;kbdcalls;sesmgr;som;pmwin;pmshapi;pmgpi;tcpip32) add_library(${_I} SHARED "native/${_I}.c") set_target_properties(${_I} PROPERTIES COMPILE_FLAGS "-m32") @@ -73,6 +76,7 @@ endforeach() target_link_libraries(doscalls "pthread") # FIXME target_link_libraries(viocalls ${CURSES_LIBRARIES}) target_link_libraries(viocalls ncursesw) +target_link_libraries(pmwin "${CMAKE_CURRENT_SOURCE_DIR}/libSDL2-2.0.so.0") add_executable(lx_dump lx_dump.c) diff --git a/libSDL2-2.0.so.0 b/libSDL2-2.0.so.0 new file mode 100644 index 0000000..30e52d1 Binary files /dev/null and b/libSDL2-2.0.so.0 differ diff --git a/lx_loader.c b/lx_loader.c index 35b15d7..dce0711 100644 --- a/lx_loader.c +++ b/lx_loader.c @@ -2046,7 +2046,10 @@ static __attribute__((noreturn)) void handleThreadLocalStorageAccess(const int s : "=a" (ptib2) : "eax" (gregs[REG_FS]) ); - uint32 *tls = (uint32 *) (ptib2 + 1); // The thread's TLS data is stored right after its TIB2 struct. + + // The thread's TLS data is stored in LxPostTIB, right after its TIB2 struct. + LxPostTIB *posttib = (LxPostTIB *) (ptib2 + 1); + uint32 *tls = posttib->tls; tls += slot; //printf("We wanted to access thread %p TLS slot %d (currently holds %u)\n", tls - slot, slot, (uint) *tls); @@ -2151,6 +2154,9 @@ int main(int argc, char **argv, char **envp) if (getenv("TRACE_NATIVE")) GLoaderState->trace_native = 1; + if (getenv("TRACE_EVENTS")) + GLoaderState->trace_events = 1; + unsigned int segment = 0; __asm__ __volatile__ ( "movw %%cs, %%ax \n\t" : "=a" (segment) ); GLoaderState->original_cs = segment; diff --git a/lx_loader.h b/lx_loader.h index 58bec72..9add93c 100644 --- a/lx_loader.h +++ b/lx_loader.h @@ -202,8 +202,14 @@ typedef struct LxPIB #pragma pack(pop) -// We put the 128 bytes of TLS slots after the TIB structs. -#define LXTIBSIZE (sizeof (LxTIB) + sizeof (LxTIB2) + 128) +// We put the 128 bytes of TLS slots (etc) after the TIB structs. +typedef struct LxPostTIB +{ + uint32 tls[32]; + void *anchor_block; +} LxPostTIB; + +#define LXTIBSIZE (sizeof (LxTIB) + sizeof (LxTIB2) + sizeof (LxPostTIB)) typedef struct LxLoaderState { @@ -214,6 +220,7 @@ typedef struct LxLoaderState int subprocess; int running; int trace_native; + int trace_events; uint16 original_cs; uint16 original_ds; uint16 original_es; diff --git a/native/os2native.h b/native/os2native.h index e6d9ff7..f722553 100644 --- a/native/os2native.h +++ b/native/os2native.h @@ -25,6 +25,12 @@ static LxLoaderState *GLoaderState = NULL; #define TRACE_NATIVE(...) do {} while (0) #endif +#if 1 +#define TRACE_EVENT(...) do { if (GLoaderState->trace_events) { fprintf(stderr, "2INE TRACE [%lu]: ", (unsigned long) pthread_self()); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); } } while (0) +#else +#define TRACE_EVENT(...) do {} while (0) +#endif + OS2EXPORT const LxExport * lxNativeModuleInit(LxLoaderState *lx_state, uint32 *lx_num_exports); void OS2EXPORT lxNativeModuleDeinit(void); diff --git a/native/os2types.h b/native/os2types.h index 128795c..029efb7 100644 --- a/native/os2types.h +++ b/native/os2types.h @@ -57,6 +57,7 @@ typedef uint8_t BYTE, *PBYTE; // !!! FIXME: refactor and mutex a bunch of stuff...if it has to be a 32-bit // !!! FIXME: int, it needs to be an index into a resizable array, but at the // !!! FIXME: native word size, these handles can just be pointers cast to ints. +// !!! FIXME: alternately: guarantee all handles are in the bottom 4 gigabytes? typedef uint16_t SHANDLE, *PSHANDLE; typedef uint32_t LHANDLE, *PLHANDLE; typedef LHANDLE HANDLE, *PHANDLE; @@ -71,11 +72,18 @@ typedef HANDLE PID, *PPID; typedef HANDLE TID, *PTID; typedef SHANDLE HVIO, *PHVIO; typedef SHANDLE HKBD, *PHKBD; + typedef PCHAR PSZ; typedef PCHAR PCH; typedef int (APIENTRY *PFN)(void); +typedef ULONG ERRORID; + +#define NULLHANDLE 0 +#define TRUE 1 +#define FALSE 0 + #ifdef __cplusplus } #endif diff --git a/native/pmgpi.h b/native/pmgpi.h index 5862ae0..1b157eb 100644 --- a/native/pmgpi.h +++ b/native/pmgpi.h @@ -2,17 +2,12 @@ #define _INCL_PMGPI_H_ #include "os2types.h" +#include "pmwin.h" #ifdef __cplusplus extern "C" { #endif -typedef struct -{ - int32_t x; - int32_t y; -} POINTL, *PPOINTL; - OS2EXPORT BOOL OS2API GpiQueryTextBox(HPS hps, LONG lCount1, PCH pchString, LONG lCount2, PPOINTL aptlPoints); #ifdef __cplusplus diff --git a/native/pmwin.c b/native/pmwin.c new file mode 100644 index 0000000..ba5b4e1 --- /dev/null +++ b/native/pmwin.c @@ -0,0 +1,1656 @@ +#include "os2native.h" +#include "pmwin.h" +#include "SDL.h" + +// NOTE: PM reference manual says OS/2 generally ignores the HAB you pass +// to functions, instead getting that info from the current thread, but +// other IBM platforms might not do that, so programs should always pass +// a valid HAB to everything. Things like WinCreateWindow() probably rely +// on the current thread's HAB without requiring the API call to specify +// it in any case. +// So current approach: keep a pointer to the anchor block in the TIB, and +// the anchor block keeps a copy of it's HAB. When the anchor block is +// needed, we pull it from the TIB directly, and if it's in a function +// where a HAB is specified, we fail if the handles don't match. +// If I later find out that OS/2 doesn't even care even if you give it a +// bogus HAB, we can relax this check. + + +// !!! FIXME: You can send messages to HWNDs on a different thread, which +// !!! FIXME: means HWND values must be unique across threads. Technically, +// !!! FIXME: they have to be unique across processes, too. :/ + + +#define FIRST_HWND_VALUE 10 +#define FIRST_HPS_VALUE 10 + +// This is the keyname we use on an heavyweight SDL window to find our +// associated Window*. +#define WINDATA_WINDOWPTR_NAME "2ine_windowptr" + +static SDL_atomic_t GHABCounter; +static SDL_atomic_t GHMQCounter; + +typedef struct WindowClass +{ + char *name; + PFNWP window_proc; + ULONG style; + ULONG data_len; + struct WindowClass *next; +} WindowClass; + +// these get shared with all children, but they're owned by the topmost parent. +typedef struct +{ + SDL_Window *window; + SDL_Renderer *renderer; + SDL_Texture *texture; +} HeavyWeightWindow; + +typedef struct Window +{ + PFNWP window_proc; + HeavyWeightWindow heavy; + struct Window *parent; + struct Window *children; + struct Window *sibling; + struct Window *owner; + const char *window_class_name; // Class at creation time. styles and window procs might change later, though! This is just to make debugging easier. + char *text; + void *data; + size_t data_len; + ULONG id; + ULONG class_style; + ULONG style; + HWND hwnd; + LONG x; + LONG y; + LONG w; + LONG h; +} Window; + +typedef struct MessageQueueItem +{ + QMSG qmsg; + struct MessageQueueItem *next; +} MessageQueueItem; + +typedef struct +{ + HMQ hmq; + MessageQueueItem *head; + MessageQueueItem *tail; + MessageQueueItem *free_pool; +} MessageQueue; + +typedef struct +{ + HPS hps; + Window *window; + // !!! FIXME: this is gonna be WAY more complicated. +} PresentationSpace; + +typedef struct +{ + HAB hab; // actual HAB value for this block, for comparison. + ERRORID last_error; + WindowClass *registered_classes; + MessageQueue message_queue; + Window *windows; + size_t windows_array_len; + PresentationSpace *pres_spaces; + size_t pres_spaces_array_len; +} AnchorBlock; + +#define SET_WIN_ERROR_AND_RETURN(anchor, err, rc) { anchor->last_error = (err); return (rc); } + +static Window desktop_window; // !!! FIXME: initialize and upkeep on this. + +// !!! FIXME: duplication from doscalls.c +static LxTIB2 *getTib2(void) +{ + // just read the FS register, since we have to stick it there anyhow... + LxTIB2 *ptib2; + __asm__ __volatile__ ( "movl %%fs:0xC, %0 \n\t" : "=r" (ptib2) ); + return ptib2; +} // getTib2 + +static inline LxPostTIB *getPostTib(void) +{ + // we store the LxPostTIB struct right after the TIB2 struct on the stack, + // so get the TIB2's linear address from %fs:0xC, then step over it + // to the LxPostTIB's linear address. + return (LxPostTIB *) (getTib2() + 1); +} // getPostTib + +static inline AnchorBlock *getAnchorBlockNoHAB(void) +{ + return (AnchorBlock *) getPostTib()->anchor_block; +} // getAnchorBlockNoHAB + +static AnchorBlock *getAnchorBlock(const HAB hab) +{ + AnchorBlock *anchor = getAnchorBlockNoHAB(); + if (!anchor) { + return NULL; + } else if (anchor->hab != hab) { + SET_WIN_ERROR_AND_RETURN(anchor, PMERR_INVALID_HAB, NULL); + } + return anchor; +} // getAnchorBlock + +static Window *getWindowFromHWND(const AnchorBlock *anchor, const HWND hwnd) +{ + if (hwnd >= FIRST_HWND_VALUE) { + const size_t idx = (size_t) (hwnd - FIRST_HWND_VALUE); + if (idx >= anchor->windows_array_len) { + return NULL; + } + Window *win = &anchor->windows[idx]; + return (win->hwnd == hwnd) ? win : NULL; + } else if (hwnd == HWND_DESKTOP) { + return &desktop_window; + } + return NULL; +} // getWindowFromHWND + +static PresentationSpace *getPresentationSpaceFromHPS(const AnchorBlock *anchor, const HPS hps) +{ + if (hps >= FIRST_HPS_VALUE) { + const size_t idx = (size_t) (hps - FIRST_HPS_VALUE); + if (idx >= anchor->pres_spaces_array_len) { + return NULL; + } + PresentationSpace *ps = &anchor->pres_spaces[idx]; + return (ps->hps == hps) ? ps : NULL; + } + return NULL; +} // getPresentationSpaceFromHPS + +static const char *messageName(const ULONG msg) +{ + switch (msg) { + #define MSGCASE(m) case m: return #m + MSGCASE(WM_NULL); + MSGCASE(WM_CREATE); + MSGCASE(WM_DESTROY); + MSGCASE(WM_ENABLE); + MSGCASE(WM_SHOW); + MSGCASE(WM_MOVE); + MSGCASE(WM_SIZE); + MSGCASE(WM_ADJUSTWINDOWPOS); + MSGCASE(WM_CALCVALIDRECTS); + MSGCASE(WM_SETWINDOWPARAMS); + MSGCASE(WM_QUERYWINDOWPARAMS); + MSGCASE(WM_HITTEST); + MSGCASE(WM_ACTIVATE); + MSGCASE(WM_SETFOCUS); + MSGCASE(WM_SETSELECTION); + MSGCASE(WM_PPAINT); + MSGCASE(WM_PSETFOCUS); + MSGCASE(WM_PSYSCOLORCHANGE); + MSGCASE(WM_PSIZE); + MSGCASE(WM_PACTIVATE); + MSGCASE(WM_PCONTROL); + MSGCASE(WM_COMMAND); + MSGCASE(WM_SYSCOMMAND); + MSGCASE(WM_HELP); + MSGCASE(WM_PAINT); + MSGCASE(WM_TIMER); + MSGCASE(WM_SEM1); + MSGCASE(WM_SEM2); + MSGCASE(WM_SEM3); + MSGCASE(WM_SEM4); + MSGCASE(WM_CLOSE); + MSGCASE(WM_QUIT); + MSGCASE(WM_SYSCOLORCHANGE); + MSGCASE(WM_SYSVALUECHANGED); + MSGCASE(WM_APPTERMINATENOTIFY); + MSGCASE(WM_PRESPARAMCHANGED); + MSGCASE(WM_CONTROL); + MSGCASE(WM_VSCROLL); + MSGCASE(WM_HSCROLL); + MSGCASE(WM_INITMENU); + MSGCASE(WM_MENUSELECT); + MSGCASE(WM_MENUEND); + MSGCASE(WM_DRAWITEM); + MSGCASE(WM_MEASUREITEM); + MSGCASE(WM_CONTROLPOINTER); + MSGCASE(WM_QUERYDLGCODE); + MSGCASE(WM_INITDLG); + MSGCASE(WM_SUBSTITUTESTRING); + MSGCASE(WM_MATCHMNEMONIC); + MSGCASE(WM_SAVEAPPLICATION); + MSGCASE(WM_FLASHWINDOW); + MSGCASE(WM_FORMATFRAME); + MSGCASE(WM_UPDATEFRAME); + MSGCASE(WM_FOCUSCHANGE); + MSGCASE(WM_SETBORDERSIZE); + MSGCASE(WM_TRACKFRAME); + MSGCASE(WM_MINMAXFRAME); + MSGCASE(WM_SETICON); + MSGCASE(WM_QUERYICON); + MSGCASE(WM_SETACCELTABLE); + MSGCASE(WM_QUERYACCELTABLE); + MSGCASE(WM_TRANSLATEACCEL); + MSGCASE(WM_QUERYTRACKINFO); + MSGCASE(WM_QUERYBORDERSIZE); + MSGCASE(WM_NEXTMENU); + MSGCASE(WM_ERASEBACKGROUND); + MSGCASE(WM_QUERYFRAMEINFO); + MSGCASE(WM_QUERYFOCUSCHAIN); + MSGCASE(WM_OWNERPOSCHANGE); + MSGCASE(WM_CALCFRAMERECT); + MSGCASE(WM_WINDOWPOSCHANGED); + MSGCASE(WM_ADJUSTFRAMEPOS); + MSGCASE(WM_QUERYFRAMECTLCOUNT); + MSGCASE(WM_QUERYHELPINFO); + MSGCASE(WM_SETHELPINFO); + MSGCASE(WM_ERROR); + MSGCASE(WM_REALIZEPALETTE); + MSGCASE(WM_RENDERFMT); + MSGCASE(WM_RENDERALLFMTS); + MSGCASE(WM_DESTROYCLIPBOARD); + MSGCASE(WM_PAINTCLIPBOARD); + MSGCASE(WM_SIZECLIPBOARD); + MSGCASE(WM_HSCROLLCLIPBOARD); + MSGCASE(WM_VSCROLLCLIPBOARD); + MSGCASE(WM_DRAWCLIPBOARD); + MSGCASE(WM_MOUSEMOVE); + MSGCASE(WM_BUTTON1DOWN); + MSGCASE(WM_BUTTON1UP); + MSGCASE(WM_BUTTON1DBLCLK); + MSGCASE(WM_BUTTON2DOWN); + MSGCASE(WM_BUTTON2UP); + MSGCASE(WM_BUTTON2DBLCLK); + MSGCASE(WM_BUTTON3DOWN); + MSGCASE(WM_BUTTON3UP); + MSGCASE(WM_BUTTON3DBLCLK); + MSGCASE(WM_CHAR); + MSGCASE(WM_VIOCHAR); + MSGCASE(WM_JOURNALNOTIFY); + MSGCASE(WM_MOUSEMAP); + MSGCASE(WM_VRNDISABLED); + MSGCASE(WM_VRNENABLED); + MSGCASE(WM_DDE_INITIATE); + MSGCASE(WM_DDE_REQUEST); + MSGCASE(WM_DDE_ACK); + MSGCASE(WM_DDE_DATA); + MSGCASE(WM_DDE_ADVISE); + MSGCASE(WM_DDE_UNADVISE); + MSGCASE(WM_DDE_POKE); + MSGCASE(WM_DDE_EXECUTE); + MSGCASE(WM_DDE_TERMINATE); + MSGCASE(WM_DDE_INITIATEACK); + MSGCASE(WM_QUERYCONVERTPOS); + MSGCASE(WM_MSGBOXINIT); + MSGCASE(WM_MSGBOXDISMISS); + MSGCASE(WM_CTLCOLORCHANGE); + MSGCASE(WM_QUERYCTLTYPE); + MSGCASE(WM_CHORD); + MSGCASE(WM_BUTTON1MOTIONSTART); + MSGCASE(WM_BUTTON1MOTIONEND); + MSGCASE(WM_BUTTON1CLICK); + MSGCASE(WM_BUTTON2MOTIONSTART); + MSGCASE(WM_BUTTON2MOTIONEND); + MSGCASE(WM_BUTTON2CLICK); + MSGCASE(WM_BUTTON3MOTIONSTART); + MSGCASE(WM_BUTTON3MOTIONEND); + MSGCASE(WM_BUTTON3CLICK); + MSGCASE(WM_BEGINDRAG); + MSGCASE(WM_ENDDRAG); + MSGCASE(WM_SINGLESELECT); + MSGCASE(WM_OPEN); + MSGCASE(WM_CONTEXTMENU); + MSGCASE(WM_CONTEXTHELP); + MSGCASE(WM_TEXTEDIT); + MSGCASE(WM_BEGINSELECT); + MSGCASE(WM_ENDSELECT); + MSGCASE(WM_PICKUP); + MSGCASE(WM_SEMANTICEVENT); + MSGCASE(WM_USER); + #undef MSGCASE + default: break; + } + + return "???"; +} // messageName + +static WindowClass *findRegisteredClass(AnchorBlock *anchor, const char *classname) +{ + const ULONG intclass = (ULONG) (size_t) classname; + if ((intclass >= 0xffff0001) && (intclass <= 0xffff0070)) { + // built-in class, like WC_BUTTON or whatever. + switch (intclass) { + // !!! FIXME: write me. + case WC_FRAME: + case WC_COMBOBOX: + case WC_BUTTON: + case WC_MENU: + case WC_STATIC: + case WC_ENTRYFIELD: + case WC_LISTBOX: + case WC_SCROLLBAR: + case WC_TITLEBAR: + case WC_MLE: + case WC_APPSTAT: + case WC_KBDSTAT: + case WC_PECIC: + case WC_DBE_KKPOPUP: + case WC_SPINBUTTON: + case WC_CONTAINER: + case WC_SLIDER: + case WC_VALUESET: + case WC_NOTEBOOK: + case WC_CIRCULARSLIDER: + default: + return NULL; + } + } else { + for (WindowClass *i = anchor->registered_classes; i; i = i->next) { + if (strcmp(i->name, classname) == 0) { + return i; + } + } + } + return NULL; +} // findRegisteredClass + +static ULONG currentSystemTicks(void) +{ + FIXME("this isn't correct"); // see notes in processSDLEvent() for details. + return SDL_GetTicks(); +} // currentSystemTicks + +HAB WinInitialize(ULONG flOptions) +{ + TRACE_NATIVE("WinInitialize(%u)", (unsigned int) flOptions); + + if (flOptions != 0) { + return NULLHANDLE; // reserved; must be zero. + } + + LxPostTIB *posttib = getPostTib(); + if (posttib->anchor_block != NULL) { + return NULLHANDLE; // fail if thread already has a HAB + } + + if (!SDL_WasInit(SDL_INIT_VIDEO)) { + if (SDL_Init(SDL_INIT_VIDEO) == -1) { + fprintf(stderr, "SDL_INIT_VIDEO failed: %s\n", SDL_GetError()); + return NULLHANDLE; + } + } + + FIXME("OS/2 doesn't support multi-monitor"); // this might not be true, actually. + SDL_Rect desktoprect; + SDL_GetDisplayBounds(0, &desktoprect); + desktop_window.hwnd = HWND_DESKTOP; + desktop_window.w = desktoprect.w; + desktop_window.h = desktoprect.h; + + AnchorBlock *anchor = calloc(1, sizeof (AnchorBlock)); + if (anchor == NULL) { + return NULLHANDLE; + } + + anchor->windows_array_len = 16; + anchor->windows = (Window *) malloc(sizeof (Window) * anchor->windows_array_len); + if (!anchor->windows) { + free(anchor); + return NULLHANDLE; + } + memset(anchor->windows, '\0', sizeof (Window) * anchor->windows_array_len); + + anchor->pres_spaces_array_len = 16; + anchor->pres_spaces = (PresentationSpace *) malloc(sizeof (PresentationSpace) * anchor->pres_spaces_array_len); + if (!anchor->pres_spaces) { + free(anchor->windows); + free(anchor); + return NULLHANDLE; + } + memset(anchor->pres_spaces, '\0', sizeof (PresentationSpace) * anchor->pres_spaces_array_len); + + const int ihab = SDL_AtomicAdd(&GHABCounter, 1) + 1; + if (ihab <= 0) { // this is clearly a pathological program. + free(anchor->pres_spaces); + free(anchor->windows); + free(anchor); + return NULLHANDLE; + } + + const HAB hab = (HAB) ihab; + anchor->hab = hab; + posttib->anchor_block = anchor; + + return hab; +} // WinInitialize + +static MRESULT sendMessage(Window *win, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + PFNWP winproc = win->window_proc; + if (!winproc) { + winproc = WinDefWindowProc; + } + TRACE_EVENT("EVENT SEND { hwnd=%u, msg=%u (%s), mp1=%p, mp2=%p, proc=%p }", (unsigned int) win->hwnd, (unsigned int) msg, messageName(msg), mp1, mp2, winproc); + return winproc(win->hwnd, msg, mp1, mp2); +} // sendMessage + +static BOOL destroyMessageQueue(AnchorBlock *anchor) +{ + MessageQueueItem *next = NULL; + for (MessageQueueItem *i = anchor->message_queue.head; i; i = next) { + next = i->next; + free(i); + } + for (MessageQueueItem *i = anchor->message_queue.free_pool; i; i = next) { + next = i->next; + free(i); + } + TRACE_EVENT("HMQ %u destroyed", (unsigned int) anchor->message_queue.hmq); + memset(&anchor->message_queue, '\0', sizeof (MessageQueue)); + return TRUE; +} // destroyMessageQueue + +static void destroyWindow(AnchorBlock *anchor, Window *win) +{ + if (!win || (win->hwnd == NULLHANDLE)) { + return; + } + + // !!! FIXME: hide window first, and optionally send WM_ACTIVATE message if losing focus. + // !!! FIXME: send WM_RENDERALLFMTS if we are clipboard owner and unrendered formats are in the clipboard. + + // send WM_DESTROY. This is a simple notification, and cannot prevent destruction. + sendMessage(win, WM_DESTROY, 0, 0); + + // Next, destroy all child windows. + Window *next = NULL; + for (Window *i = win->children; i != NULL; i = next) { + next = i->sibling; + destroyWindow(anchor, i); + } + + // !!! FIXME: see notes in SDK reference about disassociating/destroying HPS objects. + + // if this is a heavyweight window, destroy those parts. + if (win->parent == &desktop_window) { + SDL_DestroyTexture(win->heavy.texture); + SDL_DestroyRenderer(win->heavy.renderer); + SDL_DestroyWindow(win->heavy.window); + } + + if (win->parent->children == win) { + win->parent->children = win->sibling; + } else { + for (Window *i = win->parent->children; i != NULL; i = i->sibling) { + assert(i != win); + if (i->sibling == win) { + i->sibling = win->sibling; + break; + } + } + } + free(win->text); + free(win->data); + memset(win, '\0', sizeof (*win)); +} // destroyWindow + +static void destroyPresentationSpace(AnchorBlock *anchor, PresentationSpace *ps) +{ + if (!ps || (ps->hps == NULLHANDLE)) { + return; + } + FIXME("this will be more complicated later"); + memset(ps, '\0', sizeof (*ps)); +} // destroyPresentationSpace + +BOOL WinTerminate(HAB hab) +{ + TRACE_NATIVE("WinTerminate(%u)", (unsigned int) hab); + AnchorBlock *anchor = getAnchorBlock(hab); + if (!anchor) { + return FALSE; + } + + for (size_t i = 0; i < anchor->pres_spaces_array_len; i++) { + destroyPresentationSpace(anchor, &anchor->pres_spaces[i]); + } + free(anchor->pres_spaces); + + for (size_t i = 0; i < anchor->windows_array_len; i++) { + destroyWindow(anchor, &anchor->windows[i]); + } + free(anchor->windows); + + WindowClass *winclassnext = NULL; + for (WindowClass *i = anchor->registered_classes; i; i = winclassnext) { + winclassnext = i->next; + free(i->name); + free(i); + } + + if (anchor->message_queue.hmq != NULLHANDLE) { + destroyMessageQueue(anchor); + } + + free(anchor); + getPostTib()->anchor_block = NULL; + + SDL_Quit(); // !!! FIXME: does this reference count? + + return TRUE; +} // WinTerminate + +ERRORID WinGetLastError(HAB hab) +{ + TRACE_NATIVE("WinGetLastError(%u)", (unsigned int) hab); + AnchorBlock *anchor = getAnchorBlock(hab); + if (!anchor) { + return PMERR_INVALID_HAB; + } + const ERRORID retval = anchor->last_error; + SET_WIN_ERROR_AND_RETURN(anchor, NO_ERROR, retval); +} // WinGetLastError + +HMQ WinCreateMsgQueue(HAB hab, LONG cmsg) +{ + TRACE_NATIVE("WinCreateMsgQueue(%u, %d)", (unsigned int) hab, (int) cmsg); + AnchorBlock *anchor = getAnchorBlock(hab); + if (!anchor) { + return NULLHANDLE; + } else if (anchor->message_queue.hmq != NULLHANDLE) { + SET_WIN_ERROR_AND_RETURN(anchor, PMERR_MSG_QUEUE_ALREADY_EXISTS, NULLHANDLE); + } + + // as of OS/2 Warp 4.0, cmsg is ignored (the queue is always dynamically allocated), so we ignore it too. + + assert(anchor->message_queue.head == NULL); + assert(anchor->message_queue.tail == NULL); + assert(anchor->message_queue.free_pool == NULL); + + const int ihmq = SDL_AtomicAdd(&GHMQCounter, 1) + 1; + if (ihmq <= 0) { // this is clearly a pathological program. + return NULLHANDLE; + } + + const HMQ hmq = (HMQ) ihmq; + anchor->message_queue.hmq = hmq; + TRACE_EVENT("HMQ %u created", (unsigned int) hmq); + return hmq; +} // WinCreateMsgQueue + +static ERRORID postMessage(AnchorBlock *anchor, const QMSG *qmsg) +{ + TRACE_EVENT("EVENT POST { hwnd=%u, msg=%u (%s), mp1=%p, mp2=%p, time=%u, ptl={%d,%d}, reserved=%u }", (unsigned int) qmsg->hwnd, (unsigned int) qmsg->msg, messageName(qmsg->msg), qmsg->mp1, qmsg->mp2, (unsigned int) qmsg->time, (int) qmsg->ptl.x, (int) qmsg->ptl.y, (unsigned int) qmsg->reserved); + + MessageQueueItem *item = anchor->message_queue.free_pool; + if (item) { + anchor->message_queue.free_pool = item->next; + } else { + item = (MessageQueueItem *) malloc(sizeof (*item)); + if (item == NULL) { + return FALSE; + } + } + + memcpy(&item->qmsg, qmsg, sizeof (*qmsg)); + item->next = NULL; + + assert(!anchor->message_queue.head == !anchor->message_queue.tail); + if (anchor->message_queue.tail) { + anchor->message_queue.tail->next = item; + } else { + anchor->message_queue.head = item; + } + anchor->message_queue.tail = item; + + return TRUE; +} // postMessage + +static inline Window *getWindowFromSDLWindow(SDL_Window *sdlwin) +{ + return (Window *) sdlwin ? SDL_GetWindowData(sdlwin, WINDATA_WINDOWPTR_NAME) : NULL; +} // getWindowFromSDLWindow + + +#if 0 +static Window *hittestWindow(SDL_Window *sdlwin, int x, int y) +{ + if (!sdlwin) { + return NULL; + } + + Window *win = getWindowFromSDLWindow(sdlwin); + if (!win) { + return NULL; + } + + // (win) is currently the oldest parent, which is associated with the + // SDL_Window. We need to see which lightweight child window, if any, + // this event was meant for. + + // y coordinates are flipped on OS/2. zero is the bottom of the window. + y = sdlwin->h - y; +// !!! FIXME WRITE ME + for (Window *i = + if (win->class_style & CS_HITTEST) { + sendMessage(win, WM_HITTEST, + } + +} // findWindowFromSDL +#endif + +static BOOL postTimestampedMsg(AnchorBlock *anchor, HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2, ULONG ticks) +{ + const QMSG qmsg = { hwnd, msg, mp1, mp2, currentSystemTicks(), { 0, 0 }, 0 }; + return postMessage(anchor, &qmsg); +} // postTimestampedMsg + +#if 0 +static BOOL postSimpleMsg(AnchorBlock *anchor, HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + return postTimestampedMsg(anchor, hwnd, msg, mp1, mp2, currentSystemTicks()); +} // postSimpleMsg + +#endif + +static BOOL postExposedMessages(AnchorBlock *anchor, Window *win, const ULONG ticks) +{ + FIXME("this should WinInvalidateRect() the windows, not send paint messages"); + FIXME("this is a recursive hell"); // we need to start at the end of the sibling list, which is the bottom of the stack. + BOOL retval = FALSE; + if (win) { + retval |= postExposedMessages(anchor, win->sibling, ticks); + if (win->style & WS_VISIBLE) { + FIXME("for CS_SYNCPAINT classes, this should send the WM_PAINT message right now instead of posting"); + retval |= postTimestampedMsg(anchor, win->hwnd, WM_PAINT, 0, 0, ticks); + retval |= postExposedMessages(anchor, win->children, ticks); + } + } + return retval; +} // postExposedMessages + + +static const char *sdlEventName(const SDL_EventType ev) +{ + switch (ev) { + #define EVCASE(m) case m: return #m + EVCASE(SDL_QUIT); + EVCASE(SDL_APP_TERMINATING); + EVCASE(SDL_APP_LOWMEMORY); + EVCASE(SDL_APP_WILLENTERBACKGROUND); + EVCASE(SDL_APP_DIDENTERBACKGROUND); + EVCASE(SDL_APP_WILLENTERFOREGROUND); + EVCASE(SDL_APP_DIDENTERFOREGROUND); + EVCASE(SDL_WINDOWEVENT); + EVCASE(SDL_SYSWMEVENT); + EVCASE(SDL_KEYDOWN); + EVCASE(SDL_KEYUP); + EVCASE(SDL_TEXTEDITING); + EVCASE(SDL_TEXTINPUT); + EVCASE(SDL_KEYMAPCHANGED); + EVCASE(SDL_MOUSEMOTION); + EVCASE(SDL_MOUSEBUTTONDOWN); + EVCASE(SDL_MOUSEBUTTONUP); + EVCASE(SDL_MOUSEWHEEL); + EVCASE(SDL_JOYAXISMOTION); + EVCASE(SDL_JOYBALLMOTION); + EVCASE(SDL_JOYHATMOTION); + EVCASE(SDL_JOYBUTTONDOWN); + EVCASE(SDL_JOYBUTTONUP); + EVCASE(SDL_JOYDEVICEADDED); + EVCASE(SDL_JOYDEVICEREMOVED); + EVCASE(SDL_CONTROLLERAXISMOTION); + EVCASE(SDL_CONTROLLERBUTTONDOWN); + EVCASE(SDL_CONTROLLERBUTTONUP); + EVCASE(SDL_CONTROLLERDEVICEADDED); + EVCASE(SDL_CONTROLLERDEVICEREMOVED); + EVCASE(SDL_CONTROLLERDEVICEREMAPPED); + EVCASE(SDL_FINGERDOWN); + EVCASE(SDL_FINGERUP); + EVCASE(SDL_FINGERMOTION); + EVCASE(SDL_DOLLARGESTURE); + EVCASE(SDL_DOLLARRECORD); + EVCASE(SDL_MULTIGESTURE); + EVCASE(SDL_CLIPBOARDUPDATE); + EVCASE(SDL_DROPFILE); + EVCASE(SDL_DROPTEXT); + EVCASE(SDL_DROPBEGIN); + EVCASE(SDL_DROPCOMPLETE); + EVCASE(SDL_AUDIODEVICEADDED); + EVCASE(SDL_AUDIODEVICEREMOVED); + EVCASE(SDL_RENDER_TARGETS_RESET); + EVCASE(SDL_RENDER_DEVICE_RESET); + EVCASE(SDL_USEREVENT); + #undef EVCASE + default: break; + } + return "???"; +} // sdlEventName + +static const char *sdlWindowEventName(const SDL_WindowEventID ev) +{ + switch (ev) { + #define EVCASE(m) case m: return #m + EVCASE(SDL_WINDOWEVENT_SHOWN); + EVCASE(SDL_WINDOWEVENT_HIDDEN); + EVCASE(SDL_WINDOWEVENT_EXPOSED); + EVCASE(SDL_WINDOWEVENT_MOVED); + EVCASE(SDL_WINDOWEVENT_RESIZED); + EVCASE(SDL_WINDOWEVENT_SIZE_CHANGED); + EVCASE(SDL_WINDOWEVENT_MINIMIZED); + EVCASE(SDL_WINDOWEVENT_MAXIMIZED); + EVCASE(SDL_WINDOWEVENT_RESTORED); + EVCASE(SDL_WINDOWEVENT_ENTER); + EVCASE(SDL_WINDOWEVENT_LEAVE); + EVCASE(SDL_WINDOWEVENT_FOCUS_GAINED); + EVCASE(SDL_WINDOWEVENT_FOCUS_LOST); + EVCASE(SDL_WINDOWEVENT_CLOSE); + EVCASE(SDL_WINDOWEVENT_TAKE_FOCUS); + EVCASE(SDL_WINDOWEVENT_HIT_TEST); + #undef EVCASE + default: break; + } + return "???"; +} // sdlWindowEventName + +static BOOL processSDLEvent(AnchorBlock *anchor, const SDL_Event *sdlevent) +{ + // !!! FIXME: we just drop events if we run out of memory, etc. + + // !!! FIXME: QMSG::time appears to be milliseconds since the system + // !!! FIXME: booted (presumably rolling over every 38 days). SDL's + // !!! FIXME: event timestamps (and SDL_GetTicks()) are milliseconds + // !!! FIXME: since SDL_Init(), which is more or less since app startup. + // !!! FIXME: We might need a way to map these, so they're consistent + // !!! FIXME: across processes. + // !!! FIXME: Also, it's well known that SDL event timestamps are when + // !!! FIXME: SDL gets the event from the OS, not the timestamp of when + // !!! FIXME: the OS generated it, which might be a problem. + +/* +sdfsdf + HWND hwnd; + ULONG msg; + MPARAM mp1; + MPARAM mp2; + ULONG time; + POINTL ptl; + ULONG reserved; +sdfsdf +*/ + +//SDL_GetWindowFromID(window) sdfsdf + + const ULONG ticks = (ULONG) sdlevent->common.timestamp; + + TRACE_EVENT("EVENT SDL { type=0x%X (%s) }", (unsigned int) sdlevent->type, sdlEventName(sdlevent->type)); + + switch (sdlevent->type) { + case SDL_QUIT: + return postTimestampedMsg(anchor, NULLHANDLE, WM_QUIT, 0, 0, ticks); + + case SDL_WINDOWEVENT: + TRACE_EVENT("EVENT SDL WINDOW { type=0x%X (%s) }", (unsigned int) sdlevent->window.event, sdlWindowEventName(sdlevent->window.event)); + switch (sdlevent->window.event) { + case SDL_WINDOWEVENT_SHOWN: + case SDL_WINDOWEVENT_EXPOSED: { + // maybe this doesn't matter in a world of compositing window managers, but it would be nice to completely avoid sending WM_PAINT to child windows that otherwise don't apply. + // This only applies for heavyweight windows the OS is marking as exposed, not OS/2 apps marking OS/2 HWNDs as invalid for various reasons. + FIXME("SDL doesn't report invalid subregions, just that a window needs repainting"); + Window *win = getWindowFromSDLWindow(SDL_GetWindowFromID(sdlevent->window.windowID)); + if (!win) { + return FALSE; + } + return postExposedMessages(anchor, win, ticks); + } + + default: break; // not (currently) supported. + } + return FALSE; + + + +#if 0 + case SDL_WINDOWEVENT_SHOWN: + case SDL_WINDOWEVENT_HIDDEN: + case SDL_WINDOWEVENT_MOVED, /**< Window has been moved to data1, data2 + */ + case SDL_WINDOWEVENT_RESIZED, /**< Window has been resized to data1xdata2 */ + case SDL_WINDOWEVENT_SIZE_CHANGED, /**< The window size has changed, either as + a result of an API call or through the + system or user changing the window size. */ + case SDL_WINDOWEVENT_MINIMIZED, /**< Window has been minimized */ + case SDL_WINDOWEVENT_MAXIMIZED, /**< Window has been maximized */ + case SDL_WINDOWEVENT_RESTORED, /**< Window has been restored to normal size + and position */ + case SDL_WINDOWEVENT_ENTER, /**< Window has gained mouse focus */ + case SDL_WINDOWEVENT_LEAVE, /**< Window has lost mouse focus */ + case SDL_WINDOWEVENT_FOCUS_GAINED, /**< Window has gained keyboard focus */ + case SDL_WINDOWEVENT_FOCUS_LOST, /**< Window has lost keyboard focus */ + case SDL_WINDOWEVENT_CLOSE, /**< The window manager requests that the window be closed */ + case SDL_WINDOWEVENT_TAKE_FOCUS, /**< Window is being offered a focus (should SetWindowInputFocus() on itself or a subwindow, or ignore) */ + //case SDL_WINDOWEVENT_HIT_TEST /**< Window had a hit test that wasn't SDL_HITTEST_NORMAL. */ + + +// SDL_MOUSEMOTION = 0x400, /**< Mouse moved */ +// SDL_MOUSEBUTTONDOWN, /**< Mouse button pressed */ +// SDL_MOUSEBUTTONUP, /**< Mouse button released */ +// SDL_MOUSEWHEEL, /**< Mouse wheel motion */ +// SDL_KEYDOWN = 0x300, /**< Key pressed */ +// SDL_KEYUP, /**< Key released */ +// SDL_TEXTINPUT, /**< Keyboard text input */ +// SDL_CLIPBOARDUPDATE = 0x900, /**< The clipboard changed */ +// SDL_DROPFILE = 0x1000, /**< The system requests a file open */ +// SDL_DROPTEXT, /**< text/plain drag-and-drop event */ +// SDL_DROPBEGIN, /**< A new set of drops is beginning (NULL filename) */ +// SDL_DROPCOMPLETE, /**< Current set of drops is now complete (NULL filename) */ + + + case SDL_MOUSEBUTTONDOWN: + + case SDL_MOUSEBUTTONUP: + if (sdlevent->button.clicks == 1) {} +#endif + + + default: return FALSE; // not (currently) supported. + } + + assert(!"shouldn't hit this"); + return TRUE; +} // processSDLEvent + +static void pumpEvents(AnchorBlock *anchor) +{ + SDL_Event sdlevent; + BOOL queued = FALSE; + + // run through anything pending. If we don't post anything to the OS/2 + // event queue, we need to block until we do, though, so then we'll use + // SDL_WaitEvent() in hopes that someday it's fully waitable. + while (SDL_PollEvent(&sdlevent)) { + queued |= processSDLEvent(anchor, &sdlevent); + } + + while (!queued) { // block until stuff shows up. + while (!SDL_WaitEvent(&sdlevent)) { + SDL_Delay(10); // dunno what else to do here... + } + queued |= processSDLEvent(anchor, &sdlevent); + while (SDL_PollEvent(&sdlevent)) { // catch anything else pending. + queued |= processSDLEvent(anchor, &sdlevent); + } + } +} // waitForMessage + +static BOOL skipMessage(const PQMSG qmsg, HWND hwndFilter, ULONG msgFilterFirst, ULONG msgFilterLast) +{ + if (hwndFilter && (qmsg->hwnd != hwndFilter)) { + return TRUE; + } else if (msgFilterFirst || msgFilterLast) { + const ULONG msg = qmsg->msg; + if (msgFilterFirst > msgFilterLast) { // reject if between first and last. + if ((msg >= msgFilterLast) && (msg <= msgFilterFirst)) return TRUE; + } else { // reject if not between first and last. + if ((msg < msgFilterFirst) || (msg > msgFilterLast)) return TRUE; + } + } + return FALSE; +} // skipMessage + +BOOL WinGetMsg(HAB hab, PQMSG pqmsg, HWND hwndFilter, ULONG msgFilterFirst, ULONG msgFilterLast) +{ + TRACE_NATIVE("WinGetMsg(%u, %p, %u, %u, %u)", (unsigned int) hab, pqmsg, (unsigned int) hwndFilter, (unsigned int) msgFilterFirst, (unsigned int) msgFilterLast); + const BOOL bIsFiltering = (hwndFilter || msgFilterFirst || msgFilterLast); + AnchorBlock *anchor = getAnchorBlock(hab); + if (!anchor) { + return FALSE; + } else if (hwndFilter) { + FIXME("fail with PMERR_INVALID_HWND if this is a bogus HWND."); + } + + while (1) { + MessageQueueItem *prev = NULL; + MessageQueueItem *i = anchor->message_queue.head; + if (bIsFiltering) { + for (; i != NULL; prev = i, i = i->next) { + if (!skipMessage(&i->qmsg, hwndFilter, msgFilterFirst, msgFilterLast)) { + break; + } + } + } + + // Found an event? Remove from queue, return that info. + if (i != NULL) { + memcpy(pqmsg, &i->qmsg, sizeof (QMSG)); + + TRACE_EVENT("EVENT GET { hwnd=%u, msg=%u (%s), mp1=%p, mp2=%p, time=%u, ptl={%d,%d}, reserved=%u }", (unsigned int) pqmsg->hwnd, (unsigned int) pqmsg->msg, messageName(pqmsg->msg), pqmsg->mp1, pqmsg->mp2, (unsigned int) pqmsg->time, (int) pqmsg->ptl.x, (int) pqmsg->ptl.y, (unsigned int) pqmsg->reserved); + + if (prev) { + prev->next = i->next; + } else { + anchor->message_queue.head = i->next; + } + + if (!anchor->message_queue.head) { + assert(anchor->message_queue.tail == i); + anchor->message_queue.tail = NULL; + } + + i->next = anchor->message_queue.free_pool; + anchor->message_queue.free_pool = i; + + return (pqmsg->msg != WM_QUIT) ? TRUE : FALSE; + } + + pumpEvents(anchor); // may block. + } + + assert(!"shouldn't hit this."); + return TRUE; // shouldn't hit this. +} // WinGetMsg + +MRESULT WinDispatchMsg(HAB hab, PQMSG pqmsg) +{ + TRACE_NATIVE("WinDispatchMsg(%u, %p)", (unsigned int) hab, pqmsg); + AnchorBlock *anchor = getAnchorBlock(hab); + if (anchor) { + Window *win = getWindowFromHWND(anchor, pqmsg->hwnd); + if (win) { + return sendMessage(win, pqmsg->msg, pqmsg->mp1, pqmsg->mp2); + } + } + return 0; +} // WinDispatchMsg + +BOOL WinDestroyMsgQueue(HMQ hmq) +{ + TRACE_NATIVE("WinDestroyMsgQueue(%u)", (unsigned int) hmq); + AnchorBlock *anchor = getAnchorBlockNoHAB(); + if (!anchor) { + return FALSE; + } else if ((hmq == NULLHANDLE) || (anchor->message_queue.hmq != hmq)) { + SET_WIN_ERROR_AND_RETURN(anchor, PMERR_INVALID_HMQ, FALSE); + } + + return destroyMessageQueue(anchor); +} // WinDestroyMsgQueue + +BOOL WinRegisterClass(HAB hab, PSZ pszClassName, PFNWP pfnWndProc, ULONG flStyle, ULONG cbWindowData) +{ + TRACE_NATIVE("WinRegisterClass(%u, '%s', %p, %u, %u)", (unsigned int) hab, pszClassName, pfnWndProc, (unsigned int) flStyle, (unsigned int) cbWindowData); + + AnchorBlock *anchor = getAnchorBlock(hab); + if (!anchor) { + return FALSE; + } + + WindowClass *winclass = findRegisteredClass(anchor, pszClassName); + if (!winclass) { // PM docs say this call can replace existing class. + winclass = (WindowClass *) malloc(sizeof (WindowClass)); + if (!winclass) { + SET_WIN_ERROR_AND_RETURN(anchor, PMERR_HEAP_OUT_OF_MEMORY, FALSE); + } else if ((winclass->name = strdup(pszClassName)) == NULL) { + free(winclass); + SET_WIN_ERROR_AND_RETURN(anchor, PMERR_HEAP_OUT_OF_MEMORY, FALSE); + } + winclass->next = anchor->registered_classes; + anchor->registered_classes = winclass; + } + + winclass->window_proc = pfnWndProc; + winclass->style = flStyle; + winclass->data_len = cbWindowData; + + return TRUE; +} // WinRegisterClass + +MRESULT WinSendMsg(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + // !!! FIXME: This needs to be able to send to windows in different + // !!! FIXME: threads (and processes!), so this will need some effort to + // !!! FIXME: support. + + TRACE_NATIVE("WinSendMsg(%u, %u, %p, %p)", (unsigned int) hwnd, (unsigned int) msg, mp1, mp2); + AnchorBlock *anchor = getAnchorBlockNoHAB(); + if (anchor) { + Window *win = getWindowFromHWND(anchor, hwnd); + if (win) { + return sendMessage(win, msg, mp1, mp2); + } + } + return (MRESULT) 0; +} // WinSendMsg + +BOOL WinPostMsg(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + // !!! FIXME: SDL docs say you can call this, but not WinSendMsg() if + // !!! FIXME: the thread doesn't have a message queue, but that has to + // !!! FIXME: be a typo, right? How do you post a message to a queue that + // !!! FIXME: doesn't exist? But one could call a window procedure + // !!! FIXME: directly... + + // !!! FIXME: This needs to be able to post to windows in different + // !!! FIXME: threads (and processes!), so this will need some effort to + // !!! FIXME: support. + + TRACE_NATIVE("WinPostMsg(%u, %u, %p, %p)", (unsigned int) hwnd, (unsigned int) msg, mp1, mp2); + AnchorBlock *anchor = getAnchorBlockNoHAB(); + if (!anchor) { + return FALSE; + } + if (anchor->message_queue.hmq == NULLHANDLE) { + SET_WIN_ERROR_AND_RETURN(anchor, PMERR_NO_MSG_QUEUE, FALSE); + } + + Window *win = getWindowFromHWND(anchor, hwnd); + if (!win) { + SET_WIN_ERROR_AND_RETURN(anchor, PMERR_INVALID_HWND, FALSE); + } + + int mousex, mousey; + SDL_GetGlobalMouseState(&mousex, &mousey); FIXME("track this ourselves?"); + const QMSG qmsg = { hwnd, msg, mp1, mp2, currentSystemTicks(), { mousex, mousey }, 0 }; + const ERRORID rc = postMessage(anchor, &qmsg); + if (rc) { + SET_WIN_ERROR_AND_RETURN(anchor, rc, FALSE); + } + + return TRUE; +} // WinPostMsg + +BOOL WinPostQueueMsg(HMQ hmq, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + TRACE_NATIVE("WinPostMsgQueue(%u, %u, %p, %p)", (unsigned int) hmq, (unsigned int) msg, mp1, mp2); + // I assume this works like win32's PostThreadMessage(), in that there + // isn't a target HWND, so the target thread would have to deal with this + // message after a call to WinGetMsg() and not in a window procedure + // during a call to WinDispatchMsg(). + + // (!!! FIXME: right now these are stored on the anchor block and not + // anywhere global I can reach it.) + FIXME("need to be able to access other threads' message queues"); + return FALSE; +} // WinPostQueueMsg + +HWND WinCreateWindow(HWND hwndParent, PSZ pszClass, PSZ pszName, ULONG flStyle, LONG x, LONG y, LONG cx, LONG cy, HWND hwndOwner, HWND hwndInsertBehind, ULONG id, PVOID pCtlData, PVOID pPresParams) +{ + TRACE_NATIVE("WinCreateWindow(%u, '%s', '%s', %u, %d, %d, %d, %d, %u, %u, %u, %p, %p)", (unsigned int) hwndParent, pszClass, pszName, (unsigned int) flStyle, (int) x, (int) y, (int) cx, (int) cy, (unsigned int) hwndOwner, hwndInsertBehind, (unsigned int) id, pCtlData, pPresParams); + + AnchorBlock *anchor = getAnchorBlockNoHAB(); + if (!anchor) { + return NULLHANDLE; + } + + if (anchor->message_queue.hmq == NULLHANDLE) { + SET_WIN_ERROR_AND_RETURN(anchor, PMERR_NO_MSG_QUEUE, NULLHANDLE); + } + + const WindowClass *winclass = findRegisteredClass(anchor, pszClass); + if (!winclass) { + SET_WIN_ERROR_AND_RETURN(anchor, PMERR_INVALID_PARM, NULLHANDLE); + } + + Window *parent = getWindowFromHWND(anchor, hwndParent); + if (!parent) { + SET_WIN_ERROR_AND_RETURN(anchor, PMERR_INVALID_HWND, NULLHANDLE); + } + + Window *owner = NULL; + if (hwndOwner != NULLHANDLE) { + owner = getWindowFromHWND(anchor, hwndParent); + if (!owner) { + SET_WIN_ERROR_AND_RETURN(anchor, PMERR_INVALID_HWND, NULLHANDLE); + } + } + + // make space for the new window struct in the anchor block + Window *win = NULL; + FIXME("optimize this"); + for (size_t i = 0; i < anchor->windows_array_len; i++) { + if (anchor->windows[i].hwnd == NULLHANDLE) { + win = &anchor->windows[i]; + break; + } + } + + if (!win) { + const size_t len = anchor->windows_array_len; + void *ptr = realloc(anchor->windows, sizeof (Window) * len * 2); + if (!ptr) { + SET_WIN_ERROR_AND_RETURN(anchor, PMERR_HEAP_OUT_OF_MEMORY, NULLHANDLE); + } + anchor->windows = (Window *) ptr; + memset(&anchor->windows[len], '\0', sizeof (Window) * len); + win = &anchor->windows[len]; + anchor->windows_array_len *= 2; + } + + char *text = NULL; + if (pszName) { + // !!! FIXME: text isn't necessarily a string. It's window-class-specific data. + text = strdup(pszName); + if (!text) { + SET_WIN_ERROR_AND_RETURN(anchor, PMERR_HEAP_OUT_OF_MEMORY, NULLHANDLE); + } + } + + void *data = NULL; + if (winclass->data_len > 0) { + data = malloc(winclass->data_len); + if (!data) { + free(text); + SET_WIN_ERROR_AND_RETURN(anchor, PMERR_HEAP_OUT_OF_MEMORY, NULLHANDLE); + } + } + + if (hwndParent == HWND_DESKTOP) { // toplevel? build a heavy weight window. + Uint32 sdlflags = SDL_WINDOW_HIDDEN | SDL_WINDOW_BORDERLESS; + // !!! FIXME SDL_WINDOW_SKIP_TASKBAR = 0x00010000, /**< window should not be added to the taskbar */ + // !!! FIXME: text isn't necessarily a string. It's window-class-specific data. + // The Y coordinate is the bottom of the window, counted from the bottom of the parent window (desktop, in this case) :/ + SDL_Window *window = SDL_CreateWindow(text ? text : "", x, (desktop_window.h - y) - cy, cx, cy, sdlflags); + if (!window) { + free(text); + free(data); + FIXME("error code?"); + SET_WIN_ERROR_AND_RETURN(anchor, PMERR_INTERNAL_ERROR_1, NULLHANDLE); + } + + SDL_SetWindowData(window, WINDATA_WINDOWPTR_NAME, win); + + SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_TARGETTEXTURE); + if (!renderer) { + free(text); + free(data); + SDL_DestroyWindow(window); + FIXME("error code?"); + SET_WIN_ERROR_AND_RETURN(anchor, PMERR_INTERNAL_ERROR_1, NULLHANDLE); + } + + SDL_RendererInfo info; + SDL_GetRendererInfo(renderer, &info); FIXME("handle failure here"); + + SDL_Texture *texture = SDL_CreateTexture(renderer, info.texture_formats[0], SDL_TEXTUREACCESS_TARGET, cx, cy); + if (!texture) { + free(text); + free(data); + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); + FIXME("error code?"); + SET_WIN_ERROR_AND_RETURN(anchor, PMERR_INTERNAL_ERROR_1, NULLHANDLE); + } + + SDL_SetRenderTarget(renderer, texture); + + win->heavy.window = window; + win->heavy.renderer = renderer; + win->heavy.texture = texture; + } else { // use same heavy as parent. + win->heavy.window = parent->heavy.window; + win->heavy.renderer = parent->heavy.renderer; + win->heavy.texture = parent->heavy.texture; + } + + win->parent = parent; + win->children = NULL; + win->hwnd = (HWND) (((size_t) (win - anchor->windows)) + FIRST_HWND_VALUE); + win->window_class_name = winclass->name; // this pointer lives until Anchor Block terminates. + win->data = data; + win->text = text; + win->data_len = winclass->data_len; + win->window_proc = winclass->window_proc; + win->class_style = winclass->style; + win->style = flStyle; + win->id = id; + win->owner = owner; + win->sibling = NULL; // we'll insert this later. + win->x = win->y = win->w = win->h = 0; // we'll set these later. + + // we're ready, send WM_CREATE. Note that pCtlData has to be a pointer (not + // an integer cast to a pointer), because OS/2 would dereference it, and the + // 16 bits at the start of the data it points to tell you how many bytes are + // pointed at, so it could deal with 16-bit code. We don't (currently) care, + // so just pass it on. + if (sendMessage(win, WM_CREATE, pCtlData, pPresParams) != FALSE) { + // response to WM_CREATE was to cancel window creation!! + destroyWindow(anchor, win); + return NULLHANDLE; + } + + FIXME("should I set swp.fl here?"); + SWP swp = { 0, cy, cx, y, x, hwndInsertBehind, win->hwnd, 0, 0 }; + MRESULT adjust = sendMessage(win, WM_ADJUSTWINDOWPOS, &swp, 0); + + (void) adjust; FIXME("adjust based on WM_ADJUSTWINDOWPOS message result"); + + win->x = swp.x; + win->y = swp.y; + win->w = swp.cx; + win->h = swp.cy; + hwndInsertBehind = swp.hwndInsertBehind; + + Window *insertBehind = NULL; + if ((hwndInsertBehind != HWND_TOP) && (hwndInsertBehind != HWND_BOTTOM)) { + insertBehind = getWindowFromHWND(anchor, hwndInsertBehind); + if (!insertBehind || (insertBehind->parent != parent)) { + FIXME("should we fail or just insert at top/bottom?"); + hwndInsertBehind = HWND_BOTTOM; + insertBehind = NULL; + } + } + + if (parent->children == NULL) { // nothing to insert behind, just make it the only child. + parent->children = win; + } else if (hwndInsertBehind == HWND_TOP) { + win->sibling = parent->children; + parent->children = win; + } else if (hwndInsertBehind == HWND_BOTTOM) { + Window *prev = NULL; + for (Window *i = parent->children; i != NULL; i = i->sibling) { + prev = i; + } + prev->sibling = win; + } else { // insert behind a specific window. + win->sibling = insertBehind->sibling; + insertBehind->sibling = win; + } + + if (hwndParent == HWND_DESKTOP) { + SDL_SetWindowPosition(win->heavy.window, win->x, (parent->h - win->y) - win->h); + SDL_SetWindowSize(win->heavy.window, win->w, win->h); + if (win->style & WS_VISIBLE) { + // !!! FIXME: mark window region invalid + SDL_ShowWindow(win->heavy.window); + } + } + + return win->hwnd; +} // WinCreateWindow + +HWND WinCreateStdWindow(HWND hwndParent, ULONG flStyle, PULONG pflCreateFlags, PSZ pszClientClass, PSZ pszTitle, ULONG styleClient, HMODULE hmod, ULONG idResources, PHWND phwndClient) +{ + TRACE_NATIVE("WinCreateStdWindow(%u, %u, %p, '%s', '%s', %u, %u, %u, %p)", (unsigned int) hwndParent, (unsigned int) flStyle, pflCreateFlags, pszClientClass, pszTitle, (unsigned int) styleClient, (unsigned int) hmod, (unsigned int) idResources, phwndClient); + + if (phwndClient) { + *phwndClient = NULLHANDLE; + } + + FRAMECDATA fcd = { sizeof (FRAMECDATA), *pflCreateFlags, hmod, idResources }; + HWND retval = WinCreateWindow(hwndParent, (PSZ) WC_FRAME, pszTitle, 0, 0, 0, 0, 0, NULLHANDLE, HWND_TOP, idResources, &fcd, NULL); + if (!retval) { + return NULLHANDLE; + } + + if (pszClientClass) { + HWND clientwin = WinCreateWindow(retval, pszClientClass, NULL, 0, 0, 0, 0, 0, retval, HWND_BOTTOM, FID_CLIENT, NULL, NULL); + if (!clientwin) { + WinDestroyWindow(retval); + return NULLHANDLE; + } + if (phwndClient) { + *phwndClient = clientwin; + } + } + + return retval; +} // WinCreateStdWindow + +BOOL WinDestroyWindow(HWND hwnd) +{ + TRACE_NATIVE("WinDestroyWindow(%u)", (unsigned int) hwnd); + AnchorBlock *anchor = getAnchorBlockNoHAB(); + if (!anchor) { + return FALSE; + } + + Window *win = getWindowFromHWND(anchor, hwnd); + if (!win) { + SET_WIN_ERROR_AND_RETURN(anchor, PMERR_INVALID_HWND, FALSE); + } + + destroyWindow(anchor, win); + + return TRUE; +} // WinDestroyWindow + +MRESULT WinDefWindowProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + TRACE_NATIVE("WinDefWindowProc(%u, %u, %p, %p)", (unsigned int) hwnd, (unsigned int) msg, mp1, mp2); + + AnchorBlock *anchor = getAnchorBlockNoHAB(); + if (!anchor) { + return (MRESULT) 0; + } + Window *win = getWindowFromHWND(anchor, hwnd); + if (!win) { + return (MRESULT) 0; + } + + switch (msg) { + // this whole block just returns zero without further processing. + case WM_ACTIVATE: + case WM_APPTERMINATENOTIFY: + case WM_ADJUSTWINDOWPOS: + case WM_CALCFRAMERECT: + case WM_COMMAND: + case WM_CONTROL: + case WM_CREATE: + case WM_CTLCOLORCHANGE: + case WM_DESTROY: + case WM_DRAWITEM: + case WM_ENABLE: + case WM_ERASEBACKGROUND: + case WM_ERROR: + case WM_FORMATFRAME: + case WM_HSCROLL: + case WM_INITDLG: + case WM_INITMENU: + case WM_JOURNALNOTIFY: + case WM_MATCHMNEMONIC: + case WM_MEASUREITEM: + case WM_MENUEND: + case WM_MINMAXFRAME: + case WM_MOUSEMAP: + case WM_MOVE: + case WM_NEXTMENU: + case WM_NULL: + case WM_PCONTROL: + case WM_PRESPARAMCHANGED: + case WM_PSETFOCUS: + case WM_PSIZE: + case WM_PSYSCOLORCHANGE: + case WM_QUERYACCELTABLE: + case WM_QUIT: + case WM_SAVEAPPLICATION: + case WM_SEM1: + case WM_SEM2: + case WM_SEM3: + case WM_SEM4: + case WM_SETACCELTABLE: + case WM_SETFOCUS: + case WM_SETHELPINFO: + case WM_SETSELECTION: + case WM_SETWINDOWPARAMS: + case WM_SHOW: + case WM_SIZE: + case WM_SUBSTITUTESTRING: + case WM_SYSCOLORCHANGE: + case WM_SYSCOMMAND: + case WM_SYSVALUECHANGED: + case WM_TIMER: + case WM_TRACKFRAME: + case WM_TRANSLATEACCEL: + //case WM_TRANSLATEMNEMONIC: // !!! FIXME: this is in the SDK reference but not the SDK headers. + case WM_UPDATEFRAME: + case WM_VRNDISABLED: + case WM_VRNENABLED: + case WM_VSCROLL: + + // the SDK reference manual doesn't list default actions for these messages, but it's probably just "return zero". + case WM_MSGBOXINIT: + case WM_MSGBOXDISMISS: + + return (MRESULT) 0; + + // this whole block just returns one without further processing. + case WM_MENUSELECT: + return (MRESULT) 1; + + // this block sends the message to the window owner (if one exists), or otherwise returns 0. + case WM_BEGINDRAG: + case WM_BEGINSELECT: + case WM_BUTTON1CLICK: + case WM_BUTTON1DBLCLK: + case WM_BUTTON1MOTIONSTART: + case WM_BUTTON1MOTIONEND: + case WM_BUTTON1UP: + case WM_BUTTON2CLICK: + case WM_BUTTON2DBLCLK: + case WM_BUTTON2MOTIONSTART: + case WM_BUTTON2MOTIONEND: + case WM_BUTTON2UP: + case WM_BUTTON3CLICK: + case WM_BUTTON3DBLCLK: + case WM_BUTTON3MOTIONSTART: + case WM_BUTTON3MOTIONEND: + case WM_BUTTON3UP: + case WM_CHAR: + case WM_CHORD: + case WM_CONTEXTMENU: + case WM_ENDDRAG: + case WM_ENDSELECT: + case WM_OPEN: + case WM_PACTIVATE: + case WM_QUERYCTLTYPE: + case WM_QUERYHELPINFO: + case WM_QUERYTRACKINFO: + case WM_SINGLESELECT: + case WM_TEXTEDIT: + return win->owner ? sendMessage(win->owner, msg, mp1, mp2) : (MRESULT) 0; + + // These messages actually do something specific in default processing... + case WM_HITTEST: + return HT_NORMAL; + + case WM_BUTTON1DOWN: + case WM_BUTTON2DOWN: + case WM_BUTTON3DOWN: + case WM_CALCVALIDRECTS: + case WM_CLOSE: + case WM_CONTROLPOINTER: + case WM_FOCUSCHANGE: + case WM_HELP: + case WM_MOUSEMOVE: + case WM_PAINT: + case WM_PPAINT: + case WM_QUERYCONVERTPOS: + case WM_QUERYWINDOWPARAMS: + case WM_REALIZEPALETTE: + case WM_WINDOWPOSCHANGED: + fprintf(stderr, "Message that doesn't something other than return 0, %u, in WinDefWindowProc!\n", (unsigned int) msg); + break; + + default: + fprintf(stderr, "Unhandled message %u in WinDefWindowProc!\n", (unsigned int) msg); + break; + } + + return (MRESULT) 0; +} // WinDefWindowProc + +HPS WinBeginPaint(HWND hwnd, HPS hps, PRECTL prclPaint) +{ + TRACE_NATIVE("WinBeginPaint(%u, %u, %p)", (unsigned int) hwnd, (unsigned int) hps, prclPaint); + AnchorBlock *anchor = getAnchorBlockNoHAB(); + if (!anchor) { + return NULLHANDLE; + } + Window *win = getWindowFromHWND(anchor, hwnd); + if (!win) { + SET_WIN_ERROR_AND_RETURN(anchor, PMERR_INVALID_HWND, NULLHANDLE); + } + + PresentationSpace *ps = NULL; + if (hps != NULLHANDLE) { + ps = getPresentationSpaceFromHPS(anchor, hps); + if (!ps) { + SET_WIN_ERROR_AND_RETURN(anchor, PMERR_INV_HPS, NULLHANDLE); + } + FIXME("check if this is already assigned to this drawable"); + } else { + // make space for the new presentation struct in the anchor block + FIXME("optimize this"); + FIXME("cut-and-paste from WinCreateWindow"); + for (size_t i = 0; i < anchor->pres_spaces_array_len; i++) { + if (anchor->pres_spaces[i].hps == NULLHANDLE) { + ps = &anchor->pres_spaces[i]; + break; + } + } + + if (!ps) { + const size_t len = anchor->pres_spaces_array_len; + void *ptr = realloc(anchor->pres_spaces, sizeof (PresentationSpace) * len * 2); + if (!ptr) { + SET_WIN_ERROR_AND_RETURN(anchor, PMERR_HEAP_OUT_OF_MEMORY, NULLHANDLE); + } + anchor->pres_spaces = (PresentationSpace *) ptr; + memset(&anchor->pres_spaces[len], '\0', sizeof (PresentationSpace) * len); + ps = &anchor->pres_spaces[len]; + anchor->pres_spaces_array_len *= 2; + } + hps = (HPS) (((size_t) (ps - anchor->pres_spaces)) + FIRST_HPS_VALUE); + } + + ps->hps = hps; + ps->window = win; + + if (prclPaint) { + FIXME("report the update region, not the whole window"); + prclPaint->xLeft = 0; + prclPaint->yBottom = 0; + prclPaint->xRight = win->w; + prclPaint->yTop = win->h; + } + + return hps; +} // WinBeginPaint + +BOOL WinEndPaint(HPS hps) +{ + TRACE_NATIVE("WinEndPaint(%u)", (unsigned int) hps); + AnchorBlock *anchor = getAnchorBlockNoHAB(); + if (!anchor) { + return NULLHANDLE; + } + PresentationSpace *ps = getPresentationSpaceFromHPS(anchor, hps); + if (!ps) { + SET_WIN_ERROR_AND_RETURN(anchor, PMERR_INV_HPS, NULLHANDLE); + } + + Window *win = ps->window; + SDL_Renderer *renderer = win->heavy.renderer; + SDL_Texture *texture = win->heavy.texture; + assert(SDL_GetRenderTarget(renderer) == texture); + SDL_SetRenderTarget(renderer, NULL); + SDL_RenderCopy(renderer, texture, NULL, NULL); + SDL_RenderPresent(renderer); + SDL_SetRenderTarget(renderer, texture); + + destroyPresentationSpace(anchor, ps); + return TRUE; +} // WinEndPaint + +static void os2ColorIndexToRGB(const LONG os2color, Uint8 *r, Uint8 *g, Uint8 *b) +{ + assert(r != NULL); assert(g != NULL); assert(b != NULL); + #define RETURNRGB(rr,gg,bb) { *r = rr; *g = gg; *b = bb; return; } + switch (os2color) { + case CLR_FALSE: FIXME("this should reverse on a printer"); RETURNRGB(0x00, 0x00, 0x00); + case CLR_TRUE: FIXME("this should reverse on a printer"); RETURNRGB(0xFF, 0xFF, 0xFF); + case CLR_DEFAULT: FIXME("Let users specify this on command line or system-wide .ini?"); RETURNRGB(0x00, 0x00, 0x00); + case CLR_WHITE: RETURNRGB(0xFF, 0xFF, 0xFF); + case CLR_BLACK: RETURNRGB(0x00, 0x00, 0x00); + case CLR_BACKGROUND: FIXME("Let users specify this on command line or system-wide .ini?"); RETURNRGB(0xFF, 0xFF, 0xFF); + case CLR_BLUE: RETURNRGB(0x00, 0x00, 0xFF); + case CLR_RED: RETURNRGB(0xFF, 0x00, 0x00); + case CLR_PINK: RETURNRGB(0xFF, 0x00, 0xFF); + case CLR_GREEN: RETURNRGB(0x00, 0xFF, 0x00); + case CLR_CYAN: RETURNRGB(0x00, 0xFF, 0xFF); + case CLR_YELLOW: RETURNRGB(0xFF, 0xFF, 0x00); + case CLR_NEUTRAL: FIXME("Let users specify this on command line or system-wide .ini?"); RETURNRGB(0x00, 0x00, 0x00); + case CLR_DARKGRAY: RETURNRGB(0x80, 0x80, 0x80); + case CLR_DARKBLUE: RETURNRGB(0x00, 0x00, 0x80); + case CLR_DARKRED: RETURNRGB(0x80, 0x00, 0x00); + case CLR_DARKPINK: RETURNRGB(0x80, 0x00, 0x80); + case CLR_DARKGREEN: RETURNRGB(0x00, 0x80, 0x00); + case CLR_DARKCYAN: RETURNRGB(0x00, 0x80, 0x80); + case CLR_BROWN: RETURNRGB(0x80, 0x80, 0x00); + case CLR_PALEGRAY: RETURNRGB(0xCC, 0xCC, 0xCC); + default: break; + } + + FIXME("unknown color index"); + RETURNRGB(0x00, 0x00, 0x00); + #undef RETURNRGB +} // os2ColorIndexToRGB + +static void calcHeavyweightRect(const Window *win, SDL_Rect* rect) +{ + int x = 0, y = 0; + + rect->w = win->w; + rect->h = win->h; + + while (win->parent != &desktop_window) { + x += win->x; + y += win->y; + win = win->parent; + } + + rect->x = x; + rect->y = (win->h - y) - rect->h; +} // calcHeavyweightRect + +BOOL WinFillRect(HPS hps, PRECTL prcl, LONG lColor) +{ + TRACE_NATIVE("WinFillRect(%u, %p, %d)", (unsigned int) hps, prcl, (int) lColor); + AnchorBlock *anchor = getAnchorBlockNoHAB(); + if (!anchor) { + return NULLHANDLE; + } + PresentationSpace *ps = getPresentationSpaceFromHPS(anchor, hps); + if (!ps) { + SET_WIN_ERROR_AND_RETURN(anchor, PMERR_INV_HPS, NULLHANDLE); + } + Window *win = ps->window; + SDL_Renderer *renderer = win->heavy.renderer; + assert(SDL_GetRenderTarget(renderer) == win->heavy.texture); + + SDL_Rect cliprect; + calcHeavyweightRect(win, &cliprect); + + SDL_Rect rect; + rect.x = cliprect.x + prcl->xLeft; + rect.y = cliprect.y + (cliprect.h - prcl->yTop); + rect.w = prcl->xRight - prcl->xLeft; + rect.h = prcl->yTop - prcl->yBottom; + + Uint8 r, g, b; + os2ColorIndexToRGB(lColor, &r, &g, &b); + + //printf("fill { x=%d, y=%d, w=%d, h=%d, r=0x%X, g=0x%X, b=0x%X }\n", (int) rect.x, (int) rect.y, (int) rect.w, (int) rect.h, (unsigned int) r, (unsigned int) g, (unsigned int) b); + SDL_RenderSetClipRect(renderer, &cliprect); + SDL_SetRenderDrawColor(renderer, r, g, b, 0xFF); + SDL_RenderFillRect(renderer, &rect); + SDL_RenderSetClipRect(renderer, NULL); + return TRUE; +} // WinFillRect + +LX_NATIVE_MODULE_INIT() + LX_NATIVE_EXPORT(WinBeginPaint, 703), + LX_NATIVE_EXPORT(WinCreateMsgQueue, 716), + LX_NATIVE_EXPORT(WinDestroyMsgQueue, 726), + LX_NATIVE_EXPORT(WinDestroyWindow, 728), + LX_NATIVE_EXPORT(WinEndPaint, 738), + LX_NATIVE_EXPORT(WinFillRect, 743), + LX_NATIVE_EXPORT(WinGetLastError, 753), + LX_NATIVE_EXPORT(WinInitialize, 763), + LX_NATIVE_EXPORT(WinTerminate, 888), + LX_NATIVE_EXPORT(WinPostQueueMsg, 902), + LX_NATIVE_EXPORT(WinCreateStdWindow, 908), + LX_NATIVE_EXPORT(WinCreateWindow, 909), + LX_NATIVE_EXPORT(WinDefWindowProc, 911), + LX_NATIVE_EXPORT(WinDispatchMsg, 912), + LX_NATIVE_EXPORT(WinGetMsg, 915), + LX_NATIVE_EXPORT(WinPostMsg, 919), + LX_NATIVE_EXPORT(WinSendMsg, 920), + LX_NATIVE_EXPORT(WinRegisterClass, 926) +LX_NATIVE_MODULE_INIT_END() + +// end of pmwin.c ... + diff --git a/native/pmwin.h b/native/pmwin.h new file mode 100644 index 0000000..dd3a69c --- /dev/null +++ b/native/pmwin.h @@ -0,0 +1,897 @@ +#ifndef _INCL_PMWIN_H_ +#define _INCL_PMWIN_H_ + +#include "os2types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef HANDLE HAB, *PHAB; +typedef HANDLE HMQ, *PHMQ; +typedef HANDLE HWND, *PHWND; + +typedef PVOID MPARAM, *PMPARAM; +typedef PVOID MRESULT, *PMRESULT; + +typedef struct +{ + LONG x; + LONG y; +} POINTL, *PPOINTL; + +typedef struct +{ + LONG xLeft; + LONG yBottom; + LONG xRight; + LONG yTop; +} RECTL, *PRECTL; + +typedef struct +{ + HWND hwnd; + ULONG msg; + MPARAM mp1; + MPARAM mp2; + ULONG time; + POINTL ptl; + ULONG reserved; +} QMSG, *PQMSG; + +typedef MRESULT (OS2API FNWP)(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2); +typedef FNWP *PFNWP; + + +enum { + CS_MOVENOTIFY = 0x00000001, + CS_SIZEREDRAW = 0x00000004, + CS_HITTEST = 0x00000008, + CS_PUBLIC = 0x00000010, + CS_FRAME = 0x00000020, + CS_SYNCPAINT = 0x02000000, + CS_PARENTCLIP = 0x08000000, + CS_SAVEBITS = 0x04000000, + CS_CLIPSIBLINGS = 0x10000000, + CS_CLIPCHILDREN = 0x20000000 +}; + +enum { + WS_VISIBLE = 0x80000000, + WS_DISABLED = 0x40000000, + WS_CLIPCHILDREN = 0x20000000, + WS_CLIPSIBLINGS = 0x10000000, + WS_PARENTCLIP = 0x08000000, + WS_SAVEBITS = 0x04000000, + WS_SYNCPAINT = 0x02000000, + WS_MINIMIZED = 0x01000000, + WS_MAXIMIZED = 0x00800000, + WS_ANIMATE = 0x00400000 +}; + +// magic HWND identifiers +#define HWND_DESKTOP 1 +#define HWND_OBJECT 2 +#define HWND_TOP 3 +#define HWND_BOTTOM 4 + +// built-in window classes (not real strings, like user classes would be here). +enum { + WC_FRAME = 0xFFFF0001, + WC_COMBOBOX = 0xFFFF0002, + WC_BUTTON = 0xFFFF0003, + WC_MENU = 0xFFFF0004, + WC_STATIC = 0xFFFF0005, + WC_ENTRYFIELD = 0xFFFF0006, + WC_LISTBOX = 0xFFFF0007, + WC_SCROLLBAR = 0xFFFF0008, + WC_TITLEBAR = 0xFFFF0009, + WC_MLE = 0xFFFF000A, + WC_APPSTAT = 0xFFFF0010, + WC_KBDSTAT = 0xFFFF0011, + WC_PECIC = 0xFFFF0012, + WC_DBE_KKPOPUP = 0xFFFF0013, + WC_SPINBUTTON = 0xFFFF0020, + WC_CONTAINER = 0xFFFF0025, + WC_SLIDER = 0xFFFF0026, + WC_VALUESET = 0xFFFF0027, + WC_NOTEBOOK = 0xFFFF0028, + WC_CIRCULARSLIDER = 0xFFFF0041 +}; + +// Window messages... + +enum { + WM_NULL = 0x0000, + WM_CREATE = 0x0001, + WM_DESTROY = 0x0002, + WM_ENABLE = 0x0004, + WM_SHOW = 0x0005, + WM_MOVE = 0x0006, + WM_SIZE = 0x0007, + WM_ADJUSTWINDOWPOS = 0x0008, + WM_CALCVALIDRECTS = 0x0009, + WM_SETWINDOWPARAMS = 0x000a, + WM_QUERYWINDOWPARAMS = 0x000b, + WM_HITTEST = 0x000c, + WM_ACTIVATE = 0x000d, + WM_SETFOCUS = 0x000f, + WM_SETSELECTION = 0x0010, + WM_PPAINT = 0x0011, + WM_PSETFOCUS = 0x0012, + WM_PSYSCOLORCHANGE = 0x0013, + WM_PSIZE = 0x0014, + WM_PACTIVATE = 0x0015, + WM_PCONTROL = 0x0016, + WM_COMMAND = 0x0020, + WM_SYSCOMMAND = 0x0021, + WM_HELP = 0x0022, + WM_PAINT = 0x0023, + WM_TIMER = 0x0024, + WM_SEM1 = 0x0025, + WM_SEM2 = 0x0026, + WM_SEM3 = 0x0027, + WM_SEM4 = 0x0028, + WM_CLOSE = 0x0029, + WM_QUIT = 0x002a, + WM_SYSCOLORCHANGE = 0x002b, + WM_SYSVALUECHANGED = 0x002d, + WM_APPTERMINATENOTIFY = 0x002e, + WM_PRESPARAMCHANGED = 0x002f, + WM_CONTROL = 0x0030, + WM_VSCROLL = 0x0031, + WM_HSCROLL = 0x0032, + WM_INITMENU = 0x0033, + WM_MENUSELECT = 0x0034, + WM_MENUEND = 0x0035, + WM_DRAWITEM = 0x0036, + WM_MEASUREITEM = 0x0037, + WM_CONTROLPOINTER = 0x0038, + WM_QUERYDLGCODE = 0x003a, + WM_INITDLG = 0x003b, + WM_SUBSTITUTESTRING = 0x003c, + WM_MATCHMNEMONIC = 0x003d, + WM_SAVEAPPLICATION = 0x003e, + WM_FLASHWINDOW = 0x0040, + WM_FORMATFRAME = 0x0041, + WM_UPDATEFRAME = 0x0042, + WM_FOCUSCHANGE = 0x0043, + WM_SETBORDERSIZE = 0x0044, + WM_TRACKFRAME = 0x0045, + WM_MINMAXFRAME = 0x0046, + WM_SETICON = 0x0047, + WM_QUERYICON = 0x0048, + WM_SETACCELTABLE = 0x0049, + WM_QUERYACCELTABLE = 0x004a, + WM_TRANSLATEACCEL = 0x004b, + WM_QUERYTRACKINFO = 0x004c, + WM_QUERYBORDERSIZE = 0x004d, + WM_NEXTMENU = 0x004e, + WM_ERASEBACKGROUND = 0x004f, + WM_QUERYFRAMEINFO = 0x0050, + WM_QUERYFOCUSCHAIN = 0x0051, + WM_OWNERPOSCHANGE = 0x0052, + WM_CALCFRAMERECT = 0x0053, + WM_WINDOWPOSCHANGED = 0x0055, + WM_ADJUSTFRAMEPOS = 0x0056, + WM_QUERYFRAMECTLCOUNT = 0x0059, + WM_QUERYHELPINFO = 0x005B, + WM_SETHELPINFO = 0x005C, + WM_ERROR = 0x005D, + WM_REALIZEPALETTE = 0x005E, + WM_RENDERFMT = 0x0060, + WM_RENDERALLFMTS = 0x0061, + WM_DESTROYCLIPBOARD = 0x0062, + WM_PAINTCLIPBOARD = 0x0063, + WM_SIZECLIPBOARD = 0x0064, + WM_HSCROLLCLIPBOARD = 0x0065, + WM_VSCROLLCLIPBOARD = 0x0066, + WM_DRAWCLIPBOARD = 0x0067, + WM_MOUSEMOVE = 0x0070, + WM_BUTTON1DOWN = 0x0071, + WM_BUTTON1UP = 0x0072, + WM_BUTTON1DBLCLK = 0x0073, + WM_BUTTON2DOWN = 0x0074, + WM_BUTTON2UP = 0x0075, + WM_BUTTON2DBLCLK = 0x0076, + WM_BUTTON3DOWN = 0x0077, + WM_BUTTON3UP = 0x0078, + WM_BUTTON3DBLCLK = 0x0079, + WM_CHAR = 0x007a, + WM_VIOCHAR = 0x007b, + WM_JOURNALNOTIFY = 0x007c, + WM_MOUSEMAP = 0x007D, + WM_VRNDISABLED = 0x007e, + WM_VRNENABLED = 0x007f, + WM_DDE_INITIATE = 0x00A0, + WM_DDE_REQUEST = 0x00A1, + WM_DDE_ACK = 0x00A2, + WM_DDE_DATA = 0x00A3, + WM_DDE_ADVISE = 0x00A4, + WM_DDE_UNADVISE = 0x00A5, + WM_DDE_POKE = 0x00A6, + WM_DDE_EXECUTE = 0x00A7, + WM_DDE_TERMINATE = 0x00A8, + WM_DDE_INITIATEACK = 0x00A9, + WM_QUERYCONVERTPOS = 0x00b0, + WM_MSGBOXINIT = 0x010E, + WM_MSGBOXDISMISS = 0x010F, + WM_CTLCOLORCHANGE = 0x0129, + WM_QUERYCTLTYPE = 0x0130, + WM_CHORD = 0x0410, + WM_BUTTON1MOTIONSTART = 0x0411, + WM_BUTTON1MOTIONEND = 0x0412, + WM_BUTTON1CLICK = 0x0413, + WM_BUTTON2MOTIONSTART = 0x0414, + WM_BUTTON2MOTIONEND = 0x0415, + WM_BUTTON2CLICK = 0x0416, + WM_BUTTON3MOTIONSTART = 0x0417, + WM_BUTTON3MOTIONEND = 0x0418, + WM_BUTTON3CLICK = 0x0419, + WM_BEGINDRAG = 0x0420, + WM_ENDDRAG = 0x0421, + WM_SINGLESELECT = 0x0422, + WM_OPEN = 0x0423, + WM_CONTEXTMENU = 0x0424, + WM_CONTEXTHELP = 0x0425, + WM_TEXTEDIT = 0x0426, + WM_BEGINSELECT = 0x0427, + WM_ENDSELECT = 0x0428, + WM_PICKUP = 0x0429, + WM_SEMANTICEVENT = 0x0490, + WM_USER = 0x1000, +}; + +// used by WM_ADJUSTWINDOWPOS, etc. +enum { + SWP_SIZE = 0x0001, + SWP_MOVE = 0x0002, + SWP_ZORDER = 0x0004, + SWP_SHOW = 0x0008, + SWP_HIDE = 0x0010, + SWP_NOREDRAW = 0x0020, + SWP_NOADJUST = 0x0040, + SWP_ACTIVATE = 0x0080, + SWP_DEACTIVATE = 0x0100, + SWP_EXTSTATECHANGE = 0x0200, + SWP_MINIMIZE = 0x0400, + SWP_MAXIMIZE = 0x0800, + SWP_RESTORE = 0x1000, + SWP_FOCUSACTIVATE = 0x2000, + SWP_FOCUSDEACTIVATE = 0x4000, + SWP_NOAUTOCLOSE = 0x8000 +}; + +typedef struct +{ + ULONG fl; + LONG cy; + LONG cx; + LONG y; + LONG x; + HWND hwndInsertBehind; + HWND hwnd; + ULONG ulReserved1; + ULONG ulReserved2; +} SWP, *PSWP; + + +// used by WM_HITTEST +enum { + HT_NORMAL = 0, + HT_TRANSPARENT = -1, + HT_DISCARD = -2, + HT_ERROR = -3 +}; + + +// Built-in window class specific data... + +// frame control IDs. +enum { + FID_SYSMENU = 0x8002, + FID_TITLEBAR = 0x8003, + FID_MINMAX = 0x8004, + FID_MENU = 0x8005, + FID_VERTSCROLL = 0x8006, + FID_HORZSCROLL = 0x8007, + FID_CLIENT = 0x8008, + FID_DBE_APPSTAT = 0x8010, + FID_DBE_KBDSTAT = 0x8011, + FID_DBE_PECIC = 0x8012, + FID_DBE_KKPOPUP = 0x8013 +}; + +// OS/2's SDK packs these to 2 because 16-bit and 32-bit code share the same structs. :/ +#pragma pack(push, 2) +typedef struct +{ + USHORT cb; + ULONG flCreateFlags; + USHORT hmodResources; + USHORT idResources; +} FRAMECDATA, *PFRAMECDATA; +#pragma pack(pop) + + +// Error codes... +enum { + PMERR_OK = 0x0000, + PMERR_INVALID_HWND = 0x1001, + PMERR_INVALID_HMQ = 0x1002, + PMERR_PARAMETER_OUT_OF_RANGE = 0x1003, + PMERR_WINDOW_LOCK_UNDERFLOW = 0x1004, + PMERR_WINDOW_LOCK_OVERFLOW = 0x1005, + PMERR_BAD_WINDOW_LOCK_COUNT = 0x1006, + PMERR_WINDOW_NOT_LOCKED = 0x1007, + PMERR_INVALID_SELECTOR = 0x1008, + PMERR_CALL_FROM_WRONG_THREAD = 0x1009, + PMERR_RESOURCE_NOT_FOUND = 0x100A, + PMERR_INVALID_STRING_PARM = 0x100B, + PMERR_INVALID_HHEAP = 0x100C, + PMERR_INVALID_HEAP_POINTER = 0x100D, + PMERR_INVALID_HEAP_SIZE_PARM = 0x100E, + PMERR_INVALID_HEAP_SIZE = 0x100F, + PMERR_INVALID_HEAP_SIZE_WORD = 0x1010, + PMERR_HEAP_OUT_OF_MEMORY = 0x1011, + PMERR_HEAP_MAX_SIZE_REACHED = 0x1012, + PMERR_INVALID_HATOMTBL = 0x1013, + PMERR_INVALID_ATOM = 0x1014, + PMERR_INVALID_ATOM_NAME = 0x1015, + PMERR_INVALID_INTEGER_ATOM = 0x1016, + PMERR_ATOM_NAME_NOT_FOUND = 0x1017, + PMERR_QUEUE_TOO_LARGE = 0x1018, + PMERR_INVALID_FLAG = 0x1019, + PMERR_INVALID_HACCEL = 0x101A, + PMERR_INVALID_HPTR = 0x101B, + PMERR_INVALID_HENUM = 0x101C, + PMERR_INVALID_SRC_CODEPAGE = 0x101D, + PMERR_INVALID_DST_CODEPAGE = 0x101E, + PMERR_UNKNOWN_COMPONENT_ID = 0x101f, + PMERR_UNKNOWN_ERROR_CODE = 0x1020, + PMERR_SEVERITY_LEVELS = 0x1021, + PMERR_INVALID_RESOURCE_FORMAT = 0x1034, + PMERR_NO_MSG_QUEUE = 0x1036, + PMERR_CANNOT_SET_FOCUS = 0x1037, + PMERR_QUEUE_FULL = 0x1038, + PMERR_LIBRARY_LOAD_FAILED = 0x1039, + PMERR_PROCEDURE_LOAD_FAILED = 0x103A, + PMERR_LIBRARY_DELETE_FAILED = 0x103B, + PMERR_PROCEDURE_DELETE_FAILED = 0x103C, + PMERR_ARRAY_TOO_LARGE = 0x103D, + PMERR_ARRAY_TOO_SMALL = 0x103E, + PMERR_DATATYPE_ENTRY_BAD_INDEX = 0x103F, + PMERR_DATATYPE_ENTRY_CTL_BAD = 0x1040, + PMERR_DATATYPE_ENTRY_CTL_MISS = 0x1041, + PMERR_DATATYPE_ENTRY_INVALID = 0x1042, + PMERR_DATATYPE_ENTRY_NOT_NUM = 0x1043, + PMERR_DATATYPE_ENTRY_NOT_OFF = 0x1044, + PMERR_DATATYPE_INVALID = 0x1045, + PMERR_DATATYPE_NOT_UNIQUE = 0x1046, + PMERR_DATATYPE_TOO_LONG = 0x1047, + PMERR_DATATYPE_TOO_SMALL = 0x1048, + PMERR_DIRECTION_INVALID = 0x1049, + PMERR_INVALID_HAB = 0x104A, + PMERR_INVALID_HSTRUCT = 0x104D, + PMERR_LENGTH_TOO_SMALL = 0x104E, + PMERR_MSGID_TOO_SMALL = 0x104F, + PMERR_NO_HANDLE_ALLOC = 0x1050, + PMERR_NOT_IN_A_PM_SESSION = 0x1051, + PMERR_MSG_QUEUE_ALREADY_EXISTS = 0x1052, + PMERR_SEND_MSG_TIMEOUT = 0x1053, + PMERR_SEND_MSG_FAILED = 0x1054, + PMERR_OLD_RESOURCE = 0x1055, + PMERR_INVALID_PIB = 0x1101, + PMERR_INSUFF_SPACE_TO_ADD = 0x1102, + PMERR_INVALID_GROUP_HANDLE = 0x1103, + PMERR_DUPLICATE_TITLE = 0x1104, + PMERR_INVALID_TITLE = 0x1105, + PMERR_HANDLE_NOT_IN_GROUP = 0x1107, + PMERR_INVALID_TARGET_HANDLE = 0x1106, + PMERR_INVALID_PATH_STATEMENT = 0x1108, + PMERR_NO_PROGRAM_FOUND = 0x1109, + PMERR_INVALID_BUFFER_SIZE = 0x110A, + PMERR_BUFFER_TOO_SMALL = 0x110B, + PMERR_PL_INITIALISATION_FAIL = 0x110C, + PMERR_CANT_DESTROY_SYS_GROUP = 0x110D, + PMERR_INVALID_TYPE_CHANGE = 0x110E, + PMERR_INVALID_PROGRAM_HANDLE = 0x110F, + PMERR_NOT_CURRENT_PL_VERSION = 0x1110, + PMERR_INVALID_CIRCULAR_REF = 0x1111, + PMERR_MEMORY_ALLOCATION_ERR = 0x1112, + PMERR_MEMORY_DEALLOCATION_ERR = 0x1113, + PMERR_TASK_HEADER_TOO_BIG = 0x1114, + PMERR_INVALID_INI_FILE_HANDLE = 0x1115, + PMERR_MEMORY_SHARE = 0x1116, + PMERR_OPEN_QUEUE = 0x1117, + PMERR_CREATE_QUEUE = 0x1118, + PMERR_WRITE_QUEUE = 0x1119, + PMERR_READ_QUEUE = 0x111A, + PMERR_CALL_NOT_EXECUTED = 0x111B, + PMERR_UNKNOWN_APIPKT = 0x111C, + PMERR_INITHREAD_EXISTS = 0x111D, + PMERR_CREATE_THREAD = 0x111E, + PMERR_NO_HK_PROFILE_INSTALLED = 0x111F, + PMERR_INVALID_DIRECTORY = 0x1120, + PMERR_WILDCARD_IN_FILENAME = 0x1121, + PMERR_FILENAME_BUFFER_FULL = 0x1122, + PMERR_FILENAME_TOO_LONG = 0x1123, + PMERR_INI_FILE_IS_SYS_OR_USER = 0x1124, + PMERR_BROADCAST_PLMSG = 0x1125, + PMERR_190_INIT_DONE = 0x1126, + PMERR_HMOD_FOR_PMSHAPI = 0x1127, + PMERR_SET_HK_PROFILE = 0x1128, + PMERR_API_NOT_ALLOWED = 0x1129, + PMERR_INI_STILL_OPEN = 0x112A, + PMERR_PROGDETAILS_NOT_IN_INI = 0x112B, + PMERR_PIBSTRUCT_NOT_IN_INI = 0x112C, + PMERR_INVALID_DISKPROGDETAILS = 0x112D, + PMERR_PROGDETAILS_READ_FAILURE = 0x112E, + PMERR_PROGDETAILS_WRITE_FAILURE = 0x112F, + PMERR_PROGDETAILS_QSIZE_FAILURE = 0x1130, + PMERR_INVALID_PROGDETAILS = 0x1131, + PMERR_SHEPROFILEHOOK_NOT_FOUND = 0x1132, + PMERR_190PLCONVERTED = 0x1133, + PMERR_FAILED_TO_CONVERT_INI_PL = 0x1134, + PMERR_PMSHAPI_NOT_INITIALISED = 0x1135, + PMERR_INVALID_SHELL_API_HOOK_ID = 0x1136, + PMERR_DOS_ERROR = 0x1200, + PMERR_NO_SPACE = 0x1201, + PMERR_INVALID_SWITCH_HANDLE = 0x1202, + PMERR_NO_HANDLE = 0x1203, + PMERR_INVALID_PROCESS_ID = 0x1204, + PMERR_NOT_SHELL = 0x1205, + PMERR_INVALID_WINDOW = 0x1206, + PMERR_INVALID_POST_MSG = 0x1207, + PMERR_INVALID_PARAMETERS = 0x1208, + PMERR_INVALID_PROGRAM_TYPE = 0x1209, + PMERR_NOT_EXTENDED_FOCUS = 0x120A, + PMERR_INVALID_SESSION_ID = 0x120B, + PMERR_SMG_INVALID_ICON_FILE = 0x120C, + PMERR_SMG_ICON_NOT_CREATED = 0x120D, + PMERR_SHL_DEBUG = 0x120E, + PMERR_OPENING_INI_FILE = 0x1301, + PMERR_INI_FILE_CORRUPT = 0x1302, + PMERR_INVALID_PARM = 0x1303, + PMERR_NOT_IN_IDX = 0x1304, + PMERR_NO_ENTRIES_IN_GROUP = 0x1305, + PMERR_INI_WRITE_FAIL = 0x1306, + PMERR_IDX_FULL = 0x1307, + PMERR_INI_PROTECTED = 0x1308, + PMERR_MEMORY_ALLOC = 0x1309, + PMERR_INI_INIT_ALREADY_DONE = 0x130A, + PMERR_INVALID_INTEGER = 0x130B, + PMERR_INVALID_ASCIIZ = 0x130C, + PMERR_CAN_NOT_CALL_SPOOLER = 0x130D, + PMERR_VALIDATION_REJECTED = PMERR_CAN_NOT_CALL_SPOOLER, + PMERR_WARNING_WINDOW_NOT_KILLED = 0x1401, + PMERR_ERROR_INVALID_WINDOW = 0x1402, + PMERR_ALREADY_INITIALIZED = 0x1403, + PMERR_MSG_PROG_NO_MOU = 0x1405, + PMERR_MSG_PROG_NON_RECOV = 0x1406, + PMERR_WINCONV_INVALID_PATH = 0x1407, + PMERR_PI_NOT_INITIALISED = 0x1408, + PMERR_PL_NOT_INITIALISED = 0x1409, + PMERR_NO_TASK_MANAGER = 0x140A, + PMERR_SAVE_NOT_IN_PROGRESS = 0x140B, + PMERR_NO_STACK_SPACE = 0x140C, + PMERR_INVALID_COLR_FIELD = 0x140d, + PMERR_INVALID_COLR_VALUE = 0x140e, + PMERR_COLR_WRITE = 0x140f, + PMERR_TARGET_FILE_EXISTS = 0x1501, + PMERR_SOURCE_SAME_AS_TARGET = 0x1502, + PMERR_SOURCE_FILE_NOT_FOUND = 0x1503, + PMERR_INVALID_NEW_PATH = 0x1504, + PMERR_TARGET_FILE_NOT_FOUND = 0x1505, + PMERR_INVALID_DRIVE_NUMBER = 0x1506, + PMERR_NAME_TOO_LONG = 0x1507, + PMERR_NOT_ENOUGH_ROOM_ON_DISK = 0x1508, + PMERR_NOT_ENOUGH_MEM = 0x1509, + PMERR_LOG_DRV_DOES_NOT_EXIST = 0x150B, + PMERR_INVALID_DRIVE = 0x150C, + PMERR_ACCESS_DENIED = 0x150D, + PMERR_NO_FIRST_SLASH = 0x150E, + PMERR_READ_ONLY_FILE = 0x150F, + PMERR_GROUP_PROTECTED = 0x151F, + PMERR_INVALID_PROGRAM_CATEGORY = 0x152F, + PMERR_INVALID_APPL = 0x1530, + PMERR_CANNOT_START = 0x1531, + PMERR_STARTED_IN_BACKGROUND = 0x1532, + PMERR_INVALID_HAPP = 0x1533, + PMERR_CANNOT_STOP = 0x1534, + PMERR_INTERNAL_ERROR_1 = 0x1601, + PMERR_INTERNAL_ERROR_2 = 0x1602, + PMERR_INTERNAL_ERROR_3 = 0x1603, + PMERR_INTERNAL_ERROR_4 = 0x1604, + PMERR_INTERNAL_ERROR_5 = 0x1605, + PMERR_INTERNAL_ERROR_6 = 0x1606, + PMERR_INTERNAL_ERROR_7 = 0x1607, + PMERR_INTERNAL_ERROR_8 = 0x1608, + PMERR_INTERNAL_ERROR_9 = 0x1609, + PMERR_INTERNAL_ERROR_10 = 0x160A, + PMERR_INTERNAL_ERROR_11 = 0x160B, + PMERR_INTERNAL_ERROR_12 = 0x160C, + PMERR_INTERNAL_ERROR_13 = 0x160D, + PMERR_INTERNAL_ERROR_14 = 0x160E, + PMERR_INTERNAL_ERROR_15 = 0x160F, + PMERR_INTERNAL_ERROR_16 = 0x1610, + PMERR_INTERNAL_ERROR_17 = 0x1611, + PMERR_INTERNAL_ERROR_18 = 0x1612, + PMERR_INTERNAL_ERROR_19 = 0x1613, + PMERR_INTERNAL_ERROR_20 = 0x1614, + PMERR_INTERNAL_ERROR_21 = 0x1615, + PMERR_INTERNAL_ERROR_22 = 0x1616, + PMERR_INTERNAL_ERROR_23 = 0x1617, + PMERR_INTERNAL_ERROR_24 = 0x1618, + PMERR_INTERNAL_ERROR_25 = 0x1619, + PMERR_INTERNAL_ERROR_26 = 0x161A, + PMERR_INTERNAL_ERROR_27 = 0x161B, + PMERR_INTERNAL_ERROR_28 = 0x161C, + PMERR_INTERNAL_ERROR_29 = 0x161D, + PMERR_INVALID_FREE_MESSAGE_ID = 0x1630, + PMERR_FUNCTION_NOT_SUPPORTED = 0x1641, + PMERR_INVALID_ARRAY_COUNT = 0x1642, + PMERR_INVALID_LENGTH = 0x1643, + PMERR_INVALID_BUNDLE_TYPE = 0x1644, + PMERR_INVALID_PARAMETER = 0x1645, + PMERR_INVALID_NUMBER_OF_PARMS = 0x1646, + PMERR_GREATER_THAN_64K = 0x1647, + PMERR_INVALID_PARAMETER_TYPE = 0x1648, + PMERR_NEGATIVE_STRCOND_DIM = 0x1649, + PMERR_INVALID_NUMBER_OF_TYPES = 0x164A, + PMERR_INCORRECT_HSTRUCT = 0x164B, + PMERR_INVALID_ARRAY_SIZE = 0x164C, + PMERR_INVALID_CONTROL_DATATYPE = 0x164D, + PMERR_INCOMPLETE_CONTROL_SEQU = 0x164E, + PMERR_INVALID_DATATYPE = 0x164F, + PMERR_INCORRECT_DATATYPE = 0x1650, + PMERR_NOT_SELF_DESCRIBING_DTYP = 0x1651, + PMERR_INVALID_CTRL_SEQ_INDEX = 0x1652, + PMERR_INVALID_TYPE_FOR_LENGTH = 0x1653, + PMERR_INVALID_TYPE_FOR_OFFSET = 0x1654, + PMERR_INVALID_TYPE_FOR_MPARAM = 0x1655, + PMERR_INVALID_MESSAGE_ID = 0x1656, + PMERR_C_LENGTH_TOO_SMALL = 0x1657, + PMERR_APPL_STRUCTURE_TOO_SMALL = 0x1658, + PMERR_INVALID_ERRORINFO_HANDLE = 0x1659, + PMERR_INVALID_CHARACTER_INDEX = 0x165A, + PMERR_ALREADY_IN_AREA = 0x2001, + PMERR_ALREADY_IN_ELEMENT = 0x2002, + PMERR_ALREADY_IN_PATH = 0x2003, + PMERR_ALREADY_IN_SEG = 0x2004, + PMERR_AREA_INCOMPLETE = 0x2005, + PMERR_BASE_ERROR = 0x2006, + PMERR_BITBLT_LENGTH_EXCEEDED = 0x2007, + PMERR_BITMAP_IN_USE = 0x2008, + PMERR_BITMAP_IS_SELECTED = 0x2009, + PMERR_BITMAP_NOT_FOUND = 0x200A, + PMERR_BITMAP_NOT_SELECTED = 0x200B, + PMERR_BOUNDS_OVERFLOW = 0x200C, + PMERR_CALLED_SEG_IS_CHAINED = 0x200D, + PMERR_CALLED_SEG_IS_CURRENT = 0x200E, + PMERR_CALLED_SEG_NOT_FOUND = 0x200F, + PMERR_CANNOT_DELETE_ALL_DATA = 0x2010, + PMERR_CANNOT_REPLACE_ELEMENT_0 = 0x2011, + PMERR_COL_TABLE_NOT_REALIZABLE = 0x2012, + PMERR_COL_TABLE_NOT_REALIZED = 0x2013, + PMERR_COORDINATE_OVERFLOW = 0x2014, + PMERR_CORR_FORMAT_MISMATCH = 0x2015, + PMERR_DATA_TOO_LONG = 0x2016, + PMERR_DC_IS_ASSOCIATED = 0x2017, + PMERR_DESC_STRING_TRUNCATED = 0x2018, + PMERR_DEVICE_DRIVER_ERROR_1 = 0x2019, + PMERR_DEVICE_DRIVER_ERROR_2 = 0x201A, + PMERR_DEVICE_DRIVER_ERROR_3 = 0x201B, + PMERR_DEVICE_DRIVER_ERROR_4 = 0x201C, + PMERR_DEVICE_DRIVER_ERROR_5 = 0x201D, + PMERR_DEVICE_DRIVER_ERROR_6 = 0x201E, + PMERR_DEVICE_DRIVER_ERROR_7 = 0x201F, + PMERR_DEVICE_DRIVER_ERROR_8 = 0x2020, + PMERR_DEVICE_DRIVER_ERROR_9 = 0x2021, + PMERR_DEVICE_DRIVER_ERROR_10 = 0x2022, + PMERR_DEV_FUNC_NOT_INSTALLED = 0x2023, + PMERR_DOSOPEN_FAILURE = 0x2024, + PMERR_DOSREAD_FAILURE = 0x2025, + PMERR_DRIVER_NOT_FOUND = 0x2026, + PMERR_DUP_SEG = 0x2027, + PMERR_DYNAMIC_SEG_SEQ_ERROR = 0x2028, + PMERR_DYNAMIC_SEG_ZERO_INV = 0x2029, + PMERR_ELEMENT_INCOMPLETE = 0x202A, + PMERR_ESC_CODE_NOT_SUPPORTED = 0x202B, + PMERR_EXCEEDS_MAX_SEG_LENGTH = 0x202C, + PMERR_FONT_AND_MODE_MISMATCH = 0x202D, + PMERR_FONT_FILE_NOT_LOADED = 0x202E, + PMERR_FONT_NOT_LOADED = 0x202F, + PMERR_FONT_TOO_BIG = 0x2030, + PMERR_HARDWARE_INIT_FAILURE = 0x2031, + PMERR_HBITMAP_BUSY = 0x2032, + PMERR_HDC_BUSY = 0x2033, + PMERR_HRGN_BUSY = 0x2034, + PMERR_HUGE_FONTS_NOT_SUPPORTED = 0x2035, + PMERR_ID_HAS_NO_BITMAP = 0x2036, + PMERR_IMAGE_INCOMPLETE = 0x2037, + PMERR_INCOMPAT_COLOR_FORMAT = 0x2038, + PMERR_INCOMPAT_COLOR_OPTIONS = 0x2039, + PMERR_INCOMPATIBLE_BITMAP = 0x203A, + PMERR_INCOMPATIBLE_METAFILE = 0x203B, + PMERR_INCORRECT_DC_TYPE = 0x203C, + PMERR_INSUFFICIENT_DISK_SPACE = 0x203D, + PMERR_INSUFFICIENT_MEMORY = 0x203E, + PMERR_INV_ANGLE_PARM = 0x203F, + PMERR_INV_ARC_CONTROL = 0x2040, + PMERR_INV_AREA_CONTROL = 0x2041, + PMERR_INV_ARC_POINTS = 0x2042, + PMERR_INV_ATTR_MODE = 0x2043, + PMERR_INV_BACKGROUND_COL_ATTR = 0x2044, + PMERR_INV_BACKGROUND_MIX_ATTR = 0x2045, + PMERR_INV_BITBLT_MIX = 0x2046, + PMERR_INV_BITBLT_STYLE = 0x2047, + PMERR_INV_BITMAP_DIMENSION = 0x2048, + PMERR_INV_BOX_CONTROL = 0x2049, + PMERR_INV_BOX_ROUNDING_PARM = 0x204A, + PMERR_INV_CHAR_ANGLE_ATTR = 0x204B, + PMERR_INV_CHAR_DIRECTION_ATTR = 0x204C, + PMERR_INV_CHAR_MODE_ATTR = 0x204D, + PMERR_INV_CHAR_POS_OPTIONS = 0x204E, + PMERR_INV_CHAR_SET_ATTR = 0x204F, + PMERR_INV_CHAR_SHEAR_ATTR = 0x2050, + PMERR_INV_CLIP_PATH_OPTIONS = 0x2051, + PMERR_INV_CODEPAGE = 0x2052, + PMERR_INV_COLOR_ATTR = 0x2053, + PMERR_INV_COLOR_DATA = 0x2054, + PMERR_INV_COLOR_FORMAT = 0x2055, + PMERR_INV_COLOR_INDEX = 0x2056, + PMERR_INV_COLOR_OPTIONS = 0x2057, + PMERR_INV_COLOR_START_INDEX = 0x2058, + PMERR_INV_COORD_OFFSET = 0x2059, + PMERR_INV_COORD_SPACE = 0x205A, + PMERR_INV_COORDINATE = 0x205B, + PMERR_INV_CORRELATE_DEPTH = 0x205C, + PMERR_INV_CORRELATE_TYPE = 0x205D, + PMERR_INV_CURSOR_BITMAP = 0x205E, + PMERR_INV_DC_DATA = 0x205F, + PMERR_INV_DC_TYPE = 0x2060, + PMERR_INV_DEVICE_NAME = 0x2061, + PMERR_INV_DEV_MODES_OPTIONS = 0x2062, + PMERR_INV_DRAW_CONTROL = 0x2063, + PMERR_INV_DRAW_VALUE = 0x2064, + PMERR_INV_DRAWING_MODE = 0x2065, + PMERR_INV_DRIVER_DATA = 0x2066, + PMERR_INV_DRIVER_NAME = 0x2067, + PMERR_INV_DRAW_BORDER_OPTION = 0x2068, + PMERR_INV_EDIT_MODE = 0x2069, + PMERR_INV_ELEMENT_OFFSET = 0x206A, + PMERR_INV_ELEMENT_POINTER = 0x206B, + PMERR_INV_END_PATH_OPTIONS = 0x206C, + PMERR_INV_ESC_CODE = 0x206D, + PMERR_INV_ESCAPE_DATA = 0x206E, + PMERR_INV_EXTENDED_LCID = 0x206F, + PMERR_INV_FILL_PATH_OPTIONS = 0x2070, + PMERR_INV_FIRST_CHAR = 0x2071, + PMERR_INV_FONT_ATTRS = 0x2072, + PMERR_INV_FONT_FILE_DATA = 0x2073, + PMERR_INV_FOR_THIS_DC_TYPE = 0x2074, + PMERR_INV_FORMAT_CONTROL = 0x2075, + PMERR_INV_FORMS_CODE = 0x2076, + PMERR_INV_FONTDEF = 0x2077, + PMERR_INV_GEOM_LINE_WIDTH_ATTR = 0x2078, + PMERR_INV_GETDATA_CONTROL = 0x2079, + PMERR_INV_GRAPHICS_FIELD = 0x207A, + PMERR_INV_HBITMAP = 0x207B, + PMERR_INV_HDC = 0x207C, + PMERR_INV_HJOURNAL = 0x207D, + PMERR_INV_HMF = 0x207E, + PMERR_INV_HPS = 0x207F, + PMERR_INV_HRGN = 0x2080, + PMERR_INV_ID = 0x2081, + PMERR_INV_IMAGE_DATA_LENGTH = 0x2082, + PMERR_INV_IMAGE_DIMENSION = 0x2083, + PMERR_INV_IMAGE_FORMAT = 0x2084, + PMERR_INV_IN_AREA = 0x2085, + PMERR_INV_IN_CALLED_SEG = 0x2086, + PMERR_INV_IN_CURRENT_EDIT_MODE = 0x2087, + PMERR_INV_IN_DRAW_MODE = 0x2088, + PMERR_INV_IN_ELEMENT = 0x2089, + PMERR_INV_IN_IMAGE = 0x208A, + PMERR_INV_IN_PATH = 0x208B, + PMERR_INV_IN_RETAIN_MODE = 0x208C, + PMERR_INV_IN_SEG = 0x208D, + PMERR_INV_IN_VECTOR_SYMBOL = 0x208E, + PMERR_INV_INFO_TABLE = 0x208F, + PMERR_INV_JOURNAL_OPTION = 0x2090, + PMERR_INV_KERNING_FLAGS = 0x2091, + PMERR_INV_LENGTH_OR_COUNT = 0x2092, + PMERR_INV_LINE_END_ATTR = 0x2093, + PMERR_INV_LINE_JOIN_ATTR = 0x2094, + PMERR_INV_LINE_TYPE_ATTR = 0x2095, + PMERR_INV_LINE_WIDTH_ATTR = 0x2096, + PMERR_INV_LOGICAL_ADDRESS = 0x2097, + PMERR_INV_MARKER_BOX_ATTR = 0x2098, + PMERR_INV_MARKER_SET_ATTR = 0x2099, + PMERR_INV_MARKER_SYMBOL_ATTR = 0x209A, + PMERR_INV_MATRIX_ELEMENT = 0x209B, + PMERR_INV_MAX_HITS = 0x209C, + PMERR_INV_METAFILE = 0x209D, + PMERR_INV_METAFILE_LENGTH = 0x209E, + PMERR_INV_METAFILE_OFFSET = 0x209F, + PMERR_INV_MICROPS_DRAW_CONTROL = 0x20A0, + PMERR_INV_MICROPS_FUNCTION = 0x20A1, + PMERR_INV_MICROPS_ORDER = 0x20A2, + PMERR_INV_MIX_ATTR = 0x20A3, + PMERR_INV_MODE_FOR_OPEN_DYN = 0x20A4, + PMERR_INV_MODE_FOR_REOPEN_SEG = 0x20A5, + PMERR_INV_MODIFY_PATH_MODE = 0x20A6, + PMERR_INV_MULTIPLIER = 0x20A7, + PMERR_INV_NESTED_FIGURES = 0x20A8, + PMERR_INV_OR_INCOMPAT_OPTIONS = 0x20A9, + PMERR_INV_ORDER_LENGTH = 0x20AA, + PMERR_INV_ORDERING_PARM = 0x20AB, + PMERR_INV_OUTSIDE_DRAW_MODE = 0x20AC, + PMERR_INV_PAGE_VIEWPORT = 0x20AD, + PMERR_INV_PATH_ID = 0x20AE, + PMERR_INV_PATH_MODE = 0x20AF, + PMERR_INV_PATTERN_ATTR = 0x20B0, + PMERR_INV_PATTERN_REF_PT_ATTR = 0x20B1, + PMERR_INV_PATTERN_SET_ATTR = 0x20B2, + PMERR_INV_PATTERN_SET_FONT = 0x20B3, + PMERR_INV_PICK_APERTURE_OPTION = 0x20B4, + PMERR_INV_PICK_APERTURE_POSN = 0x20B5, + PMERR_INV_PICK_APERTURE_SIZE = 0x20B6, + PMERR_INV_PICK_NUMBER = 0x20B7, + PMERR_INV_PLAY_METAFILE_OPTION = 0x20B8, + PMERR_INV_PRIMITIVE_TYPE = 0x20B9, + PMERR_INV_PS_SIZE = 0x20BA, + PMERR_INV_PUTDATA_FORMAT = 0x20BB, + PMERR_INV_QUERY_ELEMENT_NO = 0x20BC, + PMERR_INV_RECT = 0x20BD, + PMERR_INV_REGION_CONTROL = 0x20BE, + PMERR_INV_REGION_MIX_MODE = 0x20BF, + PMERR_INV_REPLACE_MODE_FUNC = 0x20C0, + PMERR_INV_RESERVED_FIELD = 0x20C1, + PMERR_INV_RESET_OPTIONS = 0x20C2, + PMERR_INV_RGBCOLOR = 0x20C3, + PMERR_INV_SCAN_START = 0x20C4, + PMERR_INV_SEG_ATTR = 0x20C5, + PMERR_INV_SEG_ATTR_VALUE = 0x20C6, + PMERR_INV_SEG_CH_LENGTH = 0x20C7, + PMERR_INV_SEG_NAME = 0x20C8, + PMERR_INV_SEG_OFFSET = 0x20C9, + PMERR_INV_SETID = 0x20CA, + PMERR_INV_SETID_TYPE = 0x20CB, + PMERR_INV_SET_VIEWPORT_OPTION = 0x20CC, + PMERR_INV_SHARPNESS_PARM = 0x20CD, + PMERR_INV_SOURCE_OFFSET = 0x20CE, + PMERR_INV_STOP_DRAW_VALUE = 0x20CF, + PMERR_INV_TRANSFORM_TYPE = 0x20D0, + PMERR_INV_USAGE_PARM = 0x20D1, + PMERR_INV_VIEWING_LIMITS = 0x20D2, + PMERR_JFILE_BUSY = 0x20D3, + PMERR_JNL_FUNC_DATA_TOO_LONG = 0x20D4, + PMERR_KERNING_NOT_SUPPORTED = 0x20D5, + PMERR_LABEL_NOT_FOUND = 0x20D6, + PMERR_MATRIX_OVERFLOW = 0x20D7, + PMERR_METAFILE_INTERNAL_ERROR = 0x20D8, + PMERR_METAFILE_IN_USE = 0x20D9, + PMERR_METAFILE_LIMIT_EXCEEDED = 0x20DA, + PMERR_NAME_STACK_FULL = 0x20DB, + PMERR_NOT_CREATED_BY_DEVOPENDC = 0x20DC, + PMERR_NOT_IN_AREA = 0x20DD, + PMERR_NOT_IN_DRAW_MODE = 0x20DE, + PMERR_NOT_IN_ELEMENT = 0x20DF, + PMERR_NOT_IN_IMAGE = 0x20E0, + PMERR_NOT_IN_PATH = 0x20E1, + PMERR_NOT_IN_RETAIN_MODE = 0x20E2, + PMERR_NOT_IN_SEG = 0x20E3, + PMERR_NO_BITMAP_SELECTED = 0x20E4, + PMERR_NO_CURRENT_ELEMENT = 0x20E5, + PMERR_NO_CURRENT_SEG = 0x20E6, + PMERR_NO_METAFILE_RECORD_HANDLE = 0x20E7, + PMERR_ORDER_TOO_BIG = 0x20E8, + PMERR_OTHER_SET_ID_REFS = 0x20E9, + PMERR_OVERRAN_SEG = 0x20EA, + PMERR_OWN_SET_ID_REFS = 0x20EB, + PMERR_PATH_INCOMPLETE = 0x20EC, + PMERR_PATH_LIMIT_EXCEEDED = 0x20ED, + PMERR_PATH_UNKNOWN = 0x20EE, + PMERR_PEL_IS_CLIPPED = 0x20EF, + PMERR_PEL_NOT_AVAILABLE = 0x20F0, + PMERR_PRIMITIVE_STACK_EMPTY = 0x20F1, + PMERR_PROLOG_ERROR = 0x20F2, + PMERR_PROLOG_SEG_ATTR_NOT_SET = 0x20F3, + PMERR_PS_BUSY = 0x20F4, + PMERR_PS_IS_ASSOCIATED = 0x20F5, + PMERR_RAM_JNL_FILE_TOO_SMALL = 0x20F6, + PMERR_REALIZE_NOT_SUPPORTED = 0x20F7, + PMERR_REGION_IS_CLIP_REGION = 0x20F8, + PMERR_RESOURCE_DEPLETION = 0x20F9, + PMERR_SEG_AND_REFSEG_ARE_SAME = 0x20FA, + PMERR_SEG_CALL_RECURSIVE = 0x20FB, + PMERR_SEG_CALL_STACK_EMPTY = 0x20FC, + PMERR_SEG_CALL_STACK_FULL = 0x20FD, + PMERR_SEG_IS_CURRENT = 0x20FE, + PMERR_SEG_NOT_CHAINED = 0x20FF, + PMERR_SEG_NOT_FOUND = 0x2100, + PMERR_SEG_STORE_LIMIT_EXCEEDED = 0x2101, + PMERR_SETID_IN_USE = 0x2102, + PMERR_SETID_NOT_FOUND = 0x2103, + PMERR_STARTDOC_NOT_ISSUED = 0x2104, + PMERR_STOP_DRAW_OCCURRED = 0x2105, + PMERR_TOO_MANY_METAFILES_IN_USE = 0x2106, + PMERR_TRUNCATED_ORDER = 0x2107, + PMERR_UNCHAINED_SEG_ZERO_INV = 0x2108, + PMERR_UNSUPPORTED_ATTR = 0x2109, + PMERR_UNSUPPORTED_ATTR_VALUE = 0x210A, + PMERR_ENDDOC_NOT_ISSUED = 0x210B, + PMERR_PS_NOT_ASSOCIATED = 0x210C, + PMERR_INV_FLOOD_FILL_OPTIONS = 0x210D, + PMERR_INV_FACENAME = 0x210E, + PMERR_PALETTE_SELECTED = 0x210F, + PMERR_NO_PALETTE_SELECTED = 0x2110, + PMERR_INV_HPAL = 0x2111, + PMERR_PALETTE_BUSY = 0x2112, + PMERR_START_POINT_CLIPPED = 0x2113, + PMERR_NO_FILL = 0x2114, + PMERR_INV_FACENAMEDESC = 0x2115, + PMERR_INV_BITMAP_DATA = 0x2116, + PMERR_INV_CHAR_ALIGN_ATTR = 0x2117, + PMERR_INV_HFONT = 0x2118, + PMERR_HFONT_IS_SELECTED = 0x2119, + PMERR_DRVR_NOT_SUPPORTED = 0x2120, + PMERR_INV_INKPS_FUNCTION = 0x2121 + // !!! FIXME: there are more of these. +}; + +enum { + CLR_FALSE = -5, + CLR_TRUE = -4, + CLR_DEFAULT = -3, + CLR_WHITE = -2, + CLR_BLACK = -1, + CLR_BACKGROUND = 0, + CLR_BLUE = 1, + CLR_RED = 2, + CLR_PINK = 3, + CLR_GREEN = 4, + CLR_CYAN = 5, + CLR_YELLOW = 6, + CLR_NEUTRAL = 7, + CLR_DARKGRAY = 8, + CLR_DARKBLUE = 9, + CLR_DARKRED = 10, + CLR_DARKPINK = 11, + CLR_DARKGREEN = 12, + CLR_DARKCYAN = 13, + CLR_BROWN = 14, + CLR_PALEGRAY = 15 +}; + + +// API entry points... + +OS2EXPORT HAB OS2API WinInitialize(ULONG flOptions); +OS2EXPORT BOOL OS2API WinTerminate(HAB hab); +OS2EXPORT ERRORID OS2API WinGetLastError(HAB hab); +OS2EXPORT HMQ OS2API WinCreateMsgQueue(HAB hab, LONG cmsg); +OS2EXPORT BOOL OS2API WinGetMsg(HAB hab, PQMSG pqmsg, HWND hwndFilter, ULONG msgFilterFirst, ULONG msgFilterLast); +OS2EXPORT MRESULT OS2API WinDispatchMsg(HAB hab, PQMSG pqmsg); +OS2EXPORT BOOL OS2API WinDestroyMsgQueue(HMQ hmq); +OS2EXPORT HWND OS2API WinCreateStdWindow(HWND hwndParent, ULONG flStyle, PULONG pflCreateFlags, PSZ pszClientClass, PSZ pszTitle, ULONG styleClient, HMODULE hmod, ULONG idResources, PHWND phwndClient); +OS2EXPORT HWND OS2API WinCreateWindow(HWND hwndParent, PSZ pszClass, PSZ pszName, ULONG flStyle, LONG x, LONG y, LONG cx, LONG cy, HWND hwndOwner, HWND hwndInsertBehind, ULONG id, PVOID pCtlData, PVOID pPresParams); +OS2EXPORT BOOL OS2API WinDestroyWindow(HWND hwnd); +OS2EXPORT BOOL OS2API WinRegisterClass(HAB hab, PSZ pszClassName, PFNWP pfnWndProc, ULONG flStyle, ULONG cbWindowData); +OS2EXPORT MRESULT OS2API WinDefWindowProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2); +OS2EXPORT MRESULT OS2API WinSendMsg(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2); +OS2EXPORT BOOL OS2API WinPostMsg(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2); +OS2EXPORT BOOL OS2API WinPostQueueMsg(HMQ hmq, ULONG msg, MPARAM mp1, MPARAM mp2); +OS2EXPORT HPS OS2API WinBeginPaint(HWND hwnd, HPS hps, PRECTL prclPaint); +OS2EXPORT BOOL OS2API WinEndPaint(HPS hps); +OS2EXPORT BOOL OS2API WinFillRect(HPS hps, PRECTL prcl, LONG lColor); + +#ifdef __cplusplus +} +#endif + +#endif + +// end of pmwin.h ... + diff --git a/native/viocalls.c b/native/viocalls.c index c85c301..df03f8c 100644 --- a/native/viocalls.c +++ b/native/viocalls.c @@ -1,6 +1,10 @@ #include "os2native16.h" #include "viocalls.h" +// os2types.h defines these, but so does curses. +#undef TRUE +#undef FALSE + #include #include diff --git a/tests/testpm.c b/tests/testpm.c new file mode 100644 index 0000000..0aacabc --- /dev/null +++ b/tests/testpm.c @@ -0,0 +1,46 @@ +#define INCL_WININPUT 1 +#include + +static MRESULT APIENTRY winproc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + switch (msg) { + case WM_PAINT: { + RECTL rect; + HPS hps = WinBeginPaint(hwnd, NULLHANDLE, &rect); + WinFillRect(hps, &rect, CLR_WHITE); + WinEndPaint(hps); + return 0; + } + + case WM_BUTTON1CLICK: { // kill the app when the window is clicked on. + WinPostMsg(hwnd, WM_QUIT, 0, 0); + return 0; + } + } + + return WinDefWindowProc(hwnd, msg, mp1, mp2); +} // winproc + +int main(int argc, char **argv) +{ + HAB hab = WinInitialize(0); + HMQ hmq = WinCreateMsgQueue(hab, 0); + QMSG qmsg; + HWND hwnd; + + WinRegisterClass(hab, "testpm", winproc, 0, 0); + hwnd = WinCreateWindow(HWND_DESKTOP, "testpm", "testpm", WS_VISIBLE, 100, 100, 100, 100, 0, HWND_TOP, 0, NULL, NULL); + + while (WinGetMsg(hab, &qmsg, NULLHANDLE, 0, 0)) { + WinDispatchMsg(hab, &qmsg); + } + + WinDestroyWindow(hwnd); + WinDestroyMsgQueue(hmq); + WinTerminate(hab); + + return 0; +} // main + +// end of testpm.c ... + diff --git a/tests/testpm.exe b/tests/testpm.exe new file mode 100755 index 0000000..6c0ed99 Binary files /dev/null and b/tests/testpm.exe differ