/[dtapublic]/projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkwinx.c
ViewVC logotype

Contents of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkwinx.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 71 - (show annotations) (download)
Sat Nov 5 11:07:06 2016 UTC (7 years, 11 months ago) by dashley
File MIME type: text/plain
File size: 30555 byte(s)
Set EOL properties appropriately to facilitate simultaneous Linux and Windows development.
1 /* $Header$ */
2
3 /*
4 * tkWinX.c --
5 *
6 * This file contains Windows emulation procedures for X routines.
7 *
8 * Copyright (c) 1995-1996 Sun Microsystems, Inc.
9 * Copyright (c) 1994 Software Research Associates, Inc.
10 * Copyright (c) 1998-2000 by Scriptics Corporation.
11 *
12 * See the file "license.terms" for information on usage and redistribution
13 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 *
15 * RCS: @(#) $Id: tkWinX.c,v 1.10 2000/04/19 01:06:51 ericm Exp $
16 */
17
18 #include "tkWinInt.h"
19
20 /*
21 * The zmouse.h file includes the definition for WM_MOUSEWHEEL.
22 */
23
24 #include <zmouse.h>
25
26 /*
27 * Declarations of static variables used in this file.
28 */
29
30 static char winScreenName[] = ":0"; /* Default name of windows display. */
31 static HINSTANCE tkInstance; /* Application instance handle. */
32 static int childClassInitialized; /* Registered child class? */
33 static WNDCLASS childClass; /* Window class for child windows. */
34 static int tkPlatformId; /* version of Windows platform */
35
36 TCL_DECLARE_MUTEX(winXMutex)
37
38 /*
39 * Thread local storage. Notice that now each thread must have its
40 * own TkDisplay structure, since this structure contains most of
41 * the thread-specific date for threads.
42 */
43 typedef struct ThreadSpecificData {
44 TkDisplay *winDisplay; /* TkDisplay structure that *
45 * represents Windows screen. */
46 int updatingClipboard; /* If 1, we are updating the clipboard */
47 } ThreadSpecificData;
48 static Tcl_ThreadDataKey dataKey;
49
50 /*
51 * Forward declarations of procedures used in this file.
52 */
53
54 static void GenerateXEvent _ANSI_ARGS_((HWND hwnd, UINT message,
55 WPARAM wParam, LPARAM lParam));
56 static unsigned int GetState _ANSI_ARGS_((UINT message, WPARAM wParam,
57 LPARAM lParam));
58 static void GetTranslatedKey _ANSI_ARGS_((XKeyEvent *xkey));
59
60 /*
61 *----------------------------------------------------------------------
62 *
63 * TkGetServerInfo --
64 *
65 * Given a window, this procedure returns information about
66 * the window server for that window. This procedure provides
67 * the guts of the "winfo server" command.
68 *
69 * Results:
70 * None.
71 *
72 * Side effects:
73 * None.
74 *
75 *----------------------------------------------------------------------
76 */
77
78 void
79 TkGetServerInfo(interp, tkwin)
80 Tcl_Interp *interp; /* The server information is returned in
81 * this interpreter's result. */
82 Tk_Window tkwin; /* Token for window; this selects a
83 * particular display and server. */
84 {
85 char buffer[60];
86 OSVERSIONINFO os;
87
88 os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
89 GetVersionEx(&os);
90 sprintf(buffer, "Windows %d.%d %d Win32", os.dwMajorVersion,
91 os.dwMinorVersion, os.dwBuildNumber);
92 Tcl_SetResult(interp, buffer, TCL_VOLATILE);
93 }
94
95 /*
96 *----------------------------------------------------------------------
97 *
98 * Tk_GetHINSTANCE --
99 *
100 * Retrieves the global instance handle used by the Tk library.
101 *
102 * Results:
103 * Returns the global instance handle.
104 *
105 * Side effects:
106 * None.
107 *
108 *----------------------------------------------------------------------
109 */
110
111 HINSTANCE
112 Tk_GetHINSTANCE()
113 {
114 return tkInstance;
115 }
116
117 /*
118 *----------------------------------------------------------------------
119 *
120 * TkWinXInit --
121 *
122 * Initialize Xlib emulation layer.
123 *
124 * Results:
125 * None.
126 *
127 * Side effects:
128 * Sets up various data structures.
129 *
130 *----------------------------------------------------------------------
131 */
132
133 void
134 TkWinXInit(hInstance)
135 HINSTANCE hInstance;
136 {
137 OSVERSIONINFO os;
138
139 if (childClassInitialized != 0) {
140 return;
141 }
142 childClassInitialized = 1;
143
144 tkInstance = hInstance;
145
146 os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
147 GetVersionEx(&os);
148 tkPlatformId = os.dwPlatformId;
149
150 /*
151 * When threads are enabled, we cannot use CLASSDC because
152 * threads will then write into the same device context.
153 *
154 * This is a hack; we should add a subsystem that manages
155 * device context on a per-thread basis. See also tkWinWm.c,
156 * which also initializes a WNDCLASS structure.
157 */
158
159 #ifdef TCL_THREADS
160 childClass.style = CS_HREDRAW | CS_VREDRAW;
161 #else
162 childClass.style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC;
163 #endif
164
165 childClass.cbClsExtra = 0;
166 childClass.cbWndExtra = 0;
167 childClass.hInstance = hInstance;
168 childClass.hbrBackground = NULL;
169 childClass.lpszMenuName = NULL;
170
171 /*
172 * Register the Child window class.
173 */
174
175 childClass.lpszClassName = TK_WIN_CHILD_CLASS_NAME;
176 childClass.lpfnWndProc = TkWinChildProc;
177 childClass.hIcon = NULL;
178 childClass.hCursor = NULL;
179
180 if (!RegisterClass(&childClass)) {
181 panic("Unable to register TkChild class");
182 }
183 }
184
185 /*
186 *----------------------------------------------------------------------
187 *
188 * TkWinXCleanup --
189 *
190 * Removes the registered classes for Tk.
191 *
192 * Results:
193 * None.
194 *
195 * Side effects:
196 * Removes window classes from the system.
197 *
198 *----------------------------------------------------------------------
199 */
200
201 void
202 TkWinXCleanup(hInstance)
203 HINSTANCE hInstance;
204 {
205 /*
206 * Clean up our own class.
207 */
208
209 if (childClassInitialized) {
210 childClassInitialized = 0;
211 UnregisterClass(TK_WIN_CHILD_CLASS_NAME, hInstance);
212 }
213
214 /*
215 * And let the window manager clean up its own class(es).
216 */
217
218 TkWinWmCleanup(hInstance);
219 }
220
221 /*
222 *----------------------------------------------------------------------
223 *
224 * TkWinGetPlatformId --
225 *
226 * Determines whether running under NT, 95, or Win32s, to allow
227 * runtime conditional code.
228 *
229 * Results:
230 * The return value is one of:
231 * VER_PLATFORM_WIN32s Win32s on Windows 3.1.
232 * VER_PLATFORM_WIN32_WINDOWS Win32 on Windows 95.
233 * VER_PLATFORM_WIN32_NT Win32 on Windows NT
234 *
235 * Side effects:
236 * None.
237 *
238 *----------------------------------------------------------------------
239 */
240
241 int
242 TkWinGetPlatformId()
243 {
244 return tkPlatformId;
245 }
246
247 /*
248 *----------------------------------------------------------------------
249 *
250 * TkGetDefaultScreenName --
251 *
252 * Returns the name of the screen that Tk should use during
253 * initialization.
254 *
255 * Results:
256 * Returns a statically allocated string.
257 *
258 * Side effects:
259 * None.
260 *
261 *----------------------------------------------------------------------
262 */
263
264 char *
265 TkGetDefaultScreenName(interp, screenName)
266 Tcl_Interp *interp; /* Not used. */
267 char *screenName; /* If NULL, use default string. */
268 {
269 if ((screenName == NULL) || (screenName[0] == '\0')) {
270 screenName = winScreenName;
271 }
272 return screenName;
273 }
274
275 /*
276 *----------------------------------------------------------------------
277 *
278 * TkpOpenDisplay --
279 *
280 * Create the Display structure and fill it with device
281 * specific information.
282 *
283 * Results:
284 * Returns a TkDisplay structure on success or NULL on failure.
285 *
286 * Side effects:
287 * Allocates a new TkDisplay structure.
288 *
289 *----------------------------------------------------------------------
290 */
291
292 TkDisplay *
293 TkpOpenDisplay(display_name)
294 char *display_name;
295 {
296 Screen *screen;
297 HDC dc;
298 TkWinDrawable *twdPtr;
299 Display *display;
300 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
301 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
302
303 if (tsdPtr->winDisplay != NULL) {
304 if (strcmp(tsdPtr->winDisplay->display->display_name, display_name)
305 == 0) {
306 return tsdPtr->winDisplay;
307 } else {
308 return NULL;
309 }
310 }
311
312 display = (Display *) ckalloc(sizeof(Display));
313 display->display_name = (char *) ckalloc(strlen(display_name)+1);
314 strcpy(display->display_name, display_name);
315
316 display->cursor_font = 1;
317 display->nscreens = 1;
318 display->request = 1;
319 display->qlen = 0;
320
321 screen = (Screen *) ckalloc(sizeof(Screen));
322 screen->display = display;
323
324 dc = GetDC(NULL);
325 screen->width = GetDeviceCaps(dc, HORZRES);
326 screen->height = GetDeviceCaps(dc, VERTRES);
327 screen->mwidth = MulDiv(screen->width, 254,
328 GetDeviceCaps(dc, LOGPIXELSX) * 10);
329 screen->mheight = MulDiv(screen->height, 254,
330 GetDeviceCaps(dc, LOGPIXELSY) * 10);
331
332 /*
333 * Set up the root window.
334 */
335
336 twdPtr = (TkWinDrawable*) ckalloc(sizeof(TkWinDrawable));
337 if (twdPtr == NULL) {
338 return None;
339 }
340 twdPtr->type = TWD_WINDOW;
341 twdPtr->window.winPtr = NULL;
342 twdPtr->window.handle = NULL;
343 screen->root = (Window)twdPtr;
344
345 /*
346 * On windows, when creating a color bitmap, need two pieces of
347 * information: the number of color planes and the number of
348 * pixels per plane. Need to remember both quantities so that
349 * when constructing an HBITMAP for offscreen rendering, we can
350 * specify the correct value for the number of planes. Otherwise
351 * the HBITMAP won't be compatible with the HWND and we'll just
352 * get blank spots copied onto the screen.
353 */
354
355 screen->ext_data = (XExtData *) GetDeviceCaps(dc, PLANES);
356 screen->root_depth = GetDeviceCaps(dc, BITSPIXEL) * (int) screen->ext_data;
357
358 screen->root_visual = (Visual *) ckalloc(sizeof(Visual));
359 screen->root_visual->visualid = 0;
360 if (GetDeviceCaps(dc, RASTERCAPS) & RC_PALETTE) {
361 screen->root_visual->map_entries = GetDeviceCaps(dc, SIZEPALETTE);
362 screen->root_visual->class = PseudoColor;
363 screen->root_visual->red_mask = 0x0;
364 screen->root_visual->green_mask = 0x0;
365 screen->root_visual->blue_mask = 0x0;
366 } else {
367 if (screen->root_depth == 4) {
368 screen->root_visual->class = StaticColor;
369 screen->root_visual->map_entries = 16;
370 } else if (screen->root_depth == 8) {
371 screen->root_visual->class = StaticColor;
372 screen->root_visual->map_entries = 256;
373 } else if (screen->root_depth == 12) {
374 screen->root_visual->class = TrueColor;
375 screen->root_visual->map_entries = 32;
376 screen->root_visual->red_mask = 0xf0;
377 screen->root_visual->green_mask = 0xf000;
378 screen->root_visual->blue_mask = 0xf00000;
379 } else if (screen->root_depth == 16) {
380 screen->root_visual->class = TrueColor;
381 screen->root_visual->map_entries = 64;
382 screen->root_visual->red_mask = 0xf8;
383 screen->root_visual->green_mask = 0xfc00;
384 screen->root_visual->blue_mask = 0xf80000;
385 } else if (screen->root_depth >= 24) {
386 screen->root_visual->class = TrueColor;
387 screen->root_visual->map_entries = 256;
388 screen->root_visual->red_mask = 0xff;
389 screen->root_visual->green_mask = 0xff00;
390 screen->root_visual->blue_mask = 0xff0000;
391 }
392 }
393 screen->root_visual->bits_per_rgb = screen->root_depth;
394 ReleaseDC(NULL, dc);
395
396 /*
397 * Note that these pixel values are not palette relative.
398 */
399
400 screen->white_pixel = RGB(255, 255, 255);
401 screen->black_pixel = RGB(0, 0, 0);
402
403 display->screens = screen;
404 display->nscreens = 1;
405 display->default_screen = 0;
406 screen->cmap = XCreateColormap(display, None, screen->root_visual,
407 AllocNone);
408 tsdPtr->winDisplay = (TkDisplay *) ckalloc(sizeof(TkDisplay));
409 tsdPtr->winDisplay->display = display;
410 tsdPtr->updatingClipboard = FALSE;
411 return tsdPtr->winDisplay;
412 }
413
414 /*
415 *----------------------------------------------------------------------
416 *
417 * TkpCloseDisplay --
418 *
419 * Closes and deallocates a Display structure created with the
420 * TkpOpenDisplay function.
421 *
422 * Results:
423 * None.
424 *
425 * Side effects:
426 * Frees up memory.
427 *
428 *----------------------------------------------------------------------
429 */
430
431 void
432 TkpCloseDisplay(dispPtr)
433 TkDisplay *dispPtr;
434 {
435 Display *display = dispPtr->display;
436 HWND hwnd;
437 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
438 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
439
440 if (dispPtr != tsdPtr->winDisplay) {
441 panic("TkpCloseDisplay: tried to call TkpCloseDisplay on another display");
442 return;
443 }
444
445 /*
446 * Force the clipboard to be rendered if we are the clipboard owner.
447 */
448
449 if (dispPtr->clipWindow) {
450 hwnd = Tk_GetHWND(Tk_WindowId(dispPtr->clipWindow));
451 if (GetClipboardOwner() == hwnd) {
452 OpenClipboard(hwnd);
453 EmptyClipboard();
454 TkWinClipboardRender(dispPtr, CF_TEXT);
455 CloseClipboard();
456 }
457 }
458
459 tsdPtr->winDisplay = NULL;
460
461 if (display->display_name != (char *) NULL) {
462 ckfree(display->display_name);
463 }
464 if (display->screens != (Screen *) NULL) {
465 if (display->screens->root_visual != NULL) {
466 ckfree((char *) display->screens->root_visual);
467 }
468 if (display->screens->root != None) {
469 ckfree((char *) display->screens->root);
470 }
471 if (display->screens->cmap != None) {
472 XFreeColormap(display, display->screens->cmap);
473 }
474 ckfree((char *) display->screens);
475 }
476 ckfree((char *) display);
477 ckfree((char *) dispPtr);
478 }
479
480 /*
481 *----------------------------------------------------------------------
482 *
483 * XBell --
484 *
485 * Generate a beep.
486 *
487 * Results:
488 * None.
489 *
490 * Side effects:
491 * Plays a sounds out the system speakers.
492 *
493 *----------------------------------------------------------------------
494 */
495
496 void
497 XBell(display, percent)
498 Display* display;
499 int percent;
500 {
501 MessageBeep(MB_OK);
502 }
503
504 /*
505 *----------------------------------------------------------------------
506 *
507 * TkWinChildProc --
508 *
509 * Callback from Windows whenever an event occurs on a child
510 * window.
511 *
512 * Results:
513 * Standard Windows return value.
514 *
515 * Side effects:
516 * May process events off the Tk event queue.
517 *
518 *----------------------------------------------------------------------
519 */
520
521 LRESULT CALLBACK
522 TkWinChildProc(hwnd, message, wParam, lParam)
523 HWND hwnd;
524 UINT message;
525 WPARAM wParam;
526 LPARAM lParam;
527 {
528 LRESULT result;
529
530 switch (message) {
531 case WM_SETCURSOR:
532 /*
533 * Short circuit the WM_SETCURSOR message since we set
534 * the cursor elsewhere.
535 */
536
537 result = TRUE;
538 break;
539
540 case WM_CREATE:
541 case WM_ERASEBKGND:
542 result = 0;
543 break;
544
545 case WM_PAINT:
546 GenerateXEvent(hwnd, message, wParam, lParam);
547 result = DefWindowProc(hwnd, message, wParam, lParam);
548 break;
549
550 case TK_CLAIMFOCUS:
551 case TK_GEOMETRYREQ:
552 case TK_ATTACHWINDOW:
553 case TK_DETACHWINDOW:
554 result = TkWinEmbeddedEventProc(hwnd, message, wParam, lParam);
555 break;
556
557 default:
558 if (!Tk_TranslateWinEvent(hwnd, message, wParam, lParam,
559 &result)) {
560 result = DefWindowProc(hwnd, message, wParam, lParam);
561 }
562 break;
563 }
564
565 /*
566 * Handle any newly queued events before returning control to Windows.
567 */
568
569 Tcl_ServiceAll();
570 return result;
571 }
572
573 /*
574 *----------------------------------------------------------------------
575 *
576 * Tk_TranslateWinEvent --
577 *
578 * This function is called by widget window procedures to handle
579 * the translation from Win32 events to Tk events.
580 *
581 * Results:
582 * Returns 1 if the event was handled, else 0.
583 *
584 * Side effects:
585 * Depends on the event.
586 *
587 *----------------------------------------------------------------------
588 */
589
590 int
591 Tk_TranslateWinEvent(hwnd, message, wParam, lParam, resultPtr)
592 HWND hwnd;
593 UINT message;
594 WPARAM wParam;
595 LPARAM lParam;
596 LRESULT *resultPtr;
597 {
598 *resultPtr = 0;
599 switch (message) {
600 case WM_RENDERFORMAT: {
601 TkWindow *winPtr = (TkWindow *) Tk_HWNDToWindow(hwnd);
602 if (winPtr) {
603 TkWinClipboardRender(winPtr->dispPtr, wParam);
604 }
605 return 1;
606 }
607
608 case WM_COMMAND:
609 case WM_NOTIFY:
610 case WM_VSCROLL:
611 case WM_HSCROLL: {
612 /*
613 * Reflect these messages back to the sender so that they
614 * can be handled by the window proc for the control. Note
615 * that we need to be careful not to reflect a message that
616 * is targeted to this window, or we will loop.
617 */
618
619 HWND target = (message == WM_NOTIFY)
620 ? ((NMHDR*)lParam)->hwndFrom : (HWND) lParam;
621 if (target && target != hwnd) {
622 *resultPtr = SendMessage(target, message, wParam, lParam);
623 return 1;
624 }
625 break;
626 }
627
628 case WM_LBUTTONDOWN:
629 case WM_LBUTTONDBLCLK:
630 case WM_MBUTTONDOWN:
631 case WM_MBUTTONDBLCLK:
632 case WM_RBUTTONDOWN:
633 case WM_RBUTTONDBLCLK:
634 case WM_LBUTTONUP:
635 case WM_MBUTTONUP:
636 case WM_RBUTTONUP:
637 case WM_MOUSEMOVE:
638 Tk_PointerEvent(hwnd, (short) LOWORD(lParam),
639 (short) HIWORD(lParam));
640 return 1;
641
642 case WM_CLOSE:
643 case WM_SETFOCUS:
644 case WM_KILLFOCUS:
645 case WM_DESTROYCLIPBOARD:
646 case WM_CHAR:
647 case WM_SYSKEYDOWN:
648 case WM_SYSKEYUP:
649 case WM_KEYDOWN:
650 case WM_KEYUP:
651 case WM_MOUSEWHEEL:
652 GenerateXEvent(hwnd, message, wParam, lParam);
653 return 1;
654 case WM_MENUCHAR:
655 GenerateXEvent(hwnd, message, wParam, lParam);
656 /* MNC_CLOSE is the only one that looks right. This is a hack. */
657 *resultPtr = MAKELONG (0, MNC_CLOSE);
658 return 1;
659 }
660 return 0;
661 }
662
663 /*
664 *----------------------------------------------------------------------
665 *
666 * GenerateXEvent --
667 *
668 * This routine generates an X event from the corresponding
669 * Windows event.
670 *
671 * Results:
672 * None.
673 *
674 * Side effects:
675 * Queues one or more X events.
676 *
677 *----------------------------------------------------------------------
678 */
679
680 static void
681 GenerateXEvent(hwnd, message, wParam, lParam)
682 HWND hwnd;
683 UINT message;
684 WPARAM wParam;
685 LPARAM lParam;
686 {
687 XEvent event;
688 TkWindow *winPtr = (TkWindow *)Tk_HWNDToWindow(hwnd);
689 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
690 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
691
692 if (!winPtr || winPtr->window == None) {
693 return;
694 }
695
696 event.xany.serial = winPtr->display->request++;
697 event.xany.send_event = False;
698 event.xany.display = winPtr->display;
699 event.xany.window = winPtr->window;
700
701 switch (message) {
702 case WM_PAINT: {
703 PAINTSTRUCT ps;
704
705 event.type = Expose;
706 BeginPaint(hwnd, &ps);
707 event.xexpose.x = ps.rcPaint.left;
708 event.xexpose.y = ps.rcPaint.top;
709 event.xexpose.width = ps.rcPaint.right - ps.rcPaint.left;
710 event.xexpose.height = ps.rcPaint.bottom - ps.rcPaint.top;
711 EndPaint(hwnd, &ps);
712 event.xexpose.count = 0;
713 break;
714 }
715
716 case WM_CLOSE:
717 event.type = ClientMessage;
718 event.xclient.message_type =
719 Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS");
720 event.xclient.format = 32;
721 event.xclient.data.l[0] =
722 Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW");
723 break;
724
725 case WM_SETFOCUS:
726 case WM_KILLFOCUS: {
727 TkWindow *otherWinPtr = (TkWindow *)Tk_HWNDToWindow((HWND) wParam);
728
729 /*
730 * Compare toplevel windows to avoid reporting focus
731 * changes within the same toplevel.
732 */
733
734 while (!(winPtr->flags & TK_TOP_LEVEL)) {
735 winPtr = winPtr->parentPtr;
736 if (winPtr == NULL) {
737 return;
738 }
739 }
740 while (otherWinPtr && !(otherWinPtr->flags & TK_TOP_LEVEL)) {
741 otherWinPtr = otherWinPtr->parentPtr;
742 }
743 if (otherWinPtr == winPtr) {
744 return;
745 }
746
747 event.xany.window = winPtr->window;
748 event.type = (message == WM_SETFOCUS) ? FocusIn : FocusOut;
749 event.xfocus.mode = NotifyNormal;
750 event.xfocus.detail = NotifyNonlinear;
751 break;
752 }
753
754 case WM_DESTROYCLIPBOARD:
755 if (tsdPtr->updatingClipboard == TRUE) {
756 /*
757 * We want to avoid this event if we are the ones that caused
758 * this event.
759 */
760 return;
761 }
762 event.type = SelectionClear;
763 event.xselectionclear.selection =
764 Tk_InternAtom((Tk_Window)winPtr, "CLIPBOARD");
765 event.xselectionclear.time = TkpGetMS();
766 break;
767
768 case WM_MOUSEWHEEL:
769 /*
770 * The mouse wheel event is closer to a key event than a
771 * mouse event in that the message is sent to the window
772 * that has focus.
773 */
774
775 case WM_CHAR:
776 case WM_SYSKEYDOWN:
777 case WM_SYSKEYUP:
778 case WM_KEYDOWN:
779 case WM_KEYUP: {
780 unsigned int state = GetState(message, wParam, lParam);
781 Time time = TkpGetMS();
782 POINT clientPoint;
783 POINTS rootPoint; /* Note: POINT and POINTS are different */
784 DWORD msgPos;
785
786 /*
787 * Compute the screen and window coordinates of the event.
788 */
789
790 msgPos = GetMessagePos();
791 rootPoint = MAKEPOINTS(msgPos);
792 clientPoint.x = rootPoint.x;
793 clientPoint.y = rootPoint.y;
794 ScreenToClient(hwnd, &clientPoint);
795
796 /*
797 * Set up the common event fields.
798 */
799
800 event.xbutton.root = RootWindow(winPtr->display,
801 winPtr->screenNum);
802 event.xbutton.subwindow = None;
803 event.xbutton.x = clientPoint.x;
804 event.xbutton.y = clientPoint.y;
805 event.xbutton.x_root = rootPoint.x;
806 event.xbutton.y_root = rootPoint.y;
807 event.xbutton.state = state;
808 event.xbutton.time = time;
809 event.xbutton.same_screen = True;
810
811 /*
812 * Now set up event specific fields.
813 */
814
815 switch (message) {
816 case WM_MOUSEWHEEL:
817 /*
818 * We have invented a new X event type to handle
819 * this event. It still uses the KeyPress struct.
820 * However, the keycode field has been overloaded
821 * to hold the zDelta of the wheel.
822 */
823
824 event.type = MouseWheelEvent;
825 event.xany.send_event = -1;
826 event.xkey.keycode = (short) HIWORD(wParam);
827 break;
828 case WM_SYSKEYDOWN:
829 case WM_KEYDOWN:
830 /*
831 * Check for translated characters in the event queue.
832 * Setting xany.send_event to -1 indicates to the
833 * Windows implementation of XLookupString that this
834 * event was generated by windows and that the Windows
835 * extension xkey.trans_chars is filled with the
836 * characters that came from the TranslateMessage
837 * call. If it is not -1, xkey.keycode is the
838 * virtual key being sent programmatically by generic
839 * code.
840 */
841
842 event.type = KeyPress;
843 event.xany.send_event = -1;
844 event.xkey.keycode = wParam;
845 GetTranslatedKey(&event.xkey);
846 break;
847
848 case WM_SYSKEYUP:
849 case WM_KEYUP:
850 /*
851 * We don't check for translated characters on keyup
852 * because Tk won't know what to do with them. Instead, we
853 * wait for the WM_CHAR messages which will follow.
854 */
855 event.type = KeyRelease;
856 event.xkey.keycode = wParam;
857 event.xkey.nbytes = 0;
858 break;
859
860 case WM_CHAR:
861 /*
862 * Synthesize both a KeyPress and a KeyRelease.
863 * Strings generated by Input Method Editor are handled
864 * in the following manner:
865 * 1. A series of WM_KEYDOWN & WM_KEYUP messages that
866 * cause GetTranslatedKey() to be called and return
867 * immediately because the WM_KEYDOWNs have no
868 * associated WM_CHAR messages -- the IME window is
869 * accumulating the characters and translating them
870 * itself. In the "bind" command, you get an event
871 * with a mystery keysym and %A == "" for each
872 * WM_KEYDOWN that actually was meant for the IME.
873 * 2. A WM_KEYDOWN corresponding to the "confirm typing"
874 * character. This causes GetTranslatedKey() to be
875 * called.
876 * 3. A WM_IME_NOTIFY message saying that the IME is
877 * done. A side effect of this message is that
878 * GetTranslatedKey() thinks this means that there
879 * are no WM_CHAR messages and returns immediately.
880 * In the "bind" command, you get an another event
881 * with a mystery keysym and %A == "".
882 * 4. A sequence of WM_CHAR messages that correspond to
883 * the characters in the IME window. A bunch of
884 * simulated KeyPress/KeyRelease events will be
885 * generated, one for each character. Adjacent
886 * WM_CHAR messages may actually specify the high
887 * and low bytes of a multi-byte character -- in that
888 * case the two WM_CHAR messages will be combined into
889 * one event. It is the event-consumer's
890 * responsibility to convert the string returned from
891 * XLookupString from system encoding to UTF-8.
892 * 5. And finally we get the WM_KEYUP for the "confirm
893 * typing" character.
894 */
895
896 event.type = KeyPress;
897 event.xany.send_event = -1;
898 event.xkey.keycode = 0;
899 event.xkey.nbytes = 1;
900 event.xkey.trans_chars[0] = (char) wParam;
901
902 if (IsDBCSLeadByte((BYTE) wParam)) {
903 MSG msg;
904
905 if ((PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) != 0)
906 && (msg.message == WM_CHAR)) {
907 GetMessage(&msg, NULL, 0, 0);
908 event.xkey.nbytes = 2;
909 event.xkey.trans_chars[1] = (char) msg.wParam;
910 }
911 }
912 Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
913 event.type = KeyRelease;
914 break;
915 }
916 break;
917 }
918
919 default:
920 return;
921 }
922 Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
923 }
924
925 /*
926 *----------------------------------------------------------------------
927 *
928 * GetState --
929 *
930 * This function constructs a state mask for the mouse buttons
931 * and modifier keys as they were before the event occured.
932 *
933 * Results:
934 * Returns a composite value of all the modifier and button state
935 * flags that were set at the time the event occurred.
936 *
937 * Side effects:
938 * None.
939 *
940 *----------------------------------------------------------------------
941 */
942
943 static unsigned int
944 GetState(message, wParam, lParam)
945 UINT message; /* Win32 message type */
946 WPARAM wParam; /* wParam of message, used if key message */
947 LPARAM lParam; /* lParam of message, used if key message */
948 {
949 int mask;
950 int prevState; /* 1 if key was previously down */
951 unsigned int state = TkWinGetModifierState();
952
953 /*
954 * If the event is a key press or release, we check for modifier
955 * keys so we can report the state of the world before the event.
956 */
957
958 if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN
959 || message == WM_SYSKEYUP || message == WM_KEYUP) {
960 mask = 0;
961 prevState = HIWORD(lParam) & KF_REPEAT;
962 switch(wParam) {
963 case VK_SHIFT:
964 mask = ShiftMask;
965 break;
966 case VK_CONTROL:
967 mask = ControlMask;
968 break;
969 case VK_MENU:
970 mask = ALT_MASK;
971 break;
972 case VK_CAPITAL:
973 if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN) {
974 mask = LockMask;
975 prevState = ((state & mask) ^ prevState) ? 0 : 1;
976 }
977 break;
978 case VK_NUMLOCK:
979 if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN) {
980 mask = Mod1Mask;
981 prevState = ((state & mask) ^ prevState) ? 0 : 1;
982 }
983 break;
984 case VK_SCROLL:
985 if (message == WM_SYSKEYDOWN || message == WM_KEYDOWN) {
986 mask = Mod3Mask;
987 prevState = ((state & mask) ^ prevState) ? 0 : 1;
988 }
989 break;
990 }
991 if (prevState) {
992 state |= mask;
993 } else {
994 state &= ~mask;
995 }
996 }
997 return state;
998 }
999
1000 /*
1001 *----------------------------------------------------------------------
1002 *
1003 * GetTranslatedKey --
1004 *
1005 * Retrieves WM_CHAR messages that are placed on the system queue
1006 * by the TranslateMessage system call and places them in the
1007 * given KeyPress event.
1008 *
1009 * Results:
1010 * Sets the trans_chars and nbytes member of the key event.
1011 *
1012 * Side effects:
1013 * Removes any WM_CHAR messages waiting on the top of the system
1014 * event queue.
1015 *
1016 *----------------------------------------------------------------------
1017 */
1018
1019 static void
1020 GetTranslatedKey(xkey)
1021 XKeyEvent *xkey;
1022 {
1023 MSG msg;
1024 char buf[XMaxTransChars];
1025
1026 xkey->nbytes = 0;
1027
1028 while ((xkey->nbytes < XMaxTransChars)
1029 && PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
1030 if ((msg.message == WM_CHAR) || (msg.message == WM_SYSCHAR)) {
1031 GetMessage(&msg, NULL, 0, 0);
1032
1033 /*
1034 * If this is a normal character message, we may need to strip
1035 * off the Alt modifier (e.g. Alt-digits). Note that we don't
1036 * want to do this for system messages, because those were
1037 * presumably generated as an Alt-char sequence (e.g. accelerator
1038 * keys).
1039 */
1040
1041 if ((msg.message == WM_CHAR) && (msg.lParam & 0x20000000)) {
1042 xkey->state = 0;
1043 }
1044 buf[xkey->nbytes] = (char) msg.wParam;
1045 xkey->trans_chars[xkey->nbytes] = (char) msg.wParam;
1046 xkey->nbytes++;
1047 } else {
1048 break;
1049 }
1050 }
1051 }
1052
1053 /*
1054 *----------------------------------------------------------------------
1055 *
1056 * Tk_FreeXId --
1057 *
1058 * This inteface is not needed under Windows.
1059 *
1060 * Results:
1061 * None.
1062 *
1063 * Side effects:
1064 * None.
1065 *
1066 *----------------------------------------------------------------------
1067 */
1068
1069 void
1070 Tk_FreeXId(display, xid)
1071 Display *display;
1072 XID xid;
1073 {
1074 }
1075
1076 /*
1077 *----------------------------------------------------------------------
1078 *
1079 * TkWinResendEvent --
1080 *
1081 * This function converts an X event into a Windows event and
1082 * invokes the specified windo procedure.
1083 *
1084 * Results:
1085 * A standard Windows result.
1086 *
1087 * Side effects:
1088 * Invokes the window procedure
1089 *
1090 *----------------------------------------------------------------------
1091 */
1092
1093 LRESULT
1094 TkWinResendEvent(wndproc, hwnd, eventPtr)
1095 WNDPROC wndproc;
1096 HWND hwnd;
1097 XEvent *eventPtr;
1098 {
1099 UINT msg;
1100 WPARAM wparam;
1101 LPARAM lparam;
1102
1103 if (eventPtr->type == ButtonPress) {
1104 switch (eventPtr->xbutton.button) {
1105 case Button1:
1106 msg = WM_LBUTTONDOWN;
1107 wparam = MK_LBUTTON;
1108 break;
1109 case Button2:
1110 msg = WM_MBUTTONDOWN;
1111 wparam = MK_MBUTTON;
1112 break;
1113 case Button3:
1114 msg = WM_RBUTTONDOWN;
1115 wparam = MK_RBUTTON;
1116 break;
1117 default:
1118 return 0;
1119 }
1120 if (eventPtr->xbutton.state & Button1Mask) {
1121 wparam |= MK_LBUTTON;
1122 }
1123 if (eventPtr->xbutton.state & Button2Mask) {
1124 wparam |= MK_MBUTTON;
1125 }
1126 if (eventPtr->xbutton.state & Button3Mask) {
1127 wparam |= MK_RBUTTON;
1128 }
1129 if (eventPtr->xbutton.state & ShiftMask) {
1130 wparam |= MK_SHIFT;
1131 }
1132 if (eventPtr->xbutton.state & ControlMask) {
1133 wparam |= MK_CONTROL;
1134 }
1135 lparam = MAKELPARAM((short) eventPtr->xbutton.x,
1136 (short) eventPtr->xbutton.y);
1137 } else {
1138 return 0;
1139 }
1140 return CallWindowProc(wndproc, hwnd, msg, wparam, lparam);
1141 }
1142
1143 /*
1144 *----------------------------------------------------------------------
1145 *
1146 * TkpGetMS --
1147 *
1148 * Return a relative time in milliseconds. It doesn't matter
1149 * when the epoch was.
1150 *
1151 * Results:
1152 * Number of milliseconds.
1153 *
1154 * Side effects:
1155 * None.
1156 *
1157 *----------------------------------------------------------------------
1158 */
1159
1160 unsigned long
1161 TkpGetMS()
1162 {
1163 return GetTickCount();
1164 }
1165
1166 /*
1167 *----------------------------------------------------------------------
1168 *
1169 * TkWinUpdatingClipboard --
1170 *
1171 *
1172 * Results:
1173 * Number of milliseconds.
1174 *
1175 * Side effects:
1176 * None.
1177 *
1178 *----------------------------------------------------------------------
1179 */
1180
1181 void
1182 TkWinUpdatingClipboard(int mode)
1183 {
1184 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1185 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1186
1187 tsdPtr->updatingClipboard = mode;
1188 }
1189
1190 /* End of tkwinx.c */

Properties

Name Value
svn:eol-style native
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25