diff options
-rw-r--r-- | library/tk.tcl | 17 | ||||
-rw-r--r-- | macosx/tkMacOSXKeyEvent.c | 89 | ||||
-rw-r--r-- | macosx/tkMacOSXKeyboard.c | 36 | ||||
-rw-r--r-- | macosx/tkMacOSXMenu.c | 15 | ||||
-rw-r--r-- | macosx/tkMacOSXMouseEvent.c | 44 | ||||
-rw-r--r-- | macosx/tkMacOSXWm.c | 14 |
6 files changed, 192 insertions, 23 deletions
diff --git a/library/tk.tcl b/library/tk.tcl index e695924..cb6e662 100644 --- a/library/tk.tcl +++ b/library/tk.tcl @@ -3,7 +3,7 @@ # Initialization script normally executed in the interpreter for each # Tk-based application. Arranges class bindings for widgets. # -# RCS: @(#) $Id: tk.tcl,v 1.43 2002/08/31 06:12:28 das Exp $ +# RCS: @(#) $Id: tk.tcl,v 1.44 2002/09/09 23:52:02 hobbs Exp $ # # Copyright (c) 1992-1994 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. @@ -111,6 +111,11 @@ proc ::tk::PlaceWindow {w {place ""} {anchor ""}} { } elseif {$y > ([winfo screenheight $w]-[winfo reqheight $w])} { set y [expr {[winfo screenheight $w]-[winfo reqheight $w]}] } + if {[tk windowingsystem] eq "macintosh" \ + || [tk windowingsystem] eq "aqua"} { + # Avoid the native menu bar which sits on top of everything. + if {$y < 20} { set y 20 } + } } wm geometry $w +$x+$y wm deiconify $w @@ -369,13 +374,13 @@ switch [tk windowingsystem] { event add <<Redo>> <Control-Key-y> } "aqua" { - event add <<Cut>> <Control-Key-x> <Key-F2> - event add <<Copy>> <Control-Key-c> <Key-F3> - event add <<Paste>> <Control-Key-v> <Key-F4> + event add <<Cut>> <Command-Key-x> <Key-F2> + event add <<Copy>> <Command-Key-c> <Key-F3> + event add <<Paste>> <Command-Key-v> <Key-F4> event add <<PasteSelection>> <ButtonRelease-2> event add <<Clear>> <Clear> - event add <<Undo>> <Control-Key-z> - event add <<Redo>> <Control-Key-y> + event add <<Undo>> <Command-Key-z> + event add <<Redo>> <Command-Key-y> } "classic" { event add <<Cut>> <Control-Key-x> <Key-F2> diff --git a/macosx/tkMacOSXKeyEvent.c b/macosx/tkMacOSXKeyEvent.c index 7c3474c..a8d2711 100644 --- a/macosx/tkMacOSXKeyEvent.c +++ b/macosx/tkMacOSXKeyEvent.c @@ -76,7 +76,8 @@ static Tk_Window gKeyboardWinPtr = NULL; /* Current keyboard grab window. */ static int GenerateKeyEvent _ANSI_ARGS_(( EventKind eKind, KeyEventData * e, Window window, - UInt32 savedKeyCode)); + UInt32 savedKeyCode, + UInt32 savedModifiers)); /* *---------------------------------------------------------------------- * @@ -99,6 +100,7 @@ int TkMacOSXProcessKeyboardEvent( MacEventStatus * statusPtr) { static UInt32 savedKeyCode = 0; + static UInt32 savedModifiers = 0; OSStatus status; KeyEventData keyEventData; Window window; @@ -115,6 +117,26 @@ int TkMacOSXProcessKeyboardEvent( keyEventData.global = keyEventData.local; LocalToGlobal(&keyEventData.global); keyEventData.state = TkMacOSXButtonKeyState(); +#if 0 + /* + * This block of code seems like a good idea, to trap + * key-bindings which point directly to menus, but it + * has a number of problems: + * (1) when grabs are present we definitely don't want + * to do this. + * (2) Tk's semantics define accelerator keystrings in + * menus as a purely visual adornment, and require that + * the developer create separate bindings to trigger + * them. This breaks those semantics. (i.e. Tk will + * behave differently on Aqua to the behaviour on Unix/Win). + * (3) Tk's bindings depend on the current window's bindtags, + * which may be completely different to what happens to be + * in some global menu (agreed, it shouldn't be that different, + * but it often is). + * + * While a better middleground might be possible, the best, most + * compatible, approach at present is to disable this block. + */ if (IsMenuKeyEvent(NULL, eventPtr->eventRef, kNilOptions, &menuRef, &menuItemIndex)) { int oldMode; @@ -138,6 +160,7 @@ int TkMacOSXProcessKeyboardEvent( Tcl_SetServiceMode(oldMode); return 0; /* TODO: may not be on event on queue. */ } +#endif status = GetEventParameter(eventPtr->eventRef, kEventParamKeyMacCharCodes, @@ -174,7 +197,8 @@ int TkMacOSXProcessKeyboardEvent( window = TkMacOSXGetXWindow(keyEventData.whichWindow); eventGenerated = GenerateKeyEvent(eventPtr->eKind, &keyEventData, - window, savedKeyCode); + window, savedKeyCode, savedModifiers); + savedModifiers = keyEventData.keyModifiers; if (eventGenerated == 0) { savedKeyCode = keyEventData.message; @@ -212,7 +236,8 @@ int GenerateKeyEvent( EventKind eKind, KeyEventData * e, Window window, - UInt32 savedKeyCode ) + UInt32 savedKeyCode, + UInt32 savedModifiers ) { Tk_Window tkwin; XEvent event; @@ -240,7 +265,23 @@ GenerateKeyEvent( EventKind eKind, return -1; } byte = (e->message&charCodeMask); - if ((savedKeyCode == 0) && + if (byte == 0) { + /* + * Either we have a pure-modifier change, or perhaps + * a dead-key (e.g. opt-e) was pressed. In the former case we do + * want to generate an event, in the latter I'm not sure + * what to do. + */ + if (eKind == kEventRawKeyModifiersChanged) { + /* Drop through to the event code below */ + } else { + /* + * What shall we do here? We certainly aren't dealing + * with deadkeys at present. Is this where they come? + */ + return 0; + } + } else if ((savedKeyCode == 0) && (Tcl_ExternalToUtf(NULL, TkMacOSXCarbonEncoding, (char *) &byte, 1, 0, NULL, buf, sizeof(buf), NULL, NULL, NULL) != TCL_OK)) { @@ -262,6 +303,30 @@ GenerateKeyEvent( EventKind eKind, Tk_TopCoordsToWindow(tkwin, e->local.h, e->local.v, &event.xkey.x, &event.xkey.y); + /* + * Now, we may have a problem here. How do we handle 'Option-char' + * keypresses? The problem is that we might want to bind to some of + * these (e.g. Cmd-Opt-d is 'uncomment' in Alpha), but Option-d + * generates a 'delta' symbol with some keycode unrelated to 'd', and so + * the binding never triggers. In any case, the delta that is produced + * is never mapped to an 'XK_Greek_DELTA' keysym so bindings on that + * won't work either (a general KeyPress binding will of course trigger, + * but a specific binding on XK_Greek_DELTA will not). + * + * I think what we want is for the event to contain information on + * both the 'Opt-d' side of things and the 'delta'. Then a binding + * on Opt-d will trigger, but the ascii/string representation of the + * event will be a delta. + * + * A different way to look at this is that 'Opt-d' is delta, but that + * Command-Opt-d is nothing to do with delta, but I'm not sure that is + * helpful. + * + * Also some keypresses (Opt-e) are dead-keys to add accents to + * letters. We don't handle them yet. + * + * Help needed! + */ event.xkey.keycode = byte | ((savedKeyCode & charCodeMask) << 8) | ((e->message&keyCodeMask) << 8); @@ -287,6 +352,22 @@ GenerateKeyEvent( EventKind eKind, event.xany.type = KeyPress; Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); break; + case kEventRawKeyModifiersChanged: + if (savedModifiers > e->keyModifiers) { + event.xany.type = KeyRelease; + } else { + event.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. + */ + event.xany.send_event = -1; + /* Set keycode (which was zero) to the changed modifier */ + event.xkey.keycode = (e->keyModifiers ^ savedModifiers); + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + break; default: break; } diff --git a/macosx/tkMacOSXKeyboard.c b/macosx/tkMacOSXKeyboard.c index db5d679..aff807e 100644 --- a/macosx/tkMacOSXKeyboard.c +++ b/macosx/tkMacOSXKeyboard.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkMacOSXKeyboard.c,v 1.2 2002/08/31 06:12:30 das Exp $ + * RCS: @(#) $Id: tkMacOSXKeyboard.c,v 1.3 2002/09/09 23:52:02 hobbs Exp $ */ #include "tkInt.h" @@ -148,6 +148,14 @@ XKeycodeToKeysym( if (!initialized) { InitKeyMaps(); } + if (keycode == 0) { + /* + * This means we had a pure modifier keypress or + * something similar which is a TO DO. + */ + return NoSymbol; + } + virtualKey = (char) (keycode >> 16); c = (keycode) & 0xffff; if (c > 255) { @@ -240,7 +248,7 @@ TkpGetString( * Just return NULL if the character is a function key or another * non-printing key. */ - if (c == 0x10) { + if (c == 0x10 || (eventPtr->xany.send_event == -1)) { len = 0; } else { hPtr = Tcl_FindHashEntry(&keycodeTable, (char *) virtualKey); @@ -487,6 +495,30 @@ TkpGetKeySym(dispPtr, eventPtr) && (eventPtr->xkey.state & LockMask))) { index += 1; } + if (eventPtr->xany.send_event == -1) { + /* We use -1 as a special signal for a pure modifier */ + int modifier = eventPtr->xkey.keycode; + if (modifier == cmdKey) { + return XK_Alt_L; + } else if (modifier == shiftKey) { + return XK_Shift_L; + } else if (modifier == alphaLock) { + return XK_Caps_Lock; + } else if (modifier == optionKey) { + return XK_Meta_L; + } else if (modifier == controlKey) { + return XK_Control_L; + } else if (modifier == rightShiftKey) { + return XK_Shift_R; + } else if (modifier == rightOptionKey) { + return XK_Meta_R; + } else if (modifier == rightControlKey) { + return XK_Control_R; + } else { + /* If we get here, we probably need to implement something new */ + return NoSymbol; + } + } sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode, index); /* diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index 8578359..401bce5 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkMacOSXMenu.c,v 1.2 2002/08/31 06:12:30 das Exp $ + * RCS: @(#) $Id: tkMacOSXMenu.c,v 1.3 2002/09/09 23:52:02 hobbs Exp $ */ #include "tkMacOSXInt.h" #include "tkMenuButton.h" @@ -188,7 +188,7 @@ static int inPostMenu; /* We cannot be re-entrant like X * windows. */ static short lastMenuID; /* To pass to NewMenu; need to figure out * a good way to do this. */ -static unsigned char lastCascadeID; +static short lastCascadeID; /* Cascades have to have ids that are * less than 256. */ static MacDrawable macMDEFDrawable; @@ -390,6 +390,11 @@ TkMacOSXUseMenuID( * the fly. We use the id as a key into a hash table; if there * is no hash entry, we know that we can use the id. * + * Carbon allows a much larger number of menus than the old APIs. + * I believe this is 32768, but am not sure. This code just uses + * 2000 as the upper limit. Unfortunately tk leaks menus when + * cloning, under some circumstances (see bug on sourceforge). + * * Results: * Returns TCL_OK if succesful; TCL_ERROR if there are no more * ids of the appropriate type to allocate. menuIDPtr contains @@ -448,8 +453,8 @@ int * dealt with separately. */ - unsigned char curID = lastCascadeID + 1; - if (curID == 236) { + short curID = lastCascadeID + 1; + if (curID == 2000) { curID = 0; } @@ -463,7 +468,7 @@ int break; } curID++; - if (curID == 236) { + if (curID == 2000) { curID = 0; } } diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index 769472c..12bfc93 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -215,7 +215,17 @@ TkMacOSXProcessMouseEvent(TkMacOSXEvent *eventPtr, MacEventStatus * statusPtr) medPtr->global = where; medPtr->local = where; - SetPortWindowPort(frontWindow); + /* + * We must set the port to the right window -- the one + * we are actually going to use -- before finding + * the local coordinates, otherwise we will have completely + * wrong local x,y! + * + * I'm pretty sure this window is medPtr->whichWin, unless + * perhaps there is a grab. Certainly 'frontWindow' or + * 'medPtr->activeNonFloating' are wrong. + */ + SetPortWindowPort(medPtr->whichWin); GlobalToLocal(&medPtr->local); if (eventPtr->eKind == kEventMouseWheelMoved ) { return GenerateMouseWheelEvent(medPtr); @@ -389,7 +399,14 @@ GeneratePollingEvents(MouseEventData * medPtr) int local_x, local_y; TkDisplay *dispPtr; - + /* + * I really do not understand this complicated logic. Surely the event + * should be to either: (1) medPtr->whichWin, the window under the mouse + * (from which we then obviously extract the correct Tk subwindow), or + * (2) the current grab window. I really don't see why anything else is + * relevant. + */ +#if 0 if ((!TkpIsWindowFloating(medPtr->whichWin) && (medPtr->activeNonFloating != medPtr->whichWin))) { tkwin = NULL; @@ -416,6 +433,23 @@ GeneratePollingEvents(MouseEventData * medPtr) if ((tkwin == NULL) && (grabWin != NULL)) { tkwin = grabWin; } +#else + grabWin = TkMacOSXGetCapture(); + if (grabWin != NULL) { + tkwin = grabWin; + } else { + window = TkMacOSXGetXWindow(medPtr->whichWin); + dispPtr = TkGetDisplayList(); + rootwin = Tk_IdToWindow(dispPtr->display, window); + if (rootwin == NULL) { + tkwin = NULL; + } else { + tkwin = Tk_TopCoordsToWindow(rootwin, + medPtr->local.h, medPtr->local.v, + &local_x, &local_y); + } + } +#endif Tk_UpdatePointer(tkwin, medPtr->global.h, medPtr->global.v, medPtr->state); @@ -683,15 +717,17 @@ TkGenerateButtonEvent( FindWindow(where, &whichWin); frontWin = FrontNonFloatingWindow(); - if ((frontWin == NULL) || ((!(TkpIsWindowFloating(whichWin)) + if (0 && ((frontWin == NULL) || ((!(TkpIsWindowFloating(whichWin)) && (frontWin != whichWin)) - && TkMacOSXGetCapture() == NULL)) { + && TkMacOSXGetCapture() == NULL))) { return false; } dispPtr = TkGetDisplayList(); tkwin = Tk_IdToWindow(dispPtr->display, window); + /* SetPortWindowPort(ActiveNonFloatingWindow()); */ + SetPortWindowPort(whichWin); GlobalToLocal(&where); if (tkwin != NULL) { tkwin = Tk_TopCoordsToWindow(tkwin, where.h, where.v, diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index 14f93fb..633e305 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkMacOSXWm.c,v 1.3 2002/09/03 11:48:56 vincentdarley Exp $ + * RCS: @(#) $Id: tkMacOSXWm.c,v 1.4 2002/09/09 23:52:02 hobbs Exp $ */ #include <Carbon/Carbon.h> @@ -763,6 +763,7 @@ configArgs: Tcl_AppendResult(interp, "wrong # arguments: must be \"", Tcl_GetStringFromObj (objv[0], NULL), " attributes window", " ?-modified ?bool??", + " ?-titlepath ?path??", "\"", (char *) NULL); return TCL_ERROR; } @@ -2544,7 +2545,8 @@ Tcl_Obj *CONST objv[]; /* Argument objects. */ wmPtr2 = ((TkWindow *) master)->wmInfoPtr; - if (wmPtr2->iconFor != NULL) { + /* Under some circumstances, wmPtr2 is NULL here */ + if (wmPtr2 != NULL && wmPtr2->iconFor != NULL) { Tcl_AppendResult(interp, "can't make \"", Tcl_GetString(objv[3]), "\" a master: it is an icon for ", @@ -4755,6 +4757,14 @@ TkUnsupported1Cmd( } else if ((*attrArgv[i] == 's') && (strcmp(attrArgv[i], "sideTitlebar") == 0)) { wmPtr->attributes |= kWindowSideTitlebarAttribute; + foundOne = 1; + } else if ((*attrArgv[i] == 'n') + && (strcmp(attrArgv[i], "noActivates") == 0)) { + wmPtr->attributes |= kWindowNoActivatesAttribute; + foundOne = 1; + } else if ((*attrArgv[i] == 'n') + && (strcmp(attrArgv[i], "noUpdates") == 0)) { + wmPtr->attributes |= kWindowNoUpdatesAttribute; foundOne = 1; } else { foundOne = 0; |