diff options
Diffstat (limited to 'win/tkWinX.c')
-rw-r--r-- | win/tkWinX.c | 1020 |
1 files changed, 1020 insertions, 0 deletions
diff --git a/win/tkWinX.c b/win/tkWinX.c new file mode 100644 index 0000000..0b00186 --- /dev/null +++ b/win/tkWinX.c @@ -0,0 +1,1020 @@ +/* + * tkWinX.c -- + * + * This file contains Windows emulation procedures for X routines. + * + * Copyright (c) 1995-1996 Sun Microsystems, Inc. + * Copyright (c) 1994 Software Research Associates, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkWinX.c 1.51 97/09/02 13:06:57 + */ + +#include "tkInt.h" +#include "tkWinInt.h" + +/* + * Definitions of extern variables supplied by this file. + */ + +int tkpIsWin32s = -1; + +/* + * Declarations of static variables used in this file. + */ + +static HINSTANCE tkInstance = (HINSTANCE) NULL; + /* Global application instance handle. */ +static TkDisplay *winDisplay; /* Display that represents Windows screen. */ +static char winScreenName[] = ":0"; + /* Default name of windows display. */ +static WNDCLASS childClass; /* Window class for child windows. */ +static childClassInitialized = 0; /* Registered child class? */ + +/* + * Forward declarations of procedures used in this file. + */ + +static void GenerateXEvent _ANSI_ARGS_((HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam)); +static unsigned int GetState _ANSI_ARGS_((UINT message, WPARAM wParam, + LPARAM lParam)); +static void GetTranslatedKey _ANSI_ARGS_((XKeyEvent *xkey)); + +/* + *---------------------------------------------------------------------- + * + * TkGetServerInfo -- + * + * Given a window, this procedure returns information about + * the window server for that window. This procedure provides + * the guts of the "winfo server" command. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkGetServerInfo(interp, tkwin) + Tcl_Interp *interp; /* The server information is returned in + * this interpreter's result. */ + Tk_Window tkwin; /* Token for window; this selects a + * particular display and server. */ +{ + char buffer[50]; + OSVERSIONINFO info; + + info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&info); + sprintf(buffer, "Windows %d.%d %d ", info.dwMajorVersion, + info.dwMinorVersion, info.dwBuildNumber); + Tcl_AppendResult(interp, buffer, + (info.dwPlatformId == VER_PLATFORM_WIN32s) ? "Win32s" : "Win32", + (char *) NULL); +} + +/* + *---------------------------------------------------------------------- + * + * Tk_GetHINSTANCE -- + * + * Retrieves the global instance handle used by the Tk library. + * + * Results: + * Returns the global instance handle. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +HINSTANCE +Tk_GetHINSTANCE() +{ + return tkInstance; +} + +/* + *---------------------------------------------------------------------- + * + * TkWinXInit -- + * + * Initialize Xlib emulation layer. + * + * Results: + * None. + * + * Side effects: + * Sets up various data structures. + * + *---------------------------------------------------------------------- + */ + +void +TkWinXInit(hInstance) + HINSTANCE hInstance; +{ + OSVERSIONINFO info; + + info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&info); + tkpIsWin32s = (info.dwPlatformId == VER_PLATFORM_WIN32s); + + if (childClassInitialized != 0) { + return; + } + childClassInitialized = 1; + + tkInstance = hInstance; + + childClass.style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC; + childClass.cbClsExtra = 0; + childClass.cbWndExtra = 0; + childClass.hInstance = hInstance; + childClass.hbrBackground = NULL; + childClass.lpszMenuName = NULL; + + /* + * Register the Child window class. + */ + + childClass.lpszClassName = TK_WIN_CHILD_CLASS_NAME; + childClass.lpfnWndProc = TkWinChildProc; + childClass.hIcon = NULL; + childClass.hCursor = NULL; + + if (!RegisterClass(&childClass)) { + panic("Unable to register TkChild class"); + } +} + +/* + *---------------------------------------------------------------------- + * + * TkWinXCleanup -- + * + * Removes the registered classes for Tk. + * + * Results: + * None. + * + * Side effects: + * Removes window classes from the system. + * + *---------------------------------------------------------------------- + */ + +void +TkWinXCleanup(hInstance) + HINSTANCE hInstance; +{ + /* + * Clean up our own class. + */ + + if (childClassInitialized) { + childClassInitialized = 0; + UnregisterClass(TK_WIN_CHILD_CLASS_NAME, hInstance); + } + + /* + * And let the window manager clean up its own class(es). + */ + + TkWinWmCleanup(hInstance); +} + +/* + *---------------------------------------------------------------------- + * + * TkGetDefaultScreenName -- + * + * Returns the name of the screen that Tk should use during + * initialization. + * + * Results: + * Returns a statically allocated string. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +char * +TkGetDefaultScreenName(interp, screenName) + Tcl_Interp *interp; /* Not used. */ + char *screenName; /* If NULL, use default string. */ +{ + if ((screenName == NULL) || (screenName[0] == '\0')) { + screenName = winScreenName; + } + return screenName; +} + +/* + *---------------------------------------------------------------------- + * + * TkpOpenDisplay -- + * + * Create the Display structure and fill it with device + * specific information. + * + * Results: + * Returns a Display structure on success or NULL on failure. + * + * Side effects: + * Allocates a new Display structure. + * + *---------------------------------------------------------------------- + */ + +TkDisplay * +TkpOpenDisplay(display_name) + char *display_name; +{ + Screen *screen; + HDC dc; + TkWinDrawable *twdPtr; + Display *display; + + if (winDisplay != NULL) { + if (strcmp(winDisplay->display->display_name, display_name) == 0) { + return winDisplay; + } else { + return NULL; + } + } + + display = (Display *) ckalloc(sizeof(Display)); + display->display_name = (char *) ckalloc(strlen(display_name)+1); + strcpy(display->display_name, display_name); + + display->cursor_font = 1; + display->nscreens = 1; + display->request = 1; + display->qlen = 0; + + screen = (Screen *) ckalloc(sizeof(Screen)); + screen->display = display; + + dc = GetDC(NULL); + screen->width = GetDeviceCaps(dc, HORZRES); + screen->height = GetDeviceCaps(dc, VERTRES); + screen->mwidth = MulDiv(screen->width, 254, + GetDeviceCaps(dc, LOGPIXELSX) * 10); + screen->mheight = MulDiv(screen->height, 254, + GetDeviceCaps(dc, LOGPIXELSY) * 10); + + /* + * Set up the root window. + */ + + twdPtr = (TkWinDrawable*) ckalloc(sizeof(TkWinDrawable)); + if (twdPtr == NULL) { + return None; + } + twdPtr->type = TWD_WINDOW; + twdPtr->window.winPtr = NULL; + twdPtr->window.handle = NULL; + screen->root = (Window)twdPtr; + + /* + * On windows, when creating a color bitmap, need two pieces of + * information: the number of color planes and the number of + * pixels per plane. Need to remember both quantities so that + * when constructing an HBITMAP for offscreen rendering, we can + * specify the correct value for the number of planes. Otherwise + * the HBITMAP won't be compatible with the HWND and we'll just + * get blank spots copied onto the screen. + */ + + screen->ext_data = (XExtData *) GetDeviceCaps(dc, PLANES); + screen->root_depth = GetDeviceCaps(dc, BITSPIXEL) * (int) screen->ext_data; + + screen->root_visual = (Visual *) ckalloc(sizeof(Visual)); + screen->root_visual->visualid = 0; + if (GetDeviceCaps(dc, RASTERCAPS) & RC_PALETTE) { + screen->root_visual->map_entries = GetDeviceCaps(dc, SIZEPALETTE); + screen->root_visual->class = PseudoColor; + screen->root_visual->red_mask = 0x0; + screen->root_visual->green_mask = 0x0; + screen->root_visual->blue_mask = 0x0; + } else { + if (screen->root_depth == 4) { + screen->root_visual->class = StaticColor; + screen->root_visual->map_entries = 16; + } else if (screen->root_depth == 8) { + screen->root_visual->class = StaticColor; + screen->root_visual->map_entries = 256; + } else if (screen->root_depth == 12) { + screen->root_visual->class = TrueColor; + screen->root_visual->map_entries = 32; + screen->root_visual->red_mask = 0xf0; + screen->root_visual->green_mask = 0xf000; + screen->root_visual->blue_mask = 0xf00000; + } else if (screen->root_depth == 16) { + screen->root_visual->class = TrueColor; + screen->root_visual->map_entries = 64; + screen->root_visual->red_mask = 0xf8; + screen->root_visual->green_mask = 0xfc00; + screen->root_visual->blue_mask = 0xf80000; + } else if (screen->root_depth >= 24) { + screen->root_visual->class = TrueColor; + screen->root_visual->map_entries = 256; + screen->root_visual->red_mask = 0xff; + screen->root_visual->green_mask = 0xff00; + screen->root_visual->blue_mask = 0xff0000; + } + } + screen->root_visual->bits_per_rgb = screen->root_depth; + ReleaseDC(NULL, dc); + + /* + * Note that these pixel values are not palette relative. + */ + + screen->white_pixel = RGB(255, 255, 255); + screen->black_pixel = RGB(0, 0, 0); + + display->screens = screen; + display->nscreens = 1; + display->default_screen = 0; + screen->cmap = XCreateColormap(display, None, screen->root_visual, + AllocNone); + winDisplay = (TkDisplay *) ckalloc(sizeof(TkDisplay)); + winDisplay->display = display; + return winDisplay; +} + +/* + *---------------------------------------------------------------------- + * + * TkpCloseDisplay -- + * + * Closes and deallocates a Display structure created with the + * TkpOpenDisplay function. + * + * Results: + * None. + * + * Side effects: + * Frees up memory. + * + *---------------------------------------------------------------------- + */ + +void +TkpCloseDisplay(dispPtr) + TkDisplay *dispPtr; +{ + Display *display = dispPtr->display; + HWND hwnd; + + if (dispPtr != winDisplay) { + panic("TkpCloseDisplay: tried to call TkpCloseDisplay on another display"); + return; + } + + /* + * Force the clipboard to be rendered if we are the clipboard owner. + */ + + if (dispPtr->clipWindow) { + hwnd = Tk_GetHWND(Tk_WindowId(dispPtr->clipWindow)); + if (GetClipboardOwner() == hwnd) { + OpenClipboard(hwnd); + EmptyClipboard(); + TkWinClipboardRender(dispPtr, CF_TEXT); + CloseClipboard(); + } + } + + winDisplay = NULL; + + if (display->display_name != (char *) NULL) { + ckfree(display->display_name); + } + if (display->screens != (Screen *) NULL) { + if (display->screens->root_visual != NULL) { + ckfree((char *) display->screens->root_visual); + } + if (display->screens->root != None) { + ckfree((char *) display->screens->root); + } + if (display->screens->cmap != None) { + XFreeColormap(display, display->screens->cmap); + } + ckfree((char *) display->screens); + } + ckfree((char *) display); + ckfree((char *) dispPtr); +} + +/* + *---------------------------------------------------------------------- + * + * XBell -- + * + * Generate a beep. + * + * Results: + * None. + * + * Side effects: + * Plays a sounds out the system speakers. + * + *---------------------------------------------------------------------- + */ + +void +XBell(display, percent) + Display* display; + int percent; +{ + MessageBeep(MB_OK); +} + +/* + *---------------------------------------------------------------------- + * + * TkWinChildProc -- + * + * Callback from Windows whenever an event occurs on a child + * window. + * + * Results: + * Standard Windows return value. + * + * Side effects: + * May process events off the Tk event queue. + * + *---------------------------------------------------------------------- + */ + +LRESULT CALLBACK +TkWinChildProc(hwnd, message, wParam, lParam) + HWND hwnd; + UINT message; + WPARAM wParam; + LPARAM lParam; +{ + LRESULT result; + + switch (message) { + case WM_SETCURSOR: + /* + * Short circuit the WM_SETCURSOR message since we set + * the cursor elsewhere. + */ + + result = TRUE; + break; + + case WM_CREATE: + case WM_ERASEBKGND: + case WM_WINDOWPOSCHANGED: + result = 0; + break; + + case WM_PAINT: + GenerateXEvent(hwnd, message, wParam, lParam); + result = DefWindowProc(hwnd, message, wParam, lParam); + break; + + case TK_CLAIMFOCUS: + case TK_GEOMETRYREQ: + case TK_ATTACHWINDOW: + case TK_DETACHWINDOW: + result = TkWinEmbeddedEventProc(hwnd, message, wParam, lParam); + break; + + default: + if (!Tk_TranslateWinEvent(hwnd, message, wParam, lParam, + &result)) { + result = DefWindowProc(hwnd, message, wParam, lParam); + } + break; + } + + /* + * Handle any newly queued events before returning control to Windows. + */ + + Tcl_ServiceAll(); + return result; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_TranslateWinEvent -- + * + * This function is called by widget window procedures to handle + * the translation from Win32 events to Tk events. + * + * Results: + * Returns 1 if the event was handled, else 0. + * + * Side effects: + * Depends on the event. + * + *---------------------------------------------------------------------- + */ + +int +Tk_TranslateWinEvent(hwnd, message, wParam, lParam, resultPtr) + HWND hwnd; + UINT message; + WPARAM wParam; + LPARAM lParam; + LRESULT *resultPtr; +{ + *resultPtr = 0; + switch (message) { + case WM_RENDERFORMAT: { + TkWindow *winPtr = (TkWindow *) Tk_HWNDToWindow(hwnd); + if (winPtr) { + TkWinClipboardRender(winPtr->dispPtr, wParam); + } + return 1; + } + + case WM_COMMAND: + case WM_NOTIFY: + case WM_VSCROLL: + case WM_HSCROLL: { + /* + * Reflect these messages back to the sender so that they + * can be handled by the window proc for the control. Note + * that we need to be careful not to reflect a message that + * is targeted to this window, or we will loop. + */ + + HWND target = (message == WM_NOTIFY) + ? ((NMHDR*)lParam)->hwndFrom : (HWND) lParam; + if (target && target != hwnd) { + *resultPtr = SendMessage(target, message, wParam, lParam); + return 1; + } + break; + } + + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + case WM_MBUTTONDOWN: + case WM_MBUTTONDBLCLK: + case WM_RBUTTONDOWN: + case WM_RBUTTONDBLCLK: + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_MOUSEMOVE: + Tk_PointerEvent(hwnd, (short) LOWORD(lParam), + (short) HIWORD(lParam)); + return 1; + + case WM_CLOSE: + case WM_SETFOCUS: + case WM_KILLFOCUS: + case WM_DESTROYCLIPBOARD: + case WM_CHAR: + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + case WM_KEYDOWN: + case WM_KEYUP: + GenerateXEvent(hwnd, message, wParam, lParam); + return 1; + } + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * GenerateXEvent -- + * + * This routine generates an X event from the corresponding + * Windows event. + * + * Results: + * None. + * + * Side effects: + * Queues one or more X events. + * + *---------------------------------------------------------------------- + */ + +static void +GenerateXEvent(hwnd, message, wParam, lParam) + HWND hwnd; + UINT message; + WPARAM wParam; + LPARAM lParam; +{ + XEvent event; + TkWindow *winPtr = (TkWindow *)Tk_HWNDToWindow(hwnd); + + if (!winPtr || winPtr->window == None) { + return; + } + + event.xany.serial = winPtr->display->request++; + event.xany.send_event = False; + event.xany.display = winPtr->display; + event.xany.window = winPtr->window; + + switch (message) { + case WM_PAINT: { + PAINTSTRUCT ps; + + event.type = Expose; + BeginPaint(hwnd, &ps); + event.xexpose.x = ps.rcPaint.left; + event.xexpose.y = ps.rcPaint.top; + event.xexpose.width = ps.rcPaint.right - ps.rcPaint.left; + event.xexpose.height = ps.rcPaint.bottom - ps.rcPaint.top; + EndPaint(hwnd, &ps); + event.xexpose.count = 0; + break; + } + + case WM_CLOSE: + event.type = ClientMessage; + event.xclient.message_type = + Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS"); + event.xclient.format = 32; + event.xclient.data.l[0] = + Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW"); + break; + + case WM_SETFOCUS: + case WM_KILLFOCUS: { + TkWindow *otherWinPtr = (TkWindow *)Tk_HWNDToWindow((HWND) wParam); + + /* + * Compare toplevel windows to avoid reporting focus + * changes within the same toplevel. + */ + + while (!(winPtr->flags & TK_TOP_LEVEL)) { + winPtr = winPtr->parentPtr; + if (winPtr == NULL) { + return; + } + } + while (otherWinPtr && !(otherWinPtr->flags & TK_TOP_LEVEL)) { + otherWinPtr = otherWinPtr->parentPtr; + } + if (otherWinPtr == winPtr) { + return; + } + + event.xany.window = winPtr->window; + event.type = (message == WM_SETFOCUS) ? FocusIn : FocusOut; + event.xfocus.mode = NotifyNormal; + event.xfocus.detail = NotifyNonlinear; + break; + } + + case WM_DESTROYCLIPBOARD: + event.type = SelectionClear; + event.xselectionclear.selection = + Tk_InternAtom((Tk_Window)winPtr, "CLIPBOARD"); + event.xselectionclear.time = TkpGetMS(); + break; + + case WM_CHAR: + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + case WM_KEYDOWN: + case WM_KEYUP: { + unsigned int state = GetState(message, wParam, lParam); + Time time = TkpGetMS(); + POINT clientPoint; + POINTS rootPoint; /* Note: POINT and POINTS are different */ + DWORD msgPos; + + /* + * Compute the screen and window coordinates of the event. + */ + + msgPos = GetMessagePos(); + rootPoint = MAKEPOINTS(msgPos); + clientPoint.x = rootPoint.x; + clientPoint.y = rootPoint.y; + ScreenToClient(hwnd, &clientPoint); + + /* + * Set up the common event fields. + */ + + event.xbutton.root = RootWindow(winPtr->display, + winPtr->screenNum); + event.xbutton.subwindow = None; + event.xbutton.x = clientPoint.x; + event.xbutton.y = clientPoint.y; + event.xbutton.x_root = rootPoint.x; + event.xbutton.y_root = rootPoint.y; + event.xbutton.state = state; + event.xbutton.time = time; + event.xbutton.same_screen = True; + + /* + * Now set up event specific fields. + */ + + switch (message) { + case WM_SYSKEYDOWN: + case WM_KEYDOWN: + /* + * Check for translated characters in the event queue. + * Setting xany.send_event to -1 indicates to the + * Windows implementation of XLookupString that this + * event was generated by windows and that the Windows + * extension xkey.trans_chars is filled with the + * characters that came from the TranslateMessage + * call. If it is not -1, xkey.keycode is the + * virtual key being sent programmatically by generic + * code. + */ + + event.type = KeyPress; + event.xany.send_event = -1; + event.xkey.keycode = wParam; + GetTranslatedKey(&event.xkey); + break; + + case WM_SYSKEYUP: + case WM_KEYUP: + /* + * We don't check for translated characters on keyup + * because Tk won't know what to do with them. Instead, we + * wait for the WM_CHAR messages which will follow. + */ + event.type = KeyRelease; + event.xkey.keycode = wParam; + event.xkey.nchars = 0; + break; + + case WM_CHAR: + /* + * Synthesize both a KeyPress and a KeyRelease. + */ + + event.type = KeyPress; + event.xany.send_event = -1; + event.xkey.keycode = 0; + event.xkey.nchars = 1; + event.xkey.trans_chars[0] = (char) wParam; + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + event.type = KeyRelease; + break; + } + break; + } + + default: + return; + } + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); +} + +/* + *---------------------------------------------------------------------- + * + * GetState -- + * + * This function constructs a state mask for the mouse buttons + * and modifier keys as they were before the event occured. + * + * Results: + * Returns a composite value of all the modifier and button state + * flags that were set at the time the event occurred. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static unsigned int +GetState(message, wParam, lParam) + UINT message; /* Win32 message type */ + WPARAM wParam; /* wParam of message, used if key message */ + LPARAM lParam; /* lParam of message, used if key message */ +{ + int mask; + int prevState; /* 1 if key was previously down */ + unsigned int state = TkWinGetModifierState(); + + /* + * If the event is a key press or release, we check for modifier + * keys so we can report the state of the world before the event. + */ + + if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN + || message == WM_SYSKEYUP || message == WM_KEYUP) { + mask = 0; + prevState = HIWORD(lParam) & KF_REPEAT; + switch(wParam) { + case VK_SHIFT: + mask = ShiftMask; + break; + case VK_CONTROL: + mask = ControlMask; + break; + case VK_MENU: + mask = Mod2Mask; + break; + case VK_CAPITAL: + if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN) { + mask = LockMask; + prevState = ((state & mask) ^ prevState) ? 0 : 1; + } + break; + case VK_NUMLOCK: + if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN) { + mask = Mod1Mask; + prevState = ((state & mask) ^ prevState) ? 0 : 1; + } + break; + case VK_SCROLL: + if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN) { + mask = Mod3Mask; + prevState = ((state & mask) ^ prevState) ? 0 : 1; + } + break; + } + if (prevState) { + state |= mask; + } else { + state &= ~mask; + } + } + return state; +} + +/* + *---------------------------------------------------------------------- + * + * GetTranslatedKey -- + * + * Retrieves WM_CHAR messages that are placed on the system queue + * by the TranslateMessage system call and places them in the + * given KeyPress event. + * + * Results: + * Sets the trans_chars and nchars member of the key event. + * + * Side effects: + * Removes any WM_CHAR messages waiting on the top of the system + * event queue. + * + *---------------------------------------------------------------------- + */ + +static void +GetTranslatedKey(xkey) + XKeyEvent *xkey; +{ + MSG msg; + + xkey->nchars = 0; + + while (xkey->nchars < XMaxTransChars + && PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { + if (msg.message == WM_CHAR) { + xkey->trans_chars[xkey->nchars] = (char) msg.wParam; + xkey->nchars++; + GetMessage(&msg, NULL, 0, 0); + if ((msg.message == WM_CHAR) && (msg.lParam & 0x20000000)) { + xkey->state = 0; + } + } else { + break; + } + } +} + +/* + *---------------------------------------------------------------------- + * + * Tk_FreeXId -- + * + * This inteface is not needed under Windows. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +Tk_FreeXId(display, xid) + Display *display; + XID xid; +{ +} + +/* + *---------------------------------------------------------------------- + * + * TkWinResendEvent -- + * + * This function converts an X event into a Windows event and + * invokes the specified windo procedure. + * + * Results: + * A standard Windows result. + * + * Side effects: + * Invokes the window procedure + * + *---------------------------------------------------------------------- + */ + +LRESULT +TkWinResendEvent(wndproc, hwnd, eventPtr) + WNDPROC wndproc; + HWND hwnd; + XEvent *eventPtr; +{ + UINT msg; + WPARAM wparam; + LPARAM lparam; + + if (eventPtr->type == ButtonPress) { + switch (eventPtr->xbutton.button) { + case Button1: + msg = WM_LBUTTONDOWN; + wparam = MK_LBUTTON; + break; + case Button2: + msg = WM_MBUTTONDOWN; + wparam = MK_MBUTTON; + break; + case Button3: + msg = WM_RBUTTONDOWN; + wparam = MK_RBUTTON; + break; + default: + return 0; + } + if (eventPtr->xbutton.state & Button1Mask) { + wparam |= MK_LBUTTON; + } + if (eventPtr->xbutton.state & Button2Mask) { + wparam |= MK_MBUTTON; + } + if (eventPtr->xbutton.state & Button3Mask) { + wparam |= MK_RBUTTON; + } + if (eventPtr->xbutton.state & ShiftMask) { + wparam |= MK_SHIFT; + } + if (eventPtr->xbutton.state & ControlMask) { + wparam |= MK_CONTROL; + } + lparam = MAKELPARAM((short) eventPtr->xbutton.x, + (short) eventPtr->xbutton.y); + } else { + return 0; + } + return CallWindowProc(wndproc, hwnd, msg, wparam, lparam); +} + +/* + *---------------------------------------------------------------------- + * + * TkpGetMS -- + * + * Return a relative time in milliseconds. It doesn't matter + * when the epoch was. + * + * Results: + * Number of milliseconds. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +unsigned long +TkpGetMS() +{ + return GetCurrentTime(); +} |