Tk Source Code

Check-in [9844fe10]
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to [email protected]
or submit via the online form by Sep 9.

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

Overview
Comment:Fix for serious bugs with input methods, and for display of certain fonts in buttons; thanks to Adrian Robert for extensive patches.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | tk-cocoa-8-5-backport
Files: files | file ages | folders
SHA1: 9844fe10b98cc7d7659baf3eed3d94e6bbba5667
User & Date: kevin_walzer 2012-01-29 18:02:38
Context
2012-02-10
00:00
Fix for minor typos provided by Andreas Kupries check-in: 48e380fe user: kevin_walzer tags: tk-cocoa-8-5-backport
2012-01-29
18:02
Fix for serious bugs with input methods, and for display of certain fonts in buttons; thanks to Adrian Robert for extensive patches. check-in: 9844fe10 user: kevin_walzer tags: tk-cocoa-8-5-backport
2011-11-04
00:17
Update missing symbols for tk-Cocoa check-in: 566953e5 user: kevin_walzer tags: tk-cocoa-8-5-backport
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to macosx/tkMacOSXButton.c.

581
582
583
584
585
586
587







588
589
590
591
592
593
594
		    break;
		case COMPOUND_NONE:
		    pos = NSImageOnly;
		    break;
	    }
	}
	[button setImagePosition:pos];







    }

    bounds.size = [cell cellSize];
    if (haveText) {
	titleRect = [cell titleRectForBounds:bounds];
	if (butPtr->wrapLength > 0 &&
		titleRect.size.width > butPtr->wrapLength) {






>
>
>
>
>
>
>







581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
		    break;
		case COMPOUND_NONE:
		    pos = NSImageOnly;
		    break;
	    }
	}
	[button setImagePosition:pos];
    // if font is too tall, we can't use the fixed-height rounded bezel
   if (!haveImage && haveText && style == NSRoundedBezelStyle) {
     Tk_FontMetrics fm;
     Tk_GetFontMetrics(butPtr->tkfont, &fm);
     if (fm.linespace > 18) {
       [button setBezelStyle:(style = NSRegularSquareBezelStyle)];
     }
    }

    bounds.size = [cell cellSize];
    if (haveText) {
	titleRect = [cell titleRectForBounds:bounds];
	if (butPtr->wrapLength > 0 &&
		titleRect.size.width > butPtr->wrapLength) {

Changes to macosx/tkMacOSXKeyEvent.c.

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
...
339
340
341
342
343
344
345
346

347




348










349






























































































350
351
352
353
354
355
356
 * 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]>

 *
 * 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"

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



static Tk_Window grabWinPtr = NULL;
				/* Current grab window, NULL if no grab. */
static Tk_Window keyboardGrabWinPtr = NULL;
				/* Current keyboard grab window. */
static NSModalSession modalSession = NULL;










#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, len;
    BOOL	    repeat = NO;
    unsigned short  keyCode;
    NSString	    *characters = nil, *charactersIgnoringModifiers = nil;
    static NSUInteger savedModifiers = 0;








    switch (type) {
    case NSKeyUp:






    case NSKeyDown:
	repeat = [theEvent isARepeat];
	characters = [theEvent characters];
	charactersIgnoringModifiers = [theEvent charactersIgnoringModifiers];

    case NSFlagsChanged:
	modifiers = [theEvent modifierFlags];
	keyCode = [theEvent keyCode];
	w = [self windowWithWindowNumber:[theEvent windowNumber]];
#ifdef TK_MAC_DEBUG_EVENTS
	TKLog(@"-[%@(%p) %s] %d %u %@ %@ %u %@", [self class], self, _cmd, repeat, modifiers, characters, charactersIgnoringModifiers, keyCode, w);
#endif
	break;

    default:
	return theEvent;
    }


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

    /*
     * The focus must be in the FrontWindow on the Macintosh. We then query Tk
     * to determine the exact Tk window that owns the focus.
     */

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

    if (!tkwin) {
	TkMacOSXDbgMsg("tkwin == NULL");
	return theEvent;
    }
    tkwin = (Tk_Window) winPtr->dispPtr->focusPtr;
    if (!tkwin) {
	TkMacOSXDbgMsg("tkwin == NULL");
	return theEvent;
    }

    XEvent xEvent;


    memset(&xEvent, 0, sizeof(XEvent));
    xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
    xEvent.xany.send_event = false;

    xEvent.xany.display = Tk_Display(tkwin);
    xEvent.xany.window = Tk_WindowId(tkwin);



    xEvent.xkey.root = XRootWindow(Tk_Display(tkwin), 0);
    xEvent.xkey.subwindow = None;
    xEvent.xkey.time = TkpGetMS();
    xEvent.xkey.state = state;
    xEvent.xkey.same_screen = true;
    xEvent.xkey.trans_chars[0] = 0;
    xEvent.xkey.nbytes = 0;

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




/* prevent SF bug 2907388 here (crash on composite characters) */





if ([characters length] > 0) {
	xEvent.xkey.keycode = (keyCode << 16) | (UInt16)
		[characters characterAtIndex:0];
	if (![characters getCString:xEvent.xkey.trans_chars
		maxLength:XMaxTransChars encoding:NSUTF8StringEncoding]) {


	    TkMacOSXDbgMsg("characters too long");
	    return theEvent;
	}
}
/* end workaround */

	len = [charactersIgnoringModifiers length];
	if (len) {
	    xEvent.xkey.nbytes = [charactersIgnoringModifiers characterAtIndex:0];
	    if (len > 1) {
		TkMacOSXDbgMsg("more than one charactersIgnoringModifiers");
	    }
	}
	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;
}
@end

























































































































































































































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

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

}




 










/*






























































































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






>













>
>






>
>
>
>
>
>
>
>
>




>







|




>
>
>
>
>
>
>



>
>
>
>
>
>




>




|
|







>
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|

|
|

|
|
|
|
|
|
|
|
|

<
<
>
|
|
<
>
|
|
>
>

<
<
|
|
<
<
<

|
|
|
|
|
|

|
|
|
|
|

|

|
|
|

|
|
|
|
|
|
|

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

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

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



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







 







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







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
...
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
 * 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.
 *
 * 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"

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


static Tk_Window grabWinPtr = NULL;
				/* Current grab window, NULL if no grab. */
static Tk_Window keyboardGrabWinPtr = NULL;
				/* Current keyboard grab window. */
static NSModalSession modalSession = NULL;

static BOOL processingCompose = NO;
static BOOL finishedCompose = NO;

static int caret_x = 0, caret_y = 0, caret_height = 0;

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, len = 0;
    BOOL	    repeat = NO;
    unsigned short  keyCode;
    NSString	    *characters = nil, *charactersIgnoringModifiers = nil;
    static NSUInteger savedModifiers = 0;
    static NSMutableArray *nsEvArray;

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

    switch (type) {
    case NSKeyUp:
      if (finishedCompose)
        {
          // if we were composing, swallow the last release since we already sent
          finishedCompose = NO;
          return theEvent;
        }
    case NSKeyDown:
	repeat = [theEvent isARepeat];
	characters = [theEvent characters];
	charactersIgnoringModifiers = [theEvent charactersIgnoringModifiers];
        len = [charactersIgnoringModifiers length];
    case NSFlagsChanged:
	modifiers = [theEvent modifierFlags];
	keyCode = [theEvent keyCode];
	w = [self windowWithWindowNumber:[theEvent windowNumber]];
#if defined(TK_MAC_DEBUG_EVENTS) || NS_KEYLOG == 1
	NSLog(@"-[%@(%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;
    }

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

        /*
         * The focus must be in the FrontWindow on the Macintosh. We then query Tk
         * to determine the exact Tk window that owns the focus.
         */

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

        if (!tkwin) {
          TkMacOSXDbgMsg("tkwin == NULL");
          return theEvent;
        }
        tkwin = (Tk_Window) winPtr->dispPtr->focusPtr;
        if (!tkwin) {
          TkMacOSXDbgMsg("tkwin == NULL");
          return theEvent;
        }



        /*
         * 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;
              }

              /* For command key, take input manager's word so things
                 like dvorak / qwerty layout work. */
              if ((modifiers & NSCommandKeyMask) == NSCommandKeyMask
                  && (modifiers & NSAlternateKeyMask) != NSAlternateKeyMask
                  && len > 0 && !isFunctionKey(code)) {
                // head off keycode-based translation in tkMacOSXKeyboard.c
                xEvent.xkey.nbytes = [characters length]; //len
              }

              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 send straight to TK */

      }  /* if not processing compose */

    if (type == NSKeyDown) {
        if (NS_KEYLOG)
          fprintf (stderr, "keyDown: %s compose sequence.\n",
                   processingCompose == YES ? "Continue" : "Begin");
        processingCompose = YES;
        [nsEvArray addObject: theEvent];
        [[w contentView] interpretKeyEvents: nsEvArray];
        [nsEvArray removeObject: theEvent];
      }

    savedModifiers = modifiers;

    return theEvent;
}
@end

 

@implementation TKContentView(TKKeyEvent)
/* <NSTextInput> implementation (called through interpretKeyEvents:]). */

/* <NSTextInput>: called when done composing;
   NOTE: also called when we delete over working text, followed immed.
         by doCommandBySelector: deleteBackward: */
- (void)insertText: (id)aString
{
  int i, len = [(NSString *)aString length];
  XEvent xEvent;
  TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);
  Tk_Window tkwin = (Tk_Window) winPtr;

  if (NS_KEYLOG)
    NSLog (@"insertText '%@'\tlen = %d", aString, len);
  processingCompose = NO;
  finishedCompose = YES;

  /* first, clear any working text */
  if (_workingText != nil)
    [self deleteWorkingText];

  /* now insert the string as keystrokes */
  setupXEvent(&xEvent, [self window], 0);
  xEvent.xany.type = KeyPress;

  for (i =0; i<len; i++)
    {
      xEvent.xkey.keycode = (UInt16) [aString characterAtIndex: i];
      [[aString substringWithRange: NSMakeRange(i,1)]
        getCString: xEvent.xkey.trans_chars
         maxLength: XMaxTransChars encoding: NSUTF8StringEncoding];
      xEvent.xkey.nbytes = strlen(xEvent.xkey.trans_chars);
      xEvent.xany.type = KeyPress;
      Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);

      xEvent.xany.type = KeyRelease;
      xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
      Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
      xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
    }
}


/* <NSTextInput>: inserts display of composing characters */
- (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
{
  NSString *str = [aString respondsToSelector: @selector (string)] ?
    [aString string] : aString;
  if (NS_KEYLOG)
    NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
           selRange.length, selRange.location);

  if (_workingText != nil)
    [self deleteWorkingText];
  if ([str length] == 0)
    return;

  processingCompose = YES;
  _workingText = [str copy];

  //PENDING: insert workingText underlined
}


/* delete display of composing characters [not in <NSTextInput>] */
- (void)deleteWorkingText
{
  if (_workingText == nil)
    return;
  if (NS_KEYLOG)
    NSLog(@"deleteWorkingText len = %d\n", [_workingText length]);
  [_workingText release];
  _workingText = nil;
  processingCompose = NO;

  //PENDING: delete working text
}


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


- (NSRange)markedRange
{
  NSRange rng = _workingText != nil
    ? NSMakeRange (0, [_workingText length]) : NSMakeRange (NSNotFound, 0);
  if (NS_KEYLOG)
    NSLog (@"markedRange request");
  return rng;
}


- (void)unmarkText
{
  if (NS_KEYLOG)
    NSLog (@"unmark (accept) text");
  [self deleteWorkingText];
  processingCompose = NO;
}


/* used to position char selection windows, etc. */
- (NSRect)firstRectForCharacterRange: (NSRange)theRange
{
  NSRect rect;
  NSPoint pt;

  pt.x = caret_x;
  pt.y = caret_y;

  pt = [self convertPoint: pt toView: nil];
  pt = [[self window] convertBaseToScreen: pt];
  pt.y -= caret_height;

  rect.origin = pt;
  rect.size.width = caret_height;
  rect.size.height = caret_height;
  return rect;
}


- (NSInteger)conversationIdentifier
{
  return (NSInteger)self;
}


- (void)doCommandBySelector: (SEL)aSelector
{
  if (NS_KEYLOG)
    NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
  processingCompose = NO;
  if (aSelector == @selector (deleteBackward:))
    {
      /* happens when user backspaces over an ongoing composition:
         throw a 'delete' into the event queue */
      XEvent xEvent;
      setupXEvent(&xEvent, [self window], 0);
      xEvent.xany.type = KeyPress;
      xEvent.xkey.nbytes = 1;
      xEvent.xkey.keycode = (0x33 << 16) | 0x7F;
      xEvent.xkey.trans_chars[0] = 0x7F;
      xEvent.xkey.trans_chars[1] = 0x0;
      Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
    }
}


- (NSArray *)validAttributesForMarkedText
{
  static NSArray *arr = nil;
  if (arr == nil) arr = [NSArray new];
 /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
  return arr;
}


- (NSRange)selectedRange
{
  if (NS_KEYLOG)
    NSLog (@"selectedRange request");
  return NSMakeRange (NSNotFound, 0);
}


- (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
{
  if (NS_KEYLOG)
    NSLog (@"characterIndexForPoint request");
  return 0;
}


- (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
{
  static NSAttributedString *str = nil;
  if (str == nil) str = [NSAttributedString new];
  if (NS_KEYLOG)
    NSLog (@"attributedSubstringFromRange request");
  return str;
}
/* End <NSTextInput> impl. */
@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;

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

    xEvent->xkey.root = XRootWindow(Tk_Display(tkwin), 0);
    xEvent->xkey.subwindow = None;
    xEvent->xkey.time = TkpGetMS();
    xEvent->xkey.state = state;
    xEvent->xkey.same_screen = true;
    xEvent->xkey.trans_chars[0] = 0;
    xEvent->xkey.nbytes = 0;
}

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

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:
 */

Changes to macosx/tkMacOSXKeyboard.c.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
...
118
119
120
121
122
123
124
125

126
127
128
129
130
131
132
...
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
...
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
...
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
...
763
764
765
766
767
768
769
770

771
772
773
774
775
776
777
778
779
780
781
...
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
 *
 * 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.
 *
 * RCS: @(#) $Id$
 */

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

/*
 * A couple of simple definitions to make code a bit more self-explaining.
................................................................................
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

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

char *
TkpGetString(
    TkWindow *winPtr,		/* Window where event occurred: Needed to get
				 * input context. */
    XEvent *eventPtr,		/* X keyboard event. */
    Tcl_DString *dsPtr)		/* Uninitialized or empty string to hold
				 * result. */
{
................................................................................
    (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 = (XModifierKeymap *) ckalloc(sizeof(XModifierKeymap));
    modmap->max_keypermod = 0;
    modmap->modifiermap = NULL;
    return modmap;
}
 
/*
 *----------------------------------------------------------------------
................................................................................
 */

void
XFreeModifiermap(
    XModifierKeymap *modmap)
{
    if (modmap->modifiermap != NULL) {
	ckfree((char *) modmap->modifiermap);
    }
    ckfree((char *) modmap);
}
 
/*
 *----------------------------------------------------------------------
 *
 * XKeysymToString, XStringToKeysym --
 *
................................................................................
	     * If we get here, we probably need to implement something new.
	     */

	    return NoSymbol;
	}
    }

#if 0

    if (eventPtr->xkey.nbytes) {
	return eventPtr->xkey.nbytes;
    }
#endif

    /*
     * 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".)
     */
................................................................................
     * don't generate them either (the keycodes actually given in the simulated
     * modifier events are bogus). So there is no modifier map. If we ever want
     * to simulate real modifier keycodes, the list will be constant in the
     * Carbon implementation.
     */

    if (dispPtr->modKeyCodes != NULL) {
	ckfree((char *) dispPtr->modKeyCodes);
    }
    dispPtr->numModKeyCodes = 0;
    dispPtr->modKeyCodes = NULL;
}
 
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 79
 * coding: utf-8
 * End:
 */






<
<







 







|
>







 







|







 







|







 







|

|







 







|
>

|

<







 







|







|





5
6
7
8
9
10
11


12
13
14
15
16
17
18
...
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
...
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
...
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
...
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
...
762
763
764
765
766
767
768
769
770
771
772
773

774
775
776
777
778
779
780
...
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
 *
 * 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"

/*
 * A couple of simple definitions to make code a bit more self-explaining.
................................................................................
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

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

const char *
TkpGetString(
    TkWindow *winPtr,		/* Window where event occurred: Needed to get
				 * input context. */
    XEvent *eventPtr,		/* X keyboard event. */
    Tcl_DString *dsPtr)		/* Uninitialized or empty string to hold
				 * result. */
{
................................................................................
    (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;
}
 
/*
 *----------------------------------------------------------------------
................................................................................
 */

void
XFreeModifiermap(
    XModifierKeymap *modmap)
{
    if (modmap->modifiermap != NULL) {
	ckfree(modmap->modifiermap);
    }
    ckfree(modmap);
}
 
/*
 *----------------------------------------------------------------------
 *
 * XKeysymToString, XStringToKeysym --
 *
................................................................................
	     * 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 & 0xFFFF;
    }


    /*
     * 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".)
     */
................................................................................
     * don't generate them either (the keycodes actually given in the simulated
     * modifier events are bogus). So there is no modifier map. If we ever want
     * to simulate real modifier keycodes, the list will be constant in the
     * Carbon implementation.
     */

    if (dispPtr->modKeyCodes != NULL) {
	ckfree(dispPtr->modKeyCodes);
    }
    dispPtr->numModKeyCodes = 0;
    dispPtr->modKeyCodes = NULL;
}
 
/*
 * Local Variables:
 * mode: objc
 * c-basic-offset: 4
 * fill-column: 79
 * coding: utf-8
 * End:
 */

Changes to macosx/tkMacOSXMenu.c.

2
3
4
5
6
7
8

9
10
11
12
13
14
15
16
17
18
19
20
..
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
..
55
56
57
58
59
60
61

62
63
64
65
66
67
68
...
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
...
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
...
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
...
470
471
472
473
474
475
476


477
478


479
480
481
482
483
484
485
...
519
520
521
522
523
524
525

526
527
528
529
530
531
532
...
541
542
543
544
545
546
547
548
549

550
551
552
553
554
555
556
...
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
...
618
619
620
621
622
623
624
625
626

627
628
629
630
631
632
633
...
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
...
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
...
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
...
779
780
781
782
783
784
785

786
787
788
789
790
791
792
793
...
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
...
900
901
902
903
904
905
906
907

908
909
910
911
912

913
914
915
916
917
918
919
....
1030
1031
1032
1033
1034
1035
1036

1037
1038
1039
1040
1041
1042
1043
....
1152
1153
1154
1155
1156
1157
1158

1159
1160
1161
1162
1163
1164
1165
....
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240

1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
....
1263
1264
1265
1266
1267
1268
1269

1270
1271

1272
1273
1274
1275
1276
1277
1278
....
1317
1318
1319
1320
1321
1322
1323


1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
....
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
....
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
....
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
....
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
 * tkMacOSXMenu.c --
 *
 *	This module implements the Mac-platform specific features of menus.
 *
 * Copyright (c) 1996-1997 by 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.
 *
 * RCS: @(#) $Id$
 */

#include "tkMacOSXPrivate.h"
#include "tkMenubutton.h"
#include "tkMenu.h"
#include "tkColor.h"
#include "tkFont.h"
................................................................................
*/

#define ENTRY_HELP_MENU		ENTRY_PLATFORM_FLAG1
#define ENTRY_APPLE_MENU	ENTRY_PLATFORM_FLAG2
#define ENTRY_WINDOWS_MENU	ENTRY_PLATFORM_FLAG3

#define sl(s) ((int) (sizeof(s "") - 1))

#define SPECIALMENU(n, f) {.name = "." #n, .len = sl(#n) + 1, \
	.flag = ENTRY_##f##_MENU }
static const struct {
    const char *name; const size_t len; const int flag;
} specialMenus[] = {
    SPECIALMENU(help,	HELP),
    SPECIALMENU(apple,	APPLE),
    SPECIALMENU(window,	WINDOWS),
    {NULL}
};
#undef SPECIALMENU

#define MODIFIER(n, f) {.name = #n, .len = sl(#n), .mask = f }
static const struct {
    const char *name; const size_t len; const NSUInteger mask;
} modifiers[] = {
    MODIFIER(Control,	NSControlKeyMask),
    MODIFIER(Ctrl,	NSControlKeyMask),
    MODIFIER(Option,	NSAlternateKeyMask),
................................................................................
    MODIFIER(Shift,	NSShiftKeyMask),
    MODIFIER(Command,	NSCommandKeyMask),
    MODIFIER(Cmd,	NSCommandKeyMask),
    MODIFIER(Meta,	NSCommandKeyMask),
    {NULL}
};
#undef MODIFIER

#define ACCEL(n, c) {.name = #n, .len = sl(#n), .ch = c }
static const struct {
    const char *name; const size_t len; const UniChar ch;
} specialAccelerators[] = {
    ACCEL(PageUp,	NSPageUpFunctionKey),
    ACCEL(PageDown,	NSPageDownFunctionKey),
    ACCEL(Left,		NSLeftArrowFunctionKey),
................................................................................
static void	MenuSelectEvent(TkMenu *menuPtr);
static void	RecursivelyClearActiveMenu(TkMenu *menuPtr);
static int	ModifierCharWidth(Tk_Font tkfont);

#pragma mark TKMenu

@interface TKMenu(TKMenuPrivate)
- (id)initWithTkMenu:(TkMenu *)tkMenu;
- (TkMenu *)tkMenu;
- (int)tkIndexOfItem:(NSMenuItem *)menuItem;
- (void)insertItem:(NSMenuItem *)newItem atTkIndex:(NSInteger)index;
@end

#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
#define TKMenu_NSMenuDelegate <NSMenuDelegate>
#else
#define TKMenu_NSMenuDelegate
#endif
@interface TKMenu(TKMenuDelegate) TKMenu_NSMenuDelegate
@end

@implementation TKMenu
- (void)setSpecial:(NSUInteger)special {

    NSAssert(!_tkSpecial, @"Cannot change specialness of a special menu");
    _tkSpecial = special;
}
- (BOOL)isSpecial:(NSUInteger)special {

    return (_tkSpecial == special);
}
@end

@implementation TKMenu(TKMenuPrivate)
- (id)initWithTitle:(NSString *)aTitle {


    self = [super initWithTitle:aTitle];
    if (self) {
	_tkMenu = NULL;
	_tkOffset = 0;
	_tkItemCount = 0;
	_tkSpecial = 0;
	[self setDelegate:self];
    }
    return self;
}
- (id)initWithTkMenu:(TkMenu *)tkMenu {



    NSString *title = [[NSString alloc] initWithUTF8String:
	    Tk_PathName(tkMenu->tkwin)];

    self = [self initWithTitle:title];
    [title release];
    if (self) {
	_tkMenu = tkMenu;
    }
    return self;
}

- (id)copyWithZone:(NSZone *)zone {

    TKMenu *copy = [super copyWithZone:zone];

    NSAssert(_tkMenu == nil, @"Cannot copy tkMenu");
    copy->_tkMenu = _tkMenu;
    copy->_tkOffset = _tkOffset;
    copy->_tkItemCount = _tkItemCount;
    copy->_tkSpecial = _tkSpecial;
    return copy;
}

- (TkMenu *)tkMenu {

    return _tkMenu;
}
- (int)tkIndexOfItem:(NSMenuItem *)menuItem {



    return [self indexOfItem:menuItem] - _tkOffset;
}
- (void)insertItem:(NSMenuItem *)newItem atTkIndex:(NSInteger)index {



    [super insertItem:newItem atIndex:index + _tkOffset];
    _tkItemCount++;
}
- (void)insertItem:(NSMenuItem *)newItem atIndex:(NSInteger)index {


    if (_tkMenu && index >= 0) {
	if ((NSUInteger)index <= _tkOffset) {
	    _tkOffset++;
	} else {
	    NSAssert((NSUInteger)index >= _tkItemCount + _tkOffset,
		    @"Cannot insert in the middle of Tk menu");
	}
    }
    [super insertItem:newItem atIndex:index];
}

- (void)removeItemAtIndex:(NSInteger)index {

    if (_tkMenu && index >= 0) {
	if ((NSUInteger)index < _tkOffset) {
	    _tkOffset--;
	} else if ((NSUInteger)index < _tkItemCount + _tkOffset) {
	    _tkItemCount--;
	}
    }
    [super removeItemAtIndex:index];
}
- (NSMenuItem *)newTkMenuItem:(TkMenuEntry *)mePtr {



    NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:@""
	action:@selector(tkMenuItemInvoke:) keyEquivalent:@""];

    [menuItem setTarget:self];
    [menuItem setTag:(NSInteger)mePtr];
    return menuItem;
}
@end

@implementation TKMenu(TKMenuActions)
// target methods
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem {



    return [menuItem isEnabled];
}

- (void)tkMenuItemInvoke:(id)sender {

    /*
     * With the delegate matching key equivalents, when a menu action is sent
     * in response to a key equivalent, sender is the whole menu and not the
     * the specific menu item, use this to ignore key equivalents for our menus
     * (as Tk handles them directly via bindings).
     */

    if ([sender isKindOfClass:[NSMenuItem class]]) {
	NSMenuItem *menuItem = (NSMenuItem *)sender;
	TkMenu *menuPtr = (TkMenu *)_tkMenu;
	TkMenuEntry *mePtr = (TkMenuEntry *)[menuItem tag];

	if (menuPtr && mePtr) {
	    Tcl_Interp *interp = menuPtr->interp;
	    /*Add time for errors to fire if necessary. This is sub-optimal but avoids issues with Tcl/Cocoa event loop integration.*/
	    Tcl_Sleep(100);

	    Tcl_Preserve(interp);
	    Tcl_Preserve(menuPtr);

	    int result = TkInvokeMenu(interp, menuPtr, mePtr->index);

	    if (result != TCL_OK && result != TCL_CONTINUE &&
		    result != TCL_BREAK) {
		Tcl_AddErrorInfo(interp, "\n    (menu invoke)");
		Tcl_BackgroundError(interp);
	    }
	    Tcl_Release(menuPtr);
	    Tcl_Release(interp);
................................................................................
@implementation TKMenu(TKMenuDelegate)
#define keyEquivModifiersMatch(km, m) (( \
    ((km) & NSCommandKeyMask) != ((m) & NSCommandKeyMask) || \
    ((km) & NSAlternateKeyMask) != ((m) & NSAlternateKeyMask) || \
    ((km) & NSControlKeyMask) != ((m) & NSControlKeyMask) || \
    (((km) & NSShiftKeyMask) != ((m) & NSShiftKeyMask) && \
    ((m) & NSFunctionKeyMask))) ? NO : YES)
- (BOOL)menuHasKeyEquivalent:(NSMenu*)menu forEvent:(NSEvent*)event

	target:(id*)target action:(SEL*)action {



    NSString *key = [[event charactersIgnoringModifiers] lowercaseString];
    NSUInteger modifiers = [event modifierFlags] &
	    NSDeviceIndependentModifierFlagsMask;

    if (modifiers == (NSCommandKeyMask | NSShiftKeyMask) &&
	    [key compare:@"?"] == NSOrderedSame) {
	return NO;
    }







    NSArray *itemArray = [self itemArray];

    for (NSMenuItem *item in itemArray) {
	if ([item isEnabled] && [[item keyEquivalent] compare:key] ==
		NSOrderedSame) {
	    NSUInteger keyEquivModifiers = [item keyEquivalentModifierMask];

	    if (keyEquivModifiersMatch(keyEquivModifiers, modifiers)) {
		*target = [item target];
		*action = [item action];
		return YES;
	    }
	}
    }
    return NO;
}
- (void)menuWillOpen:(NSMenu *)menu {


    if (_tkMenu) {
	//RecursivelyClearActiveMenu(_tkMenu);
	GenerateMenuSelectEvent((TKMenu *)[self supermenu],
		[self itemInSupermenu]);
    }
}
- (void)menuDidClose:(NSMenu *)menu {


    if (_tkMenu) {
	RecursivelyClearActiveMenu(_tkMenu);
    }
}
- (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item {


    if (_tkMenu) {
	GenerateMenuSelectEvent(self, item);
    }
}

- (void)menuNeedsUpdate:(NSMenu*)menu {

    TkMenu *menuPtr = (TkMenu *)_tkMenu;

    if (menuPtr) {
	Tcl_Interp *interp = menuPtr->interp;

	Tcl_Preserve(interp);
	Tcl_Preserve(menuPtr);

	int result = TkPostCommand(_tkMenu);
	if (result != TCL_OK && result != TCL_CONTINUE && result != TCL_BREAK) {


	    Tcl_AddErrorInfo(interp, "\n    (menu preprocess)");
	    Tcl_BackgroundError(interp);
	}
	Tcl_Release(menuPtr);
	Tcl_Release(interp);
    }
}
@end

#pragma mark TKApplication(TKMenu)

@interface NSApplication(TKMenu)
- (void)setAppleMenu:(NSMenu *)menu;
@end

@implementation TKApplication(TKMenu)
- (void)menuBeginTracking:(NSNotification *)notification {


#ifdef TK_MAC_DEBUG_NOTIFICATIONS
    TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
#endif
    //TkMacOSXClearMenubarActive();
    //TkMacOSXPreprocessMenu();
}
- (void)menuEndTracking:(NSNotification *)notification {


#ifdef TK_MAC_DEBUG_NOTIFICATIONS
    TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
#endif
    if (!inPostMenu) {
	TkMacOSXClearMenubarActive();
    }
}

- (void)tkSetMainMenu:(TKMenu *)menu {

    if (gNoTkMenus) {
	return;
    }

    TKMenu *applicationMenu = nil;

    if (menu) {
	NSMenuItem *applicationMenuItem = [menu numberOfItems] ?
		[menu itemAtIndex:0] : nil;

	if (![menu isSpecial:tkMainMenu]) {
	    TkMenuEntry *mePtr = (TkMenuEntry *)[applicationMenuItem tag];

	    if (!mePtr || !(mePtr->entryFlags & ENTRY_APPLE_MENU)) {
		applicationMenuItem = [NSMenuItem itemWithSubmenu:
			[[_defaultApplicationMenu copy] autorelease]];
		[menu insertItem:applicationMenuItem atIndex:0];
	    }
	    [menu setSpecial:tkMainMenu];
	}
................................................................................
	applicationMenu = (TKMenu *)[applicationMenuItem submenu];
	if (![applicationMenu isSpecial:tkApplicationMenu]) {
	    for (NSMenuItem *item in _defaultApplicationMenuItems) {
		[applicationMenu addItem:[[item copy] autorelease]];
	    }
	    [applicationMenu setSpecial:tkApplicationMenu];
	}

	NSArray *itemArray = [menu itemArray];

	for (NSMenuItem *item in itemArray) {
	    TkMenuEntry *mePtr = (TkMenuEntry *)[item tag];
	    TKMenu *submenu = (TKMenu *)[item submenu];

	    if (mePtr && submenu) {
		if ((mePtr->entryFlags & ENTRY_WINDOWS_MENU) &&
			![submenu isSpecial:tkWindowsMenu]) {
		    NSInteger index = 0;

		    for (NSMenuItem *i in _defaultWindowsMenuItems) {
			[submenu insertItem:[[i copy] autorelease] atIndex:
				index++];
		    }
		    [self setWindowsMenu:submenu];
		    [submenu setSpecial:tkWindowsMenu];
		} else if ((mePtr->entryFlags & ENTRY_HELP_MENU) &&
			![submenu isSpecial:tkHelpMenu]) {
		    NSInteger index = 0;

		    for (NSMenuItem *i in _defaultHelpMenuItems) {
			[submenu insertItem:[[i copy] autorelease] atIndex:
				index++];
		    }
		    [submenu setSpecial:tkHelpMenu];
		}
	    }
	}
    } else {
	menu = _defaultMainMenu;
	applicationMenu = _defaultApplicationMenu;
    }


    NSMenuItem *servicesMenuItem = [applicationMenu itemWithTitle:@"Services"];

    if (servicesMenuItem && [servicesMenuItem submenu] != _servicesMenu) {
	[[_servicesMenu itemInSupermenu] setSubmenu:nil];
	[servicesMenuItem setSubmenu:_servicesMenu];
    }
    [self setAppleMenu:applicationMenu];
    [self setMainMenu:menu];
}
................................................................................
 *	Gets a new blank menu. Only the platform specific options are filled
 *	in.
 *
 * Results:
 *	Returns a standard Tcl error.
 *
 * Side effects:
 *	Allocates a NSMenu and puts it into the platformData field
 *	of the menuPtr.
 *
 *----------------------------------------------------------------------
 */

int
TkpNewMenu(
    TkMenu *menuPtr)		/* The common structure we are making the
................................................................................
    if (mePtr->type == SEPARATOR_ENTRY || mePtr->type == TEAROFF_ENTRY) {
	menuItem = [[NSMenuItem separatorItem] retain];
    } else {
	menuItem = [menu newTkMenuItem:mePtr];
    }
    mePtr->platformEntryData = (TkMenuPlatformEntryData)
	    TkMacOSXMakeUncollectable(menuItem);


    /* Caller TkMenuEntry() already did this same insertion into the generic
     * TkMenu so we just match it for the platform menu. */


    [menu insertItem:menuItem atTkIndex:mePtr->index];
    return TCL_OK;
}
 
/*
 *----------------------------------------------------------------------
 *
................................................................................
    if (mePtr->image) {
    	Tk_SizeOfImage(mePtr->image, &imageWidth, &imageHeight);
	image = TkMacOSXGetNSImageWithTkImage(mePtr->menuPtr->display,
		mePtr->image, imageWidth, imageHeight);
    } else if (mePtr->bitmapPtr != None) {
	Pixmap bitmap = Tk_GetBitmapFromObj(mePtr->menuPtr->tkwin,
		mePtr->bitmapPtr);

	Tk_SizeOfBitmap(mePtr->menuPtr->display, bitmap, &imageWidth,
		&imageHeight);
	image = TkMacOSXGetNSImageWithBitmap(mePtr->menuPtr->display, bitmap,
		gc, imageWidth, imageHeight);
    }
    [menuItem setImage:image];
    if ((!image || mePtr->compound != COMPOUND_NONE) && mePtr->labelPtr &&
................................................................................
    }
    [menuItem setTitle:title];
    if (strcmp(Tcl_GetString(fontPtr), "menu") || gc->foreground != defaultFg
	    || gc->background != defaultBg) {
	attributes = TkMacOSXNSFontAttributesForFont(Tk_GetFontFromObj(
		mePtr->menuPtr->tkwin, fontPtr));
	if (gc->foreground != defaultFg || gc->background != defaultBg) {
	    NSColor *color = TkMacOSXGetNSColor(gc, gc->foreground != defaultFg ?
		    gc->foreground : gc->background);

	    attributes = [[attributes mutableCopy] autorelease];
	    [(NSMutableDictionary *)attributes setObject:color
		    forKey:NSForegroundColorAttributeName];
	}
	if (attributes) {
	    attributedTitle = [[[NSAttributedString alloc]
		    initWithString:title attributes:attributes] autorelease];
................................................................................
	menuRefPtr = TkFindMenuReferencesObj(mePtr->menuPtr->interp,
		mePtr->namePtr);
	if (menuRefPtr && menuRefPtr->menuPtr) {
	    CheckForSpecialMenu(menuRefPtr->menuPtr);
	    submenu = (TKMenu *) menuRefPtr->menuPtr->platformData;
	    if ([submenu supermenu] && [menuItem submenu] != submenu) {
		/*
		* This happens during a clone, where the parent menu is cloned
		* before its children, so just ignore this temprary setting,
		* it will be changed shortly (c.f. tkMenu.c CloneMenu())

		*/

		submenu = nil;
	    } else {
		[submenu setTitle:title];
	    }
	}
    }
    [menuItem setSubmenu:submenu];

 /*Disabling parent menu disables entries; we must re-enable the entries here.*/
    NSArray *itemArray = [submenu itemArray];
    
    if ([menuItem isEnabled]) {
	    for (NSMenuItem *item in itemArray) {
		    [item setEnabled:YES];
	    }
	}

    return TCL_OK;
}
 
/*
 *----------------------------------------------------------------------
 *
 * TkpDestroyMenuEntry --
................................................................................

void
TkpDestroyMenuEntry(
    TkMenuEntry *mePtr)
{
    if (mePtr->platformEntryData && mePtr->menuPtr->platformData) {
	TKMenu *menu = (TKMenu *) mePtr->menuPtr->platformData;
	NSMenuItem *menuItem = (NSMenuItem *)mePtr->platformEntryData;
	NSInteger index = [menu indexOfItem:menuItem];

	if (index > -1) {
	    [menu removeItemAtIndex:index];
	}
    }
    TkMacOSXMakeCollectableAndRelease(mePtr->platformEntryData);
}
 
................................................................................
    TkMenu *menuPtr,		/* The menu we are posting */
    int x,			/* The global x-coordinate of the top, left-
				 * hand corner of where the menu is supposed
				 * to be posted. */
    int y)			/* The global y-coordinate */
{
    NSWindow *win = [NSApp keyWindow];
    if (win) {



	inPostMenu = 1;

	int oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE);
	NSView *view = [win contentView];
	NSRect frame = NSMakeRect(x + 9, tkMacOSXZeroScreenHeight - y - 9, 1, 1);

	frame.origin = [view convertPoint:
		[win convertScreenToBase:frame.origin] fromView:nil];

	NSMenu *menu = (NSMenu *) menuPtr->platformData;
	NSPopUpButtonCell *popUpButtonCell = [[NSPopUpButtonCell alloc]
		initTextCell:@"" pullsDown:NO];


	[popUpButtonCell setMenu:menu];
	[popUpButtonCell selectItem:nil];
	[popUpButtonCell performClickWithFrame:frame inView:view];
	[popUpButtonCell release];
	Tcl_SetServiceMode(oldMode);
	inPostMenu = 0;
	return TCL_OK;
    } else {
	return TCL_ERROR;
    }
}
 
/*
 *----------------------------------------------------------------------
 *
 * TkpSetWindowMenuBar --
 *
................................................................................
 *----------------------------------------------------------------------
 */

void
TkpSetMainMenubar(
    Tcl_Interp *interp,		/* The interpreter of the application */
    Tk_Window tkwin,		/* The frame we are setting up */
    char *menuName)		/* The name of the menu to put in front. If
				 * NULL, use the default menu bar. */
{
    static Tcl_Interp *currentInterp = NULL;
    TKMenu *menu = nil;

    if (menuName) {
	TkWindow *winPtr = (TkWindow *) tkwin;

	if (winPtr->wmInfoPtr && winPtr->wmInfoPtr->menuPtr &&
		winPtr->wmInfoPtr->menuPtr->masterMenuPtr &&
		winPtr->wmInfoPtr->menuPtr->masterMenuPtr->tkwin &&
		!strcmp(menuName, Tk_PathName(
		winPtr->wmInfoPtr->menuPtr->masterMenuPtr->tkwin))) {
	    menu = (TKMenu *) winPtr->wmInfoPtr->menuPtr->platformData;
	} else {
	    TkMenuReferences *menuRefPtr = TkFindMenuReferences(interp,
		    menuName);

	    if (menuRefPtr && menuRefPtr->menuPtr &&
		    menuRefPtr->menuPtr->platformData) {
		menu = (TKMenu *) menuRefPtr->menuPtr->platformData;
	    }
	}
    }
    if (menu || interp != currentInterp) {
................................................................................
}
 
/*
 *----------------------------------------------------------------------
 *
 * CheckForSpecialMenu --
 *
 *	Given a menu, check to see whether or not it is a cascade in
 *	a menubar with one of the special names .apple, .help or .window
 *	If it is, the entry that points to this menu will be marked.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Will set entryFlags appropriately.
 *
................................................................................
CheckForSpecialMenu(
    TkMenu *menuPtr)		/* The menu we are checking */
{
    if (!menuPtr->masterMenuPtr->tkwin) {
	return;
    }
    for (TkMenuEntry *cascadeEntryPtr = menuPtr->menuRefPtr->parentEntryPtr;

	    cascadeEntryPtr; cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) {
	if (cascadeEntryPtr->menuPtr->menuType == MENUBAR
		&& cascadeEntryPtr->menuPtr->masterMenuPtr->tkwin) {
	    TkMenu *masterMenuPtr = cascadeEntryPtr->menuPtr->masterMenuPtr;
	    int i = 0;
	    Tcl_DString ds;

	    Tcl_DStringInit(&ds);
................................................................................
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

static NSString*
ParseAccelerator(
    const char *accel,
    NSUInteger *maskPtr)
{
    unichar ch = 0;
    size_t len;
    int i;
................................................................................
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */

static int
ModifierCharWidth(Tk_Font tkfont)

{
    static NSString *cmdChar = nil;

    if (!cmdChar) {
	unichar cmd = kCommandUnicode;

	cmdChar = [[NSString alloc] initWithCharacters:&cmd length:1];
    }
    return [cmdChar sizeWithAttributes:
	    TkMacOSXNSFontAttributesForFont(tkfont)].width;
}
 
/*
................................................................................

	    if (mePtr->image) {
		Tk_SizeOfImage(mePtr->image, &width, &height);
		haveImage = 1;
	    } else if (mePtr->bitmapPtr) {
		Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin,
			mePtr->bitmapPtr);

		Tk_SizeOfBitmap(menuPtr->display, bitmap, &width, &height);
		haveImage = 1;
	    }
	    if (!haveImage || (mePtr->compound != COMPOUND_NONE)) {
		NSAttributedString *attrTitle = [menuItem attributedTitle];
		NSSize size;

................................................................................
    TKMenu *menu,
    NSMenuItem *menuItem)
{
    TkMenu *menuPtr = [menu tkMenu];

    if (menuPtr) {
	int index = [menu tkIndexOfItem:menuItem];

	if (index < 0 || index >= menuPtr->numEntries ||
		(menuPtr->entries[index])->state == ENTRY_DISABLED) {
	    TkActivateMenuEntry(menuPtr, -1);
	} else {
	    TkActivateMenuEntry(menuPtr, index);
	    MenuSelectEvent(menuPtr);
	    return true;
................................................................................
 */

void
RecursivelyClearActiveMenu(
    TkMenu *menuPtr)		/* The menu to reset. */
{
    int i;
    TkMenuEntry *mePtr;

    TkActivateMenuEntry(menuPtr, -1);
    for (i = 0; i < menuPtr->numEntries; i++) {
	mePtr = menuPtr->entries[i];

	if (mePtr->type == CASCADE_ENTRY) {
	    if ((mePtr->childMenuRefPtr != NULL)
		    && (mePtr->childMenuRefPtr->menuPtr != NULL)) {
		RecursivelyClearActiveMenu(mePtr->childMenuRefPtr->menuPtr);
	    }
	}
    }
}
 
/*
 *----------------------------------------------------------------------
 *
................................................................................
 *----------------------------------------------------------------------
 */

void
TkMacOSXClearMenubarActive(void)
{
    NSMenu *mainMenu = [NSApp mainMenu];

    if (mainMenu && [mainMenu isKindOfClass:[TKMenu class]]) {
	TkMenu *menuPtr = [(TKMenu *)mainMenu tkMenu];

	if (menuPtr && menuPtr->numEntries && menuPtr->entries) {
	    RecursivelyClearActiveMenu(menuPtr);
	}
    }
}
 
/*
................................................................................

void
TkpMenuInit(void)
{
    TkColor *tkColPtr;

    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];


#define observe(n, s) [nc addObserver:NSApp selector:@selector(s) name:(n) object:nil]
    observe(NSMenuDidBeginTrackingNotification, menuBeginTracking:);
    observe(NSMenuDidEndTrackingNotification, menuEndTracking:);
#undef observe

    [NSMenuItem setUsesUserKeyEquivalents:NO];
    tkColPtr = TkpGetColor(None, DEF_MENU_BG_COLOR);
    defaultBg = tkColPtr->color.pixel;
    ckfree((char *) tkColPtr);
    tkColPtr = TkpGetColor(None, DEF_MENU_FG);
    defaultFg = tkColPtr->color.pixel;
    ckfree((char *) tkColPtr);

    ChkErr(GetThemeMetric, kThemeMetricMenuMarkColumnWidth,
	    &menuMarkColumnWidth);
    ChkErr(GetThemeMetric, kThemeMetricMenuTextLeadingEdgeMargin,
	    &menuTextLeadingEdgeMargin);
    ChkErr(GetThemeMetric, kThemeMetricMenuTextTrailingEdgeMargin,
	    &menuTextTrailingEdgeMargin);
................................................................................
 
/*
 *----------------------------------------------------------------------
 *
 * TkpMenuNotifyToplevelCreate --
 *
 *	This routine reconfigures the menu and the clones indicated by
 *	menuName becuase a toplevel has been created and any system menus need
 *	to be created. Only applicable to Windows.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	An idle handler is set up to do the reconfiguration.
................................................................................
 *
 *----------------------------------------------------------------------
 */

void
TkpMenuNotifyToplevelCreate(
    Tcl_Interp *interp,		/* The interp the menu lives in. */
    char *menuName)		/* The name of the menu to reconfigure. */
{
    /*
     * Nothing to do.
     */
}
 
/*
................................................................................
    const Tk_FontMetrics *menuMetricsPtr,
				/* Precalculated metrics for menu */
    int x,			/* X-coordinate of topleft of entry */
    int y,			/* Y-coordinate of topleft of entry */
    int width,			/* Width of the entry rectangle */
    int height,			/* Height of the current rectangle */
    int strictMotif,		/* Boolean flag */
    int drawArrow)		/* Whether or not to draw the cascade
				 * arrow for cascade items. Only applies
				 * to Windows. */
{
}

#pragma mark Obsolete
 
/*
 *----------------------------------------------------------------------
................................................................................
void
TkMacOSXMenuClick(void)
{
}
 
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 79
 * coding: utf-8
 * End:
 */






>



<
<







 







>











>







 







>







 







|
|
|
|











|
>



|
>





|
>
>










<
>
>
>


>







>
|
>

>







>
|
>


<
>
>
>


<
>
>
>



|
>
>










>
|
>









<
>
>
>

|
>








<
>
>
>


>
|
>



|
|

>




>




>


>

>







 







<
>
|
>
>
>



>




>
>
>
>
>
>
>

>




>









|
>
>






|
>
>




|
>
>




>
|
>
|
>


>


>

<
>
>
|
|










|



|
>
>






|
>
>







>
|
>



>

>



>


>







 







>

>



>




>









>












>
>
|
>







 







|
|







 







>
>
|
|
>
>







 







>







 







|
|
>







 







|
|
|
>
|
>








|







>







 







|

>







 







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







 







|




>


>









>







 







|
|
|







 







>
|







 







|







 







|
>





>







 







>







 







>







 







<



|
>
|
|
|
|
<







 







>

|
>







 







>
>
|







|


|







 







|







 







|







 







|
|
|







 







|





2
3
4
5
6
7
8
9
10
11
12


13
14
15
16
17
18
19
..
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
..
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
...
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
...
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
...
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
...
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
...
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
...
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
...
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
...
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
...
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
...
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
...
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
...
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
...
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
...
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
....
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
....
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
....
1329
1330
1331
1332
1333
1334
1335

1336
1337
1338
1339
1340
1341
1342
1343
1344

1345
1346
1347
1348
1349
1350
1351
....
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
....
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
....
1479
1480
1481
1482
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
....
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
....
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
 * tkMacOSXMenu.c --
 *
 *	This module implements the Mac-platform specific features of menus.
 *
 * Copyright (c) 1996-1997 by Sun Microsystems, Inc.
 * Copyright 2001-2009, Apple Inc.
 * Copyright (c) 2005-2009 Daniel A. Steffen <[email protected]>
 * Copyright (c) 2012 Adrian Robert.
 *
 * 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 "tkMenubutton.h"
#include "tkMenu.h"
#include "tkColor.h"
#include "tkFont.h"
................................................................................
*/

#define ENTRY_HELP_MENU		ENTRY_PLATFORM_FLAG1
#define ENTRY_APPLE_MENU	ENTRY_PLATFORM_FLAG2
#define ENTRY_WINDOWS_MENU	ENTRY_PLATFORM_FLAG3

#define sl(s) ((int) (sizeof(s "") - 1))

#define SPECIALMENU(n, f) {.name = "." #n, .len = sl(#n) + 1, \
	.flag = ENTRY_##f##_MENU }
static const struct {
    const char *name; const size_t len; const int flag;
} specialMenus[] = {
    SPECIALMENU(help,	HELP),
    SPECIALMENU(apple,	APPLE),
    SPECIALMENU(window,	WINDOWS),
    {NULL}
};
#undef SPECIALMENU

#define MODIFIER(n, f) {.name = #n, .len = sl(#n), .mask = f }
static const struct {
    const char *name; const size_t len; const NSUInteger mask;
} modifiers[] = {
    MODIFIER(Control,	NSControlKeyMask),
    MODIFIER(Ctrl,	NSControlKeyMask),
    MODIFIER(Option,	NSAlternateKeyMask),
................................................................................
    MODIFIER(Shift,	NSShiftKeyMask),
    MODIFIER(Command,	NSCommandKeyMask),
    MODIFIER(Cmd,	NSCommandKeyMask),
    MODIFIER(Meta,	NSCommandKeyMask),
    {NULL}
};
#undef MODIFIER

#define ACCEL(n, c) {.name = #n, .len = sl(#n), .ch = c }
static const struct {
    const char *name; const size_t len; const UniChar ch;
} specialAccelerators[] = {
    ACCEL(PageUp,	NSPageUpFunctionKey),
    ACCEL(PageDown,	NSPageDownFunctionKey),
    ACCEL(Left,		NSLeftArrowFunctionKey),
................................................................................
static void	MenuSelectEvent(TkMenu *menuPtr);
static void	RecursivelyClearActiveMenu(TkMenu *menuPtr);
static int	ModifierCharWidth(Tk_Font tkfont);

#pragma mark TKMenu

@interface TKMenu(TKMenuPrivate)
- (id) initWithTkMenu: (TkMenu *) tkMenu;
- (TkMenu *) tkMenu;
- (int) tkIndexOfItem: (NSMenuItem *) menuItem;
- (void) insertItem: (NSMenuItem *) newItem atTkIndex: (NSInteger) index;
@end

#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
#define TKMenu_NSMenuDelegate <NSMenuDelegate>
#else
#define TKMenu_NSMenuDelegate
#endif
@interface TKMenu(TKMenuDelegate) TKMenu_NSMenuDelegate
@end

@implementation TKMenu
- (void) setSpecial: (NSUInteger) special
{
    NSAssert(!_tkSpecial, @"Cannot change specialness of a special menu");
    _tkSpecial = special;
}
- (BOOL) isSpecial: (NSUInteger) special
{
    return (_tkSpecial == special);
}
@end

@implementation TKMenu(TKMenuPrivate)

- (id) initWithTitle: (NSString *) aTitle
{
    self = [super initWithTitle:aTitle];
    if (self) {
	_tkMenu = NULL;
	_tkOffset = 0;
	_tkItemCount = 0;
	_tkSpecial = 0;
	[self setDelegate:self];
    }
    return self;
}


- (id) initWithTkMenu: (TkMenu *) tkMenu
{
    NSString *title = [[NSString alloc] initWithUTF8String:
	    Tk_PathName(tkMenu->tkwin)];

    self = [self initWithTitle:title];
    [title release];
    if (self) {
	_tkMenu = tkMenu;
    }
    return self;
}

- (id) copyWithZone: (NSZone *) zone
{
    TKMenu *copy = [super copyWithZone:zone];

    NSAssert(_tkMenu == nil, @"Cannot copy tkMenu");
    copy->_tkMenu = _tkMenu;
    copy->_tkOffset = _tkOffset;
    copy->_tkItemCount = _tkItemCount;
    copy->_tkSpecial = _tkSpecial;
    return copy;
}

- (TkMenu *) tkMenu
{
    return _tkMenu;
}


- (int) tkIndexOfItem: (NSMenuItem *) menuItem
{
    return [self indexOfItem:menuItem] - _tkOffset;
}


- (void) insertItem: (NSMenuItem *) newItem atTkIndex: (NSInteger) index
{
    [super insertItem:newItem atIndex:index + _tkOffset];
    _tkItemCount++;
}

- (void) insertItem: (NSMenuItem *) newItem atIndex: (NSInteger) index
{
    if (_tkMenu && index >= 0) {
	if ((NSUInteger)index <= _tkOffset) {
	    _tkOffset++;
	} else {
	    NSAssert((NSUInteger)index >= _tkItemCount + _tkOffset,
		    @"Cannot insert in the middle of Tk menu");
	}
    }
    [super insertItem:newItem atIndex:index];
}

- (void) removeItemAtIndex: (NSInteger) index
{
    if (_tkMenu && index >= 0) {
	if ((NSUInteger)index < _tkOffset) {
	    _tkOffset--;
	} else if ((NSUInteger)index < _tkItemCount + _tkOffset) {
	    _tkItemCount--;
	}
    }
    [super removeItemAtIndex:index];
}


- (NSMenuItem *) newTkMenuItem: (TkMenuEntry *) mePtr
{
    NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:@""
	    action:@selector(tkMenuItemInvoke:) keyEquivalent:@""];

    [menuItem setTarget:self];
    [menuItem setTag:(NSInteger)mePtr];
    return menuItem;
}
@end

@implementation TKMenu(TKMenuActions)
// target methods


- (BOOL) validateMenuItem: (NSMenuItem *) menuItem
{
    return [menuItem isEnabled];
}

- (void) tkMenuItemInvoke: (id) sender
{
    /*
     * With the delegate matching key equivalents, when a menu action is sent
     * in response to a key equivalent, sender is the whole menu and not the
     * the specific menu item, use this to ignore key equivalents for our
     * menus (as Tk handles them directly via bindings).
     */

    if ([sender isKindOfClass:[NSMenuItem class]]) {
	NSMenuItem *menuItem = (NSMenuItem *)sender;
	TkMenu *menuPtr = (TkMenu *)_tkMenu;
	TkMenuEntry *mePtr = (TkMenuEntry *)[menuItem tag];

	if (menuPtr && mePtr) {
	    Tcl_Interp *interp = menuPtr->interp;
	    /*Add time for errors to fire if necessary. This is sub-optimal but avoids issues with Tcl/Cocoa event loop integration.*/
	    Tcl_Sleep(100);

	    Tcl_Preserve(interp);
	    Tcl_Preserve(menuPtr);

	    int result = TkInvokeMenu(interp, menuPtr, mePtr->index);

	    if (result != TCL_OK && result != TCL_CONTINUE &&
		    result != TCL_BREAK) {
		Tcl_AddErrorInfo(interp, "\n    (menu invoke)");
		Tcl_BackgroundError(interp);
	    }
	    Tcl_Release(menuPtr);
	    Tcl_Release(interp);
................................................................................
@implementation TKMenu(TKMenuDelegate)
#define keyEquivModifiersMatch(km, m) (( \
    ((km) & NSCommandKeyMask) != ((m) & NSCommandKeyMask) || \
    ((km) & NSAlternateKeyMask) != ((m) & NSAlternateKeyMask) || \
    ((km) & NSControlKeyMask) != ((m) & NSControlKeyMask) || \
    (((km) & NSShiftKeyMask) != ((m) & NSShiftKeyMask) && \
    ((m) & NSFunctionKeyMask))) ? NO : YES)


- (BOOL) menuHasKeyEquivalent: (NSMenu *) menu forEvent: (NSEvent *) event
	target: (id *) target action: (SEL *) action
{
    /*Use lowercaseString to keep "shift" from firing twice if bound to different procedure.*/
    NSString *key = [[event charactersIgnoringModifiers] lowercaseString];
    NSUInteger modifiers = [event modifierFlags] &
	    NSDeviceIndependentModifierFlagsMask;

    if (modifiers == (NSCommandKeyMask | NSShiftKeyMask) &&
	    [key compare:@"?"] == NSOrderedSame) {
	return NO;
    }

    // For command key, take input manager's word so things
    // like dvorak / qwerty layout work.
    if (([event modifierFlags] & NSCommandKeyMask) == NSCommandKeyMask) {
      key = [event characters];
    }

    NSArray *itemArray = [self itemArray];

    for (NSMenuItem *item in itemArray) {
	if ([item isEnabled] && [[item keyEquivalent] compare:key] ==
		NSOrderedSame) {
	    NSUInteger keyEquivModifiers = [item keyEquivalentModifierMask];

	    if (keyEquivModifiersMatch(keyEquivModifiers, modifiers)) {
		*target = [item target];
		*action = [item action];
		return YES;
	    }
	}
    }
    return NO;
}

- (void) menuWillOpen: (NSMenu *) menu
{
    if (_tkMenu) {
	//RecursivelyClearActiveMenu(_tkMenu);
	GenerateMenuSelectEvent((TKMenu *)[self supermenu],
		[self itemInSupermenu]);
    }
}

- (void) menuDidClose: (NSMenu *) menu
{
    if (_tkMenu) {
	RecursivelyClearActiveMenu(_tkMenu);
    }
}

- (void) menu: (NSMenu *) menu willHighlightItem: (NSMenuItem *) item
{
    if (_tkMenu) {
	GenerateMenuSelectEvent(self, item);
    }
}

- (void) menuNeedsUpdate: (NSMenu *) menu
{
    TkMenu *menuPtr = (TkMenu *) _tkMenu;

    if (menuPtr) {
	Tcl_Interp *interp = menuPtr->interp;

	Tcl_Preserve(interp);
	Tcl_Preserve(menuPtr);

	int result = TkPostCommand(_tkMenu);


	if (result!=TCL_OK && result!=TCL_CONTINUE && result!=TCL_BREAK) {
	      Tcl_AddErrorInfo(interp, "\n    (menu preprocess)");
	      Tcl_BackgroundError(interp);
	}
	Tcl_Release(menuPtr);
	Tcl_Release(interp);
    }
}
@end

#pragma mark TKApplication(TKMenu)

@interface NSApplication(TKMenu)
- (void) setAppleMenu: (NSMenu *) menu;
@end

@implementation TKApplication(TKMenu)

- (void) menuBeginTracking: (NSNotification *) notification
{
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
    TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
#endif
    //TkMacOSXClearMenubarActive();
    //TkMacOSXPreprocessMenu();
}

- (void) menuEndTracking: (NSNotification *) notification
{
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
    TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
#endif
    if (!inPostMenu) {
	TkMacOSXClearMenubarActive();
    }
}

- (void) tkSetMainMenu: (TKMenu *) menu
{
    if (gNoTkMenus) {
	return;
    }

    TKMenu *applicationMenu = nil;

    if (menu) {
	NSMenuItem *applicationMenuItem = [menu numberOfItems] ?
		[menu itemAtIndex:0] : nil;

	if (![menu isSpecial:tkMainMenu]) {
	    TkMenuEntry *mePtr = (TkMenuEntry *)[applicationMenuItem tag];

	    if (!mePtr || !(mePtr->entryFlags & ENTRY_APPLE_MENU)) {
		applicationMenuItem = [NSMenuItem itemWithSubmenu:
			[[_defaultApplicationMenu copy] autorelease]];
		[menu insertItem:applicationMenuItem atIndex:0];
	    }
	    [menu setSpecial:tkMainMenu];
	}
................................................................................
	applicationMenu = (TKMenu *)[applicationMenuItem submenu];
	if (![applicationMenu isSpecial:tkApplicationMenu]) {
	    for (NSMenuItem *item in _defaultApplicationMenuItems) {
		[applicationMenu addItem:[[item copy] autorelease]];
	    }
	    [applicationMenu setSpecial:tkApplicationMenu];
	}

	NSArray *itemArray = [menu itemArray];

	for (NSMenuItem *item in itemArray) {
	    TkMenuEntry *mePtr = (TkMenuEntry *)[item tag];
	    TKMenu *submenu = (TKMenu *)[item submenu];

	    if (mePtr && submenu) {
		if ((mePtr->entryFlags & ENTRY_WINDOWS_MENU) &&
			![submenu isSpecial:tkWindowsMenu]) {
		    NSInteger index = 0;

		    for (NSMenuItem *i in _defaultWindowsMenuItems) {
			[submenu insertItem:[[i copy] autorelease] atIndex:
				index++];
		    }
		    [self setWindowsMenu:submenu];
		    [submenu setSpecial:tkWindowsMenu];
		} else if ((mePtr->entryFlags & ENTRY_HELP_MENU) &&
			![submenu isSpecial:tkHelpMenu]) {
		    NSInteger index = 0;

		    for (NSMenuItem *i in _defaultHelpMenuItems) {
			[submenu insertItem:[[i copy] autorelease] atIndex:
				index++];
		    }
		    [submenu setSpecial:tkHelpMenu];
		}
	    }
	}
    } else {
	menu = _defaultMainMenu;
	applicationMenu = _defaultApplicationMenu;
    }

    NSMenuItem *servicesMenuItem =
	    [applicationMenu itemWithTitle:@"Services"];

    if (servicesMenuItem && [servicesMenuItem submenu] != _servicesMenu) {
	[[_servicesMenu itemInSupermenu] setSubmenu:nil];
	[servicesMenuItem setSubmenu:_servicesMenu];
    }
    [self setAppleMenu:applicationMenu];
    [self setMainMenu:menu];
}
................................................................................
 *	Gets a new blank menu. Only the platform specific options are filled
 *	in.
 *
 * Results:
 *	Returns a standard Tcl error.
 *
 * Side effects:
 *	Allocates a NSMenu and puts it into the platformData field of the
 *	menuPtr.
 *
 *----------------------------------------------------------------------
 */

int
TkpNewMenu(
    TkMenu *menuPtr)		/* The common structure we are making the
................................................................................
    if (mePtr->type == SEPARATOR_ENTRY || mePtr->type == TEAROFF_ENTRY) {
	menuItem = [[NSMenuItem separatorItem] retain];
    } else {
	menuItem = [menu newTkMenuItem:mePtr];
    }
    mePtr->platformEntryData = (TkMenuPlatformEntryData)
	    TkMacOSXMakeUncollectable(menuItem);

    /*
     * Caller TkMenuEntry() already did this same insertion into the generic
     * TkMenu so we just match it for the platform menu.
     */

    [menu insertItem:menuItem atTkIndex:mePtr->index];
    return TCL_OK;
}
 
/*
 *----------------------------------------------------------------------
 *
................................................................................
    if (mePtr->image) {
    	Tk_SizeOfImage(mePtr->image, &imageWidth, &imageHeight);
	image = TkMacOSXGetNSImageWithTkImage(mePtr->menuPtr->display,
		mePtr->image, imageWidth, imageHeight);
    } else if (mePtr->bitmapPtr != None) {
	Pixmap bitmap = Tk_GetBitmapFromObj(mePtr->menuPtr->tkwin,
		mePtr->bitmapPtr);

	Tk_SizeOfBitmap(mePtr->menuPtr->display, bitmap, &imageWidth,
		&imageHeight);
	image = TkMacOSXGetNSImageWithBitmap(mePtr->menuPtr->display, bitmap,
		gc, imageWidth, imageHeight);
    }
    [menuItem setImage:image];
    if ((!image || mePtr->compound != COMPOUND_NONE) && mePtr->labelPtr &&
................................................................................
    }
    [menuItem setTitle:title];
    if (strcmp(Tcl_GetString(fontPtr), "menu") || gc->foreground != defaultFg
	    || gc->background != defaultBg) {
	attributes = TkMacOSXNSFontAttributesForFont(Tk_GetFontFromObj(
		mePtr->menuPtr->tkwin, fontPtr));
	if (gc->foreground != defaultFg || gc->background != defaultBg) {
	    NSColor *color = TkMacOSXGetNSColor(gc,
		    gc->foreground!=defaultFg? gc->foreground:gc->background);

	    attributes = [[attributes mutableCopy] autorelease];
	    [(NSMutableDictionary *)attributes setObject:color
		    forKey:NSForegroundColorAttributeName];
	}
	if (attributes) {
	    attributedTitle = [[[NSAttributedString alloc]
		    initWithString:title attributes:attributes] autorelease];
................................................................................
	menuRefPtr = TkFindMenuReferencesObj(mePtr->menuPtr->interp,
		mePtr->namePtr);
	if (menuRefPtr && menuRefPtr->menuPtr) {
	    CheckForSpecialMenu(menuRefPtr->menuPtr);
	    submenu = (TKMenu *) menuRefPtr->menuPtr->platformData;
	    if ([submenu supermenu] && [menuItem submenu] != submenu) {
		/*
		 * This happens during a clone, where the parent menu is
		 * cloned before its children, so just ignore this temprary
		 * setting, it will be changed shortly (c.f. tkMenu.c
		 * CloneMenu())
		 */

		submenu = nil;
	    } else {
		[submenu setTitle:title];
	    }
	}
    }
    [menuItem setSubmenu:submenu];

    /*Disabling parent menu disables entries; we must re-enable the entries here.*/
    NSArray *itemArray = [submenu itemArray];
    
    if ([menuItem isEnabled]) {
	    for (NSMenuItem *item in itemArray) {
		    [item setEnabled:YES];
	    }
	}

    return TCL_OK;
}
 
/*
 *----------------------------------------------------------------------
 *
 * TkpDestroyMenuEntry --
................................................................................

void
TkpDestroyMenuEntry(
    TkMenuEntry *mePtr)
{
    if (mePtr->platformEntryData && mePtr->menuPtr->platformData) {
	TKMenu *menu = (TKMenu *) mePtr->menuPtr->platformData;
	NSMenuItem *menuItem = (NSMenuItem *) mePtr->platformEntryData;
	NSInteger index = [menu indexOfItem:menuItem];

	if (index > -1) {
	    [menu removeItemAtIndex:index];
	}
    }
    TkMacOSXMakeCollectableAndRelease(mePtr->platformEntryData);
}
 
................................................................................
    TkMenu *menuPtr,		/* The menu we are posting */
    int x,			/* The global x-coordinate of the top, left-
				 * hand corner of where the menu is supposed
				 * to be posted. */
    int y)			/* The global y-coordinate */
{
    NSWindow *win = [NSApp keyWindow];
    if (!win) {
	return TCL_ERROR;
    }

    inPostMenu = 1;

    int oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE);
    NSView *view = [win contentView];
    NSRect frame = NSMakeRect(x + 9, tkMacOSXZeroScreenHeight - y - 9, 1, 1);

    frame.origin = [view convertPoint:
	    [win convertScreenToBase:frame.origin] fromView:nil];

    NSMenu *menu = (NSMenu *) menuPtr->platformData;
    NSPopUpButtonCell *popUpButtonCell = [[NSPopUpButtonCell alloc]
	    initTextCell:@"" pullsDown:NO];

    [popUpButtonCell setAltersStateOfSelectedItem:NO];
    [popUpButtonCell setMenu:menu];
    [popUpButtonCell selectItem:nil];
    [popUpButtonCell performClickWithFrame:frame inView:view];
    [popUpButtonCell release];
    Tcl_SetServiceMode(oldMode);
    inPostMenu = 0;
    return TCL_OK;



}
 
/*
 *----------------------------------------------------------------------
 *
 * TkpSetWindowMenuBar --
 *
................................................................................
 *----------------------------------------------------------------------
 */

void
TkpSetMainMenubar(
    Tcl_Interp *interp,		/* The interpreter of the application */
    Tk_Window tkwin,		/* The frame we are setting up */
    const char *menuName)	/* The name of the menu to put in front. If
				 * NULL, use the default menu bar. */
{
    static Tcl_Interp *currentInterp = NULL;
    TKMenu *menu = nil;

    if (menuName) {
	TkWindow *winPtr = (TkWindow *) tkwin;

	if (winPtr->wmInfoPtr && winPtr->wmInfoPtr->menuPtr &&
		winPtr->wmInfoPtr->menuPtr->masterMenuPtr &&
		winPtr->wmInfoPtr->menuPtr->masterMenuPtr->tkwin &&
		!strcmp(menuName, Tk_PathName(
		winPtr->wmInfoPtr->menuPtr->masterMenuPtr->tkwin))) {
	    menu = (TKMenu *) winPtr->wmInfoPtr->menuPtr->platformData;
	} else {
	    TkMenuReferences *menuRefPtr = TkFindMenuReferences(interp,
		    menuName);

	    if (menuRefPtr && menuRefPtr->menuPtr &&
		    menuRefPtr->menuPtr->platformData) {
		menu = (TKMenu *) menuRefPtr->menuPtr->platformData;
	    }
	}
    }
    if (menu || interp != currentInterp) {
................................................................................
}
 
/*
 *----------------------------------------------------------------------
 *
 * CheckForSpecialMenu --
 *
 *	Given a menu, check to see whether or not it is a cascade in a menubar
 *	with one of the special names .apple, .help or .window If it is, the
 *	entry that points to this menu will be marked.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Will set entryFlags appropriately.
 *
................................................................................
CheckForSpecialMenu(
    TkMenu *menuPtr)		/* The menu we are checking */
{
    if (!menuPtr->masterMenuPtr->tkwin) {
	return;
    }
    for (TkMenuEntry *cascadeEntryPtr = menuPtr->menuRefPtr->parentEntryPtr;
	    cascadeEntryPtr;
	    cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) {
	if (cascadeEntryPtr->menuPtr->menuType == MENUBAR
		&& cascadeEntryPtr->menuPtr->masterMenuPtr->tkwin) {
	    TkMenu *masterMenuPtr = cascadeEntryPtr->menuPtr->masterMenuPtr;
	    int i = 0;
	    Tcl_DString ds;

	    Tcl_DStringInit(&ds);
................................................................................
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

static NSString *
ParseAccelerator(
    const char *accel,
    NSUInteger *maskPtr)
{
    unichar ch = 0;
    size_t len;
    int i;
................................................................................
 * Side effects:
 *	None.
 *
 *--------------------------------------------------------------
 */

static int
ModifierCharWidth(
    Tk_Font tkfont)
{
    static NSString *cmdChar = nil;

    if (!cmdChar) {
	unichar cmd = kCommandUnicode;

	cmdChar = [[NSString alloc] initWithCharacters:&cmd length:1];
    }
    return [cmdChar sizeWithAttributes:
	    TkMacOSXNSFontAttributesForFont(tkfont)].width;
}
 
/*
................................................................................

	    if (mePtr->image) {
		Tk_SizeOfImage(mePtr->image, &width, &height);
		haveImage = 1;
	    } else if (mePtr->bitmapPtr) {
		Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin,
			mePtr->bitmapPtr);

		Tk_SizeOfBitmap(menuPtr->display, bitmap, &width, &height);
		haveImage = 1;
	    }
	    if (!haveImage || (mePtr->compound != COMPOUND_NONE)) {
		NSAttributedString *attrTitle = [menuItem attributedTitle];
		NSSize size;

................................................................................
    TKMenu *menu,
    NSMenuItem *menuItem)
{
    TkMenu *menuPtr = [menu tkMenu];

    if (menuPtr) {
	int index = [menu tkIndexOfItem:menuItem];

	if (index < 0 || index >= menuPtr->numEntries ||
		(menuPtr->entries[index])->state == ENTRY_DISABLED) {
	    TkActivateMenuEntry(menuPtr, -1);
	} else {
	    TkActivateMenuEntry(menuPtr, index);
	    MenuSelectEvent(menuPtr);
	    return true;
................................................................................
 */

void
RecursivelyClearActiveMenu(
    TkMenu *menuPtr)		/* The menu to reset. */
{
    int i;


    TkActivateMenuEntry(menuPtr, -1);
    for (i = 0; i < menuPtr->numEntries; i++) {
	TkMenuEntry *mePtr = menuPtr->entries[i];

	if (mePtr->type == CASCADE_ENTRY
		&& (mePtr->childMenuRefPtr != NULL)
		&& (mePtr->childMenuRefPtr->menuPtr != NULL)) {
	    RecursivelyClearActiveMenu(mePtr->childMenuRefPtr->menuPtr);

	}
    }
}
 
/*
 *----------------------------------------------------------------------
 *
................................................................................
 *----------------------------------------------------------------------
 */

void
TkMacOSXClearMenubarActive(void)
{
    NSMenu *mainMenu = [NSApp mainMenu];

    if (mainMenu && [mainMenu isKindOfClass:[TKMenu class]]) {
	TkMenu *menuPtr = [(TKMenu *) mainMenu tkMenu];

	if (menuPtr && menuPtr->numEntries && menuPtr->entries) {
	    RecursivelyClearActiveMenu(menuPtr);
	}
    }
}
 
/*
................................................................................

void
TkpMenuInit(void)
{
    TkColor *tkColPtr;

    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];

#define observe(n, s) \
	[nc addObserver:NSApp selector:@selector(s) name:(n) object:nil]
    observe(NSMenuDidBeginTrackingNotification, menuBeginTracking:);
    observe(NSMenuDidEndTrackingNotification, menuEndTracking:);
#undef observe

    [NSMenuItem setUsesUserKeyEquivalents:NO];
    tkColPtr = TkpGetColor(None, DEF_MENU_BG_COLOR);
    defaultBg = tkColPtr->color.pixel;
    ckfree(tkColPtr);
    tkColPtr = TkpGetColor(None, DEF_MENU_FG);
    defaultFg = tkColPtr->color.pixel;
    ckfree(tkColPtr);

    ChkErr(GetThemeMetric, kThemeMetricMenuMarkColumnWidth,
	    &menuMarkColumnWidth);
    ChkErr(GetThemeMetric, kThemeMetricMenuTextLeadingEdgeMargin,
	    &menuTextLeadingEdgeMargin);
    ChkErr(GetThemeMetric, kThemeMetricMenuTextTrailingEdgeMargin,
	    &menuTextTrailingEdgeMargin);
................................................................................
 
/*
 *----------------------------------------------------------------------
 *
 * TkpMenuNotifyToplevelCreate --
 *
 *	This routine reconfigures the menu and the clones indicated by
 *	menuName because a toplevel has been created and any system menus need
 *	to be created. Only applicable to Windows.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	An idle handler is set up to do the reconfiguration.
................................................................................
 *
 *----------------------------------------------------------------------
 */

void
TkpMenuNotifyToplevelCreate(
    Tcl_Interp *interp,		/* The interp the menu lives in. */
    const char *menuName)	/* The name of the menu to reconfigure. */
{
    /*
     * Nothing to do.
     */
}
 
/*
................................................................................
    const Tk_FontMetrics *menuMetricsPtr,
				/* Precalculated metrics for menu */
    int x,			/* X-coordinate of topleft of entry */
    int y,			/* Y-coordinate of topleft of entry */
    int width,			/* Width of the entry rectangle */
    int height,			/* Height of the current rectangle */
    int strictMotif,		/* Boolean flag */
    int drawArrow)		/* Whether or not to draw the cascade arrow
				 * for cascade items. Only applies to
				 * Windows. */
{
}

#pragma mark Obsolete
 
/*
 *----------------------------------------------------------------------
................................................................................
void
TkMacOSXMenuClick(void)
{
}
 
/*
 * Local Variables:
 * mode: objc
 * c-basic-offset: 4
 * fill-column: 79
 * coding: utf-8
 * End:
 */

Changes to macosx/tkMacOSXPrivate.h.

312
313
314
315
316
317
318
319
320
321
322

323
324




325
326
327
328
329
330
331
@end
@interface TKApplication(TKClipboard)
- (void)tkProvidePasteboard:(TkDisplay *)dispPtr;
- (void)tkCheckPasteboard;
@end

VISIBILITY_HIDDEN
@interface TKContentView : NSView {
@private
    id _savedSubviews;
    BOOL _subviewsSetAside;

}
@end





VISIBILITY_HIDDEN
@interface TKWindow : NSWindow
@end

#pragma mark NSMenu & NSMenuItem Utilities







|



>


>
>
>
>







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
@end
@interface TKApplication(TKClipboard)
- (void)tkProvidePasteboard:(TkDisplay *)dispPtr;
- (void)tkCheckPasteboard;
@end

VISIBILITY_HIDDEN
@interface TKContentView : NSView <NSTextInput> {
@private
    id _savedSubviews;
    BOOL _subviewsSetAside;
    NSString *_workingText;
}
@end

@interface TKContentView(TKKeyEvent)
- (void) deleteWorkingText;
@end

VISIBILITY_HIDDEN
@interface TKWindow : NSWindow
@end

#pragma mark NSMenu & NSMenuItem Utilities