summaryrefslogtreecommitdiffstats
path: root/win/tkWinX.c
diff options
context:
space:
mode:
Diffstat (limited to 'win/tkWinX.c')
-rw-r--r--win/tkWinX.c124
1 files changed, 98 insertions, 26 deletions
diff --git a/win/tkWinX.c b/win/tkWinX.c
index 50a9e24..358d15e 100644
--- a/win/tkWinX.c
+++ b/win/tkWinX.c
@@ -10,10 +10,9 @@
* 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 $
+ * RCS: @(#) $Id: tkWinX.c,v 1.5 1999/04/16 01:51:54 stanton Exp $
*/
-#include "tkInt.h"
#include "tkWinInt.h"
/*
@@ -32,13 +31,23 @@ 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? */
+static char winScreenName[] = ":0"; /* Default name of windows display. */
+static HINSTANCE tkInstance; /* Application instance handle. */
+static int childClassInitialized; /* Registered child class? */
+static WNDCLASS childClass; /* Window class for child windows. */
+
+TCL_DECLARE_MUTEX(winXMutex)
+
+/*
+ * Thread local storage. Notice that now each thread must have its
+ * own TkDisplay structure, since this structure contains most of
+ * the thread-specific date for threads.
+ */
+typedef struct ThreadSpecificData {
+ TkDisplay *winDisplay; /* TkDisplay structure that *
+ * represents Windows screen. */
+} ThreadSpecificData;
+static Tcl_ThreadDataKey dataKey;
/*
* Forward declarations of procedures used in this file.
@@ -142,7 +151,21 @@ TkWinXInit(hInstance)
tkInstance = hInstance;
+ /*
+ * When threads are enabled, we cannot use CLASSDC because
+ * threads will then write into the same device context.
+ *
+ * This is a hack; we should add a subsystem that manages
+ * device context on a per-thread basis. See also tkWinWm.c,
+ * which also initializes a WNDCLASS structure.
+ */
+
+#ifdef TCL_THREADS
+ childClass.style = CS_HREDRAW | CS_VREDRAW;
+#else
childClass.style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC;
+#endif
+
childClass.cbClsExtra = 0;
childClass.cbWndExtra = 0;
childClass.hInstance = hInstance;
@@ -236,10 +259,10 @@ TkGetDefaultScreenName(interp, screenName)
* specific information.
*
* Results:
- * Returns a Display structure on success or NULL on failure.
+ * Returns a TkDisplay structure on success or NULL on failure.
*
* Side effects:
- * Allocates a new Display structure.
+ * Allocates a new TkDisplay structure.
*
*----------------------------------------------------------------------
*/
@@ -252,10 +275,13 @@ TkpOpenDisplay(display_name)
HDC dc;
TkWinDrawable *twdPtr;
Display *display;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- if (winDisplay != NULL) {
- if (strcmp(winDisplay->display->display_name, display_name) == 0) {
- return winDisplay;
+ if (tsdPtr->winDisplay != NULL) {
+ if (strcmp(tsdPtr->winDisplay->display->display_name, display_name)
+ == 0) {
+ return tsdPtr->winDisplay;
} else {
return NULL;
}
@@ -357,9 +383,9 @@ TkpOpenDisplay(display_name)
display->default_screen = 0;
screen->cmap = XCreateColormap(display, None, screen->root_visual,
AllocNone);
- winDisplay = (TkDisplay *) ckalloc(sizeof(TkDisplay));
- winDisplay->display = display;
- return winDisplay;
+ tsdPtr->winDisplay = (TkDisplay *) ckalloc(sizeof(TkDisplay));
+ tsdPtr->winDisplay->display = display;
+ return tsdPtr->winDisplay;
}
/*
@@ -385,8 +411,10 @@ TkpCloseDisplay(dispPtr)
{
Display *display = dispPtr->display;
HWND hwnd;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- if (dispPtr != winDisplay) {
+ if (dispPtr != tsdPtr->winDisplay) {
panic("TkpCloseDisplay: tried to call TkpCloseDisplay on another display");
return;
}
@@ -405,7 +433,7 @@ TkpCloseDisplay(dispPtr)
}
}
- winDisplay = NULL;
+ tsdPtr->winDisplay = NULL;
if (display->display_name != (char *) NULL) {
ckfree(display->display_name);
@@ -795,19 +823,61 @@ GenerateXEvent(hwnd, message, wParam, lParam)
*/
event.type = KeyRelease;
event.xkey.keycode = wParam;
- event.xkey.nchars = 0;
+ event.xkey.nbytes = 0;
break;
case WM_CHAR:
/*
* Synthesize both a KeyPress and a KeyRelease.
+ * Strings generated by Input Method Editor are handled
+ * in the following manner:
+ * 1. A series of WM_KEYDOWN & WM_KEYUP messages that
+ * cause GetTranslatedKey() to be called and return
+ * immediately because the WM_KEYDOWNs have no
+ * associated WM_CHAR messages -- the IME window is
+ * accumulating the characters and translating them
+ * itself. In the "bind" command, you get an event
+ * with a mystery keysym and %A == "" for each
+ * WM_KEYDOWN that actually was meant for the IME.
+ * 2. A WM_KEYDOWN corresponding to the "confirm typing"
+ * character. This causes GetTranslatedKey() to be
+ * called.
+ * 3. A WM_IME_NOTIFY message saying that the IME is
+ * done. A side effect of this message is that
+ * GetTranslatedKey() thinks this means that there
+ * are no WM_CHAR messages and returns immediately.
+ * In the "bind" command, you get an another event
+ * with a mystery keysym and %A == "".
+ * 4. A sequence of WM_CHAR messages that correspond to
+ * the characters in the IME window. A bunch of
+ * simulated KeyPress/KeyRelease events will be
+ * generated, one for each character. Adjacent
+ * WM_CHAR messages may actually specify the high
+ * and low bytes of a multi-byte character -- in that
+ * case the two WM_CHAR messages will be combined into
+ * one event. It is the event-consumer's
+ * responsibility to convert the string returned from
+ * XLookupString from system encoding to UTF-8.
+ * 5. And finally we get the WM_KEYUP for the "confirm
+ * typing" character.
*/
event.type = KeyPress;
event.xany.send_event = -1;
event.xkey.keycode = 0;
- event.xkey.nchars = 1;
+ event.xkey.nbytes = 1;
event.xkey.trans_chars[0] = (char) wParam;
+
+ if (IsDBCSLeadByte((BYTE) wParam)) {
+ MSG msg;
+
+ if ((PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) != 0)
+ && (msg.message == WM_CHAR)) {
+ GetMessage(&msg, NULL, 0, 0);
+ event.xkey.nbytes = 2;
+ event.xkey.trans_chars[1] = (char) msg.wParam;
+ }
+ }
Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
event.type = KeyRelease;
break;
@@ -906,7 +976,7 @@ GetState(message, wParam, lParam)
* given KeyPress event.
*
* Results:
- * Sets the trans_chars and nchars member of the key event.
+ * Sets the trans_chars and nbytes member of the key event.
*
* Side effects:
* Removes any WM_CHAR messages waiting on the top of the system
@@ -920,14 +990,13 @@ GetTranslatedKey(xkey)
XKeyEvent *xkey;
{
MSG msg;
+ char buf[XMaxTransChars];
- xkey->nchars = 0;
+ xkey->nbytes = 0;
- while (xkey->nchars < XMaxTransChars
+ while ((xkey->nbytes < 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);
/*
@@ -941,6 +1010,9 @@ GetTranslatedKey(xkey)
if ((msg.message == WM_CHAR) && (msg.lParam & 0x20000000)) {
xkey->state = 0;
}
+ buf[xkey->nbytes] = (char) msg.wParam;
+ xkey->trans_chars[xkey->nbytes] = (char) msg.wParam;
+ xkey->nbytes++;
} else {
break;
}