Tk Source Code

Changes On Branch pspjuth-touch
Login
Bounty program for improvements to Tcl and certain Tcl packages.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch pspjuth-touch Excluding Merge-Ins

This is equivalent to a diff from b26f2446 to 170c0759

2016-11-18
13:17
merge core-8-6-branch check-in: 826e632b user: jan.nijtmans tags: trunk
2016-11-09
14:01
merge trunk Leaf check-in: 170c0759 user: jan.nijtmans tags: pspjuth-touch
13:43
merge trunk check-in: 01c423f9 user: jan.nijtmans tags: novem-support
13:41
Bring all win32 version stuff to one place. Should work the same (should still work on XP, although I don't know if we really want that). check-in: b26f2446 user: jan.nijtmans tags: trunk
12:43
Merge trunk check-in: 02f42506 user: jan.nijtmans tags: pspjuth-touch
11:03
Merge core-8-6-branch check-in: e7e8ecae user: jan.nijtmans tags: trunk

Changes to win/tkWin.h.

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
 * the SystemParametersInfo API doesn't like to receive structures that
 * are larger than it expects which affects the font assignments.
 *
 * NTDDI_VERSION = 0x0600 means Windows Vista and above
 */

#ifndef NTDDI_VERSION
#define NTDDI_VERSION 0x06000000
#endif
#ifndef WINVER
#define WINVER 0x0600
#endif
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#endif
#ifndef _WIN32_IE
#define _WIN32_IE 0x0600
#endif

#ifndef _TK
#include <tk.h>
#endif

#define WIN32_LEAN_AND_MEAN






|


|


|


|







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
 * the SystemParametersInfo API doesn't like to receive structures that
 * are larger than it expects which affects the font assignments.
 *
 * NTDDI_VERSION = 0x0600 means Windows Vista and above
 */

#ifndef NTDDI_VERSION
#define NTDDI_VERSION 0x06010000
#endif
#ifndef WINVER
#define WINVER 0x0601
#endif
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0601
#endif
#ifndef _WIN32_IE
#define _WIN32_IE 0x0601
#endif

#ifndef _TK
#include <tk.h>
#endif

#define WIN32_LEAN_AND_MEAN

Changes to win/tkWinWm.c.

533
534
535
536
537
538
539



540
541
542
543
544
545
546
			    Tcl_Obj *const objv[]);
static int		WmStateCmd(Tk_Window tkwin,
			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static int		WmTitleCmd(Tk_Window tkwin,
			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);



static int		WmTransientCmd(Tk_Window tkwin,
			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static int		WmWithdrawCmd(Tk_Window tkwin,
			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static void		WmUpdateGeom(WmInfo *wmPtr, TkWindow *winPtr);






>
>
>







533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
			    Tcl_Obj *const objv[]);
static int		WmStateCmd(Tk_Window tkwin,
			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static int		WmTitleCmd(Tk_Window tkwin,
			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static int		WmTouchCmd(Tk_Window tkwin,
			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static int		WmTransientCmd(Tk_Window tkwin,
			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static int		WmWithdrawCmd(Tk_Window tkwin,
			    TkWindow *winPtr, Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static void		WmUpdateGeom(WmInfo *wmPtr, TkWindow *winPtr);
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
	"aspect", "attributes", "client", "colormapwindows",
	"command", "deiconify", "focusmodel", "forget", "frame",
	"geometry", "grid", "group", "iconbitmap",
	"iconify", "iconmask", "iconname",
	"iconphoto", "iconposition",
	"iconwindow", "manage", "maxsize", "minsize", "overrideredirect",
	"positionfrom", "protocol", "resizable", "sizefrom",
	"stackorder", "state", "title", "transient",
	"withdraw", NULL
    };
    enum options {
	WMOPT_ASPECT, WMOPT_ATTRIBUTES, WMOPT_CLIENT, WMOPT_COLORMAPWINDOWS,
	WMOPT_COMMAND, WMOPT_DEICONIFY, WMOPT_FOCUSMODEL, WMOPT_FORGET,
	WMOPT_FRAME,
	WMOPT_GEOMETRY, WMOPT_GRID, WMOPT_GROUP, WMOPT_ICONBITMAP,
	WMOPT_ICONIFY, WMOPT_ICONMASK, WMOPT_ICONNAME,
	WMOPT_ICONPHOTO, WMOPT_ICONPOSITION,
	WMOPT_ICONWINDOW, WMOPT_MANAGE, WMOPT_MAXSIZE, WMOPT_MINSIZE,
	WMOPT_OVERRIDEREDIRECT,
	WMOPT_POSITIONFROM, WMOPT_PROTOCOL, WMOPT_RESIZABLE, WMOPT_SIZEFROM,
	WMOPT_STACKORDER, WMOPT_STATE, WMOPT_TITLE, WMOPT_TRANSIENT,
	WMOPT_WITHDRAW
    };
    int index;
    size_t length;
    const char *argv1;
    TkWindow *winPtr, **winPtrPtr = &winPtr;
    TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;






|












|







2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
	"aspect", "attributes", "client", "colormapwindows",
	"command", "deiconify", "focusmodel", "forget", "frame",
	"geometry", "grid", "group", "iconbitmap",
	"iconify", "iconmask", "iconname",
	"iconphoto", "iconposition",
	"iconwindow", "manage", "maxsize", "minsize", "overrideredirect",
	"positionfrom", "protocol", "resizable", "sizefrom",
	"stackorder", "state", "title", "touch", "transient",
	"withdraw", NULL
    };
    enum options {
	WMOPT_ASPECT, WMOPT_ATTRIBUTES, WMOPT_CLIENT, WMOPT_COLORMAPWINDOWS,
	WMOPT_COMMAND, WMOPT_DEICONIFY, WMOPT_FOCUSMODEL, WMOPT_FORGET,
	WMOPT_FRAME,
	WMOPT_GEOMETRY, WMOPT_GRID, WMOPT_GROUP, WMOPT_ICONBITMAP,
	WMOPT_ICONIFY, WMOPT_ICONMASK, WMOPT_ICONNAME,
	WMOPT_ICONPHOTO, WMOPT_ICONPOSITION,
	WMOPT_ICONWINDOW, WMOPT_MANAGE, WMOPT_MAXSIZE, WMOPT_MINSIZE,
	WMOPT_OVERRIDEREDIRECT,
	WMOPT_POSITIONFROM, WMOPT_PROTOCOL, WMOPT_RESIZABLE, WMOPT_SIZEFROM,
	WMOPT_STACKORDER, WMOPT_STATE, WMOPT_TITLE, WMOPT_TOUCH, WMOPT_TRANSIENT,
	WMOPT_WITHDRAW
    };
    int index;
    size_t length;
    const char *argv1;
    TkWindow *winPtr, **winPtrPtr = &winPtr;
    TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
    }

    if (TkGetWindowFromObj(interp, tkwin, objv[2], (Tk_Window *) winPtrPtr)
	    != TCL_OK) {
	return TCL_ERROR;
    }
    if (!Tk_IsTopLevel(winPtr) && (index != WMOPT_MANAGE)
	    && (index != WMOPT_FORGET)) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"window \"%s\" isn't a top-level window", winPtr->pathName));
	Tcl_SetErrorCode(interp, "TK", "LOOKUP", "TOPLEVEL", winPtr->pathName,
		NULL);
	return TCL_ERROR;
    }







|







2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
    }

    if (TkGetWindowFromObj(interp, tkwin, objv[2], (Tk_Window *) winPtrPtr)
	    != TCL_OK) {
	return TCL_ERROR;
    }
    if (!Tk_IsTopLevel(winPtr) && (index != WMOPT_MANAGE)
	    && (index != WMOPT_TOUCH) && (index != WMOPT_FORGET)) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"window \"%s\" isn't a top-level window", winPtr->pathName));
	Tcl_SetErrorCode(interp, "TK", "LOOKUP", "TOPLEVEL", winPtr->pathName,
		NULL);
	return TCL_ERROR;
    }

2917
2918
2919
2920
2921
2922
2923


2924
2925
2926
2927
2928
2929
2930
	return WmSizefromCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_STACKORDER:
	return WmStackorderCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_STATE:
	return WmStateCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_TITLE:
	return WmTitleCmd(tkwin, winPtr, interp, objc, objv);


    case WMOPT_TRANSIENT:
	return WmTransientCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_WITHDRAW:
	return WmWithdrawCmd(tkwin, winPtr, interp, objc, objv);
    }

    /* This should not happen */






>
>







2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
	return WmSizefromCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_STACKORDER:
	return WmStackorderCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_STATE:
	return WmStateCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_TITLE:
	return WmTitleCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_TOUCH:
	return WmTouchCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_TRANSIENT:
	return WmTransientCmd(tkwin, winPtr, interp, objc, objv);
    case WMOPT_WITHDRAW:
	return WmWithdrawCmd(tkwin, winPtr, interp, objc, objv);
    }

    /* This should not happen */
5495
5496
5497
5498
5499
5500
5501




























































































































































































5502
5503
5504
5505
5506
5507
5508
	    Tcl_WinUtfToTChar(wmPtr->title, -1, &titleString);
	    SetWindowText(wrapper, (LPCTSTR) Tcl_DStringValue(&titleString));
	    Tcl_DStringFree(&titleString);
	}
    }
    return TCL_OK;
}





























































































































































































/*
 *----------------------------------------------------------------------
 *
 * WmTransientCmd --
 *
 *	This function is invoked to process the "wm transient" Tcl command.






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







5500
5501
5502
5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
5519
5520
5521
5522
5523
5524
5525
5526
5527
5528
5529
5530
5531
5532
5533
5534
5535
5536
5537
5538
5539
5540
5541
5542
5543
5544
5545
5546
5547
5548
5549
5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
5561
5562
5563
5564
5565
5566
5567
5568
5569
5570
5571
5572
5573
5574
5575
5576
5577
5578
5579
5580
5581
5582
5583
5584
5585
5586
5587
5588
5589
5590
5591
5592
5593
5594
5595
5596
5597
5598
5599
5600
5601
5602
5603
5604
5605
5606
5607
5608
5609
5610
5611
5612
5613
5614
5615
5616
5617
5618
5619
5620
5621
5622
5623
5624
5625
5626
5627
5628
5629
5630
5631
5632
5633
5634
5635
5636
5637
5638
5639
5640
5641
5642
5643
5644
5645
5646
5647
5648
5649
5650
5651
5652
5653
5654
5655
5656
5657
5658
5659
5660
5661
5662
5663
5664
5665
5666
5667
5668
5669
5670
5671
5672
5673
5674
5675
5676
5677
5678
5679
5680
5681
5682
5683
5684
5685
5686
5687
5688
5689
5690
5691
5692
5693
5694
5695
5696
5697
5698
5699
5700
5701
	    Tcl_WinUtfToTChar(wmPtr->title, -1, &titleString);
	    SetWindowText(wrapper, (LPCTSTR) Tcl_DStringValue(&titleString));
	    Tcl_DStringFree(&titleString);
	}
    }
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * WmTouchCmd --
 *
 *	This function is invoked to process the "wm touch" Tcl command. See
 *	the user documentation for details on what it does.
 *
 * Results:
 *	A standard Tcl result.
 *
 * Side effects:
 *	See the user documentation.
 *
 *----------------------------------------------------------------------
 */

static int
WmTouchCmd(
    Tk_Window tkwin,		/* Main window of the application. */
    TkWindow *winPtr,		/* Toplevel to work with */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Window win;
    HWND hwnd;
    int i, index, gCnt = 0, value;
    ULONG flags = 0;
    int touch = 0, panFlag;
    GESTURECONFIG gcPan = { 0, 0, 0 };
    GESTURECONFIG gc[10]; /* TBD: protect from overflow */
    static const char *const optionStrings[] = {
	"-all", "-fine", "-pan", "-pangutter", "-paninertia",
	"-pansfh", "-pansfv", "-pressandtap", "-rotate",
	"-touch", "-twofingertap", "-wantpalm", "-zoom",
	NULL
    };
    enum options {
	TOUCH_ALL, TOUCH_FINE, TOUCH_PAN, TOUCH_PANGUTTER, TOUCH_PANINERTIA,
	TOUCH_PANSFH, TOUCH_PANSFV, TOUCH_PRESSANDTAP, TOUCH_ROTATE,
	TOUCH_TOUCH, TOUCH_TWOFINGERTAP, TOUCH_WANTPALM, TOUCH_ZOOM
    };

    if (objc < 3) {
	Tcl_WrongNumArgs(interp, 2, objv, "window ?-option value ...?");
	return TCL_ERROR;
    }
    ZeroMemory(&gc, sizeof(gc));
    for (i = 3; i < objc; i++) {
	if (Tcl_GetIndexFromObj(interp, objv[i], optionStrings, "option", 0,
				&index) != TCL_OK) {
	    return TCL_ERROR;
	}
	switch ((enum options) index) {
	case TOUCH_ALL:
	    gc[gCnt++].dwWant = GC_ALLGESTURES;
	    break;
	case TOUCH_FINE:
	    flags |= TWF_FINETOUCH;
	    touch = 1;
	    break;
	case TOUCH_PAN:
	    panFlag = GC_PAN;
	    goto pan;
	case TOUCH_PANGUTTER:
	    panFlag = GC_PAN_WITH_GUTTER;
	    goto pan;
	case TOUCH_PANINERTIA:
	    panFlag = GC_PAN_WITH_INERTIA;
	    goto pan;
	case TOUCH_PANSFH:
	    panFlag = GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
	    goto pan;
	case TOUCH_PANSFV:
	    panFlag = GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
	pan:
	    if (++i >= objc) {
		Tcl_SetObjResult(interp, Tcl_NewStringObj(
			"missing value", -1));
		return TCL_ERROR;
	    }
	    if (Tcl_GetBooleanFromObj(interp, objv[i], &value) != TCL_OK) {
		return TCL_ERROR;
	    }
	    gcPan.dwID = GID_PAN;
	    if (value) {
		gcPan.dwWant |= panFlag;
	    } else {
		gcPan.dwBlock |= panFlag;
	    }
            break;
	case TOUCH_PRESSANDTAP:
	    if (++i >= objc) {
		Tcl_SetObjResult(interp, Tcl_NewStringObj(
			"missing pressandtap", -1));
		return TCL_ERROR;
	    }
	    if (Tcl_GetBooleanFromObj(interp, objv[i], &value) != TCL_OK) {
		return TCL_ERROR;
	    }
	    gc[gCnt].dwID = GID_PRESSANDTAP;
	    if (value) {
		gc[gCnt++].dwWant = GC_PRESSANDTAP;
	    } else {
		gc[gCnt++].dwBlock = GC_PRESSANDTAP;
	    }
            break;
	case TOUCH_ROTATE:
	    if (++i >= objc) {
		Tcl_SetObjResult(interp, Tcl_NewStringObj(
			"missing rotate", -1));
		return TCL_ERROR;
	    }
	    if (Tcl_GetBooleanFromObj(interp, objv[i], &value) != TCL_OK) {
		return TCL_ERROR;
	    }
	    gc[gCnt].dwID = GID_ROTATE;
	    if (value) {
		gc[gCnt++].dwWant = GC_ROTATE;
	    } else {
		gc[gCnt++].dwBlock = GC_ROTATE;
	    }
            break;
	case TOUCH_TOUCH:
	    touch = 1;
	    break;
	case TOUCH_TWOFINGERTAP:
	    if (++i >= objc) {
		Tcl_SetObjResult(interp, Tcl_NewStringObj(
			"missing pressandtap", -1));
		return TCL_ERROR;
	    }
	    if (Tcl_GetBooleanFromObj(interp, objv[i], &value) != TCL_OK) {
		return TCL_ERROR;
	    }
	    gc[gCnt].dwID = GID_TWOFINGERTAP;
	    if (value) {
		gc[gCnt++].dwWant = GC_TWOFINGERTAP;
	    } else {
		gc[gCnt++].dwBlock = GC_TWOFINGERTAP;
	    }
            break;
	case TOUCH_WANTPALM:
	    flags |= TWF_WANTPALM;
	    touch = 1;
	    break;
	case TOUCH_ZOOM:
	    if (++i >= objc) {
		Tcl_SetObjResult(interp, Tcl_NewStringObj(
			"missing zoom", -1));
		return TCL_ERROR;
	    }
	    if (Tcl_GetBooleanFromObj(interp, objv[i], &value) != TCL_OK) {
		return TCL_ERROR;
	    }
	    gc[gCnt].dwID = GID_ZOOM;
	    if (value) {
		gc[gCnt++].dwWant = GC_ZOOM;
	    } else {
		gc[gCnt++].dwBlock = GC_ZOOM;
	    }
            break;
	}
    }

    if (gcPan.dwID != 0) {
	gc[gCnt++] = gcPan;
    }

    win = Tk_WindowId((Tk_Window) winPtr);
    if (win == None) {
	Tk_MakeWindowExist((Tk_Window) winPtr);
	win = Tk_WindowId((Tk_Window) winPtr);
    }

    hwnd = Tk_GetHWND(win);

    if (touch) {
	/* TBD: support to unregister */
	RegisterTouchWindow(hwnd, flags);
    }
    if (gCnt > 0) {
	SetGestureConfig(hwnd, 0, gCnt, gc, sizeof(GESTURECONFIG));
    }
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * WmTransientCmd --
 *
 *	This function is invoked to process the "wm transient" Tcl command.

Changes to win/tkWinX.c.

38
39
40
41
42
43
44






















45
46
47
48
49
50
51
 * WM_UNICHAR is a message for Unicode input on all windows systems.
 * Perhaps this definition should be moved in another file.
 */
#ifndef WM_UNICHAR
#define WM_UNICHAR     0x0109
#define UNICODE_NOCHAR 0xFFFF
#endif























/*
 * Declarations of static variables used in this file.
 */

static const char winScreenName[] = ":0"; /* Default name of windows display. */
static HINSTANCE tkInstance = NULL;	/* Application instance handle. */






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
 * WM_UNICHAR is a message for Unicode input on all windows systems.
 * Perhaps this definition should be moved in another file.
 */
#ifndef WM_UNICHAR
#define WM_UNICHAR     0x0109
#define UNICODE_NOCHAR 0xFFFF
#endif

#ifndef WM_TOUCH
#define WM_TOUCH       0x0240
#endif

#ifndef WM_GESTURE
#define WM_GESTURE     0x0119
#endif

/*
 * Helpers for touch event to fill in its dictionary.
 */

#define ADD_DICT_STR(d, s, v)						\
    Tcl_DictObjPut(NULL, d, Tcl_NewStringObj(s, -1), Tcl_NewStringObj(v, -1))
#define ADD_DICT_INT(d, s, v)						\
    Tcl_DictObjPut(NULL, d, Tcl_NewStringObj(s, -1), Tcl_NewIntObj(v))
#define ADD_DICT_WIDE(d, s, v) \
    Tcl_DictObjPut(NULL, d, Tcl_NewStringObj(s, -1), Tcl_NewWideIntObj(v))
#define ADD_DICT_DOUB(d, s, v) \
    Tcl_DictObjPut(NULL, d, Tcl_NewStringObj(s, -1), Tcl_NewDoubleObj(v))


/*
 * Declarations of static variables used in this file.
 */

static const char winScreenName[] = ":0"; /* Default name of windows display. */
static HINSTANCE tkInstance = NULL;	/* Application instance handle. */
828
829
830
831
832
833
834



























































































































































































































































835
836
837
838
839
840
841
    Tcl_ServiceAll();
    return result;
}

/*
 *----------------------------------------------------------------------
 *



























































































































































































































































 * Tk_TranslateWinEvent --
 *
 *	This function is called by widget window functions to handle the
 *	translation from Win32 events to Tk events.
 *
 * Results:
 *	Returns 1 if the event was handled, else 0.






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
    Tcl_ServiceAll();
    return result;
}

/*
 *----------------------------------------------------------------------
 *
 * InitTouchEvent --
 *
 *	This function initialises an event structure with the base
 *	fields used in a TouchEvent.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

static void
InitTouchEvent(XEvent *event, HWND hwnd, int rootx, int rooty)
{
    POINT sInput, cInput;
    Tk_Window tkwin;
    TkWindow *winPtr;

    sInput.x = rootx;
    sInput.y = rooty;
    cInput = sInput;
    ScreenToClient(hwnd, &cInput);

    tkwin = Tk_HWNDToWindow(hwnd);
    winPtr = (TkWindow *)tkwin;
    memset(event, 0, sizeof(*event));
    event->xany.type = VirtualEvent;
    event->xany.serial =
	LastKnownRequestProcessed(winPtr->display);
    event->xany.send_event = False;
    event->xany.window = Tk_WindowId(tkwin);
    event->xany.display = winPtr->display;
    event->xkey.root =
	RootWindow(winPtr->display,winPtr->screenNum);
    event->xkey.x_root = sInput.x;
    event->xkey.y_root = sInput.y;
    event->xkey.x = cInput.x;
    event->xkey.y = cInput.y;
}

/*
 *----------------------------------------------------------------------
 *
 * GenerateTouchEvent --
 *
 *	This function generate touch events when a WM_TOUCH event has
 *      been received.
 *
 * Results:
 *	Returns 1 if the event was handled, else 0.
 *
 * Side effects:
 *	May queue one or more X events.
 *
 *----------------------------------------------------------------------
 */

static int
GenerateTouchEvent(
    HWND hwnd,
    WPARAM wParam,
    LPARAM lParam)
{
    BOOL bHandled = FALSE;
    UINT cInputs = LOWORD(wParam);
    PTOUCHINPUT pInputs = ckalloc(sizeof(TOUCHINPUT)*cInputs);
    union {XEvent general; XVirtualEvent virtual;} event;
    Tcl_Obj *dictPtr;

    if (pInputs != NULL) {
	if (GetTouchInputInfo((HTOUCHINPUT)lParam,
			      cInputs,
			      pInputs,
			      sizeof(TOUCHINPUT))) {
	    for (UINT i=0; i < cInputs; i++){
		TOUCHINPUT ti = pInputs[i];
		InitTouchEvent(&event.general, hwnd,
			       TOUCH_COORD_TO_PIXEL(ti.x),
			       TOUCH_COORD_TO_PIXEL(ti.y));
		/*
		 * Which info needs to be passed to the event, and how should
		 * is be passed ?
		 * Put it into a dict and pass it through %d
		 */
		dictPtr = Tcl_NewDictObj();
		Tcl_IncrRefCount(dictPtr);
		/* Identify as a touch event */
		ADD_DICT_STR(dictPtr, "event", "touch");
		/* Touch ID */
		ADD_DICT_INT(dictPtr, "id", ti.dwID);
		/* Raw flags value */
		ADD_DICT_INT(dictPtr, "flags", ti.dwFlags);
		/* Decode known flags */
		if (ti.dwFlags & TOUCHEVENTF_MOVE) {
		    ADD_DICT_INT(dictPtr, "move", 1);
		    event.virtual.name = Tk_GetUid("FingerMotion");
		}
		if (ti.dwFlags & TOUCHEVENTF_DOWN) {
		    ADD_DICT_INT(dictPtr, "down", 1);
		    event.virtual.name = Tk_GetUid("FingerDown");
		}
		if (ti.dwFlags & TOUCHEVENTF_UP) {
		    ADD_DICT_INT(dictPtr, "up", 1);
		    event.virtual.name = Tk_GetUid("FingerUp");
		}
		if (ti.dwFlags & TOUCHEVENTF_INRANGE) {
		    ADD_DICT_INT(dictPtr, "inrange", 1);
		}
		if (ti.dwFlags & TOUCHEVENTF_PRIMARY) {
		    ADD_DICT_INT(dictPtr, "primary", 1);
		}
		if (ti.dwFlags & TOUCHEVENTF_NOCOALESCE) {
		    ADD_DICT_INT(dictPtr, "nocoalesce", 1);
		}
		if (ti.dwFlags & TOUCHEVENTF_PALM) {
		    ADD_DICT_INT(dictPtr, "palm", 1);
		}
		event.virtual.user_data = dictPtr;
		Tk_QueueWindowEvent(&event.general, TCL_QUEUE_TAIL);
	    }
	    bHandled = TRUE;
	}
	ckfree(pInputs);
    }
    if (bHandled) {
	CloseTouchInputHandle((HTOUCHINPUT)lParam);
	return 1;
    }
    return 0;
}

/*
 *----------------------------------------------------------------------
 *
 * GenerateGestureEvent --
 *
 *	This function generate touch events when a WM_GESTURE event has
 *      been received.
 *
 * Results:
 *	Returns 1 if the event was handled, else 0.
 *
 * Side effects:
 *	May queue an X event.
 *
 *----------------------------------------------------------------------
 */

static int
GenerateGestureEvent(
    HWND hwnd,
    WPARAM wParam,
    LPARAM lParam)
{
    GESTUREINFO gi;
    union {XEvent general; XVirtualEvent virtual;} event;
    Tcl_Obj *dictPtr;
    POINT sLoc, delta;
    POINTS pts;
    UINT LInt, HInt;

    ZeroMemory(&gi, sizeof(GESTUREINFO));
    gi.cbSize = sizeof(GESTUREINFO);

    if (!GetGestureInfo((HGESTUREINFO)lParam, &gi)){
	return 0;
    }

    /* Is it something we want to handle? */
    switch (gi.dwID) {
    case GID_BEGIN:
    case GID_END:
	/* These should not be handled */
	return 0;
    case GID_ZOOM:
    case GID_PAN:
    case GID_ROTATE:
    case GID_TWOFINGERTAP:
    case GID_PRESSANDTAP:
	break;
    default:
	/* A gesture was not recognized */
	return 0;
    }

    POINTSTOPOINT(sLoc, gi.ptsLocation);

    InitTouchEvent(&event.general, hwnd, sLoc.x, sLoc.y);
    event.virtual.name = Tk_GetUid("Gesture");
    dictPtr = Tcl_NewDictObj();
    Tcl_IncrRefCount(dictPtr);
    /* Identify as a gesture event */
    ADD_DICT_STR(dictPtr, "event", "gesture");
    /* Raw flags value */
    ADD_DICT_INT(dictPtr, "flags", gi.dwFlags);
    /* Decode known flags */
    if (gi.dwFlags & GF_BEGIN) {
	ADD_DICT_INT(dictPtr, "begin", 1);
    }
    if (gi.dwFlags & GF_INERTIA) {
	ADD_DICT_INT(dictPtr, "inertia", 1);
    }
    if (gi.dwFlags & GF_END) {
	ADD_DICT_INT(dictPtr, "end", 1);
    }

    LInt = (UINT) (gi.ullArguments & 0xFFFFFFFF);
    HInt = (UINT) (gi.ullArguments >> 32);
    switch (gi.dwID){
    case GID_ZOOM:
	ADD_DICT_STR(dictPtr, "gesture", "zoom");
	ADD_DICT_WIDE(dictPtr, "distance", gi.ullArguments);
	event.virtual.name = Tk_GetUid("PinchToZoom");
	break;
    case GID_PAN:
	ADD_DICT_STR(dictPtr, "gesture", "pan");
	ADD_DICT_WIDE(dictPtr, "distance", LInt);
	if (gi.dwFlags & GF_INERTIA) {
	    pts = MAKEPOINTS(HInt);
	    ADD_DICT_INT(dictPtr, "inertiax", pts.x);
	    ADD_DICT_INT(dictPtr, "inertiay", pts.y);
	}
	break;
    case GID_ROTATE:
	ADD_DICT_STR(dictPtr, "gesture", "rotate");
	ADD_DICT_DOUB(dictPtr, "angle",
		      GID_ROTATE_ANGLE_FROM_ARGUMENT(gi.ullArguments));
	break;
    case GID_TWOFINGERTAP:
	ADD_DICT_STR(dictPtr, "gesture", "twofingertap");
	ADD_DICT_WIDE(dictPtr, "distance", gi.ullArguments);
	break;
    case GID_PRESSANDTAP:
	ADD_DICT_STR(dictPtr, "gesture", "pressandtap");
	pts = MAKEPOINTS(LInt);
	POINTSTOPOINT(delta, pts);
	ADD_DICT_INT(dictPtr, "deltax", delta.x);
	ADD_DICT_INT(dictPtr, "deltay", delta.y);
	break;
    }
    event.virtual.user_data = dictPtr;
    Tk_QueueWindowEvent(&event.general, TCL_QUEUE_TAIL);
    return 1;
}

/*
 *----------------------------------------------------------------------
 *
 * Tk_TranslateWinEvent --
 *
 *	This function is called by widget window functions to handle the
 *	translation from Win32 events to Tk events.
 *
 * Results:
 *	Returns 1 if the event was handled, else 0.
895
896
897
898
899
900
901






902
903
904
905
906
907
908
    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_SYSKEYDOWN:
    case WM_KEYDOWN:
	if (wParam == VK_PACKET) {
	    /*
	     * This will trigger WM_CHAR event(s) with unicode data.
	     */
	    *resultPtr =






>
>
>
>
>
>







1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
    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_TOUCH:
	return GenerateTouchEvent(hwnd, wParam, lParam);

    case WM_GESTURE:
	return GenerateGestureEvent(hwnd, wParam, lParam);

    case WM_SYSKEYDOWN:
    case WM_KEYDOWN:
	if (wParam == VK_PACKET) {
	    /*
	     * This will trigger WM_CHAR event(s) with unicode data.
	     */
	    *resultPtr =

Added win/touch.tcl.





































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# Example usage of the touch interface

if 0 {
    The current interface is as follows.

    All configuration is done via:
    wm touch <win> ?options?

    Some gestures are on by default. It seems like all but rotate.
    To get raw touch events, they must be turned on.

    To control gestures:
    -all : Turn on all gestures
    -pressandtap <bool> : Turn on or off PressAndTap gesture
    -rotate <bool> : Turn on or off Rotate gesture
    -twofingertap <bool> : Turn on or off TwoFingerTap gesture
    -zoom <bool> : Turn on or off Zoom gesture
    -pan <bool> : Turn on or off Pan gestures
    -pansfh <bool> : Turn on or off Pan single finger horizontal gesture
    -pansfv <bool> : Turn on or off Pan single finger vertical gesture
    -pangutter <bool> : Turn on or off Pan gutter mode
    -paninertia <bool> : Turn on or off Pan inertial mode
    See GESTURECONFIG in win API for pan flags.

    To get raw touch events:
    If any of the flags -touch, -fine or -wantpalm is given,
    the window is registered to receive raw touch event.
    It will no longer receive any gesture events.
    The flags -fine/-wantpalm corresponds to the Windows API
    RegisterTouchWindow.

    Events are received as virtual events.
    These events support at least base %W %x %y %X %Y fields.
    All extra information is given in a dictionary in the %d field.
    <<FingerDown>> <<FingerUp>> <<FingerMotion>> : Raw touch events
    <<PinchToZoom>> : Zoom gesture
    <<Gesture>>     : Other gestures

    Any boolean field in the dictionary is either present with
    the value 1 or not present. Below they are written without a value.

    Touch fields:
    event = touch : Identify event as a touch. (i.e. not a gesture)
    id <val> : Id to know what events belong to the same touch.
    flags <val> : Raw flags value, in case future flags are provided.
    down : Start of touch
    move : Touch is moving
    up   : End of touch
    primary : First touch in a multi touch. Primary touch might also cause
              button events.
    inrange/nocoalesce/palm : See TOUCHINPUT in Windows API.

    Gesture fields:
    event = gesture : Identify event as a gesture.
    flags <val> : Raw flags value, in case future flags are provided.
    begin : Start of gesture
    end : End of gesture
    inertia : Gesture has triggered inertia

    Note that begin and end can both be set, e.g. in two finger tap.

    gesture <type> : Where type is one of:
      zoom : Zoom gesture. %x/y is between fingers
      pan  : Pan gesture. %x/y is between fingers
      rotate : Rotate gesture. %x/y is between fingers
      twofingertap : Two finger tap gesture. %x/y is between fingers
      pressandtap : Press and tap gesture. %x/y is first finger
    
    distance <i> : For zoom/pan/twofingertap: Distance between fingers.
    angle <r> : For rotate: Rotation angle in radians.
    deltax <i> : For pressandtap: Locates second finger. Valid with begin.
    deltay <i> : For pressandtap: Locates second finger. Valid with begin.
    inertiax <i> : For pan: Inertia vector. Valid with inertia flag.
    inertiay <i> : For pan: Inertia vector. Valid with inertia flag.

}

namespace import tcl::mathop::*

proc rndCol {} {
    set lst {orange yellow green cyan blue purple violet pink}
    set i [expr {int(rand()*[llength $lst])}]
    return [lindex $lst $i]
}

proc Circle {w x y r args} {
    $w create oval [- $x $r] [- $y $r] [+ $x $r] [+ $y $r] \
	-fill "" -outline black -width 2 {*}$args
}

proc Touch1 {W d x y X Y} {
    set id [dict get $d id]

    set move [dict exists $d move]
    set down [dict exists $d down]
    set up   [dict exists $d up]
    set primary [dict exists $d primary]

    if {![info exists ::t($id,id)]} {
	set ::t($id,id) [$W create oval $x $y $x $y]
	if {$primary} {
	    $W itemconfigure $::t($id,id) -fill red
	} else {
	    $W itemconfigure $::t($id,id) -fill [rndCol]
	}
    }
    if {$up} {
	$W delete $::t($id,id)
	array unset ::t $id,*
	return
    }

    # Filter unnecessary movement
    if {$move && $x == $::t($id,x) && $y == $::t($id,y)} {
	return
    }
    set r [expr {[winfo screenwidth .] / 50}]
    set ::t($id,x) $x
    set ::t($id,y) $y
    $W coords $::t($id,id) [- $x $r] [- $y $r] [+ $x $r] [+ $y $r]
}

proc Log {W d} {
    # Make a little log of messages for now
    if {[lindex $::messages 9] ne $d} {
	lappend ::messages $d
	set ::messages [lrange $::messages end-9 end]
    }
    set txt [join $::messages \n]
    $W itemconfigure gesture -text $txt
    $W raise gesture
}

proc Touch2 {W d x y X Y} {
    if {[dict get $d event] ne "gesture"} return

    switch [dict get $d gesture] {
        twofingertap {
            $W delete twofingertap
            set r [expr {[dict get $d distance] / 2}]
            Circle $W $x $y $r -fill yellow -tags twofingertap
        }
        pressandtap {
            if {[dict exists $d begin]} {
                # Only the begin message has delta set
                $W delete pressandtap
                set x1 [expr {$x + [dict get $d deltax]}]
                set y1 [expr {$y + [dict get $d deltay]}]
                $W create line $x $y $x1 $y1 -width 5 -fill red \
                        -tags pressandtap
            }
            if {[dict exists $d end]} {
                # Make end visible by changing colour
                $W itemconfigure pressandtap -fill purple
            }
        }
        zoom {
            $W delete zoom
            set r [expr {[dict get $d distance] / 2}]
            Circle $W $x $y $r -fill blue -tags zoom
        }
        pan {
            $W delete pan
            set dist [dict get $d distance]
            if {$dist == 0} {
                # Must be one finger?
                set r 40
                set col red
            } else {
                set r [expr {$dist / 2}]
                set col green
            }
            Circle $W $x $y $r -fill $col -tags pan
        }
        rotate {
            $W delete rotate
            set a [expr {180.0*[dict get $d angle]/3.141592 - 20}]
            set r [expr {$::size/4}]
            $W create arc [- $x $r] [- $y $r] [+ $x $r] [+ $y $r] \
                    -fill orange -outline black -width 2 -tags rotate \
                    -start $a -extent 40
        }
    }
    Log $W $d
}

console show
set ::size [expr {[winfo screenwidth .] / 4}]
canvas .c1 -width $::size -height $::size -bd 3 -relief solid
canvas .c2 -width $::size -height $::size -bd 3 -relief solid
canvas .c3 -width $::size -height $::size -bd 3 -relief solid
.c1 create text [expr {$::size /2}] [expr {$::size /2}] -text Touch
lappend ::messages "Gesture"
.c2 create text [expr {$::size / 2}] [expr {$::size / 2}] -text GestureAll -tags gesture
.c3 create text [expr {$::size / 2}] [expr {$::size / 2}] -text Gesture -tags gesture

grid .c1 -   -sticky news
grid .c2 .c3 -sticky news
grid columnconfigure . all -weight 1
grid rowconfigure . all -weight 1
wm touch .c1 -touch
wm touch .c2 -all
wm touch .c3 -pan 1 -pansfv 0 -pansfh 0 -pangutter 0 -paninertia 0
bind .c1 <<FingerDown>> "Touch1 %W %d %x %y %X %Y"
bind .c1 <<FingerUp>> "Touch1 %W %d %x %y %X %Y"
bind .c1 <<FingerMotion>> "Touch1 %W %d %x %y %X %Y"
bind .c2 <<Gesture>> "Touch2 %W %d %x %y %X %Y"
bind .c2 <<PinchToZoom>> "Touch2 %W %d %x %y %X %Y"
bind .c3 <<Gesture>> "Touch2 %W %d %x %y %X %Y"
bind .c3 <<PinchToZoom>> "Touch2 %W %d %x %y %X %Y"