Logo Search packages:      
Sourcecode: tcltk8.0-ja version File versions  Download package

tkWinX.c

/* 
 * 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.
 * Copyright (c) 1998 by Scriptics Corporation.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tkWinX.c,v 1.4 1998/10/10 00:30:37 rjohnson Exp $
 */

#include "tkInt.h"
#include "tkWinInt.h"

/*
 * The zmouse.h file includes the definition for WM_MOUSEWHEEL.
 */

#ifdef BUGFIX
#if defined(_MSC_VER) && _MSC_VER >= 1100
#include <zmouse.h>
#endif /* _MSC_VER */
#ifndef WM_MOUSEWHEEL
#define WM_MOUSEWHEEL   0x20A
#endif /* !WM_MOUSEWHEEL */
#else
#include <zmouse.h>
#endif /* BUGFIX */

/*
 * 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));
#if defined(KANJI) && defined(IME_AWARE)
static void       ConfigureIMEComposition _ANSI_ARGS_((HWND hwnd));
#endif /* KANJI && IME_AWARE */

/*
 *----------------------------------------------------------------------
 *
 * 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;

#if defined(KANJI) && defined(IME_AWARE)
      case WM_IME_STARTCOMPOSITION:
          result = DefWindowProc(hwnd, message, wParam, lParam);
          ConfigureIMEComposition(hwnd);
          break;
#endif /* KANJI && IME_AWARE */
      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:
#ifdef KANJI
      case WM_IME_CHAR:
#endif
      case WM_SYSKEYDOWN:
      case WM_SYSKEYUP:
      case WM_KEYDOWN:
      case WM_KEYUP:
#ifdef USE_MOUSEWHEEL
      case WM_MOUSEWHEEL:
#endif /* USE_MOUSEWHEEL */
          GenerateXEvent(hwnd, message, wParam, lParam);
          return 1;
      case WM_MENUCHAR:
          GenerateXEvent(hwnd, message, wParam, lParam);
          /* MNC_CLOSE is the only one that looks right.  This is a hack. */
          *resultPtr = MAKELONG (0, MNC_CLOSE);
          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;

#ifdef USE_MOUSEWHEEL       
      case WM_MOUSEWHEEL:
          /*
           * The mouse wheel event is closer to a key event than a
           * mouse event in that the message is sent to the window
           * that has focus.
           */
#endif /* USE_MOUSEWHEEL */
          
      case WM_CHAR:
#ifdef KANJI
      case WM_IME_CHAR:
#endif
      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) {
#ifdef USE_MOUSEWHEEL
            case WM_MOUSEWHEEL:
                /*
                 * We have invented a new X event type to handle
                 * this event.  It still uses the KeyPress struct.
                 * However, the keycode field has been overloaded
                 * to hold the zDelta of the wheel.
                 */
                
                event.type = MouseWheelEvent;
                event.xany.send_event = -1;
                event.xkey.keycode = (short) HIWORD(wParam);
                break;
#endif /* USE_MOUSEWHEEL */
            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;
#ifdef KANJI
            case WM_IME_CHAR:
                /*
                 * Synthesize both a KeyPress and a KeyRelease.
                 */

                event.type = KeyPress;
                event.xany.send_event = -1;
                event.xkey.keycode = 0;
                if (wParam>>8 != 0) {
                  event.xkey.nchars = 2;
                  event.xkey.trans_chars[0] = (TCHAR) (wParam>>8);
                  event.xkey.trans_chars[1] = (TCHAR) wParam;
                } else {
                  event.xkey.nchars = 1;
                  event.xkey.trans_chars[0] = (TCHAR) wParam;
                }
                Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
                event.type = KeyRelease;
                break;
#endif /* KANJI */
          }
          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) || (msg.message == WM_SYSCHAR)) {
          xkey->trans_chars[xkey->nchars] = (char) msg.wParam;
          xkey->nchars++;
          GetMessage(&msg, NULL, 0, 0);

          /*
           * If this is a normal character message, we may need to strip
           * off the Alt modifier (e.g. Alt-digits).  Note that we don't
           * want to do this for system messages, because those were
           * presumably generated as an Alt-char sequence (e.g. accelerator
           * keys).
           */

          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();
}

#if defined(KANJI) && defined(IME_AWARE)

static void
ConfigureIMEComposition(hwnd)
    HWND hwnd;
{
    /* set composition window placement */
    TkWindow *winPtr = (TkWindow *) Tk_HWNDToWindow(hwnd);
    Tk_Window focusPtr = (Tk_Window)TkGetFocusWin(winPtr);

    if (focusPtr) {
      HWND hwndFocus = Tk_GetHWND(Tk_WindowId(focusPtr));
      HIMC hIMC = ImmGetContext(hwnd);
      COMPOSITIONFORM form;
      int xpos, ypos, left, top;

      Tk_GetRootCoords(focusPtr, &left, &top);
      Tk_GetRootCoords((Tk_Window)winPtr, &xpos, &ypos);
      left -= xpos;
      top -= ypos;
      /* default: at bottom of a focused widget. */
      xpos = left;
      ypos = top + Tk_Height(focusPtr);

      if (Tk_Class(focusPtr) == Tk_GetUid("Entry") ||
          Tk_Class(focusPtr) == Tk_GetUid("Text")) {
          Tcl_Interp *interp = winPtr->mainPtr->interp;
          int argc;
          char **argv;
          /* Entry/Text: near the insertion cursor. */
          if (Tcl_VarEval(interp, Tk_PathName(focusPtr), " xypos insert",
                      NULL) == TCL_OK &&
            Tcl_SplitList(interp, Tcl_GetStringResult(interp),
                        &argc, &argv) == TCL_OK &&
            argc == 2 &&
            Tcl_GetInt(interp, argv[0], &xpos) == TCL_OK &&
            Tcl_GetInt(interp, argv[1], &ypos) == TCL_OK) {

            /* get metrics of the IME font */
            HDC hdc = GetDC(hwndFocus);
            LOGFONT lf;
            TEXTMETRIC tm;
            ImmGetCompositionFont(hIMC, &lf);
            SelectObject(hdc, CreateFontIndirect(&lf));
            GetTextMetrics(hdc, &tm);
            ReleaseDC(hwndFocus, hdc);

            xpos += left;
            ypos += top;
            ypos -= tm.tmAscent;
          }
      }
      form.dwStyle = CFS_POINT;
      form.ptCurrentPos.x = xpos;
      form.ptCurrentPos.y = ypos;
      ImmSetCompositionWindow(hIMC, &form);
      ImmReleaseContext(hwnd, hIMC);
    }
}
#endif /* KANJI && IME_AWARE */

Generated by  Doxygen 1.6.0   Back to index