Tk Source Code

Check-in [95cf4257]
Login

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

Overview
Comment:More improvements handling characters > U+FFFF as surrogates. Add internal TkUtfPrev(), which handles jumping back over surrogate pairs.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | bug-a179564826
Files: files | file ages | folders
SHA3-256: 95cf4257d6ba29424c067731e238f05400af0793605c2bc7b28772cb52d5d6c5
User & Date: jan.nijtmans 2020-05-14 19:11:57
Context
2020-05-18
22:01
Merge 8.6 check-in: 2a783500 user: jan.nijtmans tags: bug-a179564826
2020-05-14
19:11
More improvements handling characters > U+FFFF as surrogates. Add internal TkUtfPrev(), which handles jumping back over surrogate pairs. check-in: 95cf4257 user: jan.nijtmans tags: bug-a179564826
2020-05-13
19:58
Make bind-34.1 pass on Debian 10 with KDE/Plasma by giving the WM a more complete setup for this test. check-in: a6c87041 user: fvogel tags: core-8-6-branch
2020-04-06
14:52
Better implementation of TkUtfToUniChar(), one that doesn't require cooperation of Tcl (TCL_UTF_MAX>3). Just let Tk do the splitting of 4-byte UTF-8 sequences into surrogates. check-in: 1b1c1394 user: jan.nijtmans tags: bug-a179564826
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Added .gitignore.

























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
*.a
*.dll
*.dylib
*.exe
*.exp
*.lib
*.o
*.obj
*.pdb
*.res
*.sl
*.so
*/Makefile
*/config.cache
*/config.log
*/config.status
*/tkConfig.sh
*/wish*
*/tktest*
*/versions.vc
unix/tk.pc
unix/tclIndex
win/Debug*
win/Release*
win/*.manifest
win/nmhlp-out.txt
win/nmakehlp.out

Changes to .travis.yml.

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
      os: linux
      dist: bionic
      compiler: clang
      env:
        - BUILD_DIR=unix
        - CFGOPT="--enable-symbols"
# Testing on Mac, various styles
    - name: "macOS/Xcode 11.3/Shared"
      os: osx
      osx_image: xcode11.3
      env:
        - BUILD_DIR=unix
        - CFGOPT="--prefix=/usr/local/opt/tcl-tk --with-tcl=/usr/local/opt/tcl-tk/lib --enable-aqua CC=clang CFLAGS=-I/usr/local/opt/tcl-tk/include"
    - name: "macOS/Xcode 11.3/Static"
      os: osx
      osx_image: xcode11.3
      env:
        - BUILD_DIR=unix
        - CFGOPT="--prefix=/usr/local/opt/tcl-tk --with-tcl=/usr/local/opt/tcl-tk/lib --enable-aqua --disable-shared CC=clang CFLAGS=-I/usr/local/opt/tcl-tk/include"
    - name: "macOS/Xcode 11.3/Debug"
      os: osx
      osx_image: xcode11.3
      env:
        - BUILD_DIR=unix
        - CFGOPT="--prefix=/usr/local/opt/tcl-tk --with-tcl=/usr/local/opt/tcl-tk/lib --enable-aqua --enable-symbols CC=clang CFLAGS=-I/usr/local/opt/tcl-tk/include"
    - name: "macOS/Xcode 11.3/Shared/XQuartz"
      os: osx
      osx_image: xcode11.3
      env:
        - BUILD_DIR=unix
        - CFGOPT="--prefix=/usr/local/opt/tcl-tk --with-tcl=/usr/local/opt/tcl-tk/lib --disable-corefoundation --x-includes=/opt/X11/include --x-libraries=/opt/X11/lib CC=clang CFLAGS=-I/usr/local/opt/tcl-tk/include"
# Older MacOS versions
    - name: "macOS/Xcode 11/Shared"
      os: osx
      osx_image: xcode11







|

|



|

|



|

|



|

|







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
      os: linux
      dist: bionic
      compiler: clang
      env:
        - BUILD_DIR=unix
        - CFGOPT="--enable-symbols"
# Testing on Mac, various styles
    - name: "macOS/Xcode 11.4/Shared"
      os: osx
      osx_image: xcode11.4
      env:
        - BUILD_DIR=unix
        - CFGOPT="--prefix=/usr/local/opt/tcl-tk --with-tcl=/usr/local/opt/tcl-tk/lib --enable-aqua CC=clang CFLAGS=-I/usr/local/opt/tcl-tk/include"
    - name: "macOS/Xcode 11.4/Static"
      os: osx
      osx_image: xcode11.4
      env:
        - BUILD_DIR=unix
        - CFGOPT="--prefix=/usr/local/opt/tcl-tk --with-tcl=/usr/local/opt/tcl-tk/lib --enable-aqua --disable-shared CC=clang CFLAGS=-I/usr/local/opt/tcl-tk/include"
    - name: "macOS/Xcode 11.4/Debug"
      os: osx
      osx_image: xcode11.4
      env:
        - BUILD_DIR=unix
        - CFGOPT="--prefix=/usr/local/opt/tcl-tk --with-tcl=/usr/local/opt/tcl-tk/lib --enable-aqua --enable-symbols CC=clang CFLAGS=-I/usr/local/opt/tcl-tk/include"
    - name: "macOS/Xcode 11.4/Shared/XQuartz"
      os: osx
      osx_image: xcode11.4
      env:
        - BUILD_DIR=unix
        - CFGOPT="--prefix=/usr/local/opt/tcl-tk --with-tcl=/usr/local/opt/tcl-tk/lib --disable-corefoundation --x-includes=/opt/X11/include --x-libraries=/opt/X11/lib CC=clang CFLAGS=-I/usr/local/opt/tcl-tk/include"
# Older MacOS versions
    - name: "macOS/Xcode 11/Shared"
      os: osx
      osx_image: xcode11

Changes to doc/bind.n.

506
507
508
509
510
511
512



513
514
515
516
517
518
519
\fBResizeRequest\fR, and \fBExpose\fR events.
.IP "\fB%x\fR, \fB%y\fR" 5
The \fIx\fR and \fIy\fR fields from the event.
For \fBButtonPress\fR, \fBButtonRelease\fR, \fBMotion\fR,
\fBKeyPress\fR, \fBKeyRelease\fR, and \fBMouseWheel\fR events,
\fB%x\fR and \fB%y\fR indicate the position of the mouse pointer
relative to the receiving window.



For \fBEnter\fR and \fBLeave\fR events, the position where the
mouse pointer crossed the window, relative to the receiving window.
For \fBConfigure\fR and \fBCreate\fR requests, the \fIx\fR and \fIy\fR
coordinates of the window relative to its parent window.
.IP \fB%A\fR 5
Substitutes the UNICODE character corresponding to the event, or
the empty string if the event does not correspond to a UNICODE character







>
>
>







506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
\fBResizeRequest\fR, and \fBExpose\fR events.
.IP "\fB%x\fR, \fB%y\fR" 5
The \fIx\fR and \fIy\fR fields from the event.
For \fBButtonPress\fR, \fBButtonRelease\fR, \fBMotion\fR,
\fBKeyPress\fR, \fBKeyRelease\fR, and \fBMouseWheel\fR events,
\fB%x\fR and \fB%y\fR indicate the position of the mouse pointer
relative to the receiving window.
For key events on the Macintosh these are the coordinates of the
mouse at the moment when an X11 KeyEvent is sent to Tk, which could
be slightly later than the time of the physical press or release.
For \fBEnter\fR and \fBLeave\fR events, the position where the
mouse pointer crossed the window, relative to the receiving window.
For \fBConfigure\fR and \fBCreate\fR requests, the \fIx\fR and \fIy\fR
coordinates of the window relative to its parent window.
.IP \fB%A\fR 5
Substitutes the UNICODE character corresponding to the event, or
the empty string if the event does not correspond to a UNICODE character

Changes to doc/colors.n.

940
941
942
943
944
945
946

947
948
949
950
951
952
953
predecessor.
.RS
.DS
systemControlAccentColor
systemControlTextColor
systemDisabledControlTextColor
systemLabelColor  

systemSelectedTextBackgroundColor  
systemSelectedTextColor
systemTextBackgroundColor
systemTextColor  
systemWindowBackgroundColor
systemWindowBackgroundColor1
systemWindowBackgroundColor2







>







940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
predecessor.
.RS
.DS
systemControlAccentColor
systemControlTextColor
systemDisabledControlTextColor
systemLabelColor  
systemLinkColor
systemSelectedTextBackgroundColor  
systemSelectedTextColor
systemTextBackgroundColor
systemTextColor  
systemWindowBackgroundColor
systemWindowBackgroundColor1
systemWindowBackgroundColor2

Changes to doc/entry.n.

444
445
446
447
448
449
450
451

452
453
454
455
456
457
458
459
460
.IP [5]
Clicking mouse button 1 with the Control key down will position the
insertion cursor in the entry without affecting the selection.
.IP [6]
If any normal printing characters are typed in an entry, they are
inserted at the point of the insertion cursor.
.IP [7]
The view in the entry can be adjusted by dragging with mouse button 2.

If mouse button 2 is clicked without moving the mouse, the selection
is copied into the entry at the position of the mouse cursor.
.IP [8]
If the mouse is dragged out of the entry on the left or right sides
while button 1 is pressed, the entry will automatically scroll to
make more text visible (if there is more text off-screen on the side
where the mouse left the window).
.IP [9]
The Left and Right keys move the insertion cursor one character to the







|
>
|
|







444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
.IP [5]
Clicking mouse button 1 with the Control key down will position the
insertion cursor in the entry without affecting the selection.
.IP [6]
If any normal printing characters are typed in an entry, they are
inserted at the point of the insertion cursor.
.IP [7]
The view in the entry can be adjusted by dragging with the middle
mouse button (button 2, or button 3 in TkAqua). If the middle mouse
button is clicked without moving the mouse, the selection is copied
into the entry at the position of the mouse cursor.
.IP [8]
If the mouse is dragged out of the entry on the left or right sides
while button 1 is pressed, the entry will automatically scroll to
make more text visible (if there is more text off-screen on the side
where the mouse left the window).
.IP [9]
The Left and Right keys move the insertion cursor one character to the

Changes to doc/spinbox.n.

510
511
512
513
514
515
516
517

518
519
520
521
522
523
524
525
526
.IP [5]
Clicking mouse button 1 with the Control key down will position the
insertion cursor in the spinbox without affecting the selection.
.IP [6]
If any normal printing characters are typed in a spinbox, they are
inserted at the point of the insertion cursor.
.IP [7]
The view in the spinbox can be adjusted by dragging with mouse button 2.

If mouse button 2 is clicked without moving the mouse, the selection
is copied into the spinbox at the position of the mouse cursor.
.IP [8]
If the mouse is dragged out of the spinbox on the left or right sides
while button 1 is pressed, the spinbox will automatically scroll to
make more text visible (if there is more text off-screen on the side
where the mouse left the window).
.IP [9]
The Left and Right keys move the insertion cursor one character to the







|
>
|
|







510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
.IP [5]
Clicking mouse button 1 with the Control key down will position the
insertion cursor in the spinbox without affecting the selection.
.IP [6]
If any normal printing characters are typed in a spinbox, they are
inserted at the point of the insertion cursor.
.IP [7]
The view in the spinbox can be adjusted by dragging with the middle
mouse button (button 2, or button 3 in TkAqua). If the middle mouse
button is clicked without moving the mouse, the selection is copied
into the spinbox at the position of the mouse cursor.
.IP [8]
If the mouse is dragged out of the spinbox on the left or right sides
while button 1 is pressed, the spinbox will automatically scroll to
make more text visible (if there is more text off-screen on the side
where the mouse left the window).
.IP [9]
The Left and Right keys move the insertion cursor one character to the

Changes to doc/text.n.

2053
2054
2055
2056
2057
2058
2059
2060

2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
.IP [5]
Clicking mouse button 1 with the Control key down will reposition the
insertion cursor without affecting the selection.
.IP [6]
If any normal printing characters are typed, they are inserted at the point of
the insertion cursor.
.IP [7]
The view in the widget can be adjusted by dragging with mouse button 2. If

mouse button 2 is clicked without moving the mouse, the selection is copied
into the text at the position of the mouse cursor. The Insert key also inserts
the selection, but at the position of the insertion cursor.
.IP [8]
If the mouse is dragged out of the widget while button 1 is pressed, the entry
will automatically scroll to make more text visible (if there is more text
off-screen on the side where the mouse left the window).
.IP [9]
The Left and Right keys move the insertion cursor one character to the left or
right; they also clear any selection in the text. If Left or Right is typed







|
>
|
|
|







2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
.IP [5]
Clicking mouse button 1 with the Control key down will reposition the
insertion cursor without affecting the selection.
.IP [6]
If any normal printing characters are typed, they are inserted at the point of
the insertion cursor.
.IP [7]
The view in the widget can be adjusted by dragging with the middle mouse
button (button 2, or button 3 in TkAqua). If the middle mouse button is
clicked without moving the mouse, the selection is copied into the text at the
position of the mouse cursor. The Insert key also inserts the selection,
but at the position of the insertion cursor.
.IP [8]
If the mouse is dragged out of the widget while button 1 is pressed, the entry
will automatically scroll to make more text visible (if there is more text
off-screen on the side where the mouse left the window).
.IP [9]
The Left and Right keys move the insertion cursor one character to the left or
right; they also clear any selection in the text. If Left or Right is typed

Changes to doc/ttk_entry.n.

349
350
351
352
353
354
355
356

357
358
359
360
361
362
363
364
365
.IP \0\(bu 4
Clicking mouse button 1 with the Control key down will position the
insert cursor in the entry without affecting the selection.
.IP \0\(bu 4
If any normal printing characters are typed in an entry, they are
inserted at the point of the insert cursor.
.IP \0\(bu 4
The view in the entry can be adjusted by dragging with mouse button 2.

If mouse button 2 is clicked without moving the mouse, the selection
is copied into the entry at the position of the mouse cursor.
.IP \0\(bu 4
If the mouse is dragged out of the entry on the left or right sides
while button 1 is pressed, the entry will automatically scroll to
make more text visible (if there is more text off-screen on the side
where the mouse left the window).
.IP \0\(bu 4
The Left and Right keys move the insert cursor one character to the







|
>
|
|







349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
.IP \0\(bu 4
Clicking mouse button 1 with the Control key down will position the
insert cursor in the entry without affecting the selection.
.IP \0\(bu 4
If any normal printing characters are typed in an entry, they are
inserted at the point of the insert cursor.
.IP \0\(bu 4
The view in the entry can be adjusted by dragging with the middle
mouse button (button 2, or button 3 in TkAqua). If the middle mouse
button is clicked without moving the mouse, the selection is copied
into the entry at the position of the mouse cursor.
.IP \0\(bu 4
If the mouse is dragged out of the entry on the left or right sides
while button 1 is pressed, the entry will automatically scroll to
make more text visible (if there is more text off-screen on the side
where the mouse left the window).
.IP \0\(bu 4
The Left and Right keys move the insert cursor one character to the

Changes to generic/tk.h.

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
 *				window's parent either doesn't exist or is not
 *				owned by this Tk application.
 * TK_PROP_PROPCHANGE		1 means that PropertyNotify events in the
 *				window's children should propagate up to this
 *				window.
 * TK_WM_MANAGEABLE		1 marks a window as capable of being converted
 *				into a toplevel using [wm manage].




 */

#define TK_MAPPED		1
#define TK_TOP_LEVEL		2
#define TK_ALREADY_DEAD		4
#define TK_NEED_CONFIG_NOTIFY	8
#define TK_GRAB_FLAG		0x10
#define TK_CHECKED_IC		0x20
#define TK_DONT_DESTROY_WINDOW	0x40
#define TK_WM_COLORMAP_WINDOW	0x80
#define TK_EMBEDDED		0x100
#define TK_CONTAINER		0x200
#define TK_BOTH_HALVES		0x400

#define TK_WRAPPER		0x1000
#define TK_REPARENTED		0x2000
#define TK_ANONYMOUS_WINDOW	0x4000
#define TK_HAS_WRAPPER		0x8000
#define TK_WIN_MANAGED		0x10000
#define TK_TOP_HIERARCHY	0x20000
#define TK_PROP_PROPCHANGE	0x40000
#define TK_WM_MANAGEABLE	0x80000


/*
 *----------------------------------------------------------------------
 *
 * Procedure prototypes and structures used for defining new canvas items:
 *
 *----------------------------------------------------------------------







>
>
>
>













>








>







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
 *				window's parent either doesn't exist or is not
 *				owned by this Tk application.
 * TK_PROP_PROPCHANGE		1 means that PropertyNotify events in the
 *				window's children should propagate up to this
 *				window.
 * TK_WM_MANAGEABLE		1 marks a window as capable of being converted
 *				into a toplevel using [wm manage].
 * TK_CAN_INPUT_TEXT            1 means that this window accepts text input.
 *                              Used on macOS to indicate that key events can be
 *                              processed with the NSTextInputClient protocol.
 *                              Not currently accessible through the public API.
 */

#define TK_MAPPED		1
#define TK_TOP_LEVEL		2
#define TK_ALREADY_DEAD		4
#define TK_NEED_CONFIG_NOTIFY	8
#define TK_GRAB_FLAG		0x10
#define TK_CHECKED_IC		0x20
#define TK_DONT_DESTROY_WINDOW	0x40
#define TK_WM_COLORMAP_WINDOW	0x80
#define TK_EMBEDDED		0x100
#define TK_CONTAINER		0x200
#define TK_BOTH_HALVES		0x400

#define TK_WRAPPER		0x1000
#define TK_REPARENTED		0x2000
#define TK_ANONYMOUS_WINDOW	0x4000
#define TK_HAS_WRAPPER		0x8000
#define TK_WIN_MANAGED		0x10000
#define TK_TOP_HIERARCHY	0x20000
#define TK_PROP_PROPCHANGE	0x40000
#define TK_WM_MANAGEABLE	0x80000
#define TK_CAN_INPUT_TEXT       0x100000

/*
 *----------------------------------------------------------------------
 *
 * Procedure prototypes and structures used for defining new canvas items:
 *
 *----------------------------------------------------------------------

Changes to generic/tkBind.c.

339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
 * Constants that define how close together two events must be in milliseconds
 * or pixels to meet the PAT_NEARBY constraint:
 */

#define NEARBY_PIXELS	5
#define NEARBY_MS	500

/*
 * Needed as "no-number" constant for integers. The value of this constant is
 * outside of integer range (type "int"). (Unfortunatly current version of
 * Tcl/Tk does not provide C99 integer support.)
 */

#define NO_NUMBER (((Tcl_WideInt) (~ (unsigned) 0)) + 1)

/*
 * The following structure is used in the nameTable of a virtual event table
 * to associate a virtual event with all the physical events that can trigger
 * it.
 */

TK_PTR_ARRAY_DEFINE(PhysOwned, PatSeq); /* define array of pattern seqs */







<
<
<
<
<
<
<
<







339
340
341
342
343
344
345








346
347
348
349
350
351
352
 * Constants that define how close together two events must be in milliseconds
 * or pixels to meet the PAT_NEARBY constraint:
 */

#define NEARBY_PIXELS	5
#define NEARBY_MS	500









/*
 * The following structure is used in the nameTable of a virtual event table
 * to associate a virtual event with all the physical events that can trigger
 * it.
 */

TK_PTR_ARRAY_DEFINE(PhysOwned, PatSeq); /* define array of pattern seqs */
557
558
559
560
561
562
563

564
565
566
567
568





569
570













571
572
573
574
575
576
577
#define CONFIG			(1<<12)
#define GRAVITY			(1<<13)
#define CIRC			(1<<14)
#define PROP			(1<<15)
#define COLORMAP		(1<<16)
#define VIRTUAL			(1<<17)
#define ACTIVATE		(1<<18)

#define	MAPREQ			(1<<19)
#define	CONFIGREQ		(1<<20)
#define	RESIZEREQ		(1<<21)
#define CIRCREQ			(1<<22)






#define KEY_BUTTON_MOTION_VIRTUAL	(KEY|BUTTON|MOTION|VIRTUAL)
#define KEY_BUTTON_MOTION_CROSSING	(KEY|BUTTON|MOTION|VIRTUAL|CROSSING)














static const int flagArray[TK_LASTEVENT] = {
   /* Not used */		0,
   /* Not used */		0,
   /* KeyPress */		KEY,
   /* KeyRelease */		KEY,
   /* ButtonPress */		BUTTON,







>
|
|
|
|

>
>
>
>
>
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>







549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
#define CONFIG			(1<<12)
#define GRAVITY			(1<<13)
#define CIRC			(1<<14)
#define PROP			(1<<15)
#define COLORMAP		(1<<16)
#define VIRTUAL			(1<<17)
#define ACTIVATE		(1<<18)
#define WHEEL			(1<<19)
#define	MAPREQ			(1<<20)
#define	CONFIGREQ		(1<<21)
#define	RESIZEREQ		(1<<22)
#define CIRCREQ			(1<<23)

/*
 * These structs agree with xkey for the fields type, serial, send_event, display,
 * window, root, subwindow, time, x, y, x_root, and y_root.  So when accessing
 * these fields we may pretend that we are using a struct xkey.
 */

#define HAS_XKEY_HEAD (KEY|BUTTON|MOTION|VIRTUAL|CROSSING|WHEEL)

/* 
 * The xcrossing struct puts the state field in a different location, but the other
 * events above agree on where state is located.
 */

#define HAS_XKEY_HEAD_AND_STATE (KEY|BUTTON|MOTION|VIRTUAL|WHEEL)

/*
 * Event types which support -warp.
 */

#define CAN_WARP (KEY|BUTTON|MOTION|WHEEL)

static const int flagArray[TK_LASTEVENT] = {
   /* Not used */		0,
   /* Not used */		0,
   /* KeyPress */		KEY,
   /* KeyRelease */		KEY,
   /* ButtonPress */		BUTTON,
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
   /* SelectionNotify */	0,
   /* ColormapNotify */		COLORMAP,
   /* ClientMessage */		0,
   /* MappingNotify */		0,
   /* VirtualEvent */		VIRTUAL,
   /* Activate */		ACTIVATE,
   /* Deactivate */		ACTIVATE,
   /* MouseWheel */		KEY
};

/*
 * The following table is used to map between the location where an generated
 * event should be queued and the string used to specify the location.
 */








|







615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
   /* SelectionNotify */	0,
   /* ColormapNotify */		COLORMAP,
   /* ClientMessage */		0,
   /* MappingNotify */		0,
   /* VirtualEvent */		VIRTUAL,
   /* Activate */		ACTIVATE,
   /* Deactivate */		ACTIVATE,
   /* MouseWheel */		WHEEL
};

/*
 * The following table is used to map between the location where an generated
 * event should be queued and the string used to specify the location.
 */

1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
    /* type of TkPattern.info is well defined? */
    assert(sizeof(Info) >= sizeof(KeySym));
    assert(sizeof(Info) >= sizeof(unsigned));

    /* ensure that our matching algorithm is working (when testing detail) */
    assert(sizeof(Detail) == sizeof(Tk_Uid));

    /* test that constant NO_NUMBER is indeed out of integer range */
    assert(sizeof(NO_NUMBER) > sizeof(int));
    assert(((int) NO_NUMBER) == 0 && NO_NUMBER != 0);

    /* test expected indices of Button1..Button5, otherwise our button handling is not working */
    assert(Button1 == 1 && Button2 == 2 && Button3 == 3 && Button4 == 4 && Button5 == 5);
    assert(Button2Mask == (Button1Mask << 1));
    assert(Button3Mask == (Button1Mask << 2));
    assert(Button4Mask == (Button1Mask << 3));
    assert(Button5Mask == (Button1Mask << 4));








<
<
<
<







1241
1242
1243
1244
1245
1246
1247




1248
1249
1250
1251
1252
1253
1254
    /* type of TkPattern.info is well defined? */
    assert(sizeof(Info) >= sizeof(KeySym));
    assert(sizeof(Info) >= sizeof(unsigned));

    /* ensure that our matching algorithm is working (when testing detail) */
    assert(sizeof(Detail) == sizeof(Tk_Uid));





    /* test expected indices of Button1..Button5, otherwise our button handling is not working */
    assert(Button1 == 1 && Button2 == 2 && Button3 == 3 && Button4 == 4 && Button5 == 5);
    assert(Button2Mask == (Button1Mask << 1));
    assert(Button3Mask == (Button1Mask << 2));
    assert(Button4Mask == (Button1Mask << 3));
    assert(Button5Mask == (Button1Mask << 4));

2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
     * Ignore event types which are not in flagArray and all zeroes there.
     */

    if (eventPtr->type >= TK_LASTEVENT || !flags) {
	return;
    }

    if (flags & KEY_BUTTON_MOTION_VIRTUAL) {
	bindPtr->curModMask = eventPtr->xkey.state;
    } else if (flags & CROSSING) {
	bindPtr->curModMask = eventPtr->xcrossing.state;
    }

    dispPtr = ((TkWindow *) tkwin)->dispPtr;
    bindInfoPtr = winPtr->mainPtr->bindInfo;







|







2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
     * Ignore event types which are not in flagArray and all zeroes there.
     */

    if (eventPtr->type >= TK_LASTEVENT || !flags) {
	return;
    }

    if (flags & HAS_XKEY_HEAD_AND_STATE) {
	bindPtr->curModMask = eventPtr->xkey.state;
    } else if (flags & CROSSING) {
	bindPtr->curModMask = eventPtr->xcrossing.state;
    }

    dispPtr = ((TkWindow *) tkwin)->dispPtr;
    bindInfoPtr = winPtr->mainPtr->bindInfo;
2919
2920
2921
2922
2923
2924
2925










2926
2927
2928
2929
2930

2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221



3222
3223
3224
3225
3226
3227
3228
    assert(before);
    assert(eventPtr);
    assert(dsPtr);

    Tcl_DStringInit(&buf);
    evPtr = &eventPtr->xev;
    flags = (evPtr->type < TK_LASTEVENT) ? flagArray[evPtr->type] : 0;











    while (1) {
	char numStorage[TCL_INTEGER_SPACE];
	const char *string;
	Tcl_WideInt number;


	/*
	 * Find everything up to the next % character and append it to the
	 * result string.
	 */

	for (string = before; *string && *string != '%'; ++string)
	    ;
	if (string != before) {
	    Tcl_DStringAppend(dsPtr, before, string - before);
	    before = string;
	}
	if (!*before) {
	    break;
	}

	/*
	 * There's a percent sequence here. Process it.
	 */

	number = NO_NUMBER;
	string = "??";

	switch (before[1]) {
	case '#':
	    number = evPtr->xany.serial;
	    break;
	case 'a':
	    if (flags & CONFIG) {
		TkpPrintWindowId(numStorage, evPtr->xconfigure.above);
		string = numStorage;
	    }
	    break;
	case 'b':
	    if (flags & BUTTON) {
		number = evPtr->xbutton.button;
	    }
	    break;
	case 'c':
	    if (flags & EXPOSE) {
		number = evPtr->xexpose.count;
	    }
	    break;
	case 'd':
	    if (flags & (CROSSING|FOCUS)) {
		int detail = (flags & FOCUS) ? evPtr->xfocus.detail : evPtr->xcrossing.detail;
		string = TkFindStateString(notifyDetail, detail);
	    } else if (flags & CONFIGREQ) {
		if (evPtr->xconfigurerequest.value_mask & CWStackMode) {
		    string = TkFindStateString(configureRequestDetail, evPtr->xconfigurerequest.detail);
		} else {
		    string = "";
		}
	    } else if (flags & VIRTUAL) {
		XVirtualEvent *vePtr = (XVirtualEvent *) evPtr;
		string = vePtr->user_data ? Tcl_GetString(vePtr->user_data) : "";
	    }
	    break;
	case 'f':
	    if (flags & CROSSING) {
		number = evPtr->xcrossing.focus;
	    }
	    break;
	case 'h':
	    if (flags & EXPOSE) {
		number = evPtr->xexpose.height;
	    } else if (flags & CONFIG) {
		number = evPtr->xconfigure.height;
	    } else if (flags & CREATE) {
		number = evPtr->xcreatewindow.height;
	    } else if (flags & CONFIGREQ) {
		number = evPtr->xconfigurerequest.height;
	    } else if (flags & RESIZEREQ) {
		number = evPtr->xresizerequest.height;
	    }
	    break;
	case 'i':
	    if (flags & CREATE) {
		TkpPrintWindowId(numStorage, evPtr->xcreatewindow.window);
	    } else if (flags & CONFIGREQ) {
		TkpPrintWindowId(numStorage, evPtr->xconfigurerequest.window);
	    } else if (flags & MAPREQ) {
		TkpPrintWindowId(numStorage, evPtr->xmaprequest.window);
	    } else {
		TkpPrintWindowId(numStorage, evPtr->xany.window);
	    }
	    string = numStorage;
	    break;
	case 'k':
	    if ((flags & KEY) && evPtr->type != MouseWheelEvent) {
		number = evPtr->xkey.keycode;
	    }
	    break;
	case 'm':
	    if (flags & CROSSING) {
		string = TkFindStateString(notifyMode, evPtr->xcrossing.mode);
	    } else if (flags & FOCUS) {
		string = TkFindStateString(notifyMode, evPtr->xfocus.mode);
	    }
	    break;
	case 'o':
	    if (flags & CREATE) {
		number = evPtr->xcreatewindow.override_redirect;
	    } else if (flags & MAP) {
		number = evPtr->xmap.override_redirect;
	    } else if (flags & REPARENT) {
		number = evPtr->xreparent.override_redirect;
	    } else if (flags & CONFIG) {
		number = evPtr->xconfigure.override_redirect;
	    }
	    break;
	case 'p':
	    if (flags & CIRC) {
		string = TkFindStateString(circPlace, evPtr->xcirculate.place);
	    } else if (flags & CIRCREQ) {
		string = TkFindStateString(circPlace, evPtr->xcirculaterequest.place);
	    }
	    break;
	case 's':
	    if (flags & KEY_BUTTON_MOTION_VIRTUAL) {
		number = evPtr->xkey.state;
	    } else if (flags & CROSSING) {
		number = evPtr->xcrossing.state;
	    } else if (flags & PROP) {
		string = TkFindStateString(propNotify, evPtr->xproperty.state);
	    } else if (flags & VISIBILITY) {
		string = TkFindStateString(visNotify, evPtr->xvisibility.state);
	    }
	    break;
	case 't':
	    if (flags & KEY_BUTTON_MOTION_VIRTUAL) {
		number = (int) evPtr->xkey.time;
	    } else if (flags & CROSSING) {
		number = (int) evPtr->xcrossing.time;
	    } else if (flags & PROP) {
		number = (int) evPtr->xproperty.time;
	    }
	    break;
	case 'v':
	    number = evPtr->xconfigurerequest.value_mask;
	    break;
	case 'w':
	    if (flags & EXPOSE) {
		number = evPtr->xexpose.width;
	    } else if (flags & CONFIG) {
		number = evPtr->xconfigure.width;
	    } else if (flags & CREATE) {
		number = evPtr->xcreatewindow.width;
	    } else if (flags & CONFIGREQ) {
		number = evPtr->xconfigurerequest.width;
	    } else if (flags & RESIZEREQ) {
		number = evPtr->xresizerequest.width;
	    }
	    break;
	case 'x':
	    if (flags & KEY_BUTTON_MOTION_VIRTUAL) {
		number = evPtr->xkey.x;
	    } else if (flags & CROSSING) {
		number = evPtr->xcrossing.x;
	    } else if (flags & EXPOSE) {
		number = evPtr->xexpose.x;
	    } else if (flags & (CREATE|CONFIG|GRAVITY)) {
		number = evPtr->xcreatewindow.x;
	    } else if (flags & REPARENT) {
		number = evPtr->xreparent.x;
	    } else if (flags & CREATE) {
		number = evPtr->xcreatewindow.x;
	    } else if (flags & CONFIGREQ) {
		number = evPtr->xconfigurerequest.x;
	    }
	    break;
	case 'y':
	    if (flags & KEY_BUTTON_MOTION_VIRTUAL) {
		number = evPtr->xkey.y;
	    } else if (flags & EXPOSE) {
		number = evPtr->xexpose.y;
	    } else if (flags & (CREATE|CONFIG|GRAVITY)) {
		number = evPtr->xcreatewindow.y;
	    } else if (flags & REPARENT) {
		number = evPtr->xreparent.y;
	    } else if (flags & CROSSING) {
		number = evPtr->xcrossing.y;
	    } else if (flags & CREATE) {
		number = evPtr->xcreatewindow.y;
	    } else if (flags & CONFIGREQ) {
		number = evPtr->xconfigurerequest.y;
	    }
	    break;
	case 'A':
	    if ((flags & KEY) && evPtr->type != MouseWheelEvent) {
		Tcl_DStringFree(&buf);
		string = TkpGetString(winPtr, evPtr, &buf);
	    }
	    break;
	case 'B':
	    if (flags & CREATE) {
		number = evPtr->xcreatewindow.border_width;
	    } else if (flags & CONFIGREQ) {
		number = evPtr->xconfigurerequest.border_width;
	    } else if (flags & CONFIG) {
		number = evPtr->xconfigure.border_width;
	    }
	    break;
	case 'D':
	    /*
	     * This is used only by the MouseWheel event.
	     */
	    if ((flags & KEY) && evPtr->type == MouseWheelEvent) {
		number = evPtr->xkey.keycode;
	    }
	    break;
	case 'E':
	    number = (int) evPtr->xany.send_event;
	    break;
	case 'K':
	    if ((flags & KEY) && evPtr->type != MouseWheelEvent) {
		const char *name = TkKeysymToString(eventPtr->detail.info);
		if (name) {
		    string = name;
		}
	    }
	    break;
	case 'M':
	    number = scriptCount;
	    break;
	case 'N':
	    if ((flags & KEY) && evPtr->type != MouseWheelEvent) {
		number = (int) eventPtr->detail.info;
	    }
	    break;
	case 'P':
	    if (flags & PROP) {
		string = Tk_GetAtomName((Tk_Window) winPtr, evPtr->xproperty.atom);
	    }
	    break;
	case 'R':
	    if (flags & KEY_BUTTON_MOTION_CROSSING) {
		TkpPrintWindowId(numStorage, evPtr->xkey.root);
		string = numStorage;
	    }
	    break;
	case 'S':
	    if (flags & KEY_BUTTON_MOTION_CROSSING) {
		TkpPrintWindowId(numStorage, evPtr->xkey.subwindow);
		string = numStorage;
	    }
	    break;
	case 'T':
	    number = evPtr->type;
	    break;
	case 'W': {
	    Tk_Window tkwin = Tk_IdToWindow(evPtr->xany.display, evPtr->xany.window);
	    if (tkwin) {
		string = Tk_PathName(tkwin);
	    }
	    break;
	}
	case 'X':
	    if (flags & KEY_BUTTON_MOTION_CROSSING) {
		number = evPtr->xkey.x_root;
	    }
	    break;
	case 'Y':
	    if (flags & KEY_BUTTON_MOTION_CROSSING) {
		number = evPtr->xkey.y_root;
	    }
	    break;
	default:
	    numStorage[0] = before[1];
	    numStorage[1] = '\0';
	    string = numStorage;
	    break;
	}

	if (number != NO_NUMBER) {
	    snprintf(numStorage, sizeof(numStorage), "%d", (int) number);
	    string = numStorage;
	}
	{   /* local scope */
	    int cvtFlags;
	    unsigned spaceNeeded = Tcl_ScanElement(string, &cvtFlags);
	    unsigned length = Tcl_DStringLength(dsPtr);

	    Tcl_DStringSetLength(dsPtr, length + spaceNeeded);
	    spaceNeeded = Tcl_ConvertElement(
		    string, Tcl_DStringValue(dsPtr) + length, cvtFlags | TCL_DONT_USE_BRACES);
	    Tcl_DStringSetLength(dsPtr, length + spaceNeeded);
	    before += 2;
	}
    }




    Tcl_DStringFree(&buf);
}

/*
 *----------------------------------------------------------------------
 *
 * ChangeScreen --







>
>
>
>
>
>
>
>
>
>




|
>




















<

<


|









|




|



















|




|

|

|

|

|















|
|











|

|

|

|










|
|

|







|
|
<
<

|



|



|

|

|

|

|



|
|
<
<

|

|

|
<
<

|



|
|

|

|

|
<
<
<
<

|



|






|

|

|



<
<
<
|
|



|


|







|


|
|








|





|





|









|
|



|
|








<
<
<
<
<













>
>
>







2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968

2969

2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078


3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101


3102
3103
3104
3105
3106
3107


3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120




3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140



3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206





3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
    assert(before);
    assert(eventPtr);
    assert(dsPtr);

    Tcl_DStringInit(&buf);
    evPtr = &eventPtr->xev;
    flags = (evPtr->type < TK_LASTEVENT) ? flagArray[evPtr->type] : 0;

#define SET_NUMBER(value)   { number = (value);			     \
    snprintf(numStorage, sizeof(numStorage), "%" TCL_LL_MODIFIER "d", number);	     \
    string = numStorage;					     \
    }

#define SET_UNUMBER(value)  { unumber = (value);				\
	snprintf(numStorage, sizeof(numStorage), "%" TCL_LL_MODIFIER "u", unumber);	\
	string = numStorage;						\
    }

    while (1) {
	char numStorage[TCL_INTEGER_SPACE];
	const char *string;
	Tcl_WideInt number;     /* signed */
	Tcl_WideUInt unumber;   /* unsigned */

	/*
	 * Find everything up to the next % character and append it to the
	 * result string.
	 */

	for (string = before; *string && *string != '%'; ++string)
	    ;
	if (string != before) {
	    Tcl_DStringAppend(dsPtr, before, string - before);
	    before = string;
	}
	if (!*before) {
	    break;
	}

	/*
	 * There's a percent sequence here. Process it.
	 */


	string = "??";

	switch (before[1]) {
	case '#':
	    SET_UNUMBER(evPtr->xany.serial);
	    break;
	case 'a':
	    if (flags & CONFIG) {
		TkpPrintWindowId(numStorage, evPtr->xconfigure.above);
		string = numStorage;
	    }
	    break;
	case 'b':
	    if (flags & BUTTON) {
		SET_UNUMBER(evPtr->xbutton.button);
	    }
	    break;
	case 'c':
	    if (flags & EXPOSE) {
		SET_NUMBER(evPtr->xexpose.count);
	    }
	    break;
	case 'd':
	    if (flags & (CROSSING|FOCUS)) {
		int detail = (flags & FOCUS) ? evPtr->xfocus.detail : evPtr->xcrossing.detail;
		string = TkFindStateString(notifyDetail, detail);
	    } else if (flags & CONFIGREQ) {
		if (evPtr->xconfigurerequest.value_mask & CWStackMode) {
		    string = TkFindStateString(configureRequestDetail, evPtr->xconfigurerequest.detail);
		} else {
		    string = "";
		}
	    } else if (flags & VIRTUAL) {
		XVirtualEvent *vePtr = (XVirtualEvent *) evPtr;
		string = vePtr->user_data ? Tcl_GetString(vePtr->user_data) : "";
	    }
	    break;
	case 'f':
	    if (flags & CROSSING) {
		SET_NUMBER(evPtr->xcrossing.focus != 0);
	    }
	    break;
	case 'h':
	    if (flags & EXPOSE) {
		SET_NUMBER(evPtr->xexpose.height);
	    } else if (flags & CONFIG) {
		SET_NUMBER(evPtr->xconfigure.height);
	    } else if (flags & CREATE) {
		SET_NUMBER(evPtr->xcreatewindow.height);
	    } else if (flags & CONFIGREQ) {
		SET_NUMBER(evPtr->xconfigurerequest.height);
	    } else if (flags & RESIZEREQ) {
		SET_NUMBER(evPtr->xresizerequest.height);
	    }
	    break;
	case 'i':
	    if (flags & CREATE) {
		TkpPrintWindowId(numStorage, evPtr->xcreatewindow.window);
	    } else if (flags & CONFIGREQ) {
		TkpPrintWindowId(numStorage, evPtr->xconfigurerequest.window);
	    } else if (flags & MAPREQ) {
		TkpPrintWindowId(numStorage, evPtr->xmaprequest.window);
	    } else {
		TkpPrintWindowId(numStorage, evPtr->xany.window);
	    }
	    string = numStorage;
	    break;
	case 'k':
	    if (flags & KEY) {
		SET_UNUMBER(evPtr->xkey.keycode);
	    }
	    break;
	case 'm':
	    if (flags & CROSSING) {
		string = TkFindStateString(notifyMode, evPtr->xcrossing.mode);
	    } else if (flags & FOCUS) {
		string = TkFindStateString(notifyMode, evPtr->xfocus.mode);
	    }
	    break;
	case 'o':
	    if (flags & CREATE) {
		SET_NUMBER(evPtr->xcreatewindow.override_redirect != 0);
	    } else if (flags & MAP) {
		SET_NUMBER(evPtr->xmap.override_redirect != 0);
	    } else if (flags & REPARENT) {
		SET_NUMBER(evPtr->xreparent.override_redirect != 0);
	    } else if (flags & CONFIG) {
		SET_NUMBER(evPtr->xconfigure.override_redirect != 0);
	    }
	    break;
	case 'p':
	    if (flags & CIRC) {
		string = TkFindStateString(circPlace, evPtr->xcirculate.place);
	    } else if (flags & CIRCREQ) {
		string = TkFindStateString(circPlace, evPtr->xcirculaterequest.place);
	    }
	    break;
	case 's':
	    if (flags & HAS_XKEY_HEAD_AND_STATE) {
		SET_UNUMBER(evPtr->xkey.state);
	    } else if (flags & CROSSING) {
		SET_UNUMBER(evPtr->xcrossing.state);
	    } else if (flags & PROP) {
		string = TkFindStateString(propNotify, evPtr->xproperty.state);
	    } else if (flags & VISIBILITY) {
		string = TkFindStateString(visNotify, evPtr->xvisibility.state);
	    }
	    break;
	case 't':
	    if (flags & HAS_XKEY_HEAD) {
		SET_UNUMBER(evPtr->xkey.time);


	    } else if (flags & PROP) {
		SET_UNUMBER(evPtr->xproperty.time);
	    }
	    break;
	case 'v':
	    SET_UNUMBER(evPtr->xconfigurerequest.value_mask);
	    break;
	case 'w':
	    if (flags & EXPOSE) {
		SET_NUMBER(evPtr->xexpose.width);
	    } else if (flags & CONFIG) {
		SET_NUMBER(evPtr->xconfigure.width);
	    } else if (flags & CREATE) {
		SET_NUMBER(evPtr->xcreatewindow.width);
	    } else if (flags & CONFIGREQ) {
		SET_NUMBER(evPtr->xconfigurerequest.width);
	    } else if (flags & RESIZEREQ) {
		SET_NUMBER(evPtr->xresizerequest.width);
	    }
	    break;
	case 'x':
	    if (flags & HAS_XKEY_HEAD) {
		SET_NUMBER(evPtr->xkey.x);


	    } else if (flags & EXPOSE) {
		SET_NUMBER(evPtr->xexpose.x);
	    } else if (flags & (CREATE|CONFIG|GRAVITY)) {
		SET_NUMBER(evPtr->xcreatewindow.x);
	    } else if (flags & REPARENT) {
		SET_NUMBER(evPtr->xreparent.x);


	    } else if (flags & CONFIGREQ) {
		SET_NUMBER(evPtr->xconfigurerequest.x);
	    }
	    break;
	case 'y':
	    if (flags & HAS_XKEY_HEAD) {
		SET_NUMBER(evPtr->xkey.y);
	    } else if (flags & EXPOSE) {
		SET_NUMBER(evPtr->xexpose.y);
	    } else if (flags & (CREATE|CONFIG|GRAVITY)) {
		SET_NUMBER(evPtr->xcreatewindow.y);
	    } else if (flags & REPARENT) {
		SET_NUMBER(evPtr->xreparent.y);




	    } else if (flags & CONFIGREQ) {
		SET_NUMBER(evPtr->xconfigurerequest.y);
	    }
	    break;
	case 'A':
	    if (flags & KEY) {
		Tcl_DStringFree(&buf);
		string = TkpGetString(winPtr, evPtr, &buf);
	    }
	    break;
	case 'B':
	    if (flags & CREATE) {
		SET_NUMBER(evPtr->xcreatewindow.border_width);
	    } else if (flags & CONFIGREQ) {
		SET_NUMBER(evPtr->xconfigurerequest.border_width);
	    } else if (flags & CONFIG) {
		SET_NUMBER(evPtr->xconfigure.border_width);
	    }
	    break;
	case 'D':



	    if (flags & WHEEL) {
		SET_NUMBER((int)evPtr->xbutton.button); /* mis-use button field for this */
	    }
	    break;
	case 'E':
	    SET_NUMBER(evPtr->xany.send_event != 0);
	    break;
	case 'K':
	    if (flags & KEY) {
		const char *name = TkKeysymToString(eventPtr->detail.info);
		if (name) {
		    string = name;
		}
	    }
	    break;
	case 'M':
	    SET_UNUMBER(scriptCount);
	    break;
	case 'N':
	    if (flags & KEY) {
		SET_UNUMBER(eventPtr->detail.info);
	    }
	    break;
	case 'P':
	    if (flags & PROP) {
		string = Tk_GetAtomName((Tk_Window) winPtr, evPtr->xproperty.atom);
	    }
	    break;
	case 'R':
	    if (flags & HAS_XKEY_HEAD) {
		TkpPrintWindowId(numStorage, evPtr->xkey.root);
		string = numStorage;
	    }
	    break;
	case 'S':
	    if (flags & HAS_XKEY_HEAD) {
		TkpPrintWindowId(numStorage, evPtr->xkey.subwindow);
		string = numStorage;
	    }
	    break;
	case 'T':
	    SET_NUMBER(evPtr->type);
	    break;
	case 'W': {
	    Tk_Window tkwin = Tk_IdToWindow(evPtr->xany.display, evPtr->xany.window);
	    if (tkwin) {
		string = Tk_PathName(tkwin);
	    }
	    break;
	}
	case 'X':
	    if (flags & HAS_XKEY_HEAD) {
		SET_NUMBER(evPtr->xkey.x_root);
	    }
	    break;
	case 'Y':
	    if (flags & HAS_XKEY_HEAD) {
		SET_NUMBER(evPtr->xkey.y_root);
	    }
	    break;
	default:
	    numStorage[0] = before[1];
	    numStorage[1] = '\0';
	    string = numStorage;
	    break;
	}





	{   /* local scope */
	    int cvtFlags;
	    unsigned spaceNeeded = Tcl_ScanElement(string, &cvtFlags);
	    unsigned length = Tcl_DStringLength(dsPtr);

	    Tcl_DStringSetLength(dsPtr, length + spaceNeeded);
	    spaceNeeded = Tcl_ConvertElement(
		    string, Tcl_DStringValue(dsPtr) + length, cvtFlags | TCL_DONT_USE_BRACES);
	    Tcl_DStringSetLength(dsPtr, length + spaceNeeded);
	    before += 2;
	}
    }

#undef SET_NUMBER
#undef SET_UNUMBER   

    Tcl_DStringFree(&buf);
}

/*
 *----------------------------------------------------------------------
 *
 * ChangeScreen --
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
    if (flags & DESTROY) {
	/*
	 * Event DestroyNotify should be generated by destroying the window.
	 */
	Tk_DestroyWindow(tkwin);
	return TCL_OK;
    }
    if (flags & KEY_BUTTON_MOTION_VIRTUAL) {
	event.general.xkey.state = pat.modMask;
	if ((flags & KEY) && event.general.xany.type != MouseWheelEvent) {
	    TkpSetKeycodeAndState(tkwin, pat.info, &event.general);
	} else if (flags & BUTTON) {
	    event.general.xbutton.button = pat.info;
	} else if (flags & VIRTUAL) {
	    event.virtual.name = pat.name;
	}
    }
    if (flags & (CREATE|UNMAP|MAP|REPARENT|CONFIG|GRAVITY|CIRC)) {
	event.general.xcreatewindow.window = event.general.xany.window;
    }

    if (flags & KEY_BUTTON_MOTION_CROSSING) {
	event.general.xkey.x_root = -1;
	event.general.xkey.y_root = -1;
    }

    if (event.general.xany.type == FocusIn || event.general.xany.type == FocusOut) {
	event.general.xany.send_event = GENERATED_FOCUS_EVENT_MAGIC;
    }







|

|











|







3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
    if (flags & DESTROY) {
	/*
	 * Event DestroyNotify should be generated by destroying the window.
	 */
	Tk_DestroyWindow(tkwin);
	return TCL_OK;
    }
    if (flags & HAS_XKEY_HEAD_AND_STATE) {
	event.general.xkey.state = pat.modMask;
	if (flags & KEY) {
	    TkpSetKeycodeAndState(tkwin, pat.info, &event.general);
	} else if (flags & BUTTON) {
	    event.general.xbutton.button = pat.info;
	} else if (flags & VIRTUAL) {
	    event.virtual.name = pat.name;
	}
    }
    if (flags & (CREATE|UNMAP|MAP|REPARENT|CONFIG|GRAVITY|CIRC)) {
	event.general.xcreatewindow.window = event.general.xany.window;
    }

    if (flags & HAS_XKEY_HEAD) {
	event.general.xkey.x_root = -1;
	event.general.xkey.y_root = -1;
    }

    if (event.general.xany.type == FocusIn || event.general.xany.type == FocusOut) {
	event.general.xany.send_event = GENERATED_FOCUS_EVENT_MAGIC;
    }
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
	}

	switch ((enum field) index) {
	case EVENT_WARP:
	    if (Tcl_GetBooleanFromObj(interp, valuePtr, &warp) != TCL_OK) {
		return TCL_ERROR;
	    }
	    if (!(flags & KEY_BUTTON_MOTION_VIRTUAL)) {
		badOpt = 1;
	    }
	    break;
	case EVENT_WHEN:
	    pos = (Tcl_QueuePosition) TkFindStateNumObj(interp, optionPtr, queuePosition, valuePtr);
	    if ((int) pos < -1) {
		return TCL_ERROR;







|







3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
	}

	switch ((enum field) index) {
	case EVENT_WARP:
	    if (Tcl_GetBooleanFromObj(interp, valuePtr, &warp) != TCL_OK) {
		return TCL_ERROR;
	    }
	    if (!(flags & CAN_WARP)) {
		badOpt = 1;
	    }
	    break;
	case EVENT_WHEN:
	    pos = (Tcl_QueuePosition) TkFindStateNumObj(interp, optionPtr, queuePosition, valuePtr);
	    if ((int) pos < -1) {
		return TCL_ERROR;
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
		badOpt = 1;
	    }
	    break;
	case EVENT_DELTA:
	    if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) {
		return TCL_ERROR;
	    }
	    if ((flags & KEY) && event.general.xkey.type == MouseWheelEvent) {
		event.general.xkey.keycode = number;
	    } else {
		badOpt = 1;
	    }
	    break;
	case EVENT_DETAIL:
	    number = TkFindStateNumObj(interp, optionPtr, notifyDetail, valuePtr);
	    if (number < 0) {







|
|







4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
		badOpt = 1;
	    }
	    break;
	case EVENT_DELTA:
	    if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) {
		return TCL_ERROR;
	    }
	    if (flags & WHEEL) {
		event.general.xbutton.button = (unsigned)number; /* mis-use button field for this */
	    } else {
		badOpt = 1;
	    }
	    break;
	case EVENT_DETAIL:
	    number = TkFindStateNumObj(interp, optionPtr, notifyDetail, valuePtr);
	    if (number < 0) {
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
		badOpt = 1;
	    }
	    break;
	case EVENT_KEYCODE:
	    if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) {
		return TCL_ERROR;
	    }
	    if ((flags & KEY) && event.general.xkey.type != MouseWheelEvent) {
		event.general.xkey.keycode = number;
	    } else {
		badOpt = 1;
	    }
	    break;
	case EVENT_KEYSYM: {
	    KeySym keysym;







|







4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
		badOpt = 1;
	    }
	    break;
	case EVENT_KEYCODE:
	    if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) {
		return TCL_ERROR;
	    }
	    if (flags & KEY) {
		event.general.xkey.keycode = number;
	    } else {
		badOpt = 1;
	    }
	    break;
	case EVENT_KEYSYM: {
	    KeySym keysym;
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099

	    TkpSetKeycodeAndState(tkwin, keysym, &event.general);
	    if (event.general.xkey.keycode == 0) {
		Tcl_SetObjResult(interp, Tcl_ObjPrintf("no keycode for keysym \"%s\"", value));
		Tcl_SetErrorCode(interp, "TK", "LOOKUP", "KEYCODE", value, NULL);
		return TCL_ERROR;
	    }
	    if (!(flags & KEY) || (event.general.xkey.type == MouseWheelEvent)) {
		badOpt = 1;
	    }
	    break;
	}
	case EVENT_MODE:
	    if ((number = TkFindStateNumObj(interp, optionPtr, notifyMode, valuePtr)) < 0) {
		return TCL_ERROR;







|







4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100

	    TkpSetKeycodeAndState(tkwin, keysym, &event.general);
	    if (event.general.xkey.keycode == 0) {
		Tcl_SetObjResult(interp, Tcl_ObjPrintf("no keycode for keysym \"%s\"", value));
		Tcl_SetErrorCode(interp, "TK", "LOOKUP", "KEYCODE", value, NULL);
		return TCL_ERROR;
	    }
	    if (!(flags & KEY)) {
		badOpt = 1;
	    }
	    break;
	}
	case EVENT_MODE:
	    if ((number = TkFindStateNumObj(interp, optionPtr, notifyMode, valuePtr)) < 0) {
		return TCL_ERROR;
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
		badOpt = 1;
	    }
	    break;
	case EVENT_ROOT:
	    if (!NameToWindow(interp, tkwin, valuePtr, &tkwin2)) {
		return TCL_ERROR;
	    }
	    if (flags & KEY_BUTTON_MOTION_CROSSING) {
		event.general.xkey.root = Tk_WindowId(tkwin2);
	    } else {
		badOpt = 1;
	    }
	    break;
	case EVENT_ROOTX:
	    if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number) != TCL_OK) {
		return TCL_ERROR;
	    }
	    if (flags & KEY_BUTTON_MOTION_CROSSING) {
		event.general.xkey.x_root = number;
	    } else {
		badOpt = 1;
	    }
	    break;
	case EVENT_ROOTY:
	    if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number) != TCL_OK) {
		return TCL_ERROR;
	    }
	    if (flags & KEY_BUTTON_MOTION_CROSSING) {
		event.general.xkey.y_root = number;
	    } else {
		badOpt = 1;
	    }
	    break;
	case EVENT_SEND: {
	    const char *value;







|









|









|







4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
		badOpt = 1;
	    }
	    break;
	case EVENT_ROOT:
	    if (!NameToWindow(interp, tkwin, valuePtr, &tkwin2)) {
		return TCL_ERROR;
	    }
	    if (flags & HAS_XKEY_HEAD) {
		event.general.xkey.root = Tk_WindowId(tkwin2);
	    } else {
		badOpt = 1;
	    }
	    break;
	case EVENT_ROOTX:
	    if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number) != TCL_OK) {
		return TCL_ERROR;
	    }
	    if (flags & HAS_XKEY_HEAD) {
		event.general.xkey.x_root = number;
	    } else {
		badOpt = 1;
	    }
	    break;
	case EVENT_ROOTY:
	    if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number) != TCL_OK) {
		return TCL_ERROR;
	    }
	    if (flags & HAS_XKEY_HEAD) {
		event.general.xkey.y_root = number;
	    } else {
		badOpt = 1;
	    }
	    break;
	case EVENT_SEND: {
	    const char *value;
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
	case EVENT_SERIAL:
	    if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) {
		return TCL_ERROR;
	    }
	    event.general.xany.serial = number;
	    break;
	case EVENT_STATE:
	    if (flags & KEY_BUTTON_MOTION_CROSSING) {
		if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) {
		    return TCL_ERROR;
		}
		if (flags & KEY_BUTTON_MOTION_VIRTUAL) {
		    event.general.xkey.state = number;
		} else {
		    event.general.xcrossing.state = number;
		}
	    } else if (flags & VISIBILITY) {
		if ((number = TkFindStateNumObj(interp, optionPtr, visNotify, valuePtr)) < 0) {
		    return TCL_ERROR;
		}
		event.general.xvisibility.state = number;
	    } else {
		badOpt = 1;
	    }
	    break;
	case EVENT_SUBWINDOW:
	    if (!NameToWindow(interp, tkwin, valuePtr, &tkwin2)) {
		return TCL_ERROR;
	    }
	    if (flags & KEY_BUTTON_MOTION_CROSSING) {
		event.general.xkey.subwindow = Tk_WindowId(tkwin2);
	    } else {
		badOpt = 1;
	    }
	    break;
	case EVENT_TIME: {
	    if (strcmp(Tcl_GetString(valuePtr), "current") == 0) {
		TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
		BindInfo *biPtr = mainPtr->mainPtr->bindInfo;
		number = dispPtr->lastEventTime + (CurrentTimeInMilliSecs() - biPtr->lastCurrentTime);
	    } else if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) {
		return TCL_ERROR;
	    }
	    if (flags & KEY_BUTTON_MOTION_CROSSING) {
		event.general.xkey.time = number;
	    } else if (flags & PROP) {
		event.general.xproperty.time = number;
	    } else {
		badOpt = 1;
	    }
	    break;







|



|

















|













|







4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
	case EVENT_SERIAL:
	    if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) {
		return TCL_ERROR;
	    }
	    event.general.xany.serial = number;
	    break;
	case EVENT_STATE:
	    if (flags & HAS_XKEY_HEAD) {
		if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) {
		    return TCL_ERROR;
		}
		if (flags & HAS_XKEY_HEAD_AND_STATE) {
		    event.general.xkey.state = number;
		} else {
		    event.general.xcrossing.state = number;
		}
	    } else if (flags & VISIBILITY) {
		if ((number = TkFindStateNumObj(interp, optionPtr, visNotify, valuePtr)) < 0) {
		    return TCL_ERROR;
		}
		event.general.xvisibility.state = number;
	    } else {
		badOpt = 1;
	    }
	    break;
	case EVENT_SUBWINDOW:
	    if (!NameToWindow(interp, tkwin, valuePtr, &tkwin2)) {
		return TCL_ERROR;
	    }
	    if (flags & HAS_XKEY_HEAD) {
		event.general.xkey.subwindow = Tk_WindowId(tkwin2);
	    } else {
		badOpt = 1;
	    }
	    break;
	case EVENT_TIME: {
	    if (strcmp(Tcl_GetString(valuePtr), "current") == 0) {
		TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
		BindInfo *biPtr = mainPtr->mainPtr->bindInfo;
		number = dispPtr->lastEventTime + (CurrentTimeInMilliSecs() - biPtr->lastCurrentTime);
	    } else if (Tcl_GetIntFromObj(interp, valuePtr, &number) != TCL_OK) {
		return TCL_ERROR;
	    }
	    if (flags & HAS_XKEY_HEAD) {
		event.general.xkey.time = number;
	    } else if (flags & PROP) {
		event.general.xproperty.time = number;
	    } else {
		badOpt = 1;
	    }
	    break;
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
		badOpt = 1;
	    }
	    break;
	case EVENT_X:
	    if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number) != TCL_OK) {
		return TCL_ERROR;
	    }
	    if (flags & KEY_BUTTON_MOTION_CROSSING) {
		event.general.xkey.x = number;

		/*
		 * Only modify rootx as well if it hasn't been changed.
		 */

		if (event.general.xkey.x_root == -1) {







|







4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
		badOpt = 1;
	    }
	    break;
	case EVENT_X:
	    if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number) != TCL_OK) {
		return TCL_ERROR;
	    }
	    if (flags & HAS_XKEY_HEAD) {
		event.general.xkey.x = number;

		/*
		 * Only modify rootx as well if it hasn't been changed.
		 */

		if (event.general.xkey.x_root == -1) {
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
		badOpt = 1;
	    }
	    break;
	case EVENT_Y:
	    if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number) != TCL_OK) {
		return TCL_ERROR;
	    }
	    if (flags & KEY_BUTTON_MOTION_CROSSING) {
		event.general.xkey.y = number;

		/*
		 * Only modify rooty as well if it hasn't been changed.
		 */

		if (event.general.xkey.y_root == -1) {







|







4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
		badOpt = 1;
	    }
	    break;
	case EVENT_Y:
	    if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr, &number) != TCL_OK) {
		return TCL_ERROR;
	    }
	    if (flags & HAS_XKEY_HEAD) {
		event.general.xkey.y = number;

		/*
		 * Only modify rooty as well if it hasn't been changed.
		 */

		if (event.general.xkey.y_root == -1) {

Changes to generic/tkCanvText.c.

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
     * text up to the selection, draw the selection, then draw the rest of the
     * regular text. Drawing the regular text and then the selected text over
     * it would causes problems with anti-aliased text because the two
     * anti-aliasing colors would blend together.
     */

    if ((selFirstChar >= 0) && (textPtr->selTextGC != textPtr->gc)) {

	TkDrawAngledTextLayout(display, drawable, textPtr->gc,
		textPtr->textLayout, drawableX, drawableY, textPtr->angle,
		0, selFirstChar);

	TkDrawAngledTextLayout(display, drawable, textPtr->selTextGC,
		textPtr->textLayout, drawableX, drawableY, textPtr->angle,
		selFirstChar, selLastChar + 1);

	TkDrawAngledTextLayout(display, drawable, textPtr->gc,
		textPtr->textLayout, drawableX, drawableY, textPtr->angle,
		selLastChar + 1, -1);

    } else {
	TkDrawAngledTextLayout(display, drawable, textPtr->gc,
		textPtr->textLayout, drawableX, drawableY, textPtr->angle,
		0, -1);
    }
    TkUnderlineAngledTextLayout(display, drawable, textPtr->gc,
	    textPtr->textLayout, drawableX, drawableY, textPtr->angle,
	    textPtr->underline);

    if (stipple != None) {
	XSetTSOrigin(display, textPtr->gc, 0, 0);







>
|
|
|
>



>
|
|
|
>



|







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
     * text up to the selection, draw the selection, then draw the rest of the
     * regular text. Drawing the regular text and then the selected text over
     * it would causes problems with anti-aliased text because the two
     * anti-aliasing colors would blend together.
     */

    if ((selFirstChar >= 0) && (textPtr->selTextGC != textPtr->gc)) {
	if (0 < selFirstChar) {
	    TkDrawAngledTextLayout(display, drawable, textPtr->gc,
		    textPtr->textLayout, drawableX, drawableY, textPtr->angle,
		    0, selFirstChar);
	}
	TkDrawAngledTextLayout(display, drawable, textPtr->selTextGC,
		textPtr->textLayout, drawableX, drawableY, textPtr->angle,
		selFirstChar, selLastChar + 1);
	if (selLastChar + 1 < textPtr->numChars) {
	    TkDrawAngledTextLayout(display, drawable, textPtr->gc,
		    textPtr->textLayout, drawableX, drawableY, textPtr->angle,
		    selLastChar + 1, textPtr->numChars);
	}
    } else {
	TkDrawAngledTextLayout(display, drawable, textPtr->gc,
		textPtr->textLayout, drawableX, drawableY, textPtr->angle,
		0, textPtr->numChars);
    }
    TkUnderlineAngledTextLayout(display, drawable, textPtr->gc,
	    textPtr->textLayout, drawableX, drawableY, textPtr->angle,
	    textPtr->underline);

    if (stipple != None) {
	XSetTSOrigin(display, textPtr->gc, 0, 0);

Changes to generic/tkFont.c.

2739
2740
2741
2742
2743
2744
2745

2746
2747
2748
2749
2750
2751
2752
2753
2754
	    end = Tcl_UtfAtIndex(chunkPtr->start, index);
	    if (xPtr != NULL) {
		Tk_MeasureChars(tkfont, chunkPtr->start,
			end - chunkPtr->start, -1, 0, &x);
		x += chunkPtr->x;
	    }
	    if (widthPtr != NULL) {

		Tk_MeasureChars(tkfont, end, Tcl_UtfNext(end) - end,
			-1, 0, &w);
	    }
	    goto check;
	}
	index -= chunkPtr->numChars;
	chunkPtr++;
    }
    if (index != 0) {







>
|
<







2739
2740
2741
2742
2743
2744
2745
2746
2747

2748
2749
2750
2751
2752
2753
2754
	    end = Tcl_UtfAtIndex(chunkPtr->start, index);
	    if (xPtr != NULL) {
		Tk_MeasureChars(tkfont, chunkPtr->start,
			end - chunkPtr->start, -1, 0, &x);
		x += chunkPtr->x;
	    }
	    if (widthPtr != NULL) {
		int ch;
		Tk_MeasureChars(tkfont, end, TkUtfToUniChar(end, &ch), -1, 0, &w);

	    }
	    goto check;
	}
	index -= chunkPtr->numChars;
	chunkPtr++;
    }
    if (index != 0) {

Changes to generic/tkInt.h.

1280
1281
1282
1283
1284
1285
1286

1287
1288
1289

1290
1291
1292
1293
1294
1295
1296
#if !defined(__cplusplus) && !defined(c_plusplus)
# define c_class class
#endif

#if TCL_UTF_MAX > 4
#   define TkUtfToUniChar Tcl_UtfToUniChar
#   define TkUniCharToUtf Tcl_UniCharToUtf

#else
    MODULE_SCOPE int TkUtfToUniChar(const char *, int *);
    MODULE_SCOPE int TkUniCharToUtf(int, char *);

#endif

/*
 * Unsupported commands.
 */

MODULE_SCOPE int	TkUnsupported1ObjCmd(ClientData clientData,







>



>







1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
#if !defined(__cplusplus) && !defined(c_plusplus)
# define c_class class
#endif

#if TCL_UTF_MAX > 4
#   define TkUtfToUniChar Tcl_UtfToUniChar
#   define TkUniCharToUtf Tcl_UniCharToUtf
#   define TkUtfPrev Tcl_UtfPrev
#else
    MODULE_SCOPE int TkUtfToUniChar(const char *, int *);
    MODULE_SCOPE int TkUniCharToUtf(int, char *);
    MODULE_SCOPE const char *TkUtfPrev(const char *, const char *);
#endif

/*
 * Unsupported commands.
 */

MODULE_SCOPE int	TkUnsupported1ObjCmd(ClientData clientData,

Changes to generic/tkSelect.c.

1396
1397
1398
1399
1400
1401
1402

1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
	 */

	if (cmdInfoPtr->interp != NULL) {
	    if (length <= maxBytes) {
		cmdInfoPtr->charOffset += Tcl_NumUtfChars(string, -1);
		cmdInfoPtr->buffer[0] = '\0';
	    } else {

		p = string;
		string += count;
		numChars = 0;
		while (p < string) {
		    p = Tcl_UtfNext(p);
		    numChars++;
		}
		cmdInfoPtr->charOffset += numChars;
		length = p - string;
		if (length > 0) {
		    strncpy(cmdInfoPtr->buffer, string, (size_t) length);
		}







>




|







1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
	 */

	if (cmdInfoPtr->interp != NULL) {
	    if (length <= maxBytes) {
		cmdInfoPtr->charOffset += Tcl_NumUtfChars(string, -1);
		cmdInfoPtr->buffer[0] = '\0';
	    } else {
		Tcl_UniChar ch = 0;
		p = string;
		string += count;
		numChars = 0;
		while (p < string) {
		    p += Tcl_UtfToUniChar(p, &ch);
		    numChars++;
		}
		cmdInfoPtr->charOffset += numChars;
		length = p - string;
		if (length > 0) {
		    strncpy(cmdInfoPtr->buffer, string, (size_t) length);
		}

Changes to generic/tkTextIndex.c.

432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
		 * Prevent UTF-8 character from being split up by ensuring
		 * that byteIndex falls on a character boundary. If the index
		 * falls in the middle of a UTF-8 character, it will be
		 * adjusted to the end of that UTF-8 character.
		 */

		start = segPtr->body.chars + (byteIndex - index);
		p = Tcl_UtfPrev(start, segPtr->body.chars);
		p += TkUtfToUniChar(p, &ch);
		indexPtr->byteIndex += p - start;
	    }
	    break;
	}
	index += segPtr->size;
    }







|







432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
		 * Prevent UTF-8 character from being split up by ensuring
		 * that byteIndex falls on a character boundary. If the index
		 * falls in the middle of a UTF-8 character, it will be
		 * adjusted to the end of that UTF-8 character.
		 */

		start = segPtr->body.chars + (byteIndex - index);
		p = TkUtfPrev(start, segPtr->body.chars);
		p += TkUtfToUniChar(p, &ch);
		indexPtr->byteIndex += p - start;
	    }
	    break;
	}
	index += segPtr->size;
    }
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
	    }
	}

	if (!elide) {
	    if (segPtr->typePtr == &tkTextCharType) {
		start = segPtr->body.chars;
		end = segPtr->body.chars + segSize;
		for (p = end; ; p = Tcl_UtfPrev(p, start)) {
		    if (charCount == 0) {
			dstPtr->byteIndex -= (end - p);
			goto backwardCharDone;
		    }
		    if (p == start) {
			break;
		    }







|







2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
	    }
	}

	if (!elide) {
	    if (segPtr->typePtr == &tkTextCharType) {
		start = segPtr->body.chars;
		end = segPtr->body.chars + segSize;
		for (p = end; ; p = TkUtfPrev(p, start)) {
		    if (charCount == 0) {
			dstPtr->byteIndex -= (end - p);
			goto backwardCharDone;
		    }
		    if (p == start) {
			break;
		    }
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
		int ch;
		TkUtfToUniChar(segPtr->body.chars + offset, &ch);
		if (!Tcl_UniCharIsWordChar(ch)) {
		    break;
		}
		if (offset > 0) {
		    chSize = (segPtr->body.chars + offset
			    - Tcl_UtfPrev(segPtr->body.chars + offset,
			    segPtr->body.chars));
		}
		firstChar = 0;
	    }
            if (offset == 0) {
                if (modifier == TKINDEX_DISPLAY) {
                    TkTextIndexBackChars(textPtr, indexPtr, 1, indexPtr,







|







2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
		int ch;
		TkUtfToUniChar(segPtr->body.chars + offset, &ch);
		if (!Tcl_UniCharIsWordChar(ch)) {
		    break;
		}
		if (offset > 0) {
		    chSize = (segPtr->body.chars + offset
			    - TkUtfPrev(segPtr->body.chars + offset,
			    segPtr->body.chars));
		}
		firstChar = 0;
	    }
            if (offset == 0) {
                if (modifier == TKINDEX_DISPLAY) {
                    TkTextIndexBackChars(textPtr, indexPtr, 1, indexPtr,

Changes to generic/tkUtil.c.

1260
1261
1262
1263
1264
1265
1266


1267



























1268
1269
1270
1271
1272
1273
1274
	/* Spit out a 4-byte UTF-8 character or 2 x 3-byte UTF-8 characters, depending on Tcl
	 * version and/or TCL_UTF_MAX build value */
	int len = Tcl_UniCharToUtf(0xD800 | ((ch - 0x10000) >> 10), buf);
	return len + Tcl_UniCharToUtf(0xDC00 | (ch & 0x7FF), buf + len);
    }
    return Tcl_UniCharToUtf(ch, buf);
}































#endif
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78







>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
	/* Spit out a 4-byte UTF-8 character or 2 x 3-byte UTF-8 characters, depending on Tcl
	 * version and/or TCL_UTF_MAX build value */
	int len = Tcl_UniCharToUtf(0xD800 | ((ch - 0x10000) >> 10), buf);
	return len + Tcl_UniCharToUtf(0xDC00 | (ch & 0x7FF), buf + len);
    }
    return Tcl_UniCharToUtf(ch, buf);
}
/*
 *---------------------------------------------------------------------------
 *
 * TkUtfPrev --
 *
 *	Almost the same as Tcl_UtfPrev.
 *	This function is capable of jumping over a upper/lower surrogate pair.
 *	So, might jump back up to 6 bytes.
 *
 * Results:
 *	pointer to the first byte of the current UTF-8 character. A surrogate
 *	pair is also handled as being a single entity.
 *
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------------
 */

const char *
TkUtfPrev(
    const char *src,	/* The UTF-8 string. */
    const char *start)		/* Start position of string */
{
    const char *p = Tcl_UtfPrev(src, start);
    const char *first = Tcl_UtfPrev(p, start);
    int ch;

    return (first + TkUtfToUniChar(first, &ch) >= src) ? first : p ;
}

#endif
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78

Changes to generic/ttk/ttkScroll.c.

100
101
102
103
104
105
106
107




108
109
110
111
112
113
114
115

116
117
118
119
120
121
122
    if (WidgetDestroyed(corePtr)) {
	Tcl_Release(corePtr);
	return TCL_ERROR;
    }
    Tcl_Release(corePtr);

    if (code != TCL_OK && !Tcl_InterpDeleted(interp)) {
	/* Disable the -scrollcommand, add to stack trace:




	 */
	ckfree(s->scrollCmd);
	s->scrollCmd = 0;

	Tcl_AddErrorInfo(interp, /* @@@ "horizontal" / "vertical" */
		"\n    (scrolling command executed by ");
	Tcl_AddErrorInfo(interp, Tk_PathName(h->corePtr->tkwin));
	Tcl_AddErrorInfo(interp, ")");

    }
    return code;
}

/* UpdateScrollbarBG --
 * 	Idle handler to update the scrollbar.
 */







|
>
>
>
>

<
<





>







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
    if (WidgetDestroyed(corePtr)) {
	Tcl_Release(corePtr);
	return TCL_ERROR;
    }
    Tcl_Release(corePtr);

    if (code != TCL_OK && !Tcl_InterpDeleted(interp)) {
	/* Add error to stack trace.
         * Also set the SCROLL_UPDATE_REQUIRED flag so that a later call to
         * TtkScrolled has an effect. Indeed, the error in the -scrollcommand
         * callback may later be gone, for instance the callback proc got
         * defined in the meantime.
	 */



	Tcl_AddErrorInfo(interp, /* @@@ "horizontal" / "vertical" */
		"\n    (scrolling command executed by ");
	Tcl_AddErrorInfo(interp, Tk_PathName(h->corePtr->tkwin));
	Tcl_AddErrorInfo(interp, ")");
        TtkScrollbarUpdateRequired(h);
    }
    return code;
}

/* UpdateScrollbarBG --
 * 	Idle handler to update the scrollbar.
 */

Changes to generic/ttk/ttkTreeview.c.

2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
	if (!(parent->state & TTK_STATE_OPEN)) {
	    parent->openObj = unshareObj(parent->openObj);
	    Tcl_SetBooleanObj(parent->openObj, 1);
	    parent->state |= TTK_STATE_OPEN;
	    TtkRedisplayWidget(&tv->core);
	}
    }
    tv->tree.yscroll.total = CountRows(tv->tree.root) - 1;

    /* Make sure item is visible:
     */
    rowNumber = RowNumber(tv, item);
    if (rowNumber < tv->tree.yscroll.first) {
	TtkScrollTo(tv->tree.yscrollHandle, rowNumber, 1);
    } else if (rowNumber >= tv->tree.yscroll.last) {







<







2838
2839
2840
2841
2842
2843
2844

2845
2846
2847
2848
2849
2850
2851
	if (!(parent->state & TTK_STATE_OPEN)) {
	    parent->openObj = unshareObj(parent->openObj);
	    Tcl_SetBooleanObj(parent->openObj, 1);
	    parent->state |= TTK_STATE_OPEN;
	    TtkRedisplayWidget(&tv->core);
	}
    }


    /* Make sure item is visible:
     */
    rowNumber = RowNumber(tv, item);
    if (rowNumber < tv->tree.yscroll.first) {
	TtkScrollTo(tv->tree.yscrollHandle, rowNumber, 1);
    } else if (rowNumber >= tv->tree.yscroll.last) {

Changes to library/demos/entry1.tcl.

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
set w .entry1
catch {destroy $w}
toplevel $w
wm title $w "Entry Demonstration (no scrollbars)"
wm iconname $w "entry1"
positionWindow $w

label $w.msg -font $font -wraplength 5i -justify left -text "Three different entries are displayed below.  You can add characters by pointing, clicking and typing.  The normal Motif editing characters are supported, along with many Emacs bindings.  For example, Backspace and Control-h delete the character to the left of the insertion cursor and Delete and Control-d delete the chararacter to the right of the insertion cursor.  For entries that are too large to fit in the window all at once, you can scan through the entries by dragging with mouse button2 pressed."
pack $w.msg -side top

## See Code / Dismiss buttons
set btns [addSeeDismiss $w.buttons $w]
pack $btns -side bottom -fill x

entry $w.e1







|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
set w .entry1
catch {destroy $w}
toplevel $w
wm title $w "Entry Demonstration (no scrollbars)"
wm iconname $w "entry1"
positionWindow $w

label $w.msg -font $font -wraplength 5i -justify left -text "Three different entries are displayed below.  You can add characters by pointing, clicking and typing.  The normal Motif editing characters are supported, along with many Emacs bindings.  For example, Backspace and Control-h delete the character to the left of the insertion cursor and Delete and Control-d delete the chararacter to the right of the insertion cursor.  For entries that are too large to fit in the window all at once, you can scan through the entries by dragging with mouse the middle mouse button pressed."
pack $w.msg -side top

## See Code / Dismiss buttons
set btns [addSeeDismiss $w.buttons $w]
pack $btns -side bottom -fill x

entry $w.e1

Changes to library/demos/entry2.tcl.

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
set w .entry2
catch {destroy $w}
toplevel $w
wm title $w "Entry Demonstration (with scrollbars)"
wm iconname $w "entry2"
positionWindow $w

label $w.msg -font $font -wraplength 5i -justify left -text "Three different entries are displayed below, with a scrollbar for each entry.  You can add characters by pointing, clicking and typing.  The normal Motif editing characters are supported, along with many Emacs bindings.  For example, Backspace and Control-h delete the character to the left of the insertion cursor and Delete and Control-d delete the chararacter to the right of the insertion cursor.  For entries that are too large to fit in the window all at once, you can scan through the entries with the scrollbars, or by dragging with mouse button2 pressed."
pack $w.msg -side top

## See Code / Dismiss buttons
set btns [addSeeDismiss $w.buttons $w]
pack $btns -side bottom -fill x

frame $w.frame -borderwidth 10







|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
set w .entry2
catch {destroy $w}
toplevel $w
wm title $w "Entry Demonstration (with scrollbars)"
wm iconname $w "entry2"
positionWindow $w

label $w.msg -font $font -wraplength 5i -justify left -text "Three different entries are displayed below, with a scrollbar for each entry.  You can add characters by pointing, clicking and typing.  The normal Motif editing characters are supported, along with many Emacs bindings.  For example, Backspace and Control-h delete the character to the left of the insertion cursor and Delete and Control-d delete the chararacter to the right of the insertion cursor.  For entries that are too large to fit in the window all at once, you can scan through the entries with the scrollbars, or by dragging with the middle mouse button pressed."
pack $w.msg -side top

## See Code / Dismiss buttons
set btns [addSeeDismiss $w.buttons $w]
pack $btns -side bottom -fill x

frame $w.frame -borderwidth 10

Changes to library/demos/text.tcl.

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
$w.text insert 0.0 \
{This window is a text widget.  It displays one or more lines of text
and allows you to edit the text.  Here is a summary of the things you
can do to a text widget:

1. Scrolling. Use the scrollbar to adjust the view in the text window.

2. Scanning. Press mouse button 2 in the text window and drag up or down.
This will drag the text at high speed to allow you to scan its contents.


3. Insert text. Press mouse button 1 to set the insertion cursor, then
type text.  What you type will be added to the widget.

4. Select. Press mouse button 1 and drag to select a range of characters.
Once you've released the button, you can adjust the selection by pressing
button 1 with the shift key down.  This will reset the end of the
selection nearest the mouse cursor and you can drag that end of the
selection by dragging the mouse before releasing the mouse button.
You can double-click to select whole words or triple-click to select
whole lines.

5. Delete and replace. To delete text, select the characters you'd like
to delete and type Backspace or Delete.  Alternatively, you can type new
text, in which case it will replace the selected text.

6. Copy the selection. To copy the selection into this window, select
what you want to copy (either here or in another application), then
click button 2 to copy the selection to the point of the mouse cursor.


7. Edit.  Text widgets support the standard Motif editing characters
plus many Emacs editing characters.  Backspace and Control-h erase the
character to the left of the insertion cursor.  Delete and Control-d
erase the character to the right of the insertion cursor.  Meta-backspace
deletes the word to the left of the insertion cursor, and Meta-d deletes
the word to the right of the insertion cursor.  Control-k deletes from







|
|
>


















|
>







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
$w.text insert 0.0 \
{This window is a text widget.  It displays one or more lines of text
and allows you to edit the text.  Here is a summary of the things you
can do to a text widget:

1. Scrolling. Use the scrollbar to adjust the view in the text window.

2. Scanning. Press the middle mouse button in the text window and drag up
or down. This will drag the text at high speed to allow you to scan its
contents.

3. Insert text. Press mouse button 1 to set the insertion cursor, then
type text.  What you type will be added to the widget.

4. Select. Press mouse button 1 and drag to select a range of characters.
Once you've released the button, you can adjust the selection by pressing
button 1 with the shift key down.  This will reset the end of the
selection nearest the mouse cursor and you can drag that end of the
selection by dragging the mouse before releasing the mouse button.
You can double-click to select whole words or triple-click to select
whole lines.

5. Delete and replace. To delete text, select the characters you'd like
to delete and type Backspace or Delete.  Alternatively, you can type new
text, in which case it will replace the selected text.

6. Copy the selection. To copy the selection into this window, select
what you want to copy (either here or in another application), then
click the middle mouse button to copy the selection to the point of the
mouse cursor.

7. Edit.  Text widgets support the standard Motif editing characters
plus many Emacs editing characters.  Backspace and Control-h erase the
character to the left of the insertion cursor.  Delete and Control-d
erase the character to the right of the insertion cursor.  Meta-backspace
deletes the word to the left of the insertion cursor, and Meta-d deletes
the word to the right of the insertion cursor.  Control-k deletes from

Changes to library/demos/widget.

79
80
81
82
83
84
85
86
87
88
89
90
91








92
93
94
95
96
97
98
    AAAAAAAAAAAAAAAAACH5BAEAAAoALAAAAAAQABAAAARGUMlJKwU4AztB+ODGeUiJ
    fGLlgeEYmGWQXmx7aXgmAUTv/74N4EAsGhOJg1DAbDqbwoJ0Sp0KB9isNis0eL/g
    ryhH5pgnEQA7
}

# Note that this is run through the message catalog! This is because this is
# actually an image of a word.
image create photo ::img::new -format GIF -data [mc {
    R0lGODlhHgAOALMPALMAANyIiOu7u8dEROaqqvru7sxVVeGZmbgREfXd3b0iItZ3
    d8IzM9FmZvDMzP///yH5BAEAAA8ALAAAAAAeAA4AAASa8MlJq7046827WVOCHEkw
    nANhUgJlEBIABJIwL3K+4IcUALCHjfbItYZDSgJgkBiYPmBMAUAkkLPKs/BAyLgM
    wAQwOAAY2ByCaw4QAFQSoDEePJ6DmU1xInYZTw5nOEFFdgVUelkVDTIMd3AKFGQ1
    MgI2AwEmQW8APZ0gdRONAks5nhIFVVxdAAkUAS2pAVwFl7ITB4UqHb0XEQA7








}]

#----------------------------------------------------------------
# The code below creates the main window, consisting of a menu bar and a text
# widget that explains how to use the program, plus lists all of the demos as
# hypertext items.
#----------------------------------------------------------------







|
|
|
|
|
|
>
>
>
>
>
>
>
>







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
    AAAAAAAAAAAAAAAAACH5BAEAAAoALAAAAAAQABAAAARGUMlJKwU4AztB+ODGeUiJ
    fGLlgeEYmGWQXmx7aXgmAUTv/74N4EAsGhOJg1DAbDqbwoJ0Sp0KB9isNis0eL/g
    ryhH5pgnEQA7
}

# Note that this is run through the message catalog! This is because this is
# actually an image of a word.
image create photo ::img::new -format PNG -data [mc {
    iVBORw0KGgoAAAANSUhEUgAAAB4AAAAOCAYAAAA45qw5AAACMElEQVR4AeVTAwxd
    QRCc2tZHGtQ2w9q2bdsOa9u2bUW1bdt2Z372JZe6DapJLqtb3h7+T8yKi5j4CsYD
    EUQXxETclT7kWOlH2VV+tFkdQHPSwksSISF+BauCqL0qgOcMWgGfgEkaMsHxqUBk
    3plE/sOnh/qDPAPJH/CKFBivGHWzFwBRnHhlqbu1Mh6CoFNnC/JshQ9p4YC2lrKt
    DCAV+THiVejyhMjAbrNSrroiEfKR9g7ZfCgOog8QfnUQV62wAk68ndQ9ZbyoWO1H
    Y6eDY1LCQL6a9ApOp9Hi1T0+gQq2JKMlky/oTKQliKWxEZvyG575kpW4pl1aZnQK
    CLOVt45Lkp8uXp2SL8KO6uitNTZLdpK6s+I/eZbhpmsmWeOGOVQNKYLITzpKPAO3
    tY7LSNZ7ccSLxX9y3uuOxRkg3dKESMoCHvL+GRVCutXsB3guLgDCeXOv4iWWkvwG
    BaS+PmlpK6SI9ApI2oC2UtrwZQEkhkH+NtolVlQXJl1I+QltuU3XEc721bIRFpa8
    IA5iqTo6vNNWmkNBLQbPeXwF2g17Q94nTQAfY3YzeY+WSu8MDzQ2kpELUhSGJUHE
    0zeR3rY1L+Xl5G/re+jbiK6KhThwwInsts1fbMUUcpZszKeVtggZEiGdZDe5AtHh
    7vL4CGiRvvKPS8FAvq9Nr4ZkFadR2y6kggu1z4vlyIbBp6BugQ8JLEg4bTkD9eMZ
    QZ8hpJ3VvTtuvbWrY/ElvP/9R+Aj3603+iE3fkEAAAAASUVORK5CYII=
}]

#----------------------------------------------------------------
# The code below creates the main window, consisting of a menu bar and a text
# widget that explains how to use the program, plus lists all of the demos as
# hypertext items.
#----------------------------------------------------------------
182
183
184
185
186
187
188




189
190
191
192
193
194
195
	-underline 1
    .t tag configure hot -background black -foreground white
} else {
    .t tag configure demo -lmargin1 1c -lmargin2 1c \
	-foreground blue -underline 1
    .t tag configure visited -lmargin1 1c -lmargin2 1c \
	-foreground #303080 -underline 1




    .t tag configure hot -foreground red -underline 1
}
.t tag bind demo <ButtonRelease-1> {
    invoke [.t index {@%x,%y}]
}
set lastLine ""
.t tag bind demo <Enter> {







>
>
>
>







190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
	-underline 1
    .t tag configure hot -background black -foreground white
} else {
    .t tag configure demo -lmargin1 1c -lmargin2 1c \
	-foreground blue -underline 1
    .t tag configure visited -lmargin1 1c -lmargin2 1c \
	-foreground #303080 -underline 1
    if {[tk windowingsystem] eq "aqua"} {
	.t tag configure demo -foreground systemLinkColor
	.t tag configure visited -foreground purple
    }
    .t tag configure hot -foreground red -underline 1
}
.t tag bind demo <ButtonRelease-1> {
    invoke [.t index {@%x,%y}]
}
set lastLine ""
.t tag bind demo <Enter> {

Changes to library/entry.tcl.

289
290
291
292
293
294
295

296
297
298
299
300
301
302
303












304
305
306
307
308
309
310
}
bind Entry <<TkAccentBackspace>> {
    tk::EntryBackspace %W
}

# A few additional bindings of my own.


bind Entry <2> {
    if {!$tk_strictMotif} {
	::tk::EntryScanMark %W %x
    }
}
bind Entry <B2-Motion> {
    if {!$tk_strictMotif} {
	::tk::EntryScanDrag %W %x












    }
}

# ::tk::EntryClosestGap --
# Given x and y coordinates, this procedure finds the closest boundary
# between characters to the given coordinates and returns the index
# of the character just after the boundary.







>
|
|
|
|
|
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>







289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
}
bind Entry <<TkAccentBackspace>> {
    tk::EntryBackspace %W
}

# A few additional bindings of my own.

if {[tk windowingsystem] ne "aqua"} {
    bind Entry <2> {
        if {!$tk_strictMotif} {
        ::tk::EntryScanMark %W %x
        }
    }
    bind Entry <B2-Motion> {
        if {!$tk_strictMotif} {
        ::tk::EntryScanDrag %W %x
        }
    }
} else {
    bind Entry <3> {
        if {!$tk_strictMotif} {
        ::tk::EntryScanMark %W %x
        }
    }
    bind Entry <B3-Motion> {
        if {!$tk_strictMotif} {
        ::tk::EntryScanDrag %W %x
        }
    }
}

# ::tk::EntryClosestGap --
# Given x and y coordinates, this procedure finds the closest boundary
# between characters to the given coordinates and returns the index
# of the character just after the boundary.

Changes to library/spinbox.tcl.

276
277
278
279
280
281
282

283
284
285
286
287
288
289
290












291
292
293
294
295
296
297
    if {!$tk_strictMotif} {
	%W delete [::tk::EntryPreviousWord %W insert] insert
    }
}

# A few additional bindings of my own.


bind Spinbox <2> {
    if {!$tk_strictMotif} {
	::tk::EntryScanMark %W %x
    }
}
bind Spinbox <B2-Motion> {
    if {!$tk_strictMotif} {
	::tk::EntryScanDrag %W %x












    }
}

# ::tk::spinbox::Invoke --
# Invoke an element of the spinbox
#
# Arguments:







>
|
|
|
|
|
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>







276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
    if {!$tk_strictMotif} {
	%W delete [::tk::EntryPreviousWord %W insert] insert
    }
}

# A few additional bindings of my own.

if {[tk windowingsystem] ne "aqua"} {
    bind Spinbox <2> {
        if {!$tk_strictMotif} {
        ::tk::EntryScanMark %W %x
        }
    }
    bind Spinbox <B2-Motion> {
        if {!$tk_strictMotif} {
        ::tk::EntryScanDrag %W %x
        }
    }
} else {
    bind Spinbox <3> {
        if {!$tk_strictMotif} {
        ::tk::EntryScanMark %W %x
        }
    }
    bind Spinbox <B3-Motion> {
        if {!$tk_strictMotif} {
        ::tk::EntryScanDrag %W %x
        }
    }
}

# ::tk::spinbox::Invoke --
# Invoke an element of the spinbox
#
# Arguments:

Changes to library/text.tcl.

425
426
427
428
429
430
431

432
433
434
435
436
437
438
439












440
441
442
443
444
445
446

bind Text <Control-h> {
    if {!$tk_strictMotif && [%W compare insert != 1.0]} {
	%W delete insert-1c
	%W see insert
    }
}

bind Text <2> {
    if {!$tk_strictMotif} {
	tk::TextScanMark %W %x %y
    }
}
bind Text <B2-Motion> {
    if {!$tk_strictMotif} {
	tk::TextScanDrag %W %x %y












    }
}
set ::tk::Priv(prevPos) {}

# The MouseWheel will typically only fire on Windows and MacOS X.
# However, someone could use the "event generate" command to produce one
# on other platforms.  We must be careful not to round -ve values of %D







>
|
|
|
|
|
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>







425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459

bind Text <Control-h> {
    if {!$tk_strictMotif && [%W compare insert != 1.0]} {
	%W delete insert-1c
	%W see insert
    }
}
if {[tk windowingsystem] ne "aqua"} {
    bind Text <2> {
        if {!$tk_strictMotif} {
        tk::TextScanMark %W %x %y
        }
    }
    bind Text <B2-Motion> {
        if {!$tk_strictMotif} {
        tk::TextScanDrag %W %x %y
        }
    }
} else {
    bind Text <3> {
        if {!$tk_strictMotif} {
        tk::TextScanMark %W %x %y
        }
    }
    bind Text <B3-Motion> {
        if {!$tk_strictMotif} {
        tk::TextScanDrag %W %x %y
        }
    }
}
set ::tk::Priv(prevPos) {}

# The MouseWheel will typically only fire on Windows and MacOS X.
# However, someone could use the "event generate" command to produce one
# on other platforms.  We must be careful not to round -ve values of %D

Changes to library/tk.tcl.

458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
	event add <<PasteSelection>>	<ButtonRelease-3>
	event add <<Clear>>		<Clear>
	event add <<ContextMenu>>	<Button-2>

	# Official bindings
	# See http://support.apple.com/kb/HT1343
	event add <<SelectAll>>		<Command-Key-a>
	#Attach function keys not otherwise assigned to this event so they no-op - workaround for bug 0e6930dfe7
	event add <<SelectNone>>	<Option-Command-Key-a> <Key-F5> <Key-F1> <Key-F5> <Key-F6> <Key-F7> <Key-F8> <Key-F9> <Key-F10> <Key-F11> <Key-F12>
	event add <<Undo>>		<Command-Key-z> <Command-Lock-Key-Z>
	event add <<Redo>>		<Shift-Command-Key-z> <Shift-Command-Lock-Key-z>
	event add <<NextChar>>		<Right> <Control-Key-f> <Control-Lock-Key-F>
	event add <<SelectNextChar>>	<Shift-Right> <Shift-Control-Key-F> <Shift-Control-Lock-Key-F>
	event add <<PrevChar>>		<Left> <Control-Key-b> <Control-Lock-Key-B>
	event add <<SelectPrevChar>>	<Shift-Left> <Shift-Control-Key-B> <Shift-Control-Lock-Key-B>
	event add <<NextWord>>		<Option-Right>







<
<







458
459
460
461
462
463
464


465
466
467
468
469
470
471
	event add <<PasteSelection>>	<ButtonRelease-3>
	event add <<Clear>>		<Clear>
	event add <<ContextMenu>>	<Button-2>

	# Official bindings
	# See http://support.apple.com/kb/HT1343
	event add <<SelectAll>>		<Command-Key-a>


	event add <<Undo>>		<Command-Key-z> <Command-Lock-Key-Z>
	event add <<Redo>>		<Shift-Command-Key-z> <Shift-Command-Lock-Key-z>
	event add <<NextChar>>		<Right> <Control-Key-f> <Control-Lock-Key-F>
	event add <<SelectNextChar>>	<Shift-Right> <Shift-Control-Key-F> <Shift-Control-Lock-Key-F>
	event add <<PrevChar>>		<Left> <Control-Key-b> <Control-Lock-Key-B>
	event add <<SelectPrevChar>>	<Shift-Left> <Shift-Control-Key-B> <Shift-Control-Lock-Key-B>
	event add <<NextWord>>		<Option-Right>

Changes to library/ttk/entry.tcl.

78
79
80
81
82
83
84
85
86

87
88

89
90
91





92
93
94
95
96
97
98
bind TEntry <B1-Enter>		{ ttk::entry::DragIn %W }
bind TEntry <ButtonRelease-1>	{ ttk::entry::Release %W }

bind TEntry <<ToggleSelection>> {
    %W instate {!readonly !disabled} { %W icursor @%x ; focus %W }
}

## Button2 bindings:
#	Used for scanning and primary transfer.

#	Note: ButtonRelease-2 is mapped to <<PasteSelection>> in tk.tcl.
#

bind TEntry <ButtonPress-2> 		{ ttk::entry::ScanMark %W %x }
bind TEntry <B2-Motion> 		{ ttk::entry::ScanDrag %W %x }
bind TEntry <ButtonRelease-2>		{ ttk::entry::ScanRelease %W %x }





bind TEntry <<PasteSelection>>		{ ttk::entry::ScanRelease %W %x }

## Keyboard navigation bindings:
#
bind TEntry <<PrevChar>>		{ ttk::entry::Move %W prevchar }
bind TEntry <<NextChar>> 		{ ttk::entry::Move %W nextchar }
bind TEntry <<PrevWord>>		{ ttk::entry::Move %W prevword }







|

>
|

>
|
|
|
>
>
>
>
>







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
bind TEntry <B1-Enter>		{ ttk::entry::DragIn %W }
bind TEntry <ButtonRelease-1>	{ ttk::entry::Release %W }

bind TEntry <<ToggleSelection>> {
    %W instate {!readonly !disabled} { %W icursor @%x ; focus %W }
}

## Button2 (Button3 on Aqua) bindings:
#	Used for scanning and primary transfer.
#	Note: ButtonRelease-2 (ButtonRelease-3 on Aqua)
#	is mapped to <<PasteSelection>> in tk.tcl.
#
if {[tk windowingsystem] ne "aqua"} {
    bind TEntry <ButtonPress-2> 		{ ttk::entry::ScanMark %W %x }
    bind TEntry <B2-Motion> 		{ ttk::entry::ScanDrag %W %x }
    bind TEntry <ButtonRelease-2>		{ ttk::entry::ScanRelease %W %x }
} else {
    bind TEntry <ButtonPress-3> 		{ ttk::entry::ScanMark %W %x }
    bind TEntry <B3-Motion> 		{ ttk::entry::ScanDrag %W %x }
    bind TEntry <ButtonRelease-3>		{ ttk::entry::ScanRelease %W %x }
}
bind TEntry <<PasteSelection>>		{ ttk::entry::ScanRelease %W %x }

## Keyboard navigation bindings:
#
bind TEntry <<PrevChar>>		{ ttk::entry::Move %W prevchar }
bind TEntry <<NextChar>> 		{ ttk::entry::Move %W nextchar }
bind TEntry <<PrevWord>>		{ ttk::entry::Move %W prevword }

Changes to library/ttk/treeview.tcl.

261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
#
proc ttk::treeview::SelectOp {w item op} {
    select.$op.[$w cget -selectmode] $w $item
}

## -selectmode none:
#
proc ttk::treeview::select.choose.none {w item} { $w focus $item }
proc ttk::treeview::select.toggle.none {w item} { $w focus $item }
proc ttk::treeview::select.extend.none {w item} { $w focus $item }

## -selectmode browse:
#
proc ttk::treeview::select.choose.browse {w item} { BrowseTo $w $item }
proc ttk::treeview::select.toggle.browse {w item} { BrowseTo $w $item }
proc ttk::treeview::select.extend.browse {w item} { BrowseTo $w $item }








|
|
|







261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
#
proc ttk::treeview::SelectOp {w item op} {
    select.$op.[$w cget -selectmode] $w $item
}

## -selectmode none:
#
proc ttk::treeview::select.choose.none {w item} { $w focus $item; $w see $item }
proc ttk::treeview::select.toggle.none {w item} { $w focus $item; $w see $item }
proc ttk::treeview::select.extend.none {w item} { $w focus $item; $w see $item }

## -selectmode browse:
#
proc ttk::treeview::select.choose.browse {w item} { BrowseTo $w $item }
proc ttk::treeview::select.toggle.browse {w item} { BrowseTo $w $item }
proc ttk::treeview::select.extend.browse {w item} { BrowseTo $w $item }

Changes to macosx/README.

271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
appearance.  Part of the implementation of the Dark Mode was to make
some of the named NSColors have dynamic values.  Apple calls these
"semantic colors" because the name does not specify a specific color,
but rather refers to the context in which the color should be used.
Tk now provides the following semantic colors as system colors:
systemTextColor, systemTextBackgroundColor, systemSelectedTextColor,
systemSelectedTextBackgroundColor, systemControlTextColor,
systemDisabledControlTextColor, systemLabelColor, and
systemControlAccentColor.  All of these except the last two were
present in OSX 10.0 (and those two are simulated in systems where they
do not exist).  The change in 10.14 was that the RGB color value of
these colors became dynamic, meaning that the color value can change
when the application appearance changes.  In particular, when a user
selects Dark Mode in the system preferences these colors change
appearance.  For example systemTextColor is dark in Aqua and light in
DarkAqua.  One additional color, systemSelectedTabTextColor, does not
exist in macOS but is used by Tk to match the different colors used







|
|
|







271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
appearance.  Part of the implementation of the Dark Mode was to make
some of the named NSColors have dynamic values.  Apple calls these
"semantic colors" because the name does not specify a specific color,
but rather refers to the context in which the color should be used.
Tk now provides the following semantic colors as system colors:
systemTextColor, systemTextBackgroundColor, systemSelectedTextColor,
systemSelectedTextBackgroundColor, systemControlTextColor,
systemDisabledControlTextColor, systemLabelColor, systemLinkColor, and
systemControlAccentColor.  All of these except the last three were
present in OSX 10.0 (and those three are simulated in systems where they
do not exist).  The change in 10.14 was that the RGB color value of
these colors became dynamic, meaning that the color value can change
when the application appearance changes.  In particular, when a user
selects Dark Mode in the system preferences these colors change
appearance.  For example systemTextColor is dark in Aqua and light in
DarkAqua.  One additional color, systemSelectedTabTextColor, does not
exist in macOS but is used by Tk to match the different colors used

Changes to macosx/tkMacOSXClipboard.c.

31
32
33
34
35
36
37


38
39
40
41
42
43
44
45
	    [type isEqualToString:NSStringPboardType]) {
	for (TkClipboardTarget *targetPtr = dispPtr->clipTargetPtr; targetPtr;
		targetPtr = targetPtr->nextPtr) {
	    if (targetPtr->type == XA_STRING ||
		    targetPtr->type == dispPtr->utf8Atom) {
		for (TkClipboardBuffer *cbPtr = targetPtr->firstBufferPtr;
			cbPtr; cbPtr = cbPtr->nextPtr) {


		    NSString *s = TkUtfToNSString(cbPtr->buffer, cbPtr->length);
		    [string appendString:s];
		    [s release];
		}
		break;
	    }
	}
    }







>
>
|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
	    [type isEqualToString:NSStringPboardType]) {
	for (TkClipboardTarget *targetPtr = dispPtr->clipTargetPtr; targetPtr;
		targetPtr = targetPtr->nextPtr) {
	    if (targetPtr->type == XA_STRING ||
		    targetPtr->type == dispPtr->utf8Atom) {
		for (TkClipboardBuffer *cbPtr = targetPtr->firstBufferPtr;
			cbPtr; cbPtr = cbPtr->nextPtr) {
		    NSString *s = [[TKNSString alloc]
				      initWithTclUtfBytes:cbPtr->buffer
						   length:cbPtr->length];
		    [string appendString:s];
		    [s release];
		}
		break;
	    }
	}
    }

Changes to macosx/tkMacOSXColor.c.

209
210
211
212
213
214
215

216
217
218
219
220
221
222
223
224
225
226
    { "DisabledControlTextColor",	    semantic, 4 },						    /* 178 */
    { "SelectedTabTextColor",		    semantic, 5 },						    /* 179 */
    { "TextBackgroundColor",		    semantic, 6 },						    /* 180 */
    { "SelectedTextBackgroundColor",	    semantic, 7 },						    /* 181 */
    { "ControlAccentColor",		    semantic, 8 },						    /* 182 */
    /* Apple's SecondaryLabelColor is the same as their LabelColor so we roll our own. */
    { "SecondaryLabelColor",		    ttkBackground, 14 },					    /* 183 */

    { NULL,				    0, 0 }
};
#define FIRST_SEMANTIC_COLOR 166
#define MAX_PIXELCODE 183

/*
 *----------------------------------------------------------------------
 *
 * GetEntryFromPixelCode --
 *
 *	Extract a SystemColorMapEntry from the table.







>



|







209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
    { "DisabledControlTextColor",	    semantic, 4 },						    /* 178 */
    { "SelectedTabTextColor",		    semantic, 5 },						    /* 179 */
    { "TextBackgroundColor",		    semantic, 6 },						    /* 180 */
    { "SelectedTextBackgroundColor",	    semantic, 7 },						    /* 181 */
    { "ControlAccentColor",		    semantic, 8 },						    /* 182 */
    /* Apple's SecondaryLabelColor is the same as their LabelColor so we roll our own. */
    { "SecondaryLabelColor",		    ttkBackground, 14 },					    /* 183 */
    { "LinkColor",			    semantic, 9 },						    /* 184 */
    { NULL,				    0, 0 }
};
#define FIRST_SEMANTIC_COLOR 166
#define MAX_PIXELCODE 184

/*
 *----------------------------------------------------------------------
 *
 * GetEntryFromPixelCode --
 *
 *	Extract a SystemColorMapEntry from the table.
365
366
367
368
369
370
371
372
373

374
375
376

377
378
379
380
381









382
383
384
385
386
387
388
	    color = [[NSColor textBackgroundColor] colorUsingColorSpace:sRGB];
	    break;
	case 7:
	    color = [[NSColor selectedTextBackgroundColor]
			colorUsingColorSpace:sRGB];
	    break;
	case 8:
	    if ([NSApp macMinorVersion] >= 14) {
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400

		color = [[NSColor controlAccentColor]
			    colorUsingColorSpace:sRGB];
#endif

	    } else {
		color = [[NSColor
			    colorForControlTint:[NSColor currentControlTint]]
			        colorUsingColorSpace: sRGB];
	    }









	    break;
	default:
	    if ([NSApp macMinorVersion] >= 10) {
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
		color = [[NSColor labelColor] colorUsingColorSpace:sRGB];
#endif
	    } else {







<

>
|
|

>





>
>
>
>
>
>
>
>
>







366
367
368
369
370
371
372

373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
	    color = [[NSColor textBackgroundColor] colorUsingColorSpace:sRGB];
	    break;
	case 7:
	    color = [[NSColor selectedTextBackgroundColor]
			colorUsingColorSpace:sRGB];
	    break;
	case 8:

#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
	    if (@available(macOS 14, *)) {
#else
	    if (false) {
#endif
		color = [[NSColor controlAccentColor] colorUsingColorSpace:sRGB];
	    } else {
		color = [[NSColor
			    colorForControlTint:[NSColor currentControlTint]]
			        colorUsingColorSpace: sRGB];
	    }
	    break;
	case 9:
	    if ([NSApp macMinorVersion] >= 10) {
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
		color = [[NSColor linkColor] colorUsingColorSpace:sRGB];
#endif
	    } else {
		color = [[NSColor blueColor] colorUsingColorSpace:sRGB];
	    }
	    break;
	default:
	    if ([NSApp macMinorVersion] >= 10) {
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
		color = [[NSColor labelColor] colorUsingColorSpace:sRGB];
#endif
	    } else {

Changes to macosx/tkMacOSXDialog.c.

206
207
208
209
210
211
212

213
214
215
216
217
218
219
220

- (BOOL)panel:(id)sender validateURL:(NSURL *)url error:(NSError **)outError {
    *outError = nil;
    return YES;
}

- (void) tkFilePanelDidEnd: (NSSavePanel *) panel

	returnCode: (NSInteger) returnCode contextInfo: (void *) contextInfo
{
    FilePanelCallbackInfo *callbackInfo = contextInfo;

    if (returnCode == modalOK) {
	Tcl_Obj *resultObj;

	if (callbackInfo->multiple) {







>
|







206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221

- (BOOL)panel:(id)sender validateURL:(NSURL *)url error:(NSError **)outError {
    *outError = nil;
    return YES;
}

- (void) tkFilePanelDidEnd: (NSSavePanel *) panel
		returnCode: (NSModalResponse) returnCode
	       contextInfo: (void *) contextInfo
{
    FilePanelCallbackInfo *callbackInfo = contextInfo;

    if (returnCode == modalOK) {
	Tcl_Obj *resultObj;

	if (callbackInfo->multiple) {
339
340
341
342
343
344
345
346
347
348
349
350
351
352

353
354
355
356
357
358
359
360
361
static NSInteger showOpenSavePanel(
    NSSavePanel *panel,
    NSWindow *parent,
    FilePanelCallbackInfo *callbackInfo)
{
    NSInteger modalReturnCode;

    if (parent && ![parent attachedSheet] && [NSApp macMinorVersion] < 15) {
	[panel beginSheetModalForWindow:parent
	       completionHandler:^(NSInteger returnCode) {
	    [NSApp tkFilePanelDidEnd:panel
		       returnCode:returnCode
		       contextInfo:callbackInfo ];
	    }];

	modalReturnCode = callbackInfo->cmdObj ? modalOther :
	    [NSApp runModalForWindow:panel];
    } else {
	modalReturnCode = [panel runModal];
	[NSApp tkFilePanelDidEnd:panel returnCode:modalReturnCode
		     contextInfo:callbackInfo];
    }
    return modalReturnCode;
}







|

|




>

|







340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
static NSInteger showOpenSavePanel(
    NSSavePanel *panel,
    NSWindow *parent,
    FilePanelCallbackInfo *callbackInfo)
{
    NSInteger modalReturnCode;

    if (parent && ![parent attachedSheet]) {
	[panel beginSheetModalForWindow:parent
	       completionHandler:^(NSModalResponse returnCode) {
	    [NSApp tkFilePanelDidEnd:panel
		       returnCode:returnCode
		       contextInfo:callbackInfo ];
	    }];

	modalReturnCode = callbackInfo->cmdObj ? modalOther :
	    [panel runModal];
    } else {
	modalReturnCode = [panel runModal];
	[NSApp tkFilePanelDidEnd:panel returnCode:modalReturnCode
		     contextInfo:callbackInfo];
    }
    return modalReturnCode;
}
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
    NSString *directory = nil, *filename = nil;
    NSString *message = nil, *title = nil;
    NSWindow *parent;
    openpanel =  [NSOpenPanel openPanel];
    NSInteger modalReturnCode = modalError;
    BOOL parentIsKey = NO;

    [openpanel setDelegate:NSApp];

    for (i = 1; i < objc; i += 2) {
	if (Tcl_GetIndexFromObjStruct(interp, objv[i], openOptionStrings,
		sizeof(char *), "option", TCL_EXACT, &index) != TCL_OK) {
	    goto end;
	}
	if (i + 1 == objc) {
	    Tcl_SetObjResult(interp, Tcl_ObjPrintf(







<
<







652
653
654
655
656
657
658


659
660
661
662
663
664
665
    NSString *directory = nil, *filename = nil;
    NSString *message = nil, *title = nil;
    NSWindow *parent;
    openpanel =  [NSOpenPanel openPanel];
    NSInteger modalReturnCode = modalError;
    BOOL parentIsKey = NO;



    for (i = 1; i < objc; i += 2) {
	if (Tcl_GetIndexFromObjStruct(interp, objv[i], openOptionStrings,
		sizeof(char *), "option", TCL_EXACT, &index) != TCL_OK) {
	    goto end;
	}
	if (i + 1 == objc) {
	    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
    NSString *directory = nil, *filename = nil, *defaultType = nil;
    NSString *message = nil, *title = nil;
    NSWindow *parent;
    savepanel = [NSSavePanel savePanel];
    NSInteger modalReturnCode = modalError;
    BOOL parentIsKey = NO;

    [savepanel setDelegate:NSApp];

    for (i = 1; i < objc; i += 2) {
	if (Tcl_GetIndexFromObjStruct(interp, objv[i], saveOptionStrings,
		sizeof(char *), "option", TCL_EXACT, &index) != TCL_OK) {
	    goto end;
	}
	if (i + 1 == objc) {
	    Tcl_SetObjResult(interp, Tcl_ObjPrintf(







<
<







924
925
926
927
928
929
930


931
932
933
934
935
936
937
    NSString *directory = nil, *filename = nil, *defaultType = nil;
    NSString *message = nil, *title = nil;
    NSWindow *parent;
    savepanel = [NSSavePanel savePanel];
    NSInteger modalReturnCode = modalError;
    BOOL parentIsKey = NO;



    for (i = 1; i < objc; i += 2) {
	if (Tcl_GetIndexFromObjStruct(interp, objv[i], saveOptionStrings,
		sizeof(char *), "option", TCL_EXACT, &index) != TCL_OK) {
	    goto end;
	}
	if (i + 1 == objc) {
	    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
    NSString *directory = nil;
    NSString *message, *title;
    NSWindow *parent;
    NSOpenPanel *panel = [NSOpenPanel openPanel];
    NSInteger modalReturnCode = modalError;
    BOOL parentIsKey = NO;

    [panel setDelegate:NSApp];

    for (i = 1; i < objc; i += 2) {
	if (Tcl_GetIndexFromObjStruct(interp, objv[i], chooseOptionStrings,
		sizeof(char *), "option", TCL_EXACT, &index) != TCL_OK) {
	    goto end;
	}
	if (i + 1 == objc) {
	    Tcl_SetObjResult(interp, Tcl_ObjPrintf(







<
<







1165
1166
1167
1168
1169
1170
1171


1172
1173
1174
1175
1176
1177
1178
    NSString *directory = nil;
    NSString *message, *title;
    NSWindow *parent;
    NSOpenPanel *panel = [NSOpenPanel openPanel];
    NSInteger modalReturnCode = modalError;
    BOOL parentIsKey = NO;



    for (i = 1; i < objc; i += 2) {
	if (Tcl_GetIndexFromObjStruct(interp, objv[i], chooseOptionStrings,
		sizeof(char *), "option", TCL_EXACT, &index) != TCL_OK) {
	    goto end;
	}
	if (i + 1 == objc) {
	    Tcl_SetObjResult(interp, Tcl_ObjPrintf(

Changes to macosx/tkMacOSXFont.c.

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
			    int numBytes, int rangeStart, int rangeLength,
			    int x, int y, double angle);

#pragma mark -
#pragma mark Font Helpers:

/*
 *---------------------------------------------------------------------------
 *
 * TkUtfToNSString --
 *
 * When Tcl is compiled with TCL_UTF_MAX = 3 (the default for 8.6) it cannot
 * deal directly with UTF-8 encoded non-BMP characters, since their UTF-8
 * encoding requires 4 bytes.
 *
 * As a workaround, these versions of Tcl encode non-BMP characters as a string
 * of length 6 in which the high and low UTF-16 surrogates have been encoded
 * using the UTF-8 algorithm.  The UTF-8 encoding does not allow encoding
 * surrogates, so these 6-byte strings are not valid UTF-8, and hence Apple's
 * NString class will refuse to instantiate an NSString from the 6-byte
 * encoding.  This function allows creating an NSString from a C-string which
 * has been encoded using this scheme.
 *
 * Results:
 *	An NSString, which may be nil.
 *
 * Side effects:
 *	None.
 *---------------------------------------------------------------------------
 */

MODULE_SCOPE NSString*
TkUtfToNSString(
   const char *source,
   size_t numBytes)
{
    NSString *string;

    Tcl_DString ds;


    Tcl_DStringInit(&ds);
    Tcl_UtfToUniCharDString(source, numBytes, &ds);
    string = [[NSString alloc] initWithCharacters:(const unichar *)Tcl_DStringValue(&ds)

	    length:(Tcl_DStringLength(&ds)>>1)];








    Tcl_DStringFree(&ds);






    return string;
}








/*
 *---------------------------------------------------------------------------
 *
 * TkUtfAtIndex --
 *
 *  Write a sequence of bytes up to length 6 which is an encoding of a UTF-16
 *  character in an NSString.  Also record the unicode code point of the character.
 *  this may be a non-BMP character constructed by reading two surrogates from
 *  the NSString.
 *
 * Results:
 *	Returns the number of bytes written.
 *
 * Side effects:
 *	Bytes are written to the char array referenced by the pointer uni and
 *      the unicode code point is written to the integer referenced by the







<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<


<
|
<
<
|
<
>
|
|
>
|
|
|
>
|
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
|

|
>
>
>
>
>
>
>








|







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
			    int numBytes, int rangeStart, int rangeLength,
			    int x, int y, double angle);

#pragma mark -
#pragma mark Font Helpers:

/*


 * To avoid an extra copy, a TKNSString object wraps a Tcl_DString with an














 * NSString that uses the DString's buffer as its character buffer.




 */


@implementation TKNSString




- (instancetype)initWithTclUtfBytes:(const void *)bytes
		       length:(NSUInteger)len
{
    if (self = [self init]) {
	Tcl_DStringInit(&_ds);
	Tcl_UtfToUniCharDString(bytes, len, &_ds);
	_string = [[NSString alloc]
	     initWithCharactersNoCopy:(unichar *)Tcl_DStringValue(&_ds)
			       length:Tcl_DStringLength(&_ds)>>1
			 freeWhenDone:NO];
	self.UTF8String = _string.UTF8String;
    }
    return self;
}

- (void)dealloc
{
    Tcl_DStringFree(&_ds);
    [_string release];
    [super dealloc];
}

- (NSUInteger)length
{
    return _string.length;
}

- (unichar)characterAtIndex:(NSUInteger)index
{
    return [_string characterAtIndex:index];
}

@end

/*
 *---------------------------------------------------------------------------
 *
 * TkUtfAtIndex --
 *
 *  Write a sequence of bytes up to length 6 which is an encoding of a UTF-16
 *  character in an NSString.  Also record the unicode code point of the character.
 *  this may be a non-BMP character constructed by reading two surrogates from
 *  the NSString.  See the documentation for TKNSString in tkMacOSXPrivate.h.
 *
 * Results:
 *	Returns the number of bytes written.
 *
 * Side effects:
 *	Bytes are written to the char array referenced by the pointer uni and
 *      the unicode code point is written to the integer referenced by the
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
	    (maxLength == 0 && !(flags & TK_AT_LEAST_ONE))) {
	*lengthPtr = 0;
	return 0;
    }
    if (maxLength > 32767) {
	maxLength = 32767;
    }
    string = TkUtfToNSString((const char *)source, numBytes);
    if (!string) {
	length = 0;
	fit = rangeLength;
	goto done;
    }
    attributedString = [[NSAttributedString alloc] initWithString:string
	    attributes:fontPtr->nsAttributes];







|







975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
	    (maxLength == 0 && !(flags & TK_AT_LEAST_ONE))) {
	*lengthPtr = 0;
	return 0;
    }
    if (maxLength > 32767) {
	maxLength = 32767;
    }
    string = [[TKNSString alloc] initWithTclUtfBytes:source length:numBytes];
    if (!string) {
	length = 0;
	fit = rangeLength;
	goto done;
    }
    attributedString = [[NSAttributedString alloc] initWithString:string
	    attributes:fontPtr->nsAttributes];
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285


1286
1287
1288
1289
1290

1291
1292






1293
1294
1295
1296
1297
1298

1299
1300

1301
1302
1303
1304
1305
1306
1307
    double angle)
{
    const MacFont *fontPtr = (const MacFont *) tkfont;
    NSString *string;
    NSMutableDictionary *attributes;
    NSAttributedString *attributedString;
    CTTypesetterRef typesetter;
    CFIndex start, len;
    CTLineRef line;
    MacDrawable *macWin = (MacDrawable *) drawable;
    TkMacOSXDrawingContext drawingContext;
    CGContextRef context;
    CGColorRef fg;
    NSFont *nsFont;
    CGAffineTransform t;
    int h;

    if (rangeStart < 0 || rangeLength <= 0 ||
	    rangeStart + rangeLength > numBytes ||
	    !TkMacOSXSetupDrawingContext(drawable, gc, 1, &drawingContext)) {
	return;
    }
    string = TkUtfToNSString((const char *)source, numBytes);
    if (!string) {
	return;
    }
    context = drawingContext.context;
    fg = TkMacOSXCreateCGColor(gc, gc->foreground);
    attributes = [fontPtr->nsAttributes mutableCopy];
    [attributes setObject:(id)fg forKey:(id)kCTForegroundColorAttributeName];
    CFRelease(fg);
    nsFont = [attributes objectForKey:NSFontAttributeName];
    [nsFont setInContext:[NSGraphicsContext graphicsContextWithGraphicsPort:
	    context flipped:NO]];
    CGContextSetTextMatrix(context, CGAffineTransformIdentity);
    attributedString = [[NSAttributedString alloc] initWithString:string
	    attributes:attributes];
    typesetter = CTTypesetterCreateWithAttributedString(
	    (CFAttributedStringRef)attributedString);
    x += macWin->xOff;
    y += macWin->yOff;
    h = drawingContext.portBounds.size.height;
    y = h - y;
    t = CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, h);
    if (angle != 0.0) {
	t = CGAffineTransformTranslate(CGAffineTransformRotate(
		CGAffineTransformTranslate(t, x, y), angle*PI/180.0), -x, -y);


    }
    CGContextConcatCTM(context, t);
    CGContextSetTextPosition(context, x, y);
    start = Tcl_NumUtfChars(source, rangeStart);
    len = Tcl_NumUtfChars(source, rangeStart + rangeLength);

    if (start > 0) {
	CGRect clipRect = CGRectInfinite, startBounds;







	line = CTTypesetterCreateLine(typesetter, CFRangeMake(0, start));
	startBounds = CTLineGetImageBounds(line, context);
	CFRelease(line);
	clipRect.origin.x = startBounds.origin.x + startBounds.size.width;
	CGContextClipToRect(context, clipRect);

    }
    line = CTTypesetterCreateLine(typesetter, CFRangeMake(0, len));

    CTLineDraw(line, context);
    CFRelease(line);
    CFRelease(typesetter);
    [attributedString release];
    [string release];
    [attributes release];
    TkMacOSXRestoreDrawingContext(&drawingContext);







|
|






|

|
|
|


|
















|
|
|
|
|

|
|
>
>


<

|
>

|
>
>
>
>
>
>

|
|
|
<
<
>

<
>







1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289

1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304


1305
1306

1307
1308
1309
1310
1311
1312
1313
1314
    double angle)
{
    const MacFont *fontPtr = (const MacFont *) tkfont;
    NSString *string;
    NSMutableDictionary *attributes;
    NSAttributedString *attributedString;
    CTTypesetterRef typesetter;
    CFIndex start, length;
    CTLineRef line, full=nil;
    MacDrawable *macWin = (MacDrawable *) drawable;
    TkMacOSXDrawingContext drawingContext;
    CGContextRef context;
    CGColorRef fg;
    NSFont *nsFont;
    CGAffineTransform t;
    CGFloat width, height, textX = (CGFloat) x, textY = (CGFloat) y;

    if (rangeStart < 0 || rangeLength <= 0  ||
	rangeStart + rangeLength > numBytes ||
	!TkMacOSXSetupDrawingContext(drawable, gc, 1, &drawingContext)) {
	return;
    }
    string = [[TKNSString alloc] initWithTclUtfBytes:source length:numBytes];
    if (!string) {
	return;
    }
    context = drawingContext.context;
    fg = TkMacOSXCreateCGColor(gc, gc->foreground);
    attributes = [fontPtr->nsAttributes mutableCopy];
    [attributes setObject:(id)fg forKey:(id)kCTForegroundColorAttributeName];
    CFRelease(fg);
    nsFont = [attributes objectForKey:NSFontAttributeName];
    [nsFont setInContext:[NSGraphicsContext graphicsContextWithGraphicsPort:
	    context flipped:NO]];
    CGContextSetTextMatrix(context, CGAffineTransformIdentity);
    attributedString = [[NSAttributedString alloc] initWithString:string
	    attributes:attributes];
    typesetter = CTTypesetterCreateWithAttributedString(
	    (CFAttributedStringRef)attributedString);
    textX += (CGFloat) macWin->xOff;
    textY += (CGFloat) macWin->yOff;
    height = drawingContext.portBounds.size.height;
    textY = height - textY;
    t = CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, height);
    if (angle != 0.0) {
	t = CGAffineTransformTranslate(
             CGAffineTransformRotate(
                 CGAffineTransformTranslate(t, textX, textY), angle*PI/180.0),
             -textX, -textY);
    }
    CGContextConcatCTM(context, t);

    start = Tcl_NumUtfChars(source, rangeStart);
    length = Tcl_NumUtfChars(source, rangeStart + rangeLength) - start;
    line = CTTypesetterCreateLine(typesetter, CFRangeMake(start, length));
    if (start > 0) {

	/*
	 * We are only drawing part of the string.  To compute the x coordinate
	 * of the part we are drawing we subtract its typographical length from
	 * the typographical length of the full string.  This accounts for the
	 * kerning after the initial part of the string.
	 */

	full = CTTypesetterCreateLine(typesetter, CFRangeMake(0, start + length));
	width = CTLineGetTypographicBounds(full, NULL, NULL, NULL);
	CFRelease(full);


	textX += (width - CTLineGetTypographicBounds(line, NULL, NULL, NULL));
    }

    CGContextSetTextPosition(context, textX, textY);
    CTLineDraw(line, context);
    CFRelease(line);
    CFRelease(typesetter);
    [attributedString release];
    [string release];
    [attributes release];
    TkMacOSXRestoreDrawingContext(&drawingContext);

Changes to macosx/tkMacOSXInit.c.

71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

- (void) _setupApplicationNotifications
{
    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
#define observe(n, s) \
	[nc addObserver:self selector:@selector(s) name:(n) object:nil]
    observe(NSApplicationDidBecomeActiveNotification, applicationActivate:);
    observe(NSApplicationDidResignActiveNotification, applicationDeactivate:);
    observe(NSApplicationDidUnhideNotification, applicationShowHide:);
    observe(NSApplicationDidHideNotification, applicationShowHide:);
    observe(NSApplicationDidChangeScreenParametersNotification, displayChanged:);
    observe(NSTextInputContextKeyboardSelectionDidChangeNotification, keyboardChanged:);
#undef observe
}








|







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

- (void) _setupApplicationNotifications
{
    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
#define observe(n, s) \
	[nc addObserver:self selector:@selector(s) name:(n) object:nil]
    observe(NSApplicationDidBecomeActiveNotification, applicationActivate:);
    observe(NSApplicationWillResignActiveNotification, applicationDeactivate:);
    observe(NSApplicationDidUnhideNotification, applicationShowHide:);
    observe(NSApplicationDidHideNotification, applicationShowHide:);
    observe(NSApplicationDidChangeScreenParametersNotification, displayChanged:);
    observe(NSTextInputContextKeyboardSelectionDidChangeNotification, keyboardChanged:);
#undef observe
}

Changes to macosx/tkMacOSXKeyEvent.c.

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
212
213
214
215
216
217
218

219
220




221




222
223
224
225
226
227
228
229
230
231
232

233
234
235
236
237
238



239


240
241
242
243
244
245
246
247
248
249

250
251
252
253

254




255
256
257

258

259




260





261






262

263











































264
265
266
267
268
269
270
/*
 * tkMacOSXKeyEvent.c --
 *
 *	This file implements functions that decode & handle keyboard events on
 *	MacOS X.
 *
 * Copyright 2001-2009, Apple Inc.
 * Copyright (c) 2006-2009 Daniel A. Steffen <[email protected]>
 * Copyright (c) 2012 Adrian Robert.
 * Copyright 2015-2019 Marc Culler.
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tkMacOSXPrivate.h"
#include "tkMacOSXInt.h"
#include "tkMacOSXConstants.h"






/*
#ifdef TK_MAC_DEBUG
#define TK_MAC_DEBUG_KEYBOARD
#endif
*/

#define NS_KEYLOG 0

static Tk_Window keyboardGrabWinPtr = NULL;
				/* Current keyboard grab window. */
static NSWindow *keyboardGrabNSWindow = nil;
				/* NSWindow for the current keyboard grab
				 * window. */
static NSModalSession modalSession = nil;
static BOOL processingCompose = NO;
static Tk_Window composeWin = NULL;
static int caret_x = 0, caret_y = 0, caret_height = 0;
static unsigned short releaseCode;

static void setupXEvent(XEvent *xEvent, NSWindow *w, unsigned int state);
static unsigned	isFunctionKey(unsigned int code);


#pragma mark TKApplication(TKKeyEvent)

@implementation TKApplication(TKKeyEvent)

- (NSEvent *) tkProcessKeyEvent: (NSEvent *) theEvent
{
#ifdef TK_MAC_DEBUG_EVENTS
    TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, theEvent);
#endif
    NSWindow *w;


    NSEventType type = [theEvent type];

    NSUInteger modifiers = ([theEvent modifierFlags] &
			    NSDeviceIndependentModifierFlagsMask);
    NSUInteger len = 0;

    BOOL repeat = NO;
    unsigned short keyCode = [theEvent keyCode];
    NSString *characters = nil, *charactersIgnoringModifiers = nil;
    static NSUInteger savedModifiers = 0;
    static NSMutableArray *nsEvArray;

    if (nsEvArray == nil) {
        nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
        processingCompose = NO;
    }

    w = [theEvent window];
    TkWindow *winPtr = TkMacOSXGetTkWindow(w);
    Tk_Window tkwin = (Tk_Window) winPtr;
    XEvent xEvent;

    if (!winPtr) {
	return theEvent;
    }

    /*
     * Control-Tab and Control-Shift-Tab are used to switch tabs in a tabbed
     * window.  We do not want to generate an Xevent for these since that might
     * cause the deselected tab to be reactivated.
     */

    if (keyCode == 48 && (modifiers & NSControlKeyMask) == NSControlKeyMask) {
	return theEvent;
    }

    switch (type) {
    case NSKeyUp:
	/*Fix for bug #1ba71a86bb: key release firing on key press.*/
	setupXEvent(&xEvent, w, 0);
	xEvent.xany.type = KeyRelease;
	xEvent.xkey.keycode = releaseCode;
	xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
    case NSKeyDown:
	repeat = [theEvent isARepeat];
	characters = [theEvent characters];
	charactersIgnoringModifiers = [theEvent charactersIgnoringModifiers];
        len = [charactersIgnoringModifiers length];
    case NSFlagsChanged:

#if defined(TK_MAC_DEBUG_EVENTS) || NS_KEYLOG == 1
	TKLog(@"-[%@(%p) %s] r=%d mods=%u '%@' '%@' code=%u c=%d %@ %d", [self class], self, _cmd, repeat, modifiers, characters, charactersIgnoringModifiers, keyCode,([charactersIgnoringModifiers length] == 0) ? 0 : [charactersIgnoringModifiers characterAtIndex: 0], w, type);
#endif
	break;

    default:
	return theEvent; /* Unrecognized key event. */
    }

    /*
     * Create an Xevent to add to the Tk queue.
     */

    if (!processingCompose) {
        unsigned int state = 0;

        if (modifiers & NSAlphaShiftKeyMask) {
	    state |= LockMask;
        }
        if (modifiers & NSShiftKeyMask) {
	    state |= ShiftMask;
        }
        if (modifiers & NSControlKeyMask) {
	    state |= ControlMask;
        }
        if (modifiers & NSCommandKeyMask) {
	    state |= Mod1Mask;		/* command key */
        }
        if (modifiers & NSAlternateKeyMask) {
	    state |= Mod2Mask;		/* option key */
        }
        if (modifiers & NSNumericPadKeyMask) {
	    state |= Mod3Mask;
        }
        if (modifiers & NSFunctionKeyMask) {
	    state |= Mod4Mask;
        }

        /*
         * Key events are only received for the front Window on the Macintosh. So
	 * to build an XEvent we look up the Tk window associated to the Front
	 * window.
         */

        TkWindow *winPtr = TkMacOSXGetTkWindow(w);
        Tk_Window tkwin = (Tk_Window) winPtr;

	if (tkwin) {
	    TkWindow *grabWinPtr = winPtr->dispPtr->grabWinPtr;

	    /*
	     * If a local grab is in effect, key events for windows in the
	     * grabber's application are redirected to the grabber.  Key events
	     * for other applications are delivered normally.  If a global
	     * grab is in effect all key events are redirected to the grabber.
	     */


	    if (grabWinPtr) {
		if (winPtr->dispPtr->grabFlags ||  /* global grab */
		    grabWinPtr->mainPtr == winPtr->mainPtr){ /* same appl. */

			tkwin = (Tk_Window) winPtr->dispPtr->focusPtr;
		    }
	    }
	} else {
	    tkwin = (Tk_Window) winPtr->dispPtr->focusPtr;
	}
        if (!tkwin) {

	    TkMacOSXDbgMsg("tkwin == NULL");
	    return theEvent;  /* Give up. No window for this event. */
        }




        /*


         * If it's a function key, or we have modifiers other than Shift or






         * Alt, pass it straight to Tk.  Otherwise we'll send for input
         * processing.
         */


        int code = (len == 0) ? 0 :
		[charactersIgnoringModifiers characterAtIndex: 0];
        if (type != NSKeyDown || isFunctionKey(code)
		|| (len > 0 && state & (ControlMask | Mod1Mask | Mod3Mask | Mod4Mask))) {
            XEvent xEvent;


            setupXEvent(&xEvent, w, state);
            if (type == NSFlagsChanged) {
		if (savedModifiers > modifiers) {
		    xEvent.xany.type = KeyRelease;
		} else {
		    xEvent.xany.type = KeyPress;
		}

		/*
		 * Use special '-1' to signify a special keycode to our
		 * platform specific code in tkMacOSXKeyboard.c. This is rather
		 * like what happens on Windows.

		 */




		xEvent.xany.send_event = -1;









		/*
		 * Set keycode (which was zero) to the changed modifier


		 */












		xEvent.xkey.keycode = (modifiers ^ savedModifiers);

            } else {
		if (type == NSKeyUp || repeat) {
		    xEvent.xany.type = KeyRelease;
		} else {
		    xEvent.xany.type = KeyPress;
		}


		if ([characters length] > 0) {
		    xEvent.xkey.keycode = (keyCode << 16) |
			    (UInt16) [characters characterAtIndex:0];
		    if (![characters getCString:xEvent.xkey.trans_chars
			    maxLength:XMaxTransChars encoding:NSUTF8StringEncoding]) {
			/* prevent SF bug 2907388 (crash on some composite chars) */
			//PENDING: we might not need this anymore
			TkMacOSXDbgMsg("characters too long");

			return theEvent;
		    }




		}





		if (repeat) {
		    Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
		    xEvent.xany.type = KeyPress;
		    xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
		}
            }
            Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
            savedModifiers = modifiers;
            return theEvent;
	}  /* if this is a function key or has modifiers */

    }  /* if not processing compose */

    if (type == NSKeyDown) {
        if (NS_KEYLOG) {
	    TKLog(@"keyDown: %s compose sequence.\n",
		    processingCompose == YES ? "Continue" : "Begin");



	}



	/*
	 * Call the interpretKeyEvents method to interpret composition key
	 * strokes.  When it detects a complete composition sequence it will
	 * call our implementation of insertText: replacementRange, which
	 * generates a key down XEvent with the appropriate character.  In IME
	 * when multiple characters have the same composition sequence and the
	 * chosen character is not the default it may be necessary to hit the
	 * enter key multiple times before the character is accepted and
	 * rendered. We send enter key events until inputText has cleared

	 * the processingCompose flag.
	 */

	processingCompose = YES;

	while(processingCompose) {




	    [nsEvArray addObject: theEvent];
	    [[w contentView] interpretKeyEvents: nsEvArray];
	    [nsEvArray removeObject: theEvent];

	    if ([theEvent keyCode] != 36) {

		break;




	    }





	}






    }

    savedModifiers = modifiers;











































    return theEvent;
}
@end


@implementation TKContentView










|








>
>
>
>
>






>

|
|
<
|
<
<




<
<
|
|
|










|
>
>

>


|
>
|
<
|

|





<
<
<
<
<
<





<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
|
|
|
|

>
|
|
|
>
|
|
|
<
<
|
<
>
|
|
|
>
>
>

|
>
>
|
>
>
>
>
>
>
|
<
|
>
|
<
<
<
<
<
>

<
<
<
<
|
<
|

|
<
<
<
>
|

>
>
>
|
>
>
>
>
>
>

>
>
|
|
>
>
|
>
>
>
>
>
>

>
>
>
>
>
|
>
|
<
<
|
|
|
>

|
<
<
<
<
|
<
<
>
|
|
>
>
>
>
|
>
>
>
>
|
<
<
<
<
|
|
<
<
<
<
>
|
|
<
<
|
<
>
>
>
|
>
>


<
|
<
<
|
|
|
|
>
|


|
>
|
>
>
>
>



>
|
>
|
>
>
>
>
|
>
>
>
>
>
|
>
>
>
>
>
>
|
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
/*
 * tkMacOSXKeyEvent.c --
 *
 *	This file implements functions that decode & handle keyboard events on
 *	MacOS X.
 *
 * Copyright 2001-2009, Apple Inc.
 * Copyright (c) 2006-2009 Daniel A. Steffen <[email protected]>
 * Copyright (c) 2012 Adrian Robert.
 * Copyright 2015-2020 Marc Culler.
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tkMacOSXPrivate.h"
#include "tkMacOSXInt.h"
#include "tkMacOSXConstants.h"
#include "tkMacOSXWm.h"

/*
 * See tkMacOSXPrivate.h for macros related to key event processing.
 */

/*
#ifdef TK_MAC_DEBUG
#define TK_MAC_DEBUG_KEYBOARD
#endif
*/

#define NS_KEYLOG 0
#define XEVENT_MOD_MASK (ControlMask | Mod1Mask | Mod3Mask | Mod4Mask)
static Tk_Window keyboardGrabWinPtr = NULL; /* Current keyboard grab window. */

static NSWindow *keyboardGrabNSWindow = nil; /* Its underlying NSWindow.*/


static NSModalSession modalSession = nil;
static BOOL processingCompose = NO;
static Tk_Window composeWin = NULL;
static int caret_x = 0, caret_y = 0, caret_height = 0;


static void setupXEvent(XEvent *xEvent, Tk_Window tkwin, NSUInteger modifiers);
static void setXEventPoint(XEvent *xEvent, Tk_Window tkwin, NSWindow *w);
static NSUInteger textInputModifiers;

#pragma mark TKApplication(TKKeyEvent)

@implementation TKApplication(TKKeyEvent)

- (NSEvent *) tkProcessKeyEvent: (NSEvent *) theEvent
{
#ifdef TK_MAC_DEBUG_EVENTS
    TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, theEvent);
#endif
    NSWindow *w = [theEvent window];
    TkWindow *winPtr = TkMacOSXGetTkWindow(w), *grabWinPtr, *focusWinPtr;
    Tk_Window tkwin = (Tk_Window) winPtr;
    NSEventType type = [theEvent type];
    NSUInteger virtual = [theEvent keyCode];
    NSUInteger modifiers = ([theEvent modifierFlags] &
			    NSDeviceIndependentModifierFlagsMask);
    XEvent xEvent;
    MacKeycode macKC;
    UniChar keychar = 0;

    Bool can_input_text, has_modifiers = NO, use_text_input = NO;
    static NSUInteger savedModifiers = 0;
    static NSMutableArray *nsEvArray = nil;

    if (nsEvArray == nil) {
        nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
        processingCompose = NO;
    }






    if (!winPtr) {
	return theEvent;
    }

    /*










































































     * If a local grab is in effect, key events for windows in the
     * grabber's application are redirected to the grabber.  Key events
     * for other applications are delivered normally.  If a global
     * grab is in effect all key events are redirected to the grabber.
     */

    grabWinPtr = winPtr->dispPtr->grabWinPtr;
    if (grabWinPtr) {
	if (winPtr->dispPtr->grabFlags ||  /* global grab */
	    grabWinPtr->mainPtr == winPtr->mainPtr){ /* same application */
	    winPtr =winPtr->dispPtr->focusPtr;
	    tkwin = (Tk_Window) winPtr;
	}
    }




    /*
     * Extract the unicode character from KeyUp and KeyDown events.
     */

    if (type == NSKeyUp || type == NSKeyDown) {
	if ([[theEvent characters] length] > 0) {
	    keychar = [[theEvent characters] characterAtIndex:0];

	    /*
	     * Currently, real keys always send BMP characters, but who knows?
	     */

	    if (CFStringIsSurrogateHighCharacter(keychar)) {
		UniChar lowChar = [[theEvent characters] characterAtIndex:1];
		keychar = CFStringGetLongCharacterForSurrogatePair(
		    keychar, lowChar);
	    }
	} else {


	    /*
	     * This is a dead key, such as Option-e, so it should go to the
	     * TextInputClient.





	     */





	    use_text_input = YES;

	}

	/*



	 * Apple uses 0x10 for unrecognized keys.
	 */

	if (keychar == 0x10) {
	    keychar = UNKNOWN_KEYCHAR;
	}

#if defined(TK_MAC_DEBUG_EVENTS) || NS_KEYLOG == 1
	TKLog(@"-[%@(%p) %s] repeat=%d mods=%x char=%x code=%lu c=%d type=%d",
	      [self class], self, _cmd,
	      (type == NSKeyDown) && [theEvent isARepeat], modifiers, keychar,
	      virtual, w, type);
#endif

    }

    /*
     * Build a skeleton XEvent.  We need to build it here, even if we will not
     * send it, so we can pass it to TkFocusKeyEvent to determine whether the
     * target widget can input text.
     */

    setupXEvent(&xEvent, tkwin, modifiers);
    has_modifiers = xEvent.xkey.state & XEVENT_MOD_MASK;
    focusWinPtr = TkFocusKeyEvent(winPtr, &xEvent);
    if (focusWinPtr == NULL) {
	TKContentView *contentView = [w contentView];

	/*
	 * This NSEvent is being sent to a window which does not have focus.
	 * This could mean, for example, that the user deactivated the Tk app
	 * while the NSTextInputClient's popup character selection window was
	 * still open.  We attempt to abandon any ongoing composition operation
	 * and discard the event.
	 */



	[contentView cancelComposingText];
	return theEvent;
    }
    can_input_text = ((focusWinPtr->flags & TK_CAN_INPUT_TEXT) != 0);

#if (NS_KEYLOG)




    TKLog(@"keyDown: %s compose sequence.\n",


	  processingCompose == YES ? "Continue" : "Begin");
#endif

    /*
     * Decide whether this event should be processed with the NSTextInputClient
     * protocol.
     */

    if (processingCompose ||
	(type == NSKeyDown && can_input_text && !has_modifiers &&
	 IS_PRINTABLE(keychar))
	) {
	use_text_input = YES;




    }





    /*
     * If we are processing this KeyDown event as an NSTextInputClient we do
     * not queue an XEvent.  We pass the NSEvent to our interpretKeyEvents


     * method.  When the composition sequence is complete, the callback method

     * insertText: replacementRange will be called.  That method generates a
     * keyPress XEvent with the selected character.
     */

    if (use_text_input) {
	textInputModifiers = modifiers;

	/*

	 * In IME the Enter key is used to terminate a composition sequence.


	 * When there are multiple choices of input text available, and the
	 * user's selected choice is not the default, it may be necessary to
	 * hit the Enter key multiple times before the text is accepted and
	 * rendered (See ticket 39de9677aa]). So when sending an Enter key
	 * during composition, we continue sending Enter keys until the
	 * inputText method has cleared the processingCompose flag.
	 */

	if (processingCompose && [theEvent keyCode] == 36) {
	    [nsEvArray addObject: theEvent];
	    while(processingCompose) {
		[[w contentView] interpretKeyEvents: nsEvArray];
	    }
	    [nsEvArray removeObject: theEvent];
	} else {
	    [nsEvArray addObject: theEvent];
	    [[w contentView] interpretKeyEvents: nsEvArray];
	    [nsEvArray removeObject: theEvent];
	}
	return theEvent;
    }

    /*
     * We are not handling this event as an NSTextInputClient, so we need to
     * finish constructing the XEvent and queue it.
     */

    macKC.v.o_s =  ((modifiers & NSShiftKeyMask ? INDEX_SHIFT : 0) |
		    (modifiers & NSAlternateKeyMask ? INDEX_OPTION : 0));
    macKC.v.virtual = virtual;
    switch (type) {
    case NSFlagsChanged:

	/*
	 * This XEvent is a simulated KeyPress or KeyRelease event for a
	 * modifier key.  To determine the type, note that the highest bit
	 * where the flags differ is 1 if and only if it is a KeyPress. The
	 * modifiers are saved so we can detect the next flag change.
	 */

	xEvent.xany.type = modifiers > savedModifiers ? KeyPress : KeyRelease;
	savedModifiers = modifiers;

	/*
	 * Set the keychar to MOD_KEYCHAR as a signal to TkpGetKeySym (see
	 * tkMacOSXKeyboard.c) that this is a modifier key event.
	 */

	keychar = MOD_KEYCHAR;
	break;
    case NSKeyUp:
	xEvent.xany.type = KeyRelease;
	break;
    case NSKeyDown:
	xEvent.xany.type = KeyPress;
	break;
    default:
	return theEvent; /* Unrecognized key event. */
    }
    macKC.v.keychar = keychar;
    xEvent.xkey.keycode = macKC.uint;

    /*
     * Set the trans_chars for keychars outside of the private-use range.
     */

    setXEventPoint(&xEvent, tkwin, w);
    if (IS_PRINTABLE(keychar)) {
	int length = TkUniCharToUtf(keychar, xEvent.xkey.trans_chars);
	xEvent.xkey.trans_chars[length] = 0;
    }

    /*
     * Finally we can queue the XEvent, inserting a KeyRelease before a
     * repeated KeyPress.
     */

    if (type == NSKeyDown && [theEvent isARepeat]) {
	xEvent.xany.type = KeyRelease;
	Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
	xEvent.xany.type = KeyPress;
    }
    if (xEvent.xany.type == KeyPress) {
    }
    Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
    return theEvent;
}
@end


@implementation TKContentView

278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293



294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309

310
311
312
313
314
315
316
317

318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334


335
336
337
338
339


340
341
342
343
344
345
346
347
348

349



350

















351

352




353
354

355
356

357
358
359
360
361
362
363
364
365

/*
 * Implementation of the NSTextInputClient protocol.
 */

/* [NSTextInputClient inputText: replacementRange:] is called by
 * interpretKeyEvents when a composition sequence is complete.  It is also
 * called when we delete over working text.  In that case the call is followed
 * immediately by doCommandBySelector: deleteBackward:
 */
- (void)insertText: (id)aString
  replacementRange: (NSRange)repRange
{
    int i, len;
    XEvent xEvent;
    NSString *str;




    str = ([aString isKindOfClass: [NSAttributedString class]]) ?
        [aString string] : aString;
    len = [str length];

    if (NS_KEYLOG) {
	TKLog(@"insertText '%@'\tlen = %d", aString, len);
    }

    processingCompose = NO;

    /*
     * Clear any working text.
     */

    if (privateWorkingText != nil) {

    	[self deleteWorkingText];
    }

    /*
     * Insert the string as a sequence of keystrokes.
     */

    setupXEvent(&xEvent, [self window], 0);

    xEvent.xany.type = KeyPress;

    /*
     * Apple evidently sets location to 0 to signal that an accented letter has
     * been selected from the accent menu.  An unaccented letter has already
     * been displayed and we need to erase it before displaying the accented
     * letter.
     */

    if (repRange.location == 0) {
	TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);
	Tk_Window focusWin = (Tk_Window) winPtr->dispPtr->focusPtr;
	TkSendVirtualEvent(focusWin, "TkAccentBackspace", NULL);
    }

    /*
     * Next we generate an XEvent for each unicode character in our string.


     *
     * NSString uses UTF-16 internally, which means that a non-BMP character is
     * represented by a sequence of two 16-bit "surrogates".  In principle we
     * could record this in the XEvent by setting the keycode to the 32-bit
     * unicode code point and setting the trans_chars string to the 4-byte


     * UTF-8 string for the non-BMP character.  However, that will not work
     * when TCL_UTF_MAX is set to 3, as is the case for Tcl 8.6.  A workaround
     * used internally by Tcl 8.6 is to encode each surrogate as a 3-byte
     * sequence using the UTF-8 algorithm (ignoring the fact that the UTF-8
     * encoding specification does not allow encoding UTF-16 surrogates).
     * This gives a 6-byte encoding of the non-BMP character which we write into
     * the trans_chars field of the XEvent.
     */


    for (i = 0; i < len; i++) {



	xEvent.xkey.nbytes = TkUtfAtIndex(str, i, xEvent.xkey.trans_chars,

















					   &xEvent.xkey.keycode);

	if (xEvent.xkey.keycode > 0xffff){




	    i++;
	}

    	xEvent.xany.type = KeyPress;
    	Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);

    }
    releaseCode = (UInt16) [str characterAtIndex: 0];
}

/*
 * This required method is allowed to return nil.
 */

- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)theRange







|





|

|
>
>
>









<
<





>







|
>










<






>
>


|
|
<
>
>
|
|
|
|
|
|
|


>

>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
|
>
>
>
>


>


>

<







288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315


316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340

341
342
343
344
345
346
347
348
349
350
351
352

353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400

401
402
403
404
405
406
407

/*
 * Implementation of the NSTextInputClient protocol.
 */

/* [NSTextInputClient inputText: replacementRange:] is called by
 * interpretKeyEvents when a composition sequence is complete.  It is also
 * called when we delete working text.  In that case the call is followed
 * immediately by doCommandBySelector: deleteBackward:
 */
- (void)insertText: (id)aString
  replacementRange: (NSRange)repRange
{
    int i, len, state;
    XEvent xEvent;
    NSString *str, *keystr, *lower;
    TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);
    Tk_Window tkwin = (Tk_Window) winPtr;
    Bool sendingIMEText = NO;

    str = ([aString isKindOfClass: [NSAttributedString class]]) ?
        [aString string] : aString;
    len = [str length];

    if (NS_KEYLOG) {
	TKLog(@"insertText '%@'\tlen = %d", aString, len);
    }



    /*
     * Clear any working text.
     */

    if (privateWorkingText != nil) {
	sendingIMEText = YES;
    	[self deleteWorkingText];
    }

    /*
     * Insert the string as a sequence of keystrokes.
     */

    setupXEvent(&xEvent, tkwin, textInputModifiers);
    setXEventPoint(&xEvent, tkwin, [self window]);
    xEvent.xany.type = KeyPress;

    /*
     * Apple evidently sets location to 0 to signal that an accented letter has
     * been selected from the accent menu.  An unaccented letter has already
     * been displayed and we need to erase it before displaying the accented
     * letter.
     */

    if (repRange.location == 0) {

	Tk_Window focusWin = (Tk_Window) winPtr->dispPtr->focusPtr;
	TkSendVirtualEvent(focusWin, "TkAccentBackspace", NULL);
    }

    /*
     * Next we generate an XEvent for each unicode character in our string.
     * This string could contain non-BMP characters, for example if the
     * emoji palette was used.
     *
     * NSString uses UTF-16 internally, which means that a non-BMP character is
     * represented by a sequence of two 16-bit "surrogates".  We record this in
     * the XEvent by setting the low order 21-bits of the keycode to the UCS-32

     * value value of the character and the virtual keycode in the high order
     * byte to the special value NON_BMP. In principle we could set the
     * trans_chars string to the UTF-8 string for the non-BMP character.
     * However, that will not work when TCL_UTF_MAX is set to 3, as is the case
     * for Tcl 8.6.  A workaround used internally by Tcl 8.6 is to encode each
     * surrogate as a 3-byte sequence using the UTF-8 algorithm (ignoring the
     * fact that the UTF-8 encoding specification does not allow encoding
     * UTF-16 surrogates).  This gives a 6-byte encoding of the non-BMP
     * character which we write into the trans_chars field of the XEvent.
     */

    state = xEvent.xkey.state;
    for (i = 0; i < len; i++) {
	unsigned int code;
	UniChar keychar;
	MacKeycode macKC = {0};

	keychar = [str characterAtIndex:i];
	macKC.v.keychar = keychar;
	if (CFStringIsSurrogateHighCharacter(keychar)) {
	    UniChar lowChar = [str characterAtIndex:i+1];
	    macKC.v.keychar = CFStringGetLongCharacterForSurrogatePair(
				  (UniChar)keychar, lowChar);
	    macKC.v.virtual = NON_BMP_VIRTUAL;
	} else if (repRange.location == 0 || sendingIMEText) {
	    macKC.v.virtual = REPLACEMENT_VIRTUAL;
	} else {
	    macKC.uint = TkMacOSXAddVirtual(macKC.uint);
	    xEvent.xkey.state |= INDEX2STATE(macKC.x.xvirtual);
	}
	keystr = [[NSString alloc] initWithCharacters:&keychar length:1];
	lower = [keystr lowercaseString];
	if (![keystr isEqual: lower]) {
	    macKC.v.o_s |= INDEX_SHIFT;
	    xEvent.xkey.state |= ShiftMask;
	}
	if (xEvent.xkey.state & Mod2Mask) {
	    macKC.v.o_s |= INDEX_OPTION;
	}
	TkUtfAtIndex(str, i, xEvent.xkey.trans_chars, &code);
	if (code > 0xFFFF){
	    i++;
	}
	xEvent.xkey.keycode = macKC.uint;
    	xEvent.xany.type = KeyPress;
    	Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
	xEvent.xkey.state = state;
    }

}

/*
 * This required method is allowed to return nil.
 */

- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)theRange
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
    TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);
    Tk_Window focusWin = (Tk_Window) winPtr->dispPtr->focusPtr;
    NSString *temp;
    NSString *str;

    str = ([aString isKindOfClass: [NSAttributedString class]]) ?
        [aString string] : aString;

    if (focusWin) {

	/*
	 * Remember the widget where the composition is happening, in case it
	 * gets defocussed during the composition.
	 */








<







423
424
425
426
427
428
429

430
431
432
433
434
435
436
    TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);
    Tk_Window focusWin = (Tk_Window) winPtr->dispPtr->focusPtr;
    NSString *temp;
    NSString *str;

    str = ([aString isKindOfClass: [NSAttributedString class]]) ?
        [aString string] : aString;

    if (focusWin) {

	/*
	 * Remember the widget where the composition is happening, in case it
	 * gets defocussed during the composition.
	 */

412
413
414
415
416
417
418

419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
    }

    /*
     * Use our insertText method to display the marked text.
     */

    TkSendVirtualEvent(focusWin, "TkStartIMEMarkedText", NULL);

    temp = [str copy];
    [self insertText: temp replacementRange:repRange];
    privateWorkingText = temp;
    processingCompose = YES;
    TkSendVirtualEvent(focusWin, "TkEndIMEMarkedText", NULL);
}

- (BOOL)hasMarkedText
{
    return privateWorkingText != nil;
}


- (NSRange)markedRange
{
    NSRange rng = privateWorkingText != nil
	? NSMakeRange(0, [privateWorkingText length])
	: NSMakeRange(NSNotFound, 0);

    if (NS_KEYLOG) {
	TKLog(@"markedRange request");
    }
    return rng;
}

- (void)cancelComposingText
{
    if (NS_KEYLOG) {
	TKLog(@"cancelComposingText");
    }
    [self deleteWorkingText];
    processingCompose = NO;
}

- (void)unmarkText
{
    if (NS_KEYLOG) {
	TKLog(@"unmarkText");
    }
    [self deleteWorkingText];
    processingCompose = NO;
}


/*
 * Called by the system to get a position for popup character selection windows
 * such as a Character Palette, or a selection menu for IME.
 */

- (NSRect)firstRectForCharacterRange: (NSRange)theRange







>



<







<













<
<
<
<
<
<
<
<
<








<







453
454
455
456
457
458
459
460
461
462
463

464
465
466
467
468
469
470

471
472
473
474
475
476
477
478
479
480
481
482
483









484
485
486
487
488
489
490
491

492
493
494
495
496
497
498
    }

    /*
     * Use our insertText method to display the marked text.
     */

    TkSendVirtualEvent(focusWin, "TkStartIMEMarkedText", NULL);
    processingCompose = YES;
    temp = [str copy];
    [self insertText: temp replacementRange:repRange];
    privateWorkingText = temp;

    TkSendVirtualEvent(focusWin, "TkEndIMEMarkedText", NULL);
}

- (BOOL)hasMarkedText
{
    return privateWorkingText != nil;
}


- (NSRange)markedRange
{
    NSRange rng = privateWorkingText != nil
	? NSMakeRange(0, [privateWorkingText length])
	: NSMakeRange(NSNotFound, 0);

    if (NS_KEYLOG) {
	TKLog(@"markedRange request");
    }
    return rng;
}










- (void)unmarkText
{
    if (NS_KEYLOG) {
	TKLog(@"unmarkText");
    }
    [self deleteWorkingText];
    processingCompose = NO;
}


/*
 * Called by the system to get a position for popup character selection windows
 * such as a Character Palette, or a selection menu for IME.
 */

- (NSRect)firstRectForCharacterRange: (NSRange)theRange
569
570
571
572
573
574
575










576
577
578
579
580
581
582
583
584
585
586
587
588
589
590








591
592
593
594
595
596
597
598
599
600
601
602
603



































604
605
606
607
608
609
610
	privateWorkingText = nil;
	processingCompose = NO;
	if (composeWin) {
	    TkSendVirtualEvent(composeWin, "TkClearIMEMarkedText", NULL);
	}
    }
}










@end

/*
 * Set up basic fields in xevent for keyboard input.
 */

static void
setupXEvent(XEvent *xEvent, NSWindow *w, unsigned int state)
{
    TkWindow *winPtr = TkMacOSXGetTkWindow(w);
    Tk_Window tkwin = (Tk_Window) winPtr;

    if (!winPtr) {
	return;
    }









    memset(xEvent, 0, sizeof(XEvent));
    xEvent->xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
    xEvent->xany.display = Tk_Display(tkwin);
    xEvent->xany.window = Tk_WindowId(tkwin);

    xEvent->xkey.root = XRootWindow(Tk_Display(tkwin), 0);
    xEvent->xkey.time = TkpGetMS();
    xEvent->xkey.state = state;
    xEvent->xkey.same_screen = true;
    /* No need to initialize other fields implicitly here,
     * because of the memset() above. */
}




































#pragma mark -

/*
 *----------------------------------------------------------------------
 *
 * XGrabKeyboard --







>
>
>
>
>
>
>
>
>
>







|

|
|

|


>
>
>
>
>
>
>
>
|

|



|






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







599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
	privateWorkingText = nil;
	processingCompose = NO;
	if (composeWin) {
	    TkSendVirtualEvent(composeWin, "TkClearIMEMarkedText", NULL);
	}
    }
}

- (void)cancelComposingText
{
    if (NS_KEYLOG) {
	TKLog(@"cancelComposingText");
    }
    [self deleteWorkingText];
    processingCompose = NO;
}

@end

/*
 * Set up basic fields in xevent for keyboard input.
 */

static void
setupXEvent(XEvent *xEvent, Tk_Window tkwin, NSUInteger modifiers)
{
    unsigned int state = 0;
    Display *display = Tk_Display(tkwin);

    if (tkwin == NULL) {
	return;
    }
    if (modifiers) {
	state = (modifiers & NSAlphaShiftKeyMask ? LockMask    : 0) |
	        (modifiers & NSShiftKeyMask      ? ShiftMask   : 0) |
	        (modifiers & NSControlKeyMask    ? ControlMask : 0) |
	        (modifiers & NSCommandKeyMask    ? Mod1Mask    : 0) |
	        (modifiers & NSAlternateKeyMask  ? Mod2Mask    : 0) |
	        (modifiers & NSNumericPadKeyMask ? Mod3Mask    : 0) |
	        (modifiers & NSFunctionKeyMask   ? Mod4Mask    : 0) ;
    }
    memset(xEvent, 0, sizeof(XEvent));
    xEvent->xany.serial = LastKnownRequestProcessed(display);
    xEvent->xany.display = Tk_Display(tkwin);
    xEvent->xany.window = Tk_WindowId(tkwin);

    xEvent->xkey.root = XRootWindow(display, 0);
    xEvent->xkey.time = TkpGetMS();
    xEvent->xkey.state = state;
    xEvent->xkey.same_screen = true;
    /* No need to initialize other fields implicitly here,
     * because of the memset() above. */
}

static void
setXEventPoint(
    XEvent *xEvent,
    Tk_Window tkwin,
    NSWindow *w)
{
    TkWindow *winPtr = (TkWindow *) tkwin;
    NSPoint local = [w  mouseLocationOutsideOfEventStream];
    NSPoint global = [w tkConvertPointToScreen: local];
    int win_x, win_y;

    if (Tk_IsEmbedded(winPtr)) {
	TkWindow *contPtr = TkpGetOtherWindow(winPtr);
	if (Tk_IsTopLevel(contPtr)) {
	    local.x -= contPtr->wmInfoPtr->xInParent;
	    local.y -= contPtr->wmInfoPtr->yInParent;
	} else {
	    TkWindow *topPtr = TkMacOSXGetHostToplevel(winPtr)->winPtr;
	    local.x -= (topPtr->wmInfoPtr->xInParent + contPtr->changes.x);
	    local.y -= (topPtr->wmInfoPtr->yInParent + contPtr->changes.y);
	}
    } else if (winPtr->wmInfoPtr != NULL) {
	local.x -= winPtr->wmInfoPtr->xInParent;
	local.y -= winPtr->wmInfoPtr->yInParent;
    }
    tkwin = Tk_TopCoordsToWindow(tkwin, local.x, local.y, &win_x, &win_y);
    local.x = win_x;
    local.y = win_y;
    global.y = TkMacOSXZeroScreenHeight() - global.y;
    xEvent->xbutton.x = local.x;
    xEvent->xbutton.y = local.y;
    xEvent->xbutton.x_root = global.x;
    xEvent->xbutton.y_root = global.y;
}

#pragma mark -

/*
 *----------------------------------------------------------------------
 *
 * XGrabKeyboard --
702
703
704
705
706
707
708
709



710


711
712
713
714
715
716
717


718
719
720
721
722
723
724
725
726
727
728

729

730
731
732
733


734
735




736
737
738
739
740




741
742
743
744
745
746
747

748
749

750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
}

/*
 *----------------------------------------------------------------------
 *
 * Tk_SetCaretPos --
 *
 *	This enables correct placement of the XIM caret. This is called by



 *	widgets to indicate their cursor placement, and the caret location is


 *	used by TkpGetString to place the XIM caret.
 *
 * Results:
 *	None
 *
 * Side effects:
 *	None


 *
 *----------------------------------------------------------------------
 */

void
Tk_SetCaretPos(
    Tk_Window tkwin,
    int x,
    int y,
    int height)
 {

    TkCaret *caretPtr = &(((TkWindow *) tkwin)->dispPtr->caret);


    /*
     * Prevent processing anything if the values haven't changed. Windows only
     * has one display, so we can do this with statics.


     */





    if ((caretPtr->winPtr == ((TkWindow *) tkwin))
	    && (caretPtr->x == x) && (caretPtr->y == y)) {
	return;
    }





    caretPtr->winPtr = ((TkWindow *) tkwin);
    caretPtr->x = x;
    caretPtr->y = y;
    caretPtr->height = height;

    /*
     * As in Windows, adjust to the toplevel to get the coords right.

     */


    while (!Tk_IsTopLevel(tkwin)) {
	x += Tk_X(tkwin);
	y += Tk_Y(tkwin);
	tkwin = Tk_Parent(tkwin);
	if (tkwin == NULL) {
	    return;
	}
    }

    /*
     * But adjust for fact that NS uses flipped view.
     */

    y = Tk_Height(tkwin) - y;

    caret_x = x;
    caret_y = y;
    caret_height = height;
}


static unsigned convert_ns_to_X_keysym[] =
{
    NSHomeFunctionKey,		0x50,
    NSLeftArrowFunctionKey,	0x51,
    NSUpArrowFunctionKey,	0x52,
    NSRightArrowFunctionKey,	0x53,
    NSDownArrowFunctionKey,	0x54,
    NSPageUpFunctionKey,	0x55,
    NSPageDownFunctionKey,	0x56,
    NSEndFunctionKey,		0x57,
    NSBeginFunctionKey,		0x58,
    NSSelectFunctionKey,	0x60,
    NSPrintFunctionKey,		0x61,
    NSExecuteFunctionKey,	0x62,
    NSInsertFunctionKey,	0x63,
    NSUndoFunctionKey,		0x65,
    NSRedoFunctionKey,		0x66,
    NSMenuFunctionKey,		0x67,
    NSFindFunctionKey,		0x68,
    NSHelpFunctionKey,		0x6A,
    NSBreakFunctionKey,		0x6B,

    NSF1FunctionKey,		0xBE,
    NSF2FunctionKey,		0xBF,
    NSF3FunctionKey,		0xC0,
    NSF4FunctionKey,		0xC1,
    NSF5FunctionKey,		0xC2,
    NSF6FunctionKey,		0xC3,
    NSF7FunctionKey,		0xC4,
    NSF8FunctionKey,		0xC5,
    NSF9FunctionKey,		0xC6,
    NSF10FunctionKey,		0xC7,
    NSF11FunctionKey,		0xC8,
    NSF12FunctionKey,		0xC9,
    NSF13FunctionKey,		0xCA,
    NSF14FunctionKey,		0xCB,
    NSF15FunctionKey,		0xCC,
    NSF16FunctionKey,		0xCD,
    NSF17FunctionKey,		0xCE,
    NSF18FunctionKey,		0xCF,
    NSF19FunctionKey,		0xD0,
    NSF20FunctionKey,		0xD1,
    NSF21FunctionKey,		0xD2,
    NSF22FunctionKey,		0xD3,
    NSF23FunctionKey,		0xD4,
    NSF24FunctionKey,		0xD5,

    NSBackspaceCharacter,	0x08,  /* 8: Not on some KBs. */
    NSDeleteCharacter,		0xFF,  /* 127: Big 'delete' key upper right. */
    NSDeleteFunctionKey,	0x9F,  /* 63272: Del forw key off main array. */

    NSTabCharacter,		0x09,
    0x19,			0x09,  /* left tab->regular since pass shift */
    NSCarriageReturnCharacter,	0x0D,
    NSNewlineCharacter,		0x0D,
    NSEnterCharacter,		0x8D,

    0x1B,			0x1B   /* escape */
};


static unsigned
isFunctionKey(
    unsigned code)
{
    const unsigned last_keysym = (sizeof(convert_ns_to_X_keysym)
                                / sizeof(convert_ns_to_X_keysym[0]));
    unsigned keysym;

    for (keysym = 0; keysym < last_keysym; keysym += 2) {
	if (code == convert_ns_to_X_keysym[keysym]) {
	    return 0xFF00 | convert_ns_to_X_keysym[keysym + 1];
	}
    }
    return 0;
}

/*
 * Local Variables:
 * mode: objc
 * c-basic-offset: 4
 * fill-column: 79
 * coding: utf-8
 * End:
 */







|
>
>
>
|
>
>
|





|
>
>











>
|
>


<
|
>
>


>
>
>
>
|
|



>
>
>
>
|





|
>


>








<
<
<
<
<
<
<

|
<


<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823

824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860







861
862

863
864














































































865
866
867
868
869
870
871
872
}

/*
 *----------------------------------------------------------------------
 *
 * Tk_SetCaretPos --
 *
 *	This enables correct placement of the popups used for character
 *      selection by the NSTextInputClient.  It gets called by text entry
 *      widgets whenever the cursor is drawn.  It does nothing if the widget's
 *      NSWindow is not the current KeyWindow.  Otherwise it udpates the
 *      display's caret structure and records the caret geometry in static
 *      variables for use by the NSTextInputClient implementation.  Any
 *      widget passed to this function will be marked as being able to input
 *      text by setting the TK_CAN_INPUT_TEXT flag.
 *
 * Results:
 *	None
 *
 * Side effects:
 *      Sets the CAN_INPUT_TEXT flag on the widget passed as tkwin.  May update
 *      the display's caret structure as well as the static variables caret_x,
 *      caret_y and caret_height.
 *
 *----------------------------------------------------------------------
 */

void
Tk_SetCaretPos(
    Tk_Window tkwin,
    int x,
    int y,
    int height)
 {
    TkWindow *winPtr = (TkWindow *) tkwin;
    TkCaret *caretPtr = &(winPtr->dispPtr->caret);
    NSWindow *w = TkMacOSXDrawableWindow(Tk_WindowId(tkwin));

    /*

     * Register this widget as being capable of text input, so we know we
     * should process (appropriate) key events for this window with the
     * NSTextInputClient protocol.
     */

    winPtr->flags |= TK_CAN_INPUT_TEXT;
    if (w && ![w isKeyWindow]) {
	return;
    }
    if ((caretPtr->winPtr == winPtr
	 && caretPtr->x == x) && (caretPtr->y == y)) {
	return;
    }

    /*
     * Update the display's caret information.
     */

    caretPtr->winPtr = winPtr;
    caretPtr->x = x;
    caretPtr->y = y;
    caretPtr->height = height;

    /*
     * Record the caret geometry in static variables for use when processing
     * key events.  We use the TKContextView coordinate system for this.
     */

    caret_height = height;
    while (!Tk_IsTopLevel(tkwin)) {
	x += Tk_X(tkwin);
	y += Tk_Y(tkwin);
	tkwin = Tk_Parent(tkwin);
	if (tkwin == NULL) {
	    return;
	}
    }







    caret_x = x;
    caret_y = Tk_Height(tkwin) - y;

}















































































/*
 * Local Variables:
 * mode: objc
 * c-basic-offset: 4
 * fill-column: 79
 * coding: utf-8
 * End:
 */

Changes to macosx/tkMacOSXKeyboard.c.

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
212
213
214
215
216
217
218
219
220
221

222




223
224
225
226
227
228
229

230
231
232
233
234
235
236
237
238
239

240

241
242
243



244

245
246
247
248

249

250

251
252
253
254
255
256
257
258
259
260
261



262
263
264
265
266
267
268
269
270
271
272
273
274

275
276
277
278

279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326

327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347


348
349
350

351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368


369
370
371
372


373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388







389
390
391
392
393

394
395




396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426

427
428
429
430
431
432
433
434
435
436
/*
 * tkMacOSXKeyboard.c --
 *
 *	Routines to support keyboard events on the Macintosh.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 * Copyright 2001-2009, Apple Inc.
 * Copyright (c) 2005-2009 Daniel A. Steffen <[email protected]>

 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tkMacOSXPrivate.h"
#include "tkMacOSXEvent.h"
#include "tkMacOSXConstants.h"


/*




 * A couple of simple definitions to make code a bit more self-explaining.
 *
 * For the assignments of Mod1==meta==command and Mod2==alt==option, see also

 * tkMacOSXMouseEvent.c.





 */

#define LATIN1_MAX	 255
#define MAC_KEYCODE_MAX	 0x7F
#define MAC_KEYCODE_MASK 0x7F
#define COMMAND_MASK	 Mod1Mask
#define OPTION_MASK	 Mod2Mask


/*



 * Tables enumerating the special keys defined on Mac keyboards. These are
 * necessary for correct keysym mappings for all keys where the keysyms are
 * not identical with their ASCII or Latin-1 code points.
 */






typedef struct {
    int keycode;		/* Macintosh keycode. */
    KeySym keysym;		/* X windows keysym. */
} KeyInfo;

/*
 * Notes on keyArray:
 *
 * 0x34, XK_Return - Powerbooks use this and some keymaps define it.
 *
 * 0x4C, XK_Return - XFree86 and Apple's X11 call this one XK_KP_Enter.
 *
 * 0x47, XK_Clear - This key is NumLock when used on PCs, but Mac
 * applications don't use it like that, nor does Apple's X11.




 *
 * All other keycodes are taken from the published ADB keyboard layouts.
 */

static KeyInfo keyArray[] = {
    {0x24,	XK_Return},
    {0x30,	XK_Tab},
    {0x33,	XK_BackSpace},
    {0x34,	XK_Return},
    {0x35,	XK_Escape},

    {0x47,	XK_Clear},
    {0x4C,	XK_KP_Enter},




    {0x72,	XK_Help},
    {0x73,	XK_Home},
    {0x74,	XK_Page_Up},
    {0x75,	XK_Delete},
    {0x77,	XK_End},
    {0x79,	XK_Page_Down},











    {0x7B,	XK_Left},
    {0x7C,	XK_Right},
    {0x7D,	XK_Down},
    {0x7E,	XK_Up},







    {0,		0}
};







static KeyInfo virtualkeyArray[] = {
    {122,	XK_F1},
    {120,	XK_F2},
    {99,	XK_F3},
    {118,	XK_F4},
    {96,	XK_F5},
    {97,	XK_F6},
    {98,	XK_F7},
    {100,	XK_F8},
    {101,	XK_F9},
    {109,	XK_F10},
    {103,	XK_F11},
    {111,	XK_F12},
    {105,	XK_F13},
    {107,	XK_F14},
    {113,	XK_F15},
    {0,		0}
};














#define NUM_MOD_KEYCODES 14
static KeyCode modKeyArray[NUM_MOD_KEYCODES] = {
    XK_Shift_L,
    XK_Shift_R,
    XK_Control_L,
    XK_Control_R,
    XK_Caps_Lock,
    XK_Shift_Lock,
    XK_Meta_L,
    XK_Meta_R,

    XK_Alt_L,

    XK_Alt_R,
    XK_Super_L,
    XK_Super_R,

    XK_Hyper_L,
    XK_Hyper_R,
};



static int initialized = 0;
static Tcl_HashTable keycodeTable;	/* keyArray hashed by keycode value. */
static Tcl_HashTable vkeyTable;		/* virtualkeyArray hashed by virtual
					 * keycode value. */


static int latin1Table[LATIN1_MAX+1];	/* Reverse mapping table for

					 * controls, ASCII and Latin-1. */



static int keyboardChanged = 1;

/*
 * Prototypes for static functions used in this file.
 */

static void	InitKeyMaps (void);
static void	InitLatin1Table(Display *display);
static int	XKeysymToMacKeycode(Display *display, KeySym keysym);
static int	KeycodeToUnicode(UniChar * uniChars, int maxChars,
			UInt16 keyaction, UInt32 keycode, UInt32 modifiers,
			UInt32 * deadKeyStatePtr);

#pragma mark TKApplication(TKKeyboard)

@implementation TKApplication(TKKeyboard)
- (void) keyboardChanged: (NSNotification *) notification
{
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
    TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
#endif
    keyboardChanged = 1;

}
@end

#pragma mark -

/*
 *----------------------------------------------------------------------
 *
 * InitKeyMaps --
 *
 *	Creates hash tables used by some of the functions in this file.
 *
 *	FIXME: As keycodes are defined to be in the limited range 0-127, it
 *	would be easier and more efficient to use directly initialized plain
 *	arrays and drop this function.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Allocates memory & creates some hash tables.
 *
 *----------------------------------------------------------------------
 */

static void
InitKeyMaps(void)
{
    Tcl_HashEntry *hPtr;
    KeyInfo *kPtr;

    int dummy;


    Tcl_InitHashTable(&keycodeTable, TCL_ONE_WORD_KEYS);
    for (kPtr = keyArray; kPtr->keycode != 0; kPtr++) {


	hPtr = Tcl_CreateHashEntry(&keycodeTable, INT2PTR(kPtr->keycode),
		&dummy);
	Tcl_SetHashValue(hPtr, INT2PTR(kPtr->keysym));





    }











    Tcl_InitHashTable(&vkeyTable, TCL_ONE_WORD_KEYS);




    for (kPtr = virtualkeyArray; kPtr->keycode != 0; kPtr++) {
	hPtr = Tcl_CreateHashEntry(&vkeyTable, INT2PTR(kPtr->keycode),
		&dummy);
	Tcl_SetHashValue(hPtr, INT2PTR(kPtr->keysym));
    }

    initialized = 1;
}

/*
 *----------------------------------------------------------------------
 *
 * InitLatin1Table --
 *

 *	Creates a simple table to be used for mapping from keysyms to keycodes.
 *	Always needs to be called before using latin1Table, because the


 *	keyboard layout may have changed, and than the table must be
 *	re-computed.
 *
 * Results:
 *	None.
 *
 * Side effects:

 *	Sets the global latin1Table.
 *
 *----------------------------------------------------------------------
 */

static void
InitLatin1Table(
    Display *display)
{
    int keycode;
    KeySym keysym;
    int state;
    int modifiers;


    memset(latin1Table, 0, sizeof(latin1Table));





    /*
     * In the common X11 implementations, a keymap has four columns
     * "plain", "Shift", "Mode_switch" and "Mode_switch + Shift". We don't
     * use "Mode_switch", but we use "Option" instead. (This is similar to
     * Apple's X11 implementation, where "Mode_switch" is used as an alias
     * for "Option".)

     *
     * So here we go through all 4 columns of the keymap and find all
     * Latin-1 compatible keycodes. We go through the columns back-to-front
     * from the more exotic columns to the more simple, so that simple
     * keycode-modifier combinations are preferred in the resulting table.
     */

    for (state = 3; state >= 0; state--) {
	modifiers = 0;
	if (state & 1) {

	    modifiers |= shiftKey;

	}
	if (state & 2) {
	    modifiers |= optionKey;



	}


	for (keycode = 0; keycode <= MAC_KEYCODE_MAX; keycode++) {
	    keysym = XKeycodeToKeysym(display,keycode<<16,state);
	    if (keysym <= LATIN1_MAX) {

		latin1Table[keysym] = keycode | modifiers;

	    }

	}
    }
}

/*
 *----------------------------------------------------------------------
 *
 * KeycodeToUnicode --
 *
 *	Given MacOS key event data this function generates the Unicode
 *	characters. It does this using OS resources and APIs.



 *
 *	The parameter deadKeyStatePtr can be NULL, if no deadkey handling is
 *	needed.
 *
 *	This function is called from XKeycodeToKeysym() in tkMacOSKeyboard.c.
 *
 * Results:
 *	The number of characters generated if any, 0 if we are waiting for
 *	another byte of a dead-key sequence. Fills in the uniChars array with a
 *	Unicode string.
 *
 * Side Effects:
 *	None

 *
 *----------------------------------------------------------------------
 */


static int
KeycodeToUnicode(
    UniChar *uniChars,
    int maxChars,
    UInt16 keyaction,
    UInt32 keycode,
    UInt32 modifiers,
    UInt32 *deadKeyStatePtr)
{
    static const void *uchr = NULL;
    static UInt32 keyboardType = 0;
    UniCharCount actuallength = 0;

    if (keyboardChanged) {
	TISInputSourceRef currentKeyboardLayout =
		TISCopyCurrentKeyboardLayoutInputSource();

	if (currentKeyboardLayout) {
	    CFDataRef keyLayoutData = (CFDataRef) TISGetInputSourceProperty(
		    currentKeyboardLayout, kTISPropertyUnicodeKeyLayoutData);

	    if (keyLayoutData) {
		uchr = CFDataGetBytePtr(keyLayoutData);
		keyboardType = LMGetKbdType();
	    }
	    CFRelease(currentKeyboardLayout);
	}
	keyboardChanged = 0;
    }
    if (uchr) {
	OptionBits options = 0;
	UInt32 dummyState;
	OSStatus err;

	keycode &= 0xFF;
	modifiers = (modifiers >> 8) & 0xFF;

	if (!deadKeyStatePtr) {
	    options = kUCKeyTranslateNoDeadKeysMask;
	    dummyState = 0;
	    deadKeyStatePtr = &dummyState;
	}

	err = ChkErr(UCKeyTranslate, uchr, keycode, keyaction, modifiers,
		keyboardType, options, deadKeyStatePtr, maxChars,
		&actuallength, uniChars);

	if (!actuallength && *deadKeyStatePtr) {

	    /*
	     * More data later
	     */

	    return 0;
	}
	*deadKeyStatePtr = 0;
	if (err != noErr) {
	    actuallength = 0;
	}
    }
    return actuallength;
}

/*
 *----------------------------------------------------------------------
 *
 * XKeycodeToKeysym --
 *
 *	Translate from a system-dependent keycode to a system-independent
 *	keysym.


 *
 * Results:
 *	Returns the translated keysym, or NoSymbol on failure.

 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

KeySym
XKeycodeToKeysym(
    Display* display,
    KeyCode keycode,
    int index)
{
    Tcl_HashEntry *hPtr;
    int newKeycode;
    UniChar newChar;

    (void) display; /*unused*/



    if (!initialized) {
	InitKeyMaps();
    }



    /*
     * When determining what keysym to produce we first check to see if the key
     * is a function key. We then check to see if the character is another
     * non-printing key. Finally, we return the key syms for all ASCII and
     * Latin-1 chars.
     */

    newKeycode = keycode >> 16;

    if ((keycode & 0xFFFF) >= 0xF700) { /* NSEvent.h function key unicodes */
	hPtr = Tcl_FindHashEntry(&vkeyTable, INT2PTR(newKeycode));
	if (hPtr != NULL) {
	    return (KeySym) Tcl_GetHashValue(hPtr);
	}
    }







    hPtr = Tcl_FindHashEntry(&keycodeTable, INT2PTR(newKeycode));
    if (hPtr != NULL) {
	return (KeySym) Tcl_GetHashValue(hPtr);
    }


    /*
     * Add in the Mac modifier flags for shift and option.




     */

    if (index & 1) {
	newKeycode |= shiftKey;
    }
    if (index & 2) {
	newKeycode |= optionKey;
    }

    newChar = 0;
    KeycodeToUnicode(&newChar, 1, kUCKeyActionDown, newKeycode & 0x00FF,
	    newKeycode & 0xFF00, NULL);

    /*
     * X11 keysyms are identical to Unicode for ASCII and Latin-1. Give up for
     * other characters for now.
     */

    if ((newChar >= XK_space) && (newChar <= LATIN1_MAX)) {
	return newChar;
    }

    return NoSymbol;
}

/*
 *----------------------------------------------------------------------
 *
 * TkpGetString --
 *
 *	Retrieve the string equivalent for the given keyboard event.

 *
 * Results:
 *	Returns the UTF string.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */









>








>
>

>
>
>
>
|

<
>
|
>
>
>
>
>
|
|
<
<
<
<
<
|
|
<
>
>
>
|
<
<
<
>
>
>
>
>
|
<
<
<
<
|
|
|
|
|
|
|
|
|
|
>
>
>
>

|
<
|
<
<
<
|
|
|
|
|
|
>
>
>
|
<
<
<
|
|
|
>
>
>
>
>
>
>
>
>
>
|
<
<
<
<
>
>
>
>
>
>
|
<
<
>
>
>
>
>
>
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
>
>
>
>
>
>
>
>
>
>
>
>
>

|
<
<
<
<
<
<
<
<
<
>
|
>
|
<
<
>
|
<
<
>

>
|
|
|
|
>

<
>
|
>

>
|





|
|
<
|
|










|
>








|



<
<
<
<










|


|
>
|

>
|
|
>
>
|
|

>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
|
|
|
|

>
|





|

>
|
|
>
>
|
<





>
|





|
<

|
<
|
|

>
|
>
>
>
>
|

<
<
<
|
|
>
|
|
<
|
|
<
|
|
|
|
>
|
>
|
<
<
>
>
>
|
>
|
|
<
|
>
|
>
|
>







|

|
|
>
>
>


|

|



|
<


<
>




>

|



|



|












|






|




|

<





<
|


<

>

|

















|
|
>
>


|
>














|
<
<

>
>


|

>
>


|
|
<
<


<
<
<
|
|
|
|
|
>
>
>
>
>
>
>
|
|
|
|
|
>

<
>
>
>
>


<
<
<
<
<
<
|
<
|
|
|
<
<
<
<
|
|
|
|
|








|
>


|







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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239

240
241
242
243
244
245
246
247
248
249
250
251
252

253
254

255
256
257
258
259
260
261
262
263
264
265



266
267
268
269
270

271
272

273
274
275
276
277
278
279
280


281
282
283
284
285
286
287

288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316

317
318

319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360

361
362
363
364
365

366
367
368

369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412


413
414
415
416
417
418
419
420
421
422
423
424
425


426
427



428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446

447
448
449
450
451
452






453

454
455
456




457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
/*
 * tkMacOSXKeyboard.c --
 *
 *	Routines to support keyboard events on the Macintosh.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 * Copyright 2001-2009, Apple Inc.
 * Copyright (c) 2005-2009 Daniel A. Steffen <[email protected]>
 * Copyright (c) 2020 Marc Culler
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tkMacOSXPrivate.h"
#include "tkMacOSXEvent.h"
#include "tkMacOSXConstants.h"
#include "tkMacOSXKeysyms.h"

/*
 * About keyboards
 * ---------------
 * Keyboards are complicated.  This long comment is an attempt to provide
 * enough information about them to make it possible to read and understand
 * the code in this file.
 *

 * Every key on a keyboard is identified by a number between 0 and 127.  In
 * macOS, pressing or releasing a key on the keyboard generates an NSEvent of
 * type KeyDown, KeyUp or FlagsChanged.  The 8-bit identifier of the key that
 * was involved in this event is provided in the attribute [NSEvent keyCode].
 * Apple also refers to this number as a "Virtual KeyCode".  In this file, to
 * avoid confusion with other uses of the word keycode, we will refer to this
 * key identifier as a "virtual keycode", usually the value of a variable named
 * "virtual".
 *





 * Some of the keys on a keyboard, such as the Shift, Option, Command or
 * Control keys, are "modifier" keys.  The effect of pressing or releasing a

 * key depends on three quantities:
 *     - which key is being pressed or released
 *     - which modifier keys are being held down at the moment
 *     - the current keyboard layout



 * If the key is a modifier key then the effect of pressing or releasing it is
 * only to change the list of which modifier keys are being held down.  Apple
 * reports this by sending an NSEvent of type FlagsChanged.  X11 reports this
 * as a KeyPress or KeyRelease event for the modifier key.  Note that there may
 * be combinations of modifier key states and key presses which have no effect.
 *




 * In X11 every meaningful effect from a key action is identified by a 16 bit
 * value known as a keysym.  Every keysym has an associated string name, also
 * known as a keysym.  The Tk bind command uses the X11 keysym string to
 * specify a key event which should invoke a certain action and it provides the
 * numeric and symbolic keysyms to the bound proc as %N and %K respectively.
 * An X11 XEvent which reports a KeyPress or KeyRelease does not include the
 * keysym.  Instead it includes a platform-specific numerical value called a
 * keycode which is available to the bound procedure as %k.  A platform port of
 * Tk must provide functions which convert between keycodes and numerical
 * keysyms.  Conversion between numerical and symbolic keysyms is provided by
 * the generic Tk code, although platforms are allowed to provide their own by
 * defining the XKeysymToString and XStringToKeysym functions and undefining
 * the macro REDO_KEYSYM_LOOKUP.  This macOS port uses the conversion provided
 * by the generic code.
 *
 * When the keyboard focus is on a Tk widget which provides text input, there

 * are some X11 KeyPress events which cause text to be inserted.  We will call



 * these "printable" events.  On macOS the text which should be inserted is
 * contained in the xkeys.trans_chars field of a key XEvent as a
 * null-terminated unicode string encoded with a special Tcl encoding.  The
 * value of the trans_chars string in an Xevent depends on more than the three
 * items above.  It may also depend on the sequence of keypresses that preceded
 * the one being reported by the XEvent.  For example, on macOS an <Alt-e>
 * event does not cause text to be inserted but a following <a> event causes an
 * accented 'a' to be inserted.  The events in such a composition sequence,
 * other than the final one, are known as "dead-key" events.
 *



 * MacOS packages the information described above in a different way.  Every
 * meaningful effect from a key action *other than changing the state of
 * modifier keys* is identified by a unicode string which is provided as the
 * [NSEvent characters] attribute of a KeyDown or KeyUp event.  FlagsChanged
 * events do not have characters.  In principle, the characters attribute could
 * be an arbitrary unicode string but in practice it is always a single UTF-16
 * character which we usually store in a variable named keychar.  While the
 * keychar is a legal unicode code point, it does not necessarily represent a
 * glyph. MacOS uses unicode code points in the private-use range 0xF700-0xF8FF
 * for non-printable events which have no associated ASCII code point.  For
 * example, pressing the F2 key generates an NSEvent with the character 0xF705,
 * the Backspace key produces 0x7F (ASCII del) and the Delete key produces
 * 0xF728.
 *




 * With the exception of modifier keys, it is possible to translate between
 * numerical X11 keysyms and macOS keychars; this file constructs Tcl hash
 * tables to do this job, using data defined in the file tkMacOSXKeysyms.h.
 * The code here adopts the convention that the keychar of any modifier key
 * is MOD_KEYCHAR.  Keys which do not appear on any Macintosh keyboard, such
 * as the Menu key on PC keyboards, are assigned UNKNOWN_KEYCHAR.
 *


 * The macosx platform-specific scheme for generating a keycode when mapping an
 * NSEvent of type KeyUp, KeyDown or FlagsChanged to an XEvent of type KeyPress
 * or KeyRelease is as follows:
 *     keycode = (virtual << 24) | index << 22 | keychar
 * where index is a 2-bit quantity whose bits indicate the state of the Option
 * and Shift keys.
 *















 * A few remarks are in order.  First, we are using 32 bits for the keycode and


 * we are allowing room for up to 22 bits for the keychar.  This means that
 * there is enough room in the keycode to hold a UTF-32 character, which only
 * requires 21 bits.  Second, the KeyCode type for the keycode field in an
 * XEvent is currently defined as unsigned int, which was modified from the
 * unsigned short used in X11 in order to accomodate macOS. Finally, there is
 * no obstruction to generating KeyPress events for keys that represent letters
 * which do not exist on the current keyboard layout.  And different keyboard
 * layouts can assign a given letter to different keys.  So we need a
 * convention for what value to assign to "virtual" when computing the keycode
 * for a generated event.  The convention used here is as follows: If there is
 * a key on the current keyboard which produces the keychar, use the virtual
 * keycode of that key.  Otherwise set virtual = NO_VIRTUAL.
 */











/*
 * See tkMacOSXPrivate.h for macros and structures related to key event processing.
 */



/*
 * Hash tables and array used to translate between various key attributes.


 */

static Tcl_HashTable special2keysym;	/* Special virtual keycode to keysym */
static Tcl_HashTable keysym2keycode;	/* keysym to XEvent keycode */
static Tcl_HashTable keysym2unichar;	/* keysym to unichar */
static Tcl_HashTable unichar2keysym;	/* unichar to X11 keysym */
static Tcl_HashTable unichar2xvirtual;	/* unichar to virtual with index */
static UniChar xvirtual2unichar[512];	/* virtual with index to unichar */


/*
 * Flags.
 */

static BOOL initialized = NO;
static BOOL keyboardChanged = YES;

/*
 * Prototypes for static functions used in this file.
 */

static void	InitHashTables(void);
static void     UpdateKeymaps(void);

static int	KeyDataToUnicode(UniChar *uniChars, int maxChars,
			UInt16 keyaction, UInt32 virtual, UInt32 modifiers,
			UInt32 * deadKeyStatePtr);

#pragma mark TKApplication(TKKeyboard)

@implementation TKApplication(TKKeyboard)
- (void) keyboardChanged: (NSNotification *) notification
{
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
    TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
#endif
    keyboardChanged = YES;
    UpdateKeymaps();
}
@end

#pragma mark -

/*
 *----------------------------------------------------------------------
 *
 * InitHashTables --
 *
 *	Creates hash tables used by some of the functions in this file.
 *




 * Results:
 *	None.
 *
 * Side effects:
 *	Allocates memory & creates some hash tables.
 *
 *----------------------------------------------------------------------
 */

static void
InitHashTables(void)
{
    Tcl_HashEntry *hPtr;
    const KeyInfo *kPtr;
    const KeysymInfo *ksPtr;
    int dummy, index;

    Tcl_InitHashTable(&special2keysym, TCL_ONE_WORD_KEYS);
    Tcl_InitHashTable(&keysym2keycode, TCL_ONE_WORD_KEYS);
    for (kPtr = keyArray; kPtr->virtual != 0; kPtr++) {
	MacKeycode macKC;
	macKC.v.o_s = 0;
	hPtr = Tcl_CreateHashEntry(&special2keysym, INT2PTR(kPtr->virtual),
				   &dummy);
	Tcl_SetHashValue(hPtr, INT2PTR(kPtr->keysym));
	hPtr = Tcl_CreateHashEntry(&keysym2keycode, INT2PTR(kPtr->keysym),
				   &dummy);
	macKC.v.virtual = kPtr->virtual;
	macKC.v.keychar = kPtr->keychar;
	Tcl_SetHashValue(hPtr, INT2PTR(macKC.uint));

	/*
	 * The Carbon framework does not work for finding the unicode character
	 * of a special key.  But that does not depend on the keyboard layout,
	 * so we can record the information here.
	 */

	for (index = 3; index >= 0; index--) {
	    macKC.v.o_s = index;
	    xvirtual2unichar[macKC.x.xvirtual] = macKC.x.keychar;
	}
    }
    Tcl_InitHashTable(&keysym2unichar, TCL_ONE_WORD_KEYS);
    Tcl_InitHashTable(&unichar2keysym, TCL_ONE_WORD_KEYS);
    for (ksPtr = keysymTable; ksPtr->keysym != 0; ksPtr++) {
	hPtr = Tcl_CreateHashEntry(&keysym2unichar, INT2PTR(ksPtr->keysym),
				   &dummy);
	Tcl_SetHashValue(hPtr, INT2PTR(ksPtr->keycode));
	hPtr = Tcl_CreateHashEntry(&unichar2keysym, INT2PTR(ksPtr->keycode),
				   &dummy);
	Tcl_SetHashValue(hPtr, INT2PTR(ksPtr->keysym));
    }
    UpdateKeymaps();
    initialized = YES;
}

/*
 *----------------------------------------------------------------------
 *
 * UpdateKeymaps --
 *
 *	Called when the keyboard changes to update the hash tables that provide
 *      maps between unicode characters and virtual keycodes with indexes.  In
 *      order for the map from characters to virtual keycodes to be
 *      well-defined we have to ignore virtual keycodes for keypad keys, since
 *      each keypad key has the same character as the corresponding key on the
 *      main keyboard.

 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Initializes, if necessary, and updates the unichar2xvirtual hash table
 *      and the xvirtual2unichar array.
 *
 *----------------------------------------------------------------------
 */

static void
UpdateKeymaps()

{
    static Bool keymapInitialized = false;

    Tcl_HashEntry *hPtr;
    int virtual, index, dummy;

    if (!keymapInitialized) {
	Tcl_InitHashTable(&unichar2xvirtual, TCL_ONE_WORD_KEYS);
	keymapInitialized = true;
    } else {
	Tcl_DeleteHashTable(&unichar2xvirtual);
	Tcl_InitHashTable(&unichar2xvirtual, TCL_ONE_WORD_KEYS);
    }
    /*



     * This loop goes backwards so that a lookup by keychar will provide the
     * minimal modifier mask.  Simpler combinations will overwrite more complex
     * ones when constructing the table.
     */


    for (index = 3; index >= 0; index--) {
        for (virtual = 0; virtual < 128; virtual++) {

	    MacKeycode macKC;
	    macKC.v = (keycode_v) {.virtual = virtual, .o_s = index, .keychar = 0};
	    int modifiers = INDEX2CARBON(index), result;
	    UniChar keychar = 0;
	    result = KeyDataToUnicode(&keychar, 1, kUCKeyActionDown, virtual,
				      modifiers, NULL);
	    if (keychar == 0x10) {



		/*
		 * This is a special key, handled in InitHashTables.
		 */

		continue;
	    }
	    macKC.v.keychar = keychar;

	    if (! ON_KEYPAD(virtual)) {
		hPtr = Tcl_CreateHashEntry(&unichar2xvirtual,
					   INT2PTR(macKC.x.keychar), &dummy);
		Tcl_SetHashValue(hPtr, INT2PTR(macKC.x.xvirtual));
            }
	    xvirtual2unichar[macKC.x.xvirtual] = macKC.x.keychar;
	}
    }
}

/*
 *----------------------------------------------------------------------
 *
 * KeyDataToUnicode --
 *
 *	Given MacOS key event data this function generates the keychar.  It
 *	does this by using OS resources from the Carbon framework.  Note that
 *      the Carbon functions used here are not aware of the keychars in the
 *      private-use range which macOS now uses for special keys.  For those
 *      keys this function returns 0x10 (ASCII dle).
 *
 *	The parameter deadKeyStatePtr can be NULL, if no deadkey handling is
 *	needed (which is always the case here).
 *
 *	This function is called in XKeycodeToKeysym and UpdateKeymaps.
 *
 * Results:
 *	The number of characters generated if any, 0 if we are waiting for
 *	another byte of a dead-key sequence.

 *
 * Side Effects:

 *	 Fills in the uniChars array with a Unicode string.
 *
 *----------------------------------------------------------------------
 */


static int
KeyDataToUnicode(
    UniChar *uniChars,
    int maxChars,
    UInt16 keyaction,
    UInt32 virtual,
    UInt32 modifiers,
    UInt32 *deadKeyStatePtr)
{
    static const void *layoutData = NULL;
    static UInt32 keyboardType = 0;
    UniCharCount actuallength = 0;

    if (keyboardChanged) {
	TISInputSourceRef currentKeyboardLayout =
		TISCopyCurrentKeyboardLayoutInputSource();

	if (currentKeyboardLayout) {
	    CFDataRef keyLayoutData = (CFDataRef) TISGetInputSourceProperty(
		    currentKeyboardLayout, kTISPropertyUnicodeKeyLayoutData);

	    if (keyLayoutData) {
		layoutData = CFDataGetBytePtr(keyLayoutData);
		keyboardType = LMGetKbdType();
	    }
	    CFRelease(currentKeyboardLayout);
	}
	keyboardChanged = 0;
    }
    if (layoutData) {
	OptionBits options = 0;
	UInt32 dummyState;
	OSStatus err;

	virtual &= 0xFF;
	modifiers = (modifiers >> 8) & 0xFF;

	if (!deadKeyStatePtr) {
	    options = kUCKeyTranslateNoDeadKeysMask;
	    dummyState = 0;
	    deadKeyStatePtr = &dummyState;
	}

	err = ChkErr(UCKeyTranslate, layoutData, virtual, keyaction, modifiers,
		keyboardType, options, deadKeyStatePtr, maxChars,
		&actuallength, uniChars);

	if (!actuallength && *deadKeyStatePtr) {

	    /*
	     * We are waiting for another key.
	     */

	    return 0;
	}
	*deadKeyStatePtr = 0;
	if (err != noErr) {
	    actuallength = 0;
	}
    }
    return actuallength;
}

/*
 *----------------------------------------------------------------------
 *
 * XKeycodeToKeysym --
 *
 *	This is a stub function which translates from the keycode used in an
 *      XEvent to a numerical keysym.  On macOS, the display parameter is
 *      ignored and only the the virtual keycode stored in the .virtual bitfield
 *      of a MacKeycode.v.
 *
 * Results:
 *      Returns the corresponding numerical keysym, or NoSymbol if the keysym
 *      cannot be found.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

KeySym
XKeycodeToKeysym(
    Display* display,
    KeyCode keycode,
    int index)
{
    Tcl_HashEntry *hPtr;
    MacKeycode macKC;


    (void) display; /*unused*/
    int modifiers, result;
    UniChar keychar = 0;

    if (!initialized) {
	InitHashTables();
    }
    macKC.uint = keycode;
    macKC.v.o_s = index;

    /*
     * First check if the virtual keycode corresponds to a special key, such as
     * an Fn function key or Tab, Backspace, Home, End, etc.


     */




    hPtr = Tcl_FindHashEntry(&special2keysym, INT2PTR(macKC.v.virtual));
    if (hPtr != NULL) {
	return (KeySym) Tcl_GetHashValue(hPtr);
    }

    /*
     * If the virtual value in this keycode does not correspond to an actual
     * key in the current keyboard layout, try using its keychar to look up a
     * keysym.
     */

    if (macKC.v.virtual > 127) {
	hPtr = Tcl_FindHashEntry(&unichar2keysym, INT2PTR(macKC.v.keychar));
	if (hPtr != NULL) {
	    return (KeySym) Tcl_GetHashValue(hPtr);
	}
    }

    /*

     * If the virtual keycode does belong to a key, use the virtual and the
     * Option-Shift from index to look up a keychar by using the Carbon
     * Framework; then translate the keychar to a keysym using the
     * unicode2keysym hash table.
     */







    modifiers = INDEX2CARBON(macKC.v.o_s);

    result = KeyDataToUnicode(&keychar, 1, kUCKeyActionDown, macKC.v.virtual,
			      modifiers, NULL);
    if (result) {




	hPtr = Tcl_FindHashEntry(&unichar2keysym, INT2PTR(keychar));
	if (hPtr != NULL) {
	    return (KeySym) Tcl_GetHashValue(hPtr);
	}
    }
    return NoSymbol;
}

/*
 *----------------------------------------------------------------------
 *
 * TkpGetString --
 *
 *	This is a stub function which retrieves the string stored in the
 *      transchars field of an XEvent and converts it to a Tcl_DString.
 *
 * Results:
 *	Returns a pointer to the string value of the DString.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

451
452
453
454
455
456
457
458

459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492

493
494
495
496
497
498
499
}

/*
 *----------------------------------------------------------------------
 *
 * XGetModifierMapping --
 *
 *	Fetch the current keycodes used as modifiers.

 *
 * Results:
 *	Returns a new modifier map.
 *
 * Side effects:
 *	Allocates a new modifier map data structure.
 *
 *----------------------------------------------------------------------
 */

XModifierKeymap *
XGetModifierMapping(
    Display *display)
{
    XModifierKeymap *modmap;

    (void) display; /*unused*/

    /*
     * MacOSX doesn't use the key codes for the modifiers for anything, and we
     * don't generate them either. So there is no modifier map.
     */
    modmap = ckalloc(sizeof(XModifierKeymap));
    modmap->max_keypermod = 0;
    modmap->modifiermap = NULL;
    return modmap;
}

/*
 *----------------------------------------------------------------------
 *
 * XFreeModifiermap --
 *
 *	Deallocate a modifier map that was created by XGetModifierMapping.

 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Frees the datastructure referenced by modmap.
 *







|
>


|













<
<
<
<
<
<











|
>







496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520






521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
}

/*
 *----------------------------------------------------------------------
 *
 * XGetModifierMapping --
 *
 *	X11 stub function to get the keycodes used as modifiers.  This
 *      is never called by the macOS port.
 *
 * Results:
 *	Returns a newly allocated modifier map.
 *
 * Side effects:
 *	Allocates a new modifier map data structure.
 *
 *----------------------------------------------------------------------
 */

XModifierKeymap *
XGetModifierMapping(
    Display *display)
{
    XModifierKeymap *modmap;







    modmap = ckalloc(sizeof(XModifierKeymap));
    modmap->max_keypermod = 0;
    modmap->modifiermap = NULL;
    return modmap;
}

/*
 *----------------------------------------------------------------------
 *
 * XFreeModifiermap --
 *
 *	Deallocates a modifier map that was created by XGetModifierMapping.
 *      This is also never called by the macOS port.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Frees the datastructure referenced by modmap.
 *
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
}

/*
 *----------------------------------------------------------------------
 *
 * XKeysymToString, XStringToKeysym --
 *
 *	These X window functions map keysyms to strings & strings to keysyms.
 *	However, Tk already does this for the most common keysyms. Therefore,
 *	these functions only need to support keysyms that will be specific to
 *	the Macintosh. Currently, there are none.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *







|
|
|
|







553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
}

/*
 *----------------------------------------------------------------------
 *
 * XKeysymToString, XStringToKeysym --
 *
 *	These X11 stub functions map keysyms to strings & strings to keysyms.
 *      A platform can do its own conversion by defining these and undefining
 *      REDO_KEYSYM_LOOKUP.  The macOS port defines REDO_KEYSYM_LOOKUP so these
 *      are never called and Tk does the conversion for us.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644

645

646
647

648
649
650
651
652
653
654



655


656

657



658




659






660

661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678

679
680
681





682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702

703

704
705
706








707
708
709
710
711
712
713










714
715
716

717
718
719
720
721
722
723
724

725
726
727
728
729
730
731
732
733
734
735
736

737
738
739
740
741
742
743
744
745
746

747
748
749
750
751
752
753
754
755
756
757


758
759
760
761
762
763
764
765
766
767
768
769
770
771
772

773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801

802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
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
{
    return NoSymbol;
}

/*
 *----------------------------------------------------------------------
 *
 * XKeysymToMacKeycode --
 *
 *	An internal function like XKeysymToKeycode but only generating the Mac
 *	specific keycode plus the modifiers Shift and Option.
 *
 * Results:
 *	A Mac keycode with the actual keycode in the low byte and Mac-style
 *	modifier bits in the high byte.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

static int
XKeysymToMacKeycode(
    Display *display,
    KeySym keysym)
{
    KeyInfo *kPtr;
    if (keysym <= LATIN1_MAX) {
	/*
	 * Handle keysyms in the Latin-1 range where keysym and Unicode
	 * character code point are the same.
	 */

	if (keyboardChanged) {
	    InitLatin1Table(display);
	    keyboardChanged = 0;
	}
	return latin1Table[keysym];
    }

    /*
     * Handle special keys from our exception tables. Don't mind if this is
     * slow, neither the test suite nor [event generate] need to be optimized
     * (we hope).
     */

    for (kPtr = keyArray; kPtr->keycode != 0; kPtr++) {
	if (kPtr->keysym == keysym) {
	    return kPtr->keycode;
	}
    }
    for (kPtr = virtualkeyArray; kPtr->keycode != 0; kPtr++) {
	if (kPtr->keysym == keysym) {
	    return kPtr->keycode;
	}
    }

    /*
     * Modifier keycodes only come from generated events.  No translation
     * is needed.
     */

    for (int i=0; i < NUM_MOD_KEYCODES; i++) {
	if (keysym == modKeyArray[i]) {
	    return keysym;
	}
    }

    /*
     * For other keysyms (not Latin-1 and not special keys), we'd need a
     * generic keysym-to-unicode table. We don't have that, so we give up here.
     */

    return 0;
}

/*
 *----------------------------------------------------------------------
 *
 * XKeysymToKeycode --
 *
 *	The function XKeysymToKeycode takes an X11 keysym and converts it into
 *	a Mac keycode. It is in the stubs table for compatibility but not used
 *	anywhere in the core.
 *
 * Results:
 *	A 32 bit keycode with the the mac keycode (without modifiers) in the
 *	higher 16 bits of the keycode and the ASCII or Latin-1 code in the
 *	lower 8 bits of the keycode.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

KeyCode
XKeysymToKeycode(
    Display* display,
    KeySym keysym)
{

    int macKeycode = XKeysymToMacKeycode(display, keysym);

    KeyCode result;


    /*
     * See also TkpSetKeycodeAndState. The 0x0010 magic is used in
     * XKeycodeToKeysym. For special keys like XK_Return the lower 8 bits of
     * the keysym are usually a related ASCII control code.
     */

    if ((keysym >= XK_F1) && (keysym <= XK_F35)) {



	result = 0x0010;


    } else {

	result = 0x00FF & keysym;



    }




    result |= (macKeycode & MAC_KEYCODE_MASK) << 16;








    return result;
}

/*
 *----------------------------------------------------------------------
 *
 * TkpSetKeycodeAndState --
 *
 *	The function TkpSetKeycodeAndState takes a keysym and fills in the
 *	appropriate members of an XEvent. It is similar to XKeysymToKeycode,
 *	but it also sets the modifier mask in the XEvent. It is used by [event
 *	generate] and it is in the stubs table.
 *
 * Results:
 *	Fills an XEvent, sets the member xkey.keycode with a keycode
 *	formatted the same as XKeysymToKeycode and the member xkey.state with
 *	the modifiers implied by the keysym. Also fills in xkey.trans_chars,
 *	so that the actual characters can be retrieved later.

 *
 * Side effects:
 *	None.





 *
 *----------------------------------------------------------------------
 */

void
TkpSetKeycodeAndState(
    Tk_Window tkwin,
    KeySym keysym,
    XEvent *eventPtr)
{
    if (keysym == NoSymbol) {
	eventPtr->xkey.keycode = 0;
    } else if ( modKeyArray[0] <= keysym &&
		keysym <= modKeyArray[NUM_MOD_KEYCODES - 1]) {
	/*
	 * Keysyms for pure modifiers only arise in generated events.
	 * We should just copy them to the keycode.
	 */
	eventPtr->xkey.keycode = keysym;
    } else {
	Display *display = Tk_Display(tkwin);

	int macKeycode = XKeysymToMacKeycode(display, keysym);


	/*
	 * See also XKeysymToKeycode.








	 */
	if ((keysym >= XK_F1) && (keysym <= XK_F35)) {
	    eventPtr->xkey.keycode = 0x0010;
	} else {
	    eventPtr->xkey.keycode = 0x00FF & keysym;
	}
	eventPtr->xkey.keycode |= (macKeycode & MAC_KEYCODE_MASK) << 16;











	if (shiftKey & macKeycode) {
	    eventPtr->xkey.state |= ShiftMask;

	}
	if (optionKey & macKeycode) {
	    eventPtr->xkey.state |= OPTION_MASK;
	}

	if (keysym <= LATIN1_MAX) {
	    int done = TkUniCharToUtf(keysym, eventPtr->xkey.trans_chars);


	    eventPtr->xkey.trans_chars[done] = 0;
	} else {
	    eventPtr->xkey.trans_chars[0] = 0;
	}
    }
}

/*
 *----------------------------------------------------------------------
 *
 * TkpGetKeySym --
 *

 *	Given an X KeyPress or KeyRelease event, map the keycode in the event
 *	into a keysym.
 *
 * Results:
 *	The return value is the keysym corresponding to eventPtr, or NoSymbol
 *	if no matching keysym could be found.
 *
 * Side effects:
 *	In the first call for a given display, keycode-to-keysym maps get
 *	loaded.

 *
 *----------------------------------------------------------------------
 */

KeySym
TkpGetKeySym(
    TkDisplay *dispPtr,		/* Display in which to map keycode. */
    XEvent *eventPtr)		/* Description of X event. */
{
    KeySym sym;
    int index;



    /*
     * Refresh the mapping information if it's stale.
     */

    if (dispPtr->bindInfoStale) {
	TkpInitKeymapInfo(dispPtr);
    }

    /*
     * Handle pure modifier keys specially. We use -1 as a signal for
     * this.
     */

    if (eventPtr->xany.send_event == -1) {

	int modifier = eventPtr->xkey.keycode & NSDeviceIndependentModifierFlagsMask;

	if (modifier == NSCommandKeyMask) {
	    return XK_Meta_L;
	} else if (modifier == NSShiftKeyMask) {
	    return XK_Shift_L;
	} else if (modifier == NSAlphaShiftKeyMask) {
	    return XK_Caps_Lock;
	} else if (modifier == NSAlternateKeyMask) {
	    return XK_Alt_L;
	} else if (modifier == NSControlKeyMask) {
	    return XK_Control_L;
	} else if (modifier == NSNumericPadKeyMask) {
	    return XK_Num_Lock;
	} else if (modifier == NSFunctionKeyMask) {
	    return XK_Super_L;
/*
	} else if (modifier == rightShiftKey) {
	    return XK_Shift_R;
	} else if (modifier == rightOptionKey) {
	    return XK_Alt_R;
	} else if (modifier == rightControlKey) {
	    return XK_Control_R;
*/
	} else {
	    /*
	     * If we get here, we probably need to implement something new.
	     */


	    return NoSymbol;
	}
    }

    /* If nbytes has been set, it's not a function key, but a regular key that
       has been translated in tkMacOSXKeyEvent.c; just use that. */
    if (eventPtr->xkey.nbytes) {
      return eventPtr->xkey.keycode;
    }

    /*
     * Figure out which of the four slots in the keymap vector to use for this
     * key. Refer to Xlib documentation for more info on how this computation
     * works. (Note: We use "Option" in keymap columns 2 and 3 where other
     * implementations have "Mode_switch".)
     */

    index = 0;

    /*
     * We want Option key combinations to use their base chars as keysyms, so
     * we ignore the option modifier here.
     */

#if 0
    if (eventPtr->xkey.state & OPTION_MASK) {
	index |= 2;
    }
#endif

    if ((eventPtr->xkey.state & ShiftMask)
	    || (/* (dispPtr->lockUsage != LU_IGNORE)
	    && */ (eventPtr->xkey.state & LockMask))) {
	index |= 1;
    }

    /*
     * First try of the actual translation.
     */

    sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode, index);

    /*
     * Special handling: If the key was shifted because of Lock, but lock is
     * only caps lock, not shift lock, and the shifted keysym isn't upper-case
     * alphabetic, then switch back to the unshifted keysym.
     */

    if ((index & 1) && !(eventPtr->xkey.state & ShiftMask)
	    /*&& (dispPtr->lockUsage == LU_CAPS)*/ ) {
	/*
	 * FIXME: Keysyms are only identical to Unicode for ASCII and Latin-1,
	 * so we can't use Tcl_UniCharIsUpper() for keysyms outside that range.
	 * This may be a serious problem here.
	 */

	if ((sym == NoSymbol) || (sym > LATIN1_MAX)
		|| !Tcl_UniCharIsUpper(sym)) {
	    index &= ~1;
	    sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode,
		    index);
	}
    }

    /*
     * Another bit of special handling: If this is a shifted key and there is
     * no keysym defined, then use the keysym for the unshifted key.
     */

    if ((index & 1) && (sym == NoSymbol)) {
	sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode,
		index & ~1);
    }
    return sym;
}

/*
 *--------------------------------------------------------------
 *
 * TkpInitKeymapInfo --
 *
 *	This procedure is invoked to scan keymap information to recompute stuff
 *	that's important for binding, such as the modifier key (if any) that
 *	corresponds to the "Mode_switch" keysym.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Keymap-related information in dispPtr is updated.
 *
 *--------------------------------------------------------------
 */

void
TkpInitKeymapInfo(
    TkDisplay *dispPtr)		/* Display for which to recompute keymap
				 * information. */
{
    dispPtr->bindInfoStale = 0;

    /*
     * Behaviours that are variable on X11 are defined constant on MacOSX.
     * lockUsage is only used above in TkpGetKeySym(), nowhere else currently.


     * There is no offical "Mode_switch" key.
     */

    dispPtr->lockUsage = LU_CAPS;



    dispPtr->modeModMask = 0;

#if 0
    /*
     * With this, <Alt> and <Meta> become synonyms for <Command> and <Option>
     * in bindings like they are (and always have been) in the keysyms that
     * are reported by KeyPress events. But the init scripts like text.tcl
     * have some disabling bindings for <Meta>, so we don't want this without
     * some changes in those scripts. See also bug #700311.
     */

    dispPtr->altModMask = OPTION_MASK;
    dispPtr->metaModMask = COMMAND_MASK;
#else
    dispPtr->altModMask = 0;
    dispPtr->metaModMask = 0;
#endif

    /*

     * MacOSX doesn't create a key event when a modifier key is pressed or
     * released.  However, it is possible to generate key events for
     * modifier keys, and this is done in the tests.  So we construct an array
     * containing the keycodes of the standard modifier keys from static data.
     */

    if (dispPtr->modKeyCodes != NULL) {
	ckfree(dispPtr->modKeyCodes);
    }
    dispPtr->numModKeyCodes = NUM_MOD_KEYCODES;
    dispPtr->modKeyCodes = (KeyCode *)ckalloc(NUM_MOD_KEYCODES * sizeof(KeyCode));
    for (int i = 0; i < NUM_MOD_KEYCODES; i++) {
	dispPtr->modKeyCodes[i] = modKeyArray[i];
    }
}












































/*
 * Local Variables:
 * mode: objc
 * c-basic-offset: 4
 * fill-column: 79
 * coding: utf-8
 * End:
 */







|

<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
|
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
|
<
<
<
<
<
|
<
<
<
<
|
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<









|


>
|
>
|
|
>

<
|
<


|
>
>
>
|
>
>
|
>
|
>
>
>
|
>
>
>
>
|
>
>
>
>
>
>
|
>
|







|
<
|
<


<
<
<
<
>


<
>
>
>
>
>



<








<
<
<
<
<
<
<

<
>
|
>


|
>
>
>
>
>
>
>
>

|
|
<
|

|
>
>
>
>
>
>
>
>
>
>
|
|
<
>
|
<
<
|
|
|
|
|
>
|
<
|









>
|
|






|
<
>











>
>










|
<


|
>
|
|
|

|

|

|

|

<
<
<
<
<
|

|

|

<
|
<
<
<
|
>




<
<
<
<
<
<



|
<


|
<
<
<
<
<
<
<
|
|

<

<
<
<
<
<
<

|


|


|
|
|


|
<
<
<
<
<
<
<
|
<
<
|
|








|
|
|









|
|
<





|












|
|
>
>




>
>
>


<
<
<
|
|
|
|


<
<
<


<


>
|
<
|
<








|



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








584
585
586
587
588
589
590
591
592












593











594






595





596










597




598





599




600


601













602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620

621

622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659

660

661
662




663
664
665

666
667
668
669
670
671
672
673

674
675
676
677
678
679
680
681







682

683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699

700
701
702
703
704
705
706
707
708
709
710
711
712
713
714

715
716


717
718
719
720
721
722
723

724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743

744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768

769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784





785
786
787
788
789
790

791



792
793
794
795
796
797






798
799
800
801

802
803
804







805
806
807

808






809
810
811
812
813
814
815
816
817
818
819
820
821







822


823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846

847
848
849
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
{
    return NoSymbol;
}

/*
 *----------------------------------------------------------------------
 *
 * XKeysymToKeycode --
 *












 *	This is a stub function which converts a numerical keysym to the











 *      platform-specific keycode used in a KeyPress or KeyRelease XEvent.






 *      For macOS the keycode is an unsigned int with bitfields described





 *      in the definition of the MacKeycode type.










 *




 * Results:





 *




 *      A macOS KeyCode. See the description of keycodes at the top of this


 *	file and the definition of the MacKeycode type in tkMacOSXPrivate.h.













 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

KeyCode
XKeysymToKeycode(
    Display *display,
    KeySym keysym)
{
    Tcl_HashEntry *hPtr;
    MacKeycode macKC;
    if (!initialized) {
	InitHashTables();
    }

    /*

     * First check for a special key.

     */

    hPtr = Tcl_FindHashEntry(&keysym2keycode, INT2PTR(keysym));
    if (hPtr != NULL) {
	return (unsigned int) Tcl_GetHashValue(hPtr);
    }

    /*
     * Initialize the keycode as if the keysym cannot be converted to anything
     * else.
     */

    macKC.v.virtual = NO_VIRTUAL;
    macKC.v.o_s = 0;
    macKC.v.keychar = 0;

    /*
     * If the keysym is recognized fill in the keychar.  Also fill in the
     * xvirtual field if the key exists on the current keyboard.
     */

    hPtr = Tcl_FindHashEntry(&keysym2unichar, INT2PTR(keysym));
    if (hPtr != NULL) {
	macKC.x.keychar = (unsigned int) Tcl_GetHashValue(hPtr);
	hPtr = Tcl_FindHashEntry(&unichar2xvirtual, INT2PTR(macKC.x.keychar));
	if (hPtr != NULL) {
	    macKC.x.xvirtual = (unsigned int) Tcl_GetHashValue(hPtr);
	}
    }
    return macKC.uint;
}

/*
 *----------------------------------------------------------------------
 *
 * TkpSetKeycodeAndState --
 *
 *	This function accepts a keysym and an XEvent and sets some fields of

 *	the XEvent.  It is used by the event generate command.

 *
 * Results:




 *      None
 *
 * Side effects:

 *
 *	Modifies the XEvent. Sets the xkey.keycode to a keycode value formatted
 *	by XKeysymToKeycode and updates the shift and option flags in
 *	xkey.state if either of those modifiers is required to generate the
 *	keysym. Also fills in xkey.trans_chars for printable events.
 *
 *----------------------------------------------------------------------
 */

void
TkpSetKeycodeAndState(
    Tk_Window tkwin,
    KeySym keysym,
    XEvent *eventPtr)
{
    if (keysym == NoSymbol) {
	eventPtr->xkey.keycode = 0;







    } else {

	int eventIndex = STATE2INDEX(eventPtr->xkey.state);
	MacKeycode macKC;
	macKC.uint = XKeysymToKeycode(NULL, keysym);

	/*
	 * We have a virtual keycode and a minimal choice for Shift and Option
	 * modifiers which generates the keychar that corresponds to the
	 * specified keysym.  But we might not have the correct keychar yet,
	 * because the xEvent may have specified modifiers beyond our minimal
	 * set.  For example, the events described by <Oslash>, <Shift-oslash>,
	 * <Shift-Option-O> and <Shift-Option-o> should all produce the same
	 * uppercase Danish O.  So we may need to add the extra modifiers and
	 * do another lookup for the keychar.  We don't want to do this for
	 * special keys, however.
	 */

	if (macKC.v.o_s != eventIndex) {

	    macKC.v.o_s |= eventIndex;
	}
	if (macKC.v.keychar < 0xF700) {
	    UniChar keychar = macKC.v.keychar;
	    NSString *str, *lower, *upper;
	    if (macKC.v.virtual != NO_VIRTUAL) {
		macKC.x.keychar = xvirtual2unichar[macKC.x.xvirtual];
	    } else {
		str = [[NSString alloc] initWithCharacters:&keychar length:1];
		lower = [str lowercaseString];
		upper = [str uppercaseString];
		if (![str isEqual: lower]) {
		    macKC.v.o_s |= INDEX_SHIFT;
		}
		if (macKC.v.o_s & INDEX_SHIFT) {

		    macKC.v.keychar = [upper characterAtIndex:0];
		}


	    }
	}
	eventPtr->xkey.keycode = macKC.uint;
	eventPtr->xkey.state |= INDEX2STATE(macKC.v.o_s);
	if (IS_PRINTABLE(macKC.v.keychar)) {
	    int length = TkUniCharToUtf(macKC.v.keychar,
					eventPtr->xkey.trans_chars);

	    eventPtr->xkey.trans_chars[length] = 0;
	}
    }
}

/*
 *----------------------------------------------------------------------
 *
 * TkpGetKeySym --
 *
 *	This is a stub function called in tkBind.c.  Given a KeyPress or
 *	KeyRelease XEvent, it maps the keycode in the event to a numerical
 *      keysym.
 *
 * Results:
 *	The return value is the keysym corresponding to eventPtr, or NoSymbol
 *	if no matching keysym could be found.
 *
 * Side effects:
 *	In the first call for a given display, calls TkpInitKeymapInfo.

 *
 *
 *----------------------------------------------------------------------
 */

KeySym
TkpGetKeySym(
    TkDisplay *dispPtr,		/* Display in which to map keycode. */
    XEvent *eventPtr)		/* Description of X event. */
{
    KeySym sym;
    int index;
    MacKeycode macKC;
    macKC.uint = eventPtr->xkey.keycode;

    /*
     * Refresh the mapping information if it's stale.
     */

    if (dispPtr->bindInfoStale) {
	TkpInitKeymapInfo(dispPtr);
    }

    /*
     * Modifier key events have a special mac keycode (see tkProcessKeyEvent).

     */

    if (macKC.v.keychar == MOD_KEYCHAR) {
	switch (macKC.v.virtual) {
	case 54:
	    return XK_Meta_R;
	case 55:
	    return XK_Meta_L;
	case 56:
	    return XK_Shift_L;
	case 57:
	    return XK_Caps_Lock;
	case 58:
	    return XK_Alt_L;
	case 59:
	    return XK_Control_L;





	case 60:
	    return XK_Shift_R;
	case 61:
	    return XK_Alt_R;
	case 62:
	    return XK_Control_R;

	case 63:



	    return XK_Super_L;
	default:
	    return NoSymbol;
	}
    }







    /*
     * Figure out which of the four slots in the keymap vector to use for this
     * key. Refer to Xlib documentation for more info on how this computation
     * works.

     */

    index = STATE2INDEX(eventPtr->xkey.state);







    if (eventPtr->xkey.state & LockMask) {
	index |= INDEX_SHIFT;
    }








    /*
     * First do the straightforward lookup.
     */

    sym = XKeycodeToKeysym(dispPtr->display, macKC.uint, index);

    /*
     * Special handling: If the key was shifted because of Lock, which is only
     * caps lock on macOS, not shift lock, and if the shifted keysym isn't
     * upper-case alphabetic, then switch back to the unshifted keysym.
     */

    if ((index & INDEX_SHIFT) && !(eventPtr->xkey.state & ShiftMask)) {







	if ((sym == NoSymbol) || !Tcl_UniCharIsUpper(sym)) {


	    sym = XKeycodeToKeysym(dispPtr->display, macKC.uint,
				   index & ~INDEX_SHIFT);
	}
    }

    /*
     * Another bit of special handling: If this is a shifted key and there is
     * no keysym defined, then use the keysym for the unshifted key.
     */

    if ((index & INDEX_SHIFT) && (sym == NoSymbol)) {
	sym = XKeycodeToKeysym(dispPtr->display, macKC.uint,
			       index & ~INDEX_SHIFT);
    }
    return sym;
}

/*
 *--------------------------------------------------------------
 *
 * TkpInitKeymapInfo --
 *
 *	This procedure initializes fields in the display that pertain
 *      to modifier keys.

 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Modifier key information in dispPtr is initialized.
 *
 *--------------------------------------------------------------
 */

void
TkpInitKeymapInfo(
    TkDisplay *dispPtr)		/* Display for which to recompute keymap
				 * information. */
{
    dispPtr->bindInfoStale = 0;

    /*
     * On macOS the caps lock key is always interpreted to mean that alphabetic
     * keys become uppercase but other keys do not get shifted.  (X11 allows
     * a configuration option which makes the caps lock equivalent to holding
     * down the shift key.)
     * There is no offical "Mode_switch" key.
     */

    dispPtr->lockUsage = LU_CAPS;

    /* This field is no longer used by tkBind.c */

    dispPtr->modeModMask = 0;




    /* The Alt and Meta keys are interchanged on Macintosh keyboards compared
     * to PC keyboards.  These fields could be set to make the Alt key on a PC
     * keyboard behave likd an Alt key. That would also require interchanging
     * Mod1Mask and Mod2Mask in tkMacOSXKeyEvent.c.
     */




    dispPtr->altModMask = 0;
    dispPtr->metaModMask = 0;


    /*
     * The modKeyCodes table lists the keycodes that appear in KeyPress or
     * KeyRelease XEvents for modifier keys.  In tkBind.c this table is

     * searched to determine whether an XEvent corresponds to a modifier key.

     */

    if (dispPtr->modKeyCodes != NULL) {
	ckfree(dispPtr->modKeyCodes);
    }
    dispPtr->numModKeyCodes = NUM_MOD_KEYCODES;
    dispPtr->modKeyCodes = (KeyCode *)ckalloc(NUM_MOD_KEYCODES * sizeof(KeyCode));
    for (int i = 0; i < NUM_MOD_KEYCODES; i++) {
	dispPtr->modKeyCodes[i] = XKeysymToKeycode(NULL, modKeyArray[i]);
    }
}

/*
 *--------------------------------------------------------------
 *
 * TkMacOSXAddVirtual --
 *
 *	This procedure is an internal utility which accepts an unsigned int
 *      that has been partially filled as a MacKeycode, having the Option and
 *      Shift state set in the o_s field and the keychar field set but with the
 *      virtual keycode blank.  It looks up the virtual keycode for the keychar
 *      (possibly NO_VIRTUAL) and returns an unsigned int which is a complete
 *      MacKeycode with the looked up virtual keycode added.  This is used when
 *      creating XEvents for the unicode characters which are generated by the
 *      NSTextInputClient.
 *
 * Results:
 *      An unsigned int which is a complete MacKeycode, including a virtual
 *	keycode which matches the Option-Shift state and keychar.
 *
 * Side effects:
 *	None
 *
 *--------------------------------------------------------------
 */
unsigned
TkMacOSXAddVirtual(
    unsigned int keycode)
{
    MacKeycode macKC;
    Tcl_HashEntry *hPtr;
    macKC.uint = keycode;

    if (!initialized) {
	InitHashTables();
    }

    hPtr = Tcl_FindHashEntry(&unichar2xvirtual, INT2PTR(macKC.v.keychar));
    if (hPtr != NULL) {
	macKC.x.xvirtual = (unsigned int) Tcl_GetHashValue(hPtr);
    } else {
	macKC.v.virtual = NO_VIRTUAL;
    }
    return macKC.uint;
}
/*
 * Local Variables:
 * mode: objc
 * c-basic-offset: 4
 * fill-column: 79
 * coding: utf-8
 * End:
 */

Added macosx/tkMacOSXKeysyms.h.

























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
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
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
/*
 * tkMacOSXKeysyms.h --
 *
 *      Contains data used for processing key events, some of which was
 *      moved from tkMacOSXKeyboard.c.
 *
 * Copyright (c) 1990-1994 The Regents of the University of California.
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 * Copyright 2001-2009, Apple Inc.
 * Copyright (c) 2006-2009 Daniel A. Steffen <[email protected]>
 * Copyright (c) 2020 Marc Culler
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#ifndef TKMACOSXKEYSYMS_H
#define TKMACOSXKEYSYMS_H 1

/*
 * This table enumerates the keys on Mac keyboards which do not represent
 * letters.  This is static data -- these keys do not change when the keyboard
 * layout changes.  The unicode representation of a special key which is not a
 * modifier and does not have an ASCII code point lies in the reserved range
 * 0xF700 - 0xF8FF.
 *
 * The table includes every key listed in Apple's documentation of Function-Key
 * Unicodes which is not marked as "Not on most Macintosh keyboards", as well
 * as F20, which is reported to be usable in scripts even though it does not
 * appear on any Macintosh keyboard.
 */

typedef struct {
    int virtual;	/* value of [NSEvent keyCode] */
    KeySym keysym;	/* X11 keysym */
    KeyCode keychar;	/* XEvent keycode & 0xFFFF */
} KeyInfo;

static const KeyInfo keyArray[] = {
    {36,	XK_Return,	NSNewlineCharacter},
    {48,	XK_Tab,		NSTabCharacter},
    {51,	XK_BackSpace,	NSDeleteCharacter},
    {52,	XK_Return,	NSNewlineCharacter},  /* Used on some Powerbooks */
    {53,	XK_Escape,	0x1B},
    {54,	XK_Meta_R,      MOD_KEYCHAR},
    {55,	XK_Meta_L,	MOD_KEYCHAR},
    {56,	XK_Shift_L,	MOD_KEYCHAR},
    {57,	XK_Caps_Lock,   MOD_KEYCHAR},
    {58,	XK_Alt_L,	MOD_KEYCHAR},
    {59,	XK_Control_L,	MOD_KEYCHAR},
    {60,	XK_Shift_R, 	MOD_KEYCHAR},
    {61,	XK_Alt_R,	MOD_KEYCHAR},
    {62,	XK_Control_R,	MOD_KEYCHAR},
    {63,	XK_Super_L,	MOD_KEYCHAR},
    {64,	XK_F17,		NSF17FunctionKey},
    {65,	XK_KP_Decimal,	'.'},
    {67,	XK_KP_Multiply, '*'},
    {69,	XK_KP_Add,	'+'},
    {71,	XK_Clear,       NSClearLineFunctionKey}, /* Numlock on PC */
    {75,	XK_KP_Divide,   '/'},
    {76,	XK_KP_Enter,	NSEnterCharacter},       /* Fn Return */
    {78,	XK_KP_Subtract, '-'},
    {79,	XK_F18,		NSF18FunctionKey},
    {80,	XK_F19,		NSF19FunctionKey},
    {81,	XK_KP_Equal,	'='},
    {82,	XK_KP_0,	'0'},
    {83,	XK_KP_1,	'1'},
    {84,	XK_KP_2,	'2'},
    {85,	XK_KP_3,	'3'},
    {86,	XK_KP_4,	'4'},
    {87,	XK_KP_5,	'5'},
    {88,	XK_KP_6,	'6'},
    {89,	XK_KP_7,	'7'},
    {90,	XK_F20,		NSF20FunctionKey}, /* For scripting only */
    {91,	XK_KP_8,	'8'},
    {92,	XK_KP_9,	'9'},
    {96,	XK_F5,		NSF5FunctionKey},
    {97,	XK_F6,		NSF6FunctionKey},
    {98,	XK_F7,		NSF7FunctionKey},
    {99,	XK_F3,		NSF3FunctionKey},
    {100,	XK_F8,		NSF8FunctionKey},
    {101,	XK_F9,		NSF9FunctionKey},
    {103,	XK_F11,		NSF11FunctionKey},
    {105,	XK_F13,		NSF13FunctionKey},
    {106,	XK_F16,		NSF16FunctionKey},
    {107,	XK_F14,		NSF14FunctionKey},
    {109,	XK_F10,		NSF10FunctionKey},
    {110,       XK_Menu,	UNKNOWN_KEYCHAR},
    {111,	XK_F12,		NSF12FunctionKey},
    {113,	XK_F15,		NSF15FunctionKey},
    {114,	XK_Help,	NSHelpFunctionKey},
    {115,	XK_Home,	NSHomeFunctionKey},     /* Fn Left */
    {116,	XK_Page_Up,	NSPageUpFunctionKey},   /* Fn Up */
    {117,	XK_Delete,	NSDeleteFunctionKey},   /* Fn Deleete */
    {118,	XK_F4,		NSF4FunctionKey},
    {119,	XK_End,		NSEndFunctionKey},      /* Fn Right */
    {120,	XK_F2,		NSF2FunctionKey},
    {121,	XK_Page_Down,	NSPageDownFunctionKey}, /* Fn Down */
    {122,	XK_F1,		NSF1FunctionKey},
    {123,	XK_Left,	NSLeftArrowFunctionKey},
    {124,	XK_Right,	NSRightArrowFunctionKey},
    {125,	XK_Down,	NSDownArrowFunctionKey},
    {126,	XK_Up,		NSUpArrowFunctionKey},
    {0, 0, 0}
};

/*
 * X11 keysyms for modifier keys, in order.  This list includes keys
 * which do not appear on Apple keyboards, such as Shift_Lock and
 * Super_R.  While most systems don't provide events for the "fn"
 * function key, Apple does.  We map it to Super_L when processing a
 * FlagsChanged NSEvent.
 */

#define NUM_MOD_KEYCODES 14
static const KeyCode modKeyArray[NUM_MOD_KEYCODES] = {
    XK_Shift_L,
    XK_Shift_R,
    XK_Control_L,
    XK_Control_R,
    XK_Caps_Lock,
    XK_Shift_Lock,
    XK_Meta_L,
    XK_Meta_R,
    XK_Alt_L,
    XK_Alt_R,
    XK_Super_L,
    XK_Super_R,
    XK_Hyper_L,
    XK_Hyper_R,
};

/*
 * This table pairs X11 Keysyms for alphanumeric characters with the
 * unicode code point for that letter.
 * The data comes from http://www.cl.cam.ac.uk/~mgk25/ucs/keysyms.txt
 */

typedef struct KeysymInfo {
    KeySym keysym;
    KeyCode keycode;
} KeysymInfo;

const KeysymInfo keysymTable[] = {
    {0x0020, 0x0020}, /* space */
    {0x0021, 0x0021}, /* exclam */
    {0x0022, 0x0022}, /* quotedbl */
    {0x0023, 0x0023}, /* numbersign */
    {0x0024, 0x0024}, /* dollar */
    {0x0025, 0x0025}, /* percent */
    {0x0026, 0x0026}, /* ampersand */
    {0x0027, 0x0027}, /* apostrophe */
    {0x0028, 0x0028}, /* parenleft */
    {0x0029, 0x0029}, /* parenright */
    {0x002a, 0x002a}, /* asterisk */
    {0x002b, 0x002b}, /* plus */
    {0x002c, 0x002c}, /* comma */
    {0x002d, 0x002d}, /* minus */
    {0x002e, 0x002e}, /* period */
    {0x002f, 0x002f}, /* slash */
    {0x0030, 0x0030}, /* 0 */
    {0x0031, 0x0031}, /* 1 */
    {0x0032, 0x0032}, /* 2 */
    {0x0033, 0x0033}, /* 3 */
    {0x0034, 0x0034}, /* 4 */
    {0x0035, 0x0035}, /* 5 */
    {0x0036, 0x0036}, /* 6 */
    {0x0037, 0x0037}, /* 7 */
    {0x0038, 0x0038}, /* 8 */
    {0x0039, 0x0039}, /* 9 */
    {0x003a, 0x003a}, /* colon */
    {0x003b, 0x003b}, /* semicolon */
    {0x003c, 0x003c}, /* less */
    {0x003d, 0x003d}, /* equal */
    {0x003e, 0x003e}, /* greater */
    {0x003f, 0x003f}, /* question */
    {0x0040, 0x0040}, /* at */
    {0x0041, 0x0041}, /* A */
    {0x0042, 0x0042}, /* B */
    {0x0043, 0x0043}, /* C */
    {0x0044, 0x0044}, /* D */
    {0x0045, 0x0045}, /* E */
    {0x0046, 0x0046}, /* F */
    {0x0047, 0x0047}, /* G */
    {0x0048, 0x0048}, /* H */
    {0x0049, 0x0049}, /* I */
    {0x004a, 0x004a}, /* J */
    {0x004b, 0x004b}, /* K */
    {0x004c, 0x004c}, /* L */
    {0x004d, 0x004d}, /* M */
    {0x004e, 0x004e}, /* N */
    {0x004f, 0x004f}, /* O */
    {0x0050, 0x0050}, /* P */
    {0x0051, 0x0051}, /* Q */
    {0x0052, 0x0052}, /* R */
    {0x0053, 0x0053}, /* S */
    {0x0054, 0x0054}, /* T */
    {0x0055, 0x0055}, /* U */
    {0x0056, 0x0056}, /* V */
    {0x0057, 0x0057}, /* W */
    {0x0058, 0x0058}, /* X */
    {0x0059, 0x0059}, /* Y */
    {0x005a, 0x005a}, /* Z */
    {0x005b, 0x005b}, /* bracketleft */
    {0x005c, 0x005c}, /* backslash */
    {0x005d, 0x005d}, /* bracketright */
    {0x005e, 0x005e}, /* asciicircum */
    {0x005f, 0x005f}, /* underscore */
    {0x0060, 0x0060}, /* grave */
    {0x0061, 0x0061}, /* a */
    {0x0062, 0x0062}, /* b */
    {0x0063, 0x0063}, /* c */
    {0x0064, 0x0064}, /* d */
    {0x0065, 0x0065}, /* e */
    {0x0066, 0x0066}, /* f */
    {0x0067, 0x0067}, /* g */
    {0x0068, 0x0068}, /* h */
    {0x0069, 0x0069}, /* i */
    {0x006a, 0x006a}, /* j */
    {0x006b, 0x006b}, /* k */
    {0x006c, 0x006c}, /* l */
    {0x006d, 0x006d}, /* m */
    {0x006e, 0x006e}, /* n */
    {0x006f, 0x006f}, /* o */
    {0x0070, 0x0070}, /* p */
    {0x0071, 0x0071}, /* q */
    {0x0072, 0x0072}, /* r */
    {0x0073, 0x0073}, /* s */
    {0x0074, 0x0074}, /* t */
    {0x0075, 0x0075}, /* u */
    {0x0076, 0x0076}, /* v */
    {0x0077, 0x0077}, /* w */
    {0x0078, 0x0078}, /* x */
    {0x0079, 0x0079}, /* y */
    {0x007a, 0x007a}, /* z */
    {0x007b, 0x007b}, /* braceleft */
    {0x007c, 0x007c}, /* bar */
    {0x007d, 0x007d}, /* braceright */
    {0x007e, 0x007e}, /* asciitilde */
    {0x00a0, 0x00a0}, /* nobreakspace */
    {0x00a1, 0x00a1}, /* exclamdown */
    {0x00a2, 0x00a2}, /* cent */
    {0x00a3, 0x00a3}, /* sterling */
    {0x00a4, 0x00a4}, /* currency */
    {0x00a5, 0x00a5}, /* yen */
    {0x00a6, 0x00a6}, /* brokenbar */
    {0x00a7, 0x00a7}, /* section */
    {0x00a8, 0x00a8}, /* diaeresis */
    {0x00a9, 0x00a9}, /* copyright */
    {0x00aa, 0x00aa}, /* ordfeminine */
    {0x00ab, 0x00ab}, /* guillemotleft */
    {0x00ac, 0x00ac}, /* notsign */
    {0x00ad, 0x00ad}, /* hyphen */
    {0x00ae, 0x00ae}, /* registered */
    {0x00af, 0x00af}, /* macron */
    {0x00b0, 0x00b0}, /* degree */
    {0x00b1, 0x00b1}, /* plusminus */
    {0x00b2, 0x00b2}, /* twosuperior */
    {0x00b3, 0x00b3}, /* threesuperior */
    {0x00b4, 0x00b4}, /* acute */
    {0x00b5, 0x00b5}, /* mu */
    {0x00b6, 0x00b6}, /* paragraph */
    {0x00b7, 0x00b7}, /* periodcentered */
    {0x00b8, 0x00b8}, /* cedilla */
    {0x00b9, 0x00b9}, /* onesuperior */
    {0x00ba, 0x00ba}, /* masculine */
    {0x00bb, 0x00bb}, /* guillemotright */
    {0x00bc, 0x00bc}, /* onequarter */
    {0x00bd, 0x00bd}, /* onehalf */
    {0x00be, 0x00be}, /* threequarters */
    {0x00bf, 0x00bf}, /* questiondown */
    {0x00c0, 0x00c0}, /* Agrave */
    {0x00c1, 0x00c1}, /* Aacute */
    {0x00c2, 0x00c2}, /* Acircumflex */
    {0x00c3, 0x00c3}, /* Atilde */
    {0x00c4, 0x00c4}, /* Adiaeresis */
    {0x00c5, 0x00c5}, /* Aring */
    {0x00c6, 0x00c6}, /* AE */
    {0x00c7, 0x00c7}, /* Ccedilla */
    {0x00c8, 0x00c8}, /* Egrave */
    {0x00c9, 0x00c9}, /* Eacute */
    {0x00ca, 0x00ca}, /* Ecircumflex */
    {0x00cb, 0x00cb}, /* Ediaeresis */
    {0x00cc, 0x00cc}, /* Igrave */
    {0x00cd, 0x00cd}, /* Iacute */
    {0x00ce, 0x00ce}, /* Icircumflex */
    {0x00cf, 0x00cf}, /* Idiaeresis */
    {0x00d0, 0x00d0}, /* ETH */
    {0x00d1, 0x00d1}, /* Ntilde */
    {0x00d2, 0x00d2}, /* Ograve */
    {0x00d3, 0x00d3}, /* Oacute */
    {0x00d4, 0x00d4}, /* Ocircumflex */
    {0x00d5, 0x00d5}, /* Otilde */
    {0x00d6, 0x00d6}, /* Odiaeresis */
    {0x00d7, 0x00d7}, /* multiply */
    {0x00d8, 0x00d8}, /* Ooblique */
    {0x00d9, 0x00d9}, /* Ugrave */
    {0x00da, 0x00da}, /* Uacute */
    {0x00db, 0x00db}, /* Ucircumflex */
    {0x00dc, 0x00dc}, /* Udiaeresis */
    {0x00dd, 0x00dd}, /* Yacute */
    {0x00de, 0x00de}, /* THORN */
    {0x00df, 0x00df}, /* ssharp */
    {0x00e0, 0x00e0}, /* agrave */
    {0x00e1, 0x00e1}, /* aacute */
    {0x00e2, 0x00e2}, /* acircumflex */
    {0x00e3, 0x00e3}, /* atilde */
    {0x00e4, 0x00e4}, /* adiaeresis */
    {0x00e5, 0x00e5}, /* aring */
    {0x00e6, 0x00e6}, /* ae */
    {0x00e7, 0x00e7}, /* ccedilla */
    {0x00e8, 0x00e8}, /* egrave */
    {0x00e9, 0x00e9}, /* eacute */
    {0x00ea, 0x00ea}, /* ecircumflex */
    {0x00eb, 0x00eb}, /* ediaeresis */
    {0x00ec, 0x00ec}, /* igrave */
    {0x00ed, 0x00ed}, /* iacute */
    {0x00ee, 0x00ee}, /* icircumflex */
    {0x00ef, 0x00ef}, /* idiaeresis */
    {0x00f0, 0x00f0}, /* eth */
    {0x00f1, 0x00f1}, /* ntilde */
    {0x00f2, 0x00f2}, /* ograve */
    {0x00f3, 0x00f3}, /* oacute */
    {0x00f4, 0x00f4}, /* ocircumflex */
    {0x00f5, 0x00f5}, /* otilde */
    {0x00f6, 0x00f6}, /* odiaeresis */
    {0x00f7, 0x00f7}, /* division */
    {0x00f8, 0x00f8}, /* oslash */
    {0x00f9, 0x00f9}, /* ugrave */
    {0x00fa, 0x00fa}, /* uacute */
    {0x00fb, 0x00fb}, /* ucircumflex */
    {0x00fc, 0x00fc}, /* udiaeresis */
    {0x00fd, 0x00fd}, /* yacute */
    {0x00fe, 0x00fe}, /* thorn */
    {0x00ff, 0x00ff}, /* ydiaeresis */
    {0x01a1, 0x0104}, /* Aogonek */
    {0x01a2, 0x02d8}, /* breve */
    {0x01a3, 0x0141}, /* Lstroke */
    {0x01a5, 0x013d}, /* Lcaron */
    {0x01a6, 0x015a}, /* Sacute */
    {0x01a9, 0x0160}, /* Scaron */
    {0x01aa, 0x015e}, /* Scedilla */
    {0x01ab, 0x0164}, /* Tcaron */
    {0x01ac, 0x0179}, /* Zacute */
    {0x01ae, 0x017d}, /* Zcaron */
    {0x01af, 0x017b}, /* Zabovedot */
    {0x01b1, 0x0105}, /* aogonek */
    {0x01b2, 0x02db}, /* ogonek */
    {0x01b3, 0x0142}, /* lstroke */
    {0x01b5, 0x013e}, /* lcaron */
    {0x01b6, 0x015b}, /* sacute */
    {0x01b7, 0x02c7}, /* caron */
    {0x01b9, 0x0161}, /* scaron */
    {0x01ba, 0x015f}, /* scedilla */
    {0x01bb, 0x0165}, /* tcaron */
    {0x01bc, 0x017a}, /* zacute */
    {0x01bd, 0x02dd}, /* doubleacute */
    {0x01be, 0x017e}, /* zcaron */
    {0x01bf, 0x017c}, /* zabovedot */
    {0x01c0, 0x0154}, /* Racute */
    {0x01c3, 0x0102}, /* Abreve */
    {0x01c5, 0x0139}, /* Lacute */
    {0x01c6, 0x0106}, /* Cacute */
    {0x01c8, 0x010c}, /* Ccaron */
    {0x01ca, 0x0118}, /* Eogonek */
    {0x01cc, 0x011a}, /* Ecaron */
    {0x01cf, 0x010e}, /* Dcaron */
    {0x01d0, 0x0110}, /* Dstroke */
    {0x01d1, 0x0143}, /* Nacute */
    {0x01d2, 0x0147}, /* Ncaron */
    {0x01d5, 0x0150}, /* Odoubleacute */
    {0x01d8, 0x0158}, /* Rcaron */
    {0x01d9, 0x016e}, /* Uring */
    {0x01db, 0x0170}, /* Udoubleacute */
    {0x01de, 0x0162}, /* Tcedilla */
    {0x01e0, 0x0155}, /* racute */
    {0x01e3, 0x0103}, /* abreve */
    {0x01e5, 0x013a}, /* lacute */
    {0x01e6, 0x0107}, /* cacute */
    {0x01e8, 0x010d}, /* ccaron */
    {0x01ea, 0x0119}, /* eogonek */
    {0x01ec, 0x011b}, /* ecaron */
    {0x01ef, 0x010f}, /* dcaron */
    {0x01f0, 0x0111}, /* dstroke */
    {0x01f1, 0x0144}, /* nacute */
    {0x01f2, 0x0148}, /* ncaron */
    {0x01f5, 0x0151}, /* odoubleacute */
    {0x01f8, 0x0159}, /* rcaron */
    {0x01f9, 0x016f}, /* uring */
    {0x01fb, 0x0171}, /* udoubleacute */
    {0x01fe, 0x0163}, /* tcedilla */
    {0x01ff, 0x02d9}, /* abovedot */
    {0x02a1, 0x0126}, /* Hstroke */
    {0x02a6, 0x0124}, /* Hcircumflex */
    {0x02a9, 0x0130}, /* Iabovedot */
    {0x02ab, 0x011e}, /* Gbreve */
    {0x02ac, 0x0134}, /* Jcircumflex */
    {0x02b1, 0x0127}, /* hstroke */
    {0x02b6, 0x0125}, /* hcircumflex */
    {0x02b9, 0x0131}, /* idotless */
    {0x02bb, 0x011f}, /* gbreve */
    {0x02bc, 0x0135}, /* jcircumflex */
    {0x02c5, 0x010a}, /* Cabovedot */
    {0x02c6, 0x0108}, /* Ccircumflex */
    {0x02d5, 0x0120}, /* Gabovedot */
    {0x02d8, 0x011c}, /* Gcircumflex */
    {0x02dd, 0x016c}, /* Ubreve */
    {0x02de, 0x015c}, /* Scircumflex */
    {0x02e5, 0x010b}, /* cabovedot */
    {0x02e6, 0x0109}, /* ccircumflex */
    {0x02f5, 0x0121}, /* gabovedot */
    {0x02f8, 0x011d}, /* gcircumflex */
    {0x02fd, 0x016d}, /* ubreve */
    {0x02fe, 0x015d}, /* scircumflex */
    {0x03a2, 0x0138}, /* kra */
    {0x03a3, 0x0156}, /* Rcedilla */
    {0x03a5, 0x0128}, /* Itilde */
    {0x03a6, 0x013b}, /* Lcedilla */
    {0x03aa, 0x0112}, /* Emacron */
    {0x03ab, 0x0122}, /* Gcedilla */
    {0x03ac, 0x0166}, /* Tslash */
    {0x03b3, 0x0157}, /* rcedilla */
    {0x03b5, 0x0129}, /* itilde */
    {0x03b6, 0x013c}, /* lcedilla */
    {0x03ba, 0x0113}, /* emacron */
    {0x03bb, 0x0123}, /* gcedilla */
    {0x03bc, 0x0167}, /* tslash */
    {0x03bd, 0x014a}, /* ENG */
    {0x03bf, 0x014b}, /* eng */
    {0x03c0, 0x0100}, /* Amacron */
    {0x03c7, 0x012e}, /* Iogonek */
    {0x03cc, 0x0116}, /* Eabovedot */
    {0x03cf, 0x012a}, /* Imacron */
    {0x03d1, 0x0145}, /* Ncedilla */
    {0x03d2, 0x014c}, /* Omacron */
    {0x03d3, 0x0136}, /* Kcedilla */
    {0x03d9, 0x0172}, /* Uogonek */
    {0x03dd, 0x0168}, /* Utilde */
    {0x03de, 0x016a}, /* Umacron */
    {0x03e0, 0x0101}, /* amacron */
    {0x03e7, 0x012f}, /* iogonek */
    {0x03ec, 0x0117}, /* eabovedot */
    {0x03ef, 0x012b}, /* imacron */
    {0x03f1, 0x0146}, /* ncedilla */
    {0x03f2, 0x014d}, /* omacron */
    {0x03f3, 0x0137}, /* kcedilla */
    {0x03f9, 0x0173}, /* uogonek */
    {0x03fd, 0x0169}, /* utilde */
    {0x03fe, 0x016b}, /* umacron */
    {0x047e, 0x203e}, /* overline */
    {0x04a1, 0x3002}, /* kana_fullstop */
    {0x04a2, 0x300c}, /* kana_openingbracket */
    {0x04a3, 0x300d}, /* kana_closingbracket */
    {0x04a4, 0x3001}, /* kana_comma */
    {0x04a5, 0x30fb}, /* kana_conjunctive */
    {0x04a6, 0x30f2}, /* kana_WO */
    {0x04a7, 0x30a1}, /* kana_a */
    {0x04a8, 0x30a3}, /* kana_i */
    {0x04a9, 0x30a5}, /* kana_u */
    {0x04aa, 0x30a7}, /* kana_e */
    {0x04ab, 0x30a9}, /* kana_o */
    {0x04ac, 0x30e3}, /* kana_ya */
    {0x04ad, 0x30e5}, /* kana_yu */
    {0x04ae, 0x30e7}, /* kana_yo */
    {0x04af, 0x30c3}, /* kana_tsu */
    {0x04b0, 0x30fc}, /* prolongedsound */
    {0x04b1, 0x30a2}, /* kana_A */
    {0x04b2, 0x30a4}, /* kana_I */
    {0x04b3, 0x30a6}, /* kana_U */
    {0x04b4, 0x30a8}, /* kana_E */
    {0x04b5, 0x30aa}, /* kana_O */
    {0x04b6, 0x30ab}, /* kana_KA */
    {0x04b7, 0x30ad}, /* kana_KI */
    {0x04b8, 0x30af}, /* kana_KU */
    {0x04b9, 0x30b1}, /* kana_KE */
    {0x04ba, 0x30b3}, /* kana_KO */
    {0x04bb, 0x30b5}, /* kana_SA */
    {0x04bc, 0x30b7}, /* kana_SHI */
    {0x04bd, 0x30b9}, /* kana_SU */
    {0x04be, 0x30bb}, /* kana_SE */
    {0x04bf, 0x30bd}, /* kana_SO */
    {0x04c0, 0x30bf}, /* kana_TA */
    {0x04c1, 0x30c1}, /* kana_CHI */
    {0x04c2, 0x30c4}, /* kana_TSU */
    {0x04c3, 0x30c6}, /* kana_TE */
    {0x04c4, 0x30c8}, /* kana_TO */
    {0x04c5, 0x30ca}, /* kana_NA */
    {0x04c6, 0x30cb}, /* kana_NI */
    {0x04c7, 0x30cc}, /* kana_NU */
    {0x04c8, 0x30cd}, /* kana_NE */
    {0x04c9, 0x30ce}, /* kana_NO */
    {0x04ca, 0x30cf}, /* kana_HA */
    {0x04cb, 0x30d2}, /* kana_HI */
    {0x04cc, 0x30d5}, /* kana_FU */
    {0x04cd, 0x30d8}, /* kana_HE */
    {0x04ce, 0x30db}, /* kana_HO */
    {0x04cf, 0x30de}, /* kana_MA */
    {0x04d0, 0x30df}, /* kana_MI */
    {0x04d1, 0x30e0}, /* kana_MU */
    {0x04d2, 0x30e1}, /* kana_ME */
    {0x04d3, 0x30e2}, /* kana_MO */
    {0x04d4, 0x30e4}, /* kana_YA */
    {0x04d5, 0x30e6}, /* kana_YU */
    {0x04d6, 0x30e8}, /* kana_YO */
    {0x04d7, 0x30e9}, /* kana_RA */
    {0x04d8, 0x30ea}, /* kana_RI */
    {0x04d9, 0x30eb}, /* kana_RU */
    {0x04da, 0x30ec}, /* kana_RE */
    {0x04db, 0x30ed}, /* kana_RO */
    {0x04dc, 0x30ef}, /* kana_WA */
    {0x04dd, 0x30f3}, /* kana_N */
    {0x04de, 0x309b}, /* voicedsound */
    {0x04df, 0x309c}, /* semivoicedsound */
    {0x05ac, 0x060c}, /* Arabic_comma */
    {0x05bb, 0x061b}, /* Arabic_semicolon */
    {0x05bf, 0x061f}, /* Arabic_question_mark */
    {0x05c1, 0x0621}, /* Arabic_hamza */
    {0x05c2, 0x0622}, /* Arabic_maddaonalef */
    {0x05c3, 0x0623}, /* Arabic_hamzaonalef */
    {0x05c4, 0x0624}, /* Arabic_hamzaonwaw */
    {0x05c5, 0x0625}, /* Arabic_hamzaunderalef */
    {0x05c6, 0x0626}, /* Arabic_hamzaonyeh */
    {0x05c7, 0x0627}, /* Arabic_alef */
    {0x05c8, 0x0628}, /* Arabic_beh */
    {0x05c9, 0x0629}, /* Arabic_tehmarbuta */
    {0x05ca, 0x062a}, /* Arabic_teh */
    {0x05cb, 0x062b}, /* Arabic_theh */
    {0x05cc, 0x062c}, /* Arabic_jeem */
    {0x05cd, 0x062d}, /* Arabic_hah */
    {0x05ce, 0x062e}, /* Arabic_khah */
    {0x05cf, 0x062f}, /* Arabic_dal */
    {0x05d0, 0x0630}, /* Arabic_thal */
    {0x05d1, 0x0631}, /* Arabic_ra */
    {0x05d2, 0x0632}, /* Arabic_zain */
    {0x05d3, 0x0633}, /* Arabic_seen */
    {0x05d4, 0x0634}, /* Arabic_sheen */
    {0x05d5, 0x0635}, /* Arabic_sad */
    {0x05d6, 0x0636}, /* Arabic_dad */
    {0x05d7, 0x0637}, /* Arabic_tah */
    {0x05d8, 0x0638}, /* Arabic_zah */
    {0x05d9, 0x0639}, /* Arabic_ain */
    {0x05da, 0x063a}, /* Arabic_ghain */
    {0x05e0, 0x0640}, /* Arabic_tatweel */
    {0x05e1, 0x0641}, /* Arabic_feh */
    {0x05e2, 0x0642}, /* Arabic_qaf */
    {0x05e3, 0x0643}, /* Arabic_kaf */
    {0x05e4, 0x0644}, /* Arabic_lam */
    {0x05e5, 0x0645}, /* Arabic_meem */
    {0x05e6, 0x0646}, /* Arabic_noon */
    {0x05e7, 0x0647}, /* Arabic_ha */
    {0x05e8, 0x0648}, /* Arabic_waw */
    {0x05e9, 0x0649}, /* Arabic_alefmaksura */
    {0x05ea, 0x064a}, /* Arabic_yeh */
    {0x05eb, 0x064b}, /* Arabic_fathatan */
    {0x05ec, 0x064c}, /* Arabic_dammatan */
    {0x05ed, 0x064d}, /* Arabic_kasratan */
    {0x05ee, 0x064e}, /* Arabic_fatha */
    {0x05ef, 0x064f}, /* Arabic_damma */
    {0x05f0, 0x0650}, /* Arabic_kasra */
    {0x05f1, 0x0651}, /* Arabic_shadda */
    {0x05f2, 0x0652}, /* Arabic_sukun */
    {0x06a1, 0x0452}, /* Serbian_dje */
    {0x06a2, 0x0453}, /* Macedonia_gje */
    {0x06a3, 0x0451}, /* Cyrillic_io */
    {0x06a4, 0x0454}, /* Ukrainian_ie */
    {0x06a5, 0x0455}, /* Macedonia_dse */
    {0x06a6, 0x0456}, /* Ukrainian_i */
    {0x06a7, 0x0457}, /* Ukrainian_yi */
    {0x06a8, 0x0458}, /* Cyrillic_je */
    {0x06a9, 0x0459}, /* Cyrillic_lje */
    {0x06aa, 0x045a}, /* Cyrillic_nje */
    {0x06ab, 0x045b}, /* Serbian_tshe */
    {0x06ac, 0x045c}, /* Macedonia_kje */
    {0x06ae, 0x045e}, /* Byelorussian_shortu */
    {0x06af, 0x045f}, /* Cyrillic_dzhe */
    {0x06b0, 0x2116}, /* numerosign */
    {0x06b1, 0x0402}, /* Serbian_DJE */
    {0x06b2, 0x0403}, /* Macedonia_GJE */
    {0x06b3, 0x0401}, /* Cyrillic_IO */
    {0x06b4, 0x0404}, /* Ukrainian_IE */
    {0x06b5, 0x0405}, /* Macedonia_DSE */
    {0x06b6, 0x0406}, /* Ukrainian_I */
    {0x06b7, 0x0407}, /* Ukrainian_YI */
    {0x06b8, 0x0408}, /* Cyrillic_JE */
    {0x06b9, 0x0409}, /* Cyrillic_LJE */
    {0x06ba, 0x040a}, /* Cyrillic_NJE */
    {0x06bb, 0x040b}, /* Serbian_TSHE */
    {0x06bc, 0x040c}, /* Macedonia_KJE */
    {0x06be, 0x040e}, /* Byelorussian_SHORTU */
    {0x06bf, 0x040f}, /* Cyrillic_DZHE */
    {0x06c0, 0x044e}, /* Cyrillic_yu */
    {0x06c1, 0x0430}, /* Cyrillic_a */
    {0x06c2, 0x0431}, /* Cyrillic_be */
    {0x06c3, 0x0446}, /* Cyrillic_tse */
    {0x06c4, 0x0434}, /* Cyrillic_de */
    {0x06c5, 0x0435}, /* Cyrillic_ie */
    {0x06c6, 0x0444}, /* Cyrillic_ef */
    {0x06c7, 0x0433}, /* Cyrillic_ghe */
    {0x06c8, 0x0445}, /* Cyrillic_ha */
    {0x06c9, 0x0438}, /* Cyrillic_i */
    {0x06ca, 0x0439}, /* Cyrillic_shorti */
    {0x06cb, 0x043a}, /* Cyrillic_ka */
    {0x06cc, 0x043b}, /* Cyrillic_el */
    {0x06cd, 0x043c}, /* Cyrillic_em */
    {0x06ce, 0x043d}, /* Cyrillic_en */
    {0x06cf, 0x043e}, /* Cyrillic_o */
    {0x06d0, 0x043f}, /* Cyrillic_pe */
    {0x06d1, 0x044f}, /* Cyrillic_ya */
    {0x06d2, 0x0440}, /* Cyrillic_er */
    {0x06d3, 0x0441}, /* Cyrillic_es */
    {0x06d4, 0x0442}, /* Cyrillic_te */
    {0x06d5, 0x0443}, /* Cyrillic_u */
    {0x06d6, 0x0436}, /* Cyrillic_zhe */
    {0x06d7, 0x0432}, /* Cyrillic_ve */
    {0x06d8, 0x044c}, /* Cyrillic_softsign */
    {0x06d9, 0x044b}, /* Cyrillic_yeru */
    {0x06da, 0x0437}, /* Cyrillic_ze */
    {0x06db, 0x0448}, /* Cyrillic_sha */
    {0x06dc, 0x044d}, /* Cyrillic_e */
    {0x06dd, 0x0449}, /* Cyrillic_shcha */
    {0x06de, 0x0447}, /* Cyrillic_che */
    {0x06df, 0x044a}, /* Cyrillic_hardsign */
    {0x06e0, 0x042e}, /* Cyrillic_YU */
    {0x06e1, 0x0410}, /* Cyrillic_A */
    {0x06e2, 0x0411}, /* Cyrillic_BE */
    {0x06e3, 0x0426}, /* Cyrillic_TSE */
    {0x06e4, 0x0414}, /* Cyrillic_DE */
    {0x06e5, 0x0415}, /* Cyrillic_IE */
    {0x06e6, 0x0424}, /* Cyrillic_EF */
    {0x06e7, 0x0413}, /* Cyrillic_GHE */
    {0x06e8, 0x0425}, /* Cyrillic_HA */
    {0x06e9, 0x0418}, /* Cyrillic_I */
    {0x06ea, 0x0419}, /* Cyrillic_SHORTI */
    {0x06eb, 0x041a}, /* Cyrillic_KA */
    {0x06ec, 0x041b}, /* Cyrillic_EL */
    {0x06ed, 0x041c}, /* Cyrillic_EM */
    {0x06ee, 0x041d}, /* Cyrillic_EN */
    {0x06ef, 0x041e}, /* Cyrillic_O */
    {0x06f0, 0x041f}, /* Cyrillic_PE */
    {0x06f1, 0x042f}, /* Cyrillic_YA */
    {0x06f2, 0x0420}, /* Cyrillic_ER */
    {0x06f3, 0x0421}, /* Cyrillic_ES */
    {0x06f4, 0x0422}, /* Cyrillic_TE */
    {0x06f5, 0x0423}, /* Cyrillic_U */
    {0x06f6, 0x0416}, /* Cyrillic_ZHE */
    {0x06f7, 0x0412}, /* Cyrillic_VE */
    {0x06f8, 0x042c}, /* Cyrillic_SOFTSIGN */
    {0x06f9, 0x042b}, /* Cyrillic_YERU */
    {0x06fa, 0x0417}, /* Cyrillic_ZE */
    {0x06fb, 0x0428}, /* Cyrillic_SHA */
    {0x06fc, 0x042d}, /* Cyrillic_E */
    {0x06fd, 0x0429}, /* Cyrillic_SHCHA */
    {0x06fe, 0x0427}, /* Cyrillic_CHE */
    {0x06ff, 0x042a}, /* Cyrillic_HARDSIGN */
    {0x07a1, 0x0386}, /* Greek_ALPHAaccent */
    {0x07a2, 0x0388}, /* Greek_EPSILONaccent */
    {0x07a3, 0x0389}, /* Greek_ETAaccent */
    {0x07a4, 0x038a}, /* Greek_IOTAaccent */
    {0x07a5, 0x03aa}, /* Greek_IOTAdiaeresis */
    {0x07a7, 0x038c}, /* Greek_OMICRONaccent */
    {0x07a8, 0x038e}, /* Greek_UPSILONaccent */
    {0x07a9, 0x03ab}, /* Greek_UPSILONdieresis */
    {0x07ab, 0x038f}, /* Greek_OMEGAaccent */
    {0x07ae, 0x0385}, /* Greek_accentdieresis */
    {0x07af, 0x2015}, /* Greek_horizbar */
    {0x07b1, 0x03ac}, /* Greek_alphaaccent */
    {0x07b2, 0x03ad}, /* Greek_epsilonaccent */
    {0x07b3, 0x03ae}, /* Greek_etaaccent */
    {0x07b4, 0x03af}, /* Greek_iotaaccent */
    {0x07b5, 0x03ca}, /* Greek_iotadieresis */
    {0x07b6, 0x0390}, /* Greek_iotaaccentdieresis */
    {0x07b7, 0x03cc}, /* Greek_omicronaccent */
    {0x07b8, 0x03cd}, /* Greek_upsilonaccent */
    {0x07b9, 0x03cb}, /* Greek_upsilondieresis */
    {0x07ba, 0x03b0}, /* Greek_upsilonaccentdieresis */
    {0x07bb, 0x03ce}, /* Greek_omegaaccent */
    {0x07c1, 0x0391}, /* Greek_ALPHA */
    {0x07c2, 0x0392}, /* Greek_BETA */
    {0x07c3, 0x0393}, /* Greek_GAMMA */
    {0x07c4, 0x0394}, /* Greek_DELTA */
    {0x07c5, 0x0395}, /* Greek_EPSILON */
    {0x07c6, 0x0396}, /* Greek_ZETA */
    {0x07c7, 0x0397}, /* Greek_ETA */
    {0x07c8, 0x0398}, /* Greek_THETA */
    {0x07c9, 0x0399}, /* Greek_IOTA */
    {0x07ca, 0x039a}, /* Greek_KAPPA */
    {0x07cb, 0x039b}, /* Greek_LAMDA */
    {0x07cc, 0x039c}, /* Greek_MU */
    {0x07cd, 0x039d}, /* Greek_NU */
    {0x07ce, 0x039e}, /* Greek_XI */
    {0x07cf, 0x039f}, /* Greek_OMICRON */
    {0x07d0, 0x03a0}, /* Greek_PI */
    {0x07d1, 0x03a1}, /* Greek_RHO */
    {0x07d2, 0x03a3}, /* Greek_SIGMA */
    {0x07d4, 0x03a4}, /* Greek_TAU */
    {0x07d5, 0x03a5}, /* Greek_UPSILON */
    {0x07d6, 0x03a6}, /* Greek_PHI */
    {0x07d7, 0x03a7}, /* Greek_CHI */
    {0x07d8, 0x03a8}, /* Greek_PSI */
    {0x07d9, 0x03a9}, /* Greek_OMEGA */
    {0x07e1, 0x03b1}, /* Greek_alpha */
    {0x07e2, 0x03b2}, /* Greek_beta */
    {0x07e3, 0x03b3}, /* Greek_gamma */
    {0x07e4, 0x03b4}, /* Greek_delta */
    {0x07e5, 0x03b5}, /* Greek_epsilon */
    {0x07e6, 0x03b6}, /* Greek_zeta */
    {0x07e7, 0x03b7}, /* Greek_eta */
    {0x07e8, 0x03b8}, /* Greek_theta */
    {0x07e9, 0x03b9}, /* Greek_iota */
    {0x07ea, 0x03ba}, /* Greek_kappa */
    {0x07eb, 0x03bb}, /* Greek_lambda */
    {0x07ec, 0x03bc}, /* Greek_mu */
    {0x07ed, 0x03bd}, /* Greek_nu */
    {0x07ee, 0x03be}, /* Greek_xi */
    {0x07ef, 0x03bf}, /* Greek_omicron */
    {0x07f0, 0x03c0}, /* Greek_pi */
    {0x07f1, 0x03c1}, /* Greek_rho */
    {0x07f2, 0x03c3}, /* Greek_sigma */
    {0x07f3, 0x03c2}, /* Greek_finalsmallsigma */
    {0x07f4, 0x03c4}, /* Greek_tau */
    {0x07f5, 0x03c5}, /* Greek_upsilon */
    {0x07f6, 0x03c6}, /* Greek_phi */
    {0x07f7, 0x03c7}, /* Greek_chi */
    {0x07f8, 0x03c8}, /* Greek_psi */
    {0x07f9, 0x03c9}, /* Greek_omega */
    {0x08a1, 0x23b7}, /* leftradical */
    {0x08a4, 0x2320}, /* topintegral */
    {0x08a5, 0x2321}, /* botintegral */
    {0x08a7, 0x23a1}, /* topleftsqbracket */
    {0x08a8, 0x23a3}, /* botleftsqbracket */
    {0x08a9, 0x23a4}, /* toprightsqbracket */
    {0x08aa, 0x23a6}, /* botrightsqbracket */
    {0x08ab, 0x239b}, /* topleftparens */
    {0x08ac, 0x239d}, /* botleftparens */
    {0x08ad, 0x239e}, /* toprightparens */
    {0x08ae, 0x23a0}, /* botrightparens */
    {0x08af, 0x23a8}, /* leftmiddlecurlybrace */
    {0x08b0, 0x23ac}, /* rightmiddlecurlybrace */
    {0x08bc, 0x2264}, /* lessthanequal */
    {0x08bd, 0x2260}, /* notequal */
    {0x08be, 0x2265}, /* greaterthanequal */
    {0x08bf, 0x222b}, /* integral */
    {0x08c0, 0x2234}, /* therefore */
    {0x08c1, 0x221d}, /* variation */
    {0x08c2, 0x221e}, /* infinity */
    {0x08c5, 0x2207}, /* nabla */
    {0x08c8, 0x223c}, /* approximate */
    {0x08c9, 0x2243}, /* similarequal */
    {0x08cd, 0x21d4}, /* ifonlyif */
    {0x08ce, 0x21d2}, /* implies */
    {0x08cf, 0x2261}, /* identical */
    {0x08d6, 0x221a}, /* radical */
    {0x08da, 0x2282}, /* includedin */
    {0x08db, 0x2283}, /* includes */
    {0x08dc, 0x2229}, /* intersection */
    {0x08dd, 0x222a}, /* union */
    {0x08de, 0x2227}, /* logicaland */
    {0x08df, 0x2228}, /* logicalor */
    {0x08ef, 0x2202}, /* partialderivative */
    {0x08f6, 0x0192}, /* function */
    {0x08fb, 0x2190}, /* leftarrow */
    {0x08fc, 0x2191}, /* uparrow */
    {0x08fd, 0x2192}, /* rightarrow */
    {0x08fe, 0x2193}, /* downarrow */
    {0x09e0, 0x25c6}, /* soliddiamond */
    {0x09e1, 0x2592}, /* checkerboard */
    {0x09e2, 0x2409}, /* ht */
    {0x09e3, 0x240c}, /* ff */
    {0x09e4, 0x240d}, /* cr */
    {0x09e5, 0x240a}, /* lf */
    {0x09e8, 0x2424}, /* nl */
    {0x09e9, 0x240b}, /* vt */
    {0x09ea, 0x2518}, /* lowrightcorner */
    {0x09eb, 0x2510}, /* uprightcorner */
    {0x09ec, 0x250c}, /* upleftcorner */
    {0x09ed, 0x2514}, /* lowleftcorner */
    {0x09ee, 0x253c}, /* crossinglines */
    {0x09ef, 0x23ba}, /* horizlinescan1 */
    {0x09f0, 0x23bb}, /* horizlinescan3 */
    {0x09f1, 0x2500}, /* horizlinescan5 */
    {0x09f2, 0x23bc}, /* horizlinescan7 */
    {0x09f3, 0x23bd}, /* horizlinescan9 */
    {0x09f4, 0x251c}, /* leftt */
    {0x09f5, 0x2524}, /* rightt */
    {0x09f6, 0x2534}, /* bott */
    {0x09f7, 0x252c}, /* topt */
    {0x09f8, 0x2502}, /* vertbar */
    {0x0aa1, 0x2003}, /* emspace */
    {0x0aa2, 0x2002}, /* enspace */
    {0x0aa3, 0x2004}, /* em3space */
    {0x0aa4, 0x2005}, /* em4space */
    {0x0aa5, 0x2007}, /* digitspace */
    {0x0aa6, 0x2008}, /* punctspace */
    {0x0aa7, 0x2009}, /* thinspace */
    {0x0aa8, 0x200a}, /* hairspace */
    {0x0aa9, 0x2014}, /* emdash */
    {0x0aaa, 0x2013}, /* endash */
    {0x0aae, 0x2026}, /* ellipsis */
    {0x0aaf, 0x2025}, /* doubbaselinedot */
    {0x0ab0, 0x2153}, /* onethird */
    {0x0ab1, 0x2154}, /* twothirds */
    {0x0ab2, 0x2155}, /* onefifth */
    {0x0ab3, 0x2156}, /* twofifths */
    {0x0ab4, 0x2157}, /* threefifths */
    {0x0ab5, 0x2158}, /* fourfifths */
    {0x0ab6, 0x2159}, /* onesixth */
    {0x0ab7, 0x215a}, /* fivesixths */
    {0x0ab8, 0x2105}, /* careof */
    {0x0abb, 0x2012}, /* figdash */
    {0x0ac3, 0x215b}, /* oneeighth */
    {0x0ac4, 0x215c}, /* threeeighths */
    {0x0ac5, 0x215d}, /* fiveeighths */
    {0x0ac6, 0x215e}, /* seveneighths */
    {0x0ac9, 0x2122}, /* trademark */
    {0x0ad0, 0x2018}, /* leftsinglequotemark */
    {0x0ad1, 0x2019}, /* rightsinglequotemark */
    {0x0ad2, 0x201c}, /* leftdoublequotemark */
    {0x0ad3, 0x201d}, /* rightdoublequotemark */
    {0x0ad4, 0x211e}, /* prescription */
    {0x0ad6, 0x2032}, /* minutes */
    {0x0ad7, 0x2033}, /* seconds */
    {0x0ad9, 0x271d}, /* latincross */
    {0x0aec, 0x2663}, /* club */
    {0x0aed, 0x2666}, /* diamond */
    {0x0aee, 0x2665}, /* heart */
    {0x0af0, 0x2720}, /* maltesecross */
    {0x0af1, 0x2020}, /* dagger */
    {0x0af2, 0x2021}, /* doubledagger */
    {0x0af3, 0x2713}, /* checkmark */
    {0x0af4, 0x2717}, /* ballotcross */
    {0x0af5, 0x266f}, /* musicalsharp */
    {0x0af6, 0x266d}, /* musicalflat */
    {0x0af7, 0x2642}, /* malesymbol */
    {0x0af8, 0x2640}, /* femalesymbol */
    {0x0af9, 0x260e}, /* telephone */
    {0x0afa, 0x2315}, /* telephonerecorder */
    {0x0afb, 0x2117}, /* phonographcopyright */
    {0x0afc, 0x2038}, /* caret */
    {0x0afd, 0x201a}, /* singlelowquotemark */
    {0x0afe, 0x201e}, /* doublelowquotemark */
    {0x0bc2, 0x22a5}, /* downtack */
    {0x0bc4, 0x230a}, /* downstile */
    {0x0bca, 0x2218}, /* jot */
    {0x0bcc, 0x2395}, /* quad */
    {0x0bce, 0x22a4}, /* uptack */
    {0x0bcf, 0x25cb}, /* circle */
    {0x0bd3, 0x2308}, /* upstile */
    {0x0bdc, 0x22a2}, /* lefttack */
    {0x0bfc, 0x22a3}, /* righttack */
    {0x0cdf, 0x2017}, /* hebrew_doublelowline */
    {0x0ce0, 0x05d0}, /* hebrew_aleph */
    {0x0ce1, 0x05d1}, /* hebrew_bet */
    {0x0ce2, 0x05d2}, /* hebrew_gimel */
    {0x0ce3, 0x05d3}, /* hebrew_dalet */
    {0x0ce4, 0x05d4}, /* hebrew_he */
    {0x0ce5, 0x05d5}, /* hebrew_waw */
    {0x0ce6, 0x05d6}, /* hebrew_zain */
    {0x0ce7, 0x05d7}, /* hebrew_chet */
    {0x0ce8, 0x05d8}, /* hebrew_tet */
    {0x0ce9, 0x05d9}, /* hebrew_yod */
    {0x0cea, 0x05da}, /* hebrew_finalkaph */
    {0x0ceb, 0x05db}, /* hebrew_kaph */
    {0x0cec, 0x05dc}, /* hebrew_lamed */
    {0x0ced, 0x05dd}, /* hebrew_finalmem */
    {0x0cee, 0x05de}, /* hebrew_mem */
    {0x0cef, 0x05df}, /* hebrew_finalnun */
    {0x0cf0, 0x05e0}, /* hebrew_nun */
    {0x0cf1, 0x05e1}, /* hebrew_samech */
    {0x0cf2, 0x05e2}, /* hebrew_ayin */
    {0x0cf3, 0x05e3}, /* hebrew_finalpe */
    {0x0cf4, 0x05e4}, /* hebrew_pe */
    {0x0cf5, 0x05e5}, /* hebrew_finalzade */
    {0x0cf6, 0x05e6}, /* hebrew_zade */
    {0x0cf7, 0x05e7}, /* hebrew_qoph */
    {0x0cf8, 0x05e8}, /* hebrew_resh */
    {0x0cf9, 0x05e9}, /* hebrew_shin */
    {0x0cfa, 0x05ea}, /* hebrew_taw */
    {0x0da1, 0x0e01}, /* Thai_kokai */
    {0x0da2, 0x0e02}, /* Thai_khokhai */
    {0x0da3, 0x0e03}, /* Thai_khokhuat */
    {0x0da4, 0x0e04}, /* Thai_khokhwai */
    {0x0da5, 0x0e05}, /* Thai_khokhon */
    {0x0da6, 0x0e06}, /* Thai_khorakhang */
    {0x0da7, 0x0e07}, /* Thai_ngongu */
    {0x0da8, 0x0e08}, /* Thai_chochan */
    {0x0da9, 0x0e09}, /* Thai_choching */
    {0x0daa, 0x0e0a}, /* Thai_chochang */
    {0x0dab, 0x0e0b}, /* Thai_soso */
    {0x0dac, 0x0e0c}, /* Thai_chochoe */
    {0x0dad, 0x0e0d}, /* Thai_yoying */
    {0x0dae, 0x0e0e}, /* Thai_dochada */
    {0x0daf, 0x0e0f}, /* Thai_topatak */
    {0x0db0, 0x0e10}, /* Thai_thothan */
    {0x0db1, 0x0e11}, /* Thai_thonangmontho */
    {0x0db2, 0x0e12}, /* Thai_thophuthao */
    {0x0db3, 0x0e13}, /* Thai_nonen */
    {0x0db4, 0x0e14}, /* Thai_dodek */
    {0x0db5, 0x0e15}, /* Thai_totao */
    {0x0db6, 0x0e16}, /* Thai_thothung */
    {0x0db7, 0x0e17}, /* Thai_thothahan */
    {0x0db8, 0x0e18}, /* Thai_thothong */
    {0x0db9, 0x0e19}, /* Thai_nonu */
    {0x0dba, 0x0e1a}, /* Thai_bobaimai */
    {0x0dbb, 0x0e1b}, /* Thai_popla */
    {0x0dbc, 0x0e1c}, /* Thai_phophung */
    {0x0dbd, 0x0e1d}, /* Thai_fofa */
    {0x0dbe, 0x0e1e}, /* Thai_phophan */
    {0x0dbf, 0x0e1f}, /* Thai_fofan */
    {0x0dc0, 0x0e20}, /* Thai_phosamphao */
    {0x0dc1, 0x0e21}, /* Thai_moma */
    {0x0dc2, 0x0e22}, /* Thai_yoyak */
    {0x0dc3, 0x0e23}, /* Thai_rorua */
    {0x0dc4, 0x0e24}, /* Thai_ru */
    {0x0dc5, 0x0e25}, /* Thai_loling */
    {0x0dc6, 0x0e26}, /* Thai_lu */
    {0x0dc7, 0x0e27}, /* Thai_wowaen */
    {0x0dc8, 0x0e28}, /* Thai_sosala */
    {0x0dc9, 0x0e29}, /* Thai_sorusi */
    {0x0dca, 0x0e2a}, /* Thai_sosua */
    {0x0dcb, 0x0e2b}, /* Thai_hohip */
    {0x0dcc, 0x0e2c}, /* Thai_lochula */
    {0x0dcd, 0x0e2d}, /* Thai_oang */
    {0x0dce, 0x0e2e}, /* Thai_honokhuk */
    {0x0dcf, 0x0e2f}, /* Thai_paiyannoi */
    {0x0dd0, 0x0e30}, /* Thai_saraa */
    {0x0dd1, 0x0e31}, /* Thai_maihanakat */
    {0x0dd2, 0x0e32}, /* Thai_saraaa */
    {0x0dd3, 0x0e33}, /* Thai_saraam */
    {0x0dd4, 0x0e34}, /* Thai_sarai */
    {0x0dd5, 0x0e35}, /* Thai_saraii */
    {0x0dd6, 0x0e36}, /* Thai_saraue */
    {0x0dd7, 0x0e37}, /* Thai_sarauee */
    {0x0dd8, 0x0e38}, /* Thai_sarau */
    {0x0dd9, 0x0e39}, /* Thai_sarauu */
    {0x0dda, 0x0e3a}, /* Thai_phinthu */
    {0x0ddf, 0x0e3f}, /* Thai_baht */
    {0x0de0, 0x0e40}, /* Thai_sarae */
    {0x0de1, 0x0e41}, /* Thai_saraae */
    {0x0de2, 0x0e42}, /* Thai_sarao */
    {0x0de3, 0x0e43}, /* Thai_saraaimaimuan */
    {0x0de4, 0x0e44}, /* Thai_saraaimaimalai */
    {0x0de5, 0x0e45}, /* Thai_lakkhangyao */
    {0x0de6, 0x0e46}, /* Thai_maiyamok */
    {0x0de7, 0x0e47}, /* Thai_maitaikhu */
    {0x0de8, 0x0e48}, /* Thai_maiek */
    {0x0de9, 0x0e49}, /* Thai_maitho */
    {0x0dea, 0x0e4a}, /* Thai_maitri */
    {0x0deb, 0x0e4b}, /* Thai_maichattawa */
    {0x0dec, 0x0e4c}, /* Thai_thanthakhat */
    {0x0ded, 0x0e4d}, /* Thai_nikhahit */
    {0x0df0, 0x0e50}, /* Thai_leksun */
    {0x0df1, 0x0e51}, /* Thai_leknung */
    {0x0df2, 0x0e52}, /* Thai_leksong */
    {0x0df3, 0x0e53}, /* Thai_leksam */
    {0x0df4, 0x0e54}, /* Thai_leksi */
    {0x0df5, 0x0e55}, /* Thai_lekha */
    {0x0df6, 0x0e56}, /* Thai_lekhok */
    {0x0df7, 0x0e57}, /* Thai_lekchet */
    {0x0df8, 0x0e58}, /* Thai_lekpaet */
    {0x0df9, 0x0e59}, /* Thai_lekkao */
    {0x13bc, 0x0152}, /* OE */
    {0x13bd, 0x0153}, /* oe */
    {0x13be, 0x0178}, /* Ydiaeresis */
    {0x20a0, 0x20a0}, /* EcuSign */
    {0x20a1, 0x20a1}, /* ColonSign */
    {0x20a2, 0x20a2}, /* CruzeiroSign */
    {0x20a3, 0x20a3}, /* FFrancSign */
    {0x20a4, 0x20a4}, /* LiraSign */
    {0x20a5, 0x20a5}, /* MillSign */
    {0x20a6, 0x20a6}, /* NairaSign */
    {0x20a7, 0x20a7}, /* PesetaSign */
    {0x20a8, 0x20a8}, /* RupeeSign */
    {0x20a9, 0x20a9}, /* WonSign */
    {0x20aa, 0x20aa}, /* NewSheqelSign */
    {0x20ab, 0x20ab}, /* DongSign */
    {0x20ac, 0x20ac}, /* EuroSign */
    {0x06ad, 0x0491}, /* Ukrainian_ghe_with_upturn */
    {0x06bd, 0x0490}, /* Ukrainian_GHE_WITH_UPTURN */
    {0x14a2, 0x0587}, /* Armenian_ligature_ew */
    {0x14a3, 0x0589}, /* Armenian_verjaket */
    {0x14aa, 0x055d}, /* Armenian_but */
    {0x14ad, 0x058a}, /* Armenian_yentamna */
    {0x14af, 0x055c}, /* Armenian_amanak */
    {0x14b0, 0x055b}, /* Armenian_shesht */
    {0x14b1, 0x055e}, /* Armenian_paruyk */
    {0x14b2, 0x0531}, /* Armenian_AYB */
    {0x14b3, 0x0561}, /* Armenian_ayb */
    {0x14b4, 0x0532}, /* Armenian_BEN */
    {0x14b5, 0x0562}, /* Armenian_ben */
    {0x14b6, 0x0533}, /* Armenian_GIM */
    {0x14b7, 0x0563}, /* Armenian_gim */
    {0x14b8, 0x0534}, /* Armenian_DA */
    {0x14b9, 0x0564}, /* Armenian_da */
    {0x14ba, 0x0535}, /* Armenian_YECH */
    {0x14bb, 0x0565}, /* Armenian_yech */
    {0x14bc, 0x0536}, /* Armenian_ZA */
    {0x14bd, 0x0566}, /* Armenian_za */
    {0x14be, 0x0537}, /* Armenian_E */
    {0x14bf, 0x0567}, /* Armenian_e */
    {0x14c0, 0x0538}, /* Armenian_AT */
    {0x14c1, 0x0568}, /* Armenian_at */
    {0x14c2, 0x0539}, /* Armenian_TO */
    {0x14c3, 0x0569}, /* Armenian_to */
    {0x14c4, 0x053a}, /* Armenian_ZHE */
    {0x14c5, 0x056a}, /* Armenian_zhe */
    {0x14c6, 0x053b}, /* Armenian_INI */
    {0x14c7, 0x056b}, /* Armenian_ini */
    {0x14c8, 0x053c}, /* Armenian_LYUN */
    {0x14c9, 0x056c}, /* Armenian_lyun */
    {0x14ca, 0x053d}, /* Armenian_KHE */
    {0x14cb, 0x056d}, /* Armenian_khe */
    {0x14cc, 0x053e}, /* Armenian_TSA */
    {0x14cd, 0x056e}, /* Armenian_tsa */
    {0x14ce, 0x053f}, /* Armenian_KEN */
    {0x14cf, 0x056f}, /* Armenian_ken */
    {0x14d0, 0x0540}, /* Armenian_HO */
    {0x14d1, 0x0570}, /* Armenian_ho */
    {0x14d2, 0x0541}, /* Armenian_DZA */
    {0x14d3, 0x0571}, /* Armenian_dza */
    {0x14d4, 0x0542}, /* Armenian_GHAT */
    {0x14d5, 0x0572}, /* Armenian_ghat */
    {0x14d6, 0x0543}, /* Armenian_TCHE */
    {0x14d7, 0x0573}, /* Armenian_tche */
    {0x14d8, 0x0544}, /* Armenian_MEN */
    {0x14d9, 0x0574}, /* Armenian_men */
    {0x14da, 0x0545}, /* Armenian_HI */
    {0x14db, 0x0575}, /* Armenian_hi */
    {0x14dc, 0x0546}, /* Armenian_NU */
    {0x14dd, 0x0576}, /* Armenian_nu */
    {0x14de, 0x0547}, /* Armenian_SHA */
    {0x14df, 0x0577}, /* Armenian_sha */
    {0x14e0, 0x0548}, /* Armenian_VO */
    {0x14e1, 0x0578}, /* Armenian_vo */
    {0x14e2, 0x0549}, /* Armenian_CHA */
    {0x14e3, 0x0579}, /* Armenian_cha */
    {0x14e4, 0x054a}, /* Armenian_PE */
    {0x14e5, 0x057a}, /* Armenian_pe */
    {0x14e6, 0x054b}, /* Armenian_JE */
    {0x14e7, 0x057b}, /* Armenian_je */
    {0x14e8, 0x054c}, /* Armenian_RA */
    {0x14e9, 0x057c}, /* Armenian_ra */
    {0x14ea, 0x054d}, /* Armenian_SE */
    {0x14eb, 0x057d}, /* Armenian_se */
    {0x14ec, 0x054e}, /* Armenian_VEV */
    {0x14ed, 0x057e}, /* Armenian_vev */
    {0x14ee, 0x054f}, /* Armenian_TYUN */
    {0x14ef, 0x057f}, /* Armenian_tyun */
    {0x14f0, 0x0550}, /* Armenian_RE */
    {0x14f1, 0x0580}, /* Armenian_re */
    {0x14f2, 0x0551}, /* Armenian_TSO */
    {0x14f3, 0x0581}, /* Armenian_tso */
    {0x14f4, 0x0552}, /* Armenian_VYUN */
    {0x14f5, 0x0582}, /* Armenian_vyun */
    {0x14f6, 0x0553}, /* Armenian_PYUR */
    {0x14f7, 0x0583}, /* Armenian_pyur */
    {0x14f8, 0x0554}, /* Armenian_KE */
    {0x14f9, 0x0584}, /* Armenian_ke */
    {0x14fa, 0x0555}, /* Armenian_O */
    {0x14fb, 0x0585}, /* Armenian_o */
    {0x14fc, 0x0556}, /* Armenian_FE */
    {0x14fd, 0x0586}, /* Armenian_fe */
    {0x14fe, 0x055a}, /* Armenian_apostrophe */
    {0x15d0, 0x10d0}, /* Georgian_an */
    {0x15d1, 0x10d1}, /* Georgian_ban */
    {0x15d2, 0x10d2}, /* Georgian_gan */
    {0x15d3, 0x10d3}, /* Georgian_don */
    {0x15d4, 0x10d4}, /* Georgian_en */
    {0x15d5, 0x10d5}, /* Georgian_vin */
    {0x15d6, 0x10d6}, /* Georgian_zen */
    {0x15d7, 0x10d7}, /* Georgian_tan */
    {0x15d8, 0x10d8}, /* Georgian_in */
    {0x15d9, 0x10d9}, /* Georgian_kan */
    {0x15da, 0x10da}, /* Georgian_las */
    {0x15db, 0x10db}, /* Georgian_man */
    {0x15dc, 0x10dc}, /* Georgian_nar */
    {0x15dd, 0x10dd}, /* Georgian_on */
    {0x15de, 0x10de}, /* Georgian_par */
    {0x15df, 0x10df}, /* Georgian_zhar */
    {0x15e0, 0x10e0}, /* Georgian_rae */
    {0x15e1, 0x10e1}, /* Georgian_san */
    {0x15e2, 0x10e2}, /* Georgian_tar */
    {0x15e3, 0x10e3}, /* Georgian_un */
    {0x15e4, 0x10e4}, /* Georgian_phar */
    {0x15e5, 0x10e5}, /* Georgian_khar */
    {0x15e6, 0x10e6}, /* Georgian_ghan */
    {0x15e7, 0x10e7}, /* Georgian_qar */
    {0x15e8, 0x10e8}, /* Georgian_shin */
    {0x15e9, 0x10e9}, /* Georgian_chin */
    {0x15ea, 0x10ea}, /* Georgian_can */
    {0x15eb, 0x10eb}, /* Georgian_jil */
    {0x15ec, 0x10ec}, /* Georgian_cil */
    {0x15ed, 0x10ed}, /* Georgian_char */
    {0x15ee, 0x10ee}, /* Georgian_xan */
    {0x15ef, 0x10ef}, /* Georgian_jhan */
    {0x15f0, 0x10f0}, /* Georgian_hae */
    {0x15f1, 0x10f1}, /* Georgian_he */
    {0x15f2, 0x10f2}, /* Georgian_hie */
    {0x15f3, 0x10f3}, /* Georgian_we */
    {0x15f4, 0x10f4}, /* Georgian_har */
    {0x15f5, 0x10f5}, /* Georgian_hoe */
    {0x15f6, 0x10f6}, /* Georgian_fi */
    {0x12a1, 0x1e02}, /* Babovedot */
    {0x12a2, 0x1e03}, /* babovedot */
    {0x12a6, 0x1e0a}, /* Dabovedot */
    {0x12a8, 0x1e80}, /* Wgrave */
    {0x12aa, 0x1e82}, /* Wacute */
    {0x12ab, 0x1e0b}, /* dabovedot */
    {0x12ac, 0x1ef2}, /* Ygrave */
    {0x12b0, 0x1e1e}, /* Fabovedot */
    {0x12b1, 0x1e1f}, /* fabovedot */
    {0x12b4, 0x1e40}, /* Mabovedot */
    {0x12b5, 0x1e41}, /* mabovedot */
    {0x12b7, 0x1e56}, /* Pabovedot */
    {0x12b8, 0x1e81}, /* wgrave */
    {0x12b9, 0x1e57}, /* pabovedot */
    {0x12ba, 0x1e83}, /* wacute */
    {0x12bb, 0x1e60}, /* Sabovedot */
    {0x12bc, 0x1ef3}, /* ygrave */
    {0x12bd, 0x1e84}, /* Wdiaeresis */
    {0x12be, 0x1e85}, /* wdiaeresis */
    {0x12bf, 0x1e61}, /* sabovedot */
    {0x12d0, 0x0174}, /* Wcircumflex */
    {0x12d7, 0x1e6a}, /* Tabovedot */
    {0x12de, 0x0176}, /* Ycircumflex */
    {0x12f0, 0x0175}, /* wcircumflex */
    {0x12f7, 0x1e6b}, /* tabovedot */
    {0x12fe, 0x0177}, /* ycircumflex */
    {0x0590, 0x06f0}, /* Farsi_0 */
    {0x0591, 0x06f1}, /* Farsi_1 */
    {0x0592, 0x06f2}, /* Farsi_2 */
    {0x0593, 0x06f3}, /* Farsi_3 */
    {0x0594, 0x06f4}, /* Farsi_4 */
    {0x0595, 0x06f5}, /* Farsi_5 */
    {0x0596, 0x06f6}, /* Farsi_6 */
    {0x0597, 0x06f7}, /* Farsi_7 */
    {0x0598, 0x06f8}, /* Farsi_8 */
    {0x0599, 0x06f9}, /* Farsi_9 */
    {0x05a5, 0x066a}, /* Arabic_percent */
    {0x05a6, 0x0670}, /* Arabic_superscript_alef */
    {0x05a7, 0x0679}, /* Arabic_tteh */
    {0x05a8, 0x067e}, /* Arabic_peh */
    {0x05a9, 0x0686}, /* Arabic_tcheh */
    {0x05aa, 0x0688}, /* Arabic_ddal */
    {0x05ab, 0x0691}, /* Arabic_rreh */
    {0x05ae, 0x06d4}, /* Arabic_fullstop */
    {0x05b0, 0x0660}, /* Arabic_0 */
    {0x05b1, 0x0661}, /* Arabic_1 */
    {0x05b2, 0x0662}, /* Arabic_2 */
    {0x05b3, 0x0663}, /* Arabic_3 */
    {0x05b4, 0x0664}, /* Arabic_4 */
    {0x05b5, 0x0665}, /* Arabic_5 */
    {0x05b6, 0x0666}, /* Arabic_6 */
    {0x05b7, 0x0667}, /* Arabic_7 */
    {0x05b8, 0x0668}, /* Arabic_8 */
    {0x05b9, 0x0669}, /* Arabic_9 */
    {0x05f3, 0x0653}, /* Arabic_madda_above */
    {0x05f4, 0x0654}, /* Arabic_hamza_above */
    {0x05f5, 0x0655}, /* Arabic_hamza_below */
    {0x05f6, 0x0698}, /* Arabic_jeh */
    {0x05f7, 0x06a4}, /* Arabic_veh */
    {0x05f8, 0x06a9}, /* Arabic_keheh */
    {0x05f9, 0x06af}, /* Arabic_gaf */
    {0x05fa, 0x06ba}, /* Arabic_noon_ghunna */
    {0x05fb, 0x06be}, /* Arabic_heh_doachashmee */
    {0x05fc, 0x06cc}, /* Farsi_yeh */
    {0x05fd, 0x06d2}, /* Arabic_yeh_baree */
    {0x05fe, 0x06c1}, /* Arabic_heh_goal */
    {0x0680, 0x0492}, /* Cyrillic_GHE_bar */
    {0x0681, 0x0496}, /* Cyrillic_ZHE_descender */
    {0x0682, 0x049a}, /* Cyrillic_KA_descender */
    {0x0683, 0x049c}, /* Cyrillic_KA_vertstroke */
    {0x0684, 0x04a2}, /* Cyrillic_EN_descender */
    {0x0685, 0x04ae}, /* Cyrillic_U_straight */
    {0x0686, 0x04b0}, /* Cyrillic_U_straight_bar */
    {0x0687, 0x04b2}, /* Cyrillic_HA_descender */
    {0x0688, 0x04b6}, /* Cyrillic_CHE_descender */
    {0x0689, 0x04b8}, /* Cyrillic_CHE_vertstroke */
    {0x068a, 0x04ba}, /* Cyrillic_SHHA */
    {0x068c, 0x04d8}, /* Cyrillic_SCHWA */
    {0x068d, 0x04e2}, /* Cyrillic_I_macron */
    {0x068e, 0x04e8}, /* Cyrillic_O_bar */
    {0x068f, 0x04ee}, /* Cyrillic_U_macron */
    {0x0690, 0x0493}, /* Cyrillic_ghe_bar */
    {0x0691, 0x0497}, /* Cyrillic_zhe_descender */
    {0x0692, 0x049b}, /* Cyrillic_ka_descender */
    {0x0693, 0x049d}, /* Cyrillic_ka_vertstroke */
    {0x0694, 0x04a3}, /* Cyrillic_en_descender */
    {0x0695, 0x04af}, /* Cyrillic_u_straight */
    {0x0696, 0x04b1}, /* Cyrillic_u_straight_bar */
    {0x0697, 0x04b3}, /* Cyrillic_ha_descender */
    {0x0698, 0x04b7}, /* Cyrillic_che_descender */
    {0x0699, 0x04b9}, /* Cyrillic_che_vertstroke */
    {0x069a, 0x04bb}, /* Cyrillic_shha */
    {0x069c, 0x04d9}, /* Cyrillic_schwa */
    {0x069d, 0x04e3}, /* Cyrillic_i_macron */
    {0x069e, 0x04e9}, /* Cyrillic_o_bar */
    {0x069f, 0x04ef}, /* Cyrillic_u_macron */
    {0x16a3, 0x1e8a}, /* Xabovedot */
    {0x16a6, 0x012c}, /* Ibreve */
    {0x16a9, 0x01b5}, /* Zstroke */
    {0x16aa, 0x01e6}, /* Gcaron */
    {0x16af, 0x019f}, /* Obarred */
    {0x16b3, 0x1e8b}, /* xabovedot */
    {0x16b6, 0x012d}, /* ibreve */
    {0x16b9, 0x01b6}, /* zstroke */
    {0x16ba, 0x01e7}, /* gcaron */
    {0x16bd, 0x01d2}, /* ocaron */
    {0x16bf, 0x0275}, /* obarred */
    {0x16c6, 0x018f}, /* SCHWA */
    {0x16f6, 0x0259}, /* schwa */
    {0x16d1, 0x1e36}, /* Lbelowdot */
    {0x16e1, 0x1e37}, /* lbelowdot */
    {0x1ea0, 0x1ea0}, /* Abelowdot */
    {0x1ea1, 0x1ea1}, /* abelowdot */
    {0x1ea2, 0x1ea2}, /* Ahook */
    {0x1ea3, 0x1ea3}, /* ahook */
    {0x1ea4, 0x1ea4}, /* Acircumflexacute */
    {0x1ea5, 0x1ea5}, /* acircumflexacute */
    {0x1ea6, 0x1ea6}, /* Acircumflexgrave */
    {0x1ea7, 0x1ea7}, /* acircumflexgrave */
    {0x1ea8, 0x1ea8}, /* Acircumflexhook */
    {0x1ea9, 0x1ea9}, /* acircumflexhook */
    {0x1eaa, 0x1eaa}, /* Acircumflextilde */
    {0x1eab, 0x1eab}, /* acircumflextilde */
    {0x1eac, 0x1eac}, /* Acircumflexbelowdot */
    {0x1ead, 0x1ead}, /* acircumflexbelowdot */
    {0x1eae, 0x1eae}, /* Abreveacute */
    {0x1eaf, 0x1eaf}, /* abreveacute */
    {0x1eb0, 0x1eb0}, /* Abrevegrave */
    {0x1eb1, 0x1eb1}, /* abrevegrave */
    {0x1eb2, 0x1eb2}, /* Abrevehook */
    {0x1eb3, 0x1eb3}, /* abrevehook */
    {0x1eb4, 0x1eb4}, /* Abrevetilde */
    {0x1eb5, 0x1eb5}, /* abrevetilde */
    {0x1eb6, 0x1eb6}, /* Abrevebelowdot */
    {0x1eb7, 0x1eb7}, /* abrevebelowdot */
    {0x1eb8, 0x1eb8}, /* Ebelowdot */
    {0x1eb9, 0x1eb9}, /* ebelowdot */
    {0x1eba, 0x1eba}, /* Ehook */
    {0x1ebb, 0x1ebb}, /* ehook */
    {0x1ebc, 0x1ebc}, /* Etilde */
    {0x1ebd, 0x1ebd}, /* etilde */
    {0x1ebe, 0x1ebe}, /* Ecircumflexacute */
    {0x1ebf, 0x1ebf}, /* ecircumflexacute */
    {0x1ec0, 0x1ec0}, /* Ecircumflexgrave */
    {0x1ec1, 0x1ec1}, /* ecircumflexgrave */
    {0x1ec2, 0x1ec2}, /* Ecircumflexhook */
    {0x1ec3, 0x1ec3}, /* ecircumflexhook */
    {0x1ec4, 0x1ec4}, /* Ecircumflextilde */
    {0x1ec5, 0x1ec5}, /* ecircumflextilde */
    {0x1ec6, 0x1ec6}, /* Ecircumflexbelowdot */
    {0x1ec7, 0x1ec7}, /* ecircumflexbelowdot */
    {0x1ec8, 0x1ec8}, /* Ihook */
    {0x1ec9, 0x1ec9}, /* ihook */
    {0x1eca, 0x1eca}, /* Ibelowdot */
    {0x1ecb, 0x1ecb}, /* ibelowdot */
    {0x1ecc, 0x1ecc}, /* Obelowdot */
    {0x1ecd, 0x1ecd}, /* obelowdot */
    {0x1ece, 0x1ece}, /* Ohook */
    {0x1ecf, 0x1ecf}, /* ohook */
    {0x1ed0, 0x1ed0}, /* Ocircumflexacute */
    {0x1ed1, 0x1ed1}, /* ocircumflexacute */
    {0x1ed2, 0x1ed2}, /* Ocircumflexgrave */
    {0x1ed3, 0x1ed3}, /* ocircumflexgrave */
    {0x1ed4, 0x1ed4}, /* Ocircumflexhook */
    {0x1ed5, 0x1ed5}, /* ocircumflexhook */
    {0x1ed6, 0x1ed6}, /* Ocircumflextilde */
    {0x1ed7, 0x1ed7}, /* ocircumflextilde */
    {0x1ed8, 0x1ed8}, /* Ocircumflexbelowdot */
    {0x1ed9, 0x1ed9}, /* ocircumflexbelowdot */
    {0x1eda, 0x1eda}, /* Ohornacute */
    {0x1edb, 0x1edb}, /* ohornacute */
    {0x1edc, 0x1edc}, /* Ohorngrave */
    {0x1edd, 0x1edd}, /* ohorngrave */
    {0x1ede, 0x1ede}, /* Ohornhook */
    {0x1edf, 0x1edf}, /* ohornhook */
    {0x1ee0, 0x1ee0}, /* Ohorntilde */
    {0x1ee1, 0x1ee1}, /* ohorntilde */
    {0x1ee2, 0x1ee2}, /* Ohornbelowdot */
    {0x1ee3, 0x1ee3}, /* ohornbelowdot */
    {0x1ee4, 0x1ee4}, /* Ubelowdot */
    {0x1ee5, 0x1ee5}, /* ubelowdot */
    {0x1ee6, 0x1ee6}, /* Uhook */
    {0x1ee7, 0x1ee7}, /* uhook */
    {0x1ee8, 0x1ee8}, /* Uhornacute */
    {0x1ee9, 0x1ee9}, /* uhornacute */
    {0x1eea, 0x1eea}, /* Uhorngrave */
    {0x1eeb, 0x1eeb}, /* uhorngrave */
    {0x1eec, 0x1eec}, /* Uhornhook */
    {0x1eed, 0x1eed}, /* uhornhook */
    {0x1eee, 0x1eee}, /* Uhorntilde */
    {0x1eef, 0x1eef}, /* uhorntilde */
    {0x1ef0, 0x1ef0}, /* Uhornbelowdot */
    {0x1ef1, 0x1ef1}, /* uhornbelowdot */
    {0x1ef4, 0x1ef4}, /* Ybelowdot */
    {0x1ef5, 0x1ef5}, /* ybelowdot */
    {0x1ef6, 0x1ef6}, /* Yhook */
    {0x1ef7, 0x1ef7}, /* yhook */
    {0x1ef8, 0x1ef8}, /* Ytilde */
    {0x1ef9, 0x1ef9}, /* ytilde */
    {0x1efa, 0x01a0}, /* Ohorn */
    {0x1efb, 0x01a1}, /* ohorn */
    {0x1efc, 0x01af}, /* Uhorn */
    {0x1efd, 0x01b0}, /* uhorn */
    {0, 0}
};

#endif

Changes to macosx/tkMacOSXMouseEvent.c.

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
- (NSEvent *) tkProcessMouseEvent: (NSEvent *) theEvent
{
    NSWindow *eventWindow = [theEvent window];
    NSEventType eventType = [theEvent type];
    TkWindow *winPtr = NULL, *grabWinPtr;
    Tk_Window tkwin;
    NSPoint local, global;

#if 0
    NSTrackingArea *trackingArea = nil;
    NSInteger eventNumber, clickCount, buttonNumber;
#endif
    [NSEvent stopPeriodicEvents];

#ifdef TK_MAC_DEBUG_EVENTS
    TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, theEvent);
#endif
    switch (eventType) {
    case NSMouseEntered:
    case NSMouseExited:
    case NSCursorUpdate:
    case NSLeftMouseDown:
    case NSLeftMouseUp:
    case NSRightMouseDown:
    case NSRightMouseUp:
    case NSOtherMouseDown:
    case NSOtherMouseUp:
    case NSLeftMouseDragged:
    case NSRightMouseDragged:
    case NSOtherMouseDragged:







    case NSMouseMoved:
    case NSTabletPoint:
    case NSTabletProximity:
    case NSScrollWheel:
	break;
    default: /* Unrecognized mouse event. */
	return theEvent;
    }

    /*
     * Compute the mouse position in Tk screen coordinates (global) and in the
     * Tk coordinates of its containing Tk Window (local). If a grab is in effect,
     * the local coordinates should be relative to the grab window.
     */

    if (eventWindow) {
	local = [theEvent locationInWindow];















	global = [eventWindow tkConvertPointToScreen: local];
	tkwin = TkMacOSXGetCapture();
	if (tkwin) {
	    winPtr = (TkWindow *) tkwin;
	    eventWindow = TkMacOSXDrawableWindow(winPtr->window);
	    if (eventWindow) {
		local = [eventWindow tkConvertPointFromScreen: global];







>










<
<
<

<

<

<



>
>
>
>
>
>
>

















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







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
- (NSEvent *) tkProcessMouseEvent: (NSEvent *) theEvent
{
    NSWindow *eventWindow = [theEvent window];
    NSEventType eventType = [theEvent type];
    TkWindow *winPtr = NULL, *grabWinPtr;
    Tk_Window tkwin;
    NSPoint local, global;
    NSInteger button = -1;
#if 0
    NSTrackingArea *trackingArea = nil;
    NSInteger eventNumber, clickCount, buttonNumber;
#endif
    [NSEvent stopPeriodicEvents];

#ifdef TK_MAC_DEBUG_EVENTS
    TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, theEvent);
#endif
    switch (eventType) {



    case NSLeftMouseDown:

    case NSRightMouseDown:

    case NSOtherMouseDown:

    case NSLeftMouseDragged:
    case NSRightMouseDragged:
    case NSOtherMouseDragged:
	button = [theEvent buttonNumber] + Button1;
    case NSMouseEntered:
    case NSMouseExited:
    case NSCursorUpdate:
    case NSLeftMouseUp:
    case NSRightMouseUp:
    case NSOtherMouseUp:
    case NSMouseMoved:
    case NSTabletPoint:
    case NSTabletProximity:
    case NSScrollWheel:
	break;
    default: /* Unrecognized mouse event. */
	return theEvent;
    }

    /*
     * Compute the mouse position in Tk screen coordinates (global) and in the
     * Tk coordinates of its containing Tk Window (local). If a grab is in effect,
     * the local coordinates should be relative to the grab window.
     */

    if (eventWindow) {
	local = [theEvent locationInWindow];

	/*
	 * Do not send ButtonPress XEvents for MouseDown NSEvents that start a
	 * resize.  (The MouseUp will be handled during LiveResize.)  See
	 * ticket [d72abe6b54].
	 */

	if (eventType == NSEventTypeLeftMouseDown &&
	    ([eventWindow styleMask] & NSWindowStyleMaskResizable) &&
	    [NSApp macMinorVersion] > 6) {
	    NSRect frame = [eventWindow frame];
	    if (local.x < 3 || local.x > frame.size.width - 3 || local.y < 3) {
		return theEvent;
	    }
	}
	global = [eventWindow tkConvertPointToScreen: local];
	tkwin = TkMacOSXGetCapture();
	if (tkwin) {
	    winPtr = (TkWindow *) tkwin;
	    eventWindow = TkMacOSXDrawableWindow(winPtr->window);
	    if (eventWindow) {
		local = [eventWindow tkConvertPointFromScreen: global];
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
    local.y = win_y;

    /*
     *  Generate an XEvent for this mouse event.
     */

    unsigned int state = 0;
    int button = [theEvent buttonNumber] + Button1;
    EventRef eventRef = (EventRef)[theEvent eventRef];
    UInt32 buttons;
    OSStatus err = GetEventParameter(eventRef, kEventParamMouseChord,
	    typeUInt32, NULL, sizeof(UInt32), NULL, &buttons);

    if (err == noErr) {
	state |= (buttons & 0x1F) * Button1Mask;
    } else if (button <= Button5) {
	switch (eventType) {
	case NSLeftMouseDown:
	case NSRightMouseDown:
	case NSLeftMouseDragged:
	case NSRightMouseDragged:
	case NSOtherMouseDown:
	    state |= TkGetButtonMask(button);
	    break;
	default:
	    break;
	}
    }

    NSUInteger modifiers = [theEvent modifierFlags];

    if (modifiers & NSAlphaShiftKeyMask) {
	state |= LockMask;
    }







<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
|
<
<
<
<







224
225
226
227
228
229
230








231






232




233
234
235
236
237
238
239
    local.y = win_y;

    /*
     *  Generate an XEvent for this mouse event.
     */

    unsigned int state = 0;








    if (button > 0) {






	state |= TkGetButtonMask(button);




    }

    NSUInteger modifiers = [theEvent modifierFlags];

    if (modifiers & NSAlphaShiftKeyMask) {
	state |= LockMask;
    }

Changes to macosx/tkMacOSXNotify.c.

137
138
139
140
141
142
143

































144
145

146
147
148
149

150
151
152
153
154
155
156
/*
 * Since the contentView is the first responder for a Tk Window, it is
 * responsible for sending events up the responder chain.  We also check the
 * pasteboard here.
 */
- (void) sendEvent: (NSEvent *) theEvent
{

































    [super sendEvent:theEvent];
    [NSApp tkCheckPasteboard];

#ifdef TK_MAC_DEBUG_EVENTS
    fprintf(stderr, "Sending event of type %d\n", (int)[theEvent type]);
    DebugPrintQueue();
#endif

}
@end

#pragma mark -

/*
 *----------------------------------------------------------------------







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


>




>







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
/*
 * Since the contentView is the first responder for a Tk Window, it is
 * responsible for sending events up the responder chain.  We also check the
 * pasteboard here.
 */
- (void) sendEvent: (NSEvent *) theEvent
{

    /*
     * Workaround for an Apple bug.  When an accented character is selected
     * from an NSTextInputClient popup character viewer with the mouse, Apple
     * sends an event of type NSEventTypeAppKitDefined and subtype 21. If that
     * event is sent up the responder chain it causes Apple to print a warning
     * to the console log and, extremely obnoxiously, also to stderr, which
     * says "Window move completed without beginning."  Apparently they are
     * sending the "move completed" event without having sent the "move began"
     * event of subtype 20, and then announcing their error on our stderr.
     * Also, of course, no movement is occurring.  The popup is not movable and
     * is just being closed.  The bug has been reported to Apple.  If they ever
     * fix it, this block should be removed.
     */

    if ([theEvent type] == NSEventTypeAppKitDefined) {
	static Bool aWindowIsMoving = NO;
	switch([theEvent subtype]) {
	case 20:
	    aWindowIsMoving = YES;
	    break;
	case 21:
	    if (aWindowIsMoving) {
		aWindowIsMoving = NO;
		break;
	    } else {
		// printf("Bug!!!!\n");
		return;
	    }
	default:
	    break;
	}
    }
    [super sendEvent:theEvent];
    [NSApp tkCheckPasteboard];

#ifdef TK_MAC_DEBUG_EVENTS
    fprintf(stderr, "Sending event of type %d\n", (int)[theEvent type]);
    DebugPrintQueue();
#endif

}
@end

#pragma mark -

/*
 *----------------------------------------------------------------------

Changes to macosx/tkMacOSXPrivate.h.

118
119
120
121
122
123
124




































































125
126
127
128
129
130
131
#define TkMacOSXInitNamedSymbol(module, ret, symbol, ...) \
    static ret (* symbol)(__VA_ARGS__) = (void*)(-1L); \
    if (symbol == (void*)(-1L)) { \
	symbol = TkMacOSXGetNamedSymbol(STRINGIFY(module), \
		STRINGIFY(symbol)); \
    }





































































/*
 * Structure encapsulating current drawing environment.
 */

typedef struct TkMacOSXDrawingContext {
    CGContextRef context;
    NSView *view;







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







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
#define TkMacOSXInitNamedSymbol(module, ret, symbol, ...) \
    static ret (* symbol)(__VA_ARGS__) = (void*)(-1L); \
    if (symbol == (void*)(-1L)) { \
	symbol = TkMacOSXGetNamedSymbol(STRINGIFY(module), \
		STRINGIFY(symbol)); \
    }

/*
 *  The structure of a 32-bit XEvent keycode on macOS. It may be viewed as
 *  an unsigned int or as having either two or three bitfields.
 */

typedef struct keycode_v_t {
    unsigned keychar: 22;    /* UCS-32 character */
    unsigned o_s: 2;         /* State of Option and Shift keys. */
    unsigned virtual: 8;     /* 8-bit virtual keycode - identifies a key. */
} keycode_v;

typedef struct keycode_x_t {
    unsigned keychar: 22;     /* UCS-32 character */
    unsigned xvirtual: 10;    /* Combines o_s and virtual. This 10-bit integer
			       * is used as a key for looking up the character
			       * produced when pressing a key with a particular
			       * Shift and Option modifier state. */
} keycode_x;

typedef union MacKeycode_t {
  unsigned int uint;
  keycode_v v;
  keycode_x x;
} MacKeycode;

/*
 * Macros used in tkMacOSXKeyboard.c and tkMacOSXKeyEvent.c.
 * Note that 0x7f is del and 0xF8FF is the Apple Logo character.
 */

#define ON_KEYPAD(virtual) ((virtual >= 0x41) && (virtual <= 0x5C))
#define IS_PRINTABLE(keychar) ((keychar >= 0x20) && (keychar != 0x7f) && \
                               ((keychar < 0xF700) || keychar >= 0xF8FF))

/*
 * An "index" is 2-bit bitfield showing the state of the Option and Shift
 * keys.  It is used as an index when building the keymaps and it
 * is the value of the o_s bitfield of a keycode_v.
 */

#define INDEX_SHIFT 1
#define INDEX_OPTION 2
#define INDEX2STATE(index) ((index & INDEX_SHIFT ? ShiftMask : 0) |	\
			    (index & INDEX_OPTION ? Mod2Mask : 0))
#define INDEX2CARBON(index) ((index & INDEX_SHIFT ? shiftKey : 0) |	\
			     (index & INDEX_OPTION ? optionKey : 0))
#define STATE2INDEX(state) ((state & ShiftMask ? INDEX_SHIFT : 0) |	\
			    (state & Mod2Mask ? INDEX_OPTION : 0))

/*
 * Special values for the virtual bitfield.  Actual virtual keycodes are < 128.
 */

#define NO_VIRTUAL 0xFF /* Not generated by a key or the NSText"InputClient. */
#define REPLACEMENT_VIRTUAL 0x80 /* A BMP char sent by the NSTextInputClient. */
#define NON_BMP_VIRTUAL 0x81 /* A non-BMP char sent by the NSTextInputClient. */

/*
 * A special character is used in the keycode for simulated modifier KeyPress
 * or KeyRelease XEvents.  It is near the end of the private-use range but
 * different from the UniChar 0xF8FF which Apple uses for their logo character.
 * A different special character is used for keys, like the Menu key, which do
 * not appear on Macintosh keyboards.
 */

#define MOD_KEYCHAR 0xF8FE
#define UNKNOWN_KEYCHAR 0xF8FD

/*
 * Structure encapsulating current drawing environment.
 */

typedef struct TkMacOSXDrawingContext {
    CGContextRef context;
    NSView *view;
235
236
237
238
239
240
241

242
243
244
245
246
247
248
MODULE_SCOPE int	TkMacOSXRegisterServiceWidgetObjCmd(ClientData clientData,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
MODULE_SCOPE NSString*  TkUtfToNSString(const char *source, size_t numBytes);
MODULE_SCOPE int        TkUtfAtIndex(NSString *string, int index, char *uni,
				      unsigned int *code);
MODULE_SCOPE char*      TkNSStringToUtf(NSString *string, int *numBytes);


#pragma mark Private Objective-C Classes

#define VISIBILITY_HIDDEN __attribute__((visibility("hidden")))

enum { tkMainMenu = 1, tkApplicationMenu, tkWindowsMenu, tkHelpMenu};








>







303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
MODULE_SCOPE int	TkMacOSXRegisterServiceWidgetObjCmd(ClientData clientData,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
MODULE_SCOPE NSString*  TkUtfToNSString(const char *source, size_t numBytes);
MODULE_SCOPE int        TkUtfAtIndex(NSString *string, int index, char *uni,
				      unsigned int *code);
MODULE_SCOPE char*      TkNSStringToUtf(NSString *string, int *numBytes);
MODULE_SCOPE unsigned   TkMacOSXAddVirtual(unsigned int keycode);

#pragma mark Private Objective-C Classes

#define VISIBILITY_HIDDEN __attribute__((visibility("hidden")))

enum { tkMainMenu = 1, tkApplicationMenu, tkWindowsMenu, tkHelpMenu};

352
353
354
355
356
357
358

359
360
361
362
363
364
365
    Bool _needsRedisplay;
}
@property Bool needsRedisplay;
@end

@interface TKContentView(TKKeyEvent)
- (void) deleteWorkingText;

@end

@interface TKContentView(TKWindowEvent)
- (void) generateExposeEvents: (HIShapeRef) shape;
- (void) tkToolbarButton: (id) sender;
@end








>







421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
    Bool _needsRedisplay;
}
@property Bool needsRedisplay;
@end

@interface TKContentView(TKKeyEvent)
- (void) deleteWorkingText;
- (void) cancelComposingText;
@end

@interface TKContentView(TKWindowEvent)
- (void) generateExposeEvents: (HIShapeRef) shape;
- (void) tkToolbarButton: (id) sender;
@end

425
426
427
428
429
430
431













































432
433
434
435
436
437
438
439
440
441
442
443
 * declare it here to be a method of the TKMenu category.
 */

@interface NSApplication(TKMenu)
- (void) setAppleMenu: (NSMenu *) menu;
@end














































#endif /* _TKMACPRIV */

int TkMacOSXGetAppPath(ClientData cd, Tcl_Interp *ip, int objc, Tcl_Obj *const objv[]);

/*
 * Local Variables:
 * mode: objc
 * c-basic-offset: 4
 * fill-column: 79
 * coding: utf-8
 * End:
 */







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












495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
 * declare it here to be a method of the TKMenu category.
 */

@interface NSApplication(TKMenu)
- (void) setAppleMenu: (NSMenu *) menu;
@end

/*
 * These methods are exposed because they are needed to prevent zombie windows
 * on systems with a TouchBar.  The TouchBar Key-Value observer holds a
 * reference to the key window, which prevents deallocation of the key window
 * when it is closed.
 */

@interface NSApplication(TkWm)
- (id) _setKeyWindow: (NSWindow *) window;
- (id) _setMainWindow: (NSWindow *) window;
@end


/*
 *---------------------------------------------------------------------------
 *
 * TKNSString --
 *
 * When Tcl is compiled with TCL_UTF_MAX = 3 (the default for 8.6) it cannot
 * deal directly with UTF-8 encoded non-BMP characters, since their UTF-8
 * encoding requires 4 bytes.
 *
 * As a workaround, these versions of Tcl encode non-BMP characters as a string
 * of length 6 in which the high and low UTF-16 surrogates have been encoded
 * using the UTF-8 algorithm.  The UTF-8 encoding does not allow encoding
 * surrogates, so these 6-byte strings are not valid UTF-8, and hence Apple's
 * NString class will refuse to instantiate an NSString from the 6-byte
 * encoding.
 *
 * This subclass of NSString adds a new initialization method which accepts
 * a C string encoded with the scheme described above.
 *
 *---------------------------------------------------------------------------
 */

@interface TKNSString:NSString {
@private
    Tcl_DString _ds;
    NSString *_string;
}
@property const char *UTF8String;
- (instancetype)initWithTclUtfBytes:(const void *)bytes
			     length:(NSUInteger)len;
@end

#endif /* _TKMACPRIV */

int TkMacOSXGetAppPath(ClientData cd, Tcl_Interp *ip, int objc, Tcl_Obj *const objv[]);

/*
 * Local Variables:
 * mode: objc
 * c-basic-offset: 4
 * fill-column: 79
 * coding: utf-8
 * End:
 */

Changes to macosx/tkMacOSXTest.c.

21
22
23
24
25
26
27


28
29
30
31
32
33
34

#if MAC_OS_X_VERSION_MAX_ALLOWED < 1080
static int		DebuggerObjCmd (ClientData dummy, Tcl_Interp *interp,
					int objc, Tcl_Obj *const objv[]);
#endif
static int		PressButtonObjCmd (ClientData dummy, Tcl_Interp *interp,
					int objc, Tcl_Obj *const objv[]);




/*
 *----------------------------------------------------------------------
 *
 * TkplatformtestInit --
 *







>
>







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

#if MAC_OS_X_VERSION_MAX_ALLOWED < 1080
static int		DebuggerObjCmd (ClientData dummy, Tcl_Interp *interp,
					int objc, Tcl_Obj *const objv[]);
#endif
static int		PressButtonObjCmd (ClientData dummy, Tcl_Interp *interp,
					int objc, Tcl_Obj *const objv[]);
static int		InjectKeyEventObjCmd (ClientData dummy, Tcl_Interp *interp,
					int objc, Tcl_Obj *const objv[]);


/*
 *----------------------------------------------------------------------
 *
 * TkplatformtestInit --
 *
52
53
54
55
56
57
58

59
60
61
62
63
64
65
     * Add commands for platform specific tests on MacOS here.
     */

#if MAC_OS_X_VERSION_MAX_ALLOWED < 1080
    Tcl_CreateObjCommand(interp, "debugger", DebuggerObjCmd, NULL, NULL);
#endif
    Tcl_CreateObjCommand(interp, "pressbutton", PressButtonObjCmd, NULL, NULL);


    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *







>







54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
     * Add commands for platform specific tests on MacOS here.
     */

#if MAC_OS_X_VERSION_MAX_ALLOWED < 1080
    Tcl_CreateObjCommand(interp, "debugger", DebuggerObjCmd, NULL, NULL);
#endif
    Tcl_CreateObjCommand(interp, "pressbutton", PressButtonObjCmd, NULL, NULL);
    Tcl_CreateObjCommand(interp, "injectkeyevent", InjectKeyEventObjCmd, NULL, NULL);

    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
215
216
217
218
219
220
221






222





































































































223
224
225
226
227
228
229
230
	eventNumber:2
	clickCount:1
	pressure:0.0];
    [NSApp postEvent:release atStart:NO];
    return TCL_OK;
}













































































































/*
 * Local Variables:
 * mode: objc
 * c-basic-offset: 4
 * fill-column: 79
 * coding: utf-8
 * End:
 */







>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>








218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
	eventNumber:2
	clickCount:1
	pressure:0.0];
    [NSApp postEvent:release atStart:NO];
    return TCL_OK;
}

static int
InjectKeyEventObjCmd(
    ClientData clientData,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const objv[])
{
    static const char *const optionStrings[] = {
	"press", "release", "flagschanged", NULL};
    NSUInteger types[3] = {NSKeyDown, NSKeyUp, NSFlagsChanged};
    static const char *const argStrings[] = {
	"-shift", "-control", "-option", "-command", "-function", "-x", "-y", NULL};
    enum args {KEYEVENT_SHIFT, KEYEVENT_CONTROL, KEYEVENT_OPTION, KEYEVENT_COMMAND,
	       KEYEVENT_FUNCTION, KEYEVENT_X, KEYEVENT_Y};
    int i, index, keysym, mods = 0, x = 0, y = 0;
    NSString *chars = nil, *unmod = nil, *upper, *lower;
    NSEvent *keyEvent;
    NSUInteger type;
    MacKeycode macKC;

    if (objc < 3) {
    wrongArgs:
        Tcl_WrongNumArgs(interp, 1, objv, "option keysym ?arg?");
        return TCL_ERROR;
    }
    if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
            &index) != TCL_OK) {
        return TCL_ERROR;
    }
    type = types[index];
    if (Tcl_GetIntFromObj(interp, objv[2], &keysym) != TCL_OK) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
			 "keysym must be an integer"));
	Tcl_SetErrorCode(interp, "TK", "TEST", "INJECT", "KEYSYM", NULL);
	return TCL_ERROR;
    }
    macKC.uint = XKeysymToKeycode(NULL, keysym);
    for (i = 3; i < objc; i++) {
	if (Tcl_GetIndexFromObjStruct(interp, objv[i], argStrings,
                sizeof(char *), "option", TCL_EXACT, &index) != TCL_OK) {
            return TCL_ERROR;
        }
        switch ((enum args) index) {
	case KEYEVENT_SHIFT:
	    mods |= NSShiftKeyMask;
            break;
	case KEYEVENT_CONTROL:
	    mods |= NSControlKeyMask;
            break;
	case KEYEVENT_OPTION:
	    mods |= NSAlternateKeyMask;
            break;
	case KEYEVENT_COMMAND:
	    mods |= NSCommandKeyMask;
            break;
	case KEYEVENT_FUNCTION:
	    mods |= NSFunctionKeyMask;
            break;
	case KEYEVENT_X:
	    if (++i >= objc) {
                goto wrongArgs;
            }
	    if (Tcl_GetIntFromObj(interp,objv[i], &x) != TCL_OK) {
		return TCL_ERROR;
	    }
	    break;
	case KEYEVENT_Y:
	    if (++i >= objc) {
                goto wrongArgs;
            }
	    if (Tcl_GetIntFromObj(interp,objv[i], &y) != TCL_OK) {
		return TCL_ERROR;
	    }
	    break;
	}
    }
    if (type != NSFlagsChanged) {
	UniChar keychar = macKC.v.keychar;
	chars = [[NSString alloc] initWithCharacters: &keychar length:1];
	upper = [chars uppercaseString];
	lower = [chars lowercaseString];
	if (![upper isEqual: lower] && [chars isEqual: upper]) {
	    mods |= NSShiftKeyMask;
	}
	if (mods & NSShiftKeyMask) {
	    chars = upper;
	    unmod = lower;
	    macKC.v.o_s |= INDEX_SHIFT;
	} else {
	    unmod = chars;
	}
	if (macKC.v.o_s & INDEX_OPTION) {
	    mods |= NSAlternateKeyMask;
	}
    }
    keyEvent = [NSEvent keyEventWithType:type
	location:NSMakePoint(x, y)
        modifierFlags:mods
	timestamp:GetCurrentEventTime()
	windowNumber:0
	context:nil
	characters:chars
	charactersIgnoringModifiers:unmod
	isARepeat:NO
	keyCode:macKC.v.virtual];
    [NSApp postEvent:keyEvent atStart:NO];
    return TCL_OK;
}
/*
 * Local Variables:
 * mode: objc
 * c-basic-offset: 4
 * fill-column: 79
 * coding: utf-8
 * End:
 */

Changes to macosx/tkMacOSXWindowEvent.c.

311
312
313
314
315
316
317














318
319
320
321
322
323
324
}

- (void) applicationDeactivate: (NSNotification *) notification
{
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
    TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
#endif














}

- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender
                    hasVisibleWindows:(BOOL)flag
{
    /*
     * Allowing the default response means that withdrawn windows will get







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







311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
}

- (void) applicationDeactivate: (NSNotification *) notification
{
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
    TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
#endif

    /*
     * To prevent zombie windows on systems with a TouchBar, set the key window
     * to nil if the current key window is not visible.  This allows a closed
     * Help or About window to be deallocated so it will not reappear as a
     * zombie when the app is reactivated.
     */

    NSWindow *keywindow = [NSApp keyWindow];
    if (keywindow && ![keywindow isVisible]) {
	[NSApp _setKeyWindow:nil];
	[NSApp _setMainWindow:nil];
    }

}

- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender
                    hasVisibleWindows:(BOOL)flag
{
    /*
     * Allowing the default response means that withdrawn windows will get

Changes to macosx/tkMacOSXWm.c.

18
19
20
21
22
23
24






25
26
27
28
29
30
31
#include "tkMacOSXPrivate.h"
#include "tkScrollbar.h"
#include "tkMacOSXWm.h"
#include "tkMacOSXEvent.h"
#include "tkMacOSXDebug.h"
#include "tkMacOSXConstants.h"







#define DEBUG_ZOMBIES 0

/*
#ifdef TK_MAC_DEBUG
#define TK_MAC_DEBUG_WINDOWS
#endif
*/







>
>
>
>
>
>







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include "tkMacOSXPrivate.h"
#include "tkScrollbar.h"
#include "tkMacOSXWm.h"
#include "tkMacOSXEvent.h"
#include "tkMacOSXDebug.h"
#include "tkMacOSXConstants.h"

/*
 * Setting this to 1 prints when each window is freed, setting it to 2 adds
 * dumps of the autorelease pools, and setting it to 3 also shows each retain
 * and release.
 */

#define DEBUG_ZOMBIES 0

/*
#ifdef TK_MAC_DEBUG
#define TK_MAC_DEBUG_WINDOWS
#endif
*/
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
@end

#pragma mark -

#pragma mark TKWindow(TKWm)

@implementation TKWindow: NSWindow

@end

@implementation TKWindow(TKWm)

/*
 * This method synchronizes Tk's understanding of the bounds of a contentView
 * with the window's.  It is needed because there are situations when the







<







359
360
361
362
363
364
365

366
367
368
369
370
371
372
@end

#pragma mark -

#pragma mark TKWindow(TKWm)

@implementation TKWindow: NSWindow

@end

@implementation TKWindow(TKWm)

/*
 * This method synchronizes Tk's understanding of the bounds of a contentView
 * with the window's.  It is needed because there are situations when the
426
427
428
429
430
431
432

433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
    }
    return frameSize;
}

- (BOOL) canBecomeKeyWindow
{
    TkWindow *winPtr = TkMacOSXGetTkWindow(self);

    if (!winPtr) {
	return NO;
    }
    return (winPtr->wmInfoPtr &&
	    (winPtr->wmInfoPtr->macClass == kHelpWindowClass ||
	     winPtr->wmInfoPtr->attributes & kWindowNoActivatesAttribute)
	    ) ? NO : YES;
}

#if DEBUG_ZOMBIES
- (id) retain
{
    id result = [super retain];
    const char *title = [[self title] UTF8String];
    if (title == nil) {
	title = "unnamed window";
    }
    if (DEBUG_ZOMBIES > 1) {
	fprintf(stderr, "Retained <%s>. Count is: %lu\n",
		title, [self retainCount]);
    }
    return result;
}

- (id) autorelease
{
    id result = [super autorelease];
    const char *title = [[self title] UTF8String];
    if (title == nil) {
	title = "unnamed window";
    }
    if (DEBUG_ZOMBIES > 1) {
	fprintf(stderr, "Autoreleased <%s>. Count is %lu\n",
		title, [self retainCount]);
    }
    return result;
}

- (oneway void) release {
    const char *title = [[self title] UTF8String];
    if (title == nil) {
	title = "unnamed window";
    }
    if (DEBUG_ZOMBIES > 1) {
	fprintf(stderr, "Releasing <%s>. Count is %lu\n",
		title, [self retainCount]);
    }
    [super release];
}

- (void) dealloc {







>
|
















|













|











|







431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
    }
    return frameSize;
}

- (BOOL) canBecomeKeyWindow
{
    TkWindow *winPtr = TkMacOSXGetTkWindow(self);

    if (!winPtr || !winPtr->wmInfoPtr) {
	return NO;
    }
    return (winPtr->wmInfoPtr &&
	    (winPtr->wmInfoPtr->macClass == kHelpWindowClass ||
	     winPtr->wmInfoPtr->attributes & kWindowNoActivatesAttribute)
	    ) ? NO : YES;
}

#if DEBUG_ZOMBIES
- (id) retain
{
    id result = [super retain];
    const char *title = [[self title] UTF8String];
    if (title == nil) {
	title = "unnamed window";
    }
    if (DEBUG_ZOMBIES > 2) {
	fprintf(stderr, "Retained <%s>. Count is: %lu\n",
		title, [self retainCount]);
    }
    return result;
}

- (id) autorelease
{
    id result = [super autorelease];
    const char *title = [[self title] UTF8String];
    if (title == nil) {
	title = "unnamed window";
    }
    if (DEBUG_ZOMBIES > 2) {
	fprintf(stderr, "Autoreleased <%s>. Count is %lu\n",
		title, [self retainCount]);
    }
    return result;
}

- (oneway void) release {
    const char *title = [[self title] UTF8String];
    if (title == nil) {
	title = "unnamed window";
    }
    if (DEBUG_ZOMBIES > 2) {
	fprintf(stderr, "Releasing <%s>. Count is %lu\n",
		title, [self retainCount]);
    }
    [super release];
}

- (void) dealloc {
875
876
877
878
879
880
881

882
883
884
885
886
887
888
 */

void
TkWmDeadWindow(
    TkWindow *winPtr)		/* Top-level window that's being deleted. */
{
    WmInfo *wmPtr = winPtr->wmInfoPtr, *wmPtr2;


    if (wmPtr == NULL) {
	return;
    }

    /*
     *If the dead window is a transient, remove it from the master's list.







>







881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
 */

void
TkWmDeadWindow(
    TkWindow *winPtr)		/* Top-level window that's being deleted. */
{
    WmInfo *wmPtr = winPtr->wmInfoPtr, *wmPtr2;
    NSWindow *ourNSWindow;

    if (wmPtr == NULL) {
	return;
    }

    /*
     *If the dead window is a transient, remove it from the master's list.
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
	Transient *transientPtr = wmPtr->transientPtr;

	wmPtr->transientPtr = transientPtr->nextPtr;
	ckfree(transientPtr);
    }

    /*
     * Delete the Mac window and remove it from the windowTable. The window
     * could be nil if the window was never mapped. However, we don't do this
     * for embedded windows, they don't go in the window list, and they do not
     * own their portPtr's.
     */

    NSWindow *window = wmPtr->window;






    if (window && !Tk_IsEmbedded(winPtr)) {
	NSWindow *parent = [window parentWindow];

	if (parent) {
	    [parent removeChildWindow:window];
	}

#if DEBUG_ZOMBIES > 0
	{
	    const char *title = [[window title] UTF8String];
	    if (title == nil) {
		title = "unnamed window";
	    }
	    fprintf(stderr, ">>>> Closing <%s>. Count is: %lu\n", title,
		    [window retainCount]);
	}
#endif
	[window close];
	TkMacOSXUnregisterMacWindow(window);
        if (winPtr->window) {
            ((MacDrawable *) winPtr->window)->view = nil;
        }



	wmPtr->window = NULL;






        [window release];


	/* Activate the highest window left on the screen. */
	NSArray *windows = [NSApp orderedWindows];
	for (id nswindow in windows) {
	    TkWindow *winPtr2 = TkMacOSXGetTkWindow(nswindow);

	    if (winPtr2 && nswindow != window) {
		WmInfo *wmPtr = winPtr2->wmInfoPtr;
		BOOL minimized = (wmPtr->hints.initial_state == IconicState
			|| wmPtr->hints.initial_state == WithdrawnState);

		/*
		 * If no windows are left on the screen and the next window is
		 * iconified or withdrawn, we don't want to make it be the
		 * KeyWindow because that would cause it to be displayed on the
		 * screen.
		 */




		if ([nswindow canBecomeKeyWindow] && !minimized) {
		    [nswindow makeKeyAndOrderFront:NSApp];
		    break;
		}
	    }
	}

	/*
	 * Process all window events immediately to force the closed window to
	 * be deallocated.  But don't do this for the root window as that is
	 * unnecessary and can lead to segfaults.
	 */

	if (winPtr->parentPtr) {

	    while (Tcl_DoOneEvent(TCL_WINDOW_EVENTS|TCL_DONT_WAIT)) {}
	}


	[NSApp _resetAutoreleasePool];

#if DEBUG_ZOMBIES > 0
	fprintf(stderr, "================= Pool dump ===================\n");
	[NSAutoreleasePool showPools];
#endif
    }






    ckfree(wmPtr);
    winPtr->wmInfoPtr = NULL;
}

/*
 *----------------------------------------------------------------------
 *







|
|
<
|


|
>
>
>
>
>
|
|
<


|

>
|

|




|


<
<
<
<
|
>
>
>
|
>
>
>
>
>
>
|
>

<
|
<
|
|
<
<
<
<
<
<
<
|
|
|
<
|
>
>
>
|
|
|
|
|
|
<

<
|
<


|
>
|

>
>

>
|



|
>
>
>
>
>
>







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
	Transient *transientPtr = wmPtr->transientPtr;

	wmPtr->transientPtr = transientPtr->nextPtr;
	ckfree(transientPtr);
    }

    /*
     * Unregister the NSWindow and remove all references to it from the Tk
     * data structures.  If the NSWindow is a child, disassociate it from

     * the parent.  Then close and release the NSWindow.
     */

    ourNSWindow = wmPtr->window;
    if (ourNSWindow && !Tk_IsEmbedded(winPtr)) {
	NSWindow *parent = [ourNSWindow parentWindow];
	TkMacOSXUnregisterMacWindow(ourNSWindow);
        if (winPtr->window) {
            ((MacDrawable *) winPtr->window)->view = nil;
        }
	wmPtr->window = NULL;


	if (parent) {
	    [parent removeChildWindow:ourNSWindow];
	}

#if DEBUG_ZOMBIES > 1
	{
	    const char *title = [[ourNSWindow title] UTF8String];
	    if (title == nil) {
		title = "unnamed window";
	    }
	    fprintf(stderr, ">>>> Closing <%s>. Count is: %lu\n", title,
		    [ourNSWindow retainCount]);
	}
#endif





	/*
	 * When a window is closed we want to move the focus to the next
	 * highest window.  Apple's documentation says that calling the
	 * orderOut method of the key window will accomplish this.  But
	 * experiment shows that this is not the case.  So we have to reset the
	 * key window ourselves.  When the window is the last one on the screen
	 * there is no choice for a new key window.  Moreover, if the host
	 * computer has a TouchBar then the TouchBar holds a reference to the
	 * key window which prevents it from being deallocated until it stops
	 * being the key window.  On these systems the only option for
	 * preventing zombies is to set the key window to nil.
	 */


	for (NSWindow *w in [NSApp orderedWindows]) {

	    TkWindow *winPtr2 = TkMacOSXGetTkWindow(w);
	    BOOL isOnScreen;








	    if (!winPtr2 || !winPtr2->wmInfoPtr) {
		continue;

	    }
	    wmPtr2 = winPtr2->wmInfoPtr;
	    isOnScreen = (wmPtr2->hints.initial_state != IconicState &&
			  wmPtr2->hints.initial_state != WithdrawnState);
	    if (w != ourNSWindow && isOnScreen && [w canBecomeKeyWindow]) {
		[w makeKeyAndOrderFront:NSApp];
		break;
	    }
	}


	/*

	 * Prevent zombies on systems with a TouchBar.

	 */

	if (ourNSWindow == [NSApp keyWindow]) {
	    [NSApp _setKeyWindow:nil];
	    [NSApp _setMainWindow:nil];
	}
	[ourNSWindow close];
	[ourNSWindow release];
	[NSApp _resetAutoreleasePool];

#if DEBUG_ZOMBIES > 1
	fprintf(stderr, "================= Pool dump ===================\n");
	[NSAutoreleasePool showPools];
#endif

    }

    /*
     * Deallocate the wmInfo and clear the wmInfoPtr.
     */

    ckfree(wmPtr);
    winPtr->wmInfoPtr = NULL;
}

/*
 *----------------------------------------------------------------------
 *
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
	Tcl_SetErrorCode(interp, "TK", "WM", "WITHDRAW", "ICON", NULL);
	return TCL_ERROR;
    }

    TkpWmSetState(winPtr, WithdrawnState);

    NSWindow *win = TkMacOSXDrawableWindow(winPtr->window);
    [win orderOut:nil];
    [win setExcludedFromWindowsMenu:YES];

    /*
     * If this window has a transient, the transient must also be withdrawn.
     */

    for (Transient *transientPtr = wmPtr->transientPtr;







|







3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
	Tcl_SetErrorCode(interp, "TK", "WM", "WITHDRAW", "ICON", NULL);
	return TCL_ERROR;
    }

    TkpWmSetState(winPtr, WithdrawnState);

    NSWindow *win = TkMacOSXDrawableWindow(winPtr->window);
    [win orderOut:NSApp];
    [win setExcludedFromWindowsMenu:YES];

    /*
     * If this window has a transient, the transient must also be withdrawn.
     */

    for (Transient *transientPtr = wmPtr->transientPtr;

Changes to tests/bind.test.

6623
6624
6625
6626
6627
6628
6629


6630
6631
6632
6633
6634
6635
6636
6637
6638
6639
    # Old implementation failed, and returned "first", but this was wrong,
    # because both bindings are homogeneous equal, so the most recently defined
    # must be preferred.
} -result {last}

test bind-34.1 {-warp works relatively to a window} -setup {
    toplevel .top


} -body {
    # In order to avoid platform-dependent coordinate results due to
    # decorations and borders, this test warps the pointer twice 
    # relatively to a window that moved in the meantime, and checks
    # how much the pointer moved
    wm geometry .top +200+200
    update
    event generate .top <Motion> -x 20 -y 20 -warp 1
    update idletasks ; # DoWarp is an idle callback
    after 50         ; # Win specific - wait for SendInput to be executed







>
>


|







6623
6624
6625
6626
6627
6628
6629
6630
6631
6632
6633
6634
6635
6636
6637
6638
6639
6640
6641
    # Old implementation failed, and returned "first", but this was wrong,
    # because both bindings are homogeneous equal, so the most recently defined
    # must be preferred.
} -result {last}

test bind-34.1 {-warp works relatively to a window} -setup {
    toplevel .top
    wm geometry .top +100+100
    update
} -body {
    # In order to avoid platform-dependent coordinate results due to
    # decorations and borders, this test warps the pointer twice
    # relatively to a window that moved in the meantime, and checks
    # how much the pointer moved
    wm geometry .top +200+200
    update
    event generate .top <Motion> -x 20 -y 20 -warp 1
    update idletasks ; # DoWarp is an idle callback
    after 50         ; # Win specific - wait for SendInput to be executed
6702
6703
6704
6705
6706
6707
6708



































































































































6709
6710
6711
6712
6713
6714
6715
6716
6717
        } else {
            lappend res $dim
        }
    }
    set res
} -cleanup {
} -result {ok ok ok ok}




































































































































# cleanup
cleanupTests
return

# vi:set ts=4 sw=4 et:
# Local Variables:
# mode: tcl
# End:







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









6704
6705
6706
6707
6708
6709
6710
6711
6712
6713
6714
6715
6716
6717
6718
6719
6720
6721
6722
6723
6724
6725
6726
6727
6728
6729
6730
6731
6732
6733
6734
6735
6736
6737
6738
6739
6740
6741
6742
6743
6744
6745
6746
6747
6748
6749
6750
6751
6752
6753
6754
6755
6756
6757
6758
6759
6760
6761
6762
6763
6764
6765
6766
6767
6768
6769
6770
6771
6772
6773
6774
6775
6776
6777
6778
6779
6780
6781
6782
6783
6784
6785
6786
6787
6788
6789
6790
6791
6792
6793
6794
6795
6796
6797
6798
6799
6800
6801
6802
6803
6804
6805
6806
6807
6808
6809
6810
6811
6812
6813
6814
6815
6816
6817
6818
6819
6820
6821
6822
6823
6824
6825
6826
6827
6828
6829
6830
6831
6832
6833
6834
6835
6836
6837
6838
6839
6840
6841
6842
6843
6844
6845
6846
6847
6848
6849
6850
        } else {
            lappend res $dim
        }
    }
    set res
} -cleanup {
} -result {ok ok ok ok}

set keyInfo {}
set numericKeysym {}
proc testKey {window event type mods} {
    global keyInfo numericKeysym
    set keyInfo {}
    set numericKeysym {}
    bind $window <KeyPress> {
	set keyInfo [format "%K,0x%%X,0x%%X,%A" %N %k]
	set numericKeysym %N
    }
    focus -force $window
    update
    event generate $window $event
    if {$keyInfo == {}} {
        vwait keyInfo
    }
    set save $keyInfo
    set keyInfo {}
    set injectcmd [list injectkeyevent $type $numericKeysym]
    foreach {option} $mods {
	lappend injectcmd $option
    }
    eval $injectcmd
    if {$keyInfo == {}} {
        vwait keyInfo
    }
    if {$save != $keyInfo} {
	return "[format "0x%x" $numericKeysym] ($mods): $save != $keyInfo"
    }
    return pass
}
proc testKeyWithMods {window keysym type} {
    set result [testKey $window "<$keysym>" $type {}]
    if {$result != {pass}} {
	return $result
    }
    set result [testKey $window "<Shift-$keysym>" $type {-shift}]
    if {$result != {pass}} {
	return $result
    }
    set result [testKey $window "<Option-$keysym>" $type {-option}]
    if {$result != {pass}} {
	return $result
    }
    set result [testKey $window "<Shift-Option-$keysym>" $type {-shift -option}]
    if {$result != {pass}} {
	return $result
    }
    return pass
}
test bind-35.0 {Generated and real key events agree} -constraints {aqua} -body {
    foreach k {o O F2 Home Right Greek_sigma Greek_ALPHA} {
	set result [testKeyWithMods . $k press]
	if {$result != "pass"} {
	    return $result
	}
    }
    return pass
} -cleanup {
} -result pass

test bind-35.1 {Key events agree for entry widgets} -constraints {aqua} -setup {
    toplevel .new
    entry .new.e
    pack .new.e
} -body {
    foreach k {o O F2 Home Right Greek_sigma Greek_ALPHA Menu} {
	set result [testKeyWithMods .new.e $k press]
	if {$result != "pass"} {
	    return $result
	}
    }
    return pass
} -cleanup {
    destroy .new.e
    destroy .new
} -result pass

test bind-35.2 {Can bind to function keys} -constraints {aqua} -body {
    global keyInfo numericKeysym
    bind . <KeyPress> {}
    bind . <KeyPress> {
	lappend keyInfo %K
	set numericKeysym %N
    }
    set keyInfo {}
    set numericKeysym {}
    focus -force .
    event generate . <F2>
    injectkeyevent press $numericKeysym -function
    vwait keyInfo
    return $keyInfo
} -cleanup {
} -result {F2 F2}

test bind-35.3 {Events agree for modifier keys} -constraints {aqua} -setup {
} -body {
    global keyInfo numericalKeysym
    set result {}
    bind . <KeyPress> {
    	set keyInfo [format "%K,0x%%X,0x%%X,%A" %N %k]
    	set numericalKeysym [format "0x%x" %N]
    }
    foreach event {
	{<Control_L> -control}
	{<Control_R> -control}
	{<Alt_L> -option}
	{<Alt_R> -option}
	{<Meta_L> -command}
	{<Meta_R> -command}
	{<Shift_L> -shift}
	{<Shift_R> -shift}
    } {
	set keyInfo {}
	event generate . [lindex $event 0]
	if {$keyInfo == {}} {
	    vwait keyInfo
	}
	set save $keyInfo
	injectkeyevent flagschanged $numericKeysym [lindex $event 1]
	if {$keyInfo == {}} {
	    vwait keyInfo
	}
	if {$save != $keyInfo} {
	    return "$save != $keyInfo"
	}
    }
    return pass
} -cleanup {
} -result pass

# cleanup
cleanupTests
return

# vi:set ts=4 sw=4 et:
# Local Variables:
# mode: tcl
# End:

Changes to tests/canvImg.test.

799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
} -body {
    image create test foo -variable x
    image create test foo2 -variable z
    foo changed 0 0 0 0 40 50
    foo2 changed 0 0 0 0 80 60
    .c create image 50 100 -image foo -tags image -anchor nw
    .c create image 70 110 -image foo2 -anchor nw
    update
    set z {}
    set timer [after 500 {lappend z "timed out"}]
    image create test foo -variable x
    vwait x
    after cancel $timer
    return $z
} -cleanup {







|







799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
} -body {
    image create test foo -variable x
    image create test foo2 -variable z
    foo changed 0 0 0 0 40 50
    foo2 changed 0 0 0 0 80 60
    .c create image 50 100 -image foo -tags image -anchor nw
    .c create image 70 110 -image foo2 -anchor nw
    update idletasks
    set z {}
    set timer [after 500 {lappend z "timed out"}]
    image create test foo -variable x
    vwait x
    after cancel $timer
    return $z
} -cleanup {

Changes to tests/canvText.test.

959
960
961
962
963
964
965














966
967
968
969
    list [expr {$bb0 eq $bb2 ? "ok" : "$bb0,$bb2"}] \
	[expr {$bb1 eq $bb3 ? "ok" : "$bb1,$bb3"}] \
	[expr {$bb0 eq [transpose $bb1] ? "ok" : "$bb0,$bb1"}] \
} -cleanup {
    destroy .c
    rename transpose {}
} -result {ok ok ok}















# cleanup
cleanupTests
return







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




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
    list [expr {$bb0 eq $bb2 ? "ok" : "$bb0,$bb2"}] \
	[expr {$bb1 eq $bb3 ? "ok" : "$bb1,$bb3"}] \
	[expr {$bb0 eq [transpose $bb1] ? "ok" : "$bb0,$bb1"}] \
} -cleanup {
    destroy .c
    rename transpose {}
} -result {ok ok ok}

test canvText-20.2 {crash on angled text selection (X11, without xft) - bug 2712f43f6e} -setup {
    destroy .c
    canvas .c -background bisque -selectforeground green2
    grid .c
    set id [.c create text 50 150 -anchor w -text "Angled text" \
	    -angle 30 -font {Helvetica 32} -fill darkblue]
} -body {
    .c select clear
    .c select from $id 0
    .c select to $id 8 ; update    ;  # used to crash on X11 (--disable-xft build only)
} -cleanup {
    destroy .c
} -result {}

# cleanup
cleanupTests
return

Changes to tests/event.test.

856
857
858
859
860
861
862

863
864
865
866
867
868
869
                physical key - in this case, test is actually void."
    }
} -cleanup {
    deleteWindows
} -result {OK}

# cleanup

unset -nocomplain keypress_lookup
rename _init_keypress_lookup {}
rename _keypress_lookup {}
rename _keypress {}
rename _pause {}
rename _text_ind_to_x_y {}
rename _get_selection {}







>







856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
                physical key - in this case, test is actually void."
    }
} -cleanup {
    deleteWindows
} -result {OK}

# cleanup
update
unset -nocomplain keypress_lookup
rename _init_keypress_lookup {}
rename _keypress_lookup {}
rename _keypress {}
rename _pause {}
rename _text_ind_to_x_y {}
rename _get_selection {}

Changes to tests/frame.test.

669
670
671
672
673
674
675


676
677


678



679
680

681
682
683
684
685
686
687
test frame-3.10 {TkCreateFrame procedure, -use option} -constraints {
    unix
} -setup {
    deleteWindows
} -body {
    toplevel .t -container 1 -width 300 -height 120
    wm geometry .t +0+0


    option add *x.use [winfo id .t]
    update


    toplevel .x -width 140 -height 300 -bg green



    tkwait visibility .x
    update

    list [expr {[winfo rootx .x] - [winfo rootx .t]}] \
	    [expr {[winfo rooty .x] - [winfo rooty .t]}] \
	    [winfo width .t] [winfo height .t]
} -cleanup {
    destroy .t
    option clear
} -result {0 0 140 300}







>
>
|
|
>
>

>
>
>
|
|
>







669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
test frame-3.10 {TkCreateFrame procedure, -use option} -constraints {
    unix
} -setup {
    deleteWindows
} -body {
    toplevel .t -container 1 -width 300 -height 120
    wm geometry .t +0+0
    if {[tk windowingsystem] eq "aqua"} {
	update idletasks
    } else {
	update
    }
    option add *x.use [winfo id .t]
    toplevel .x -width 140 -height 300 -bg green
    if {[tk windowingsystem] eq "aqua"} {
	update idletasks
    } else {
	tkwait visibility .x
	update
    }
    list [expr {[winfo rootx .x] - [winfo rootx .t]}] \
	    [expr {[winfo rooty .x] - [winfo rooty .t]}] \
	    [winfo width .t] [winfo height .t]
} -cleanup {
    destroy .t
    option clear
} -result {0 0 140 300}
1150
1151
1152
1153
1154
1155
1156

1157
1158
1159
1160
1161
1162



1163

1164
1165
1166



1167

1168
1169
1170
1171
1172
1173
1174
    }
    return $result
} -cleanup {
    deleteWindows
} -result {1 1 1 1 1 1 1 1 1 1 1 1}
test frame-12.3 {FrameWorldChanged procedure} -setup {
	deleteWindows

} -body {
    # Check reaction on font change
    font create myfont -family courier -size 10
    labelframe .f -font myfont -text Mupp
    place .f -x 0 -y 0 -width 40 -height 40
    pack [frame .f.f] -fill both -expand 1



    update

    set h1 [font metrics myfont -linespace]
    set y1 [winfo y .f.f]
    font configure myfont -size 20



    update

    set h2 [font metrics myfont -linespace]
    set y2 [winfo y .f.f]
    expr {($h2 - $h1) - ($y2 - $y1)}
} -cleanup {
    deleteWindows
    font delete myfont
} -result {0}







>






>
>
>
|
>



>
>
>
|
>







1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
    }
    return $result
} -cleanup {
    deleteWindows
} -result {1 1 1 1 1 1 1 1 1 1 1 1}
test frame-12.3 {FrameWorldChanged procedure} -setup {
	deleteWindows
	update idletasks
} -body {
    # Check reaction on font change
    font create myfont -family courier -size 10
    labelframe .f -font myfont -text Mupp
    place .f -x 0 -y 0 -width 40 -height 40
    pack [frame .f.f] -fill both -expand 1
    if {[tk windowingsystem] eq "aqua"} {
	update idletasks
    } else {
	update
    }
    set h1 [font metrics myfont -linespace]
    set y1 [winfo y .f.f]
    font configure myfont -size 20
    if {[tk windowingsystem] eq "aqua"} {
	update idletasks
    } else {
	update
    }
    set h2 [font metrics myfont -linespace]
    set y2 [winfo y .f.f]
    expr {($h2 - $h1) - ($y2 - $y1)}
} -cleanup {
    deleteWindows
    font delete myfont
} -result {0}

Changes to tests/text.test.

6688
6689
6690
6691
6692
6693
6694

6695
6696
6697
6698
6699
6700
6701
6702
    .t insert end "and it will be impacted by the <Delete> event received.\n"
    .t insert end "Therefore a <<Selection>> event must fire back."
    .t tag add sel 1.0 1.28
    bind .t <<Selection>> "set ::retval <<Selection>>_fired"
    update
    set ::retval no_<<Selection>>_event_fired
    .t mark set insert 1.15

    focus .t
    event generate .t <Delete>
    update
    set ::retval
} -cleanup {
    destroy .t
} -result {<<Selection>>_fired}
test text-27.15e {No <<Selection>> virtual event on <Delete> with cursor outside selection} -body {







>
|







6688
6689
6690
6691
6692
6693
6694
6695
6696
6697
6698
6699
6700
6701
6702
6703
    .t insert end "and it will be impacted by the <Delete> event received.\n"
    .t insert end "Therefore a <<Selection>> event must fire back."
    .t tag add sel 1.0 1.28
    bind .t <<Selection>> "set ::retval <<Selection>>_fired"
    update
    set ::retval no_<<Selection>>_event_fired
    .t mark set insert 1.15
    update idletasks
    focus -force .t
    event generate .t <Delete>
    update
    set ::retval
} -cleanup {
    destroy .t
} -result {<<Selection>>_fired}
test text-27.15e {No <<Selection>> virtual event on <Delete> with cursor outside selection} -body {

Changes to tests/ttk/entry.test.

69
70
71
72
73
74
75












76
77
78
79
80
81
82

test entry-2.1 "Create entry before scrollbar" -body {
    pack [ttk::entry .te -xscrollcommand [list .tsb set]] \
	-expand true -fill both
    pack [ttk::scrollbar .tsb -orient horizontal -command [list .te xview]] \
    	-expand false -fill x
}  -cleanup {destroy .te .tsb}













test entry-2.2 "Initial scroll position" -body {
    ttk::entry .e -font fixed -width 5 -xscrollcommand scroll
    .e insert end "0123456789"
    pack .e;
    set timeout [after 500 {set $scrollInfo "timeout"}]
    vwait scrollInfo







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







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

test entry-2.1 "Create entry before scrollbar" -body {
    pack [ttk::entry .te -xscrollcommand [list .tsb set]] \
	-expand true -fill both
    pack [ttk::scrollbar .tsb -orient horizontal -command [list .te xview]] \
    	-expand false -fill x
}  -cleanup {destroy .te .tsb}

test entry-2.1.1 "Create entry before scrollbar - scrollbar catches up" -body {
    pack [ttk::entry .te -xscrollcommand [list .tsb set]] \
	-expand true -fill both
    .te insert end [string repeat "abc" 50]
    catch {update} ; # error triggers because the -xscrollcommand callback
                     # errors out: invalid command name ".tsb"
    pack [ttk::scrollbar .tsb -orient horizontal -command [list .te xview]] \
    	-expand false -fill x
    update ; # no error
    lappend res [expr [lindex [.tsb get] 1] < 1] ; # scrollbar did update
} -result {1} -cleanup {destroy .te .tsb}

test entry-2.2 "Initial scroll position" -body {
    ttk::entry .e -font fixed -width 5 -xscrollcommand scroll
    .e insert end "0123456789"
    pack .e;
    set timeout [after 500 {set $scrollInfo "timeout"}]
    vwait scrollInfo

Changes to tests/ttk/treeview.test.

503
504
505
506
507
508
509






















































510
511
512
513
514
515
516
    }
} -body {
    .tree yview scroll 5 units
    .tree identify item 2 2
} -cleanup {
    destroy .tree
} -result {I006}























































### identify tests:
#
proc identify* {tv comps args} {
    foreach {x y} $args {
	foreach comp $comps {
	    lappend result [$tv identify $comp $x $y]







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







503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
    }
} -body {
    .tree yview scroll 5 units
    .tree identify item 2 2
} -cleanup {
    destroy .tree
} -result {I006}

test treeview-9.2 {scrolling on see command - bug [14188104c3]} -setup {
    toplevel .top
    ttk::treeview .top.tree -show {} -height 10 -columns {label} \
            -yscrollcommand [list .top.vs set]
    ttk::scrollbar .top.vs -command {.top.tree yview}
    grid .top.tree -row 0 -column 0 -sticky ns
    grid .top.vs -row 0 -column 1 -sticky ns
    update
    proc setrows {n} {
        .top.tree delete [.top.tree children {}]
        for {set i 1} {$i <= $n} {incr i} {
            .top.tree insert {} end -id row$i \
                    -values [list [format "Row %2.2d" $i]]
        }
        .top.tree see row1
        update idletasks
    }
} -body {
    setrows 10
    set res [.top.vs get]
    setrows 20
    lappend res [expr [lindex [.top.vs get] 1] < 1]
} -cleanup {
    destroy .top
} -result {0.0 1.0 1}

test treeview-9.3 {scrolling on see command, requested item is closed} -setup {
    toplevel .top
    ttk::treeview .top.tree -show tree -height 10 -columns {label} \
            -yscrollcommand [list .top.vs set]
    ttk::scrollbar .top.vs -command {.top.tree yview}
    grid .top.tree -row 0 -column 0 -sticky ns
    grid .top.vs -row 0 -column 1 -sticky ns

    .top.tree insert {} end -id a -text a
    .top.tree insert a  end -id b -text b
    .top.tree insert b  end -id c -text c
    .top.tree insert c  end -id d -text d
    .top.tree insert d  end -id e -text e
    for {set i 6} {$i <= 15} {incr i} {
        .top.tree insert {} end -id row$i \
                -values [list [format "Row %2.2d" $i]]
    }
    update
} -body {
    set before [lindex [.top.vs get] 1]
    .top.tree see e
    update idletasks
    set after [lindex [.top.vs get] 1]
    expr $after < $before
} -cleanup {
    destroy .top
} -result {1}

### identify tests:
#
proc identify* {tv comps args} {
    foreach {x y} $args {
	foreach comp $comps {
	    lappend result [$tv identify $comp $x $y]

Changes to unix/configure.

4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
		    case `${CC} -dumpmachine` in
			hppa64*)
			    # 64-bit gcc in use.  Fix flags for GNU ld.
			    do64bit_ok=yes
			    SHLIB_LD='${CC} -shared'
			    if test $doRpath = yes; then

				CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
fi

			    LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
			    ;;
			*)
			    { echo "$as_me:$LINENO: WARNING: 64bit mode not supported with GCC on $system" >&5
echo "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;}







|







4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
		    case `${CC} -dumpmachine` in
			hppa64*)
			    # 64-bit gcc in use.  Fix flags for GNU ld.
			    do64bit_ok=yes
			    SHLIB_LD='${CC} -shared'
			    if test $doRpath = yes; then

				CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
fi

			    LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
			    ;;
			*)
			    { echo "$as_me:$LINENO: WARNING: 64bit mode not supported with GCC on $system" >&5
echo "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;}
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149
5150
    "mkstemp.$ac_objext "* | \
  *" mkstemp.$ac_objext "* ) ;;
  *) LIBOBJS="$LIBOBJS mkstemp.$ac_objext" ;;
esac

	    if test $doRpath = yes; then

		CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
		LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'
fi

	    ;;
	IRIX-6.*)
	    SHLIB_CFLAGS=""
	    SHLIB_LD="ld -n32 -shared -rdata_shared"
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    case $LIBOBJS in
    "mkstemp.$ac_objext"   | \
  *" mkstemp.$ac_objext"   | \
    "mkstemp.$ac_objext "* | \
  *" mkstemp.$ac_objext "* ) ;;
  *) LIBOBJS="$LIBOBJS mkstemp.$ac_objext" ;;
esac

	    if test $doRpath = yes; then

		CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
		LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'
fi

	    if test "$GCC" = yes; then

		CFLAGS="$CFLAGS -mabi=n32"
		LDFLAGS="$LDFLAGS -mabi=n32"







|




















|







5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149
5150
    "mkstemp.$ac_objext "* | \
  *" mkstemp.$ac_objext "* ) ;;
  *) LIBOBJS="$LIBOBJS mkstemp.$ac_objext" ;;
esac

	    if test $doRpath = yes; then

		CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
		LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'
fi

	    ;;
	IRIX-6.*)
	    SHLIB_CFLAGS=""
	    SHLIB_LD="ld -n32 -shared -rdata_shared"
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    case $LIBOBJS in
    "mkstemp.$ac_objext"   | \
  *" mkstemp.$ac_objext"   | \
    "mkstemp.$ac_objext "* | \
  *" mkstemp.$ac_objext "* ) ;;
  *) LIBOBJS="$LIBOBJS mkstemp.$ac_objext" ;;
esac

	    if test $doRpath = yes; then

		CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
		LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'
fi

	    if test "$GCC" = yes; then

		CFLAGS="$CFLAGS -mabi=n32"
		LDFLAGS="$LDFLAGS -mabi=n32"
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
    "mkstemp.$ac_objext "* | \
  *" mkstemp.$ac_objext "* ) ;;
  *) LIBOBJS="$LIBOBJS mkstemp.$ac_objext" ;;
esac

	    if test $doRpath = yes; then

		CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
		LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'
fi


	    # Check to enable 64-bit flags for compiler/linker

	    if test "$do64bit" = yes; then







|







5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
    "mkstemp.$ac_objext "* | \
  *" mkstemp.$ac_objext "* ) ;;
  *) LIBOBJS="$LIBOBJS mkstemp.$ac_objext" ;;
esac

	    if test $doRpath = yes; then

		CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
		LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'
fi


	    # Check to enable 64-bit flags for compiler/linker

	    if test "$do64bit" = yes; then
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234

	    SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS} -shared'
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS="-ldl"
	    LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
	    if test $doRpath = yes; then

		CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
fi

	    LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
	    if test "`uname -m`" = "alpha"; then
  CFLAGS="$CFLAGS -mieee"
fi








|







5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234

	    SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS} -shared'
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS="-ldl"
	    LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
	    if test $doRpath = yes; then

		CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
fi

	    LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
	    if test "`uname -m`" = "alpha"; then
  CFLAGS="$CFLAGS -mieee"
fi

5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
	    CFLAGS_OPTIMIZE=-02
	    SHLIB_LD='${CC} -shared'
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS="-mshared -ldl"
	    LD_FLAGS="-Wl,--export-dynamic"
	    if test $doRpath = yes; then

		CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
		LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
fi

	    ;;
	MP-RAS-02*)
	    SHLIB_CFLAGS="-K PIC"
	    SHLIB_LD='${CC} -G'
	    SHLIB_LD_LIBS=""







|
|







5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
	    CFLAGS_OPTIMIZE=-02
	    SHLIB_LD='${CC} -shared'
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS="-mshared -ldl"
	    LD_FLAGS="-Wl,--export-dynamic"
	    if test $doRpath = yes; then

		CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
		LD_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
fi

	    ;;
	MP-RAS-02*)
	    SHLIB_CFLAGS="-K PIC"
	    SHLIB_LD='${CC} -G'
	    SHLIB_LD_LIBS=""
5362
5363
5364
5365
5366
5367
5368
5369
5370
5371
5372
5373
5374
5375
5376
	    esac
	    SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared'
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    if test $doRpath = yes; then

		CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
fi

	    LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
	    SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}'
	    LDFLAGS="-Wl,-export-dynamic"
	    CFLAGS_OPTIMIZE="-O2"
	    if test "${TCL_THREADS}" = "1"; then







|







5362
5363
5364
5365
5366
5367
5368
5369
5370
5371
5372
5373
5374
5375
5376
	    esac
	    SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared'
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    if test $doRpath = yes; then

		CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
fi

	    LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
	    SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}'
	    LDFLAGS="-Wl,-export-dynamic"
	    CFLAGS_OPTIMIZE="-O2"
	    if test "${TCL_THREADS}" = "1"; then
5392
5393
5394
5395
5396
5397
5398
5399
5400
5401
5402
5403
5404
5405
5406
	    SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared'
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    LDFLAGS="$LDFLAGS -export-dynamic"
	    if test $doRpath = yes; then

		CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
fi

	    LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
	    if test "${TCL_THREADS}" = "1"; then

		# The -pthread needs to go in the CFLAGS, not LIBS
		LIBS=`echo $LIBS | sed s/-pthread//`







|







5392
5393
5394
5395
5396
5397
5398
5399
5400
5401
5402
5403
5404
5405
5406
	    SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared'
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    LDFLAGS="$LDFLAGS -export-dynamic"
	    if test $doRpath = yes; then

		CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
fi

	    LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
	    if test "${TCL_THREADS}" = "1"; then

		# The -pthread needs to go in the CFLAGS, not LIBS
		LIBS=`echo $LIBS | sed s/-pthread//`
5416
5417
5418
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
5430
5431
	    SHLIB_LD="${CC} -shared"
	    SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,-soname,\$@"
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    if test $doRpath = yes; then

		CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
		LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
fi

	    if test "${TCL_THREADS}" = "1"; then

		# The -pthread needs to go in the LDFLAGS, not LIBS
		LIBS=`echo $LIBS | sed s/-pthread//`
		CFLAGS="$CFLAGS $PTHREAD_CFLAGS"







|
|







5416
5417
5418
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
5430
5431
	    SHLIB_LD="${CC} -shared"
	    SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,-soname,\$@"
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    if test $doRpath = yes; then

		CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
		LD_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
fi

	    if test "${TCL_THREADS}" = "1"; then

		# The -pthread needs to go in the LDFLAGS, not LIBS
		LIBS=`echo $LIBS | sed s/-pthread//`
		CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
6006
6007
6008
6009
6010
6011
6012
6013
6014
6015
6016
6017
6018
6019
6020
fi

	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    if test $doRpath = yes; then

		CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
		LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'
fi

	    if test "$GCC" = yes; then
  CFLAGS="$CFLAGS -mieee"
else








|







6006
6007
6008
6009
6010
6011
6012
6013
6014
6015
6016
6017
6018
6019
6020
fi

	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    if test $doRpath = yes; then

		CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
		LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'
fi

	    if test "$GCC" = yes; then
  CFLAGS="$CFLAGS -mieee"
else

Changes to unix/tcl.m4.

1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
		AS_IF([test "$GCC" = yes], [
		    case `${CC} -dumpmachine` in
			hppa64*)
			    # 64-bit gcc in use.  Fix flags for GNU ld.
			    do64bit_ok=yes
			    SHLIB_LD='${CC} -shared'
			    AS_IF([test $doRpath = yes], [
				CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'])
			    LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
			    ;;
			*)
			    AC_MSG_WARN([64bit mode not supported with GCC on $system])
			    ;;
		    esac
		], [







|







1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
		AS_IF([test "$GCC" = yes], [
		    case `${CC} -dumpmachine` in
			hppa64*)
			    # 64-bit gcc in use.  Fix flags for GNU ld.
			    do64bit_ok=yes
			    SHLIB_LD='${CC} -shared'
			    AS_IF([test $doRpath = yes], [
				CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'])
			    LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
			    ;;
			*)
			    AC_MSG_WARN([64bit mode not supported with GCC on $system])
			    ;;
		    esac
		], [
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
	    SHLIB_CFLAGS=""
	    SHLIB_LD="ld -shared -rdata_shared"
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    AC_LIBOBJ(mkstemp)
	    AS_IF([test $doRpath = yes], [
		CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
		LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'])
	    ;;
	IRIX-6.*)
	    SHLIB_CFLAGS=""
	    SHLIB_LD="ld -n32 -shared -rdata_shared"
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    AC_LIBOBJ(mkstemp)
	    AS_IF([test $doRpath = yes], [
		CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
		LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'])
	    AS_IF([test "$GCC" = yes], [
		CFLAGS="$CFLAGS -mabi=n32"
		LDFLAGS="$LDFLAGS -mabi=n32"
	    ], [
		case $system in
		    IRIX-6.3)







|










|







1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
	    SHLIB_CFLAGS=""
	    SHLIB_LD="ld -shared -rdata_shared"
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    AC_LIBOBJ(mkstemp)
	    AS_IF([test $doRpath = yes], [
		CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
		LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'])
	    ;;
	IRIX-6.*)
	    SHLIB_CFLAGS=""
	    SHLIB_LD="ld -n32 -shared -rdata_shared"
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    AC_LIBOBJ(mkstemp)
	    AS_IF([test $doRpath = yes], [
		CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
		LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'])
	    AS_IF([test "$GCC" = yes], [
		CFLAGS="$CFLAGS -mabi=n32"
		LDFLAGS="$LDFLAGS -mabi=n32"
	    ], [
		case $system in
		    IRIX-6.3)
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
	    SHLIB_CFLAGS=""
	    SHLIB_LD="ld -n32 -shared -rdata_shared"
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    AC_LIBOBJ(mkstemp)
	    AS_IF([test $doRpath = yes], [
		CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
		LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'])

	    # Check to enable 64-bit flags for compiler/linker

	    AS_IF([test "$do64bit" = yes], [
	        AS_IF([test "$GCC" = yes], [
	            AC_MSG_WARN([64bit mode not supported by gcc])







|







1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
	    SHLIB_CFLAGS=""
	    SHLIB_LD="ld -n32 -shared -rdata_shared"
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    AC_LIBOBJ(mkstemp)
	    AS_IF([test $doRpath = yes], [
		CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
		LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'])

	    # Check to enable 64-bit flags for compiler/linker

	    AS_IF([test "$do64bit" = yes], [
	        AS_IF([test "$GCC" = yes], [
	            AC_MSG_WARN([64bit mode not supported by gcc])
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
	    #CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D__NO_STRING_INLINES -D__NO_MATH_INLINES"

	    SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS} -shared'
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS="-ldl"
	    LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
	    AS_IF([test $doRpath = yes], [
		CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'])
	    LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
	    AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"])
	    AS_IF([test $do64bit = yes], [
		AC_CACHE_CHECK([if compiler accepts -m64 flag], tcl_cv_cc_m64, [
		    hold_cflags=$CFLAGS
		    CFLAGS="$CFLAGS -m64"
		    AC_TRY_LINK(,, tcl_cv_cc_m64=yes, tcl_cv_cc_m64=no)







|







1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
	    #CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D__NO_STRING_INLINES -D__NO_MATH_INLINES"

	    SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS} -shared'
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS="-ldl"
	    LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
	    AS_IF([test $doRpath = yes], [
		CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'])
	    LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
	    AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"])
	    AS_IF([test $do64bit = yes], [
		AC_CACHE_CHECK([if compiler accepts -m64 flag], tcl_cv_cc_m64, [
		    hold_cflags=$CFLAGS
		    CFLAGS="$CFLAGS -m64"
		    AC_TRY_LINK(,, tcl_cv_cc_m64=yes, tcl_cv_cc_m64=no)
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
	    SHLIB_SUFFIX=".so"
	    CFLAGS_OPTIMIZE=-02
	    SHLIB_LD='${CC} -shared'
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS="-mshared -ldl"
	    LD_FLAGS="-Wl,--export-dynamic"
	    AS_IF([test $doRpath = yes], [
		CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
		LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'])
	    ;;
	MP-RAS-02*)
	    SHLIB_CFLAGS="-K PIC"
	    SHLIB_LD='${CC} -G'
	    SHLIB_LD_LIBS=""
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"







|
|







1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
	    SHLIB_SUFFIX=".so"
	    CFLAGS_OPTIMIZE=-02
	    SHLIB_LD='${CC} -shared'
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS="-mshared -ldl"
	    LD_FLAGS="-Wl,--export-dynamic"
	    AS_IF([test $doRpath = yes], [
		CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
		LD_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'])
	    ;;
	MP-RAS-02*)
	    SHLIB_CFLAGS="-K PIC"
	    SHLIB_LD='${CC} -G'
	    SHLIB_LD_LIBS=""
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
		;;
	    esac
	    SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared'
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    AS_IF([test $doRpath = yes], [
		CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'])
	    LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
	    SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}'
	    LDFLAGS="-Wl,-export-dynamic"
	    CFLAGS_OPTIMIZE="-O2"
	    AS_IF([test "${TCL_THREADS}" = "1"], [
		# On OpenBSD:	Compile with -pthread
		#		Don't link with -lpthread







|







1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
		;;
	    esac
	    SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared'
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    AS_IF([test $doRpath = yes], [
		CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'])
	    LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
	    SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}'
	    LDFLAGS="-Wl,-export-dynamic"
	    CFLAGS_OPTIMIZE="-O2"
	    AS_IF([test "${TCL_THREADS}" = "1"], [
		# On OpenBSD:	Compile with -pthread
		#		Don't link with -lpthread
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
	    SHLIB_CFLAGS="-fPIC"
	    SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared'
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    LDFLAGS="$LDFLAGS -export-dynamic"
	    AS_IF([test $doRpath = yes], [
		CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'])
	    LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
	    AS_IF([test "${TCL_THREADS}" = "1"], [
		# The -pthread needs to go in the CFLAGS, not LIBS
		LIBS=`echo $LIBS | sed s/-pthread//`
		CFLAGS="$CFLAGS -pthread"
	    	LDFLAGS="$LDFLAGS -pthread"
	    ])
	    ;;
	DragonFly-*|FreeBSD-*)
	    # This configuration from FreeBSD Ports.
	    SHLIB_CFLAGS="-fPIC"
	    SHLIB_LD="${CC} -shared"
	    SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,-soname,\$[@]"
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    AS_IF([test $doRpath = yes], [
		CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
		LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'])
	    AS_IF([test "${TCL_THREADS}" = "1"], [
		# The -pthread needs to go in the LDFLAGS, not LIBS
		LIBS=`echo $LIBS | sed s/-pthread//`
		CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
		LDFLAGS="$LDFLAGS $PTHREAD_LIBS"])
	    case $system in
	    FreeBSD-3.*)







|

















|
|







1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
	    SHLIB_CFLAGS="-fPIC"
	    SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared'
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    LDFLAGS="$LDFLAGS -export-dynamic"
	    AS_IF([test $doRpath = yes], [
		CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'])
	    LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
	    AS_IF([test "${TCL_THREADS}" = "1"], [
		# The -pthread needs to go in the CFLAGS, not LIBS
		LIBS=`echo $LIBS | sed s/-pthread//`
		CFLAGS="$CFLAGS -pthread"
	    	LDFLAGS="$LDFLAGS -pthread"
	    ])
	    ;;
	DragonFly-*|FreeBSD-*)
	    # This configuration from FreeBSD Ports.
	    SHLIB_CFLAGS="-fPIC"
	    SHLIB_LD="${CC} -shared"
	    SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,-soname,\$[@]"
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    AS_IF([test $doRpath = yes], [
		CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
		LD_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'])
	    AS_IF([test "${TCL_THREADS}" = "1"], [
		# The -pthread needs to go in the LDFLAGS, not LIBS
		LIBS=`echo $LIBS | sed s/-pthread//`
		CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
		LDFLAGS="$LDFLAGS $PTHREAD_LIBS"])
	    case $system in
	    FreeBSD-3.*)
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
	    ], [
	        SHLIB_LD='ld -non_shared -expect_unresolved "*"'
	    ])
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    AS_IF([test $doRpath = yes], [
		CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
		LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'])
	    AS_IF([test "$GCC" = yes], [CFLAGS="$CFLAGS -mieee"], [
		CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"])
	    # see pthread_intro(3) for pthread support on osf1, k.furukawa
	    AS_IF([test "${TCL_THREADS}" = 1], [
		CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE"
		CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64"







|







1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
	    ], [
	        SHLIB_LD='ld -non_shared -expect_unresolved "*"'
	    ])
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    AS_IF([test $doRpath = yes], [
		CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'
		LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'])
	    AS_IF([test "$GCC" = yes], [CFLAGS="$CFLAGS -mieee"], [
		CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"])
	    # see pthread_intro(3) for pthread support on osf1, k.furukawa
	    AS_IF([test "${TCL_THREADS}" = 1], [
		CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE"
		CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64"

Changes to unix/tkUnixFont.c.

3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073

3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091

3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110

3111
3112
3113
3114
3115
3116
3117
3118
3119
3120

3121
3122
3123
3124
3125
3126
3127
    int *realWidthPtr, int *realHeightPtr)
{
    int width, height;
    TkFont *fontPtr = (TkFont *) tkfont;
    Pixmap bitmap;
    GC bitmapGC;
    XGCValues values;
    XImage *image;

    (void) Tk_MeasureChars(tkfont, source, numBytes, -1, 0, &width);
    height = fontPtr->fm.ascent + fontPtr->fm.descent;


    bitmap = Tk_GetPixmap(display, drawable, width, height, 1);
    values.graphics_exposures = False;
    values.foreground = BlackPixel(display, DefaultScreen(display));
    bitmapGC = XCreateGC(display, bitmap, GCGraphicsExposures|GCForeground,
	    &values);
    XFillRectangle(display, bitmap, bitmapGC, 0, 0, width, height);

    values.font = Tk_FontId(tkfont);
    values.foreground = WhitePixel(display, DefaultScreen(display));
    values.background = BlackPixel(display, DefaultScreen(display));
    XChangeGC(display, bitmapGC, GCFont|GCForeground|GCBackground, &values);
    Tk_DrawChars(display, bitmap, bitmapGC, tkfont, source, numBytes, 0,
	    fontPtr->fm.ascent);
    XFreeGC(display, bitmapGC);

    image = XGetImage(display, bitmap, 0, 0, width, height, AllPlanes,
	    ZPixmap);
    Tk_FreePixmap(display, bitmap);


    *realWidthPtr = width;
    *realHeightPtr = height;
    return image;
}

static inline XImage *
InitDestImage(
    Display *display,
    Drawable drawable,
    int width,
    int height,
    Pixmap *bitmapPtr)
{
    Pixmap bitmap;
    XImage *image;
    GC bitmapGC;
    XGCValues values;


    bitmap = Tk_GetPixmap(display, drawable, width, height, 1);
    values.graphics_exposures = False;
    values.foreground = BlackPixel(display, DefaultScreen(display));
    bitmapGC = XCreateGC(display, bitmap, GCGraphicsExposures|GCForeground,
	    &values);
    XFillRectangle(display, bitmap, bitmapGC, 0, 0, width, height);
    XFreeGC(display, bitmapGC);

    image = XGetImage(display, bitmap, 0, 0, width, height, AllPlanes,
	    ZPixmap);

    *bitmapPtr = bitmap;
    return image;
}

void
TkDrawAngledChars(
    Display *display,		/* Display on which to draw. */







|




>
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
>














|
|



>
|
|
|
|
|
|
|

|
|
>







3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
    int *realWidthPtr, int *realHeightPtr)
{
    int width, height;
    TkFont *fontPtr = (TkFont *) tkfont;
    Pixmap bitmap;
    GC bitmapGC;
    XGCValues values;
    XImage *image = NULL;

    (void) Tk_MeasureChars(tkfont, source, numBytes, -1, 0, &width);
    height = fontPtr->fm.ascent + fontPtr->fm.descent;

    if ((width > 0) && (height > 0)) {
	bitmap = Tk_GetPixmap(display, drawable, width, height, 1);
	values.graphics_exposures = False;
	values.foreground = BlackPixel(display, DefaultScreen(display));
	bitmapGC = XCreateGC(display, bitmap, GCGraphicsExposures|GCForeground,
		&values);
	XFillRectangle(display, bitmap, bitmapGC, 0, 0, width, height);

	values.font = Tk_FontId(tkfont);
	values.foreground = WhitePixel(display, DefaultScreen(display));
	values.background = BlackPixel(display, DefaultScreen(display));
	XChangeGC(display, bitmapGC, GCFont|GCForeground|GCBackground, &values);
	Tk_DrawChars(display, bitmap, bitmapGC, tkfont, source, numBytes, 0,
		fontPtr->fm.ascent);
	XFreeGC(display, bitmapGC);

	image = XGetImage(display, bitmap, 0, 0, width, height, AllPlanes,
		ZPixmap);
	Tk_FreePixmap(display, bitmap);
    }

    *realWidthPtr = width;
    *realHeightPtr = height;
    return image;
}

static inline XImage *
InitDestImage(
    Display *display,
    Drawable drawable,
    int width,
    int height,
    Pixmap *bitmapPtr)
{
    Pixmap bitmap = None;
    XImage *image = NULL;
    GC bitmapGC;
    XGCValues values;

    if ((width > 0) && (height > 0)) {
	bitmap = Tk_GetPixmap(display, drawable, width, height, 1);
	values.graphics_exposures = False;
	values.foreground = BlackPixel(display, DefaultScreen(display));
	bitmapGC = XCreateGC(display, bitmap, GCGraphicsExposures|GCForeground,
		&values);
	XFillRectangle(display, bitmap, bitmapGC, 0, 0, width, height);
	XFreeGC(display, bitmapGC);

	image = XGetImage(display, bitmap, 0, 0, width, height, AllPlanes,
		ZPixmap);
    }
    *bitmapPtr = bitmap;
    return image;
}

void
TkDrawAngledChars(
    Display *display,		/* Display on which to draw. */

Changes to unix/tkUnixMenu.c.

855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
    int width, int height)
{
    if ((mePtr->underline >= 0) && (mePtr->labelPtr != NULL)) {
	int len;

	len = Tcl_GetCharLength(mePtr->labelPtr);
	if (mePtr->underline < len) {
	    int activeBorderWidth, leftEdge;
	    const char *label, *start, *end;

	    label = Tcl_GetString(mePtr->labelPtr);
	    start = Tcl_UtfAtIndex(label, mePtr->underline);
	    end = Tcl_UtfNext(start);

	    Tk_GetPixelsFromObj(NULL, menuPtr->tkwin,
		    menuPtr->activeBorderWidthPtr, &activeBorderWidth);
	    leftEdge = x + mePtr->indicatorSpace + activeBorderWidth;
	    if (menuPtr->menuType == MENUBAR) {
		leftEdge += 5;
	    }







|




|







855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
    int width, int height)
{
    if ((mePtr->underline >= 0) && (mePtr->labelPtr != NULL)) {
	int len;

	len = Tcl_GetCharLength(mePtr->labelPtr);
	if (mePtr->underline < len) {
	    int activeBorderWidth, leftEdge, ch;
	    const char *label, *start, *end;

	    label = Tcl_GetString(mePtr->labelPtr);
	    start = Tcl_UtfAtIndex(label, mePtr->underline);
	    end = start + TkUtfToUniChar(start, &ch);

	    Tk_GetPixelsFromObj(NULL, menuPtr->tkwin,
		    menuPtr->activeBorderWidthPtr, &activeBorderWidth);
	    leftEdge = x + mePtr->indicatorSpace + activeBorderWidth;
	    if (menuPtr->menuType == MENUBAR) {
		leftEdge += 5;
	    }

Changes to unix/tkUnixRFont.c.

250
251
252
253
254
255
256

















257
258
259
260
261
262
263
264
265
266
267
268

269
270
271
272
273
274
275
 *	also allocates a new UnixFtFont.
 *
 * Results:
 * 	On error, frees fontPtr and returns NULL, otherwise returns fontPtr.
 *
 *---------------------------------------------------------------------------
 */


















static UnixFtFont *
InitFont(
    Tk_Window tkwin,
    FcPattern *pattern,
    UnixFtFont *fontPtr)
{
    FcFontSet *set;
    FcCharSet *charset;
    FcResult result;
    XftFont *ftFont;
    int i, iWidth;


    if (!fontPtr) {
	fontPtr = ckalloc(sizeof(UnixFtFont));
    }

    FcConfigSubstitute(0, pattern, FcMatchPattern);
    XftDefaultSubstitute(Tk_Display(tkwin), Tk_ScreenNumber(tkwin), pattern);







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











|
>







250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
 *	also allocates a new UnixFtFont.
 *
 * Results:
 * 	On error, frees fontPtr and returns NULL, otherwise returns fontPtr.
 *
 *---------------------------------------------------------------------------
 */

static void
FinishedWithFont(
    UnixFtFont *fontPtr);

static int
InitFontErrorProc(
    ClientData clientData,
    XErrorEvent *errorPtr)
{
    int *errorFlagPtr = (int *) clientData;

    if (errorFlagPtr != NULL) {
	*errorFlagPtr = 1;
    }
    return 0;
}

static UnixFtFont *
InitFont(
    Tk_Window tkwin,
    FcPattern *pattern,
    UnixFtFont *fontPtr)
{
    FcFontSet *set;
    FcCharSet *charset;
    FcResult result;
    XftFont *ftFont;
    int i, iWidth, errorFlag;
    Tk_ErrorHandler handler;

    if (!fontPtr) {
	fontPtr = ckalloc(sizeof(UnixFtFont));
    }

    FcConfigSubstitute(0, pattern, FcMatchPattern);
    XftDefaultSubstitute(Tk_Display(tkwin), Tk_ScreenNumber(tkwin), pattern);
312
313
314
315
316
317
318



319






320
321
322






323
324
325
326
327
328
329
    fontPtr->ncolors = 0;
    fontPtr->firstColor = -1;

    /*
     * Fill in platform-specific fields of TkFont.
     */




    ftFont = GetFont(fontPtr, 0, 0.0);






    fontPtr->font.fid = XLoadFont(Tk_Display(tkwin), "fixed");
    GetTkFontAttributes(ftFont, &fontPtr->font.fa);
    GetTkFontMetrics(ftFont, &fontPtr->font.fm);







    /*
     * Fontconfig can't report any information about the position or thickness
     * of underlines or overstrikes. Thus, we use some defaults that are
     * hacked around from backup defaults in tkUnixFont.c, which are in turn
     * based on recommendations in the X manual. The comments from that file
     * leading to these computations were:







>
>
>

>
>
>
>
>
>



>
>
>
>
>
>







330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
    fontPtr->ncolors = 0;
    fontPtr->firstColor = -1;

    /*
     * Fill in platform-specific fields of TkFont.
     */

    errorFlag = 0;
    handler = Tk_CreateErrorHandler(Tk_Display(tkwin),
		    -1, -1, -1, InitFontErrorProc, (ClientData) &errorFlag);
    ftFont = GetFont(fontPtr, 0, 0.0);
    if ((ftFont == NULL) || errorFlag) {
	Tk_DeleteErrorHandler(handler);
	FinishedWithFont(fontPtr);
	ckfree(fontPtr);
	return NULL;
    }
    fontPtr->font.fid = XLoadFont(Tk_Display(tkwin), "fixed");
    GetTkFontAttributes(ftFont, &fontPtr->font.fa);
    GetTkFontMetrics(ftFont, &fontPtr->font.fm);
    Tk_DeleteErrorHandler(handler);
    if (errorFlag) {
	FinishedWithFont(fontPtr);
	ckfree(fontPtr);
	return NULL;
    }

    /*
     * Fontconfig can't report any information about the position or thickness
     * of underlines or overstrikes. Thus, we use some defaults that are
     * hacked around from backup defaults in tkUnixFont.c, which are in turn
     * based on recommendations in the X manual. The comments from that file
     * leading to these computations were:
340
341
342
343
344
345
346



347






348
349
350
351
352
353
354
     * Fontconfig at all. [Bug 1961455]
     */

    {
	TkFont *fPtr = &fontPtr->font;

	fPtr->underlinePos = fPtr->fm.descent / 2;



	Tk_MeasureChars((Tk_Font) fPtr, "I", 1, -1, 0, &iWidth);






	fPtr->underlineHeight = iWidth / 3;
	if (fPtr->underlineHeight == 0) {
	    fPtr->underlineHeight = 1;
	}
	if (fPtr->underlineHeight + fPtr->underlinePos > fPtr->fm.descent) {
	    fPtr->underlineHeight = fPtr->fm.descent - fPtr->underlinePos;
	    if (fPtr->underlineHeight == 0) {







>
>
>

>
>
>
>
>
>







373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
     * Fontconfig at all. [Bug 1961455]
     */

    {
	TkFont *fPtr = &fontPtr->font;

	fPtr->underlinePos = fPtr->fm.descent / 2;
	handler = Tk_CreateErrorHandler(Tk_Display(tkwin),
			-1, -1, -1, InitFontErrorProc, (ClientData) &errorFlag);
	errorFlag = 0;
	Tk_MeasureChars((Tk_Font) fPtr, "I", 1, -1, 0, &iWidth);
	Tk_DeleteErrorHandler(handler);
	if (errorFlag) {
	    FinishedWithFont(fontPtr);
	    ckfree(fontPtr);
	    return NULL;
	}
	fPtr->underlineHeight = iWidth / 3;
	if (fPtr->underlineHeight == 0) {
	    fPtr->underlineHeight = 1;
	}
	if (fPtr->underlineHeight + fPtr->underlinePos > fPtr->fm.descent) {
	    fPtr->underlineHeight = fPtr->fm.descent - fPtr->underlinePos;
	    if (fPtr->underlineHeight == 0) {
665
666
667
668
669
670
671
672

673
674
675
676
677


678
679
680
681
682
683
684
				 * terminating character. */
{
    UnixFtFont *fontPtr = (UnixFtFont *) tkfont;
    XftFont *ftFont;
    FcChar32 c;
    XGlyphInfo extents;
    int clen, curX, newX, curByte, newByte, sawNonSpace;
    int termByte = 0, termX = 0;

#if DEBUG_FONTSEL
    char string[256];
    int len = 0;
#endif /* DEBUG_FONTSEL */



    curX = 0;
    curByte = 0;
    sawNonSpace = 0;
    while (numBytes > 0) {
	int unichar;

	clen = TkUtfToUniChar(source, &unichar);







|
>





>
>







707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
				 * terminating character. */
{
    UnixFtFont *fontPtr = (UnixFtFont *) tkfont;
    XftFont *ftFont;
    FcChar32 c;
    XGlyphInfo extents;
    int clen, curX, newX, curByte, newByte, sawNonSpace;
    int termByte = 0, termX = 0, errorFlag = 0;
    Tk_ErrorHandler handler;
#if DEBUG_FONTSEL
    char string[256];
    int len = 0;
#endif /* DEBUG_FONTSEL */

    handler = Tk_CreateErrorHandler(fontPtr->display,
	    -1, -1, -1, InitFontErrorProc, &errorFlag);
    curX = 0;
    curByte = 0;
    sawNonSpace = 0;
    while (numBytes > 0) {
	int unichar;

	clen = TkUtfToUniChar(source, &unichar);
706
707
708
709
710
711
712

713




714
715
716
717
718
719
720
	}

#if DEBUG_FONTSEL
	string[len++] = (char) c;
#endif /* DEBUG_FONTSEL */
	ftFont = GetFont(fontPtr, c, 0.0);


	XftTextExtents32(fontPtr->display, ftFont, &c, 1, &extents);





	newX = curX + extents.xOff;
	newByte = curByte + clen;
	if (maxLength >= 0 && newX > maxLength) {
	    if (flags & TK_PARTIAL_OK ||
		    (flags & TK_AT_LEAST_ONE && curByte == 0)) {
		curX = newX;







>
|
>
>
>
>







751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
	}

#if DEBUG_FONTSEL
	string[len++] = (char) c;
#endif /* DEBUG_FONTSEL */
	ftFont = GetFont(fontPtr, c, 0.0);

	if (!errorFlag) {
	    XftTextExtents32(fontPtr->display, ftFont, &c, 1, &extents);
	} else {
	    extents.xOff = 0;
	    errorFlag = 0;
	}

	newX = curX + extents.xOff;
	newByte = curByte + clen;
	if (maxLength >= 0 && newX > maxLength) {
	    if (flags & TK_PARTIAL_OK ||
		    (flags & TK_AT_LEAST_ONE && curByte == 0)) {
		curX = newX;
735
736
737
738
739
740
741

742
743
744
745
746
747
748
	    }
	    break;
	}

	curX = newX;
	curByte = newByte;
    }

#if DEBUG_FONTSEL
    string[len] = '\0';
    printf("MeasureChars %s length %d bytes %d\n", string, curX, curByte);
#endif /* DEBUG_FONTSEL */
    *lengthPtr = curX;
    return curByte;
}







>







785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
	    }
	    break;
	}

	curX = newX;
	curByte = newByte;
    }
    Tk_DeleteErrorHandler(handler);
#if DEBUG_FONTSEL
    string[len] = '\0';
    printf("MeasureChars %s length %d bytes %d\n", string, curX, curByte);
#endif /* DEBUG_FONTSEL */
    *lengthPtr = curX;
    return curByte;
}

Changes to win/rules.vc.

298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
TCLINSTALL	= 1
TCLDIR          = $(_INSTALLDIR)\..
# NOTE: we will be resetting _INSTALLDIR to _INSTALLDIR/lib for extensions
# later so the \.. accounts for the /lib
_TCLDIR		= $(_INSTALLDIR)\..
_TCL_H          = $(_TCLDIR)\include\tcl.h

!else # exist(...) && ! $(NEED_TCL_SOURCE)

!if [echo _TCLDIR = \> nmakehlp.out] \
   || [nmakehlp -L generic\tcl.h >> nmakehlp.out]
!error *** Could not locate Tcl source directory.
!endif
!include nmakehlp.out
TCLINSTALL      = 0
TCLDIR         = $(_TCLDIR)
_TCL_H          = $(_TCLDIR)\generic\tcl.h

!endif # exist(...) && ! $(NEED_TCL_SOURCE)

!endif # TCLDIR

!ifndef _TCL_H
MSG =^
Failed to find tcl.h. The TCLDIR macro is set incorrectly or is not set and default path does not contain tcl.h.
!error $(MSG)







|










|







298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
TCLINSTALL	= 1
TCLDIR          = $(_INSTALLDIR)\..
# NOTE: we will be resetting _INSTALLDIR to _INSTALLDIR/lib for extensions
# later so the \.. accounts for the /lib
_TCLDIR		= $(_INSTALLDIR)\..
_TCL_H          = $(_TCLDIR)\include\tcl.h

!else # exist(...) && !$(NEED_TCL_SOURCE)

!if [echo _TCLDIR = \> nmakehlp.out] \
   || [nmakehlp -L generic\tcl.h >> nmakehlp.out]
!error *** Could not locate Tcl source directory.
!endif
!include nmakehlp.out
TCLINSTALL      = 0
TCLDIR         = $(_TCLDIR)
_TCL_H          = $(_TCLDIR)\generic\tcl.h

!endif # exist(...) && !$(NEED_TCL_SOURCE)

!endif # TCLDIR

!ifndef _TCL_H
MSG =^
Failed to find tcl.h. The TCLDIR macro is set incorrectly or is not set and default path does not contain tcl.h.
!error $(MSG)
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
NMAKEHLPC = nmakehlp.c

!if !$(DOING_TCL)
!if $(TCLINSTALL)
!if exist("$(_TCLDIR)\lib\nmake\nmakehlp.c")
NMAKEHLPC = $(_TCLDIR)\lib\nmake\nmakehlp.c
!endif
!else # ! $(TCLINSTALL)
!if exist("$(_TCLDIR)\win\nmakehlp.c")
NMAKEHLPC = $(_TCLDIR)\win\nmakehlp.c
!endif
!endif # $(TCLINSTALL)
!endif # !$(DOING_TCL)

!endif # NMAKEHLPC







|







533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
NMAKEHLPC = nmakehlp.c

!if !$(DOING_TCL)
!if $(TCLINSTALL)
!if exist("$(_TCLDIR)\lib\nmake\nmakehlp.c")
NMAKEHLPC = $(_TCLDIR)\lib\nmake\nmakehlp.c
!endif
!else # !$(TCLINSTALL)
!if exist("$(_TCLDIR)\win\nmakehlp.c")
NMAKEHLPC = $(_TCLDIR)\win\nmakehlp.c
!endif
!endif # $(TCLINSTALL)
!endif # !$(DOING_TCL)

!endif # NMAKEHLPC
681
682
683
684
685
686
687
688
689

690
691
692
693
694
695
696
#           0 -> Use the non-thread allocator.
# UNCHECKED - 1 -> when doing a debug build with symbols, use the release
#           C runtime, 0 -> use the debug C runtime.
# USE_STUBS - 1 -> compile to use stubs interfaces, 0 -> direct linking
# CONFIG_CHECK - 1 -> check current build configuration against Tcl
#           configuration (ignored for Tcl itself)
# _USE_64BIT_TIME_T - forces a build using 64-bit time_t for 32-bit build
#           (CRT library should support this)
# TCL_UTF_MAX=4 - forces a build allowing 4-byte UTF-8 sequences internally.

# Further, LINKERFLAGS are modified based on above.

# Default values for all the above
STATIC_BUILD	= 0
TCL_THREADS	= 1
DEBUG		= 0
SYMBOLS		= 0







|

>







681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
#           0 -> Use the non-thread allocator.
# UNCHECKED - 1 -> when doing a debug build with symbols, use the release
#           C runtime, 0 -> use the debug C runtime.
# USE_STUBS - 1 -> compile to use stubs interfaces, 0 -> direct linking
# CONFIG_CHECK - 1 -> check current build configuration against Tcl
#           configuration (ignored for Tcl itself)
# _USE_64BIT_TIME_T - forces a build using 64-bit time_t for 32-bit build
#           (CRT library should support this, not needed for Tcl 9.x)
# TCL_UTF_MAX=4 - forces a build allowing 4-byte UTF-8 sequences internally.
#           (Not needed for Tcl 9.x)
# Further, LINKERFLAGS are modified based on above.

# Default values for all the above
STATIC_BUILD	= 0
TCL_THREADS	= 1
DEBUG		= 0
SYMBOLS		= 0
751
752
753
754
755
756
757

758
759
760
761
762
763
764
765

766
767
768
769
770
771
772
TCL_THREADS = 0
USE_THREAD_ALLOC= 0
!else
TCL_THREADS    = 1
USE_THREAD_ALLOC= 1
!endif


!if [nmakehlp -f $(OPTS) "time64bit"]
!message *** Force 64-bit time_t
_USE_64BIT_TIME_T = 1
!endif

!if [nmakehlp -f $(OPTS) "utfmax"]
!message *** Force allowing 4-byte UTF-8 sequences internally
TCL_UTF_MAX = 4

!endif

# Yes, it's weird that the "symbols" option controls DEBUG and
# the "pdbs" option controls SYMBOLS. That's historical.
!if [nmakehlp -f $(OPTS) "symbols"]
!message *** Doing symbols
DEBUG		= 1







>








>







752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
TCL_THREADS = 0
USE_THREAD_ALLOC= 0
!else
TCL_THREADS    = 1
USE_THREAD_ALLOC= 1
!endif

!if "$(TCL_MAJOR_VERSION)" == "8"
!if [nmakehlp -f $(OPTS) "time64bit"]
!message *** Force 64-bit time_t
_USE_64BIT_TIME_T = 1
!endif

!if [nmakehlp -f $(OPTS) "utfmax"]
!message *** Force allowing 4-byte UTF-8 sequences internally
TCL_UTF_MAX = 4
!endif
!endif

# Yes, it's weird that the "symbols" option controls DEBUG and
# the "pdbs" option controls SYMBOLS. That's historical.
!if [nmakehlp -f $(OPTS) "symbols"]
!message *** Doing symbols
DEBUG		= 1
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
TCLLIBNAME	= $(PROJECT)$(VERSION)$(SUFX).$(EXT)
TCLLIB		= $(OUT_DIR)\$(TCLLIBNAME)

TCLSTUBLIBNAME	= $(STUBPREFIX)$(VERSION).lib
TCLSTUBLIB	= $(OUT_DIR)\$(TCLSTUBLIBNAME)
TCL_INCLUDES    = -I"$(WIN_DIR)" -I"$(GENERICDIR)"

!else # ! $(DOING_TCL)

!if $(TCLINSTALL) # Building against an installed Tcl

# When building extensions, we need to locate tclsh. Depending on version
# of Tcl we are building against, this may or may not have a "t" suffix.
# Try various possibilities in turn.
TCLSH		= $(_TCLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX:t=).exe







|







1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
TCLLIBNAME	= $(PROJECT)$(VERSION)$(SUFX).$(EXT)
TCLLIB		= $(OUT_DIR)\$(TCLLIBNAME)

TCLSTUBLIBNAME	= $(STUBPREFIX)$(VERSION).lib
TCLSTUBLIB	= $(OUT_DIR)\$(TCLSTUBLIBNAME)
TCL_INCLUDES    = -I"$(WIN_DIR)" -I"$(GENERICDIR)"

!else # !$(DOING_TCL)

!if $(TCLINSTALL) # Building against an installed Tcl

# When building extensions, we need to locate tclsh. Depending on version
# of Tcl we are building against, this may or may not have a "t" suffix.
# Try various possibilities in turn.
TCLSH		= $(_TCLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX:t=).exe
1248
1249
1250
1251
1252
1253
1254

1255
1256
1257
1258
1259
1260
1261

!if $(DOING_TCL) || $(DOING_TK)
LIB_INSTALL_DIR		= $(_INSTALLDIR)\lib
BIN_INSTALL_DIR		= $(_INSTALLDIR)\bin
DOC_INSTALL_DIR		= $(_INSTALLDIR)\doc
!if $(DOING_TCL)
SCRIPT_INSTALL_DIR	= $(_INSTALLDIR)\lib\$(PROJECT)$(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION)

!else # DOING_TK
SCRIPT_INSTALL_DIR	= $(_INSTALLDIR)\lib\$(PROJECT)$(TK_MAJOR_VERSION).$(TK_MINOR_VERSION)
!endif
DEMO_INSTALL_DIR	= $(SCRIPT_INSTALL_DIR)\demos
INCLUDE_INSTALL_DIR	= $(_INSTALLDIR)\include

!else # extension other than Tk







>







1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265

!if $(DOING_TCL) || $(DOING_TK)
LIB_INSTALL_DIR		= $(_INSTALLDIR)\lib
BIN_INSTALL_DIR		= $(_INSTALLDIR)\bin
DOC_INSTALL_DIR		= $(_INSTALLDIR)\doc
!if $(DOING_TCL)
SCRIPT_INSTALL_DIR	= $(_INSTALLDIR)\lib\$(PROJECT)$(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION)
MODULE_INSTALL_DIR	= $(_INSTALLDIR)\lib\tcl$(TCL_MAJOR_VERSION)
!else # DOING_TK
SCRIPT_INSTALL_DIR	= $(_INSTALLDIR)\lib\$(PROJECT)$(TK_MAJOR_VERSION).$(TK_MINOR_VERSION)
!endif
DEMO_INSTALL_DIR	= $(SCRIPT_INSTALL_DIR)\demos
INCLUDE_INSTALL_DIR	= $(_INSTALLDIR)\include

!else # extension other than Tk
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
!if $(TCL_NO_DEPRECATED)
OPTDEFINES	= $(OPTDEFINES) /DTCL_NO_DEPRECATED
!endif

!if $(USE_STUBS)
# Note we do not define USE_TCL_STUBS even when building tk since some
# test targets in tk do not use stubs
!if ! $(DOING_TCL)
USE_STUBS_DEFS  = /DUSE_TCL_STUBS /DUSE_TCLOO_STUBS
!if $(NEED_TK)
USE_STUBS_DEFS  = $(USE_STUBS_DEFS) /DUSE_TK_STUBS
!endif
!endif
!endif # USE_STUBS








|







1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
!if $(TCL_NO_DEPRECATED)
OPTDEFINES	= $(OPTDEFINES) /DTCL_NO_DEPRECATED
!endif

!if $(USE_STUBS)
# Note we do not define USE_TCL_STUBS even when building tk since some
# test targets in tk do not use stubs
!if !$(DOING_TCL)
USE_STUBS_DEFS  = /DUSE_TCL_STUBS /DUSE_TCLOO_STUBS
!if $(NEED_TK)
USE_STUBS_DEFS  = $(USE_STUBS_DEFS) /DUSE_TK_STUBS
!endif
!endif
!endif # USE_STUBS

1353
1354
1355
1356
1357
1358
1359

1360
1361
1362
1363
1364
1365
1366
1367
1368

1369
1370
1371
1372
1373
1374
1375
!if "$(MACHINE)" == "AMD64"
OPTDEFINES	= $(OPTDEFINES) /DTCL_CFG_DO64BIT
!endif
!if $(VCVERSION) < 1300
OPTDEFINES	= $(OPTDEFINES) /DNO_STRTOI64=1
!endif


!if "$(_USE_64BIT_TIME_T)" == "1"
OPTDEFINES	= $(OPTDEFINES) /D_USE_64BIT_TIME_T=1
!endif
!if "$(TCL_UTF_MAX)" == "4"
OPTDEFINES	= $(OPTDEFINES) /DTCL_UTF_MAX=4
!endif

# _ATL_XP_TARGETING - Newer SDK's need this to build for XP
COMPILERFLAGS  = /D_ATL_XP_TARGETING


# Like the TEA system only set this non empty for non-Tk extensions
# Note: some extensions use PACKAGE_NAME and others use PACKAGE_TCLNAME
# so we pass both
!if !$(DOING_TCL) && !$(DOING_TK)
PKGNAMEFLAGS = /DPACKAGE_NAME="\"$(PRJ_PACKAGE_TCLNAME)\"" \
               /DPACKAGE_TCLNAME="\"$(PRJ_PACKAGE_TCLNAME)\"" \







>









>







1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
!if "$(MACHINE)" == "AMD64"
OPTDEFINES	= $(OPTDEFINES) /DTCL_CFG_DO64BIT
!endif
!if $(VCVERSION) < 1300
OPTDEFINES	= $(OPTDEFINES) /DNO_STRTOI64=1
!endif

!if "$(TCL_MAJOR_VERSION)" == "8"
!if "$(_USE_64BIT_TIME_T)" == "1"
OPTDEFINES	= $(OPTDEFINES) /D_USE_64BIT_TIME_T=1
!endif
!if "$(TCL_UTF_MAX)" == "4"
OPTDEFINES	= $(OPTDEFINES) /DTCL_UTF_MAX=4
!endif

# _ATL_XP_TARGETING - Newer SDK's need this to build for XP
COMPILERFLAGS  = /D_ATL_XP_TARGETING
!endif

# Like the TEA system only set this non empty for non-Tk extensions
# Note: some extensions use PACKAGE_NAME and others use PACKAGE_TCLNAME
# so we pass both
!if !$(DOING_TCL) && !$(DOING_TK)
PKGNAMEFLAGS = /DPACKAGE_NAME="\"$(PRJ_PACKAGE_TCLNAME)\"" \
               /DPACKAGE_TCLNAME="\"$(PRJ_PACKAGE_TCLNAME)\"" \
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
!endif

################################################################
# 14. Sanity check selected options against Tcl build options
# When building an extension, certain configuration options should
# match the ones used when Tcl was built. Here we check and
# warn on a mismatch.
!if ! $(DOING_TCL)

!if $(TCLINSTALL) # Building against an installed Tcl
!if exist("$(_TCLDIR)\lib\nmake\tcl.nmake")
TCLNMAKECONFIG = "$(_TCLDIR)\lib\nmake\tcl.nmake"
!endif
!else # ! $(TCLINSTALL) - building against Tcl source
!if exist("$(OUT_DIR)\tcl.nmake")
TCLNMAKECONFIG = "$(OUT_DIR)\tcl.nmake"
!endif
!endif # TCLINSTALL

!if $(CONFIG_CHECK)
!ifdef TCLNMAKECONFIG







|





|







1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
!endif

################################################################
# 14. Sanity check selected options against Tcl build options
# When building an extension, certain configuration options should
# match the ones used when Tcl was built. Here we check and
# warn on a mismatch.
!if !$(DOING_TCL)

!if $(TCLINSTALL) # Building against an installed Tcl
!if exist("$(_TCLDIR)\lib\nmake\tcl.nmake")
TCLNMAKECONFIG = "$(_TCLDIR)\lib\nmake\tcl.nmake"
!endif
!else # !$(TCLINSTALL) - building against Tcl source
!if exist("$(OUT_DIR)\tcl.nmake")
TCLNMAKECONFIG = "$(OUT_DIR)\tcl.nmake"
!endif
!endif # TCLINSTALL

!if $(CONFIG_CHECK)
!ifdef TCLNMAKECONFIG
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
!if defined(CORE_DEBUG) && $(CORE_DEBUG) != $(DEBUG)
!message WARNING: Value of DEBUG ($(DEBUG)) does not match its Tcl library configuration ($(DEBUG)).
!endif
!endif

!endif # TCLNMAKECONFIG

!endif # ! $(DOING_TCL)


#----------------------------------------------------------
# Display stats being used.
#----------------------------------------------------------

!if !$(DOING_TCL)







|







1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
!if defined(CORE_DEBUG) && $(CORE_DEBUG) != $(DEBUG)
!message WARNING: Value of DEBUG ($(DEBUG)) does not match its Tcl library configuration ($(DEBUG)).
!endif
!endif

!endif # TCLNMAKECONFIG

!endif # !$(DOING_TCL)


#----------------------------------------------------------
# Display stats being used.
#----------------------------------------------------------

!if !$(DOING_TCL)

Changes to win/tkWinFont.c.

211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
			    LOGFONTW* logFontPtr);
static int		CreateNamedSystemFont(Tcl_Interp *interp,
			    Tk_Window tkwin, const char* name, HFONT hFont);
static int		LoadFontRanges(HDC hdc, HFONT hFont,
			    USHORT **startCount, USHORT **endCount,
			    int *symbolPtr);
static void		MultiFontTextOut(HDC hdc, WinFont *fontPtr,
			    const char *source, int numBytes, int x, int y,
			    double angle);
static void		ReleaseFont(WinFont *fontPtr);
static inline void	ReleaseSubFont(SubFont *subFontPtr);
static int		SeenName(const char *name, Tcl_DString *dsPtr);
static inline HFONT	SelectFont(HDC hdc, WinFont *fontPtr,
			    SubFont *subFontPtr, double angle);
static inline void	SwapLong(PULONG p);
static inline void	SwapShort(USHORT *p);







|
|







211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
			    LOGFONTW* logFontPtr);
static int		CreateNamedSystemFont(Tcl_Interp *interp,
			    Tk_Window tkwin, const char* name, HFONT hFont);
static int		LoadFontRanges(HDC hdc, HFONT hFont,
			    USHORT **startCount, USHORT **endCount,
			    int *symbolPtr);
static void		MultiFontTextOut(HDC hdc, WinFont *fontPtr,
			    const char *source, int numBytes,
			    double x, double y, double angle);
static void		ReleaseFont(WinFont *fontPtr);
static inline void	ReleaseSubFont(SubFont *subFontPtr);
static int		SeenName(const char *name, Tcl_DString *dsPtr);
static inline HFONT	SelectFont(HDC hdc, WinFont *fontPtr,
			    SubFont *subFontPtr, double angle);
static inline void	SwapLong(PULONG p);
static inline void	SwapShort(USHORT *p);
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
	 * colors. First we draw onto a black background and copy the white
	 * bits. Then we draw onto a white background and copy the black bits.
	 * Both the foreground and background bits of the font are ANDed with
	 * the stipple pattern as they are copied.
	 */

	PatBlt(dcMem, 0, 0, size.cx, size.cy, BLACKNESS);
	MultiFontTextOut(dc, fontPtr, source, numBytes, (int)x, (int)y, angle);
	BitBlt(dc, (int)x, (int)y - tm.tmAscent, size.cx, size.cy, dcMem,
		0, 0, 0xEA02E9);
	PatBlt(dcMem, 0, 0, size.cx, size.cy, WHITENESS);
	MultiFontTextOut(dc, fontPtr, source, numBytes, (int)x, (int)y, angle);
	BitBlt(dc, (int)x, (int)y - tm.tmAscent, size.cx, size.cy, dcMem,
		0, 0, 0x8A0E06);

	/*
	 * Destroy the temporary bitmap and restore the device context.
	 */

	SelectObject(dcMem, oldBitmap);
	DeleteObject(bitmap);
	DeleteDC(dcMem);
	SelectObject(dc, oldBrush);
	DeleteObject(stipple);
    } else if (gc->function == GXcopy) {
	SetTextAlign(dc, TA_LEFT | TA_BASELINE);
	SetTextColor(dc, gc->foreground);
	SetBkMode(dc, TRANSPARENT);
	MultiFontTextOut(dc, fontPtr, source, numBytes, (int)x, (int)y, angle);
    } else {
	HBITMAP oldBitmap, bitmap;
	HDC dcMem;
	TEXTMETRICW tm;
	SIZE size;

	dcMem = CreateCompatibleDC(dc);







|



|
















|







1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
	 * colors. First we draw onto a black background and copy the white
	 * bits. Then we draw onto a white background and copy the black bits.
	 * Both the foreground and background bits of the font are ANDed with
	 * the stipple pattern as they are copied.
	 */

	PatBlt(dcMem, 0, 0, size.cx, size.cy, BLACKNESS);
	MultiFontTextOut(dc, fontPtr, source, numBytes, x, y, angle);
	BitBlt(dc, (int)x, (int)y - tm.tmAscent, size.cx, size.cy, dcMem,
		0, 0, 0xEA02E9);
	PatBlt(dcMem, 0, 0, size.cx, size.cy, WHITENESS);
	MultiFontTextOut(dc, fontPtr, source, numBytes, x, y, angle);
	BitBlt(dc, (int)x, (int)y - tm.tmAscent, size.cx, size.cy, dcMem,
		0, 0, 0x8A0E06);

	/*
	 * Destroy the temporary bitmap and restore the device context.
	 */

	SelectObject(dcMem, oldBitmap);
	DeleteObject(bitmap);
	DeleteDC(dcMem);
	SelectObject(dc, oldBrush);
	DeleteObject(stipple);
    } else if (gc->function == GXcopy) {
	SetTextAlign(dc, TA_LEFT | TA_BASELINE);
	SetTextColor(dc, gc->foreground);
	SetBkMode(dc, TRANSPARENT);
	MultiFontTextOut(dc, fontPtr, source, numBytes, x, y, angle);
    } else {
	HBITMAP oldBitmap, bitmap;
	HDC dcMem;
	TEXTMETRICW tm;
	SIZE size;

	dcMem = CreateCompatibleDC(dc);
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443

1444
1445
1446
1447
1448
1449
1450
static void
MultiFontTextOut(
    HDC hdc,			/* HDC to draw into. */
    WinFont *fontPtr,		/* Contains set of fonts to use when drawing
				 * following string. */
    const char *source,		/* Potentially multilingual UTF-8 string. */
    int numBytes,		/* Length of string in bytes. */
    int x, int y,		/* Coordinates at which to place origin of
				 * string when drawing. */
    double angle)
{
    int ch;
    SIZE size;
    HFONT oldFont;
    FontFamily *familyPtr;
    Tcl_DString runString;
    const char *p, *end, *next;
    SubFont *lastSubFontPtr, *thisSubFontPtr;
    TEXTMETRICW tm;


    lastSubFontPtr = &fontPtr->subFontArray[0];
    oldFont = SelectFont(hdc, fontPtr, lastSubFontPtr, angle);
    GetTextMetricsW(hdc, &tm);

    end = source + numBytes;
    for (p = source; p < end; ) {







|











>







1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
static void
MultiFontTextOut(
    HDC hdc,			/* HDC to draw into. */
    WinFont *fontPtr,		/* Contains set of fonts to use when drawing
				 * following string. */
    const char *source,		/* Potentially multilingual UTF-8 string. */
    int numBytes,		/* Length of string in bytes. */
    double x, double y,		/* Coordinates at which to place origin of
				 * string when drawing. */
    double angle)
{
    int ch;
    SIZE size;
    HFONT oldFont;
    FontFamily *familyPtr;
    Tcl_DString runString;
    const char *p, *end, *next;
    SubFont *lastSubFontPtr, *thisSubFontPtr;
    TEXTMETRICW tm;
    double sinA = sin(angle * PI/180.0), cosA = cos(angle * PI/180.0);

    lastSubFontPtr = &fontPtr->subFontArray[0];
    oldFont = SelectFont(hdc, fontPtr, lastSubFontPtr, angle);
    GetTextMetricsW(hdc, &tm);

    end = source + numBytes;
    for (p = source; p < end; ) {
1466
1467
1468
1469
1470
1471
1472
1473

1474
1475
1476
1477
1478
1479
1480
		familyPtr->textOutProc(hdc, x-(tm.tmOverhang/2), y,
			(WCHAR *)Tcl_DStringValue(&runString),
			Tcl_DStringLength(&runString)>>familyPtr->isWideFont);
		familyPtr->getTextExtentPoint32Proc(hdc,
			(WCHAR *)Tcl_DStringValue(&runString),
			Tcl_DStringLength(&runString) >> familyPtr->isWideFont,
			&size);
		x += size.cx;

		Tcl_DStringFree(&runString);
	    }
	    lastSubFontPtr = thisSubFontPtr;
	    source = p;
	    SelectFont(hdc, fontPtr, lastSubFontPtr, angle);
	    GetTextMetricsW(hdc, &tm);
	}







|
>







1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
		familyPtr->textOutProc(hdc, x-(tm.tmOverhang/2), y,
			(WCHAR *)Tcl_DStringValue(&runString),
			Tcl_DStringLength(&runString)>>familyPtr->isWideFont);
		familyPtr->getTextExtentPoint32Proc(hdc,
			(WCHAR *)Tcl_DStringValue(&runString),
			Tcl_DStringLength(&runString) >> familyPtr->isWideFont,
			&size);
		x += cosA*size.cx;
		y -= sinA*size.cx;
		Tcl_DStringFree(&runString);
	    }
	    lastSubFontPtr = thisSubFontPtr;
	    source = p;
	    SelectFont(hdc, fontPtr, lastSubFontPtr, angle);
	    GetTextMetricsW(hdc, &tm);
	}

Changes to win/tkWinMenu.c.

507
508
509
510
511
512
513

514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
	int i;
	const char *label = (mePtr->labelPtr == NULL) ? ""
		: Tcl_GetString(mePtr->labelPtr);
	const char *accel = ((menuPtr->menuType == MENUBAR) || (mePtr->accelPtr == NULL)) ? ""
		: Tcl_GetString(mePtr->accelPtr);
	const char *p, *next;
	Tcl_DString itemString;


	/*
	 * We have to construct the string with an ampersand preceeding the
	 * underline character, and a tab seperating the text and the accel
	 * text. We have to be careful with ampersands in the string.
	 */

	Tcl_DStringInit(&itemString);

	for (p = label, i = 0; *p != '\0'; i++, p = next) {
	    if (i == mePtr->underline) {
		Tcl_DStringAppend(&itemString, "&", 1);
	    }
	    if (*p == '&') {
		Tcl_DStringAppend(&itemString, "&", 1);
	    }
	    next = Tcl_UtfNext(p);
	    Tcl_DStringAppend(&itemString, p, (int) (next - p));
	}
	if (mePtr->accelLength > 0) {
	    Tcl_DStringAppend(&itemString, "\t", 1);
	    for (p = accel, i = 0; *p != '\0'; i++, p = next) {
		if (*p == '&') {
		    Tcl_DStringAppend(&itemString, "&", 1);
		}
		next = Tcl_UtfNext(p);
		Tcl_DStringAppend(&itemString, p, (int) (next - p));
	    }
	}

	itemText = (char *)ckalloc(Tcl_DStringLength(&itemString) + 1);
	strcpy(itemText, Tcl_DStringValue(&itemString));
	Tcl_DStringFree(&itemString);







>
















|








|







507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
	int i;
	const char *label = (mePtr->labelPtr == NULL) ? ""
		: Tcl_GetString(mePtr->labelPtr);
	const char *accel = ((menuPtr->menuType == MENUBAR) || (mePtr->accelPtr == NULL)) ? ""
		: Tcl_GetString(mePtr->accelPtr);
	const char *p, *next;
	Tcl_DString itemString;
	int ch;

	/*
	 * We have to construct the string with an ampersand preceeding the
	 * underline character, and a tab seperating the text and the accel
	 * text. We have to be careful with ampersands in the string.
	 */

	Tcl_DStringInit(&itemString);

	for (p = label, i = 0; *p != '\0'; i++, p = next) {
	    if (i == mePtr->underline) {
		Tcl_DStringAppend(&itemString, "&", 1);
	    }
	    if (*p == '&') {
		Tcl_DStringAppend(&itemString, "&", 1);
	    }
	    next = p + TkUtfToUniChar(p, &ch);
	    Tcl_DStringAppend(&itemString, p, (int) (next - p));
	}
	if (mePtr->accelLength > 0) {
	    Tcl_DStringAppend(&itemString, "\t", 1);
	    for (p = accel, i = 0; *p != '\0'; i++, p = next) {
		if (*p == '&') {
		    Tcl_DStringAppend(&itemString, "&", 1);
		}
		next = p + TkUtfToUniChar(p, &ch);
		Tcl_DStringAppend(&itemString, p, (int) (next - p));
	    }
	}

	itemText = (char *)ckalloc(Tcl_DStringLength(&itemString) + 1);
	strcpy(itemText, Tcl_DStringValue(&itemString));
	Tcl_DStringFree(&itemString);
2130
2131
2132
2133
2134
2135
2136

2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147

    if ((mePtr->underline >= 0) && (mePtr->labelPtr != NULL)) {
	int len;

	len = Tcl_GetCharLength(mePtr->labelPtr);
	if (mePtr->underline < len) {
	    const char *label, *start, *end;


	    label = Tcl_GetString(mePtr->labelPtr);
	    start = Tcl_UtfAtIndex(label, mePtr->underline);
	    end = Tcl_UtfNext(start);
	    Tk_UnderlineChars(menuPtr->display, d,
		    gc, tkfont, label, x + mePtr->indicatorSpace,
		    y + (height + fmPtr->ascent - fmPtr->descent) / 2,
		    (int) (start - label), (int) (end - label));
	}
    }
}







>



|







2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149

    if ((mePtr->underline >= 0) && (mePtr->labelPtr != NULL)) {
	int len;

	len = Tcl_GetCharLength(mePtr->labelPtr);
	if (mePtr->underline < len) {
	    const char *label, *start, *end;
	    int ch;

	    label = Tcl_GetString(mePtr->labelPtr);
	    start = Tcl_UtfAtIndex(label, mePtr->underline);
	    end = start + TkUtfToUniChar(start, &ch);
	    Tk_UnderlineChars(menuPtr->display, d,
		    gc, tkfont, label, x + mePtr->indicatorSpace,
		    y + (height + fmPtr->ascent - fmPtr->descent) / 2,
		    (int) (start - label), (int) (end - label));
	}
    }
}